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 for u8 { fn from(enumeration: Subservices) -> Self { enumeration as u8 } } pub struct EventReporterBase { msg_count: u16, apid: u16, pub dest_id: u16, } impl EventReporterBase { pub fn new(apid: u16) -> Option { if apid > MAX_APID { return None; } Some(Self { msg_count: 0, dest_id: 0, apid, }) } pub fn event_info( &mut self, buf: &mut [u8], sender: &mut (impl EcssTmSender + ?Sized), time_stamp: &[u8], event_id: impl EcssEnumeration, aux_data: Option<&[u8]>, ) -> Result<(), EcssTmError> { self.generate_and_send_generic_tm( buf, Subservices::TmInfoReport, sender, time_stamp, event_id, aux_data, ) } pub fn event_low_severity( &mut self, buf: &mut [u8], sender: &mut (impl EcssTmSender + ?Sized), time_stamp: &[u8], event_id: impl EcssEnumeration, aux_data: Option<&[u8]>, ) -> Result<(), EcssTmError> { self.generate_and_send_generic_tm( buf, Subservices::TmLowSeverityReport, sender, time_stamp, event_id, aux_data, ) } pub fn event_medium_severity( &mut self, buf: &mut [u8], sender: &mut (impl EcssTmSender + ?Sized), time_stamp: &[u8], event_id: impl EcssEnumeration, aux_data: Option<&[u8]>, ) -> Result<(), EcssTmError> { self.generate_and_send_generic_tm( buf, Subservices::TmMediumSeverityReport, sender, time_stamp, event_id, aux_data, ) } pub fn event_high_severity( &mut self, buf: &mut [u8], sender: &mut (impl EcssTmSender + ?Sized), time_stamp: &[u8], event_id: impl EcssEnumeration, aux_data: Option<&[u8]>, ) -> Result<(), EcssTmError> { self.generate_and_send_generic_tm( buf, Subservices::TmHighSeverityReport, sender, time_stamp, event_id, aux_data, ) } fn generate_and_send_generic_tm( &mut self, buf: &mut [u8], subservice: Subservices, sender: &mut (impl EcssTmSender + ?Sized), time_stamp: &[u8], event_id: impl EcssEnumeration, aux_data: Option<&[u8]>, ) -> Result<(), EcssTmError> { 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> { 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_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, pub reporter: EventReporterBase, } impl EventReporter { pub fn new(apid: u16, max_event_id_and_aux_data_size: usize) -> Option { let reporter = EventReporterBase::new(apid)?; Some(Self { source_data_buf: vec![0; max_event_id_and_aux_data_size], reporter, }) } pub fn event_info( &mut self, sender: &mut (impl EcssTmSender + ?Sized), time_stamp: &[u8], event_id: impl EcssEnumeration, aux_data: Option<&[u8]>, ) -> Result<(), EcssTmError> { self.reporter.event_info( self.source_data_buf.as_mut_slice(), sender, time_stamp, event_id, aux_data, ) } pub fn event_low_severity( &mut self, sender: &mut (impl EcssTmSender + ?Sized), time_stamp: &[u8], event_id: impl EcssEnumeration, aux_data: Option<&[u8]>, ) -> Result<(), EcssTmError> { self.reporter.event_low_severity( self.source_data_buf.as_mut_slice(), sender, time_stamp, event_id, aux_data, ) } pub fn event_medium_severity( &mut self, sender: &mut (impl EcssTmSender + ?Sized), time_stamp: &[u8], event_id: impl EcssEnumeration, aux_data: Option<&[u8]>, ) -> Result<(), EcssTmError> { self.reporter.event_medium_severity( self.source_data_buf.as_mut_slice(), sender, time_stamp, event_id, aux_data, ) } pub fn event_high_severity( &mut self, sender: &mut (impl EcssTmSender + ?Sized), time_stamp: &[u8], event_id: impl EcssEnumeration, aux_data: Option<&[u8]>, ) -> Result<(), EcssTmError> { 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::{Event, Severity}; use crate::pus::tests::CommonTmInfo; use std::collections::VecDeque; const EXAMPLE_APID: u16 = 0xee; const EXAMPLE_GROUP_ID: u16 = 2; const EXAMPLE_EVENT_ID: u16 = 1; #[derive(Debug, Eq, PartialEq)] struct TmInfo { pub common: CommonTmInfo, } #[derive(Default)] struct TestSender { pub service_queue: VecDeque, } impl EcssTmSender<()> for TestSender { fn send_tm(&mut self, tm: PusTm) -> Result<(), EcssTmError<()>> { self.service_queue.push_back(TmInfo { common: CommonTmInfo::new_from_tm(&tm), }); Ok(()) } } #[test] fn basic_event_generation() { let mut sender = TestSender::default(); let reporter = EventReporter::new(EXAMPLE_APID, 16); assert!(reporter.is_some()); let mut reporter = reporter.unwrap(); let time_stamp_empty: [u8; 7] = [0; 7]; let event = Event::new(Severity::INFO, EXAMPLE_GROUP_ID, EXAMPLE_EVENT_ID) .expect("Error creating example event"); reporter .event_info(&mut sender, &time_stamp_empty, event, None) .expect("Error reporting info event"); } }