Continue CFDP handlers #90

Merged
muellerr merged 34 commits from continue_cfdp_handlers into main 2024-01-29 23:42:04 +01:00
2 changed files with 120 additions and 14 deletions
Showing only changes of commit 303a9ab581 - Show all commits

View File

@ -155,6 +155,8 @@ pub enum DestError {
EmptySrcFileField, EmptySrcFileField,
#[error("empty dest file field")] #[error("empty dest file field")]
EmptyDestFileField, EmptyDestFileField,
#[error("packets to be sent are still left")]
PacketToSendLeft,
#[error("pdu error {0}")] #[error("pdu error {0}")]
Pdu(#[from] PduError), Pdu(#[from] PduError),
#[error("io error {0}")] #[error("io error {0}")]
@ -176,10 +178,12 @@ pub enum DestError {
/// The following core functions are the primary interface for interacting with the destination /// The following core functions are the primary interface for interacting with the destination
/// handler: /// handler:
/// 1. [DestinationHandler::state_machine]: Can be used to insert packets into the destination /// 1. [DestinationHandler::state_machine] - Can be used to insert packets into the destination
/// handler. Please note that the destination handler can also only process Metadata, EOF and /// handler and/or advance the state machine. Advancing the state machine might generate new
/// Prompt PDUs in addition to ACK PDUs where the acknowledged PDU is the Finished PDU. /// packets to be sent to the remote entity. Please note that the destination handler can also
/// 2. [DestinationHandler::get_next_packet]: Retrieve next packet to be sent back to the remote /// only process Metadata, EOF and Prompt PDUs in addition to ACK PDUs where the acknowledged
/// PDU is the Finished PDU.
/// 2. [DestinationHandler::get_next_packet] - Retrieve next packet to be sent back to the remote
/// CFDP source entity ID. /// CFDP source entity ID.
/// A new file transfer (Metadata PDU reception) is only be accepted if the handler is in the /// A new file transfer (Metadata PDU reception) is only be accepted if the handler is in the
@ -215,11 +219,23 @@ impl DestinationHandler {
} }
} }
/// This is the core function to drive the destination handler. It is also used to insert
/// packets into the destination handler.
///
/// Please note that this function will fail if there are still packets which need to be
/// retrieved with [Self::get_next_packet]. After each state machine call, the user has to
/// retrieve all packets before calling the state machine again. The state machine should
/// either be called if a packet with the appropriate destination ID is received, or
/// periodically in IDLE periods to perform all CFDP related tasks, for example checking for
/// timeouts or missed file segments.
pub fn state_machine( pub fn state_machine(
&mut self, &mut self,
cfdp_user: &mut impl CfdpUser, cfdp_user: &mut impl CfdpUser,
packet_to_insert: Option<&PacketInfo>, packet_to_insert: Option<&PacketInfo>,
) -> Result<(), DestError> { ) -> Result<(), DestError> {
if self.packet_to_send_ready() {
return Err(DestError::PacketToSendLeft);
}
if let Some(packet) = packet_to_insert { if let Some(packet) = packet_to_insert {
self.insert_packet(cfdp_user, packet)?; self.insert_packet(cfdp_user, packet)?;
} }

View File

@ -1,3 +1,5 @@
//! This module contains the implementation of the CFDP high level classes as specified in the
//! CCSDS 727.0-B-5.
use core::{cell::RefCell, fmt::Debug, hash::Hash}; use core::{cell::RefCell, fmt::Debug, hash::Hash};
use crc::{Crc, CRC_32_CKSUM}; use crc::{Crc, CRC_32_CKSUM};
@ -47,7 +49,7 @@ pub trait CheckTimer: Debug {
/// A generic trait which allows CFDP entities to create check timers which are required to /// A generic trait which allows CFDP entities to create check timers which are required to
/// implement special procedures in unacknowledged transmission mode, as specified in 4.6.3.2 /// implement special procedures in unacknowledged transmission mode, as specified in 4.6.3.2
/// and 4.6.3.3. The [CheckTimerProvider] provides more information about the purpose of the /// and 4.6.3.3. The [CheckTimer] documentation provides more information about the purpose of the
/// check timer. /// check timer.
/// ///
/// This trait also allows the creation of different check timers depending on /// This trait also allows the creation of different check timers depending on
@ -63,7 +65,7 @@ pub trait CheckTimerCreator {
) -> Box<dyn CheckTimer>; ) -> Box<dyn CheckTimer>;
} }
/// Simple implementation of the [CheckTimerProvider] trait assuming a standard runtime. /// Simple implementation of the [CheckTimerCreator] trait assuming a standard runtime.
/// It also assumes that a second accuracy of the check timer period is sufficient. /// It also assumes that a second accuracy of the check timer period is sufficient.
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[derive(Debug)] #[derive(Debug)]
@ -97,17 +99,76 @@ impl CheckTimer for StdCheckTimer {
} }
} }
/// This structure models the remote entity configuration information as specified in chapter 8.3
/// of the CFDP standard.
/// Some of the fields which were not considered necessary for the Rust implementation
/// were omitted. Some other fields which are not contained inside the standard but are considered
/// necessary for the Rust implementation are included.
///
/// ## Notes on Positive Acknowledgment Procedures
///
/// The `positive_ack_timer_interval_seconds` and `positive_ack_timer_expiration_limit` will
/// be used for positive acknowledgement procedures as specified in CFDP chapter 4.7. The sending
/// entity will start the timer for any PDUs where an acknowledgment is required (e.g. EOF PDU).
/// Once the expected ACK response has not been received for that interval, as counter will be
/// incremented and the timer will be reset. Once the counter exceeds the
/// `positive_ack_timer_expiration_limit`, a Positive ACK Limit Reached fault will be declared.
///
/// ## Notes on Deferred Lost Segment Procedures
///
/// This procedure will be active if an EOF (No Error) PDU is received in acknowledged mode. After
/// issuing the NAK sequence which has the whole file scope, a timer will be started. The timer is
/// reset when missing segments or missing metadata is received. The timer will be deactivated if
/// all missing data is received. If the timer expires, a new NAK sequence will be issued and a
/// counter will be incremented, which can lead to a NAK Limit Reached fault being declared.
///
/// ## Fields
///
/// * `entity_id` - The ID of the remote entity.
/// * `max_packet_len` - This determines of all PDUs generated for that remote entity in addition
/// to the `max_file_segment_len` attribute which also determines the size of file data PDUs.
/// * `max_file_segment_len` The maximum file segment length which determines the maximum size
/// of file data PDUs in addition to the `max_packet_len` attribute. If this field is set
/// to None, the maximum file segment length will be derived from the maximum packet length.
/// If this has some value which is smaller than the segment value derived from
/// `max_packet_len`, this value will be picked.
/// * `closure_requested_by_default` - If the closure requested field is not supplied as part of
/// the Put Request, it will be determined from this field in the remote configuration.
/// * `crc_on_transmission_by_default` - If the CRC option is not supplied as part of the Put
/// Request, it will be determined from this field in the remote configuration.
/// * `default_transmission_mode` - If the transmission mode is not supplied as part of the
/// Put Request, it will be determined from this field in the remote configuration.
/// * `disposition_on_cancellation` - Determines whether an incomplete received file is discard on
/// transaction cancellation. Defaults to False.
/// * `default_crc_type` - Default checksum type used to calculate for all file transmissions to
/// this remote entity.
/// * `check_limit` - This timer determines the expiry period for incrementing a check counter
/// after an EOF PDU is received for an incomplete file transfer. This allows out-of-order
/// reception of file data PDUs and EOF PDUs. Also see 4.6.3.3 of the CFDP standard. Defaults to
/// 2, so the check limit timer may expire twice.
/// * `positive_ack_timer_interval_seconds`- See the notes on the Positive Acknowledgment
/// Procedures inside the class documentation. Expected as floating point seconds. Defaults to
/// 10 seconds.
/// * `positive_ack_timer_expiration_limit` - See the notes on the Positive Acknowledgment
/// Procedures inside the class documentation. Defaults to 2, so the timer may expire twice.
/// * `immediate_nak_mode` - Specifies whether a NAK sequence should be issued immediately when a
/// file data gap or lost metadata is detected in the acknowledged mode. Defaults to True.
/// * `nak_timer_interval_seconds` - See the notes on the Deferred Lost Segment Procedure inside
/// the class documentation. Expected as floating point seconds. Defaults to 10 seconds.
/// * `nak_timer_expiration_limit` - See the notes on the Deferred Lost Segment Procedure inside
/// the class documentation. Defaults to 2, so the timer may expire two times.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct RemoteEntityConfig { pub struct RemoteEntityConfig {
pub entity_id: UnsignedByteField, pub entity_id: UnsignedByteField,
pub max_file_segment_len: usize,
pub max_packet_len: usize, pub max_packet_len: usize,
pub max_file_segment_len: usize,
pub closure_requested_by_default: bool, pub closure_requested_by_default: bool,
pub crc_on_transmission_by_default: bool, pub crc_on_transmission_by_default: bool,
pub default_transmission_mode: TransmissionMode, pub default_transmission_mode: TransmissionMode,
pub disposition_on_cancellation: bool,
pub default_crc_type: ChecksumType, pub default_crc_type: ChecksumType,
pub check_limit: u32, pub check_limit: u32,
pub disposition_on_cancellation: bool,
} }
impl RemoteEntityConfig { impl RemoteEntityConfig {
@ -138,11 +199,11 @@ pub trait RemoteEntityConfigProvider {
/// Retrieve the remote entity configuration for the given remote ID. /// Retrieve the remote entity configuration for the given remote ID.
fn get_remote_config(&self, remote_id: u64) -> Option<&RemoteEntityConfig>; fn get_remote_config(&self, remote_id: u64) -> Option<&RemoteEntityConfig>;
fn get_remote_config_mut(&mut self, remote_id: u64) -> Option<&mut RemoteEntityConfig>; fn get_remote_config_mut(&mut self, remote_id: u64) -> Option<&mut RemoteEntityConfig>;
/// Add a new remote configuration. Return [True] if the configuration was /// Add a new remote configuration. Return [true] if the configuration was
/// inserted successfully, and [False] if a configuration already exists. /// inserted successfully, and [false] if a configuration already exists.
fn add_config(&mut self, cfg: &RemoteEntityConfig) -> bool; fn add_config(&mut self, cfg: &RemoteEntityConfig) -> bool;
/// Remote a configuration. Returns [True] if the configuration was removed successfully, /// Remote a configuration. Returns [true] if the configuration was removed successfully,
/// and [False] if no configuration exists for the given remote ID. /// and [false] if no configuration exists for the given remote ID.
fn remove_config(&mut self, remote_id: u64) -> bool; fn remove_config(&mut self, remote_id: u64) -> bool;
} }
@ -171,8 +232,15 @@ impl RemoteEntityConfigProvider for StdRemoteEntityConfigProvider {
} }
/// This trait introduces some callbacks which will be called when a particular CFDP fault /// This trait introduces some callbacks which will be called when a particular CFDP fault
/// handler is called. This allows to implement some CFDP features like fault handler logging, /// handler is called.
/// which would not be possible generically otherwise. ///
/// It is passed into the CFDP handlers as part of the [DefaultFaultHandler] and the local entity
/// configuration and provides a way to specify custom user error handlers. This allows to
/// implement some CFDP features like fault handler logging, which would not be possible
/// generically otherwise.
///
/// For each error reported by the [DefaultFaultHandler], the appropriate fault handler callback
/// will be called depending on the [FaultHandlerCode].
pub trait UserFaultHandler { pub trait UserFaultHandler {
fn notice_of_suspension_cb( fn notice_of_suspension_cb(
&mut self, &mut self,
@ -193,6 +261,26 @@ pub trait UserFaultHandler {
fn ignore_cb(&mut self, transaction_id: TransactionId, cond: ConditionCode, progress: u64); fn ignore_cb(&mut self, transaction_id: TransactionId, cond: ConditionCode, progress: u64);
} }
/// This structure is used to implement the fault handling as specified in chapter 4.8 of the CFDP
/// standard.
///
/// It does so by mapping each applicable [spacepackets::cfdp::ConditionCode] to a fault handler
/// which is denoted by the four [spacepackets::cfdp::FaultHandlerCode]s. This code is used
/// to select the error handling inside the CFDP handler itself in addition to dispatching to a
/// user-provided callback function provided by the [UserFaultHandler].
///
/// Some note on the provided default settings:
///
/// - Checksum failures will be ignored by default. This is because for unacknowledged transfers,
/// cancelling the transfer immediately would interfere with the check limit mechanism specified
/// in chapter 4.6.3.3.
/// - Unsupported checksum types will also be ignored by default. Even if the checksum type is
/// not supported the file transfer might still have worked properly.
///
/// For all other faults, the default fault handling operation will be to cancel the transaction.
/// These defaults can be overriden by using the [Self::set_fault_handler] method.
/// Please note that in any case, fault handler overrides can be specified by the sending CFDP
/// entity.
pub struct DefaultFaultHandler { pub struct DefaultFaultHandler {
handler_array: [FaultHandlerCode; 10], handler_array: [FaultHandlerCode; 10],
// Could also change the user fault handler trait to have non mutable methods, but that limits // Could also change the user fault handler trait to have non mutable methods, but that limits
@ -308,6 +396,8 @@ pub struct LocalEntityConfig {
pub default_fault_handler: DefaultFaultHandler, pub default_fault_handler: DefaultFaultHandler,
} }
/// The CFDP transaction ID of a CFDP transaction consists of the source entity ID and the sequence
/// number of that transfer which is also determined by the CFDP source entity.
#[derive(Debug, Eq, Copy, Clone)] #[derive(Debug, Eq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TransactionId { pub struct TransactionId {