Dependency updates and doc improvements #7

Merged
muellerr merged 1 commits from dep-update-docs-improvements into main 2025-08-13 18:17:17 +02:00
7 changed files with 97 additions and 75 deletions

View File

@@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased] # [unreleased]
- Bumped `spacepackets` to v0.15
- Bumped `defmt` to v1
# [v0.2.0] 2024-11-26 # [v0.2.0] 2024-11-26
- Bumped `thiserror` to v2 - Bumped `thiserror` to v2

View File

@@ -19,26 +19,11 @@ name = "cfdp"
crc = "3" crc = "3"
smallvec = "1" smallvec = "1"
derive-new = ">=0.6, <=0.7" derive-new = ">=0.6, <=0.7"
hashbrown = { version = ">=0.14, <=0.15", optional = true }
[dependencies.spacepackets] spacepackets = { version = "0.15", default-features = false }
version = "0.13" thiserror = { version = "2", default-features = false }
default-features = false serde = { version = "1", optional = true }
defmt = { version = "1", optional = true }
[dependencies.thiserror]
version = "2"
default-features = false
[dependencies.hashbrown]
version = ">=0.14, <=0.15"
optional = true
[dependencies.serde]
version = "1"
optional = true
[dependencies.defmt]
version = "0.3"
optional = true
[features] [features]
default = ["std"] default = ["std"]
@@ -56,7 +41,7 @@ defmt = ["dep:defmt", "spacepackets/defmt"]
[dev-dependencies] [dev-dependencies]
tempfile = "3" tempfile = "3"
rand = "0.8" rand = "0.9"
log = "0.4" log = "0.4"
fern = "0.7" fern = "0.7"
chrono = "0.4" chrono = "0.4"

View File

