OBSW-Client Example #11
@ -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;
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user