eive-tmtc/tmtcc.py

255 lines
8.6 KiB
Python
Raw Normal View History

2022-07-04 18:09:24 +02:00
#!/usr/bin/env python3
2022-07-04 15:22:53 +02:00
import logging
2022-05-17 11:13:32 +02:00
import sys
2022-07-04 18:09:24 +02:00
import time
2023-11-13 08:50:51 +01:00
from importlib.metadata import version
2022-09-16 17:28:19 +02:00
from pathlib import Path
2023-11-13 08:50:51 +01:00
from typing import Tuple
2022-07-04 15:22:53 +02:00
import tmtccmd
2022-09-16 17:37:01 +02:00
from spacepackets.cfdp import (
ChecksumType,
TransmissionMode,
)
2023-11-13 08:50:51 +01:00
from spacepackets.ecss import PusVerificator
from spacepackets.version import get_version as get_sp_version
from tmtccmd import BackendBase
2023-11-13 09:05:34 +01:00
from tmtccmd.cfdp.handler import RemoteEntityCfgTable
2022-09-16 17:37:01 +02:00
from tmtccmd.cfdp.mib import (
IndicationCfg,
2023-11-13 08:50:51 +01:00
LocalEntityCfg,
2022-09-16 17:37:01 +02:00
RemoteEntityCfg,
)
from tmtccmd.config import (
SetupWrapper,
2023-11-13 08:50:51 +01:00
default_json_path,
2022-09-16 17:37:01 +02:00
params_to_procedure_conversion,
)
from tmtccmd.config.args import (
PreArgsParsingWrapper,
ProcedureParamsWrapper,
2023-11-13 08:50:51 +01:00
SetupParams,
)
from tmtccmd.core import BackendRequest
from tmtccmd.fsfw.tmtc_printer import FsfwTmTcPrinter
from tmtccmd.logging import add_colorlog_console_logger
from tmtccmd.logging.pus import (
RawTmtcTimedLogWrapper,
RegularTmtcLogWrapper,
TimedLogWhen,
2022-09-16 17:37:01 +02:00
)
2023-11-13 08:50:51 +01:00
from tmtccmd.pus import VerificationWrapper
2023-11-13 11:12:18 +01:00
from tmtccmd.tmtc import CcsdsTmHandler
2023-11-13 08:50:51 +01:00
from tmtccmd.util import FileSeqCountProvider, PusFileSeqCountProvider
2023-02-01 19:43:25 +01:00
from eive_tmtc import APP_LOGGER
2023-11-13 11:12:18 +01:00
from eive_tmtc.pus_tm.pus_handler import PusHandler, UnknownApidHandler
2023-11-13 08:50:51 +01:00
from eive_tmtc.cfdp.fault_handler import EiveCfdpFaultHandler
2023-11-13 11:12:18 +01:00
from eive_tmtc.cfdp.handler import CfdpInCcsdsHandler
2023-11-13 08:50:51 +01:00
from eive_tmtc.cfdp.tm import CfdpInCcsdsWrapper
2023-11-13 09:05:34 +01:00
from eive_tmtc.cfdp.user import EiveCfdpUser, EiveCheckTimerProvider
2022-11-29 16:53:29 +01:00
from eive_tmtc.config.definitions import (
2022-09-16 17:37:01 +02:00
CFDP_APID,
CFDP_LOCAL_ENTITY_ID,
CFDP_REMOTE_ENTITY_ID,
2023-11-13 08:50:51 +01:00
PUS_APID,
2022-09-16 17:37:01 +02:00
)
2022-11-29 16:53:29 +01:00
from eive_tmtc.config.hook import EiveHookObject
2023-11-13 08:50:51 +01:00
from eive_tmtc.pus_tc.tc_handler import TcHandler
2022-07-04 15:22:53 +02:00
2023-02-01 19:43:25 +01:00
_LOGGER = APP_LOGGER
_LOG_LEVEL = logging.INFO
2022-07-04 15:22:53 +02:00
# Put rotating file logger parameters here for quick changes
ROTATING_TIMED_LOGGER_INTERVAL_WHEN = TimedLogWhen.PER_MINUTE
ROTATING_TIMED_LOGGER_INTERVAL = 30
class CustomCcsdsTmHandler(CcsdsTmHandler):
def user_hook(self, apid: int, packet: bytes):
_LOGGER.debug(f"Received packet {packet.hex(sep=',')} with APID {apid}")
2022-07-04 15:22:53 +02:00
2023-11-13 08:50:51 +01:00
def setup_params() -> Tuple[SetupWrapper, int]:
2022-07-04 18:09:24 +02:00
hook_obj = EiveHookObject(default_json_path())
params = SetupParams()
2022-09-16 17:28:19 +02:00
parser_wrapper = PreArgsParsingWrapper()
2022-08-19 12:38:18 +02:00
parser_wrapper.create_default_parent_parser()
parser_wrapper.create_default_parser()
2023-07-10 16:03:08 +02:00
tmtc_parser, cfdp_parser = parser_wrapper.add_def_proc_and_cfdp_as_subparsers()
tmtc_parser.add_argument(
"--hk",
help="HK output level",
default=2,
)
2023-01-31 15:41:51 +01:00
post_arg_parsing_wrapper = parser_wrapper.parse(
setup_params=params, hook_obj=hook_obj
)
2022-09-16 17:28:19 +02:00
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:
2023-01-31 12:56:13 +01:00
post_arg_parsing_wrapper.set_params_with_prompts(proc_param_wrapper)
2022-09-16 17:28:19 +02:00
else:
2023-01-31 12:56:13 +01:00
post_arg_parsing_wrapper.set_params_without_prompts(proc_param_wrapper)
2023-08-29 21:31:27 +02:00
if hasattr(post_arg_parsing_wrapper.args_raw, "hk"):
hk_level = int(post_arg_parsing_wrapper.args_raw.hk)
else:
hk_level = 0
2022-07-04 18:09:24 +02:00
params.apid = PUS_APID
2023-01-31 12:56:13 +01:00
if params.com_if is None:
raise ValueError("could not determine a COM interface.")
2022-09-16 17:28:19 +02:00
setup_wrapper = SetupWrapper(
2022-09-16 17:37:01 +02:00
hook_obj=hook_obj, setup_params=params, proc_param_wrapper=proc_param_wrapper
2022-09-16 17:28:19 +02:00
)
2023-07-10 16:03:08 +02:00
return setup_wrapper, hk_level
2022-07-04 18:09:24 +02:00
2022-09-16 17:28:19 +02:00
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,
)
2023-08-29 22:34:57 +02:00
self_as_remote = RemoteEntityCfg(
closure_requested=False,
entity_id=CFDP_LOCAL_ENTITY_ID,
max_file_segment_len=990,
2023-11-10 19:23:06 +01:00
max_packet_len=1024,
check_limit=5,
2023-08-29 22:34:57 +02:00
crc_on_transmission=False,
crc_type=ChecksumType.CRC_32,
2023-08-29 23:28:57 +02:00
default_transmission_mode=TransmissionMode.UNACKNOWLEDGED,
2023-08-29 22:34:57 +02:00
)
2022-09-16 17:28:19 +02:00
remote_cfg = RemoteEntityCfg(
closure_requested=False,
entity_id=CFDP_REMOTE_ENTITY_ID,
2023-02-24 15:49:37 +01:00
max_file_segment_len=990,
2023-11-10 19:23:06 +01:00
max_packet_len=1024,
check_limit=5,
2022-09-16 17:28:19 +02:00
crc_on_transmission=False,
crc_type=ChecksumType.CRC_32,
default_transmission_mode=TransmissionMode.UNACKNOWLEDGED,
)
2023-11-13 09:05:34 +01:00
check_timer_provider = EiveCheckTimerProvider()
2022-09-16 17:28:19 +02:00
cfdp_seq_count_provider = FileSeqCountProvider(
max_bit_width=16, file_name=Path("seqcnt_cfdp_transaction.txt")
)
cfdp_ccsds_seq_count_provider = PusFileSeqCountProvider(
2022-12-15 11:10:33 +01:00
file_name=Path("seqcnt_cfdp_in_ccsds.txt")
2022-09-16 17:28:19 +02:00
)
cfdp_user = EiveCfdpUser()
cfdp_in_ccsds_handler = CfdpInCcsdsHandler(
cfg=cfdp_cfg,
2023-11-13 09:05:34 +01:00
check_timer_provider=check_timer_provider,
remote_cfg_table=RemoteEntityCfgTable([remote_cfg, self_as_remote]),
2022-09-16 17:28:19 +02:00
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(
2022-07-04 18:09:24 +02:00
verificator: PusVerificator,
printer: FsfwTmTcPrinter,
raw_logger: RawTmtcTimedLogWrapper,
2022-08-08 16:32:18 +02:00
gui: bool,
hk_level: int,
2023-11-13 08:50:51 +01:00
) -> Tuple[CcsdsTmHandler, TcHandler]:
2022-09-16 17:28:19 +02:00
cfdp_in_ccsds_wrapper = setup_cfdp_handler()
2023-02-01 15:58:34 +01:00
verification_wrapper = VerificationWrapper(
verificator, _LOGGER, printer.file_logger
)
2023-07-10 16:03:08 +02:00
pus_handler = PusHandler(verification_wrapper, printer, raw_logger, hk_level)
ccsds_handler = CustomCcsdsTmHandler(generic_handler=UnknownApidHandler(None))
2022-07-04 18:09:24 +02:00
ccsds_handler.add_apid_handler(pus_handler)
2022-09-16 17:28:19 +02:00
ccsds_handler.add_apid_handler(cfdp_in_ccsds_wrapper)
2022-07-08 16:25:46 +02:00
seq_count_provider = PusFileSeqCountProvider()
2022-07-04 18:09:24 +02:00
tc_handler = TcHandler(
seq_count_provider=seq_count_provider,
pus_verificator=verificator,
2022-10-27 15:33:25 +02:00
high_level_file_logger=printer.file_logger,
2022-10-27 15:32:50 +02:00
raw_pus_logger=raw_logger,
2022-08-08 16:32:18 +02:00
gui=gui,
2023-08-29 21:41:29 +02:00
cfdp_in_ccsds_handler=cfdp_in_ccsds_wrapper.handler,
2022-07-04 18:09:24 +02:00
)
return ccsds_handler, tc_handler
2022-05-17 11:13:32 +02:00
2022-07-04 18:09:24 +02:00
def setup_backend(
setup_wrapper: SetupWrapper,
tc_handler: TcHandler,
ccsds_handler: CcsdsTmHandler,
) -> BackendBase:
2022-09-16 17:28:19 +02:00
init_proc = params_to_procedure_conversion(setup_wrapper.proc_param_wrapper)
2022-05-17 11:13:32 +02:00
tmtc_backend = tmtccmd.create_default_tmtc_backend(
2022-09-16 17:37:01 +02:00
setup_wrapper=setup_wrapper,
tm_handler=ccsds_handler,
tc_handler=tc_handler,
init_procedure=init_proc,
2022-07-04 18:09:24 +02:00
)
tmtccmd.start(tmtc_backend=tmtc_backend, hook_obj=setup_wrapper.hook_obj)
return tmtc_backend
2023-06-19 17:16:00 +02:00
def main(): # noqa C901: Complexity okay here.
2023-09-12 13:01:40 +02:00
print(f"-- eive tmtc v{version('eive-tmtc')} --")
2023-09-12 13:03:54 +02:00
print(f"-- spacepackets v{get_sp_version()} --")
2023-02-01 11:17:04 +01:00
add_colorlog_console_logger(_LOGGER)
# TODO: -V CLI argument to enable this?
_LOGGER.setLevel(_LOG_LEVEL)
2022-07-04 18:09:24 +02:00
try:
2023-07-10 16:03:08 +02:00
setup_wrapper, hk_level = setup_params()
2022-07-04 18:09:24 +02:00
except KeyboardInterrupt as e:
2023-02-01 11:17:04 +01:00
_LOGGER.info(f"{e}. Exiting")
2022-07-04 18:09:24 +02:00
sys.exit(0)
2023-02-01 11:17:04 +01:00
2022-07-04 18:09:24 +02:00
tmtc_logger = RegularTmtcLogWrapper()
printer = FsfwTmTcPrinter(tmtc_logger.logger)
raw_logger = RawTmtcTimedLogWrapper(
when=ROTATING_TIMED_LOGGER_INTERVAL_WHEN,
2022-08-17 11:19:23 +02:00
interval=ROTATING_TIMED_LOGGER_INTERVAL,
)
2022-07-04 18:09:24 +02:00
pus_verificator = PusVerificator()
2022-09-16 17:28:19 +02:00
ccsds_handler, tc_handler = setup_tmtc_handlers(
2023-07-10 16:03:08 +02:00
pus_verificator, printer, raw_logger, setup_wrapper.params.use_gui, hk_level
2022-07-08 16:25:46 +02:00
)
2022-07-04 18:09:24 +02:00
tmtccmd.setup(setup_wrapper)
tmtc_backend = setup_backend(
setup_wrapper=setup_wrapper, ccsds_handler=ccsds_handler, tc_handler=tc_handler
2022-05-17 11:13:32 +02:00
)
2022-07-04 18:09:24 +02:00
try:
while True:
state = tmtc_backend.periodic_op(None)
2023-09-25 17:41:45 +02:00
tc_handler.cfdp_in_ccsds_handler.state_machine()
2022-07-04 18:09:24 +02:00
if state.request == BackendRequest.TERMINATION_NO_ERROR:
sys.exit(0)
elif state.request == BackendRequest.DELAY_IDLE:
2023-02-01 11:17:04 +01:00
_LOGGER.info("TMTC Client in IDLE mode")
2022-07-04 18:09:24 +02:00
time.sleep(3.0)
elif state.request == BackendRequest.DELAY_LISTENER:
2023-09-06 11:45:32 +02:00
if tc_handler.proxy_op:
time.sleep(0.1)
continue
2022-10-21 11:28:33 +02:00
if tc_handler.cfdp_done():
2023-02-01 11:17:04 +01:00
_LOGGER.info("CFDP transaction done, closing client")
2022-10-21 11:28:33 +02:00
sys.exit(0)
2022-08-11 18:10:15 +02:00
time.sleep(0.5)
2022-07-04 18:09:24 +02:00
elif state.request == BackendRequest.DELAY_CUSTOM:
2022-08-11 18:10:15 +02:00
if state.next_delay.total_seconds() < 0.5:
time.sleep(state.next_delay.total_seconds())
else:
time.sleep(0.5)
2022-07-04 18:09:24 +02:00
elif state.request == BackendRequest.CALL_NEXT:
pass
except KeyboardInterrupt:
sys.exit(0)
if __name__ == "__main__":
main()