Continue CFDP handlers #90
@ -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)?;
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user