diff --git a/fsrc-core/src/pus/mod.rs b/fsrc-core/src/pus/mod.rs index 6abb03a..f8f4901 100644 --- a/fsrc-core/src/pus/mod.rs +++ b/fsrc-core/src/pus/mod.rs @@ -1,2 +1,7 @@ +//! All PUS support modules +//! +//! Currenty includes: +//! +//! 1. PUS Verification Service 1 module inside [verification] #[cfg(feature = "alloc")] pub mod verification; diff --git a/fsrc-core/src/pus/verification.rs b/fsrc-core/src/pus/verification.rs index 58fb382..6fe87a6 100644 --- a/fsrc-core/src/pus/verification.rs +++ b/fsrc-core/src/pus/verification.rs @@ -1,3 +1,10 @@ +//! # PUS Verification Service 1 Module +//! +//! This module allows packaging and sending PUS Service 1 packets. It is conforming to section +//! 8 of the PUS standard ECSS-E-ST-70-41C. +//! +//! # Example +//! TODO: Cross Ref integration test which will be provided use crate::pool::{LocalPool, StoreAddr, StoreError}; use alloc::boxed::Box; use alloc::sync::Arc; @@ -9,7 +16,7 @@ use delegate::delegate; use downcast_rs::{impl_downcast, Downcast}; use spacepackets::ecss::{EcssEnumeration, PusError}; use spacepackets::tc::PusTc; -use spacepackets::time::{CcsdsTimeProvider, TimestampError}; +use spacepackets::time::TimestampError; use spacepackets::tm::{PusTm, PusTmSecondaryHeader}; use spacepackets::{ByteConversionError, SizeMissmatch, SpHeader}; use spacepackets::{CcsdsPacket, PacketId, PacketSequenceCtrl}; @@ -21,6 +28,8 @@ use std::sync::MutexGuard; #[cfg(feature = "std")] use std::sync::{mpsc, Mutex}; +/// This is a request identifier as specified in 5.4.11.2 c. of the PUS standard +/// This field equivalent to the first two bytes of the CCSDS space packet header. #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub struct RequestId { version_number: u8, @@ -51,6 +60,7 @@ impl RequestId { } } impl RequestId { + /// This allows extracting the request ID from a given PUS telecommand. pub fn new(tc: &PusTc) -> Self { RequestId { version_number: tc.ccsds_version(), @@ -60,23 +70,36 @@ impl RequestId { } } +/// Generic error type which is also able to wrap a user send error with the user supplied type E. #[derive(Debug, Clone)] pub enum VerificationError { + /// Errors related to sending the verification telemetry to a TM recipient SendError(E), + /// Errors related to the time stamp format of the telemetry TimestampError(TimestampError), + /// Errors related to byte conversion, for example unsufficient buffer size for given data ByteConversionError(ByteConversionError), + /// Errors related to PUS packet format PusError(PusError), } +/// If a verification operation fails, the passed token will be returned as well. This allows +/// re-trying the operation at a later point. #[derive(Debug, Clone)] pub struct VerificationErrorWithToken(VerificationError, VerificationToken); +/// Generic trait for a user supplied sender object. This sender object is responsible for sending +/// PUS Service 1 Verification Telemetry to a verification TM recipient. The [Downcast] trait +/// is implemented to allow passing the sender as a boxed trait object and still retrieve the +/// concrete type at a later point. pub trait VerificationSender: Downcast { fn send_verification_tm(&mut self, tm: PusTm) -> Result<(), VerificationError>; } impl_downcast!(VerificationSender); +/// Support token to allow type-state programming. This prevents calling the verification +/// steps in an invalid order. #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub struct VerificationToken { state: PhantomData, @@ -102,26 +125,39 @@ impl VerificationToken { pub struct VerificationReporterCfg { pub apid: u16, pub dest_id: u16, - pub step_field_width: u8, - pub failure_code_field_width: u8, + pub step_field_width: usize, + pub fail_code_field_width: usize, pub max_fail_data_len: usize, - pub max_stamp_len: usize, } impl VerificationReporterCfg { - pub fn new(time_stamper: impl CcsdsTimeProvider, apid: u16) -> Self { - let max_stamp_len = time_stamper.len_as_bytes(); + /// Create a new configuration for the verification reporter. This includes following parameters: + /// + /// 1. Destination ID and APID, which could remain constant after construction. These parameters + /// can be tweaked in the reporter after construction. + /// 2. Maximum expected field sizes. The parameters of this configuration struct will be used + /// to determine required maximum buffer sizes and there will be no addition allocation or + /// configurable buffer parameters after [VerificationReporter] construction. + /// + /// This means the user has supply the maximum expected field sizes of verification messages + /// before constructing the reporter. + pub fn new( + apid: u16, + step_field_width: usize, + fail_code_field_width: usize, + max_fail_data_len: usize, + ) -> Self { Self { apid, dest_id: 0, - step_field_width: size_of::() as u8, - failure_code_field_width: size_of::() as u8, - max_fail_data_len: 2 * size_of::(), - max_stamp_len, + step_field_width, + fail_code_field_width, + max_fail_data_len, } } } +/// Composite helper struct to pass failure parameters to the [VerificationReporter] pub struct FailParams<'a> { time_stamp: &'a [u8], failure_code: &'a dyn EcssEnumeration, @@ -142,6 +178,7 @@ impl<'a> FailParams<'a> { } } +/// Composite helper struct to pass step failure parameters to the [VerificationReporter] pub struct FailParamsWithStep<'a> { bp: FailParams<'a>, step: &'a dyn EcssEnumeration, @@ -161,6 +198,8 @@ impl<'a> FailParamsWithStep<'a> { } } +/// Primary verification handler. It provides an API to send PUS 1 verification telemetry packets +/// and verify the various steps of telecommand handling as specified in the PUS standard. pub struct VerificationReporter { pub apid: u16, pub dest_id: u16, @@ -178,7 +217,7 @@ impl VerificationReporter { 0; RequestId::SIZE_AS_BYTES + cfg.step_field_width as usize - + cfg.failure_code_field_width as usize + + cfg.fail_code_field_width as usize + cfg.max_fail_data_len ], } @@ -188,14 +227,19 @@ impl VerificationReporter { self.source_data_buf.capacity() } + /// Initialize verification handling by passing a TC reference. This returns a token required + /// to call the acceptance functions pub fn add_tc(&mut self, pus_tc: &PusTc) -> VerificationToken { self.add_tc_with_req_id(RequestId::new(pus_tc)) } + /// Same as [Self::add_tc] but pass a request ID instead of the direct telecommand. + /// This can be useful if the executing thread does not have full access to the telecommand. pub fn add_tc_with_req_id(&mut self, req_id: RequestId) -> VerificationToken { VerificationToken::::new(req_id) } + /// Package and send a PUS TM\[1, 1\] packet, see 8.1.2.1 of the PUS standard pub fn acceptance_success( &mut self, token: VerificationToken, @@ -221,6 +265,7 @@ impl VerificationReporter { }) } + /// Package and send a PUS TM\[1, 2\] packet, see 8.1.2.2 of the PUS standard pub fn acceptance_failure( &mut self, token: VerificationToken, @@ -237,6 +282,9 @@ impl VerificationReporter { Ok(()) } + /// Package and send a PUS TM\[1, 3\] packet, see 8.1.2.3 of the PUS standard. + /// + /// Requires a token previously acquired by calling [Self::acceptance_success]. pub fn start_success( &mut self, token: VerificationToken, @@ -262,6 +310,10 @@ impl VerificationReporter { }) } + /// Package and send a PUS TM\[1, 4\] packet, see 8.1.2.4 of the PUS standard. + /// + /// Requires a token previously acquired by calling [Self::acceptance_success]. It consumes + /// the token because verification handling is done. pub fn start_failure( &mut self, token: VerificationToken, @@ -278,6 +330,9 @@ impl VerificationReporter { Ok(()) } + /// Package and send a PUS TM\[1, 5\] packet, see 8.1.2.5 of the PUS standard. + /// + /// Requires a token previously acquired by calling [Self::start_success]. pub fn step_success( &mut self, token: &VerificationToken, @@ -291,6 +346,10 @@ impl VerificationReporter { Ok(()) } + /// Package and send a PUS TM\[1, 6\] packet, see 8.1.2.6 of the PUS standard. + /// + /// Requires a token previously acquired by calling [Self::start_success]. It consumes the + /// token because verification handling is done. pub fn step_failure( &mut self, token: VerificationToken, @@ -307,6 +366,10 @@ impl VerificationReporter { Ok(()) } + /// Package and send a PUS TM\[1, 7\] packet, see 8.1.2.7 of the PUS standard. + /// + /// Requires a token previously acquired by calling [Self::start_success]. It consumes the + /// token because verification handling is done. pub fn completion_success( &mut self, token: VerificationToken, @@ -329,6 +392,10 @@ impl VerificationReporter { Ok(()) } + /// Package and send a PUS TM\[1, 8\] packet, see 8.1.2.8 of the PUS standard. + /// + /// Requires a token previously acquired by calling [Self::start_success]. It consumes the + /// token because verification handling is done. pub fn completion_failure( &mut self, token: VerificationToken, @@ -458,6 +525,8 @@ impl VerificationReporter { } } +/// Helper object which caches the sender passed as a trait object. Provides the same +/// API as [VerificationReporter] but without the explicit sender arguments. pub struct VerificationReporterWithSender { reporter: VerificationReporter, pub sender: Box>, @@ -625,7 +694,6 @@ mod tests { use alloc::vec::Vec; use spacepackets::ecss::{EcssEnumU16, EcssEnumU32, EcssEnumU8, EcssEnumeration, PusPacket}; use spacepackets::tc::{PusTc, PusTcSecondaryHeader}; - use spacepackets::time::CdsShortTimeProvider; use spacepackets::tm::{PusTm, PusTmSecondaryHeaderT}; use spacepackets::{ByteConversionError, CcsdsPacket, SpHeader}; use std::collections::VecDeque; @@ -712,7 +780,7 @@ mod tests { } fn base_reporter() -> VerificationReporter { - let cfg = VerificationReporterCfg::new(CdsShortTimeProvider::default(), TEST_APID); + let cfg = VerificationReporterCfg::new(TEST_APID, 1, 2, 8); VerificationReporter::new(cfg) } diff --git a/fsrc-core/src/tmtc/ccsds_distrib.rs b/fsrc-core/src/tmtc/ccsds_distrib.rs index ec084a6..92d6c39 100644 --- a/fsrc-core/src/tmtc/ccsds_distrib.rs +++ b/fsrc-core/src/tmtc/ccsds_distrib.rs @@ -8,7 +8,7 @@ //! pass raw or CCSDS packets to it. Upon receiving a packet, it performs the following steps: //! //! 1. It tries to identify the target Application Process Identifier (APID) based on the -//! respective CCSDS space packet header field. If that process fails, a [PacketError] is +//! respective CCSDS space packet header field. If that process fails, a [ByteConversionError] is //! returned to the user //! 2. If a valid APID is found and matches one of the APIDs provided by //! [CcsdsPacketHandler::valid_apids], it will pass the packet to the user provided