From 91f85537ce9903514c411c02654410bc7489d6f4 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 16 Sep 2022 17:28:19 +0200 Subject: [PATCH] CFDP integration --- .gitignore | 2 +- config/definitions.py | 5 ++ config/hook.py | 2 +- tmtcc.py | 151 ++++++++++++++++++++++++++++++++++++++---- 4 files changed, 144 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 9e397a4..0133303 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,4 @@ log /scex_conf.json /tmtc_conf.json -/seqcnt.txt +/seqcnt*.txt diff --git a/config/definitions.py b/config/definitions.py index 8e2c76e..4cec9cf 100644 --- a/config/definitions.py +++ b/config/definitions.py @@ -6,9 +6,14 @@ import enum +from spacepackets.util import UnsignedByteField PUS_APID = 0x65 SPACE_PACKET_IDS = (0x08 << 8 | PUS_APID,) +CFDP_APID = 0x66 + +CFDP_LOCAL_ENTITY_ID = UnsignedByteField(byte_len=2, val=1) +CFDP_REMOTE_ENTITY_ID = UnsignedByteField(byte_len=2, val=CFDP_APID) class CustomServiceList(str, enum.Enum): diff --git a/config/hook.py b/config/hook.py index ca16430..1e73b2a 100644 --- a/config/hook.py +++ b/config/hook.py @@ -25,7 +25,7 @@ class EiveHookObject(TmTcCfgHookBase): cfg = create_com_interface_cfg_default( com_if_key=com_if_key, - json_cfg_path=self.json_cfg_path, + json_cfg_path=self.cfg_path, space_packet_ids=SPACE_PACKET_IDS, ) return create_com_interface_default(cfg) diff --git a/tmtcc.py b/tmtcc.py index e74171f..c7d3206 100755 --- a/tmtcc.py +++ b/tmtcc.py @@ -3,7 +3,14 @@ import logging import sys import time import traceback +from pathlib import Path +from spacepackets import SpacePacketHeader, SpacePacket +from spacepackets.cfdp import ConditionCode, ChecksumType, TransmissionMode +from tmtccmd.cfdp import CfdpUserBase, TransactionId +from tmtccmd.cfdp.handler import CfdpInCcsdsHandler +from tmtccmd.cfdp.mib import DefaultFaultHandlerBase, LocalEntityCfg, IndicationCfg, RemoteEntityCfg +from tmtccmd.cfdp.user import TransactionFinishedParams, MetadataRecvParams, FileSegmentRecvdParams from tmtccmd.tc.handler import SendCbParams try: @@ -41,16 +48,17 @@ from tmtccmd.tm import SpecificApidHandlerBase, GenericApidHandlerBase, CcsdsTmH from tmtccmd.core import BackendRequest from tmtccmd.logging import get_current_time_string from tmtccmd.tc import ( - ProcedureHelper, + ProcedureWrapper, FeedWrapper, TcProcedureType, TcQueueEntryType, DefaultPusQueueHelper, ) -from tmtccmd.config import default_json_path, SetupWrapper -from tmtccmd.config.args import SetupParams, ArgParserWrapper +from tmtccmd.config import default_json_path, SetupWrapper, params_to_procedure_conversion +from tmtccmd.config.args import SetupParams, PreArgsParsingWrapper, \ + ProcedureParamsWrapper from config import __version__ -from config.definitions import PUS_APID +from config.definitions import PUS_APID, CFDP_APID, CFDP_LOCAL_ENTITY_ID, CFDP_REMOTE_ENTITY_ID from config.hook import EiveHookObject from pus_tm.factory_hook import pus_factory_hook from pus_tc.procedure_packer import handle_default_procedure @@ -63,6 +71,61 @@ ROTATING_TIMED_LOGGER_INTERVAL_WHEN = TimedLogWhen.PER_MINUTE ROTATING_TIMED_LOGGER_INTERVAL = 30 +class EiveCfdpFaultHandler(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 + + +class EiveCfdpUser(CfdpUserBase): + def transaction_indication(self, transaction_id: TransactionId): + LOGGER.info(f"CFDP User: Start of File {transaction_id}") + + def eof_sent_indication(self, transaction_id: TransactionId): + LOGGER.info(f"CFDP User: EOF sent for {transaction_id}") + + def transaction_finished_indication(self, params: TransactionFinishedParams): + LOGGER.info(f"CFDP User: {params.transaction_id} finished") + + 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 + + class PusHandler(SpecificApidHandlerBase): def __init__( self, @@ -84,6 +147,19 @@ class UnknownApidHandler(GenericApidHandlerBase): LOGGER.warning(f"Packet with unknwon APID {apid} detected") +class CfdpInCcsdsWrapper(SpecificApidHandlerBase): + def __init__(self, cfdp_in_ccsds_handler: CfdpInCcsdsHandler): + super().__init__(CFDP_APID, None) + self.handler = cfdp_in_ccsds_handler + + 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.handler.pass_packet(sp) + + class TcHandler(TcHandlerBase): def __init__( self, @@ -106,7 +182,7 @@ class TcHandler(TcHandlerBase): pus_verificator=pus_verificator, ) - def feed_cb(self, info: ProcedureHelper, wrapper: FeedWrapper): + def feed_cb(self, info: ProcedureWrapper, wrapper: FeedWrapper): self.queue_helper.queue_wrapper = wrapper.queue_wrapper if info.proc_type == TcProcedureType.DEFAULT: handle_default_procedure(self, info.to_def_procedure(), self.queue_helper) @@ -135,7 +211,7 @@ class TcHandler(TcHandlerBase): LOGGER.info(log_entry.log_str) self.file_logger.info(log_entry.log_str) - def queue_finished_cb(self, info: ProcedureHelper): + def queue_finished_cb(self, info: ProcedureWrapper): if info is not None and info.proc_type == TcQueueEntryType.PUS_TC: def_proc = info.to_def_procedure() LOGGER.info( @@ -148,28 +224,73 @@ def setup_params() -> SetupWrapper: print(f"-- spacepackets v{spacepackets.__version__} --") hook_obj = EiveHookObject(default_json_path()) params = SetupParams() - parser_wrapper = ArgParserWrapper(hook_obj) + parser_wrapper = PreArgsParsingWrapper() parser_wrapper.create_default_parent_parser() parser_wrapper.create_default_parser() parser_wrapper.add_def_proc_and_cfdp_as_subparsers() - parser_wrapper.parse() - tmtccmd.init_printout(parser_wrapper.use_gui) - parser_wrapper.set_params(params) + 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 + proc_param_wrapper = ProcedureParamsWrapper() + 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) params.apid = PUS_APID - setup_wrapper = SetupWrapper(hook_obj=hook_obj, setup_params=params) + setup_wrapper = SetupWrapper( + hook_obj=hook_obj, + setup_params=params, + proc_param_wrapper=proc_param_wrapper + ) return setup_wrapper -def setup_tmtc( +def setup_cfdp_handler() -> CfdpInCcsdsWrapper: + fh_base = EiveCfdpFaultHandler() + 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=ChecksumType.CRC_32, + default_transmission_mode=TransmissionMode.UNACKNOWLEDGED, + ) + cfdp_seq_count_provider = FileSeqCountProvider( + max_bit_width=16, file_name=Path("seqcnt_cfdp_transaction.txt") + ) + cfdp_ccsds_seq_count_provider = PusFileSeqCountProvider( + file_name=Path("seqcnt_cfdp_ccsds_.txt") + ) + cfdp_user = EiveCfdpUser() + cfdp_in_ccsds_handler = CfdpInCcsdsHandler( + cfg=cfdp_cfg, + remote_cfgs=[remote_cfg], + ccsds_apid=CFDP_APID, + ccsds_seq_cnt_provider=cfdp_ccsds_seq_count_provider, + cfdp_seq_cnt_provider=cfdp_seq_count_provider, + user=cfdp_user, + ) + return CfdpInCcsdsWrapper(cfdp_in_ccsds_handler) + + +def setup_tmtc_handlers( verificator: PusVerificator, printer: FsfwTmTcPrinter, raw_logger: RawTmtcTimedLogWrapper, gui: bool, ) -> (CcsdsTmHandler, TcHandler): + cfdp_in_ccsds_wrapper = setup_cfdp_handler() verification_wrapper = VerificationWrapper(verificator, LOGGER, printer.file_logger) pus_handler = PusHandler(verification_wrapper, printer, raw_logger) ccsds_handler = CcsdsTmHandler(generic_handler=UnknownApidHandler(None)) ccsds_handler.add_apid_handler(pus_handler) + ccsds_handler.add_apid_handler(cfdp_in_ccsds_wrapper) seq_count_provider = PusFileSeqCountProvider() tc_handler = TcHandler( seq_count_provider=seq_count_provider, @@ -186,8 +307,10 @@ def setup_backend( tc_handler: TcHandler, ccsds_handler: CcsdsTmHandler, ) -> BackendBase: + init_proc = params_to_procedure_conversion(setup_wrapper.proc_param_wrapper) tmtc_backend = tmtccmd.create_default_tmtc_backend( - setup_wrapper=setup_wrapper, tm_handler=ccsds_handler, tc_handler=tc_handler + setup_wrapper=setup_wrapper, tm_handler=ccsds_handler, tc_handler=tc_handler, + init_procedure=init_proc ) tmtccmd.start(tmtc_backend=tmtc_backend, hook_obj=setup_wrapper.hook_obj) return tmtc_backend @@ -206,7 +329,7 @@ def main(): interval=ROTATING_TIMED_LOGGER_INTERVAL, ) pus_verificator = PusVerificator() - ccsds_handler, tc_handler = setup_tmtc( + ccsds_handler, tc_handler = setup_tmtc_handlers( pus_verificator, printer, raw_logger, setup_wrapper.params.use_gui )