From 226a7494a0266720297cf5a07883b7afaa9a6ecc Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 13 Aug 2025 17:42:04 +0200 Subject: [PATCH] Dependency updates and Doc improvements --- CHANGELOG.md | 3 +++ Cargo.toml | 27 ++++++--------------------- README.md | 18 ++++++++++++++++-- src/dest.rs | 27 ++++++++++++++------------- src/lib.rs | 42 ++++++++++++++++++++++++++++++------------ src/request.rs | 24 ++++++++++++------------ src/source.rs | 31 ++++++++++++++++--------------- 7 files changed, 97 insertions(+), 75 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 212d998..bc40490 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [unreleased] +- Bumped `spacepackets` to v0.15 +- Bumped `defmt` to v1 + # [v0.2.0] 2024-11-26 - Bumped `thiserror` to v2 diff --git a/Cargo.toml b/Cargo.toml index f8258ce..453e683 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,26 +19,11 @@ name = "cfdp" crc = "3" smallvec = "1" derive-new = ">=0.6, <=0.7" - -[dependencies.spacepackets] -version = "0.13" -default-features = false - -[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 +hashbrown = { version = ">=0.14, <=0.15", optional = true } +spacepackets = { version = "0.15", default-features = false } +thiserror = { version = "2", default-features = false } +serde = { version = "1", optional = true } +defmt = { version = "1", optional = true } [features] default = ["std"] @@ -56,7 +41,7 @@ defmt = ["dep:defmt", "spacepackets/defmt"] [dev-dependencies] tempfile = "3" -rand = "0.8" +rand = "0.9" log = "0.4" fern = "0.7" chrono = "0.4" diff --git a/README.md b/README.md index 4c4855a..988a718 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,20 @@ The underlying base packet library used to generate the packets to be sent is th # 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 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 @@ -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 run-time allocation is prohibited. -## Default features +### Default features - [`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. 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 - [`defmt`](https://defmt.ferrous-systems.com/): Add support for the `defmt` by adding the diff --git a/src/dest.rs b/src/dest.rs index 0b6c31c..b55334c 100644 --- a/src/dest.rs +++ b/src/dest.rs @@ -92,6 +92,7 @@ struct TransferState { transaction_id: Option, metadata_params: MetadataGenericParams, progress: u64, + // TODO: Can we delete this for good? // file_size_eof: u64, metadata_only: bool, condition_code: ConditionCode, @@ -298,19 +299,19 @@ impl< /// /// * `local_cfg` - The local CFDP entity configuration. /// * `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 - /// 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 - /// entity configurations in the passed `remote_cfg_table`. + /// 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, + /// or it can specifically be determined by the largest packet size parameter of all remote + /// entity configurations in the passed `remote_cfg_table`. /// * `pdu_sender` - [PduSendProvider] used to send generated PDU packets. /// * `vfs` - [VirtualFilestore] implementation used by the handler, which decouples the CFDP - /// implementation from the underlying filestore/filesystem. This allows to use this handler - /// for embedded systems where a standard runtime might not be available. + /// implementation from the underlying filestore/filesystem. This allows to use this handler + /// for embedded systems where a standard runtime might not be available. /// * `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 - /// timers required by various tasks. This allows to use this handler for embedded systems - /// where the standard time APIs might not be available. + /// timers required by various tasks. This allows to use this handler for embedded systems + /// where the standard time APIs might not be available. pub fn new( local_cfg: LocalEntityConfig, max_packet_len: usize, @@ -1429,7 +1430,7 @@ mod tests { #[test] fn test_segmented_file_transfer_not_acked() { - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); let mut random_data = [0u8; 512]; rng.fill(&mut random_data); let file_size = random_data.len() as u64; @@ -1456,7 +1457,7 @@ mod tests { #[test] fn test_check_limit_handling_transfer_success() { - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); let mut random_data = [0u8; 512]; rng.fill(&mut random_data); let file_size = random_data.len() as u64; @@ -1502,7 +1503,7 @@ mod tests { #[test] fn test_check_limit_handling_limit_reached() { - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); let mut random_data = [0u8; 512]; rng.fill(&mut random_data); let file_size = random_data.len() as u64; @@ -1752,7 +1753,7 @@ mod tests { let fault_handler = TestFaultHandler::default(); let src_path = tempfile::TempPath::from_path("/tmp/test.txt").to_path_buf(); 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( fault_handler, false, diff --git a/src/lib.rs b/src/lib.rs index d475b57..dda8628 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,23 @@ -//! This module contains the implementation of the CCSDS File Delivery Protocol (CFDP) high level -//! abstractions as specified in CCSDS 727.0-B-5. +//! # `cfdp` - High-level support for implementing CFDP +//! +//! 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 //! 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 /// 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. @@ -195,16 +213,16 @@ pub trait TimerCreatorProvider { /// /// * `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. +/// 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. +/// 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. +/// 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 @@ -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 /// 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. +/// 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. +/// 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. +/// 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. +/// 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. +/// the class documentation. Defaults to 2, so the timer may expire two times. #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] diff --git a/src/request.rs b/src/request.rs index f822969..1f2cc51 100644 --- a/src/request.rs +++ b/src/request.rs @@ -24,10 +24,10 @@ pub trait ReadablePutRequest { fn closure_requested(&self) -> Option; fn seg_ctrl(&self) -> Option; - fn msgs_to_user(&self) -> Option>; - fn fault_handler_overrides(&self) -> Option>; - fn flow_label(&self) -> Option; - fn fs_requests(&self) -> Option>; + fn msgs_to_user(&self) -> Option>>; + fn fault_handler_overrides(&self) -> Option>>; + fn flow_label(&self) -> Option>; + fn fs_requests(&self) -> Option>>; } #[derive(Debug, PartialEq, Eq)] @@ -101,25 +101,25 @@ impl ReadablePutRequest for PutRequest<'_, '_, '_, '_, '_, '_> { self.seg_ctrl } - fn msgs_to_user(&self) -> Option> { + fn msgs_to_user(&self) -> Option>> { if let Some(msgs_to_user) = self.msgs_to_user { return Some(msgs_to_user.iter().copied()); } None } - fn fault_handler_overrides(&self) -> Option> { + fn fault_handler_overrides(&self) -> Option>> { if let Some(fh_overrides) = self.fault_handler_overrides { return Some(fh_overrides.iter().copied()); } None } - fn flow_label(&self) -> Option { + fn flow_label(&self) -> Option> { self.flow_label } - fn fs_requests(&self) -> Option> { + fn fs_requests(&self) -> Option>> { if let Some(fs_requests) = self.msgs_to_user { return Some(fs_requests.iter().copied()); } @@ -370,25 +370,25 @@ pub mod alloc_mod { self.seg_ctrl } - fn msgs_to_user(&self) -> Option> { + fn msgs_to_user(&self) -> Option>> { if let Some(msgs_to_user) = &self.msgs_to_user { return Some(msgs_to_user.iter().map(|tlv_owned| tlv_owned.as_tlv())); } None } - fn fault_handler_overrides(&self) -> Option> { + fn fault_handler_overrides(&self) -> Option>> { if let Some(fh_overrides) = &self.fault_handler_overrides { return Some(fh_overrides.iter().map(|tlv_owned| tlv_owned.as_tlv())); } None } - fn flow_label(&self) -> Option { + fn flow_label(&self) -> Option> { self.flow_label.as_ref().map(|tlv| tlv.as_tlv()) } - fn fs_requests(&self) -> Option> { + fn fs_requests(&self) -> Option>> { if let Some(requests) = &self.fs_requests { return Some(requests.iter().map(|tlv_owned| tlv_owned.as_tlv())); } diff --git a/src/source.rs b/src/source.rs index dbced99..eb1dd98 100644 --- a/src/source.rs +++ b/src/source.rs @@ -260,21 +260,21 @@ impl< /// * `cfg` - The local entity configuration for this source 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 - /// implementation from the underlying filestore/filesystem. This allows to use this handler - /// for embedded systems where a standard runtime might not be available. + /// implementation from the underlying filestore/filesystem. This allows to use this handler + /// for embedded systems where a standard runtime might not be available. /// * `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 - /// 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 - /// example 2048 or 4096 bytes. + /// 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 + /// example 2048 or 4096 bytes. /// * `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 - /// timers required by various tasks. This allows to use this handler for embedded systems - /// where the standard time APIs might not be available. + /// timers required by various tasks. This allows to use this handler for embedded systems + /// where the standard time APIs might not be available. /// * `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)] pub fn new( cfg: LocalEntityConfig, @@ -386,7 +386,7 @@ impl< /// 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 /// CFDP primtiive. - + /// /// 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 /// one file copy request at a time. @@ -505,7 +505,8 @@ impl< } if let Some(active_id) = self.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); } } @@ -1533,7 +1534,7 @@ mod tests { .open(&tb.srcfile) .expect("opening file failed"); let mut rand_data = [0u8; 140]; - rand::thread_rng().fill(&mut rand_data[..]); + rand::rng().fill(&mut rand_data[..]); file.write_all(&rand_data) .expect("writing file content failed"); drop(file); @@ -1552,7 +1553,7 @@ mod tests { .open(&tb.srcfile) .expect("opening file failed"); let mut rand_data = [0u8; 140]; - rand::thread_rng().fill(&mut rand_data[..]); + rand::rng().fill(&mut rand_data[..]); file.write_all(&rand_data) .expect("writing file content failed"); drop(file); @@ -1748,7 +1749,7 @@ mod tests { .open(&tb.srcfile) .expect("opening file failed"); let mut rand_data = [0u8; 140]; - rand::thread_rng().fill(&mut rand_data[..]); + rand::rng().fill(&mut rand_data[..]); file.write_all(&rand_data) .expect("writing file content failed"); drop(file); -- 2.43.0