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 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}