1use crate::ChannelId;
6use core::fmt::{Display, Formatter};
7#[cfg(feature = "alloc")]
8use downcast_rs::{impl_downcast, Downcast};
9#[cfg(feature = "alloc")]
10use dyn_clone::DynClone;
11#[cfg(feature = "std")]
12use std::error::Error;
13
14use spacepackets::ecss::tc::{PusTcCreator, PusTcReader};
15use spacepackets::ecss::tm::PusTmCreator;
16use spacepackets::ecss::PusError;
17use spacepackets::{ByteConversionError, SpHeader};
18
19pub mod event;
20pub mod event_man;
21#[cfg(feature = "std")]
22pub mod event_srv;
23pub mod hk;
24pub mod mode;
25pub mod scheduler;
26#[cfg(feature = "std")]
27pub mod scheduler_srv;
28#[cfg(feature = "std")]
29pub mod test;
30pub mod verification;
31
32#[cfg(feature = "alloc")]
33pub use alloc_mod::*;
34
35use crate::pool::{StoreAddr, StoreError};
36use crate::pus::verification::{TcStateAccepted, TcStateToken, VerificationToken};
37#[cfg(feature = "std")]
38pub use std_mod::*;
39
40#[derive(Debug, PartialEq, Eq, Clone)]
41pub enum PusTmWrapper<'tm> {
42 InStore(StoreAddr),
43 Direct(PusTmCreator<'tm>),
44}
45
46impl From<StoreAddr> for PusTmWrapper<'_> {
47 fn from(value: StoreAddr) -> Self {
48 Self::InStore(value)
49 }
50}
51
52impl<'tm> From<PusTmCreator<'tm>> for PusTmWrapper<'tm> {
53 fn from(value: PusTmCreator<'tm>) -> Self {
54 Self::Direct(value)
55 }
56}
57
58#[derive(Debug, Copy, Clone)]
60pub enum GenericSendError {
61 RxDisconnected,
62 QueueFull(Option<u32>),
63}
64
65impl Display for GenericSendError {
66 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
67 match self {
68 GenericSendError::RxDisconnected => {
69 write!(f, "rx side has disconnected")
70 }
71 GenericSendError::QueueFull(max_cap) => {
72 write!(f, "queue with max capacity of {max_cap:?} is full")
73 }
74 }
75 }
76}
77
78#[cfg(feature = "std")]
79impl Error for GenericSendError {}
80
81#[derive(Debug, Copy, Clone)]
83pub enum GenericRecvError {
84 Empty,
85 TxDisconnected,
86}
87
88impl Display for GenericRecvError {
89 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
90 match self {
91 Self::TxDisconnected => {
92 write!(f, "tx side has disconnected")
93 }
94 Self::Empty => {
95 write!(f, "nothing to receive")
96 }
97 }
98 }
99}
100
101#[cfg(feature = "std")]
102impl Error for GenericRecvError {}
103
104#[derive(Debug, Clone)]
105pub enum EcssTmtcError {
106 StoreLock,
107 Store(StoreError),
108 Pus(PusError),
109 CantSendAddr(StoreAddr),
110 Send(GenericSendError),
111 Recv(GenericRecvError),
112}
113
114impl Display for EcssTmtcError {
115 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
116 match self {
117 EcssTmtcError::StoreLock => {
118 write!(f, "store lock error")
119 }
120 EcssTmtcError::Store(store) => {
121 write!(f, "store error: {store}")
122 }
123 EcssTmtcError::Pus(pus_e) => {
124 write!(f, "PUS error: {pus_e}")
125 }
126 EcssTmtcError::CantSendAddr(addr) => {
127 write!(f, "can not send address {addr}")
128 }
129 EcssTmtcError::Send(send_e) => {
130 write!(f, "send error {send_e}")
131 }
132 EcssTmtcError::Recv(recv_e) => {
133 write!(f, "recv error {recv_e}")
134 }
135 }
136 }
137}
138
139impl From<StoreError> for EcssTmtcError {
140 fn from(value: StoreError) -> Self {
141 Self::Store(value)
142 }
143}
144
145impl From<PusError> for EcssTmtcError {
146 fn from(value: PusError) -> Self {
147 Self::Pus(value)
148 }
149}
150
151impl From<GenericSendError> for EcssTmtcError {
152 fn from(value: GenericSendError) -> Self {
153 Self::Send(value)
154 }
155}
156
157impl From<GenericRecvError> for EcssTmtcError {
158 fn from(value: GenericRecvError) -> Self {
159 Self::Recv(value)
160 }
161}
162
163#[cfg(feature = "std")]
164impl Error for EcssTmtcError {
165 fn source(&self) -> Option<&(dyn Error + 'static)> {
166 match self {
167 EcssTmtcError::Store(e) => Some(e),
168 EcssTmtcError::Pus(e) => Some(e),
169 EcssTmtcError::Send(e) => Some(e),
170 _ => None,
171 }
172 }
173}
174pub trait EcssChannel: Send {
175 fn id(&self) -> ChannelId;
177 fn name(&self) -> &'static str {
178 "unset"
179 }
180}
181
182pub trait EcssTmSenderCore: EcssChannel {
186 fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError>;
187}
188
189pub trait EcssTcSenderCore: EcssChannel {
194 fn send_tc(&self, tc: PusTcCreator, token: Option<TcStateToken>) -> Result<(), EcssTmtcError>;
195}
196
197#[non_exhaustive]
201#[derive(Debug, Clone, PartialEq, Eq)]
202pub enum TcInMemory {
203 StoreAddr(StoreAddr),
204 #[cfg(feature = "alloc")]
205 Vec(alloc::vec::Vec<u8>),
206}
207
208impl From<StoreAddr> for TcInMemory {
209 fn from(value: StoreAddr) -> Self {
210 Self::StoreAddr(value)
211 }
212}
213
214#[cfg(feature = "alloc")]
215impl From<alloc::vec::Vec<u8>> for TcInMemory {
216 fn from(value: alloc::vec::Vec<u8>) -> Self {
217 Self::Vec(value)
218 }
219}
220
221#[derive(Debug, Clone, PartialEq, Eq)]
223pub struct EcssTcAndToken {
224 pub tc_in_memory: TcInMemory,
225 pub token: Option<TcStateToken>,
226}
227
228impl EcssTcAndToken {
229 pub fn new(tc_in_memory: impl Into<TcInMemory>, token: impl Into<TcStateToken>) -> Self {
230 Self {
231 tc_in_memory: tc_in_memory.into(),
232 token: Some(token.into()),
233 }
234 }
235}
236
237pub struct AcceptedEcssTcAndToken {
239 pub tc_in_memory: TcInMemory,
240 pub token: VerificationToken<TcStateAccepted>,
241}
242
243impl From<AcceptedEcssTcAndToken> for EcssTcAndToken {
244 fn from(value: AcceptedEcssTcAndToken) -> Self {
245 EcssTcAndToken {
246 tc_in_memory: value.tc_in_memory,
247 token: Some(value.token.into()),
248 }
249 }
250}
251
252impl TryFrom<EcssTcAndToken> for AcceptedEcssTcAndToken {
253 type Error = ();
254
255 fn try_from(value: EcssTcAndToken) -> Result<Self, Self::Error> {
256 if let Some(TcStateToken::Accepted(token)) = value.token {
257 return Ok(AcceptedEcssTcAndToken {
258 tc_in_memory: value.tc_in_memory,
259 token,
260 });
261 }
262 Err(())
263 }
264}
265
266#[derive(Debug, Clone)]
267pub enum TryRecvTmtcError {
268 Error(EcssTmtcError),
269 Empty,
270}
271
272impl From<EcssTmtcError> for TryRecvTmtcError {
273 fn from(value: EcssTmtcError) -> Self {
274 Self::Error(value)
275 }
276}
277
278impl From<PusError> for TryRecvTmtcError {
279 fn from(value: PusError) -> Self {
280 Self::Error(value.into())
281 }
282}
283
284impl From<StoreError> for TryRecvTmtcError {
285 fn from(value: StoreError) -> Self {
286 Self::Error(value.into())
287 }
288}
289
290pub trait EcssTcReceiverCore: EcssChannel {
292 fn recv_tc(&self) -> Result<EcssTcAndToken, TryRecvTmtcError>;
293}
294
295pub trait ReceivesEcssPusTc {
301 type Error;
302 fn pass_pus_tc(&mut self, header: &SpHeader, pus_tc: &PusTcReader) -> Result<(), Self::Error>;
303}
304
305#[cfg(feature = "alloc")]
306mod alloc_mod {
307 use super::*;
308
309 #[cfg(feature = "alloc")]
320 #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
321 pub trait EcssTmSender: EcssTmSenderCore + Downcast + DynClone {
322 fn upcast(&self) -> &dyn EcssTmSenderCore;
325 fn upcast_mut(&mut self) -> &mut dyn EcssTmSenderCore;
328 }
329
330 impl<T> EcssTmSender for T
332 where
333 T: EcssTmSenderCore + Clone + 'static,
334 {
335 fn upcast(&self) -> &dyn EcssTmSenderCore {
338 self
339 }
340 fn upcast_mut(&mut self) -> &mut dyn EcssTmSenderCore {
343 self
344 }
345 }
346
347 dyn_clone::clone_trait_object!(EcssTmSender);
348 impl_downcast!(EcssTmSender);
349
350 #[cfg(feature = "alloc")]
361 #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
362 pub trait EcssTcSender: EcssTcSenderCore + Downcast + DynClone {}
363
364 impl<T> EcssTcSender for T where T: EcssTcSenderCore + Clone + 'static {}
366
367 dyn_clone::clone_trait_object!(EcssTcSender);
368 impl_downcast!(EcssTcSender);
369
370 #[cfg(feature = "alloc")]
381 #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
382 pub trait EcssTcReceiver: EcssTcReceiverCore + Downcast {}
383
384 impl<T> EcssTcReceiver for T where T: EcssTcReceiverCore + 'static {}
386
387 impl_downcast!(EcssTcReceiver);
388}
389
390#[cfg(feature = "std")]
391#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
392pub mod std_mod {
393 use crate::pool::{PoolProvider, PoolProviderWithGuards, SharedStaticMemoryPool, StoreAddr};
394 use crate::pus::verification::{
395 StdVerifReporterWithSender, TcStateAccepted, VerificationToken,
396 };
397 use crate::pus::{
398 EcssChannel, EcssTcAndToken, EcssTcReceiver, EcssTcReceiverCore, EcssTmSender,
399 EcssTmSenderCore, EcssTmtcError, GenericRecvError, GenericSendError, PusTmWrapper,
400 TryRecvTmtcError,
401 };
402 use crate::tmtc::tm_helper::SharedTmPool;
403 use crate::ChannelId;
404 use alloc::boxed::Box;
405 use alloc::vec::Vec;
406 use crossbeam_channel as cb;
407 use spacepackets::ecss::tc::PusTcReader;
408 use spacepackets::ecss::tm::PusTmCreator;
409 use spacepackets::ecss::PusError;
410 use spacepackets::time::cds::TimeProvider;
411 use spacepackets::time::StdTimestampError;
412 use spacepackets::time::TimeWriter;
413 use std::cell::RefCell;
414 use std::string::String;
415 use std::sync::mpsc;
416 use std::sync::mpsc::TryRecvError;
417 use thiserror::Error;
418
419 use super::verification::VerificationReporterWithSender;
420 use super::{AcceptedEcssTcAndToken, TcInMemory};
421
422 impl From<mpsc::SendError<StoreAddr>> for EcssTmtcError {
423 fn from(_: mpsc::SendError<StoreAddr>) -> Self {
424 Self::Send(GenericSendError::RxDisconnected)
425 }
426 }
427
428 impl From<cb::SendError<StoreAddr>> for EcssTmtcError {
429 fn from(_: cb::SendError<StoreAddr>) -> Self {
430 Self::Send(GenericSendError::RxDisconnected)
431 }
432 }
433
434 impl From<cb::TrySendError<StoreAddr>> for EcssTmtcError {
435 fn from(value: cb::TrySendError<StoreAddr>) -> Self {
436 match value {
437 cb::TrySendError::Full(_) => Self::Send(GenericSendError::QueueFull(None)),
438 cb::TrySendError::Disconnected(_) => Self::Send(GenericSendError::RxDisconnected),
439 }
440 }
441 }
442
443 #[derive(Clone)]
444 pub struct MpscTmInSharedPoolSender {
445 id: ChannelId,
446 name: &'static str,
447 shared_tm_store: SharedTmPool,
448 sender: mpsc::Sender<StoreAddr>,
449 }
450
451 impl EcssChannel for MpscTmInSharedPoolSender {
452 fn id(&self) -> ChannelId {
453 self.id
454 }
455
456 fn name(&self) -> &'static str {
457 self.name
458 }
459 }
460
461 impl MpscTmInSharedPoolSender {
462 pub fn send_direct_tm(&self, tm: PusTmCreator) -> Result<(), EcssTmtcError> {
463 let addr = self.shared_tm_store.add_pus_tm(&tm)?;
464 self.sender
465 .send(addr)
466 .map_err(|_| EcssTmtcError::Send(GenericSendError::RxDisconnected))
467 }
468 }
469
470 impl EcssTmSenderCore for MpscTmInSharedPoolSender {
471 fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
472 match tm {
473 PusTmWrapper::InStore(addr) => {
474 self.sender.send(addr)?;
475 Ok(())
476 }
477 PusTmWrapper::Direct(tm) => self.send_direct_tm(tm),
478 }
479 }
480 }
481
482 impl MpscTmInSharedPoolSender {
483 pub fn new(
484 id: ChannelId,
485 name: &'static str,
486 shared_tm_store: SharedTmPool,
487 sender: mpsc::Sender<StoreAddr>,
488 ) -> Self {
489 Self {
490 id,
491 name,
492 shared_tm_store,
493 sender,
494 }
495 }
496 }
497
498 pub struct MpscTcReceiver {
499 id: ChannelId,
500 name: &'static str,
501 receiver: mpsc::Receiver<EcssTcAndToken>,
502 }
503
504 impl EcssChannel for MpscTcReceiver {
505 fn id(&self) -> ChannelId {
506 self.id
507 }
508
509 fn name(&self) -> &'static str {
510 self.name
511 }
512 }
513
514 impl EcssTcReceiverCore for MpscTcReceiver {
515 fn recv_tc(&self) -> Result<EcssTcAndToken, TryRecvTmtcError> {
516 self.receiver.try_recv().map_err(|e| match e {
517 TryRecvError::Empty => TryRecvTmtcError::Empty,
518 TryRecvError::Disconnected => {
519 TryRecvTmtcError::Error(EcssTmtcError::from(GenericRecvError::TxDisconnected))
520 }
521 })
522 }
523 }
524
525 impl MpscTcReceiver {
526 pub fn new(
527 id: ChannelId,
528 name: &'static str,
529 receiver: mpsc::Receiver<EcssTcAndToken>,
530 ) -> Self {
531 Self { id, name, receiver }
532 }
533 }
534
535 #[derive(Clone)]
540 pub struct MpscTmAsVecSender {
541 id: ChannelId,
542 name: &'static str,
543 sender: mpsc::Sender<Vec<u8>>,
544 }
545
546 impl From<mpsc::SendError<Vec<u8>>> for EcssTmtcError {
547 fn from(_: mpsc::SendError<Vec<u8>>) -> Self {
548 Self::Send(GenericSendError::RxDisconnected)
549 }
550 }
551
552 impl MpscTmAsVecSender {
553 pub fn new(id: u32, name: &'static str, sender: mpsc::Sender<Vec<u8>>) -> Self {
554 Self { id, sender, name }
555 }
556 }
557
558 impl EcssChannel for MpscTmAsVecSender {
559 fn id(&self) -> ChannelId {
560 self.id
561 }
562 fn name(&self) -> &'static str {
563 self.name
564 }
565 }
566
567 impl EcssTmSenderCore for MpscTmAsVecSender {
568 fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
569 match tm {
570 PusTmWrapper::InStore(addr) => Err(EcssTmtcError::CantSendAddr(addr)),
571 PusTmWrapper::Direct(tm) => {
572 let mut vec = Vec::new();
573 tm.append_to_vec(&mut vec).map_err(EcssTmtcError::Pus)?;
574 self.sender.send(vec)?;
575 Ok(())
576 }
577 }
578 }
579 }
580
581 #[derive(Clone)]
582 pub struct CrossbeamTmInStoreSender {
583 id: ChannelId,
584 name: &'static str,
585 shared_tm_store: SharedTmPool,
586 sender: crossbeam_channel::Sender<StoreAddr>,
587 }
588
589 impl CrossbeamTmInStoreSender {
590 pub fn new(
591 id: ChannelId,
592 name: &'static str,
593 shared_tm_store: SharedTmPool,
594 sender: crossbeam_channel::Sender<StoreAddr>,
595 ) -> Self {
596 Self {
597 id,
598 name,
599 shared_tm_store,
600 sender,
601 }
602 }
603 }
604
605 impl EcssChannel for CrossbeamTmInStoreSender {
606 fn id(&self) -> ChannelId {
607 self.id
608 }
609
610 fn name(&self) -> &'static str {
611 self.name
612 }
613 }
614
615 impl EcssTmSenderCore for CrossbeamTmInStoreSender {
616 fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
617 match tm {
618 PusTmWrapper::InStore(addr) => self.sender.try_send(addr)?,
619 PusTmWrapper::Direct(tm) => {
620 let addr = self.shared_tm_store.add_pus_tm(&tm)?;
621 self.sender.try_send(addr)?;
622 }
623 }
624 Ok(())
625 }
626 }
627
628 pub struct CrossbeamTcReceiver {
629 id: ChannelId,
630 name: &'static str,
631 receiver: cb::Receiver<EcssTcAndToken>,
632 }
633
634 impl CrossbeamTcReceiver {
635 pub fn new(
636 id: ChannelId,
637 name: &'static str,
638 receiver: cb::Receiver<EcssTcAndToken>,
639 ) -> Self {
640 Self { id, name, receiver }
641 }
642 }
643
644 impl EcssChannel for CrossbeamTcReceiver {
645 fn id(&self) -> ChannelId {
646 self.id
647 }
648
649 fn name(&self) -> &'static str {
650 self.name
651 }
652 }
653
654 impl EcssTcReceiverCore for CrossbeamTcReceiver {
655 fn recv_tc(&self) -> Result<EcssTcAndToken, TryRecvTmtcError> {
656 self.receiver.try_recv().map_err(|e| match e {
657 cb::TryRecvError::Empty => TryRecvTmtcError::Empty,
658 cb::TryRecvError::Disconnected => {
659 TryRecvTmtcError::Error(EcssTmtcError::from(GenericRecvError::TxDisconnected))
660 }
661 })
662 }
663 }
664
665 #[derive(Debug, Clone, Error)]
666 pub enum PusPacketHandlingError {
667 #[error("generic PUS error: {0}")]
668 Pus(#[from] PusError),
669 #[error("wrong service number {0} for packet handler")]
670 WrongService(u8),
671 #[error("invalid subservice {0}")]
672 InvalidSubservice(u8),
673 #[error("not enough application data available: {0}")]
674 NotEnoughAppData(String),
675 #[error("PUS packet too large, does not fit in buffer: {0}")]
676 PusPacketTooLarge(usize),
677 #[error("invalid application data")]
678 InvalidAppData(String),
679 #[error("invalid format of TC in memory: {0:?}")]
680 InvalidTcInMemoryFormat(TcInMemory),
681 #[error("generic ECSS tmtc error: {0}")]
682 EcssTmtc(#[from] EcssTmtcError),
683 #[error("invalid verification token")]
684 InvalidVerificationToken,
685 #[error("other error {0}")]
686 Other(String),
687 }
688
689 #[derive(Debug, Clone, Error)]
690 pub enum PartialPusHandlingError {
691 #[error("generic timestamp generation error")]
692 Time(#[from] StdTimestampError),
693 #[error("error sending telemetry: {0}")]
694 TmSend(#[from] EcssTmtcError),
695 #[error("error sending verification message")]
696 Verification,
697 #[error("invalid verification token")]
698 NoVerificationToken,
699 }
700
701 #[derive(Debug, Clone)]
703 pub enum PusPacketHandlerResult {
704 RequestHandled,
705 RequestHandledPartialSuccess(PartialPusHandlingError),
706 SubserviceNotImplemented(u8, VerificationToken<TcStateAccepted>),
707 CustomSubservice(u8, VerificationToken<TcStateAccepted>),
708 Empty,
709 }
710
711 impl From<PartialPusHandlingError> for PusPacketHandlerResult {
712 fn from(value: PartialPusHandlingError) -> Self {
713 Self::RequestHandledPartialSuccess(value)
714 }
715 }
716
717 pub trait EcssTcInMemConverter {
718 fn cache_ecss_tc_in_memory(
719 &mut self,
720 possible_packet: &TcInMemory,
721 ) -> Result<(), PusPacketHandlingError>;
722
723 fn tc_slice_raw(&self) -> &[u8];
724
725 fn convert_ecss_tc_in_memory_to_reader(
726 &mut self,
727 possible_packet: &TcInMemory,
728 ) -> Result<PusTcReader<'_>, PusPacketHandlingError> {
729 self.cache_ecss_tc_in_memory(possible_packet)?;
730 Ok(PusTcReader::new(self.tc_slice_raw())?.0)
731 }
732 }
733
734 #[derive(Default, Clone)]
738 pub struct EcssTcInVecConverter {
739 pub pus_tc_raw: Option<Vec<u8>>,
740 }
741
742 impl EcssTcInMemConverter for EcssTcInVecConverter {
743 fn cache_ecss_tc_in_memory(
744 &mut self,
745 tc_in_memory: &TcInMemory,
746 ) -> Result<(), PusPacketHandlingError> {
747 self.pus_tc_raw = None;
748 match tc_in_memory {
749 super::TcInMemory::StoreAddr(_) => {
750 return Err(PusPacketHandlingError::InvalidTcInMemoryFormat(
751 tc_in_memory.clone(),
752 ));
753 }
754 super::TcInMemory::Vec(vec) => {
755 self.pus_tc_raw = Some(vec.clone());
756 }
757 };
758 Ok(())
759 }
760
761 fn tc_slice_raw(&self) -> &[u8] {
762 if self.pus_tc_raw.is_none() {
763 return &[];
764 }
765 self.pus_tc_raw.as_ref().unwrap()
766 }
767 }
768
769 pub struct EcssTcInSharedStoreConverter {
774 shared_tc_store: SharedStaticMemoryPool,
775 pus_buf: Vec<u8>,
776 }
777
778 impl EcssTcInSharedStoreConverter {
779 pub fn new(shared_tc_store: SharedStaticMemoryPool, max_expected_tc_size: usize) -> Self {
780 Self {
781 shared_tc_store,
782 pus_buf: alloc::vec![0; max_expected_tc_size],
783 }
784 }
785
786 pub fn copy_tc_to_buf(&mut self, addr: StoreAddr) -> Result<(), PusPacketHandlingError> {
787 let mut tc_pool = self
789 .shared_tc_store
790 .write()
791 .map_err(|_| PusPacketHandlingError::EcssTmtc(EcssTmtcError::StoreLock))?;
792 let tc_size = tc_pool
793 .len_of_data(&addr)
794 .map_err(|e| PusPacketHandlingError::EcssTmtc(EcssTmtcError::Store(e)))?;
795 if tc_size > self.pus_buf.len() {
796 return Err(PusPacketHandlingError::PusPacketTooLarge(tc_size));
797 }
798 let tc_guard = tc_pool.read_with_guard(addr);
799 tc_guard.read(&mut self.pus_buf[0..tc_size]).unwrap();
801 Ok(())
802 }
803 }
804
805 impl EcssTcInMemConverter for EcssTcInSharedStoreConverter {
806 fn cache_ecss_tc_in_memory(
807 &mut self,
808 tc_in_memory: &TcInMemory,
809 ) -> Result<(), PusPacketHandlingError> {
810 match tc_in_memory {
811 super::TcInMemory::StoreAddr(addr) => {
812 self.copy_tc_to_buf(*addr)?;
813 }
814 super::TcInMemory::Vec(_) => {
815 return Err(PusPacketHandlingError::InvalidTcInMemoryFormat(
816 tc_in_memory.clone(),
817 ));
818 }
819 };
820 Ok(())
821 }
822
823 fn tc_slice_raw(&self) -> &[u8] {
824 self.pus_buf.as_ref()
825 }
826 }
827
828 pub struct PusServiceBase {
829 pub tc_receiver: Box<dyn EcssTcReceiver>,
830 pub tm_sender: Box<dyn EcssTmSender>,
831 pub tm_apid: u16,
832 pub verification_handler: RefCell<StdVerifReporterWithSender>,
835 }
836
837 impl PusServiceBase {
838 #[cfg(feature = "std")]
839 pub fn get_current_timestamp(
840 partial_error: &mut Option<PartialPusHandlingError>,
841 ) -> [u8; 7] {
842 let mut time_stamp: [u8; 7] = [0; 7];
843 let time_provider =
844 TimeProvider::from_now_with_u16_days().map_err(PartialPusHandlingError::Time);
845 if let Ok(time_provider) = time_provider {
846 time_provider.write_to_bytes(&mut time_stamp).unwrap();
848 } else {
849 *partial_error = Some(time_provider.unwrap_err());
850 }
851 time_stamp
852 }
853
854 #[cfg(feature = "std")]
855 pub fn get_current_timestamp_ignore_error() -> [u8; 7] {
856 let mut dummy = None;
857 Self::get_current_timestamp(&mut dummy)
858 }
859 }
860
861 pub struct PusServiceHelper<TcInMemConverter: EcssTcInMemConverter> {
871 pub common: PusServiceBase,
872 pub tc_in_mem_converter: TcInMemConverter,
873 }
874
875 impl<TcInMemConverter: EcssTcInMemConverter> PusServiceHelper<TcInMemConverter> {
876 pub fn new(
877 tc_receiver: Box<dyn EcssTcReceiver>,
878 tm_sender: Box<dyn EcssTmSender>,
879 tm_apid: u16,
880 verification_handler: VerificationReporterWithSender,
881 tc_in_mem_converter: TcInMemConverter,
882 ) -> Self {
883 Self {
884 common: PusServiceBase {
885 tc_receiver,
886 tm_sender,
887 tm_apid,
888 verification_handler: RefCell::new(verification_handler),
889 },
890 tc_in_mem_converter,
891 }
892 }
893
894 pub fn retrieve_and_accept_next_packet(
900 &mut self,
901 ) -> Result<Option<AcceptedEcssTcAndToken>, PusPacketHandlingError> {
902 match self.common.tc_receiver.recv_tc() {
903 Ok(EcssTcAndToken {
904 tc_in_memory,
905 token,
906 }) => {
907 if token.is_none() {
908 return Err(PusPacketHandlingError::InvalidVerificationToken);
909 }
910 let token = token.unwrap();
911 let accepted_token = VerificationToken::<TcStateAccepted>::try_from(token)
912 .map_err(|_| PusPacketHandlingError::InvalidVerificationToken)?;
913 Ok(Some(AcceptedEcssTcAndToken {
914 tc_in_memory,
915 token: accepted_token,
916 }))
917 }
918 Err(e) => match e {
919 TryRecvTmtcError::Error(e) => Err(PusPacketHandlingError::EcssTmtc(e)),
920 TryRecvTmtcError::Empty => Ok(None),
921 },
922 }
923 }
924 }
925}
926
927pub(crate) fn source_buffer_large_enough(cap: usize, len: usize) -> Result<(), EcssTmtcError> {
928 if len > cap {
929 return Err(
930 PusError::ByteConversion(ByteConversionError::ToSliceTooSmall {
931 found: cap,
932 expected: len,
933 })
934 .into(),
935 );
936 }
937 Ok(())
938}
939
940#[cfg(test)]
941pub mod tests {
942 use std::sync::mpsc::TryRecvError;
943 use std::sync::{mpsc, RwLock};
944
945 use alloc::boxed::Box;
946 use alloc::vec;
947 use spacepackets::ecss::tc::PusTcCreator;
948 use spacepackets::ecss::tm::{GenericPusTmSecondaryHeader, PusTmCreator, PusTmReader};
949 use spacepackets::ecss::{PusPacket, WritablePusPacket};
950 use spacepackets::CcsdsPacket;
951
952 use crate::pool::{
953 PoolProvider, SharedStaticMemoryPool, StaticMemoryPool, StaticPoolConfig, StoreAddr,
954 };
955 use crate::pus::verification::RequestId;
956 use crate::tmtc::tm_helper::SharedTmPool;
957
958 use super::verification::{
959 TcStateAccepted, VerificationReporterCfg, VerificationReporterWithSender, VerificationToken,
960 };
961 use super::{
962 EcssTcAndToken, EcssTcInSharedStoreConverter, EcssTcInVecConverter, MpscTcReceiver,
963 MpscTmAsVecSender, MpscTmInSharedPoolSender, PusPacketHandlerResult,
964 PusPacketHandlingError, PusServiceHelper, TcInMemory,
965 };
966
967 pub const TEST_APID: u16 = 0x101;
968
969 #[derive(Debug, Eq, PartialEq, Clone)]
970 pub(crate) struct CommonTmInfo {
971 pub subservice: u8,
972 pub apid: u16,
973 pub msg_counter: u16,
974 pub dest_id: u16,
975 pub time_stamp: [u8; 7],
976 }
977
978 pub trait PusTestHarness {
979 fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>;
980 fn read_next_tm(&mut self) -> PusTmReader<'_>;
981 fn check_no_tm_available(&self) -> bool;
982 fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId);
983 }
984
985 pub trait SimplePusPacketHandler {
986 fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError>;
987 }
988
989 impl CommonTmInfo {
990 pub fn new_from_tm(tm: &PusTmCreator) -> Self {
991 let mut time_stamp = [0; 7];
992 time_stamp.clone_from_slice(&tm.timestamp()[0..7]);
993 Self {
994 subservice: PusPacket::subservice(tm),
995 apid: tm.apid(),
996 msg_counter: tm.msg_counter(),
997 dest_id: tm.dest_id(),
998 time_stamp,
999 }
1000 }
1001 }
1002
1003 pub struct PusServiceHandlerWithSharedStoreCommon {
1005 pus_buf: [u8; 2048],
1006 tm_buf: [u8; 2048],
1007 tc_pool: SharedStaticMemoryPool,
1008 tm_pool: SharedTmPool,
1009 tc_sender: mpsc::Sender<EcssTcAndToken>,
1010 tm_receiver: mpsc::Receiver<StoreAddr>,
1011 verification_handler: VerificationReporterWithSender,
1012 }
1013
1014 impl PusServiceHandlerWithSharedStoreCommon {
1015 pub fn new() -> (Self, PusServiceHelper<EcssTcInSharedStoreConverter>) {
1020 let pool_cfg = StaticPoolConfig::new(vec![(16, 16), (8, 32), (4, 64)], false);
1021 let tc_pool = StaticMemoryPool::new(pool_cfg.clone());
1022 let tm_pool = StaticMemoryPool::new(pool_cfg);
1023 let shared_tc_pool = SharedStaticMemoryPool::new(RwLock::new(tc_pool));
1024 let shared_tm_pool = SharedTmPool::new(tm_pool);
1025 let (test_srv_tc_tx, test_srv_tc_rx) = mpsc::channel();
1026 let (tm_tx, tm_rx) = mpsc::channel();
1027
1028 let verif_sender = MpscTmInSharedPoolSender::new(
1029 0,
1030 "verif_sender",
1031 shared_tm_pool.clone(),
1032 tm_tx.clone(),
1033 );
1034 let verif_cfg = VerificationReporterCfg::new(TEST_APID, 1, 2, 8).unwrap();
1035 let verification_handler =
1036 VerificationReporterWithSender::new(&verif_cfg, Box::new(verif_sender));
1037 let test_srv_tm_sender =
1038 MpscTmInSharedPoolSender::new(0, "TEST_SENDER", shared_tm_pool.clone(), tm_tx);
1039 let test_srv_tc_receiver = MpscTcReceiver::new(0, "TEST_RECEIVER", test_srv_tc_rx);
1040 let in_store_converter =
1041 EcssTcInSharedStoreConverter::new(shared_tc_pool.clone(), 2048);
1042 (
1043 Self {
1044 pus_buf: [0; 2048],
1045 tm_buf: [0; 2048],
1046 tc_pool: shared_tc_pool,
1047 tm_pool: shared_tm_pool,
1048 tc_sender: test_srv_tc_tx,
1049 tm_receiver: tm_rx,
1050 verification_handler: verification_handler.clone(),
1051 },
1052 PusServiceHelper::new(
1053 Box::new(test_srv_tc_receiver),
1054 Box::new(test_srv_tm_sender),
1055 TEST_APID,
1056 verification_handler,
1057 in_store_converter,
1058 ),
1059 )
1060 }
1061 pub fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
1062 let token = self.verification_handler.add_tc(tc);
1063 let token = self
1064 .verification_handler
1065 .acceptance_success(token, Some(&[0; 7]))
1066 .unwrap();
1067 let tc_size = tc.write_to_bytes(&mut self.pus_buf).unwrap();
1068 let mut tc_pool = self.tc_pool.write().unwrap();
1069 let addr = tc_pool.add(&self.pus_buf[..tc_size]).unwrap();
1070 drop(tc_pool);
1071 self.tc_sender
1073 .send(EcssTcAndToken::new(addr, token))
1074 .expect("sending tc failed");
1075 token
1076 }
1077
1078 pub fn read_next_tm(&mut self) -> PusTmReader<'_> {
1079 let next_msg = self.tm_receiver.try_recv();
1080 assert!(next_msg.is_ok());
1081 let tm_addr = next_msg.unwrap();
1082 let tm_pool = self.tm_pool.0.read().unwrap();
1083 let tm_raw = tm_pool.read_as_vec(&tm_addr).unwrap();
1084 self.tm_buf[0..tm_raw.len()].copy_from_slice(&tm_raw);
1085 PusTmReader::new(&self.tm_buf, 7).unwrap().0
1086 }
1087
1088 pub fn check_no_tm_available(&self) -> bool {
1089 let next_msg = self.tm_receiver.try_recv();
1090 if let TryRecvError::Empty = next_msg.unwrap_err() {
1091 return true;
1092 }
1093 false
1094 }
1095
1096 pub fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId) {
1097 let next_msg = self.tm_receiver.try_recv();
1098 assert!(next_msg.is_ok());
1099 let tm_addr = next_msg.unwrap();
1100 let tm_pool = self.tm_pool.0.read().unwrap();
1101 let tm_raw = tm_pool.read_as_vec(&tm_addr).unwrap();
1102 let tm = PusTmReader::new(&tm_raw, 7).unwrap().0;
1103 assert_eq!(PusPacket::service(&tm), 1);
1104 assert_eq!(PusPacket::subservice(&tm), subservice);
1105 assert_eq!(tm.apid(), TEST_APID);
1106 let req_id =
1107 RequestId::from_bytes(tm.user_data()).expect("generating request ID failed");
1108 assert_eq!(req_id, expected_request_id);
1109 }
1110 }
1111
1112 pub struct PusServiceHandlerWithVecCommon {
1113 current_tm: Option<alloc::vec::Vec<u8>>,
1114 tc_sender: mpsc::Sender<EcssTcAndToken>,
1115 tm_receiver: mpsc::Receiver<alloc::vec::Vec<u8>>,
1116 verification_handler: VerificationReporterWithSender,
1117 }
1118
1119 impl PusServiceHandlerWithVecCommon {
1120 pub fn new() -> (Self, PusServiceHelper<EcssTcInVecConverter>) {
1121 let (test_srv_tc_tx, test_srv_tc_rx) = mpsc::channel();
1122 let (tm_tx, tm_rx) = mpsc::channel();
1123
1124 let verif_sender = MpscTmAsVecSender::new(0, "verififcatio-sender", tm_tx.clone());
1125 let verif_cfg = VerificationReporterCfg::new(TEST_APID, 1, 2, 8).unwrap();
1126 let verification_handler =
1127 VerificationReporterWithSender::new(&verif_cfg, Box::new(verif_sender));
1128 let test_srv_tm_sender = MpscTmAsVecSender::new(0, "test-sender", tm_tx);
1129 let test_srv_tc_receiver = MpscTcReceiver::new(0, "test-receiver", test_srv_tc_rx);
1130 let in_store_converter = EcssTcInVecConverter::default();
1131 (
1132 Self {
1133 current_tm: None,
1134 tc_sender: test_srv_tc_tx,
1135 tm_receiver: tm_rx,
1136 verification_handler: verification_handler.clone(),
1137 },
1138 PusServiceHelper::new(
1139 Box::new(test_srv_tc_receiver),
1140 Box::new(test_srv_tm_sender),
1141 TEST_APID,
1142 verification_handler,
1143 in_store_converter,
1144 ),
1145 )
1146 }
1147
1148 pub fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
1149 let token = self.verification_handler.add_tc(tc);
1150 let token = self
1151 .verification_handler
1152 .acceptance_success(token, Some(&[0; 7]))
1153 .unwrap();
1154 self.tc_sender
1156 .send(EcssTcAndToken::new(
1157 TcInMemory::Vec(tc.to_vec().expect("pus tc conversion to vec failed")),
1158 token,
1159 ))
1160 .expect("sending tc failed");
1161 token
1162 }
1163
1164 pub fn read_next_tm(&mut self) -> PusTmReader<'_> {
1165 let next_msg = self.tm_receiver.try_recv();
1166 assert!(next_msg.is_ok());
1167 self.current_tm = Some(next_msg.unwrap());
1168 PusTmReader::new(self.current_tm.as_ref().unwrap(), 7)
1169 .unwrap()
1170 .0
1171 }
1172
1173 pub fn check_no_tm_available(&self) -> bool {
1174 let next_msg = self.tm_receiver.try_recv();
1175 if let TryRecvError::Empty = next_msg.unwrap_err() {
1176 return true;
1177 }
1178 false
1179 }
1180
1181 pub fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId) {
1182 let next_msg = self.tm_receiver.try_recv();
1183 assert!(next_msg.is_ok());
1184 let next_msg = next_msg.unwrap();
1185 let tm = PusTmReader::new(next_msg.as_slice(), 7).unwrap().0;
1186 assert_eq!(PusPacket::service(&tm), 1);
1187 assert_eq!(PusPacket::subservice(&tm), subservice);
1188 assert_eq!(tm.apid(), TEST_APID);
1189 let req_id =
1190 RequestId::from_bytes(tm.user_data()).expect("generating request ID failed");
1191 assert_eq!(req_id, expected_request_id);
1192 }
1193 }
1194}