1use crate::tmtc::{ReceivesCcsdsTc, ReceivesTcCore};
89use alloc::boxed::Box;
90use core::fmt::{Display, Formatter};
91use downcast_rs::Downcast;
92use spacepackets::{ByteConversionError, CcsdsPacket, SpHeader};
93#[cfg(feature = "std")]
94use std::error::Error;
95
96pub trait CcsdsPacketHandler: Downcast {
107    type Error;
108
109    fn valid_apids(&self) -> &'static [u16];
110    fn handle_known_apid(&mut self, sp_header: &SpHeader, tc_raw: &[u8])
111        -> Result<(), Self::Error>;
112    fn handle_unknown_apid(
113        &mut self,
114        sp_header: &SpHeader,
115        tc_raw: &[u8],
116    ) -> Result<(), Self::Error>;
117}
118
119downcast_rs::impl_downcast!(CcsdsPacketHandler assoc Error);
120
121pub trait SendableCcsdsPacketHandler: CcsdsPacketHandler + Send {}
122
123impl<T: CcsdsPacketHandler + Send> SendableCcsdsPacketHandler for T {}
124
125downcast_rs::impl_downcast!(SendableCcsdsPacketHandler assoc Error);
126
127pub struct CcsdsDistributor<E> {
132    pub apid_handler: Box<dyn SendableCcsdsPacketHandler<Error = E>>,
136}
137
138#[derive(Debug, Copy, Clone, PartialEq, Eq)]
139pub enum CcsdsError<E> {
140    CustomError(E),
141    ByteConversionError(ByteConversionError),
142}
143
144impl<E: Display> Display for CcsdsError<E> {
145    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
146        match self {
147            Self::CustomError(e) => write!(f, "{e}"),
148            Self::ByteConversionError(e) => write!(f, "{e}"),
149        }
150    }
151}
152
153#[cfg(feature = "std")]
154impl<E: Error> Error for CcsdsError<E> {
155    fn source(&self) -> Option<&(dyn Error + 'static)> {
156        match self {
157            Self::CustomError(e) => e.source(),
158            Self::ByteConversionError(e) => e.source(),
159        }
160    }
161}
162
163impl<E: 'static> ReceivesCcsdsTc for CcsdsDistributor<E> {
164    type Error = CcsdsError<E>;
165
166    fn pass_ccsds(&mut self, header: &SpHeader, tc_raw: &[u8]) -> Result<(), Self::Error> {
167        self.dispatch_ccsds(header, tc_raw)
168    }
169}
170
171impl<E: 'static> ReceivesTcCore for CcsdsDistributor<E> {
172    type Error = CcsdsError<E>;
173
174    fn pass_tc(&mut self, tc_raw: &[u8]) -> Result<(), Self::Error> {
175        if tc_raw.len() < 7 {
176            return Err(CcsdsError::ByteConversionError(
177                ByteConversionError::FromSliceTooSmall {
178                    found: tc_raw.len(),
179                    expected: 7,
180                },
181            ));
182        }
183        let (sp_header, _) =
184            SpHeader::from_be_bytes(tc_raw).map_err(|e| CcsdsError::ByteConversionError(e))?;
185        self.dispatch_ccsds(&sp_header, tc_raw)
186    }
187}
188
189impl<E: 'static> CcsdsDistributor<E> {
190    pub fn new(apid_handler: Box<dyn SendableCcsdsPacketHandler<Error = E>>) -> Self {
191        CcsdsDistributor { apid_handler }
192    }
193
194    pub fn apid_handler_ref<T: SendableCcsdsPacketHandler<Error = E>>(&self) -> Option<&T> {
198        self.apid_handler.downcast_ref::<T>()
199    }
200
201    pub fn apid_handler_mut<T: SendableCcsdsPacketHandler<Error = E>>(&mut self) -> Option<&mut T> {
204        self.apid_handler.downcast_mut::<T>()
205    }
206
207    fn dispatch_ccsds(&mut self, sp_header: &SpHeader, tc_raw: &[u8]) -> Result<(), CcsdsError<E>> {
208        let apid = sp_header.apid();
209        let valid_apids = self.apid_handler.valid_apids();
210        for &valid_apid in valid_apids {
211            if valid_apid == apid {
212                return self
213                    .apid_handler
214                    .handle_known_apid(sp_header, tc_raw)
215                    .map_err(|e| CcsdsError::CustomError(e));
216            }
217        }
218        self.apid_handler
219            .handle_unknown_apid(sp_header, tc_raw)
220            .map_err(|e| CcsdsError::CustomError(e))
221    }
222}
223
224#[cfg(test)]
225pub(crate) mod tests {
226    use super::*;
227    use crate::tmtc::ccsds_distrib::{CcsdsDistributor, CcsdsPacketHandler};
228    use spacepackets::ecss::tc::PusTcCreator;
229    use spacepackets::ecss::WritablePusPacket;
230    use spacepackets::CcsdsPacket;
231    use std::collections::VecDeque;
232    use std::sync::{Arc, Mutex};
233    use std::vec::Vec;
234
235    fn is_send<T: Send>(_: &T) {}
236
237    pub fn generate_ping_tc(buf: &mut [u8]) -> &[u8] {
238        let mut sph = SpHeader::tc_unseg(0x002, 0x34, 0).unwrap();
239        let pus_tc = PusTcCreator::new_simple(&mut sph, 17, 1, None, true);
240        let size = pus_tc
241            .write_to_bytes(buf)
242            .expect("Error writing TC to buffer");
243        assert_eq!(size, 13);
244        &buf[0..size]
245    }
246
247    type SharedPacketQueue = Arc<Mutex<VecDeque<(u16, Vec<u8>)>>>;
248    pub struct BasicApidHandlerSharedQueue {
249        pub known_packet_queue: SharedPacketQueue,
250        pub unknown_packet_queue: SharedPacketQueue,
251    }
252
253    #[derive(Default)]
254    pub struct BasicApidHandlerOwnedQueue {
255        pub known_packet_queue: VecDeque<(u16, Vec<u8>)>,
256        pub unknown_packet_queue: VecDeque<(u16, Vec<u8>)>,
257    }
258
259    impl CcsdsPacketHandler for BasicApidHandlerSharedQueue {
260        type Error = ();
261        fn valid_apids(&self) -> &'static [u16] {
262            &[0x000, 0x002]
263        }
264
265        fn handle_known_apid(
266            &mut self,
267            sp_header: &SpHeader,
268            tc_raw: &[u8],
269        ) -> Result<(), Self::Error> {
270            let mut vec = Vec::new();
271            vec.extend_from_slice(tc_raw);
272            self.known_packet_queue
273                .lock()
274                .unwrap()
275                .push_back((sp_header.apid(), vec));
276            Ok(())
277        }
278
279        fn handle_unknown_apid(
280            &mut self,
281            sp_header: &SpHeader,
282            tc_raw: &[u8],
283        ) -> Result<(), Self::Error> {
284            let mut vec = Vec::new();
285            vec.extend_from_slice(tc_raw);
286            self.unknown_packet_queue
287                .lock()
288                .unwrap()
289                .push_back((sp_header.apid(), vec));
290            Ok(())
291        }
292    }
293
294    impl CcsdsPacketHandler for BasicApidHandlerOwnedQueue {
295        type Error = ();
296
297        fn valid_apids(&self) -> &'static [u16] {
298            &[0x000, 0x002]
299        }
300
301        fn handle_known_apid(
302            &mut self,
303            sp_header: &SpHeader,
304            tc_raw: &[u8],
305        ) -> Result<(), Self::Error> {
306            let mut vec = Vec::new();
307            vec.extend_from_slice(tc_raw);
308            Ok(self.known_packet_queue.push_back((sp_header.apid(), vec)))
309        }
310
311        fn handle_unknown_apid(
312            &mut self,
313            sp_header: &SpHeader,
314            tc_raw: &[u8],
315        ) -> Result<(), Self::Error> {
316            let mut vec = Vec::new();
317            vec.extend_from_slice(tc_raw);
318            Ok(self.unknown_packet_queue.push_back((sp_header.apid(), vec)))
319        }
320    }
321
322    #[test]
323    fn test_distribs_known_apid() {
324        let known_packet_queue = Arc::new(Mutex::default());
325        let unknown_packet_queue = Arc::new(Mutex::default());
326        let apid_handler = BasicApidHandlerSharedQueue {
327            known_packet_queue: known_packet_queue.clone(),
328            unknown_packet_queue: unknown_packet_queue.clone(),
329        };
330        let mut ccsds_distrib = CcsdsDistributor::new(Box::new(apid_handler));
331        is_send(&ccsds_distrib);
332        let mut test_buf: [u8; 32] = [0; 32];
333        let tc_slice = generate_ping_tc(test_buf.as_mut_slice());
334
335        ccsds_distrib.pass_tc(tc_slice).expect("Passing TC failed");
336        let recvd = known_packet_queue.lock().unwrap().pop_front();
337        assert!(unknown_packet_queue.lock().unwrap().is_empty());
338        assert!(recvd.is_some());
339        let (apid, packet) = recvd.unwrap();
340        assert_eq!(apid, 0x002);
341        assert_eq!(packet, tc_slice);
342    }
343
344    #[test]
345    fn test_distribs_unknown_apid() {
346        let known_packet_queue = Arc::new(Mutex::default());
347        let unknown_packet_queue = Arc::new(Mutex::default());
348        let apid_handler = BasicApidHandlerSharedQueue {
349            known_packet_queue: known_packet_queue.clone(),
350            unknown_packet_queue: unknown_packet_queue.clone(),
351        };
352        let mut ccsds_distrib = CcsdsDistributor::new(Box::new(apid_handler));
353        let mut sph = SpHeader::tc_unseg(0x004, 0x34, 0).unwrap();
354        let pus_tc = PusTcCreator::new_simple(&mut sph, 17, 1, None, true);
355        let mut test_buf: [u8; 32] = [0; 32];
356        pus_tc
357            .write_to_bytes(test_buf.as_mut_slice())
358            .expect("Error writing TC to buffer");
359        ccsds_distrib.pass_tc(&test_buf).expect("Passing TC failed");
360        let recvd = unknown_packet_queue.lock().unwrap().pop_front();
361        assert!(known_packet_queue.lock().unwrap().is_empty());
362        assert!(recvd.is_some());
363        let (apid, packet) = recvd.unwrap();
364        assert_eq!(apid, 0x004);
365        assert_eq!(packet.as_slice(), test_buf);
366    }
367}