basic docs

This commit is contained in:
Robin Müller 2022-09-06 10:44:13 +02:00
parent d917703e7d
commit 5a5985dfb6
No known key found for this signature in database
GPG Key ID: 71B58F8A3CDFA9AC
3 changed files with 87 additions and 14 deletions

View File

@ -1,2 +1,7 @@
//! All PUS support modules
//!
//! Currenty includes:
//!
//! 1. PUS Verification Service 1 module inside [verification]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub mod verification; pub mod verification;

View File

@ -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 crate::pool::{LocalPool, StoreAddr, StoreError};
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::sync::Arc; use alloc::sync::Arc;
@ -9,7 +16,7 @@ use delegate::delegate;
use downcast_rs::{impl_downcast, Downcast}; use downcast_rs::{impl_downcast, Downcast};
use spacepackets::ecss::{EcssEnumeration, PusError}; use spacepackets::ecss::{EcssEnumeration, PusError};
use spacepackets::tc::PusTc; use spacepackets::tc::PusTc;
use spacepackets::time::{CcsdsTimeProvider, TimestampError}; use spacepackets::time::TimestampError;
use spacepackets::tm::{PusTm, PusTmSecondaryHeader}; use spacepackets::tm::{PusTm, PusTmSecondaryHeader};
use spacepackets::{ByteConversionError, SizeMissmatch, SpHeader}; use spacepackets::{ByteConversionError, SizeMissmatch, SpHeader};
use spacepackets::{CcsdsPacket, PacketId, PacketSequenceCtrl}; use spacepackets::{CcsdsPacket, PacketId, PacketSequenceCtrl};
@ -21,6 +28,8 @@ use std::sync::MutexGuard;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::sync::{mpsc, Mutex}; 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)] #[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub struct RequestId { pub struct RequestId {
version_number: u8, version_number: u8,
@ -51,6 +60,7 @@ impl RequestId {
} }
} }
impl RequestId { impl RequestId {
/// This allows extracting the request ID from a given PUS telecommand.
pub fn new(tc: &PusTc) -> Self { pub fn new(tc: &PusTc) -> Self {
RequestId { RequestId {
version_number: tc.ccsds_version(), 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)] #[derive(Debug, Clone)]
pub enum VerificationError<E> { pub enum VerificationError<E> {
/// Errors related to sending the verification telemetry to a TM recipient
SendError(E), SendError(E),
/// Errors related to the time stamp format of the telemetry
TimestampError(TimestampError), TimestampError(TimestampError),
/// Errors related to byte conversion, for example unsufficient buffer size for given data
ByteConversionError(ByteConversionError), ByteConversionError(ByteConversionError),
/// Errors related to PUS packet format
PusError(PusError), 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)] #[derive(Debug, Clone)]
pub struct VerificationErrorWithToken<E, T>(VerificationError<E>, VerificationToken<T>); pub struct VerificationErrorWithToken<E, T>(VerificationError<E>, VerificationToken<T>);
/// 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<E>: Downcast { pub trait VerificationSender<E>: Downcast {
fn send_verification_tm(&mut self, tm: PusTm) -> Result<(), VerificationError<E>>; fn send_verification_tm(&mut self, tm: PusTm) -> Result<(), VerificationError<E>>;
} }
impl_downcast!(VerificationSender<E>); impl_downcast!(VerificationSender<E>);
/// Support token to allow type-state programming. This prevents calling the verification
/// steps in an invalid order.
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct VerificationToken<STATE> { pub struct VerificationToken<STATE> {
state: PhantomData<STATE>, state: PhantomData<STATE>,
@ -102,26 +125,39 @@ impl<STATE> VerificationToken<STATE> {
pub struct VerificationReporterCfg { pub struct VerificationReporterCfg {
pub apid: u16, pub apid: u16,
pub dest_id: u16, pub dest_id: u16,
pub step_field_width: u8, pub step_field_width: usize,
pub failure_code_field_width: u8, pub fail_code_field_width: usize,
pub max_fail_data_len: usize, pub max_fail_data_len: usize,
pub max_stamp_len: usize,
} }
impl VerificationReporterCfg { impl VerificationReporterCfg {
pub fn new(time_stamper: impl CcsdsTimeProvider, apid: u16) -> Self { /// Create a new configuration for the verification reporter. This includes following parameters:
let max_stamp_len = time_stamper.len_as_bytes(); ///
/// 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 { Self {
apid, apid,
dest_id: 0, dest_id: 0,
step_field_width: size_of::<u8>() as u8, step_field_width,
failure_code_field_width: size_of::<u16>() as u8, fail_code_field_width,
max_fail_data_len: 2 * size_of::<u32>(), max_fail_data_len,
max_stamp_len,
} }
} }
} }
/// Composite helper struct to pass failure parameters to the [VerificationReporter]
pub struct FailParams<'a> { pub struct FailParams<'a> {
time_stamp: &'a [u8], time_stamp: &'a [u8],
failure_code: &'a dyn EcssEnumeration, 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> { pub struct FailParamsWithStep<'a> {
bp: FailParams<'a>, bp: FailParams<'a>,
step: &'a dyn EcssEnumeration, 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 struct VerificationReporter {
pub apid: u16, pub apid: u16,
pub dest_id: u16, pub dest_id: u16,
@ -178,7 +217,7 @@ impl VerificationReporter {
0; 0;
RequestId::SIZE_AS_BYTES RequestId::SIZE_AS_BYTES
+ cfg.step_field_width as usize + 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 + cfg.max_fail_data_len
], ],
} }
@ -188,14 +227,19 @@ impl VerificationReporter {
self.source_data_buf.capacity() 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<StateNone> { pub fn add_tc(&mut self, pus_tc: &PusTc) -> VerificationToken<StateNone> {
self.add_tc_with_req_id(RequestId::new(pus_tc)) 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<StateNone> { pub fn add_tc_with_req_id(&mut self, req_id: RequestId) -> VerificationToken<StateNone> {
VerificationToken::<StateNone>::new(req_id) VerificationToken::<StateNone>::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<E>( pub fn acceptance_success<E>(
&mut self, &mut self,
token: VerificationToken<StateNone>, token: VerificationToken<StateNone>,
@ -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<E>( pub fn acceptance_failure<E>(
&mut self, &mut self,
token: VerificationToken<StateNone>, token: VerificationToken<StateNone>,
@ -237,6 +282,9 @@ impl VerificationReporter {
Ok(()) 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<E>( pub fn start_success<E>(
&mut self, &mut self,
token: VerificationToken<StateAccepted>, token: VerificationToken<StateAccepted>,
@ -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<E>( pub fn start_failure<E>(
&mut self, &mut self,
token: VerificationToken<StateAccepted>, token: VerificationToken<StateAccepted>,
@ -278,6 +330,9 @@ impl VerificationReporter {
Ok(()) 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<E>( pub fn step_success<E>(
&mut self, &mut self,
token: &VerificationToken<StateStarted>, token: &VerificationToken<StateStarted>,
@ -291,6 +346,10 @@ impl VerificationReporter {
Ok(()) 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<E>( pub fn step_failure<E>(
&mut self, &mut self,
token: VerificationToken<StateStarted>, token: VerificationToken<StateStarted>,
@ -307,6 +366,10 @@ impl VerificationReporter {
Ok(()) 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<E>( pub fn completion_success<E>(
&mut self, &mut self,
token: VerificationToken<StateStarted>, token: VerificationToken<StateStarted>,
@ -329,6 +392,10 @@ impl VerificationReporter {
Ok(()) 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<E>( pub fn completion_failure<E>(
&mut self, &mut self,
token: VerificationToken<StateStarted>, token: VerificationToken<StateStarted>,
@ -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<E> { pub struct VerificationReporterWithSender<E> {
reporter: VerificationReporter, reporter: VerificationReporter,
pub sender: Box<dyn VerificationSender<E>>, pub sender: Box<dyn VerificationSender<E>>,
@ -625,7 +694,6 @@ mod tests {
use alloc::vec::Vec; use alloc::vec::Vec;
use spacepackets::ecss::{EcssEnumU16, EcssEnumU32, EcssEnumU8, EcssEnumeration, PusPacket}; use spacepackets::ecss::{EcssEnumU16, EcssEnumU32, EcssEnumU8, EcssEnumeration, PusPacket};
use spacepackets::tc::{PusTc, PusTcSecondaryHeader}; use spacepackets::tc::{PusTc, PusTcSecondaryHeader};
use spacepackets::time::CdsShortTimeProvider;
use spacepackets::tm::{PusTm, PusTmSecondaryHeaderT}; use spacepackets::tm::{PusTm, PusTmSecondaryHeaderT};
use spacepackets::{ByteConversionError, CcsdsPacket, SpHeader}; use spacepackets::{ByteConversionError, CcsdsPacket, SpHeader};
use std::collections::VecDeque; use std::collections::VecDeque;
@ -712,7 +780,7 @@ mod tests {
} }
fn base_reporter() -> VerificationReporter { fn base_reporter() -> VerificationReporter {
let cfg = VerificationReporterCfg::new(CdsShortTimeProvider::default(), TEST_APID); let cfg = VerificationReporterCfg::new(TEST_APID, 1, 2, 8);
VerificationReporter::new(cfg) VerificationReporter::new(cfg)
} }

View File

@ -8,7 +8,7 @@
//! pass raw or CCSDS packets to it. Upon receiving a packet, it performs the following steps: //! 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 //! 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 //! returned to the user
//! 2. If a valid APID is found and matches one of the APIDs provided by //! 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 //! [CcsdsPacketHandler::valid_apids], it will pass the packet to the user provided