satrs_core/pus/
event.rs

1use crate::pus::{source_buffer_large_enough, EcssTmtcError};
2use spacepackets::ecss::tm::PusTmCreator;
3use spacepackets::ecss::tm::PusTmSecondaryHeader;
4use spacepackets::ecss::{EcssEnumeration, PusError};
5use spacepackets::{SpHeader, MAX_APID};
6
7use crate::pus::EcssTmSenderCore;
8#[cfg(feature = "alloc")]
9pub use alloc_mod::EventReporter;
10pub use spacepackets::ecss::event::*;
11
12pub struct EventReporterBase {
13    msg_count: u16,
14    apid: u16,
15    pub dest_id: u16,
16}
17
18impl EventReporterBase {
19    pub fn new(apid: u16) -> Option<Self> {
20        if apid > MAX_APID {
21            return None;
22        }
23        Some(Self {
24            msg_count: 0,
25            dest_id: 0,
26            apid,
27        })
28    }
29
30    pub fn event_info(
31        &mut self,
32        buf: &mut [u8],
33        sender: &mut (impl EcssTmSenderCore + ?Sized),
34        time_stamp: &[u8],
35        event_id: impl EcssEnumeration,
36        aux_data: Option<&[u8]>,
37    ) -> Result<(), EcssTmtcError> {
38        self.generate_and_send_generic_tm(
39            buf,
40            Subservice::TmInfoReport,
41            sender,
42            time_stamp,
43            event_id,
44            aux_data,
45        )
46    }
47
48    pub fn event_low_severity(
49        &mut self,
50        buf: &mut [u8],
51        sender: &mut (impl EcssTmSenderCore + ?Sized),
52        time_stamp: &[u8],
53        event_id: impl EcssEnumeration,
54        aux_data: Option<&[u8]>,
55    ) -> Result<(), EcssTmtcError> {
56        self.generate_and_send_generic_tm(
57            buf,
58            Subservice::TmLowSeverityReport,
59            sender,
60            time_stamp,
61            event_id,
62            aux_data,
63        )
64    }
65
66    pub fn event_medium_severity(
67        &mut self,
68        buf: &mut [u8],
69        sender: &mut (impl EcssTmSenderCore + ?Sized),
70        time_stamp: &[u8],
71        event_id: impl EcssEnumeration,
72        aux_data: Option<&[u8]>,
73    ) -> Result<(), EcssTmtcError> {
74        self.generate_and_send_generic_tm(
75            buf,
76            Subservice::TmMediumSeverityReport,
77            sender,
78            time_stamp,
79            event_id,
80            aux_data,
81        )
82    }
83
84    pub fn event_high_severity(
85        &mut self,
86        buf: &mut [u8],
87        sender: &mut (impl EcssTmSenderCore + ?Sized),
88        time_stamp: &[u8],
89        event_id: impl EcssEnumeration,
90        aux_data: Option<&[u8]>,
91    ) -> Result<(), EcssTmtcError> {
92        self.generate_and_send_generic_tm(
93            buf,
94            Subservice::TmHighSeverityReport,
95            sender,
96            time_stamp,
97            event_id,
98            aux_data,
99        )
100    }
101
102    fn generate_and_send_generic_tm(
103        &mut self,
104        buf: &mut [u8],
105        subservice: Subservice,
106        sender: &mut (impl EcssTmSenderCore + ?Sized),
107        time_stamp: &[u8],
108        event_id: impl EcssEnumeration,
109        aux_data: Option<&[u8]>,
110    ) -> Result<(), EcssTmtcError> {
111        let tm = self.generate_generic_event_tm(buf, subservice, time_stamp, event_id, aux_data)?;
112        sender.send_tm(tm.into())?;
113        self.msg_count += 1;
114        Ok(())
115    }
116
117    fn generate_generic_event_tm<'a>(
118        &'a self,
119        buf: &'a mut [u8],
120        subservice: Subservice,
121        time_stamp: &'a [u8],
122        event_id: impl EcssEnumeration,
123        aux_data: Option<&[u8]>,
124    ) -> Result<PusTmCreator, EcssTmtcError> {
125        let mut src_data_len = event_id.size();
126        if let Some(aux_data) = aux_data {
127            src_data_len += aux_data.len();
128        }
129        source_buffer_large_enough(buf.len(), src_data_len)?;
130        let mut sp_header = SpHeader::tm_unseg(self.apid, 0, 0).unwrap();
131        let sec_header = PusTmSecondaryHeader::new(
132            5,
133            subservice.into(),
134            self.msg_count,
135            self.dest_id,
136            Some(time_stamp),
137        );
138        let mut current_idx = 0;
139        event_id
140            .write_to_be_bytes(&mut buf[0..event_id.size()])
141            .map_err(PusError::ByteConversion)?;
142        current_idx += event_id.size();
143        if let Some(aux_data) = aux_data {
144            buf[current_idx..current_idx + aux_data.len()].copy_from_slice(aux_data);
145            current_idx += aux_data.len();
146        }
147        Ok(PusTmCreator::new(
148            &mut sp_header,
149            sec_header,
150            &buf[0..current_idx],
151            true,
152        ))
153    }
154}
155
156#[cfg(feature = "alloc")]
157mod alloc_mod {
158    use super::*;
159    use alloc::vec;
160    use alloc::vec::Vec;
161
162    pub struct EventReporter {
163        source_data_buf: Vec<u8>,
164        pub reporter: EventReporterBase,
165    }
166
167    impl EventReporter {
168        pub fn new(apid: u16, max_event_id_and_aux_data_size: usize) -> Option<Self> {
169            let reporter = EventReporterBase::new(apid)?;
170            Some(Self {
171                source_data_buf: vec![0; max_event_id_and_aux_data_size],
172                reporter,
173            })
174        }
175        pub fn event_info(
176            &mut self,
177            sender: &mut (impl EcssTmSenderCore + ?Sized),
178            time_stamp: &[u8],
179            event_id: impl EcssEnumeration,
180            aux_data: Option<&[u8]>,
181        ) -> Result<(), EcssTmtcError> {
182            self.reporter.event_info(
183                self.source_data_buf.as_mut_slice(),
184                sender,
185                time_stamp,
186                event_id,
187                aux_data,
188            )
189        }
190
191        pub fn event_low_severity(
192            &mut self,
193            sender: &mut (impl EcssTmSenderCore + ?Sized),
194            time_stamp: &[u8],
195            event_id: impl EcssEnumeration,
196            aux_data: Option<&[u8]>,
197        ) -> Result<(), EcssTmtcError> {
198            self.reporter.event_low_severity(
199                self.source_data_buf.as_mut_slice(),
200                sender,
201                time_stamp,
202                event_id,
203                aux_data,
204            )
205        }
206
207        pub fn event_medium_severity(
208            &mut self,
209            sender: &mut (impl EcssTmSenderCore + ?Sized),
210            time_stamp: &[u8],
211            event_id: impl EcssEnumeration,
212            aux_data: Option<&[u8]>,
213        ) -> Result<(), EcssTmtcError> {
214            self.reporter.event_medium_severity(
215                self.source_data_buf.as_mut_slice(),
216                sender,
217                time_stamp,
218                event_id,
219                aux_data,
220            )
221        }
222
223        pub fn event_high_severity(
224            &mut self,
225            sender: &mut (impl EcssTmSenderCore + ?Sized),
226            time_stamp: &[u8],
227            event_id: impl EcssEnumeration,
228            aux_data: Option<&[u8]>,
229        ) -> Result<(), EcssTmtcError> {
230            self.reporter.event_high_severity(
231                self.source_data_buf.as_mut_slice(),
232                sender,
233                time_stamp,
234                event_id,
235                aux_data,
236            )
237        }
238    }
239}
240
241#[cfg(test)]
242mod tests {
243    use super::*;
244    use crate::events::{EventU32, Severity};
245    use crate::pus::tests::CommonTmInfo;
246    use crate::pus::{EcssChannel, PusTmWrapper};
247    use crate::ChannelId;
248    use spacepackets::ByteConversionError;
249    use std::cell::RefCell;
250    use std::collections::VecDeque;
251    use std::vec::Vec;
252
253    const EXAMPLE_APID: u16 = 0xee;
254    const EXAMPLE_GROUP_ID: u16 = 2;
255    const EXAMPLE_EVENT_ID_0: u16 = 1;
256    #[allow(dead_code)]
257    const EXAMPLE_EVENT_ID_1: u16 = 2;
258
259    #[derive(Debug, Eq, PartialEq, Clone)]
260    struct TmInfo {
261        pub common: CommonTmInfo,
262        pub event: EventU32,
263        pub aux_data: Vec<u8>,
264    }
265
266    #[derive(Default, Clone)]
267    struct TestSender {
268        pub service_queue: RefCell<VecDeque<TmInfo>>,
269    }
270
271    impl EcssChannel for TestSender {
272        fn id(&self) -> ChannelId {
273            0
274        }
275    }
276
277    impl EcssTmSenderCore for TestSender {
278        fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
279            match tm {
280                PusTmWrapper::InStore(_) => {
281                    panic!("TestSender: unexpected call with address");
282                }
283                PusTmWrapper::Direct(tm) => {
284                    assert!(!tm.source_data().is_empty());
285                    let src_data = tm.source_data();
286                    assert!(src_data.len() >= 4);
287                    let event =
288                        EventU32::from(u32::from_be_bytes(src_data[0..4].try_into().unwrap()));
289                    let mut aux_data = Vec::new();
290                    if src_data.len() > 4 {
291                        aux_data.extend_from_slice(&src_data[4..]);
292                    }
293                    self.service_queue.borrow_mut().push_back(TmInfo {
294                        common: CommonTmInfo::new_from_tm(&tm),
295                        event,
296                        aux_data,
297                    });
298                    Ok(())
299                }
300            }
301        }
302    }
303
304    fn severity_to_subservice(severity: Severity) -> Subservice {
305        match severity {
306            Severity::INFO => Subservice::TmInfoReport,
307            Severity::LOW => Subservice::TmLowSeverityReport,
308            Severity::MEDIUM => Subservice::TmMediumSeverityReport,
309            Severity::HIGH => Subservice::TmHighSeverityReport,
310        }
311    }
312
313    fn report_basic_event(
314        reporter: &mut EventReporter,
315        sender: &mut TestSender,
316        time_stamp: &[u8],
317        event: EventU32,
318        severity: Severity,
319        aux_data: Option<&[u8]>,
320    ) {
321        match severity {
322            Severity::INFO => {
323                reporter
324                    .event_info(sender, time_stamp, event, aux_data)
325                    .expect("Error reporting info event");
326            }
327            Severity::LOW => {
328                reporter
329                    .event_low_severity(sender, time_stamp, event, aux_data)
330                    .expect("Error reporting low event");
331            }
332            Severity::MEDIUM => {
333                reporter
334                    .event_medium_severity(sender, time_stamp, event, aux_data)
335                    .expect("Error reporting medium event");
336            }
337            Severity::HIGH => {
338                reporter
339                    .event_high_severity(sender, time_stamp, event, aux_data)
340                    .expect("Error reporting high event");
341            }
342        }
343    }
344
345    fn basic_event_test(
346        max_event_aux_data_buf: usize,
347        severity: Severity,
348        error_data: Option<&[u8]>,
349    ) {
350        let mut sender = TestSender::default();
351        let reporter = EventReporter::new(EXAMPLE_APID, max_event_aux_data_buf);
352        assert!(reporter.is_some());
353        let mut reporter = reporter.unwrap();
354        let time_stamp_empty: [u8; 7] = [0; 7];
355        let mut error_copy = Vec::new();
356        if let Some(err_data) = error_data {
357            error_copy.extend_from_slice(err_data);
358        }
359        let event = EventU32::new(severity, EXAMPLE_GROUP_ID, EXAMPLE_EVENT_ID_0)
360            .expect("Error creating example event");
361        report_basic_event(
362            &mut reporter,
363            &mut sender,
364            &time_stamp_empty,
365            event,
366            severity,
367            error_data,
368        );
369        let mut service_queue = sender.service_queue.borrow_mut();
370        assert_eq!(service_queue.len(), 1);
371        let tm_info = service_queue.pop_front().unwrap();
372        assert_eq!(
373            tm_info.common.subservice,
374            severity_to_subservice(severity) as u8
375        );
376        assert_eq!(tm_info.common.dest_id, 0);
377        assert_eq!(tm_info.common.time_stamp, time_stamp_empty);
378        assert_eq!(tm_info.common.msg_counter, 0);
379        assert_eq!(tm_info.common.apid, EXAMPLE_APID);
380        assert_eq!(tm_info.event, event);
381        assert_eq!(tm_info.aux_data, error_copy);
382    }
383
384    #[test]
385    fn basic_info_event_generation() {
386        basic_event_test(4, Severity::INFO, None);
387    }
388
389    #[test]
390    fn basic_low_severity_event() {
391        basic_event_test(4, Severity::LOW, None);
392    }
393
394    #[test]
395    fn basic_medium_severity_event() {
396        basic_event_test(4, Severity::MEDIUM, None);
397    }
398
399    #[test]
400    fn basic_high_severity_event() {
401        basic_event_test(4, Severity::HIGH, None);
402    }
403
404    #[test]
405    fn event_with_info_string() {
406        let info_string = "Test Information";
407        basic_event_test(32, Severity::INFO, Some(info_string.as_bytes()));
408    }
409
410    #[test]
411    fn low_severity_with_raw_err_data() {
412        let raw_err_param: i32 = -1;
413        let raw_err = raw_err_param.to_be_bytes();
414        basic_event_test(8, Severity::LOW, Some(&raw_err))
415    }
416
417    fn check_buf_too_small(
418        reporter: &mut EventReporter,
419        sender: &mut TestSender,
420        expected_found_len: usize,
421    ) {
422        let time_stamp_empty: [u8; 7] = [0; 7];
423        let event = EventU32::new(Severity::INFO, EXAMPLE_GROUP_ID, EXAMPLE_EVENT_ID_0)
424            .expect("Error creating example event");
425        let err = reporter.event_info(sender, &time_stamp_empty, event, None);
426        assert!(err.is_err());
427        let err = err.unwrap_err();
428        if let EcssTmtcError::Pus(PusError::ByteConversion(
429            ByteConversionError::ToSliceTooSmall { found, expected },
430        )) = err
431        {
432            assert_eq!(expected, 4);
433            assert_eq!(found, expected_found_len);
434        } else {
435            panic!("Unexpected error {:?}", err);
436        }
437    }
438
439    #[test]
440    fn insufficient_buffer() {
441        let mut sender = TestSender::default();
442        for i in 0..3 {
443            let reporter = EventReporter::new(EXAMPLE_APID, i);
444            assert!(reporter.is_some());
445            let mut reporter = reporter.unwrap();
446            check_buf_too_small(&mut reporter, &mut sender, i);
447        }
448    }
449}