added cfdp module to common
This commit is contained in:
parent
1c0905292e
commit
b1b19f9cba
139
common.py
139
common.py
@ -1,11 +1,25 @@
|
|||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional, Sequence
|
||||||
|
|
||||||
from tmtccmd.com_if import ComInterface
|
from spacepackets import SpacePacket, SpacePacketHeader, PacketTypes
|
||||||
|
from spacepackets.cfdp import TransmissionModes, PduType, DirectiveType
|
||||||
|
from spacepackets.cfdp.pdu.helper import GenericPduPacket, PduHolder, PduFactory
|
||||||
|
from spacepackets.util import UnsignedByteField
|
||||||
|
from tmtccmd.cfdp import (
|
||||||
|
RemoteEntityCfgTable,
|
||||||
|
HostFilestore,
|
||||||
|
RemoteEntityCfg,
|
||||||
|
LocalEntityCfg,
|
||||||
|
CfdpUserBase,
|
||||||
|
)
|
||||||
|
from tmtccmd.cfdp.handler import SourceHandler, DestHandler
|
||||||
|
from tmtccmd.cfdp.request import PutRequest, PutRequestCfg
|
||||||
from tmtccmd.logging import get_current_time_string
|
from tmtccmd.logging import get_current_time_string
|
||||||
from tmtccmd.pus.pus_11_tc_sched import Subservices as Pus11Subservices
|
from tmtccmd.pus.pus_11_tc_sched import Subservices as Pus11Subservices
|
||||||
from tmtccmd.tc.queue import DefaultPusQueueHelper
|
from tmtccmd.tc.queue import DefaultPusQueueHelper
|
||||||
from tmtccmd.util import FileSeqCountProvider, PusFileSeqCountProvider
|
from tmtccmd.util import FileSeqCountProvider, PusFileSeqCountProvider, ProvidesSeqCount
|
||||||
from tmtccmd.util.tmtc_printer import FsfwTmTcPrinter
|
from tmtccmd.util.tmtc_printer import FsfwTmTcPrinter
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -38,7 +52,6 @@ from tmtccmd.tc import (
|
|||||||
ProcedureHelper,
|
ProcedureHelper,
|
||||||
FeedWrapper,
|
FeedWrapper,
|
||||||
TcProcedureType,
|
TcProcedureType,
|
||||||
QueueEntryHelper,
|
|
||||||
TcQueueEntryType,
|
TcQueueEntryType,
|
||||||
SendCbParams,
|
SendCbParams,
|
||||||
)
|
)
|
||||||
@ -46,13 +59,131 @@ from tmtccmd.tc.pus_5_event import pack_generic_service_5_test_into
|
|||||||
from tmtccmd.tm import SpecificApidHandlerBase, CcsdsTmHandler
|
from tmtccmd.tm import SpecificApidHandlerBase, CcsdsTmHandler
|
||||||
from tmtccmd.logging.pus import RawTmtcTimedLogWrapper
|
from tmtccmd.logging.pus import RawTmtcTimedLogWrapper
|
||||||
from tmtccmd.config import CoreServiceList, SetupWrapper, SetupParams, ArgParserWrapper
|
from tmtccmd.config import CoreServiceList, SetupWrapper, SetupParams, ArgParserWrapper
|
||||||
from common_tmtc.config import __version__
|
|
||||||
from common_tmtc.pus_tm.factory_hook import pus_factory_hook
|
from common_tmtc.pus_tm.factory_hook import pus_factory_hook
|
||||||
|
|
||||||
|
|
||||||
LOGGER = get_console_logger()
|
LOGGER = get_console_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class CfdpCcsdsWrapper:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
cfg: LocalEntityCfg,
|
||||||
|
user: CfdpUserBase,
|
||||||
|
cfdp_seq_cnt_provider: ProvidesSeqCount,
|
||||||
|
remote_cfg: Sequence[RemoteEntityCfg],
|
||||||
|
ccsds_seq_cnt_provider: ProvidesSeqCount,
|
||||||
|
ccsds_apid: int,
|
||||||
|
):
|
||||||
|
self.handler = CfdpHandler(cfg, user, cfdp_seq_cnt_provider, remote_cfg)
|
||||||
|
self.ccsds_seq_cnt_provider = ccsds_seq_cnt_provider
|
||||||
|
self.ccsds_apid = ccsds_apid
|
||||||
|
|
||||||
|
def pull_next_dest_packet(self) -> Optional[SpacePacket]:
|
||||||
|
"""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,
|
||||||
|
)
|
||||||
|
return SpacePacket(sp_header, None, next_packet.pack())
|
||||||
|
|
||||||
|
def confirm_dest_packet_sent(self):
|
||||||
|
self.handler.confirm_dest_packet_sent()
|
||||||
|
|
||||||
|
def pass_packet(self, packet: SpacePacket):
|
||||||
|
# Unwrap the user data and pass it to the handler
|
||||||
|
pdu_raw = packet.user_data
|
||||||
|
pdu_base = PduFactory.from_raw(pdu_raw)
|
||||||
|
self.handler.pass_packet(pdu_base)
|
||||||
|
|
||||||
|
|
||||||
|
class CfdpHandler:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
cfg: LocalEntityCfg,
|
||||||
|
user: CfdpUserBase,
|
||||||
|
seq_cnt_provider: ProvidesSeqCount,
|
||||||
|
remote_cfg: Sequence[RemoteEntityCfg],
|
||||||
|
):
|
||||||
|
vfs = HostFilestore()
|
||||||
|
super().__init__(vfs)
|
||||||
|
self.dest_id = UnsignedByteField(EXAMPLE_APID, 2)
|
||||||
|
self.remote_cfg_table = RemoteEntityCfgTable()
|
||||||
|
self.remote_cfg_table.add_remote_entities(remote_cfg)
|
||||||
|
self.dest_handler = DestHandler(cfg, user, self.remote_cfg_table)
|
||||||
|
self.source_handler = SourceHandler(cfg, seq_cnt_provider, user)
|
||||||
|
|
||||||
|
def put_request_file(
|
||||||
|
self,
|
||||||
|
source_path: Path,
|
||||||
|
dest_path: Path,
|
||||||
|
trans_mode: TransmissionModes,
|
||||||
|
closure_requested: bool,
|
||||||
|
):
|
||||||
|
put_request_cfg = PutRequestCfg(
|
||||||
|
destination_id=self.dest_id,
|
||||||
|
source_file=source_path,
|
||||||
|
dest_file=dest_path.as_posix(),
|
||||||
|
trans_mode=trans_mode,
|
||||||
|
closure_requested=closure_requested,
|
||||||
|
)
|
||||||
|
put_request = PutRequest(put_request_cfg)
|
||||||
|
self.source_handler.put_request(
|
||||||
|
put_request, self.remote_cfg_table.get_remote_entity(self.dest_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
def confirm_dest_packet_sent(self):
|
||||||
|
self.dest_handler.confirm_packet_sent_advance_fsm()
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
class PusHandler(SpecificApidHandlerBase):
|
class PusHandler(SpecificApidHandlerBase):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user