Dependency updates and doc improvements #7
@@ -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
|
||||
|
27
Cargo.toml
27
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"
|
||||
|
18
README.md
18
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
|
||||
|
27
src/dest.rs
27
src/dest.rs
@@ -92,6 +92,7 @@ struct TransferState<Countdown: CountdownProvider> {
|
||||
transaction_id: Option<TransactionId>,
|
||||
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<UserFaultHook>,
|
||||
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,
|
||||
|
42
src/lib.rs
42
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))]
|
||||
|
@@ -24,10 +24,10 @@ pub trait ReadablePutRequest {
|
||||
fn closure_requested(&self) -> Option<bool>;
|
||||
fn seg_ctrl(&self) -> Option<SegmentationControl>;
|
||||
|
||||
fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv>>;
|
||||
fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv>>;
|
||||
fn flow_label(&self) -> Option<Tlv>;
|
||||
fn fs_requests(&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 flow_label(&self) -> Option<Tlv<'_>>;
|
||||
fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv<'_>>>;
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
@@ -101,25 +101,25 @@ impl ReadablePutRequest for PutRequest<'_, '_, '_, '_, '_, '_> {
|
||||
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 {
|
||||
return Some(msgs_to_user.iter().copied());
|
||||
}
|
||||
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 {
|
||||
return Some(fh_overrides.iter().copied());
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn flow_label(&self) -> Option<Tlv> {
|
||||
fn flow_label(&self) -> Option<Tlv<'_>> {
|
||||
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 {
|
||||
return Some(fs_requests.iter().copied());
|
||||
}
|
||||
@@ -370,25 +370,25 @@ pub mod alloc_mod {
|
||||
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 {
|
||||
return Some(msgs_to_user.iter().map(|tlv_owned| tlv_owned.as_tlv()));
|
||||
}
|
||||
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 {
|
||||
return Some(fh_overrides.iter().map(|tlv_owned| tlv_owned.as_tlv()));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn flow_label(&self) -> Option<Tlv> {
|
||||
fn flow_label(&self) -> Option<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 {
|
||||
return Some(requests.iter().map(|tlv_owned| tlv_owned.as_tlv()));
|
||||
}
|
||||
|
@@ -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<UserFaultHook>,
|
||||
@@ -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);
|
||||
|
Reference in New Issue
Block a user