satrs_core/pus/
event_srv.rs

1use crate::events::EventU32;
2use crate::pus::event_man::{EventRequest, EventRequestWithToken};
3use crate::pus::verification::TcStateToken;
4use crate::pus::{PartialPusHandlingError, PusPacketHandlerResult, PusPacketHandlingError};
5use spacepackets::ecss::event::Subservice;
6use spacepackets::ecss::PusPacket;
7use std::sync::mpsc::Sender;
8
9use super::{EcssTcInMemConverter, PusServiceBase, PusServiceHelper};
10
11pub struct PusService5EventHandler<TcInMemConverter: EcssTcInMemConverter> {
12    pub service_helper: PusServiceHelper<TcInMemConverter>,
13    event_request_tx: Sender<EventRequestWithToken>,
14}
15
16impl<TcInMemConverter: EcssTcInMemConverter> PusService5EventHandler<TcInMemConverter> {
17    pub fn new(
18        service_handler: PusServiceHelper<TcInMemConverter>,
19        event_request_tx: Sender<EventRequestWithToken>,
20    ) -> Self {
21        Self {
22            service_helper: service_handler,
23            event_request_tx,
24        }
25    }
26
27    pub fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
28        let possible_packet = self.service_helper.retrieve_and_accept_next_packet()?;
29        if possible_packet.is_none() {
30            return Ok(PusPacketHandlerResult::Empty);
31        }
32        let ecss_tc_and_token = possible_packet.unwrap();
33        let tc = self
34            .service_helper
35            .tc_in_mem_converter
36            .convert_ecss_tc_in_memory_to_reader(&ecss_tc_and_token.tc_in_memory)?;
37        let subservice = tc.subservice();
38        let srv = Subservice::try_from(subservice);
39        if srv.is_err() {
40            return Ok(PusPacketHandlerResult::CustomSubservice(
41                tc.subservice(),
42                ecss_tc_and_token.token,
43            ));
44        }
45        let handle_enable_disable_request = |enable: bool, stamp: [u8; 7]| {
46            if tc.user_data().len() < 4 {
47                return Err(PusPacketHandlingError::NotEnoughAppData(
48                    "at least 4 bytes event ID expected".into(),
49                ));
50            }
51            let user_data = tc.user_data();
52            let event_u32 = EventU32::from(u32::from_be_bytes(user_data[0..4].try_into().unwrap()));
53            let start_token = self
54                .service_helper
55                .common
56                .verification_handler
57                .borrow_mut()
58                .start_success(ecss_tc_and_token.token, Some(&stamp))
59                .map_err(|_| PartialPusHandlingError::Verification);
60            let partial_error = start_token.clone().err();
61            let mut token: TcStateToken = ecss_tc_and_token.token.into();
62            if let Ok(start_token) = start_token {
63                token = start_token.into();
64            }
65            let event_req_with_token = if enable {
66                EventRequestWithToken {
67                    request: EventRequest::Enable(event_u32),
68                    token,
69                }
70            } else {
71                EventRequestWithToken {
72                    request: EventRequest::Disable(event_u32),
73                    token,
74                }
75            };
76            self.event_request_tx
77                .send(event_req_with_token)
78                .map_err(|_| {
79                    PusPacketHandlingError::Other("Forwarding event request failed".into())
80                })?;
81            if let Some(partial_error) = partial_error {
82                return Ok(PusPacketHandlerResult::RequestHandledPartialSuccess(
83                    partial_error,
84                ));
85            }
86            Ok(PusPacketHandlerResult::RequestHandled)
87        };
88        let mut partial_error = None;
89        let time_stamp = PusServiceBase::get_current_timestamp(&mut partial_error);
90        match srv.unwrap() {
91            Subservice::TmInfoReport
92            | Subservice::TmLowSeverityReport
93            | Subservice::TmMediumSeverityReport
94            | Subservice::TmHighSeverityReport => {
95                return Err(PusPacketHandlingError::InvalidSubservice(tc.subservice()))
96            }
97            Subservice::TcEnableEventGeneration => {
98                handle_enable_disable_request(true, time_stamp)?;
99            }
100            Subservice::TcDisableEventGeneration => {
101                handle_enable_disable_request(false, time_stamp)?;
102            }
103            Subservice::TcReportDisabledList | Subservice::TmDisabledEventsReport => {
104                return Ok(PusPacketHandlerResult::SubserviceNotImplemented(
105                    subservice,
106                    ecss_tc_and_token.token,
107                ));
108            }
109        }
110
111        Ok(PusPacketHandlerResult::RequestHandled)
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use delegate::delegate;
118    use spacepackets::ecss::event::Subservice;
119    use spacepackets::util::UnsignedEnum;
120    use spacepackets::{
121        ecss::{
122            tc::{PusTcCreator, PusTcSecondaryHeader},
123            tm::PusTmReader,
124        },
125        SequenceFlags, SpHeader,
126    };
127    use std::sync::mpsc::{self, Sender};
128
129    use crate::pus::event_man::EventRequest;
130    use crate::pus::tests::SimplePusPacketHandler;
131    use crate::pus::verification::RequestId;
132    use crate::{
133        events::EventU32,
134        pus::{
135            event_man::EventRequestWithToken,
136            tests::{PusServiceHandlerWithSharedStoreCommon, PusTestHarness, TEST_APID},
137            verification::{TcStateAccepted, VerificationToken},
138            EcssTcInSharedStoreConverter, PusPacketHandlerResult, PusPacketHandlingError,
139        },
140    };
141
142    use super::PusService5EventHandler;
143
144    const TEST_EVENT_0: EventU32 = EventU32::const_new(crate::events::Severity::INFO, 5, 25);
145
146    struct Pus5HandlerWithStoreTester {
147        common: PusServiceHandlerWithSharedStoreCommon,
148        handler: PusService5EventHandler<EcssTcInSharedStoreConverter>,
149    }
150
151    impl Pus5HandlerWithStoreTester {
152        pub fn new(event_request_tx: Sender<EventRequestWithToken>) -> Self {
153            let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new();
154            Self {
155                common,
156                handler: PusService5EventHandler::new(srv_handler, event_request_tx),
157            }
158        }
159    }
160
161    impl PusTestHarness for Pus5HandlerWithStoreTester {
162        delegate! {
163            to self.common {
164                fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>;
165                fn read_next_tm(&mut self) -> PusTmReader<'_>;
166                fn check_no_tm_available(&self) -> bool;
167                fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId);
168            }
169
170        }
171    }
172
173    impl SimplePusPacketHandler for Pus5HandlerWithStoreTester {
174        delegate! {
175            to self.handler {
176                fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError>;
177            }
178        }
179    }
180
181    fn event_test(
182        test_harness: &mut (impl PusTestHarness + SimplePusPacketHandler),
183        subservice: Subservice,
184        expected_event_req: EventRequest,
185        event_req_receiver: mpsc::Receiver<EventRequestWithToken>,
186    ) {
187        let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap();
188        let sec_header = PusTcSecondaryHeader::new_simple(5, subservice as u8);
189        let mut app_data = [0; 4];
190        TEST_EVENT_0
191            .write_to_be_bytes(&mut app_data)
192            .expect("writing test event failed");
193        let ping_tc = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true);
194        let token = test_harness.send_tc(&ping_tc);
195        let request_id = token.req_id();
196        test_harness.handle_one_tc().unwrap();
197        test_harness.check_next_verification_tm(1, request_id);
198        test_harness.check_next_verification_tm(3, request_id);
199        // Completion TM is not generated for us.
200        assert!(test_harness.check_no_tm_available());
201        let event_request = event_req_receiver
202            .try_recv()
203            .expect("no event request received");
204        assert_eq!(expected_event_req, event_request.request);
205    }
206
207    #[test]
208    fn test_enabling_event_reporting() {
209        let (event_request_tx, event_request_rx) = mpsc::channel();
210        let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
211        event_test(
212            &mut test_harness,
213            Subservice::TcEnableEventGeneration,
214            EventRequest::Enable(TEST_EVENT_0),
215            event_request_rx,
216        );
217    }
218
219    #[test]
220    fn test_disabling_event_reporting() {
221        let (event_request_tx, event_request_rx) = mpsc::channel();
222        let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
223        event_test(
224            &mut test_harness,
225            Subservice::TcDisableEventGeneration,
226            EventRequest::Disable(TEST_EVENT_0),
227            event_request_rx,
228        );
229    }
230
231    #[test]
232    fn test_empty_tc_queue() {
233        let (event_request_tx, _) = mpsc::channel();
234        let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
235        let result = test_harness.handle_one_tc();
236        assert!(result.is_ok());
237        let result = result.unwrap();
238        if let PusPacketHandlerResult::Empty = result {
239        } else {
240            panic!("unexpected result type {result:?}")
241        }
242    }
243
244    #[test]
245    fn test_sending_custom_subservice() {
246        let (event_request_tx, _) = mpsc::channel();
247        let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
248        let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap();
249        let sec_header = PusTcSecondaryHeader::new_simple(5, 200);
250        let ping_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true);
251        test_harness.send_tc(&ping_tc);
252        let result = test_harness.handle_one_tc();
253        assert!(result.is_ok());
254        let result = result.unwrap();
255        if let PusPacketHandlerResult::CustomSubservice(subservice, _) = result {
256            assert_eq!(subservice, 200);
257        } else {
258            panic!("unexpected result type {result:?}")
259        }
260    }
261
262    #[test]
263    fn test_sending_invalid_app_data() {
264        let (event_request_tx, _) = mpsc::channel();
265        let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
266        let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap();
267        let sec_header =
268            PusTcSecondaryHeader::new_simple(5, Subservice::TcEnableEventGeneration as u8);
269        let ping_tc = PusTcCreator::new(&mut sp_header, sec_header, &[0, 1, 2], true);
270        test_harness.send_tc(&ping_tc);
271        let result = test_harness.handle_one_tc();
272        assert!(result.is_err());
273        let result = result.unwrap_err();
274        if let PusPacketHandlingError::NotEnoughAppData(string) = result {
275            assert_eq!(string, "at least 4 bytes event ID expected");
276        } else {
277            panic!("unexpected result type {result:?}")
278        }
279    }
280}