sat-rs/satrs-core/src/pus/mod.rs

646 lines
21 KiB
Rust
Raw Normal View History

2023-01-25 10:52:24 +01:00
//! # PUS support modules
2023-07-06 01:14:01 +02:00
//!
//! This module contains structures to make working with the PUS C standard easier.
//! The satrs-example application contains various usage examples of these components.
2023-07-08 14:57:11 +02:00
use crate::SenderId;
2023-07-09 13:23:34 +02:00
use core::fmt::{Display, Formatter};
#[cfg(feature = "alloc")]
use downcast_rs::{impl_downcast, Downcast};
#[cfg(feature = "alloc")]
use dyn_clone::DynClone;
use spacepackets::ecss::PusError;
2023-07-09 13:32:59 +02:00
use spacepackets::tc::PusTc;
use spacepackets::tm::PusTm;
2023-07-09 18:38:09 +02:00
use spacepackets::{ByteConversionError, SizeMissmatch, SpHeader};
2023-07-09 13:23:34 +02:00
use std::error::Error;
pub mod event;
pub mod event_man;
2023-07-05 14:25:51 +02:00
pub mod event_srv;
pub mod hk;
2023-02-15 11:05:32 +01:00
pub mod mode;
2023-07-05 11:25:23 +02:00
pub mod scheduler;
pub mod scheduler_srv;
2023-01-21 12:19:05 +01:00
#[cfg(feature = "std")]
2023-07-05 11:25:23 +02:00
pub mod test;
pub mod verification;
2023-01-25 10:52:24 +01:00
#[cfg(feature = "alloc")]
pub use alloc_mod::*;
2023-07-09 20:05:45 +02:00
use crate::pool::{PoolGuard, PoolRwGuard, StoreAddr, StoreError};
use crate::pus::verification::{TcStateAccepted, TcStateToken, VerificationToken};
2023-02-27 17:00:21 +01:00
#[cfg(feature = "std")]
pub use std_mod::*;
2023-07-08 14:57:11 +02:00
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum PusTmWrapper<'tm> {
InStore(StoreAddr),
Direct(PusTm<'tm>),
}
impl From<StoreAddr> for PusTmWrapper<'_> {
fn from(value: StoreAddr) -> Self {
Self::InStore(value)
}
}
impl<'tm> From<PusTm<'tm>> for PusTmWrapper<'tm> {
fn from(value: PusTm<'tm>) -> Self {
Self::Direct(value)
}
}
2023-07-09 20:05:45 +02:00
pub type TcAddrWithToken = (StoreAddr, TcStateToken);
/// Generic abstraction for a telecommand being sent around after is has been accepted.
/// The actual telecommand is stored inside a pre-allocated pool structure.
pub type AcceptedTc = (StoreAddr, VerificationToken<TcStateAccepted>);
2023-07-09 13:23:34 +02:00
/// Generic error type for sending something via a message queue.
2023-07-09 13:04:00 +02:00
#[derive(Debug, Copy, Clone)]
2023-07-09 13:23:34 +02:00
pub enum GenericSendError {
2023-07-09 13:04:00 +02:00
RxDisconnected,
QueueFull(u32),
}
2023-07-09 13:23:34 +02:00
impl Display for GenericSendError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
GenericSendError::RxDisconnected => {
write!(f, "rx side has disconnected")
}
GenericSendError::QueueFull(max_cap) => {
write!(f, "queue with max capacity of {max_cap} is full")
}
}
}
}
#[cfg(feature = "std")]
impl Error for GenericSendError {}
2023-07-09 20:05:45 +02:00
/// Generic error type for sending something via a message queue.
#[derive(Debug, Copy, Clone)]
pub enum GenericRecvError {
Empty,
TxDisconnected,
}
impl Display for GenericRecvError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
Self::TxDisconnected => {
write!(f, "tx side has disconnected")
}
Self::Empty => {
write!(f, "nothing to receive")
}
}
}
}
#[cfg(feature = "std")]
impl Error for GenericRecvError {}
2023-07-09 13:23:34 +02:00
#[derive(Debug, Clone)]
2023-07-09 20:05:45 +02:00
pub enum EcssTmtcError {
2023-07-09 13:23:34 +02:00
StoreLock,
Store(StoreError),
Pus(PusError),
CantSendAddr(StoreAddr),
Send(GenericSendError),
2023-07-09 20:05:45 +02:00
Recv(GenericRecvError),
2023-07-09 13:23:34 +02:00
}
2023-07-09 20:05:45 +02:00
impl Display for EcssTmtcError {
2023-07-09 13:23:34 +02:00
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
2023-07-09 20:05:45 +02:00
EcssTmtcError::StoreLock => {
2023-07-09 13:23:34 +02:00
write!(f, "store lock error")
}
2023-07-09 20:05:45 +02:00
EcssTmtcError::Store(store) => {
2023-07-09 13:23:34 +02:00
write!(f, "store error: {store}")
}
2023-07-09 20:05:45 +02:00
EcssTmtcError::Pus(pus_e) => {
2023-07-09 13:23:34 +02:00
write!(f, "PUS error: {pus_e}")
}
2023-07-09 20:05:45 +02:00
EcssTmtcError::CantSendAddr(addr) => {
2023-07-09 13:23:34 +02:00
write!(f, "can not send address {addr}")
}
2023-07-09 20:05:45 +02:00
EcssTmtcError::Send(send_e) => {
2023-07-09 13:23:34 +02:00
write!(f, "send error {send_e}")
}
2023-07-09 20:05:45 +02:00
EcssTmtcError::Recv(recv_e) => {
write!(f, "recv error {recv_e}")
}
2023-07-09 13:23:34 +02:00
}
}
}
2023-07-09 20:05:45 +02:00
impl From<StoreError> for EcssTmtcError {
2023-07-09 13:23:34 +02:00
fn from(value: StoreError) -> Self {
Self::Store(value)
}
}
2023-07-09 20:05:45 +02:00
impl From<PusError> for EcssTmtcError {
2023-07-09 13:23:34 +02:00
fn from(value: PusError) -> Self {
Self::Pus(value)
}
}
2023-07-09 20:05:45 +02:00
impl From<GenericSendError> for EcssTmtcError {
2023-07-09 13:23:34 +02:00
fn from(value: GenericSendError) -> Self {
Self::Send(value)
}
}
2023-07-09 20:05:45 +02:00
impl From<GenericRecvError> for EcssTmtcError {
fn from(value: GenericRecvError) -> Self {
Self::Recv(value)
}
}
2023-07-09 13:23:34 +02:00
#[cfg(feature = "std")]
2023-07-09 20:05:45 +02:00
impl Error for EcssTmtcError {
2023-07-09 13:23:34 +02:00
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
2023-07-09 20:05:45 +02:00
EcssTmtcError::Store(e) => Some(e),
EcssTmtcError::Pus(e) => Some(e),
EcssTmtcError::Send(e) => Some(e),
2023-07-09 13:23:34 +02:00
_ => None,
}
}
}
2023-07-09 20:05:45 +02:00
pub trait EcssChannel: Send {
/// Each sender can have an ID associated with it
fn id(&self) -> SenderId;
fn name(&self) -> &'static str {
"unset"
}
}
2023-07-09 13:32:59 +02:00
/// Generic trait for a user supplied sender object.
///
/// This sender object is responsible for sending PUS telemetry to a TM sink.
2023-07-09 20:05:45 +02:00
pub trait EcssTmSenderCore: EcssChannel {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError>;
2023-07-09 13:32:59 +02:00
}
/// Generic trait for a user supplied sender object.
///
/// This sender object is responsible for sending PUS telecommands to a TC recipient. Each
/// telecommand can optionally have a token which contains its verification state.
2023-07-09 20:05:45 +02:00
pub trait EcssTcSenderCore: EcssChannel {
fn send_tc(&self, tc: PusTc, token: Option<TcStateToken>) -> Result<(), EcssTmtcError>;
}
pub struct ReceivedTcWrapper<'raw_tc> {
pub pool_guard: PoolGuard<'raw_tc>,
pub tc: PusTc<'raw_tc>,
pub token: Option<TcStateToken>,
}
/// Generic trait for a user supplied receiver object.
pub trait EcssTcReceiverCore: EcssChannel {
fn recv_tc<'buf>(&self, buf: &'buf mut [u8]) -> Result<ReceivedTcWrapper<'buf>, EcssTmtcError>;
}
/// Generic trait for objects which can receive ECSS PUS telecommands. This trait is
/// implemented by the [crate::tmtc::pus_distrib::PusDistributor] objects to allow passing PUS TC
/// packets into it.
pub trait ReceivesEcssPusTc {
type Error;
fn pass_pus_tc(&mut self, header: &SpHeader, pus_tc: &PusTc) -> Result<(), Self::Error>;
2023-07-09 13:32:59 +02:00
}
#[cfg(feature = "alloc")]
2023-01-25 10:52:24 +01:00
mod alloc_mod {
use super::*;
/// Extension trait for [EcssTmSenderCore].
///
/// It provides additional functionality, for example by implementing the [Downcast] trait
/// and the [DynClone] trait.
///
/// [Downcast] is implemented to allow passing the sender as a boxed trait object and still
/// retrieve the concrete type at a later point.
///
/// [DynClone] allows cloning the trait object as long as the boxed object implements
/// [Clone].
2023-01-25 10:52:24 +01:00
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
pub trait EcssTmSender: EcssTmSenderCore + Downcast + DynClone {}
/// Blanket implementation for all types which implement [EcssTmSenderCore] and are clonable.
impl<T> EcssTmSender for T where T: EcssTmSenderCore + Clone + 'static {}
2023-07-09 13:04:00 +02:00
dyn_clone::clone_trait_object!(EcssTmSender);
impl_downcast!(EcssTmSender);
2023-07-03 00:42:20 +02:00
/// Extension trait for [EcssTcSenderCore].
///
/// It provides additional functionality, for example by implementing the [Downcast] trait
/// and the [DynClone] trait.
///
/// [Downcast] is implemented to allow passing the sender as a boxed trait object and still
/// retrieve the concrete type at a later point.
///
/// [DynClone] allows cloning the trait object as long as the boxed object implements
/// [Clone].
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
pub trait EcssTcSender: EcssTcSenderCore + Downcast + DynClone {}
/// Blanket implementation for all types which implement [EcssTcSenderCore] and are clonable.
impl<T> EcssTcSender for T where T: EcssTcSenderCore + Clone + 'static {}
2023-07-09 13:04:00 +02:00
dyn_clone::clone_trait_object!(EcssTcSender);
impl_downcast!(EcssTcSender);
2023-07-09 20:05:45 +02:00
/// Extension trait for [EcssTcReceiverCore].
///
/// It provides additional functionality, for example by implementing the [Downcast] trait
/// and the [DynClone] trait.
///
/// [Downcast] is implemented to allow passing the sender as a boxed trait object and still
/// retrieve the concrete type at a later point.
///
/// [DynClone] allows cloning the trait object as long as the boxed object implements
/// [Clone].
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
pub trait EcssTcReceiver: EcssTcReceiverCore + Downcast + DynClone {}
/// Blanket implementation for all types which implement [EcssTcReceiverCore] and are clonable.
impl<T> EcssTcReceiver for T where T: EcssTcReceiverCore + Clone + 'static {}
dyn_clone::clone_trait_object!(EcssTcReceiver);
impl_downcast!(EcssTcReceiver);
2023-07-09 18:38:09 +02:00
}
2023-02-27 17:00:21 +01:00
#[cfg(feature = "std")]
pub mod std_mod {
2023-07-09 20:19:53 +02:00
use crate::pool::{PoolGuard, SharedPool, StoreAddr};
2023-07-05 11:25:23 +02:00
use crate::pus::verification::{
2023-07-09 20:05:45 +02:00
StdVerifReporterWithSender, TcStateAccepted, TcStateToken, VerificationToken,
2023-07-05 11:25:23 +02:00
};
2023-07-09 13:32:59 +02:00
use crate::pus::{
2023-07-09 20:05:45 +02:00
AcceptedTc, EcssChannel, EcssTcReceiver, EcssTcReceiverCore, EcssTmSender,
EcssTmSenderCore, EcssTmtcError, GenericRecvError, GenericSendError, PusTmWrapper,
ReceivedTcWrapper, TcAddrWithToken,
2023-07-09 13:32:59 +02:00
};
2023-07-09 20:05:45 +02:00
use crate::tmtc::tm_helper::SharedTmStore;
use crate::SenderId;
2023-07-09 13:32:59 +02:00
use alloc::boxed::Box;
2023-02-27 17:00:21 +01:00
use alloc::vec::Vec;
2023-07-09 20:05:45 +02:00
use spacepackets::ecss::PusError;
use spacepackets::tc::PusTc;
2023-07-05 11:25:23 +02:00
use spacepackets::time::cds::TimeProvider;
2023-07-09 17:04:18 +02:00
use spacepackets::time::std_mod::StdTimestampError;
use spacepackets::time::TimeWriter;
2023-07-09 20:05:45 +02:00
use spacepackets::tm::PusTm;
use spacepackets::{ByteConversionError, SizeMissmatch};
2023-07-06 00:49:18 +02:00
use std::cell::RefCell;
2023-07-05 11:25:23 +02:00
use std::string::String;
2023-07-09 20:05:45 +02:00
use std::sync::mpsc;
use std::sync::mpsc::{SendError, TryRecvError};
2023-07-05 11:25:23 +02:00
use thiserror::Error;
2023-02-27 17:00:21 +01:00
#[derive(Clone)]
2023-07-08 14:57:11 +02:00
pub struct MpscTmInStoreSender {
id: SenderId,
name: &'static str,
2023-07-09 20:05:45 +02:00
shared_tm_store: SharedTmStore,
2023-02-27 17:00:21 +01:00
sender: mpsc::Sender<StoreAddr>,
pub ignore_poison_errors: bool,
}
2023-07-09 20:05:45 +02:00
impl EcssChannel for MpscTmInStoreSender {
fn id(&self) -> SenderId {
self.id
}
2023-07-03 00:42:20 +02:00
fn name(&self) -> &'static str {
self.name
}
}
2023-07-09 20:05:45 +02:00
impl From<SendError<StoreAddr>> for EcssTmtcError {
2023-07-09 13:23:34 +02:00
fn from(_: SendError<StoreAddr>) -> Self {
Self::Send(GenericSendError::RxDisconnected)
}
}
2023-07-08 14:57:11 +02:00
impl MpscTmInStoreSender {
2023-07-09 20:05:45 +02:00
pub fn send_direct_tm(&self, tm: PusTm) -> Result<(), EcssTmtcError> {
let addr = self.shared_tm_store.add_pus_tm(&tm)?;
self.sender
.send(addr)
.map_err(|_| EcssTmtcError::Send(GenericSendError::RxDisconnected))
2023-02-27 17:00:21 +01:00
}
2023-07-03 00:42:20 +02:00
}
2023-07-08 14:57:11 +02:00
impl EcssTmSenderCore for MpscTmInStoreSender {
2023-07-09 20:05:45 +02:00
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
2023-07-08 14:57:11 +02:00
match tm {
2023-07-09 13:23:34 +02:00
PusTmWrapper::InStore(addr) => self.sender.send(addr).map_err(|e| e.into()),
2023-07-08 14:57:11 +02:00
PusTmWrapper::Direct(tm) => self.send_direct_tm(tm),
}
}
2023-02-27 17:00:21 +01:00
}
2023-07-08 14:57:11 +02:00
impl MpscTmInStoreSender {
pub fn new(
id: SenderId,
name: &'static str,
2023-07-09 20:05:45 +02:00
shared_tm_store: SharedTmStore,
sender: mpsc::Sender<StoreAddr>,
) -> Self {
2023-02-27 17:00:21 +01:00
Self {
id,
name,
2023-07-09 20:05:45 +02:00
shared_tm_store,
2023-02-27 17:00:21 +01:00
sender,
ignore_poison_errors: false,
}
}
}
2023-07-09 20:05:45 +02:00
pub struct MpscTcInStoreReceiver {
id: SenderId,
name: &'static str,
shared_tc_pool: SharedPool,
receiver: mpsc::Receiver<TcAddrWithToken>,
pub ignore_poison_errors: bool,
}
impl EcssChannel for MpscTcInStoreReceiver {
fn id(&self) -> SenderId {
self.id
}
fn name(&self) -> &'static str {
self.name
}
}
impl EcssTcReceiverCore for MpscTcInStoreReceiver {
fn recv_tc<'buf>(
&self,
buf: &'buf mut [u8],
) -> Result<ReceivedTcWrapper<'buf>, EcssTmtcError> {
let (addr, token) = self.receiver.try_recv().map_err(|e| match e {
TryRecvError::Empty => GenericRecvError::Empty,
TryRecvError::Disconnected => GenericRecvError::TxDisconnected,
})?;
2023-07-09 20:19:53 +02:00
let mut shared_tc_pool = self
2023-07-09 20:05:45 +02:00
.shared_tc_pool
.read()
.map_err(|_| EcssTmtcError::StoreLock)?;
2023-07-09 20:19:53 +02:00
let pool_guard = shared_tc_pool.read_with_guard(addr);
let tc_raw = pool_guard.read()?;
2023-07-09 20:05:45 +02:00
if buf.len() < tc_raw.len() {
return Err(
PusError::ByteConversion(ByteConversionError::ToSliceTooSmall(SizeMissmatch {
found: buf.len(),
expected: tc_raw.len(),
}))
.into(),
);
}
buf[..tc_raw.len()].copy_from_slice(tc_raw);
let (tc, _) = PusTc::from_bytes(buf)?;
2023-07-09 20:19:53 +02:00
Ok((ReceivedTcWrapper {
tc,
pool_guard,
token: Some(token),
}))
2023-07-09 20:05:45 +02:00
}
}
2023-07-08 14:57:11 +02:00
/// This class can be used if frequent heap allocations during run-time are not an issue.
/// PUS TM packets will be sent around as [Vec]s. Please note that the current implementation
/// of this class can not deal with store addresses, so it is assumed that is is always
/// going to be called with direct packets.
#[derive(Clone)]
2023-02-27 17:00:21 +01:00
pub struct MpscTmAsVecSender {
id: SenderId,
2023-02-27 17:00:21 +01:00
sender: mpsc::Sender<Vec<u8>>,
name: &'static str,
2023-02-27 17:00:21 +01:00
}
2023-07-09 20:05:45 +02:00
impl From<SendError<Vec<u8>>> for EcssTmtcError {
2023-07-09 13:23:34 +02:00
fn from(_: SendError<Vec<u8>>) -> Self {
Self::Send(GenericSendError::RxDisconnected)
}
}
2023-02-27 17:00:21 +01:00
impl MpscTmAsVecSender {
pub fn new(id: u32, name: &'static str, sender: mpsc::Sender<Vec<u8>>) -> Self {
Self { id, sender, name }
2023-02-27 17:00:21 +01:00
}
}
2023-07-03 00:42:20 +02:00
2023-07-09 20:05:45 +02:00
impl EcssChannel for MpscTmAsVecSender {
fn id(&self) -> SenderId {
self.id
}
2023-07-03 00:42:20 +02:00
fn name(&self) -> &'static str {
self.name
}
}
impl EcssTmSenderCore for MpscTmAsVecSender {
2023-07-09 20:05:45 +02:00
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
2023-07-08 14:57:11 +02:00
match tm {
2023-07-09 20:05:45 +02:00
PusTmWrapper::InStore(addr) => Err(EcssTmtcError::CantSendAddr(addr)),
2023-07-08 14:57:11 +02:00
PusTmWrapper::Direct(tm) => {
let mut vec = Vec::new();
2023-07-09 20:05:45 +02:00
tm.append_to_vec(&mut vec).map_err(EcssTmtcError::Pus)?;
2023-07-09 13:23:34 +02:00
self.sender.send(vec)?;
2023-07-08 14:57:11 +02:00
Ok(())
}
}
2023-02-27 17:00:21 +01:00
}
}
2023-07-05 11:25:23 +02:00
#[derive(Debug, Clone, Error)]
pub enum PusPacketHandlingError {
2023-07-09 20:05:45 +02:00
#[error("generic PUS error: {0}")]
Pus(#[from] PusError),
#[error("wrong service number {0} for packet handler")]
2023-07-05 11:25:23 +02:00
WrongService(u8),
2023-07-09 20:05:45 +02:00
#[error("invalid subservice {0}")]
2023-07-05 14:25:51 +02:00
InvalidSubservice(u8),
2023-07-09 20:05:45 +02:00
#[error("not enough application data available: {0}")]
2023-07-05 11:25:23 +02:00
NotEnoughAppData(String),
2023-07-09 20:05:45 +02:00
#[error("invalid application data")]
2023-07-06 01:14:01 +02:00
InvalidAppData(String),
2023-07-09 20:05:45 +02:00
#[error("generic ECSS tmtc error: {0}")]
EcssTmtc(#[from] EcssTmtcError),
2023-07-09 20:19:53 +02:00
#[error("invalid verification token")]
InvalidVerificationToken,
2023-07-09 20:05:45 +02:00
#[error("other error {0}")]
Other(String),
2023-07-05 11:25:23 +02:00
}
#[derive(Debug, Clone, Error)]
pub enum PartialPusHandlingError {
2023-07-09 20:05:45 +02:00
#[error("generic timestamp generation error")]
2023-07-09 13:32:59 +02:00
Time(#[from] StdTimestampError),
2023-07-09 20:05:45 +02:00
#[error("error sending telemetry: {0}")]
TmSend(#[from] EcssTmtcError),
#[error("error sending verification message")]
2023-07-08 13:37:27 +02:00
Verification,
2023-07-09 20:05:45 +02:00
#[error("invalid verification token")]
NoVerificationToken,
2023-07-05 11:25:23 +02:00
}
2023-07-06 01:14:01 +02:00
/// Generic result type for handlers which can process PUS packets.
2023-07-05 11:25:23 +02:00
#[derive(Debug, Clone)]
pub enum PusPacketHandlerResult {
RequestHandled,
RequestHandledPartialSuccess(PartialPusHandlingError),
2023-07-09 20:05:45 +02:00
SubserviceNotImplemented(u8, TcStateToken),
CustomSubservice(u8, TcStateToken),
2023-07-05 11:25:23 +02:00
Empty,
}
impl From<PartialPusHandlingError> for PusPacketHandlerResult {
fn from(value: PartialPusHandlingError) -> Self {
Self::RequestHandledPartialSuccess(value)
}
}
2023-07-06 01:14:01 +02:00
/// Base class for handlers which can handle PUS TC packets. Right now, the message queue
/// backend is constrained to [mpsc::channel]s and the verification reporter
/// is constrained to the [StdVerifReporterWithSender].
2023-07-05 11:25:23 +02:00
pub struct PusServiceBase {
2023-07-09 20:05:45 +02:00
pub tc_receiver: Box<dyn EcssTcReceiver>,
2023-07-09 13:32:59 +02:00
pub tm_sender: Box<dyn EcssTmSender>,
2023-07-05 21:08:04 +02:00
pub tm_apid: u16,
2023-07-06 00:49:18 +02:00
/// The verification handler is wrapped in a [RefCell] to allow the interior mutability
/// pattern. This makes writing methods which are not mutable a lot easier.
pub verification_handler: RefCell<StdVerifReporterWithSender>,
2023-07-05 21:08:04 +02:00
pub pus_buf: [u8; 2048],
pub pus_size: usize,
2023-07-05 11:25:23 +02:00
}
impl PusServiceBase {
pub fn new(
2023-07-09 20:05:45 +02:00
tc_receiver: Box<dyn EcssTcReceiver>,
2023-07-09 13:32:59 +02:00
tm_sender: Box<dyn EcssTmSender>,
2023-07-05 11:25:23 +02:00
tm_apid: u16,
verification_handler: StdVerifReporterWithSender,
) -> Self {
Self {
2023-07-09 20:05:45 +02:00
tc_receiver,
2023-07-05 11:25:23 +02:00
tm_apid,
2023-07-09 13:32:59 +02:00
tm_sender,
2023-07-06 00:49:18 +02:00
verification_handler: RefCell::new(verification_handler),
2023-07-05 11:25:23 +02:00
pus_buf: [0; 2048],
pus_size: 0,
}
}
2023-07-05 21:08:04 +02:00
pub fn get_current_timestamp(
&self,
partial_error: &mut Option<PartialPusHandlingError>,
) -> [u8; 7] {
let mut time_stamp: [u8; 7] = [0; 7];
2023-07-05 11:25:23 +02:00
let time_provider =
2023-07-08 13:37:27 +02:00
TimeProvider::from_now_with_u16_days().map_err(PartialPusHandlingError::Time);
2023-07-05 11:25:23 +02:00
if let Ok(time_provider) = time_provider {
2023-07-08 14:57:11 +02:00
// Can't fail, we have a buffer with the exact required size.
2023-07-05 21:08:04 +02:00
time_provider.write_to_bytes(&mut time_stamp).unwrap();
2023-07-05 11:25:23 +02:00
} else {
2023-07-05 21:08:04 +02:00
*partial_error = Some(time_provider.unwrap_err());
2023-07-05 11:25:23 +02:00
}
2023-07-05 21:08:04 +02:00
time_stamp
2023-07-05 11:25:23 +02:00
}
2023-07-06 01:14:01 +02:00
2023-07-05 21:08:04 +02:00
pub fn get_current_timestamp_ignore_error(&self) -> [u8; 7] {
let mut dummy = None;
self.get_current_timestamp(&mut dummy)
2023-07-05 11:58:43 +02:00
}
2023-07-05 11:25:23 +02:00
}
pub trait PusServiceHandler {
fn psb_mut(&mut self) -> &mut PusServiceBase;
fn psb(&self) -> &PusServiceBase;
fn handle_one_tc(
&mut self,
2023-07-09 20:19:53 +02:00
tc: PusTc,
tc_guard: PoolGuard,
token: VerificationToken<TcStateAccepted>,
2023-07-05 11:25:23 +02:00
) -> Result<PusPacketHandlerResult, PusPacketHandlingError>;
2023-07-05 21:08:04 +02:00
2023-07-05 11:25:23 +02:00
fn handle_next_packet(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
2023-07-09 20:19:53 +02:00
match self.psb().tc_receiver.recv_tc(&mut self.psb_mut().pus_buf) {
Ok(ReceivedTcWrapper {
tc,
pool_guard,
token,
}) => {
if token.is_none() {
return Err(PusPacketHandlingError::InvalidVerificationToken);
}
let token = token.unwrap();
self.handle_one_tc(tc, pool_guard, token.try_into().unwrap())
}
2023-07-05 11:25:23 +02:00
Err(e) => match e {
2023-07-09 20:19:53 +02:00
EcssTmtcError::StoreLock => {}
EcssTmtcError::Store(_) => {}
EcssTmtcError::Pus(_) => {}
EcssTmtcError::CantSendAddr(_) => {}
EcssTmtcError::Send(_) => {}
EcssTmtcError::Recv(_) => {}
2023-07-05 11:25:23 +02:00
},
2023-07-09 20:05:45 +02:00
}
2023-07-05 11:25:23 +02:00
}
}
}
2023-07-09 20:05:45 +02:00
pub(crate) fn source_buffer_large_enough(cap: usize, len: usize) -> Result<(), EcssTmtcError> {
if len > cap {
2023-07-09 13:23:34 +02:00
return Err(
2023-07-09 20:05:45 +02:00
PusError::ByteConversion(ByteConversionError::ToSliceTooSmall(SizeMissmatch {
found: cap,
expected: len,
2023-07-09 13:23:34 +02:00
}))
.into(),
);
}
Ok(())
}
#[cfg(test)]
pub(crate) mod tests {
use spacepackets::tm::{GenericPusTmSecondaryHeader, PusTm};
use spacepackets::CcsdsPacket;
#[derive(Debug, Eq, PartialEq, Clone)]
pub(crate) struct CommonTmInfo {
pub subservice: u8,
pub apid: u16,
pub msg_counter: u16,
pub dest_id: u16,
pub time_stamp: [u8; 7],
}
impl CommonTmInfo {
pub fn new_from_tm(tm: &PusTm) -> Self {
let mut time_stamp = [0; 7];
2023-01-21 13:52:21 +01:00
time_stamp.clone_from_slice(&tm.timestamp().unwrap()[0..7]);
Self {
subservice: tm.subservice(),
apid: tm.apid(),
msg_counter: tm.msg_counter(),
dest_id: tm.dest_id(),
time_stamp,
}
}
}
}