@@ -13,6 +13,20 @@ The underlying base packet library used to generate the packets to be sent is th
# Features # Features
`cfdp-rs` currently supports following high-level features:
- Unacknowledged (class 1) file transfers for both source and destination side.
The following features have not been implemented yet. PRs or notifications for demand are welcome!
- Acknowledged (class 2) file transfers for both source and destination side.
- Suspending transfers
- Inactivity handling
- Start and end of transmission and reception opportunity handling
- Keep Alive and Prompt PDU handling
## Rust features
The goal of this library is to be flexible enough to support the use-cases of both on-board The goal of this library is to be flexible enough to support the use-cases of both on-board
software and of ground software. It has support to make integration on `std` systems as simple software and of ground software. It has support to make integration on `std` systems as simple
as possible, but also has sufficient abstraction to allow for integration on`no_std` environments as possible, but also has sufficient abstraction to allow for integration on`no_std` environments
@@ -22,13 +36,13 @@ Please note even though the `alloc` feature is required for the core handlers, t
will only allocate memory at initialization time and thus are still viable for systems where will only allocate memory at initialization time and thus are still viable for systems where
run-time allocation is prohibited. run-time allocation is prohibited.
## Default features ### Default features
- [`std`](https://doc.rust-lang.org/std/): Enables functionality relying on the standard library. - [`std`](https://doc.rust-lang.org/std/): Enables functionality relying on the standard library.
- [`alloc`](https://doc.rust-lang.org/alloc/): Enables features which require allocation support. - [`alloc`](https://doc.rust-lang.org/alloc/): Enables features which require allocation support.
Enabled by the `std` feature. Enabled by the `std` feature.
## Optional Features ### Optional Features
- [`serde`](https://serde.rs/): Adds `serde` support for most types by adding `Serialize` and `Deserialize` `derive`s - [`serde`](https://serde.rs/): Adds `serde` support for most types by adding `Serialize` and `Deserialize` `derive`s
- [`defmt`](https://defmt.ferrous-systems.com/): Add support for the `defmt` by adding the - [`defmt`](https://defmt.ferrous-systems.com/): Add support for the `defmt` by adding the

View File

@@ -92,6 +92,7 @@ struct TransferState<Countdown: CountdownProvider> {
transaction_id: Option<TransactionId>, transaction_id: Option<TransactionId>,
metadata_params: MetadataGenericParams, metadata_params: MetadataGenericParams,
progress: u64, progress: u64,
// TODO: Can we delete this for good?
// file_size_eof: u64, // file_size_eof: u64,
metadata_only: bool, metadata_only: bool,
condition_code: ConditionCode, condition_code: ConditionCode,
@@ -298,19 +299,19 @@ impl<
/// ///
/// * `local_cfg` - The local CFDP entity configuration. /// * `local_cfg` - The local CFDP entity configuration.
/// * `max_packet_len` - The maximum expected generated packet size in bytes. Each time a /// * `max_packet_len` - The maximum expected generated packet size in bytes. Each time a
/// packet is sent, it will be buffered inside an internal buffer. The length of this buffer /// packet is sent, it will be buffered inside an internal buffer. The length of this buffer
/// will be determined by this parameter. This parameter can either be a known upper bound, /// will be determined by this parameter. This parameter can either be a known upper bound,
/// or it can specifically be determined by the largest packet size parameter of all remote /// or it can specifically be determined by the largest packet size parameter of all remote
/// entity configurations in the passed `remote_cfg_table`. /// entity configurations in the passed `remote_cfg_table`.
/// * `pdu_sender` - [PduSendProvider] used to send generated PDU packets. /// * `pdu_sender` - [PduSendProvider] used to send generated PDU packets.
/// * `vfs` - [VirtualFilestore] implementation used by the handler, which decouples the CFDP /// * `vfs` - [VirtualFilestore] implementation used by the handler, which decouples the CFDP
/// implementation from the underlying filestore/filesystem. This allows to use this handler /// implementation from the underlying filestore/filesystem. This allows to use this handler
/// for embedded systems where a standard runtime might not be available. /// for embedded systems where a standard runtime might not be available.
/// * `remote_cfg_table` - The [RemoteEntityConfigProvider] used to look up remote /// * `remote_cfg_table` - The [RemoteEntityConfigProvider] used to look up remote
/// entities and target specific configuration for file copy operations. /// entities and target specific configuration for file copy operations.
/// * `check_timer_creator` - [TimerCreatorProvider] used by the CFDP handler to generate /// * `check_timer_creator` - [TimerCreatorProvider] used by the CFDP handler to generate
/// timers required by various tasks. This allows to use this handler for embedded systems /// timers required by various tasks. This allows to use this handler for embedded systems
/// where the standard time APIs might not be available. /// where the standard time APIs might not be available.
pub fn new( pub fn new(
local_cfg: LocalEntityConfig<UserFaultHook>, local_cfg: LocalEntityConfig<UserFaultHook>,
max_packet_len: usize, max_packet_len: usize,
@@ -1429,7 +1430,7 @@ mod tests {
#[test] #[test]
fn test_segmented_file_transfer_not_acked() { fn test_segmented_file_transfer_not_acked() {
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
let mut random_data = [0u8; 512]; let mut random_data = [0u8; 512];
rng.fill(&mut random_data); rng.fill(&mut random_data);
let file_size = random_data.len() as u64; let file_size = random_data.len() as u64;
@@ -1456,7 +1457,7 @@ mod tests {
#[test] #[test]
fn test_check_limit_handling_transfer_success() { fn test_check_limit_handling_transfer_success() {
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
let mut random_data = [0u8; 512]; let mut random_data = [0u8; 512];
rng.fill(&mut random_data); rng.fill(&mut random_data);
let file_size = random_data.len() as u64; let file_size = random_data.len() as u64;
@@ -1502,7 +1503,7 @@ mod tests {
#[test] #[test]
fn test_check_limit_handling_limit_reached() { fn test_check_limit_handling_limit_reached() {
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
let mut random_data = [0u8; 512]; let mut random_data = [0u8; 512];
rng.fill(&mut random_data); rng.fill(&mut random_data);
let file_size = random_data.len() as u64; let file_size = random_data.len() as u64;
@@ -1752,7 +1753,7 @@ mod tests {
let fault_handler = TestFaultHandler::default(); let fault_handler = TestFaultHandler::default();
let src_path = tempfile::TempPath::from_path("/tmp/test.txt").to_path_buf(); let src_path = tempfile::TempPath::from_path("/tmp/test.txt").to_path_buf();
let dest_path = tempfile::TempDir::new().unwrap(); let dest_path = tempfile::TempDir::new().unwrap();
let mut dest_path_buf = dest_path.into_path(); let mut dest_path_buf = dest_path.keep();
let mut tb = DestHandlerTestbench::new( let mut tb = DestHandlerTestbench::new(
fault_handler, fault_handler,
false, false,

View File

@@ -1,5 +1,23 @@
//! This module contains the implementation of the CCSDS File Delivery Protocol (CFDP) high level //! # `cfdp` - High-level support for implementing CFDP
//! abstractions as specified in CCSDS 727.0-B-5. //!
//! This is a high-level support library for implementing the CCSDS File Delivery Protocol
//! according to the CCSDS 727.0-B-5 standard.
//!
//! # Features
//!
//! The crate currently supports following features:
//!
//! - Unacknowledged (class 1) file transfers for both source and destination side.
//!
//! The following features have not been implemented yet. PRs or notifications for demand are welcome!
//!
//! - Acknowledged (class 2) file transfers for both source and destination side.
//! - Suspending transfers
//! - Inactivity handling
//! - Start and end of transmission and reception opportunity handling
//! - Keep Alive and Prompt PDU handling
//!
//! # Overview
//! //!
//! The basic idea of CFDP is to convert files of any size into a stream of packets called packet //! The basic idea of CFDP is to convert files of any size into a stream of packets called packet
//! data units (PDU). CFPD has an unacknowledged and acknowledged mode, with the option to request //! data units (PDU). CFPD has an unacknowledged and acknowledged mode, with the option to request
@@ -169,7 +187,7 @@ pub trait TimerCreatorProvider {
/// This structure models the remote entity configuration information as specified in chapter 8.3 /// This structure models the remote entity configuration information as specified in chapter 8.3
/// of the CFDP standard. /// of the CFDP standard.
///
/// Some of the fields which were not considered necessary for the Rust implementation /// 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 /// were omitted. Some other fields which are not contained inside the standard but are considered
/// necessary for the Rust implementation are included. /// necessary for the Rust implementation are included.
@@ -195,16 +213,16 @@ pub trait TimerCreatorProvider {
/// ///
/// * `entity_id` - The ID of the remote entity. /// * `entity_id` - The ID of the remote entity.
/// * `max_packet_len` - This determines of all PDUs generated for that remote entity in addition /// * `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. /// 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 /// * `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 /// 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. /// 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 /// If this has some value which is smaller than the segment value derived from
/// `max_packet_len`, this value will be picked. /// `max_packet_len`, this value will be picked.
/// * `closure_requested_by_default` - If the closure requested field is not supplied as part of /// * `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. /// 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 /// * `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. /// 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 /// * `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. /// 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 /// * `disposition_on_cancellation` - Determines whether an incomplete received file is discard on
@@ -216,16 +234,16 @@ pub trait TimerCreatorProvider {
/// reception of file data PDUs and EOF PDUs. Also see 4.6.3.3 of the CFDP standard. Defaults to /// 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. /// 2, so the check limit timer may expire twice.
/// * `positive_ack_timer_interval_seconds`- See the notes on the Positive Acknowledgment /// * `positive_ack_timer_interval_seconds`- See the notes on the Positive Acknowledgment
/// Procedures inside the class documentation. Expected as floating point seconds. Defaults to /// Procedures inside the class documentation. Expected as floating point seconds. Defaults to
/// 10 seconds. /// 10 seconds.
/// * `positive_ack_timer_expiration_limit` - See the notes on the Positive Acknowledgment /// * `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. /// 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 /// * `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. /// 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 /// * `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. /// 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 /// * `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. /// the class documentation. Defaults to 2, so the timer may expire two times.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

View File

@@ -24,10 +24,10 @@ pub trait ReadablePutRequest {
fn closure_requested(&self) -> Option<bool>; fn closure_requested(&self) -> Option<bool>;
fn seg_ctrl(&self) -> Option<SegmentationControl>; fn seg_ctrl(&self) -> Option<SegmentationControl>;
fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv>>; fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv<'_>>>;
fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv>>; fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv<'_>>>;
fn flow_label(&self) -> Option<Tlv>; fn flow_label(&self) -> Option<Tlv<'_>>;
fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv>>; fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv<'_>>>;
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
@@ -101,25 +101,25 @@ impl ReadablePutRequest for PutRequest<'_, '_, '_, '_, '_, '_> {
self.seg_ctrl self.seg_ctrl
} }
fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv>> { fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv<'_>>> {
if let Some(msgs_to_user) = self.msgs_to_user { if let Some(msgs_to_user) = self.msgs_to_user {
return Some(msgs_to_user.iter().copied()); return Some(msgs_to_user.iter().copied());
} }
None None
} }
fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv>> { fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv<'_>>> {
if let Some(fh_overrides) = self.fault_handler_overrides { if let Some(fh_overrides) = self.fault_handler_overrides {
return Some(fh_overrides.iter().copied()); return Some(fh_overrides.iter().copied());
} }
None None
} }
fn flow_label(&self) -> Option<Tlv> { fn flow_label(&self) -> Option<Tlv<'_>> {
self.flow_label self.flow_label
} }
fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv>> { fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv<'_>>> {
if let Some(fs_requests) = self.msgs_to_user { if let Some(fs_requests) = self.msgs_to_user {
return Some(fs_requests.iter().copied()); return Some(fs_requests.iter().copied());
} }
@@ -370,25 +370,25 @@ pub mod alloc_mod {
self.seg_ctrl self.seg_ctrl
} }
fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv>> { fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv<'_>>> {
if let Some(msgs_to_user) = &self.msgs_to_user { if let Some(msgs_to_user) = &self.msgs_to_user {
return Some(msgs_to_user.iter().map(|tlv_owned| tlv_owned.as_tlv())); return Some(msgs_to_user.iter().map(|tlv_owned| tlv_owned.as_tlv()));
} }
None None
} }
fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv>> { fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv<'_>>> {
if let Some(fh_overrides) = &self.fault_handler_overrides { if let Some(fh_overrides) = &self.fault_handler_overrides {
return Some(fh_overrides.iter().map(|tlv_owned| tlv_owned.as_tlv())); return Some(fh_overrides.iter().map(|tlv_owned| tlv_owned.as_tlv()));
} }
None None
} }
fn flow_label(&self) -> Option<Tlv> { fn flow_label(&self) -> Option<Tlv<'_>> {
self.flow_label.as_ref().map(|tlv| tlv.as_tlv()) self.flow_label.as_ref().map(|tlv| tlv.as_tlv())
} }
fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv>> { fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv<'_>>> {
if let Some(requests) = &self.fs_requests { if let Some(requests) = &self.fs_requests {
return Some(requests.iter().map(|tlv_owned| tlv_owned.as_tlv())); return Some(requests.iter().map(|tlv_owned| tlv_owned.as_tlv()));
} }

View File

@@ -260,21 +260,21 @@ impl<
/// * `cfg` - The local entity configuration for this source handler. /// * `cfg` - The local entity configuration for this source handler.
/// * `pdu_sender` - [PduSendProvider] provider used to send CFDP PDUs generated by the handler. /// * `pdu_sender` - [PduSendProvider] provider used to send CFDP PDUs generated by the handler.
/// * `vfs` - [VirtualFilestore] implementation used by the handler, which decouples the CFDP /// * `vfs` - [VirtualFilestore] implementation used by the handler, which decouples the CFDP
/// implementation from the underlying filestore/filesystem. This allows to use this handler /// implementation from the underlying filestore/filesystem. This allows to use this handler
/// for embedded systems where a standard runtime might not be available. /// for embedded systems where a standard runtime might not be available.
/// * `put_request_cacher` - The put request cacher is used cache put requests without /// * `put_request_cacher` - The put request cacher is used cache put requests without
/// requiring run-time allocation. /// requiring run-time allocation.
/// * `pdu_and_cksum_buf_size` - The handler requires a buffer to generate PDUs and perform /// * `pdu_and_cksum_buf_size` - The handler requires a buffer to generate PDUs and perform
/// checksum calculations. The user can specify the size of this buffer, so this should be /// checksum calculations. The user can specify the size of this buffer, so this should be
/// set to the maximum expected PDU size or a conservative upper bound for this size, for /// set to the maximum expected PDU size or a conservative upper bound for this size, for
/// example 2048 or 4096 bytes. /// example 2048 or 4096 bytes.
/// * `remote_cfg_table` - The [RemoteEntityConfigProvider] used to look up remote /// * `remote_cfg_table` - The [RemoteEntityConfigProvider] used to look up remote
/// entities and target specific configuration for file copy operations. /// entities and target specific configuration for file copy operations.
/// * `timer_creator` - [TimerCreatorProvider] used by the CFDP handler to generate /// * `timer_creator` - [TimerCreatorProvider] used by the CFDP handler to generate
/// timers required by various tasks. This allows to use this handler for embedded systems /// timers required by various tasks. This allows to use this handler for embedded systems
/// where the standard time APIs might not be available. /// where the standard time APIs might not be available.
/// * `seq_count_provider` - The [SequenceCountProvider] used to generate the [TransactionId] /// * `seq_count_provider` - The [SequenceCountProvider] used to generate the [TransactionId]
/// which contains an incrementing counter. /// which contains an incrementing counter.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
cfg: LocalEntityConfig<UserFaultHook>, cfg: LocalEntityConfig<UserFaultHook>,
@@ -386,7 +386,7 @@ impl<
/// This function is used to pass a put request to the source handler, which is /// This function is used to pass a put request to the source handler, which is
/// also used to start a file copy operation. As such, this function models the Put.request /// also used to start a file copy operation. As such, this function models the Put.request
/// CFDP primtiive. /// CFDP primtiive.
///
/// Please note that the source handler can also process one put request at a time. /// Please note that the source handler can also process one put request at a time.
/// The caller is responsible of creating a new source handler, one handler can only handle /// The caller is responsible of creating a new source handler, one handler can only handle
/// one file copy request at a time. /// one file copy request at a time.
@@ -505,7 +505,8 @@ impl<
} }
if let Some(active_id) = self.transaction_id() { if let Some(active_id) = self.transaction_id() {
if active_id == *transaction_id { if active_id == *transaction_id {
self.notice_of_cancellation(user, ConditionCode::CancelRequestReceived)?; // Control flow result can be ignored here for the cancel request.
let _ = self.notice_of_cancellation(user, ConditionCode::CancelRequestReceived)?;
return Ok(true); return Ok(true);
} }
} }
@@ -1533,7 +1534,7 @@ mod tests {
.open(&tb.srcfile) .open(&tb.srcfile)
.expect("opening file failed"); .expect("opening file failed");
let mut rand_data = [0u8; 140]; let mut rand_data = [0u8; 140];
rand::thread_rng().fill(&mut rand_data[..]); rand::rng().fill(&mut rand_data[..]);
file.write_all(&rand_data) file.write_all(&rand_data)
.expect("writing file content failed"); .expect("writing file content failed");
drop(file); drop(file);
@@ -1552,7 +1553,7 @@ mod tests {
.open(&tb.srcfile) .open(&tb.srcfile)
.expect("opening file failed"); .expect("opening file failed");
let mut rand_data = [0u8; 140]; let mut rand_data = [0u8; 140];
rand::thread_rng().fill(&mut rand_data[..]); rand::rng().fill(&mut rand_data[..]);
file.write_all(&rand_data) file.write_all(&rand_data)
.expect("writing file content failed"); .expect("writing file content failed");
drop(file); drop(file);
@@ -1748,7 +1749,7 @@ mod tests {
.open(&tb.srcfile) .open(&tb.srcfile)
.expect("opening file failed"); .expect("opening file failed");
let mut rand_data = [0u8; 140]; let mut rand_data = [0u8; 140];
rand::thread_rng().fill(&mut rand_data[..]); rand::rng().fill(&mut rand_data[..]);
file.write_all(&rand_data) file.write_all(&rand_data)
.expect("writing file content failed"); .expect("writing file content failed");
drop(file); drop(file);