rename subfolders, add more READMEs

This commit is contained in:
2022-11-20 19:04:08 +01:00
parent db6fb0ab5c
commit 2e249ec086
43 changed files with 12 additions and 3 deletions

477
satrs-core/src/pus/event.rs Normal file
View File

@ -0,0 +1,477 @@
use crate::pus::{source_buffer_large_enough, EcssTmError, EcssTmSender};
use spacepackets::ecss::EcssEnumeration;
use spacepackets::tm::PusTm;
use spacepackets::tm::PusTmSecondaryHeader;
use spacepackets::{SpHeader, MAX_APID};
#[cfg(feature = "alloc")]
pub use allocvec::EventReporter;
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum Subservices {
TmInfoReport = 1,
TmLowSeverityReport = 2,
TmMediumSeverityReport = 3,
TmHighSeverityReport = 4,
TcEnableEventGeneration = 5,
TcDisableEventGeneration = 6,
TcReportDisabledList = 7,
TmDisabledEventsReport = 8,
}
impl From<Subservices> for u8 {
fn from(enumeration: Subservices) -> Self {
enumeration as u8
}
}
impl TryFrom<u8> for Subservices {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
x if x == Subservices::TmInfoReport as u8 => Ok(Subservices::TmInfoReport),
x if x == Subservices::TmLowSeverityReport as u8 => {
Ok(Subservices::TmLowSeverityReport)
}
x if x == Subservices::TmMediumSeverityReport as u8 => {
Ok(Subservices::TmMediumSeverityReport)
}
x if x == Subservices::TmHighSeverityReport as u8 => {
Ok(Subservices::TmHighSeverityReport)
}
x if x == Subservices::TcEnableEventGeneration as u8 => {
Ok(Subservices::TcEnableEventGeneration)
}
x if x == Subservices::TcDisableEventGeneration as u8 => {
Ok(Subservices::TcDisableEventGeneration)
}
x if x == Subservices::TcReportDisabledList as u8 => {
Ok(Subservices::TcReportDisabledList)
}
x if x == Subservices::TmDisabledEventsReport as u8 => {
Ok(Subservices::TmDisabledEventsReport)
}
_ => Err(()),
}
}
}
pub struct EventReporterBase {
msg_count: u16,
apid: u16,
pub dest_id: u16,
}
impl EventReporterBase {
pub fn new(apid: u16) -> Option<Self> {
if apid > MAX_APID {
return None;
}
Some(Self {
msg_count: 0,
dest_id: 0,
apid,
})
}
pub fn event_info<E>(
&mut self,
buf: &mut [u8],
sender: &mut (impl EcssTmSender<Error = E> + ?Sized),
time_stamp: &[u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmError<E>> {
self.generate_and_send_generic_tm(
buf,
Subservices::TmInfoReport,
sender,
time_stamp,
event_id,
aux_data,
)
}
pub fn event_low_severity<E>(
&mut self,
buf: &mut [u8],
sender: &mut (impl EcssTmSender<Error = E> + ?Sized),
time_stamp: &[u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmError<E>> {
self.generate_and_send_generic_tm(
buf,
Subservices::TmLowSeverityReport,
sender,
time_stamp,
event_id,
aux_data,
)
}
pub fn event_medium_severity<E>(
&mut self,
buf: &mut [u8],
sender: &mut (impl EcssTmSender<Error = E> + ?Sized),
time_stamp: &[u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmError<E>> {
self.generate_and_send_generic_tm(
buf,
Subservices::TmMediumSeverityReport,
sender,
time_stamp,
event_id,
aux_data,
)
}
pub fn event_high_severity<E>(
&mut self,
buf: &mut [u8],
sender: &mut (impl EcssTmSender<Error = E> + ?Sized),
time_stamp: &[u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmError<E>> {
self.generate_and_send_generic_tm(
buf,
Subservices::TmHighSeverityReport,
sender,
time_stamp,
event_id,
aux_data,
)
}
fn generate_and_send_generic_tm<E>(
&mut self,
buf: &mut [u8],
subservice: Subservices,
sender: &mut (impl EcssTmSender<Error = E> + ?Sized),
time_stamp: &[u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmError<E>> {
let tm = self.generate_generic_event_tm(buf, subservice, time_stamp, event_id, aux_data)?;
sender.send_tm(tm)?;
self.msg_count += 1;
Ok(())
}
fn generate_generic_event_tm<'a, E>(
&'a self,
buf: &'a mut [u8],
subservice: Subservices,
time_stamp: &'a [u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<PusTm, EcssTmError<E>> {
let mut src_data_len = event_id.byte_width();
if let Some(aux_data) = aux_data {
src_data_len += aux_data.len();
}
source_buffer_large_enough(buf.len(), src_data_len)?;
let mut sp_header = SpHeader::tm(self.apid, 0, 0).unwrap();
let sec_header = PusTmSecondaryHeader::new(
5,
subservice.into(),
self.msg_count,
self.dest_id,
time_stamp,
);
let mut current_idx = 0;
event_id.write_to_be_bytes(&mut buf[0..event_id.byte_width()])?;
current_idx += event_id.byte_width();
if let Some(aux_data) = aux_data {
buf[current_idx..current_idx + aux_data.len()].copy_from_slice(aux_data);
current_idx += aux_data.len();
}
Ok(PusTm::new(
&mut sp_header,
sec_header,
Some(&buf[0..current_idx]),
true,
))
}
}
#[cfg(feature = "alloc")]
mod allocvec {
use super::*;
use alloc::vec;
use alloc::vec::Vec;
pub struct EventReporter {
source_data_buf: Vec<u8>,
pub reporter: EventReporterBase,
}
impl EventReporter {
pub fn new(apid: u16, max_event_id_and_aux_data_size: usize) -> Option<Self> {
let reporter = EventReporterBase::new(apid)?;
Some(Self {
source_data_buf: vec![0; max_event_id_and_aux_data_size],
reporter,
})
}
pub fn event_info<E>(
&mut self,
sender: &mut (impl EcssTmSender<Error = E> + ?Sized),
time_stamp: &[u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmError<E>> {
self.reporter.event_info(
self.source_data_buf.as_mut_slice(),
sender,
time_stamp,
event_id,
aux_data,
)
}
pub fn event_low_severity<E>(
&mut self,
sender: &mut (impl EcssTmSender<Error = E> + ?Sized),
time_stamp: &[u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmError<E>> {
self.reporter.event_low_severity(
self.source_data_buf.as_mut_slice(),
sender,
time_stamp,
event_id,
aux_data,
)
}
pub fn event_medium_severity<E>(
&mut self,
sender: &mut (impl EcssTmSender<Error = E> + ?Sized),
time_stamp: &[u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmError<E>> {
self.reporter.event_medium_severity(
self.source_data_buf.as_mut_slice(),
sender,
time_stamp,
event_id,
aux_data,
)
}
pub fn event_high_severity<E>(
&mut self,
sender: &mut (impl EcssTmSender<Error = E> + ?Sized),
time_stamp: &[u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmError<E>> {
self.reporter.event_high_severity(
self.source_data_buf.as_mut_slice(),
sender,
time_stamp,
event_id,
aux_data,
)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::events::{EventU32, Severity};
use crate::pus::tests::CommonTmInfo;
use spacepackets::ByteConversionError;
use std::collections::VecDeque;
use std::vec::Vec;
const EXAMPLE_APID: u16 = 0xee;
const EXAMPLE_GROUP_ID: u16 = 2;
const EXAMPLE_EVENT_ID_0: u16 = 1;
#[allow(dead_code)]
const EXAMPLE_EVENT_ID_1: u16 = 2;
#[derive(Debug, Eq, PartialEq)]
struct TmInfo {
pub common: CommonTmInfo,
pub event: EventU32,
pub aux_data: Vec<u8>,
}
#[derive(Default)]
struct TestSender {
pub service_queue: VecDeque<TmInfo>,
}
impl EcssTmSender for TestSender {
type Error = ();
fn send_tm(&mut self, tm: PusTm) -> Result<(), EcssTmError<()>> {
assert!(tm.source_data().is_some());
let src_data = tm.source_data().unwrap();
assert!(src_data.len() >= 4);
let event = EventU32::from(u32::from_be_bytes(src_data[0..4].try_into().unwrap()));
let mut aux_data = Vec::new();
if src_data.len() > 4 {
aux_data.extend_from_slice(&src_data[4..]);
}
self.service_queue.push_back(TmInfo {
common: CommonTmInfo::new_from_tm(&tm),
event,
aux_data,
});
Ok(())
}
}
fn severity_to_subservice(severity: Severity) -> Subservices {
match severity {
Severity::INFO => Subservices::TmInfoReport,
Severity::LOW => Subservices::TmLowSeverityReport,
Severity::MEDIUM => Subservices::TmMediumSeverityReport,
Severity::HIGH => Subservices::TmHighSeverityReport,
}
}
fn report_basic_event(
reporter: &mut EventReporter,
sender: &mut TestSender,
time_stamp: &[u8],
event: EventU32,
severity: Severity,
aux_data: Option<&[u8]>,
) {
match severity {
Severity::INFO => {
reporter
.event_info(sender, time_stamp, event, aux_data)
.expect("Error reporting info event");
}
Severity::LOW => {
reporter
.event_low_severity(sender, time_stamp, event, aux_data)
.expect("Error reporting low event");
}
Severity::MEDIUM => {
reporter
.event_medium_severity(sender, time_stamp, event, aux_data)
.expect("Error reporting medium event");
}
Severity::HIGH => {
reporter
.event_high_severity(sender, time_stamp, event, aux_data)
.expect("Error reporting high event");
}
}
}
fn basic_event_test(
max_event_aux_data_buf: usize,
severity: Severity,
error_data: Option<&[u8]>,
) {
let mut sender = TestSender::default();
let reporter = EventReporter::new(EXAMPLE_APID, max_event_aux_data_buf);
assert!(reporter.is_some());
let mut reporter = reporter.unwrap();
let time_stamp_empty: [u8; 7] = [0; 7];
let mut error_copy = Vec::new();
if let Some(err_data) = error_data {
error_copy.extend_from_slice(err_data);
}
let event = EventU32::new(severity, EXAMPLE_GROUP_ID, EXAMPLE_EVENT_ID_0)
.expect("Error creating example event");
report_basic_event(
&mut reporter,
&mut sender,
&time_stamp_empty,
event,
severity,
error_data,
);
assert_eq!(sender.service_queue.len(), 1);
let tm_info = sender.service_queue.pop_front().unwrap();
assert_eq!(
tm_info.common.subservice,
severity_to_subservice(severity) as u8
);
assert_eq!(tm_info.common.dest_id, 0);
assert_eq!(tm_info.common.time_stamp, time_stamp_empty);
assert_eq!(tm_info.common.msg_counter, 0);
assert_eq!(tm_info.common.apid, EXAMPLE_APID);
assert_eq!(tm_info.event, event);
assert_eq!(tm_info.aux_data, error_copy);
}
#[test]
fn basic_info_event_generation() {
basic_event_test(4, Severity::INFO, None);
}
#[test]
fn basic_low_severity_event() {
basic_event_test(4, Severity::LOW, None);
}
#[test]
fn basic_medium_severity_event() {
basic_event_test(4, Severity::MEDIUM, None);
}
#[test]
fn basic_high_severity_event() {
basic_event_test(4, Severity::HIGH, None);
}
#[test]
fn event_with_info_string() {
let info_string = "Test Information";
basic_event_test(32, Severity::INFO, Some(info_string.as_bytes()));
}
#[test]
fn low_severity_with_raw_err_data() {
let raw_err_param: i32 = -1;
let raw_err = raw_err_param.to_be_bytes();
basic_event_test(8, Severity::LOW, Some(&raw_err))
}
fn check_buf_too_small(
reporter: &mut EventReporter,
sender: &mut TestSender,
expected_found_len: usize,
) {
let time_stamp_empty: [u8; 7] = [0; 7];
let event = EventU32::new(Severity::INFO, EXAMPLE_GROUP_ID, EXAMPLE_EVENT_ID_0)
.expect("Error creating example event");
let err = reporter.event_info(sender, &time_stamp_empty, event, None);
assert!(err.is_err());
let err = err.unwrap_err();
if let EcssTmError::ByteConversionError(ByteConversionError::ToSliceTooSmall(missmatch)) =
err
{
assert_eq!(missmatch.expected, 4);
assert_eq!(missmatch.found, expected_found_len);
} else {
panic!("Unexpected error {:?}", err);
}
}
#[test]
fn insufficient_buffer() {
let mut sender = TestSender::default();
for i in 0..3 {
let reporter = EventReporter::new(EXAMPLE_APID, i);
assert!(reporter.is_some());
let mut reporter = reporter.unwrap();
check_buf_too_small(&mut reporter, &mut sender, i);
}
}
}

View File

@ -0,0 +1,310 @@
use crate::events::{EventU32, EventU32TypedSev, GenericEvent, HasSeverity, Severity};
use alloc::boxed::Box;
use core::hash::Hash;
use hashbrown::HashSet;
#[cfg(feature = "alloc")]
pub use crate::pus::event::EventReporter;
use crate::pus::verification::{TcStateStarted, VerificationToken};
use crate::pus::{EcssTmError, EcssTmSender};
#[cfg(feature = "heapless")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "heapless")))]
pub use heapless_mod::*;
/// This trait allows the PUS event manager implementation to stay generic over various types
/// of backend containers.
///
/// These backend containers keep track on whether a particular event is enabled or disabled for
/// reporting and also expose a simple API to enable or disable the event reporting.
///
/// For example, a straight forward implementation for host systems could use a
/// [hash set](https://docs.rs/hashbrown/latest/hashbrown/struct.HashSet.html)
/// structure to track disabled events. A more primitive and embedded friendly
/// solution could track this information in a static or pre-allocated list which contains
/// the disabled events.
pub trait PusEventMgmtBackendProvider<Provider: GenericEvent> {
type Error;
fn event_enabled(&self, event: &Provider) -> bool;
fn enable_event_reporting(&mut self, event: &Provider) -> Result<bool, Self::Error>;
fn disable_event_reporting(&mut self, event: &Provider) -> Result<bool, Self::Error>;
}
/// Default backend provider which uses a hash set as the event reporting status container
/// like mentioned in the example of the [PusEventMgmtBackendProvider] documentation.
///
/// This provider is a good option for host systems or larger embedded systems where
/// the expected occasional memory allocation performed by the [HashSet] is not an issue.
pub struct DefaultPusMgmtBackendProvider<Event: GenericEvent = EventU32> {
disabled: HashSet<Event>,
}
/// Safety: All contained field are [Send] as well
unsafe impl<Event: GenericEvent + Send> Send for DefaultPusMgmtBackendProvider<Event> {}
impl<Event: GenericEvent> Default for DefaultPusMgmtBackendProvider<Event> {
fn default() -> Self {
Self {
disabled: HashSet::default(),
}
}
}
impl<Provider: GenericEvent + PartialEq + Eq + Hash + Copy + Clone>
PusEventMgmtBackendProvider<Provider> for DefaultPusMgmtBackendProvider<Provider>
{
type Error = ();
fn event_enabled(&self, event: &Provider) -> bool {
!self.disabled.contains(event)
}
fn enable_event_reporting(&mut self, event: &Provider) -> Result<bool, Self::Error> {
Ok(self.disabled.remove(event))
}
fn disable_event_reporting(&mut self, event: &Provider) -> Result<bool, Self::Error> {
Ok(self.disabled.insert(*event))
}
}
#[cfg(feature = "heapless")]
pub mod heapless_mod {
use super::*;
use crate::events::{GenericEvent, LargestEventRaw};
use std::marker::PhantomData;
#[cfg_attr(doc_cfg, doc(cfg(feature = "heapless")))]
// TODO: After a new version of heapless is released which uses hash32 version 0.3, try using
// regular Event type again.
#[derive(Default)]
pub struct HeaplessPusMgmtBackendProvider<const N: usize, Provider: GenericEvent> {
disabled: heapless::FnvIndexSet<LargestEventRaw, N>,
phantom: PhantomData<Provider>,
}
/// Safety: All contained field are [Send] as well
unsafe impl<const N: usize, Event: GenericEvent + Send> Send
for HeaplessPusMgmtBackendProvider<N, Event>
{
}
impl<const N: usize, Provider: GenericEvent> PusEventMgmtBackendProvider<Provider>
for HeaplessPusMgmtBackendProvider<N, Provider>
{
type Error = ();
fn event_enabled(&self, event: &Provider) -> bool {
self.disabled.contains(&event.raw_as_largest_type())
}
fn enable_event_reporting(&mut self, event: &Provider) -> Result<bool, Self::Error> {
self.disabled
.insert(event.raw_as_largest_type())
.map_err(|_| ())
}
fn disable_event_reporting(&mut self, event: &Provider) -> Result<bool, Self::Error> {
Ok(self.disabled.remove(&event.raw_as_largest_type()))
}
}
}
#[derive(Debug)]
pub enum EventRequest<Event: GenericEvent = EventU32> {
Enable(Event),
Disable(Event),
}
#[derive(Debug)]
pub struct EventRequestWithToken<Event: GenericEvent = EventU32> {
pub request: EventRequest<Event>,
pub token: VerificationToken<TcStateStarted>,
}
#[derive(Debug)]
pub enum EventManError<SenderE> {
EcssTmError(EcssTmError<SenderE>),
SeverityMissmatch(Severity, Severity),
}
impl<SenderE> From<EcssTmError<SenderE>> for EventManError<SenderE> {
fn from(v: EcssTmError<SenderE>) -> Self {
Self::EcssTmError(v)
}
}
pub struct PusEventDispatcher<BackendError, Provider: GenericEvent> {
reporter: EventReporter,
backend: Box<dyn PusEventMgmtBackendProvider<Provider, Error = BackendError>>,
}
/// Safety: All contained fields are send as well.
unsafe impl<E: Send, Event: GenericEvent + Send> Send for PusEventDispatcher<E, Event> {}
impl<BackendError, Provider: GenericEvent> PusEventDispatcher<BackendError, Provider> {
pub fn new(
reporter: EventReporter,
backend: Box<dyn PusEventMgmtBackendProvider<Provider, Error = BackendError>>,
) -> Self {
Self { reporter, backend }
}
}
impl<BackendError, Event: GenericEvent> PusEventDispatcher<BackendError, Event> {
pub fn enable_tm_for_event(&mut self, event: &Event) -> Result<bool, BackendError> {
self.backend.enable_event_reporting(event)
}
pub fn disable_tm_for_event(&mut self, event: &Event) -> Result<bool, BackendError> {
self.backend.disable_event_reporting(event)
}
pub fn generate_pus_event_tm_generic<E>(
&mut self,
sender: &mut (impl EcssTmSender<Error = E> + ?Sized),
time_stamp: &[u8],
event: Event,
aux_data: Option<&[u8]>,
) -> Result<bool, EventManError<E>> {
if !self.backend.event_enabled(&event) {
return Ok(false);
}
match event.severity() {
Severity::INFO => self
.reporter
.event_info(sender, time_stamp, event, aux_data)
.map(|_| true)
.map_err(|e| e.into()),
Severity::LOW => self
.reporter
.event_low_severity(sender, time_stamp, event, aux_data)
.map(|_| true)
.map_err(|e| e.into()),
Severity::MEDIUM => self
.reporter
.event_medium_severity(sender, time_stamp, event, aux_data)
.map(|_| true)
.map_err(|e| e.into()),
Severity::HIGH => self
.reporter
.event_high_severity(sender, time_stamp, event, aux_data)
.map(|_| true)
.map_err(|e| e.into()),
}
}
}
impl<BackendError> PusEventDispatcher<BackendError, EventU32> {
pub fn enable_tm_for_event_with_sev<Severity: HasSeverity>(
&mut self,
event: &EventU32TypedSev<Severity>,
) -> Result<bool, BackendError> {
self.backend.enable_event_reporting(event.as_ref())
}
pub fn disable_tm_for_event_with_sev<Severity: HasSeverity>(
&mut self,
event: &EventU32TypedSev<Severity>,
) -> Result<bool, BackendError> {
self.backend.disable_event_reporting(event.as_ref())
}
pub fn generate_pus_event_tm<E, Severity: HasSeverity>(
&mut self,
sender: &mut (impl EcssTmSender<Error = E> + ?Sized),
time_stamp: &[u8],
event: EventU32TypedSev<Severity>,
aux_data: Option<&[u8]>,
) -> Result<bool, EventManError<E>> {
self.generate_pus_event_tm_generic(sender, time_stamp, event.into(), aux_data)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::events::SeverityInfo;
use spacepackets::tm::PusTm;
use std::sync::mpsc::{channel, SendError, TryRecvError};
use std::vec::Vec;
const INFO_EVENT: EventU32TypedSev<SeverityInfo> =
EventU32TypedSev::<SeverityInfo>::const_new(1, 0);
const LOW_SEV_EVENT: EventU32 = EventU32::const_new(Severity::LOW, 1, 5);
const EMPTY_STAMP: [u8; 7] = [0; 7];
struct EventTmSender {
sender: std::sync::mpsc::Sender<Vec<u8>>,
}
impl EcssTmSender for EventTmSender {
type Error = SendError<Vec<u8>>;
fn send_tm(&mut self, tm: PusTm) -> Result<(), EcssTmError<Self::Error>> {
let mut vec = Vec::new();
tm.append_to_vec(&mut vec)?;
self.sender.send(vec).map_err(EcssTmError::SendError)?;
Ok(())
}
}
fn create_basic_man() -> PusEventDispatcher<(), EventU32> {
let reporter = EventReporter::new(0x02, 128).expect("Creating event repoter failed");
let backend = DefaultPusMgmtBackendProvider::<EventU32>::default();
PusEventDispatcher::new(reporter, Box::new(backend))
}
#[test]
fn test_basic() {
let mut event_man = create_basic_man();
let (event_tx, event_rx) = channel();
let mut sender = EventTmSender { sender: event_tx };
let event_sent = event_man
.generate_pus_event_tm(&mut sender, &EMPTY_STAMP, INFO_EVENT, None)
.expect("Sending info event failed");
assert!(event_sent);
// Will not check packet here, correctness of packet was tested somewhere else
event_rx.try_recv().expect("Receiving event TM failed");
}
#[test]
fn test_disable_event() {
let mut event_man = create_basic_man();
let (event_tx, event_rx) = channel();
let mut sender = EventTmSender { sender: event_tx };
let res = event_man.disable_tm_for_event(&LOW_SEV_EVENT);
assert!(res.is_ok());
assert!(res.unwrap());
let mut event_sent = event_man
.generate_pus_event_tm_generic(&mut sender, &EMPTY_STAMP, LOW_SEV_EVENT, None)
.expect("Sending low severity event failed");
assert!(!event_sent);
let res = event_rx.try_recv();
assert!(res.is_err());
assert!(matches!(res.unwrap_err(), TryRecvError::Empty));
// Check that only the low severity event was disabled
event_sent = event_man
.generate_pus_event_tm(&mut sender, &EMPTY_STAMP, INFO_EVENT, None)
.expect("Sending info event failed");
assert!(event_sent);
event_rx.try_recv().expect("No info event received");
}
#[test]
fn test_reenable_event() {
let mut event_man = create_basic_man();
let (event_tx, event_rx) = channel();
let mut sender = EventTmSender { sender: event_tx };
let mut res = event_man.disable_tm_for_event_with_sev(&INFO_EVENT);
assert!(res.is_ok());
assert!(res.unwrap());
res = event_man.enable_tm_for_event_with_sev(&INFO_EVENT);
assert!(res.is_ok());
assert!(res.unwrap());
let event_sent = event_man
.generate_pus_event_tm(&mut sender, &EMPTY_STAMP, INFO_EVENT, None)
.expect("Sending info event failed");
assert!(event_sent);
event_rx.try_recv().expect("No info event received");
}
}

93
satrs-core/src/pus/mod.rs Normal file
View File

@ -0,0 +1,93 @@
//! All PUS support modules
//!
//! Currenty includes:
//!
//! 1. PUS Verification Service 1 module inside [verification]. Requires [alloc] support.
use downcast_rs::{impl_downcast, Downcast};
use spacepackets::ecss::PusError;
use spacepackets::time::TimestampError;
use spacepackets::tm::PusTm;
use spacepackets::{ByteConversionError, SizeMissmatch};
pub mod event;
pub mod event_man;
pub mod verification;
/// Generic error type which is also able to wrap a user send error with the user supplied type E.
#[derive(Debug, Clone)]
pub enum EcssTmError<E> {
/// 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 insufficient buffer size for given data
ByteConversionError(ByteConversionError),
/// Errors related to PUS packet format
PusError(PusError),
}
impl<E> From<PusError> for EcssTmError<E> {
fn from(e: PusError) -> Self {
EcssTmError::PusError(e)
}
}
impl<E> From<ByteConversionError> for EcssTmError<E> {
fn from(e: ByteConversionError) -> Self {
EcssTmError::ByteConversionError(e)
}
}
/// Generic trait for a user supplied sender object.
///
/// This sender object is responsible for sending telemetry to a TM sink. 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 EcssTmSender: Downcast + Send {
type Error;
fn send_tm(&mut self, tm: PusTm) -> Result<(), EcssTmError<Self::Error>>;
}
impl_downcast!(EcssTmSender assoc Error);
pub(crate) fn source_buffer_large_enough<E>(cap: usize, len: usize) -> Result<(), EcssTmError<E>> {
if len > cap {
return Err(EcssTmError::ByteConversionError(
ByteConversionError::ToSliceTooSmall(SizeMissmatch {
found: cap,
expected: len,
}),
));
}
Ok(())
}
#[cfg(test)]
pub(crate) mod tests {
use spacepackets::tm::{PusTm, PusTmSecondaryHeaderT};
use spacepackets::CcsdsPacket;
#[derive(Debug, Eq, PartialEq)]
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];
time_stamp.clone_from_slice(&tm.time_stamp()[0..7]);
Self {
subservice: tm.subservice(),
apid: tm.apid(),
msg_counter: tm.msg_counter(),
dest_id: tm.dest_id(),
time_stamp,
}
}
}
}

File diff suppressed because it is too large Load Diff