2022-07-03 20:58:32 +02:00
|
|
|
import logging
|
2022-05-18 23:40:13 +02:00
|
|
|
import sys
|
2022-09-09 14:23:18 +02:00
|
|
|
from pathlib import Path
|
2022-09-13 11:59:29 +02:00
|
|
|
from typing import Optional, Sequence, Tuple
|
2022-07-03 20:58:32 +02:00
|
|
|
|
2022-09-09 14:23:18 +02:00
|
|
|
from spacepackets import SpacePacket, SpacePacketHeader, PacketTypes
|
2022-09-09 14:30:15 +02:00
|
|
|
from spacepackets.cfdp import (
|
|
|
|
TransmissionModes,
|
|
|
|
PduType,
|
|
|
|
DirectiveType,
|
|
|
|
GenericPduPacket,
|
|
|
|
PduHolder,
|
|
|
|
PduFactory,
|
2022-09-09 16:55:04 +02:00
|
|
|
ChecksumTypes,
|
|
|
|
ConditionCode,
|
2022-09-09 14:30:15 +02:00
|
|
|
)
|
2022-09-09 14:23:18 +02:00
|
|
|
from tmtccmd.cfdp import (
|
|
|
|
RemoteEntityCfgTable,
|
|
|
|
RemoteEntityCfg,
|
|
|
|
LocalEntityCfg,
|
|
|
|
CfdpUserBase,
|
2022-09-09 16:55:04 +02:00
|
|
|
IndicationCfg,
|
|
|
|
TransactionId,
|
2022-09-09 14:23:18 +02:00
|
|
|
)
|
2022-09-09 15:24:23 +02:00
|
|
|
from tmtccmd.cfdp.defs import CfdpRequestType, CfdpStates
|
2022-09-09 14:23:18 +02:00
|
|
|
from tmtccmd.cfdp.handler import SourceHandler, DestHandler
|
2022-09-09 16:55:04 +02:00
|
|
|
from tmtccmd.cfdp.mib import DefaultFaultHandlerBase
|
2022-09-13 13:54:47 +02:00
|
|
|
from tmtccmd.cfdp.request import PutRequest
|
2022-09-09 16:55:04 +02:00
|
|
|
from tmtccmd.cfdp.user import (
|
|
|
|
FileSegmentRecvdParams,
|
|
|
|
MetadataRecvParams,
|
|
|
|
TransactionFinishedParams,
|
|
|
|
)
|
2022-09-09 17:41:44 +02:00
|
|
|
from tmtccmd.config.args import ProcedureParamsWrapper
|
2022-07-03 20:58:32 +02:00
|
|
|
from tmtccmd.logging import get_current_time_string
|
2022-07-27 20:43:52 +02:00
|
|
|
from tmtccmd.pus.pus_11_tc_sched import Subservices as Pus11Subservices
|
2022-07-28 16:37:01 +02:00
|
|
|
from tmtccmd.tc.queue import DefaultPusQueueHelper
|
2022-09-09 14:23:18 +02:00
|
|
|
from tmtccmd.util import FileSeqCountProvider, PusFileSeqCountProvider, ProvidesSeqCount
|
2022-07-27 14:40:25 +02:00
|
|
|
from tmtccmd.util.tmtc_printer import FsfwTmTcPrinter
|
2022-05-18 23:40:13 +02:00
|
|
|
|
|
|
|
try:
|
|
|
|
import spacepackets
|
|
|
|
except ImportError as error:
|
|
|
|
print(error)
|
2022-07-03 20:58:32 +02:00
|
|
|
print("Python tmtccmd module could not be imported. Make sure it is installed")
|
2022-05-18 23:40:13 +02:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
try:
|
2022-07-03 20:58:32 +02:00
|
|
|
import tmtccmd
|
2022-05-18 23:40:13 +02:00
|
|
|
except ImportError as error:
|
2022-07-03 20:58:32 +02:00
|
|
|
print(error)
|
|
|
|
print("Python tmtccmd module could not be imported. Make sure it is installed")
|
2022-05-18 23:40:13 +02:00
|
|
|
sys.exit(1)
|
|
|
|
|
2022-07-28 16:37:01 +02:00
|
|
|
from spacepackets.ecss import PusVerificator, PusTelecommand, PusServices
|
2022-07-03 20:58:32 +02:00
|
|
|
|
|
|
|
from common_tmtc.pus_tc.pus_11_tc_sched import pack_service_11_commands
|
|
|
|
from common_tmtc.pus_tc.pus_17_test import pack_service_17_commands
|
|
|
|
from common_tmtc.pus_tc.pus_200_mode import pack_service_200_commands_into
|
|
|
|
from common_tmtc.pus_tc.service_20_parameters import pack_service20_commands_into
|
|
|
|
from common_tmtc.pus_tc.service_2_raw_cmd import pack_service_2_commands_into
|
|
|
|
from common_tmtc.pus_tc.service_3_housekeeping import pack_service_3_commands_into
|
|
|
|
from common_tmtc.pus_tc.service_8_func_cmd import pack_service_8_commands_into
|
2022-09-09 16:55:04 +02:00
|
|
|
from examples.tmtcc import (
|
|
|
|
EXAMPLE_PUS_APID,
|
|
|
|
EXAMPLE_CFDP_APID,
|
|
|
|
CFDP_LOCAL_ENTITY_ID,
|
|
|
|
CFDP_REMOTE_ENTITY_ID,
|
|
|
|
)
|
2022-09-09 17:51:41 +02:00
|
|
|
from tmtccmd import TcHandlerBase, get_console_logger, TmTcCfgHookBase, BackendBase
|
2022-07-27 14:40:25 +02:00
|
|
|
from tmtccmd.pus import VerificationWrapper
|
2022-07-03 20:58:32 +02:00
|
|
|
from tmtccmd.tc import (
|
2022-09-12 00:53:15 +02:00
|
|
|
ProcedureWrapper,
|
2022-07-03 20:58:32 +02:00
|
|
|
FeedWrapper,
|
|
|
|
TcProcedureType,
|
2022-07-27 20:43:52 +02:00
|
|
|
TcQueueEntryType,
|
|
|
|
SendCbParams,
|
2022-07-03 20:58:32 +02:00
|
|
|
)
|
|
|
|
from tmtccmd.tc.pus_5_event import pack_generic_service_5_test_into
|
|
|
|
from tmtccmd.tm import SpecificApidHandlerBase, CcsdsTmHandler
|
|
|
|
from tmtccmd.logging.pus import RawTmtcTimedLogWrapper
|
2022-09-09 17:41:44 +02:00
|
|
|
from tmtccmd.config import (
|
|
|
|
CoreServiceList,
|
|
|
|
SetupWrapper,
|
|
|
|
SetupParams,
|
2022-09-12 09:39:37 +02:00
|
|
|
PreArgsParsingWrapper,
|
|
|
|
params_to_procedure_conversion,
|
2022-09-09 17:41:44 +02:00
|
|
|
)
|
2022-07-03 20:58:32 +02:00
|
|
|
from common_tmtc.pus_tm.factory_hook import pus_factory_hook
|
|
|
|
|
|
|
|
|
|
|
|
LOGGER = get_console_logger()
|
|
|
|
|
|
|
|
|
2022-09-09 17:41:44 +02:00
|
|
|
class ExampleCfdpFaultHandler(DefaultFaultHandlerBase):
|
|
|
|
def notice_of_suspension_cb(self, cond: ConditionCode):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def notice_of_cancellation_cb(self, cond: ConditionCode):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def abandoned_cb(self, cond: ConditionCode):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def ignore_cb(self, cond: ConditionCode):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2022-09-09 16:55:04 +02:00
|
|
|
class ExampleCfdpUser(CfdpUserBase):
|
|
|
|
def transaction_indication(self, transaction_id: TransactionId):
|
2022-09-14 17:35:33 +02:00
|
|
|
LOGGER.info(f"CFDP User: Start of File {transaction_id}")
|
2022-09-09 16:55:04 +02:00
|
|
|
|
|
|
|
def eof_sent_indication(self, transaction_id: TransactionId):
|
2022-09-14 17:35:33 +02:00
|
|
|
LOGGER.info(f"CFDP User: EOF sent for {transaction_id}")
|
2022-09-09 16:55:04 +02:00
|
|
|
|
|
|
|
def transaction_finished_indication(self, params: TransactionFinishedParams):
|
2022-09-14 17:35:33 +02:00
|
|
|
LOGGER.info(f"CFDP User: {params.transaction_id} finished")
|
2022-09-09 16:55:04 +02:00
|
|
|
|
|
|
|
def metadata_recv_indication(self, params: MetadataRecvParams):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def file_segment_recv_indication(self, params: FileSegmentRecvdParams):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def report_indication(self, transaction_id: TransactionId, status_report: any):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def suspended_indication(
|
|
|
|
self, transaction_id: TransactionId, cond_code: ConditionCode
|
|
|
|
):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def resumed_indication(self, transaction_id: TransactionId, progress: int):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def fault_indication(
|
|
|
|
self, transaction_id: TransactionId, cond_code: ConditionCode, progress: int
|
|
|
|
):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def abandoned_indication(
|
|
|
|
self, transaction_id: TransactionId, cond_code: ConditionCode, progress: int
|
|
|
|
):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def eof_recv_indication(self, transaction_id: TransactionId):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2022-09-09 14:58:34 +02:00
|
|
|
class CfdpCcsdsWrapper(SpecificApidHandlerBase):
|
2022-09-09 14:23:18 +02:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
cfg: LocalEntityCfg,
|
|
|
|
user: CfdpUserBase,
|
2022-09-09 16:55:04 +02:00
|
|
|
remote_cfgs: Sequence[RemoteEntityCfg],
|
|
|
|
ccsds_apid: int,
|
2022-09-09 14:23:18 +02:00
|
|
|
cfdp_seq_cnt_provider: ProvidesSeqCount,
|
|
|
|
ccsds_seq_cnt_provider: ProvidesSeqCount,
|
|
|
|
):
|
2022-09-09 15:06:58 +02:00
|
|
|
"""Wrapper helper type used to wrap PDU packets into CCSDS packets and to extract PDU
|
|
|
|
packets from CCSDS packets.
|
|
|
|
|
|
|
|
:param cfg: Local CFDP entity configuration.
|
|
|
|
:param user: User wrapper. This contains the indication callback implementations and the
|
|
|
|
virtual filestore implementation.
|
|
|
|
:param cfdp_seq_cnt_provider: Every CFDP file transfer has a transaction sequence number.
|
|
|
|
This provider is used to retrieve that sequence number.
|
|
|
|
:param ccsds_seq_cnt_provider: Each CFDP PDU is wrapped into a CCSDS space packet, and each
|
|
|
|
space packet has a dedicated sequence count. This provider is used to retrieve the
|
|
|
|
sequence count.
|
|
|
|
:param ccsds_apid: APID to use for the CCSDS space packet header wrapped around each PDU.
|
|
|
|
This is important so that the OBSW can distinguish between regular PUS packets and
|
|
|
|
CFDP packets.
|
|
|
|
"""
|
2022-09-09 14:58:34 +02:00
|
|
|
super().__init__(EXAMPLE_CFDP_APID, None)
|
2022-09-09 16:55:04 +02:00
|
|
|
self.handler = CfdpHandler(cfg, user, cfdp_seq_cnt_provider, remote_cfgs)
|
2022-09-09 14:23:18 +02:00
|
|
|
self.ccsds_seq_cnt_provider = ccsds_seq_cnt_provider
|
|
|
|
self.ccsds_apid = ccsds_apid
|
|
|
|
|
2022-09-13 11:59:29 +02:00
|
|
|
def pull_next_source_packet(self) -> Optional[Tuple[PduHolder, SpacePacket]]:
|
|
|
|
"""Retrieves the next PDU to send and wraps it into a space packet"""
|
|
|
|
next_packet = self.handler.pull_next_source_packet()
|
|
|
|
if next_packet is None:
|
|
|
|
return next_packet
|
|
|
|
sp_header = SpacePacketHeader(
|
|
|
|
packet_type=PacketTypes.TC,
|
|
|
|
apid=self.ccsds_apid,
|
|
|
|
seq_count=self.ccsds_seq_cnt_provider.get_and_increment(),
|
|
|
|
data_len=next_packet.packet_len - 1,
|
|
|
|
)
|
|
|
|
return next_packet, SpacePacket(sp_header, None, next_packet.pack())
|
|
|
|
|
|
|
|
def pull_next_dest_packet(self) -> Optional[Tuple[PduHolder, SpacePacket]]:
|
2022-09-09 14:23:18 +02:00
|
|
|
"""Retrieves the next PDU to send and wraps it into a space packet"""
|
|
|
|
next_packet = self.handler.pull_next_dest_packet()
|
|
|
|
if next_packet is None:
|
|
|
|
return next_packet
|
|
|
|
sp_header = SpacePacketHeader(
|
|
|
|
packet_type=PacketTypes.TC,
|
|
|
|
apid=self.ccsds_apid,
|
|
|
|
seq_count=self.ccsds_seq_cnt_provider.get_and_increment(),
|
|
|
|
data_len=next_packet.packet_len - 1,
|
|
|
|
)
|
2022-09-13 11:59:29 +02:00
|
|
|
return next_packet, SpacePacket(sp_header, None, next_packet.pack())
|
2022-09-09 14:23:18 +02:00
|
|
|
|
|
|
|
def confirm_dest_packet_sent(self):
|
|
|
|
self.handler.confirm_dest_packet_sent()
|
|
|
|
|
2022-09-13 11:59:29 +02:00
|
|
|
def confirm_source_packet_sent(self):
|
|
|
|
self.handler.confirm_source_packet_sent()
|
|
|
|
|
|
|
|
def __iter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __next__(
|
|
|
|
self,
|
|
|
|
) -> (
|
|
|
|
Optional[Tuple[PduHolder, SpacePacket]],
|
|
|
|
Optional[Tuple[PduHolder, SpacePacket]],
|
|
|
|
):
|
|
|
|
"""The iterator for this class will returns a tuple of optional PDUs wrapped b a
|
|
|
|
:py:class:`PduHolder`.
|
|
|
|
|
|
|
|
:return: Can be a tuple where the first entry can hold a source packet and the second entry
|
|
|
|
can be a destination packet. If both packets are None, a StopIteration will be raised.
|
|
|
|
"""
|
|
|
|
next_source_tuple = self.pull_next_source_packet()
|
|
|
|
next_dest_tuple = self.pull_next_dest_packet()
|
|
|
|
if not next_source_tuple and not next_dest_tuple:
|
|
|
|
raise StopIteration
|
|
|
|
return next_source_tuple, next_dest_tuple
|
|
|
|
|
2022-09-09 14:58:34 +02:00
|
|
|
def pass_packet(self, space_packet: SpacePacket):
|
2022-09-09 14:23:18 +02:00
|
|
|
# Unwrap the user data and pass it to the handler
|
2022-09-09 14:58:34 +02:00
|
|
|
pdu_raw = space_packet.user_data
|
2022-09-09 14:23:18 +02:00
|
|
|
pdu_base = PduFactory.from_raw(pdu_raw)
|
|
|
|
self.handler.pass_packet(pdu_base)
|
|
|
|
|
2022-09-09 14:58:34 +02:00
|
|
|
def handle_tm(self, packet: bytes, _user_args: any):
|
|
|
|
ccsds_header_raw = packet[0:6]
|
|
|
|
sp_header = SpacePacketHeader.unpack(ccsds_header_raw)
|
|
|
|
pdu = packet[6:]
|
|
|
|
sp = SpacePacket(sp_header, sec_header=None, user_data=pdu)
|
|
|
|
self.pass_packet(sp)
|
|
|
|
|
2022-09-09 14:23:18 +02:00
|
|
|
|
|
|
|
class CfdpHandler:
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
cfg: LocalEntityCfg,
|
|
|
|
user: CfdpUserBase,
|
|
|
|
seq_cnt_provider: ProvidesSeqCount,
|
2022-09-09 16:55:04 +02:00
|
|
|
remote_cfgs: Sequence[RemoteEntityCfg],
|
2022-09-09 14:23:18 +02:00
|
|
|
):
|
|
|
|
self.remote_cfg_table = RemoteEntityCfgTable()
|
2022-09-09 16:55:04 +02:00
|
|
|
self.remote_cfg_table.add_configs(remote_cfgs)
|
2022-09-09 14:23:18 +02:00
|
|
|
self.dest_handler = DestHandler(cfg, user, self.remote_cfg_table)
|
|
|
|
self.source_handler = SourceHandler(cfg, seq_cnt_provider, user)
|
|
|
|
|
2022-09-09 16:55:04 +02:00
|
|
|
def put_request(self, request: PutRequest):
|
2022-09-12 09:39:37 +02:00
|
|
|
if not self.remote_cfg_table.get_cfg(request.cfg.destination_id):
|
2022-09-09 15:21:14 +02:00
|
|
|
raise ValueError(
|
|
|
|
f"No remote CFDP config found for entity ID {request.cfg.destination_id}"
|
|
|
|
)
|
2022-09-09 14:23:18 +02:00
|
|
|
self.source_handler.put_request(
|
2022-09-12 09:39:37 +02:00
|
|
|
request, self.remote_cfg_table.get_cfg(request.cfg.destination_id)
|
2022-09-09 14:23:18 +02:00
|
|
|
)
|
|
|
|
|
2022-09-13 11:59:29 +02:00
|
|
|
def pull_next_source_packet(self) -> Optional[PduHolder]:
|
|
|
|
res = self.source_handler.state_machine()
|
|
|
|
if res.states.packet_ready:
|
|
|
|
return self.source_handler.pdu_holder
|
|
|
|
return None
|
|
|
|
|
2022-09-09 14:23:18 +02:00
|
|
|
def pull_next_dest_packet(self) -> Optional[PduHolder]:
|
|
|
|
res = self.dest_handler.state_machine()
|
|
|
|
if res.states.packet_ready:
|
|
|
|
return self.dest_handler.pdu_holder
|
|
|
|
return None
|
|
|
|
|
2022-09-13 11:59:29 +02:00
|
|
|
def __iter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __next__(self) -> (Optional[PduHolder], Optional[PduHolder]):
|
|
|
|
"""The iterator for this class will returns a tuple of optional PDUs wrapped b a
|
|
|
|
:py:class:`PduHolder`.
|
|
|
|
|
|
|
|
:return: Can be a tuple where the first entry can hold a source packet and the second entry
|
|
|
|
can be a destination packet. If both packets are None, a StopIteration will be raised.
|
|
|
|
"""
|
|
|
|
next_source_packet = self.pull_next_source_packet()
|
|
|
|
next_dest_packet = self.pull_next_dest_packet()
|
|
|
|
if not next_dest_packet and not next_source_packet:
|
|
|
|
raise StopIteration
|
|
|
|
return next_source_packet, next_dest_packet
|
|
|
|
|
2022-09-09 15:24:23 +02:00
|
|
|
def put_request_pending(self) -> bool:
|
|
|
|
return self.source_handler.states.state != CfdpStates.IDLE
|
|
|
|
|
2022-09-09 14:23:18 +02:00
|
|
|
def confirm_dest_packet_sent(self):
|
|
|
|
self.dest_handler.confirm_packet_sent_advance_fsm()
|
|
|
|
|
2022-09-13 11:59:29 +02:00
|
|
|
def confirm_source_packet_sent(self):
|
|
|
|
self.source_handler.confirm_packet_sent_advance_fsm()
|
|
|
|
|
2022-09-09 14:23:18 +02:00
|
|
|
def pass_packet(self, packet: GenericPduPacket):
|
|
|
|
"""This function routes the packets based on PDU type and directive type if applicable.
|
|
|
|
|
|
|
|
The routing is based on section 4.5 of the CFDP standard whcih specifies the PDU forwarding
|
|
|
|
procedure.
|
|
|
|
"""
|
|
|
|
if packet.pdu_type == PduType.FILE_DATA:
|
|
|
|
self.dest_handler.pass_packet(packet)
|
|
|
|
else:
|
|
|
|
if packet.directive_type in [
|
|
|
|
DirectiveType.METADATA_PDU,
|
|
|
|
DirectiveType.EOF_PDU,
|
|
|
|
DirectiveType.PROMPT_PDU,
|
|
|
|
]:
|
|
|
|
# Section b) of 4.5.3: These PDUs should always be targeted towards the file
|
|
|
|
# receiver a.k.a. the destination handler
|
|
|
|
self.dest_handler.pass_packet(packet)
|
|
|
|
elif packet.directive_type in [
|
|
|
|
DirectiveType.FINISHED_PDU,
|
|
|
|
DirectiveType.NAK_PDU,
|
|
|
|
DirectiveType.KEEP_ALIVE_PDU,
|
|
|
|
]:
|
|
|
|
# Section c) of 4.5.3: These PDUs should always be targeted towards the file sender
|
|
|
|
# a.k.a. the source handler
|
|
|
|
self.source_handler.pass_packet(packet)
|
|
|
|
elif packet.directive_type == DirectiveType.ACK_PDU:
|
|
|
|
# Section a): Recipient depends on the type of PDU that is being acknowledged.
|
|
|
|
# We can simply extract the PDU type from the raw stream. If it is an EOF PDU,
|
|
|
|
# this packet is passed to the source handler. For a finished PDU, it is
|
|
|
|
# passed to the destination handler
|
|
|
|
pdu_holder = PduHolder(packet)
|
|
|
|
ack_pdu = pdu_holder.to_ack_pdu()
|
|
|
|
if ack_pdu.directive_code_of_acked_pdu == DirectiveType.EOF_PDU:
|
|
|
|
self.source_handler.pass_packet(packet)
|
|
|
|
elif ack_pdu.directive_code_of_acked_pdu == DirectiveType.FINISHED_PDU:
|
|
|
|
self.dest_handler.pass_packet(packet)
|
|
|
|
|
|
|
|
|
2022-07-03 20:58:32 +02:00
|
|
|
class PusHandler(SpecificApidHandlerBase):
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
wrapper: VerificationWrapper,
|
|
|
|
printer: FsfwTmTcPrinter,
|
|
|
|
raw_logger: RawTmtcTimedLogWrapper,
|
|
|
|
):
|
2022-09-09 14:58:34 +02:00
|
|
|
super().__init__(EXAMPLE_PUS_APID, None)
|
2022-07-03 20:58:32 +02:00
|
|
|
self.printer = printer
|
|
|
|
self.verif_wrapper = wrapper
|
|
|
|
self.raw_logger = raw_logger
|
|
|
|
|
|
|
|
def handle_tm(self, packet: bytes, _user_args: any):
|
|
|
|
pus_factory_hook(
|
|
|
|
packet=packet,
|
|
|
|
wrapper=self.verif_wrapper,
|
|
|
|
raw_logger=self.raw_logger,
|
|
|
|
printer=self.printer,
|
|
|
|
)
|
2022-05-18 23:40:13 +02:00
|
|
|
|
|
|
|
|
2022-07-03 20:58:32 +02:00
|
|
|
class TcHandler(TcHandlerBase):
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
seq_count_provider: FileSeqCountProvider,
|
2022-09-09 15:21:14 +02:00
|
|
|
cfdp_in_ccsds_wrapper: CfdpCcsdsWrapper,
|
2022-07-03 20:58:32 +02:00
|
|
|
pus_verificator: PusVerificator,
|
|
|
|
file_logger: logging.Logger,
|
|
|
|
raw_logger: RawTmtcTimedLogWrapper,
|
|
|
|
):
|
|
|
|
super().__init__()
|
2022-09-13 11:59:29 +02:00
|
|
|
self.cfdp_handler_started = False
|
2022-09-12 09:39:37 +02:00
|
|
|
self.cfdp_dest_id = CFDP_REMOTE_ENTITY_ID
|
2022-07-03 20:58:32 +02:00
|
|
|
self.seq_count_provider = seq_count_provider
|
|
|
|
self.pus_verificator = pus_verificator
|
|
|
|
self.file_logger = file_logger
|
|
|
|
self.raw_logger = raw_logger
|
2022-07-28 16:37:01 +02:00
|
|
|
self.queue_helper = DefaultPusQueueHelper(
|
|
|
|
queue_wrapper=None,
|
2022-09-09 14:58:34 +02:00
|
|
|
pus_apid=EXAMPLE_PUS_APID,
|
2022-07-28 16:37:01 +02:00
|
|
|
seq_cnt_provider=seq_count_provider,
|
|
|
|
pus_verificator=pus_verificator,
|
|
|
|
)
|
2022-09-09 15:21:14 +02:00
|
|
|
self.cfdp_in_ccsds_wrapper = cfdp_in_ccsds_wrapper
|
2022-05-18 23:40:13 +02:00
|
|
|
|
2022-09-12 00:53:15 +02:00
|
|
|
def feed_cb(self, info: ProcedureWrapper, wrapper: FeedWrapper):
|
2022-07-28 16:37:01 +02:00
|
|
|
self.queue_helper.queue_wrapper = wrapper.queue_wrapper
|
2022-07-03 20:58:32 +02:00
|
|
|
if info.proc_type == TcProcedureType.DEFAULT:
|
2022-09-09 14:46:41 +02:00
|
|
|
self.handle_default_procedure(info)
|
|
|
|
elif info.proc_type == TcProcedureType.CFDP:
|
|
|
|
self.handle_cfdp_procedure(info)
|
|
|
|
|
2022-09-12 00:53:15 +02:00
|
|
|
def handle_default_procedure(self, info: ProcedureWrapper):
|
2022-09-09 14:46:41 +02:00
|
|
|
def_proc = info.to_def_procedure()
|
|
|
|
service = def_proc.service
|
|
|
|
op_code = def_proc.op_code
|
|
|
|
if service == CoreServiceList.SERVICE_2.value:
|
|
|
|
return pack_service_2_commands_into(op_code=op_code, q=self.queue_helper)
|
|
|
|
if service == CoreServiceList.SERVICE_3.value:
|
|
|
|
return pack_service_3_commands_into(op_code=op_code, q=self.queue_helper)
|
|
|
|
if service == CoreServiceList.SERVICE_5.value:
|
|
|
|
return pack_generic_service_5_test_into(q=self.queue_helper)
|
|
|
|
if service == CoreServiceList.SERVICE_8.value:
|
|
|
|
return pack_service_8_commands_into(op_code=op_code, q=self.queue_helper)
|
|
|
|
if service == CoreServiceList.SERVICE_11.value:
|
|
|
|
return pack_service_11_commands(op_code=op_code, q=self.queue_helper)
|
|
|
|
if service == CoreServiceList.SERVICE_17.value:
|
|
|
|
return pack_service_17_commands(op_code=op_code, q=self.queue_helper)
|
|
|
|
if service == CoreServiceList.SERVICE_20.value:
|
|
|
|
return pack_service20_commands_into(q=self.queue_helper, op_code=op_code)
|
|
|
|
if service == CoreServiceList.SERVICE_200.value:
|
|
|
|
return pack_service_200_commands_into(q=self.queue_helper, op_code=op_code)
|
|
|
|
LOGGER.warning("Invalid Service !")
|
|
|
|
|
2022-09-12 00:53:15 +02:00
|
|
|
def handle_cfdp_procedure(self, info: ProcedureWrapper):
|
2022-09-09 14:58:34 +02:00
|
|
|
cfdp_procedure = info.to_cfdp_procedure()
|
|
|
|
if cfdp_procedure.cfdp_request_type == CfdpRequestType.PUT:
|
2022-09-13 11:59:29 +02:00
|
|
|
if (
|
|
|
|
not self.cfdp_in_ccsds_wrapper.handler.put_request_pending()
|
|
|
|
and not self.cfdp_handler_started
|
|
|
|
):
|
2022-09-12 09:39:37 +02:00
|
|
|
put_req = cfdp_procedure.request_wrapper.to_put_request()
|
|
|
|
put_req.cfg.destination_id = self.cfdp_dest_id
|
2022-09-14 17:35:33 +02:00
|
|
|
LOGGER.info(
|
|
|
|
f"CFDP: Starting file put request with parameters:\n{put_req}"
|
|
|
|
)
|
2022-09-09 15:24:23 +02:00
|
|
|
self.cfdp_in_ccsds_wrapper.handler.put_request(put_req)
|
2022-09-13 11:59:29 +02:00
|
|
|
self.cfdp_handler_started = True
|
|
|
|
(
|
|
|
|
pdu_holder,
|
|
|
|
packet,
|
|
|
|
) = self.cfdp_in_ccsds_wrapper.pull_next_source_packet()
|
|
|
|
self.queue_helper.add_ccsds_tc(packet)
|
2022-09-14 17:40:39 +02:00
|
|
|
self.cfdp_in_ccsds_wrapper.confirm_source_packet_sent()
|
2022-09-13 13:54:47 +02:00
|
|
|
self.queue_helper.add_log_cmd("CFDP Source: Sending Metadata PDU")
|
2022-09-13 11:59:29 +02:00
|
|
|
(
|
|
|
|
pdu_holder,
|
|
|
|
packet,
|
|
|
|
) = self.cfdp_in_ccsds_wrapper.pull_next_source_packet()
|
|
|
|
self.queue_helper.add_ccsds_tc(packet)
|
2022-09-14 17:40:39 +02:00
|
|
|
self.cfdp_in_ccsds_wrapper.confirm_source_packet_sent()
|
2022-09-13 13:54:47 +02:00
|
|
|
self.queue_helper.add_log_cmd("CFDP Source: Sending File Data PDU")
|
2022-09-14 14:00:37 +02:00
|
|
|
(
|
|
|
|
pdu_holder,
|
|
|
|
packet,
|
|
|
|
) = self.cfdp_in_ccsds_wrapper.pull_next_source_packet()
|
|
|
|
self.queue_helper.add_log_cmd("CFDP Source: Sending EOF PDU")
|
|
|
|
self.queue_helper.add_ccsds_tc(packet)
|
2022-09-14 17:40:39 +02:00
|
|
|
self.cfdp_in_ccsds_wrapper.confirm_source_packet_sent()
|
|
|
|
self.cfdp_in_ccsds_wrapper.handler.source_handler.state_machine()
|
2022-05-18 23:40:13 +02:00
|
|
|
|
2022-07-27 14:40:25 +02:00
|
|
|
def send_cb(self, params: SendCbParams):
|
|
|
|
if params.entry.is_tc:
|
|
|
|
if params.entry.entry_type == TcQueueEntryType.PUS_TC:
|
2022-07-28 15:25:06 +02:00
|
|
|
self.handle_tc_send_cb(params)
|
2022-09-13 13:54:47 +02:00
|
|
|
elif params.entry.entry_type == TcQueueEntryType.CCSDS_TC:
|
|
|
|
cfdp_packet_in_ccsds = params.entry.to_space_packet_entry()
|
|
|
|
params.com_if.send(cfdp_packet_in_ccsds.space_packet.pack())
|
2022-07-28 15:25:06 +02:00
|
|
|
elif params.entry.entry_type == TcQueueEntryType.LOG:
|
2022-07-28 15:26:37 +02:00
|
|
|
log_entry = params.entry.to_log_entry()
|
|
|
|
LOGGER.info(log_entry.log_str)
|
|
|
|
self.file_logger.info(log_entry.log_str)
|
2022-07-28 15:25:06 +02:00
|
|
|
|
|
|
|
def handle_tc_send_cb(self, params: SendCbParams):
|
|
|
|
pus_tc_wrapper = params.entry.to_pus_tc_entry()
|
|
|
|
if (
|
2022-07-28 16:37:01 +02:00
|
|
|
pus_tc_wrapper.pus_tc.service == PusServices.S11_TC_SCHED
|
|
|
|
and pus_tc_wrapper.pus_tc.subservice == Pus11Subservices.TC_INSERT
|
2022-07-28 15:25:06 +02:00
|
|
|
):
|
2022-07-28 16:37:01 +02:00
|
|
|
wrapped_tc = PusTelecommand.unpack(pus_tc_wrapper.pus_tc.app_data[4:])
|
|
|
|
tc_info_string = f"Sending time-tagged command {wrapped_tc}"
|
|
|
|
LOGGER.info(tc_info_string)
|
|
|
|
self.file_logger.info(f"{get_current_time_string(True)}: {tc_info_string}")
|
2022-07-28 15:25:06 +02:00
|
|
|
raw_tc = pus_tc_wrapper.pus_tc.pack()
|
|
|
|
self.raw_logger.log_tc(pus_tc_wrapper.pus_tc)
|
2022-07-28 16:37:01 +02:00
|
|
|
tc_info_string = f"Sending {pus_tc_wrapper.pus_tc}"
|
2022-07-28 15:25:06 +02:00
|
|
|
LOGGER.info(tc_info_string)
|
2022-07-28 16:37:01 +02:00
|
|
|
self.file_logger.info(f"{get_current_time_string(True)}: {tc_info_string}")
|
2022-07-28 15:25:06 +02:00
|
|
|
params.com_if.send(raw_tc)
|
2022-07-03 20:58:32 +02:00
|
|
|
|
2022-09-12 00:53:15 +02:00
|
|
|
def queue_finished_cb(self, info: ProcedureWrapper):
|
2022-07-03 20:58:32 +02:00
|
|
|
if info is not None and info.proc_type == TcQueueEntryType.PUS_TC:
|
|
|
|
def_proc = info.to_def_procedure()
|
|
|
|
LOGGER.info(
|
|
|
|
f"Finished queue for service {def_proc.service} and op code {def_proc.op_code}"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-09-09 17:51:41 +02:00
|
|
|
def setup_params(hook_obj: TmTcCfgHookBase) -> SetupWrapper:
|
2022-07-03 20:58:32 +02:00
|
|
|
print(f"-- eive TMTC Commander --")
|
2022-07-27 20:43:52 +02:00
|
|
|
print(f"-- spacepackets v{spacepackets.__version__} --")
|
2022-07-03 20:58:32 +02:00
|
|
|
params = SetupParams()
|
2022-09-09 17:41:44 +02:00
|
|
|
parser_wrapper = PreArgsParsingWrapper()
|
2022-08-24 15:31:06 +02:00
|
|
|
parser_wrapper.create_default_parent_parser()
|
|
|
|
parser_wrapper.create_default_parser()
|
2022-09-08 17:52:09 +02:00
|
|
|
parser_wrapper.add_def_proc_and_cfdp_as_subparsers()
|
2022-09-09 17:41:44 +02:00
|
|
|
post_arg_parsing_wrapper = parser_wrapper.parse(hook_obj)
|
|
|
|
tmtccmd.init_printout(post_arg_parsing_wrapper.use_gui)
|
|
|
|
use_prompts = not post_arg_parsing_wrapper.use_gui
|
2022-09-09 17:51:41 +02:00
|
|
|
proc_param_wrapper = ProcedureParamsWrapper()
|
2022-09-09 17:41:44 +02:00
|
|
|
if use_prompts:
|
|
|
|
post_arg_parsing_wrapper.set_params_with_prompts(params, proc_param_wrapper)
|
|
|
|
else:
|
|
|
|
post_arg_parsing_wrapper.set_params_without_prompts(params, proc_param_wrapper)
|
2022-09-09 14:58:34 +02:00
|
|
|
params.apid = EXAMPLE_PUS_APID
|
2022-09-09 17:51:41 +02:00
|
|
|
setup_wrapper = SetupWrapper(
|
|
|
|
hook_obj=hook_obj, setup_params=params, proc_param_wrapper=proc_param_wrapper
|
|
|
|
)
|
2022-07-03 20:58:32 +02:00
|
|
|
return setup_wrapper
|
|
|
|
|
|
|
|
|
|
|
|
def setup_tmtc_handlers(
|
|
|
|
verif_wrapper: VerificationWrapper,
|
|
|
|
printer: FsfwTmTcPrinter,
|
|
|
|
raw_logger: RawTmtcTimedLogWrapper,
|
|
|
|
) -> (CcsdsTmHandler, TcHandler):
|
|
|
|
|
2022-09-09 17:41:44 +02:00
|
|
|
fh_base = ExampleCfdpFaultHandler()
|
2022-09-09 16:55:04 +02:00
|
|
|
cfdp_cfg = LocalEntityCfg(
|
|
|
|
local_entity_id=CFDP_LOCAL_ENTITY_ID,
|
|
|
|
indication_cfg=IndicationCfg(),
|
|
|
|
default_fault_handlers=fh_base,
|
|
|
|
)
|
|
|
|
remote_cfg = RemoteEntityCfg(
|
|
|
|
closure_requested=False,
|
|
|
|
entity_id=CFDP_REMOTE_ENTITY_ID,
|
|
|
|
max_file_segment_len=1024,
|
|
|
|
check_limit=None,
|
|
|
|
crc_on_transmission=False,
|
|
|
|
crc_type=ChecksumTypes.CRC_32,
|
|
|
|
default_transmission_mode=TransmissionModes.UNACKNOWLEDGED,
|
|
|
|
)
|
|
|
|
cfdp_seq_count_provider = FileSeqCountProvider(
|
2022-09-09 17:41:44 +02:00
|
|
|
max_bit_width=16, file_name=Path("seqcnt_cfdp_transaction.txt")
|
2022-09-09 16:55:04 +02:00
|
|
|
)
|
|
|
|
cfdp_ccsds_seq_count_provider = PusFileSeqCountProvider(
|
2022-09-09 17:41:44 +02:00
|
|
|
file_name=Path("seqcnt_cfdp_ccsds_.txt")
|
2022-09-09 16:55:04 +02:00
|
|
|
)
|
|
|
|
cfdp_user = ExampleCfdpUser()
|
|
|
|
cfdp_in_ccsds_handler = CfdpCcsdsWrapper(
|
|
|
|
cfg=cfdp_cfg,
|
|
|
|
remote_cfgs=[remote_cfg],
|
|
|
|
ccsds_apid=EXAMPLE_CFDP_APID,
|
|
|
|
ccsds_seq_cnt_provider=cfdp_ccsds_seq_count_provider,
|
|
|
|
cfdp_seq_cnt_provider=cfdp_seq_count_provider,
|
|
|
|
user=cfdp_user,
|
|
|
|
)
|
|
|
|
|
2022-07-03 20:58:32 +02:00
|
|
|
pus_handler = PusHandler(
|
2022-09-09 15:06:58 +02:00
|
|
|
printer=printer, raw_logger=raw_logger, wrapper=verif_wrapper
|
2022-07-03 20:58:32 +02:00
|
|
|
)
|
|
|
|
ccsds_handler = CcsdsTmHandler(None)
|
|
|
|
ccsds_handler.add_apid_handler(pus_handler)
|
|
|
|
tc_handler = TcHandler(
|
|
|
|
file_logger=printer.file_logger,
|
|
|
|
raw_logger=raw_logger,
|
|
|
|
pus_verificator=verif_wrapper.pus_verificator,
|
2022-09-09 16:55:04 +02:00
|
|
|
seq_count_provider=PusFileSeqCountProvider(
|
2022-09-09 17:41:44 +02:00
|
|
|
file_name=Path("seqcnt_pus_ccsds.txt")
|
2022-09-09 16:55:04 +02:00
|
|
|
),
|
|
|
|
cfdp_in_ccsds_wrapper=cfdp_in_ccsds_handler,
|
2022-07-03 20:58:32 +02:00
|
|
|
)
|
|
|
|
return ccsds_handler, tc_handler
|
|
|
|
|
|
|
|
|
|
|
|
def setup_backend(
|
|
|
|
setup_wrapper: SetupWrapper,
|
|
|
|
tc_handler: TcHandler,
|
|
|
|
ccsds_handler: CcsdsTmHandler,
|
|
|
|
) -> BackendBase:
|
2022-09-12 09:39:37 +02:00
|
|
|
init_proc = params_to_procedure_conversion(setup_wrapper.proc_param_wrapper)
|
2022-05-18 23:40:13 +02:00
|
|
|
tmtc_backend = tmtccmd.create_default_tmtc_backend(
|
2022-09-09 17:51:41 +02:00
|
|
|
setup_wrapper=setup_wrapper,
|
|
|
|
tm_handler=ccsds_handler,
|
|
|
|
tc_handler=tc_handler,
|
2022-09-12 00:53:15 +02:00
|
|
|
init_procedure=init_proc.base,
|
2022-05-18 23:40:13 +02:00
|
|
|
)
|
2022-07-03 20:58:32 +02:00
|
|
|
tmtccmd.start(tmtc_backend=tmtc_backend, hook_obj=setup_wrapper.hook_obj)
|
|
|
|
return tmtc_backend
|