Compare commits
23 Commits
v5.4.2
...
8d6ca602f2
Author | SHA1 | Date | |
---|---|---|---|
8d6ca602f2
|
|||
c0bd5f572c
|
|||
25c7decb1e
|
|||
cc7b1d3331
|
|||
948f3a1a41
|
|||
8743f59b56
|
|||
2cc4a18c1e | |||
b1fbad39e3 | |||
de57b9da5b | |||
55624f0447 | |||
9841076699
|
|||
f1876681fd | |||
14b558b7f7
|
|||
54a7c3566f
|
|||
011be9837e
|
|||
88161ed125
|
|||
f02230804d | |||
8ddcc37c74 | |||
b50c75c13c | |||
36799ef51d
|
|||
772ef5b323
|
|||
2f8bed4581
|
|||
72def77d40
|
@@ -10,6 +10,12 @@ list yields a list of all related PRs for each release.
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v5.4.3] 2023-08-15
|
||||
|
||||
## Added
|
||||
|
||||
- PLOC SUPV HK parsing.
|
||||
|
||||
# [v5.4.2] 2023-08-15
|
||||
|
||||
## Added
|
||||
|
@@ -1,4 +1,4 @@
|
||||
__version__ = "5.4.2"
|
||||
__version__ = "5.4.3"
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
@@ -6,7 +6,7 @@ from pathlib import Path
|
||||
SW_NAME = "eive-tmtc"
|
||||
VERSION_MAJOR = 5
|
||||
VERSION_MINOR = 4
|
||||
VERSION_REVISION = 2
|
||||
VERSION_REVISION = 3
|
||||
|
||||
EIVE_TMTC_ROOT = Path(__file__).parent
|
||||
PACKAGE_ROOT = EIVE_TMTC_ROOT.parent
|
||||
|
0
eive_tmtc/cfdp/__init__.py
Normal file
0
eive_tmtc/cfdp/__init__.py
Normal file
16
eive_tmtc/cfdp/fault_handler.py
Normal file
16
eive_tmtc/cfdp/fault_handler.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from spacepackets.cfdp import ConditionCode
|
||||
from tmtccmd.cfdp.mib import DefaultFaultHandlerBase
|
||||
|
||||
|
||||
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
|
31
eive_tmtc/cfdp/tm.py
Normal file
31
eive_tmtc/cfdp/tm.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import logging
|
||||
|
||||
from eive_tmtc.config.definitions import CFDP_APID
|
||||
from spacepackets.ccsds import SPACE_PACKET_HEADER_SIZE
|
||||
from spacepackets.cfdp import PduFactory, PduType, DirectiveType
|
||||
from tmtccmd.cfdp.handler import CfdpInCcsdsHandler
|
||||
from tmtccmd.tm import SpecificApidHandlerBase
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
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):
|
||||
# Ignore the space packet header. Its only purpose is to use the same protocol and
|
||||
# have a seaprate APID for space packets. If this function is called, the APID is correct.
|
||||
pdu = packet[SPACE_PACKET_HEADER_SIZE:]
|
||||
pdu_base = PduFactory.from_raw(pdu)
|
||||
if pdu_base.pdu_type == PduType.FILE_DATA:
|
||||
_LOGGER.info("Received File Data PDU TM")
|
||||
else:
|
||||
if pdu_base.directive_type == DirectiveType.FINISHED_PDU:
|
||||
_LOGGER.info("Received Finished PDU TM")
|
||||
else:
|
||||
_LOGGER.info(
|
||||
f"Received File Directive PDU with type {pdu_base.directive_type!r} TM"
|
||||
)
|
||||
self.handler.pass_pdu_packet(pdu_base)
|
52
eive_tmtc/cfdp/user.py
Normal file
52
eive_tmtc/cfdp/user.py
Normal file
@@ -0,0 +1,52 @@
|
||||
import logging
|
||||
|
||||
from spacepackets.cfdp import ConditionCode
|
||||
from tmtccmd.cfdp import CfdpUserBase, TransactionId
|
||||
from tmtccmd.cfdp.user import (
|
||||
TransactionFinishedParams,
|
||||
MetadataRecvParams,
|
||||
FileSegmentRecvdParams,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
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
|
@@ -357,7 +357,6 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path
|
||||
0x3a02;MQI_Full;No space left for more messages;2;MESSAGE_QUEUE_IF;fsfw/src/fsfw/ipc/MessageQueueIF.h
|
||||
0x3a03;MQI_NoReplyPartner;Returned if a reply method was called without partner;3;MESSAGE_QUEUE_IF;fsfw/src/fsfw/ipc/MessageQueueIF.h
|
||||
0x3a04;MQI_DestinationInvalid;Returned if the target destination is invalid.;4;MESSAGE_QUEUE_IF;fsfw/src/fsfw/ipc/MessageQueueIF.h
|
||||
0x3b00;SPH_ConnBroken;No description;0;SEMAPHORE_IF;fsfw/src/fsfw/osal/common/TcpTmTcServer.h
|
||||
0x3b01;SPH_SemaphoreTimeout;No description;1;SEMAPHORE_IF;fsfw/src/fsfw/tasks/SemaphoreIF.h
|
||||
0x3b02;SPH_SemaphoreNotOwned;No description;2;SEMAPHORE_IF;fsfw/src/fsfw/tasks/SemaphoreIF.h
|
||||
0x3b03;SPH_SemaphoreInvalid;No description;3;SEMAPHORE_IF;fsfw/src/fsfw/tasks/SemaphoreIF.h
|
||||
@@ -373,6 +372,7 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path
|
||||
0x3e05;HKM_DatasetNotFound;No description;5;HOUSEKEEPING_MANAGER;fsfw/src/fsfw/datapoollocal/LocalDataPoolManager.h
|
||||
0x3f01;DLEE_StreamTooShort;No description;1;DLE_ENCODER;fsfw/src/fsfw/globalfunctions/DleEncoder.h
|
||||
0x3f02;DLEE_DecodingError;No description;2;DLE_ENCODER;fsfw/src/fsfw/globalfunctions/DleEncoder.h
|
||||
0x4100;PUS9_ConnBroken;No description;0;PUS_SERVICE_9;fsfw/src/fsfw/osal/common/TcpTmTcServer.h
|
||||
0x4201;PUS11_InvalidTypeTimeWindow;No description;1;PUS_SERVICE_11;fsfw/src/fsfw/pus/Service11TelecommandScheduling.h
|
||||
0x4202;PUS11_InvalidTimeWindow;No description;2;PUS_SERVICE_11;fsfw/src/fsfw/pus/Service11TelecommandScheduling.h
|
||||
0x4203;PUS11_TimeshiftingNotPossible;No description;3;PUS_SERVICE_11;fsfw/src/fsfw/pus/Service11TelecommandScheduling.h
|
||||
@@ -402,9 +402,9 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path
|
||||
0x4403;UXOS_CommandError;Command execution failed;3;LINUX_OSAL;fsfw/src/fsfw_hal/linux/CommandExecutor.h
|
||||
0x4404;UXOS_NoCommandLoadedOrPending;;4;LINUX_OSAL;fsfw/src/fsfw_hal/linux/CommandExecutor.h
|
||||
0x4406;UXOS_PcloseCallError;No description;6;LINUX_OSAL;fsfw/src/fsfw_hal/linux/CommandExecutor.h
|
||||
0x4500;HSPI_OpeningFileFailed;No description;0;HAL_SPI;fsfw/src/fsfw_hal/common/spi/spiCommon.h
|
||||
0x4501;HSPI_FullDuplexTransferFailed;No description;1;HAL_SPI;fsfw/src/fsfw_hal/common/spi/spiCommon.h
|
||||
0x4502;HSPI_HalfDuplexTransferFailed;No description;2;HAL_SPI;fsfw/src/fsfw_hal/common/spi/spiCommon.h
|
||||
0x4500;HSPI_HalTimeoutRetval;No description;0;HAL_SPI;fsfw/src/fsfw_hal/stm32h7/spi/spiDefinitions.h
|
||||
0x4501;HSPI_HalBusyRetval;No description;1;HAL_SPI;fsfw/src/fsfw_hal/stm32h7/spi/spiDefinitions.h
|
||||
0x4502;HSPI_HalErrorRetval;No description;2;HAL_SPI;fsfw/src/fsfw_hal/stm32h7/spi/spiDefinitions.h
|
||||
0x4503;HSPI_Timeout;No description;3;HAL_SPI;fsfw/src/fsfw_hal/common/spi/spiCommon.h
|
||||
0x4504;HSPI_Busy;No description;4;HAL_SPI;fsfw/src/fsfw_hal/common/spi/spiCommon.h
|
||||
0x4505;HSPI_GenericError;No description;5;HAL_SPI;fsfw/src/fsfw_hal/common/spi/spiCommon.h
|
||||
|
|
161
eive_tmtc/pus_tc/tc_handler.py
Normal file
161
eive_tmtc/pus_tc/tc_handler.py
Normal file
@@ -0,0 +1,161 @@
|
||||
import logging
|
||||
from typing import cast
|
||||
|
||||
from eive_tmtc.config.definitions import (
|
||||
CFDP_REMOTE_ENTITY_ID,
|
||||
PUS_APID,
|
||||
CFDP_LOCAL_ENTITY_ID,
|
||||
)
|
||||
from eive_tmtc.pus_tc.procedure_packer import handle_default_procedure
|
||||
from tmtccmd import TcHandlerBase, ProcedureWrapper
|
||||
from tmtccmd.cfdp.defs import CfdpRequestType
|
||||
from tmtccmd.cfdp.handler import CfdpInCcsdsHandler
|
||||
from tmtccmd.logging import get_current_time_string
|
||||
from tmtccmd.logging.pus import RawTmtcTimedLogWrapper
|
||||
from tmtccmd.tc import (
|
||||
DefaultPusQueueHelper,
|
||||
QueueWrapper,
|
||||
FeedWrapper,
|
||||
TcProcedureType,
|
||||
SendCbParams,
|
||||
TcQueueEntryType,
|
||||
)
|
||||
from tmtccmd.config import (
|
||||
cfdp_put_req_params_to_procedure,
|
||||
cfdp_req_to_put_req_proxy_get_req,
|
||||
)
|
||||
from spacepackets.ecss import PusVerificator
|
||||
from tmtccmd.util import FileSeqCountProvider
|
||||
from spacepackets.cfdp import PduHolder, DirectiveType
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TcHandler(TcHandlerBase):
|
||||
def __init__(
|
||||
self,
|
||||
seq_count_provider: FileSeqCountProvider,
|
||||
cfdp_in_ccsds_handler: CfdpInCcsdsHandler,
|
||||
pus_verificator: PusVerificator,
|
||||
high_level_file_logger: logging.Logger,
|
||||
raw_pus_logger: RawTmtcTimedLogWrapper,
|
||||
gui: bool,
|
||||
):
|
||||
super().__init__()
|
||||
self.cfdp_handler_started = False
|
||||
self.seq_count_provider = seq_count_provider
|
||||
self.pus_verificator = pus_verificator
|
||||
self.high_level_file_logger = high_level_file_logger
|
||||
self.pus_raw_logger = raw_pus_logger
|
||||
self.gui = gui
|
||||
self.queue_helper = DefaultPusQueueHelper(
|
||||
queue_wrapper=QueueWrapper.empty(),
|
||||
default_pus_apid=PUS_APID,
|
||||
seq_cnt_provider=seq_count_provider,
|
||||
pus_verificator=pus_verificator,
|
||||
tc_sched_timestamp_len=4,
|
||||
)
|
||||
self.cfdp_in_ccsds_handler = cfdp_in_ccsds_handler
|
||||
|
||||
def cfdp_done(self) -> bool:
|
||||
if self.cfdp_handler_started:
|
||||
if not self.cfdp_in_ccsds_handler.put_request_pending():
|
||||
self.cfdp_handler_started = False
|
||||
return True
|
||||
return False
|
||||
|
||||
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)
|
||||
elif info.proc_type == TcProcedureType.CFDP:
|
||||
self.handle_cfdp_procedure(info)
|
||||
|
||||
def send_cb(self, send_params: SendCbParams):
|
||||
entry_helper = send_params.entry
|
||||
if entry_helper.is_tc:
|
||||
if entry_helper.entry_type == TcQueueEntryType.PUS_TC:
|
||||
pus_tc_wrapper = entry_helper.to_pus_tc_entry()
|
||||
# pus_tc_wrapper.pus_tc.apid = PUS_APID
|
||||
raw_tc = pus_tc_wrapper.pus_tc.pack()
|
||||
self.pus_raw_logger.log_tc(pus_tc_wrapper.pus_tc)
|
||||
tc_info_string = f"Sent {pus_tc_wrapper.pus_tc}"
|
||||
_LOGGER.info(tc_info_string)
|
||||
self.high_level_file_logger.info(
|
||||
f"{get_current_time_string(True)}: {tc_info_string}"
|
||||
)
|
||||
# with open("tc.bin", "wb") as of:
|
||||
# of.write(raw_tc)
|
||||
send_params.com_if.send(raw_tc)
|
||||
elif entry_helper.entry_type == TcQueueEntryType.CCSDS_TC:
|
||||
cfdp_packet_in_ccsds = entry_helper.to_space_packet_entry()
|
||||
send_params.com_if.send(cfdp_packet_in_ccsds.space_packet.pack())
|
||||
# TODO: Log raw CFDP packets similarly to how PUS packets are logged.
|
||||
# - Log full raw format including space packet wrapper
|
||||
# - Log context information: Transaction ID, and PDU type and directive
|
||||
# Could re-use file logger. Should probably do that
|
||||
# print(f"sending packet: [{cfdp_packet_in_ccsds.space_packet.pack()}]")
|
||||
# with open(f"cfdp_packet_{self.cfdp_counter}", "wb") as of:
|
||||
# of.write(cfdp_packet_in_ccsds.space_packet.pack())
|
||||
# self.cfdp_counter += 1
|
||||
elif entry_helper.entry_type == TcQueueEntryType.LOG:
|
||||
log_entry = entry_helper.to_log_entry()
|
||||
_LOGGER.info(log_entry.log_str)
|
||||
self.high_level_file_logger.info(log_entry.log_str)
|
||||
|
||||
def handle_cfdp_procedure(self, info: ProcedureWrapper):
|
||||
cfdp_procedure = info.to_cfdp_procedure()
|
||||
if cfdp_procedure.cfdp_request_type == CfdpRequestType.PUT:
|
||||
if (
|
||||
not self.cfdp_in_ccsds_handler.put_request_pending()
|
||||
and not self.cfdp_handler_started
|
||||
):
|
||||
put_req_cfg_wrapper = cfdp_procedure.request_wrapper.to_put_request()
|
||||
if put_req_cfg_wrapper.cfg.proxy_op:
|
||||
put_req = cfdp_req_to_put_req_proxy_get_req(
|
||||
put_req_cfg_wrapper.cfg,
|
||||
CFDP_LOCAL_ENTITY_ID,
|
||||
CFDP_REMOTE_ENTITY_ID,
|
||||
)
|
||||
else:
|
||||
put_req = cfdp_put_req_params_to_procedure(put_req_cfg_wrapper.cfg)
|
||||
_LOGGER.info(
|
||||
f"CFDP: Starting file put request with parameters:\n{put_req}"
|
||||
)
|
||||
self.cfdp_in_ccsds_handler.cfdp_handler.put_request(put_req)
|
||||
self.cfdp_handler_started = True
|
||||
|
||||
for source_pair, dest_pair in self.cfdp_in_ccsds_handler:
|
||||
pdu, sp = source_pair
|
||||
pdu = cast(PduHolder, pdu)
|
||||
if pdu.is_file_directive:
|
||||
if pdu.pdu_directive_type == DirectiveType.METADATA_PDU:
|
||||
metadata = pdu.to_metadata_pdu()
|
||||
self.queue_helper.add_log_cmd(
|
||||
f"CFDP Source: Sending Metadata PDU for file with size "
|
||||
f"{metadata.file_size}"
|
||||
)
|
||||
elif pdu.pdu_directive_type == DirectiveType.EOF_PDU:
|
||||
self.queue_helper.add_log_cmd(
|
||||
"CFDP Source: Sending EOF PDU"
|
||||
)
|
||||
else:
|
||||
fd_pdu = pdu.to_file_data_pdu()
|
||||
self.queue_helper.add_log_cmd(
|
||||
f"CFDP Source: Sending File Data PDU for segment at offset "
|
||||
f"{fd_pdu.offset} with length {len(fd_pdu.file_data)}"
|
||||
)
|
||||
self.queue_helper.add_ccsds_tc(sp)
|
||||
self.cfdp_in_ccsds_handler.confirm_source_packet_sent()
|
||||
self.cfdp_in_ccsds_handler.source_handler.state_machine()
|
||||
|
||||
def queue_finished_cb(self, info: ProcedureWrapper):
|
||||
if info is not None:
|
||||
if 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}"
|
||||
)
|
||||
elif info.proc_type == TcProcedureType.CFDP:
|
||||
_LOGGER.info("Finished CFDP queue")
|
@@ -1018,7 +1018,7 @@ def handle_gps_data_processed(pw: PrintWrapper, hk_data: bytes):
|
||||
inc_len_source = struct.calcsize(fmt_source)
|
||||
inc_len_scalar = struct.calcsize(fmt_scalar)
|
||||
inc_len_vec = struct.calcsize(fmt_vec)
|
||||
if len(hk_data) < 2 * inc_len_scalar + 2 * inc_len_vec + inc_len_source:
|
||||
if len(hk_data) < 3 * inc_len_scalar + 2 * inc_len_vec + inc_len_source:
|
||||
pw.dlog("Received HK set too small")
|
||||
return
|
||||
current_idx = 0
|
||||
|
@@ -72,9 +72,7 @@ def add_gps_cmds(defs: TmtcDefinitionWrapper):
|
||||
)
|
||||
|
||||
|
||||
def pack_gps_command( # noqa: C901
|
||||
object_id: bytes, q: DefaultPusQueueHelper, op_code: str
|
||||
): # noqa: C901
|
||||
def pack_gps_command(object_id: bytes, q: DefaultPusQueueHelper, op_code: str):
|
||||
if op_code in OpCode.RESET_GNSS:
|
||||
# TODO: This needs to be re-implemented
|
||||
_LOGGER.warning("Reset pin handling needs to be re-implemented")
|
||||
@@ -217,7 +215,7 @@ def handle_skyview_data(pw: PrintWrapper, hk_data: bytes):
|
||||
inc_len_uint8 = struct.calcsize(fmt_str_uint8)
|
||||
unix = struct.unpack(
|
||||
fmt_str_unix, hk_data[current_idx : current_idx + inc_len_unix]
|
||||
)
|
||||
)[0]
|
||||
current_idx += inc_len_unix
|
||||
prn_id = struct.unpack(
|
||||
fmt_str_int16, hk_data[current_idx : current_idx + inc_len_int16]
|
||||
|
@@ -722,10 +722,42 @@ def get_event_buffer_path() -> str:
|
||||
return file
|
||||
|
||||
|
||||
class SocState(enum.IntEnum):
|
||||
OFF = 0
|
||||
BOOTING = 1
|
||||
OPERATIONAL = 2
|
||||
SHUTDOWN = 3
|
||||
|
||||
|
||||
def handle_supv_hk_data(set_id: int, hk_data: bytes, pw: PrintWrapper):
|
||||
current_idx = 0
|
||||
if set_id == SetIds.HK_REPORT:
|
||||
pass
|
||||
fmt_str = "!IIIQIIIIIBBBB"
|
||||
inc_len = struct.calcsize(fmt_str)
|
||||
(
|
||||
temp_ps,
|
||||
temp_pl,
|
||||
temp_sup,
|
||||
uptime,
|
||||
cpu_load,
|
||||
avail_heap,
|
||||
num_tcs,
|
||||
num_tms,
|
||||
soc_state,
|
||||
nvm_0_1_state,
|
||||
nvm_3_state,
|
||||
mission_io_state,
|
||||
fmc_state,
|
||||
) = struct.unpack(fmt_str, hk_data[:inc_len])
|
||||
pw.dlog(f"Temp PS {temp_ps} C | Temp PL {temp_pl} C | Temp SUP {temp_sup} C")
|
||||
pw.dlog(f"Uptime {uptime} | CPU Load {cpu_load} | Avail Heap {avail_heap}")
|
||||
pw.dlog(f"Number TCs {num_tcs} | Number TMs {num_tms}")
|
||||
pw.dlog(f"SOC state {SocState(soc_state)}")
|
||||
pw.dlog(f"NVM 01 State {nvm_0_1_state}")
|
||||
pw.dlog(f"NVM 3 State {nvm_3_state}")
|
||||
pw.dlog(f"Mission IO state {mission_io_state}")
|
||||
pw.dlog(f"FMC state {fmc_state}")
|
||||
pw.dlog(FsfwTmTcPrinter.get_validity_buffer(hk_data[inc_len:], 13))
|
||||
elif set_id == SetIds.BOOT_STATUS_REPORT:
|
||||
fmt_str = "!BBIIBBBBBB"
|
||||
inc_len = struct.calcsize(fmt_str)
|
||||
|
@@ -29,9 +29,9 @@ classifiers = [
|
||||
"Topic :: Scientific/Engineering"
|
||||
]
|
||||
dependencies = [
|
||||
"tmtccmd ~= 5.0",
|
||||
# "tmtccmd ~= 5.0",
|
||||
"python-dateutil ~= 2.8",
|
||||
# "tmtccmd @ git+https://github.com/robamu-org/tmtccmd@1b110d321ef85#egg=tmtccmd"
|
||||
"tmtccmd @ git+https://github.com/robamu-org/tmtccmd@cfdp-proxy-op-support"
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
|
256
tmtcc.py
256
tmtcc.py
@@ -4,34 +4,24 @@ import sys
|
||||
import time
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
from typing import cast
|
||||
|
||||
from spacepackets.ccsds import SPACE_PACKET_HEADER_SIZE
|
||||
from eive_tmtc.cfdp.fault_handler import EiveCfdpFaultHandler
|
||||
from eive_tmtc.cfdp.tm import CfdpInCcsdsWrapper
|
||||
from eive_tmtc.cfdp.user import EiveCfdpUser
|
||||
from spacepackets.version import get_version as get_spacepackets_version
|
||||
from spacepackets.cfdp import (
|
||||
ConditionCode,
|
||||
ChecksumType,
|
||||
TransmissionMode,
|
||||
PduHolder,
|
||||
DirectiveType,
|
||||
PduFactory,
|
||||
PduType,
|
||||
)
|
||||
|
||||
from eive_tmtc.pus_tc.tc_handler import TcHandler
|
||||
from tmtccmd.logging import add_colorlog_console_logger
|
||||
from tmtccmd.cfdp import CfdpUserBase, TransactionId
|
||||
from tmtccmd.cfdp.defs import CfdpRequestType
|
||||
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:
|
||||
import spacepackets
|
||||
@@ -54,7 +44,7 @@ except ImportError:
|
||||
sys.exit(1)
|
||||
|
||||
from spacepackets.ecss import PusVerificator
|
||||
from tmtccmd import TcHandlerBase, BackendBase
|
||||
from tmtccmd import BackendBase
|
||||
from tmtccmd.util import FileSeqCountProvider, PusFileSeqCountProvider
|
||||
from tmtccmd.fsfw.tmtc_printer import FsfwTmTcPrinter
|
||||
|
||||
@@ -66,15 +56,6 @@ from tmtccmd.logging.pus import (
|
||||
from tmtccmd.pus import VerificationWrapper
|
||||
from tmtccmd.tm import SpecificApidHandlerBase, GenericApidHandlerBase, CcsdsTmHandler
|
||||
from tmtccmd.core import BackendRequest
|
||||
from tmtccmd.logging import get_current_time_string
|
||||
from tmtccmd.tc import (
|
||||
ProcedureWrapper,
|
||||
FeedWrapper,
|
||||
TcProcedureType,
|
||||
TcQueueEntryType,
|
||||
DefaultPusQueueHelper,
|
||||
QueueWrapper,
|
||||
)
|
||||
from tmtccmd.config import (
|
||||
default_json_path,
|
||||
SetupWrapper,
|
||||
@@ -95,7 +76,6 @@ from eive_tmtc.config.definitions import (
|
||||
)
|
||||
from eive_tmtc.config.hook import EiveHookObject
|
||||
from eive_tmtc.pus_tm.pus_demux import pus_factory_hook
|
||||
from eive_tmtc.pus_tc.procedure_packer import handle_default_procedure
|
||||
|
||||
_LOGGER = APP_LOGGER
|
||||
_LOG_LEVEL = logging.INFO
|
||||
@@ -105,61 +85,6 @@ 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,
|
||||
@@ -194,151 +119,6 @@ class CustomCcsdsTmHandler(CcsdsTmHandler):
|
||||
_LOGGER.debug(f"Received packet {packet.hex(sep=',')} with APID {apid}")
|
||||
|
||||
|
||||
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):
|
||||
# Ignore the space packet header. Its only purpose is to use the same protocol and
|
||||
# have a seaprate APID for space packets. If this function is called, the APID is correct.
|
||||
pdu = packet[SPACE_PACKET_HEADER_SIZE:]
|
||||
pdu_base = PduFactory.from_raw(pdu)
|
||||
if pdu_base.pdu_type == PduType.FILE_DATA:
|
||||
_LOGGER.info("Received File Data PDU TM")
|
||||
else:
|
||||
if pdu_base.directive_type == DirectiveType.FINISHED_PDU:
|
||||
_LOGGER.info("Received Finished PDU TM")
|
||||
else:
|
||||
_LOGGER.info(
|
||||
f"Received File Directive PDU with type {pdu_base.directive_type!r} TM"
|
||||
)
|
||||
self.handler.pass_pdu_packet(pdu_base)
|
||||
|
||||
|
||||
class TcHandler(TcHandlerBase):
|
||||
def __init__(
|
||||
self,
|
||||
seq_count_provider: FileSeqCountProvider,
|
||||
cfdp_in_ccsds_wrapper: CfdpInCcsdsWrapper,
|
||||
pus_verificator: PusVerificator,
|
||||
high_level_file_logger: logging.Logger,
|
||||
raw_pus_logger: RawTmtcTimedLogWrapper,
|
||||
gui: bool,
|
||||
):
|
||||
super().__init__()
|
||||
self.cfdp_handler_started = False
|
||||
self.cfdp_dest_id = CFDP_REMOTE_ENTITY_ID
|
||||
self.seq_count_provider = seq_count_provider
|
||||
self.pus_verificator = pus_verificator
|
||||
self.high_level_file_logger = high_level_file_logger
|
||||
self.pus_raw_logger = raw_pus_logger
|
||||
self.gui = gui
|
||||
self.queue_helper = DefaultPusQueueHelper(
|
||||
queue_wrapper=QueueWrapper.empty(),
|
||||
default_pus_apid=PUS_APID,
|
||||
seq_cnt_provider=seq_count_provider,
|
||||
pus_verificator=pus_verificator,
|
||||
tc_sched_timestamp_len=4,
|
||||
)
|
||||
self.cfdp_in_ccsds_wrapper = cfdp_in_ccsds_wrapper
|
||||
|
||||
def cfdp_done(self) -> bool:
|
||||
if self.cfdp_handler_started:
|
||||
if not self.cfdp_in_ccsds_wrapper.handler.put_request_pending():
|
||||
self.cfdp_handler_started = False
|
||||
return True
|
||||
return False
|
||||
|
||||
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)
|
||||
elif info.proc_type == TcProcedureType.CFDP:
|
||||
self.handle_cfdp_procedure(info)
|
||||
|
||||
def send_cb(self, send_params: SendCbParams):
|
||||
entry_helper = send_params.entry
|
||||
if entry_helper.is_tc:
|
||||
if entry_helper.entry_type == TcQueueEntryType.PUS_TC:
|
||||
pus_tc_wrapper = entry_helper.to_pus_tc_entry()
|
||||
# pus_tc_wrapper.pus_tc.apid = PUS_APID
|
||||
raw_tc = pus_tc_wrapper.pus_tc.pack()
|
||||
self.pus_raw_logger.log_tc(pus_tc_wrapper.pus_tc)
|
||||
tc_info_string = f"Sent {pus_tc_wrapper.pus_tc}"
|
||||
_LOGGER.info(tc_info_string)
|
||||
self.high_level_file_logger.info(
|
||||
f"{get_current_time_string(True)}: {tc_info_string}"
|
||||
)
|
||||
# with open("tc.bin", "wb") as of:
|
||||
# of.write(raw_tc)
|
||||
send_params.com_if.send(raw_tc)
|
||||
elif entry_helper.entry_type == TcQueueEntryType.CCSDS_TC:
|
||||
cfdp_packet_in_ccsds = entry_helper.to_space_packet_entry()
|
||||
send_params.com_if.send(cfdp_packet_in_ccsds.space_packet.pack())
|
||||
# TODO: Log raw CFDP packets similarly to how PUS packets are logged.
|
||||
# - Log full raw format including space packet wrapper
|
||||
# - Log context information: Transaction ID, and PDU type and directive
|
||||
# Could re-use file logger. Should probably do that
|
||||
# print(f"sending packet: [{cfdp_packet_in_ccsds.space_packet.pack()}]")
|
||||
# with open(f"cfdp_packet_{self.cfdp_counter}", "wb") as of:
|
||||
# of.write(cfdp_packet_in_ccsds.space_packet.pack())
|
||||
# self.cfdp_counter += 1
|
||||
elif entry_helper.entry_type == TcQueueEntryType.LOG:
|
||||
log_entry = entry_helper.to_log_entry()
|
||||
_LOGGER.info(log_entry.log_str)
|
||||
self.high_level_file_logger.info(log_entry.log_str)
|
||||
|
||||
def handle_cfdp_procedure(self, info: ProcedureWrapper):
|
||||
cfdp_procedure = info.to_cfdp_procedure()
|
||||
if cfdp_procedure.cfdp_request_type == CfdpRequestType.PUT:
|
||||
if (
|
||||
not self.cfdp_in_ccsds_wrapper.handler.put_request_pending()
|
||||
and not self.cfdp_handler_started
|
||||
):
|
||||
put_req = cfdp_procedure.request_wrapper.to_put_request()
|
||||
put_req.cfg.destination_id = self.cfdp_dest_id
|
||||
_LOGGER.info(
|
||||
f"CFDP: Starting file put request with parameters:\n{put_req}"
|
||||
)
|
||||
self.cfdp_in_ccsds_wrapper.handler.cfdp_handler.put_request(put_req)
|
||||
self.cfdp_handler_started = True
|
||||
|
||||
for source_pair, dest_pair in self.cfdp_in_ccsds_wrapper.handler:
|
||||
pdu, sp = source_pair
|
||||
pdu = cast(PduHolder, pdu)
|
||||
if pdu.is_file_directive:
|
||||
if pdu.pdu_directive_type == DirectiveType.METADATA_PDU:
|
||||
metadata = pdu.to_metadata_pdu()
|
||||
self.queue_helper.add_log_cmd(
|
||||
f"CFDP Source: Sending Metadata PDU for file with size "
|
||||
f"{metadata.file_size}"
|
||||
)
|
||||
elif pdu.pdu_directive_type == DirectiveType.EOF_PDU:
|
||||
self.queue_helper.add_log_cmd(
|
||||
"CFDP Source: Sending EOF PDU"
|
||||
)
|
||||
else:
|
||||
fd_pdu = pdu.to_file_data_pdu()
|
||||
self.queue_helper.add_log_cmd(
|
||||
f"CFDP Source: Sending File Data PDU for segment at offset "
|
||||
f"{fd_pdu.offset} with length {len(fd_pdu.file_data)}"
|
||||
)
|
||||
self.queue_helper.add_ccsds_tc(sp)
|
||||
self.cfdp_in_ccsds_wrapper.handler.confirm_source_packet_sent()
|
||||
self.cfdp_in_ccsds_wrapper.handler.source_handler.state_machine()
|
||||
|
||||
def queue_finished_cb(self, info: ProcedureWrapper):
|
||||
if info is not None:
|
||||
if 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}"
|
||||
)
|
||||
elif info.proc_type == TcProcedureType.CFDP:
|
||||
_LOGGER.info("Finished CFDP queue")
|
||||
|
||||
|
||||
def setup_params() -> (SetupWrapper, int):
|
||||
hook_obj = EiveHookObject(default_json_path())
|
||||
params = SetupParams()
|
||||
@@ -361,7 +141,10 @@ def setup_params() -> (SetupWrapper, int):
|
||||
post_arg_parsing_wrapper.set_params_with_prompts(proc_param_wrapper)
|
||||
else:
|
||||
post_arg_parsing_wrapper.set_params_without_prompts(proc_param_wrapper)
|
||||
hk_level = int(post_arg_parsing_wrapper.args_raw.hk)
|
||||
if hasattr(post_arg_parsing_wrapper.args_raw, "hk"):
|
||||
hk_level = int(post_arg_parsing_wrapper.args_raw.hk)
|
||||
else:
|
||||
hk_level = 0
|
||||
params.apid = PUS_APID
|
||||
if params.com_if is None:
|
||||
raise ValueError("could not determine a COM interface.")
|
||||
@@ -378,6 +161,15 @@ def setup_cfdp_handler() -> CfdpInCcsdsWrapper:
|
||||
indication_cfg=IndicationCfg(),
|
||||
default_fault_handlers=fh_base,
|
||||
)
|
||||
self_as_remote = RemoteEntityCfg(
|
||||
closure_requested=False,
|
||||
entity_id=CFDP_LOCAL_ENTITY_ID,
|
||||
max_file_segment_len=990,
|
||||
check_limit=None,
|
||||
crc_on_transmission=False,
|
||||
crc_type=ChecksumType.CRC_32,
|
||||
default_transmission_mode=TransmissionMode.UNACKNOWLEDGED,
|
||||
)
|
||||
remote_cfg = RemoteEntityCfg(
|
||||
closure_requested=False,
|
||||
entity_id=CFDP_REMOTE_ENTITY_ID,
|
||||
@@ -396,7 +188,7 @@ def setup_cfdp_handler() -> CfdpInCcsdsWrapper:
|
||||
cfdp_user = EiveCfdpUser()
|
||||
cfdp_in_ccsds_handler = CfdpInCcsdsHandler(
|
||||
cfg=cfdp_cfg,
|
||||
remote_cfgs=[remote_cfg],
|
||||
remote_cfgs=[remote_cfg, self_as_remote],
|
||||
ccsds_apid=CFDP_APID,
|
||||
ccsds_seq_cnt_provider=cfdp_ccsds_seq_count_provider,
|
||||
cfdp_seq_cnt_provider=cfdp_seq_count_provider,
|
||||
@@ -427,7 +219,7 @@ def setup_tmtc_handlers(
|
||||
high_level_file_logger=printer.file_logger,
|
||||
raw_pus_logger=raw_logger,
|
||||
gui=gui,
|
||||
cfdp_in_ccsds_wrapper=cfdp_in_ccsds_wrapper,
|
||||
cfdp_in_ccsds_handler=cfdp_in_ccsds_wrapper.handler,
|
||||
)
|
||||
return ccsds_handler, tc_handler
|
||||
|
||||
@@ -450,7 +242,7 @@ def setup_backend(
|
||||
|
||||
def main(): # noqa C901: Complexity okay here.
|
||||
print(f"-- eive tmtc v{__version__} --")
|
||||
print(f"-- spacepackets v{spacepackets.__version__} --")
|
||||
print(f"-- spacepackets v{get_spacepackets_version()} --")
|
||||
add_colorlog_console_logger(_LOGGER)
|
||||
# TODO: -V CLI argument to enable this?
|
||||
_LOGGER.setLevel(_LOG_LEVEL)
|
||||
@@ -478,7 +270,7 @@ def main(): # noqa C901: Complexity okay here.
|
||||
try:
|
||||
while True:
|
||||
state = tmtc_backend.periodic_op(None)
|
||||
tc_handler.cfdp_in_ccsds_wrapper.handler.fsm()
|
||||
tc_handler.cfdp_in_ccsds_handler.fsm()
|
||||
if state.request == BackendRequest.TERMINATION_NO_ERROR:
|
||||
sys.exit(0)
|
||||
elif state.request == BackendRequest.DELAY_IDLE:
|
||||
|
Reference in New Issue
Block a user