satrs/
request.rs

1use core::{fmt, marker::PhantomData};
2#[cfg(feature = "serde")]
3use serde::{Deserialize, Serialize};
4
5#[cfg(feature = "alloc")]
6pub use alloc_mod::*;
7
8#[cfg(feature = "std")]
9pub use std_mod::*;
10
11use spacepackets::{
12    ecss::{tc::IsPusTelecommand, PusPacket},
13    ByteConversionError,
14};
15
16use crate::{queue::GenericTargetedMessagingError, ComponentId};
17
18/// Generic request ID type. Requests can be associated with an ID to have a unique identifier
19/// for them. This can be useful for tasks like tracking their progress.
20pub type RequestId = u32;
21
22/// CCSDS APID type definition. Please note that the APID is a 14 bit value.
23pub type Apid = u16;
24
25#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
26pub struct UniqueApidTargetId {
27    pub apid: Apid,
28    pub unique_id: u32,
29}
30
31impl UniqueApidTargetId {
32    pub const fn new(apid: Apid, target: u32) -> Self {
33        Self {
34            apid,
35            unique_id: target,
36        }
37    }
38
39    pub fn raw(&self) -> ComponentId {
40        ((self.apid as u64) << 32) | (self.unique_id as u64)
41    }
42
43    pub fn id(&self) -> ComponentId {
44        self.raw()
45    }
46
47    /// This function attempts to build the ID from a PUS telecommand by extracting the APID
48    /// and the first four bytes of the application data field as the target field.
49    pub fn from_pus_tc(
50        tc: &(impl PusPacket + IsPusTelecommand),
51    ) -> Result<Self, ByteConversionError> {
52        if tc.user_data().len() < 4 {
53            return Err(ByteConversionError::FromSliceTooSmall {
54                found: tc.user_data().len(),
55                expected: 4,
56            });
57        }
58        Ok(Self::new(
59            tc.apid(),
60            u32::from_be_bytes(tc.user_data()[0..4].try_into().unwrap()),
61        ))
62    }
63}
64
65impl From<u64> for UniqueApidTargetId {
66    fn from(raw: u64) -> Self {
67        Self {
68            apid: (raw >> 32) as u16,
69            unique_id: raw as u32,
70        }
71    }
72}
73
74impl From<UniqueApidTargetId> for u64 {
75    fn from(target_and_apid_id: UniqueApidTargetId) -> Self {
76        target_and_apid_id.raw()
77    }
78}
79
80impl fmt::Display for UniqueApidTargetId {
81    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82        write!(
83            f,
84            "Target and APID ID with  APID {:#03x} and target {}",
85            self.apid, self.unique_id
86        )
87    }
88}
89
90/// This contains metadata information which might be useful when used together with a
91/// generic message tpye.
92///
93/// This could for example be used to build request/reply patterns or state tracking for request.
94#[derive(Debug, Copy, PartialEq, Eq, Clone)]
95#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
96pub struct MessageMetadata {
97    request_id: RequestId,
98    sender_id: ComponentId,
99}
100
101impl MessageMetadata {
102    pub const fn new(request_id: RequestId, sender_id: ComponentId) -> Self {
103        Self {
104            request_id,
105            sender_id,
106        }
107    }
108
109    pub fn request_id(&self) -> RequestId {
110        self.request_id
111    }
112
113    pub fn sender_id(&self) -> ComponentId {
114        self.sender_id
115    }
116}
117
118/// Generic message type which adds [metadata][MessageMetadata] to a generic message typ.
119#[derive(Debug, Clone, PartialEq, Eq)]
120#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
121pub struct GenericMessage<Message> {
122    pub requestor_info: MessageMetadata,
123    pub message: Message,
124}
125
126impl<Message> GenericMessage<Message> {
127    pub fn new(requestor_info: MessageMetadata, message: Message) -> Self {
128        Self {
129            requestor_info,
130            message,
131        }
132    }
133
134    delegate::delegate! {
135        to self.requestor_info {
136            pub fn request_id(&self) -> RequestId;
137            pub fn sender_id(&self) -> ComponentId;
138        }
139    }
140}
141
142/// Generic trait for objects which can send targeted messages.
143pub trait MessageSender<MSG>: Send {
144    fn send(&self, message: GenericMessage<MSG>) -> Result<(), GenericTargetedMessagingError>;
145}
146
147// Generic trait for objects which can receive targeted messages.
148pub trait MessageReceiver<MSG> {
149    fn try_recv(&self) -> Result<Option<GenericMessage<MSG>>, GenericTargetedMessagingError>;
150}
151
152pub struct MessageWithSenderIdReceiver<MSG, R: MessageReceiver<MSG>>(pub R, PhantomData<MSG>);
153
154impl<MSG, R: MessageReceiver<MSG>> From<R> for MessageWithSenderIdReceiver<MSG, R> {
155    fn from(receiver: R) -> Self {
156        MessageWithSenderIdReceiver(receiver, PhantomData)
157    }
158}
159
160impl<MSG, R: MessageReceiver<MSG>> MessageWithSenderIdReceiver<MSG, R> {
161    pub fn try_recv_message(
162        &self,
163    ) -> Result<Option<GenericMessage<MSG>>, GenericTargetedMessagingError> {
164        self.0.try_recv()
165    }
166}
167
168pub struct MessageReceiverWithId<MSG, R: MessageReceiver<MSG>> {
169    local_channel_id: ComponentId,
170    reply_receiver: MessageWithSenderIdReceiver<MSG, R>,
171}
172
173impl<MSG, R: MessageReceiver<MSG>> MessageReceiverWithId<MSG, R> {
174    pub fn new(local_channel_id: ComponentId, reply_receiver: R) -> Self {
175        Self {
176            local_channel_id,
177            reply_receiver: MessageWithSenderIdReceiver::from(reply_receiver),
178        }
179    }
180
181    pub fn local_channel_id(&self) -> ComponentId {
182        self.local_channel_id
183    }
184}
185
186impl<MSG, R: MessageReceiver<MSG>> MessageReceiverWithId<MSG, R> {
187    pub fn try_recv_message(
188        &self,
189    ) -> Result<Option<GenericMessage<MSG>>, GenericTargetedMessagingError> {
190        self.reply_receiver.0.try_recv()
191    }
192}
193
194#[cfg(feature = "alloc")]
195pub mod alloc_mod {
196    use crate::queue::GenericSendError;
197
198    use super::*;
199    use hashbrown::HashMap;
200
201    pub struct MessageSenderMap<MSG, S: MessageSender<MSG>>(
202        pub HashMap<ComponentId, S>,
203        pub(crate) PhantomData<MSG>,
204    );
205
206    impl<MSG, S: MessageSender<MSG>> Default for MessageSenderMap<MSG, S> {
207        fn default() -> Self {
208            Self(Default::default(), PhantomData)
209        }
210    }
211
212    impl<MSG, S: MessageSender<MSG>> MessageSenderMap<MSG, S> {
213        pub fn add_message_target(&mut self, target_id: ComponentId, message_sender: S) {
214            self.0.insert(target_id, message_sender);
215        }
216
217        pub fn send_message(
218            &self,
219            requestor_info: MessageMetadata,
220            target_channel_id: ComponentId,
221            message: MSG,
222        ) -> Result<(), GenericTargetedMessagingError> {
223            if self.0.contains_key(&target_channel_id) {
224                return self
225                    .0
226                    .get(&target_channel_id)
227                    .unwrap()
228                    .send(GenericMessage::new(requestor_info, message));
229            }
230            Err(GenericSendError::TargetDoesNotExist(target_channel_id).into())
231        }
232    }
233
234    pub struct MessageSenderAndReceiver<TO, FROM, S: MessageSender<TO>, R: MessageReceiver<FROM>> {
235        pub local_channel_id: ComponentId,
236        pub message_sender_map: MessageSenderMap<TO, S>,
237        pub message_receiver: MessageWithSenderIdReceiver<FROM, R>,
238    }
239
240    impl<TO, FROM, S: MessageSender<TO>, R: MessageReceiver<FROM>>
241        MessageSenderAndReceiver<TO, FROM, S, R>
242    {
243        pub fn new(local_channel_id: ComponentId, message_receiver: R) -> Self {
244            Self {
245                local_channel_id,
246                message_sender_map: Default::default(),
247                message_receiver: MessageWithSenderIdReceiver::from(message_receiver),
248            }
249        }
250
251        pub fn add_message_target(&mut self, target_id: ComponentId, message_sender: S) {
252            self.message_sender_map
253                .add_message_target(target_id, message_sender)
254        }
255
256        pub fn local_channel_id_generic(&self) -> ComponentId {
257            self.local_channel_id
258        }
259
260        /// Try to send a message, which can be a reply or a request, depending on the generics.
261        pub fn send_message(
262            &self,
263            request_id: RequestId,
264            target_id: ComponentId,
265            message: TO,
266        ) -> Result<(), GenericTargetedMessagingError> {
267            self.message_sender_map.send_message(
268                MessageMetadata::new(request_id, self.local_channel_id_generic()),
269                target_id,
270                message,
271            )
272        }
273
274        /// Try to receive a message, which can be a reply or a request, depending on the generics.
275        pub fn try_recv_message(
276            &self,
277        ) -> Result<Option<GenericMessage<FROM>>, GenericTargetedMessagingError> {
278            self.message_receiver.try_recv_message()
279        }
280    }
281
282    pub struct RequestAndReplySenderAndReceiver<
283        REQUEST,
284        REPLY,
285        S0: MessageSender<REQUEST>,
286        R0: MessageReceiver<REPLY>,
287        S1: MessageSender<REPLY>,
288        R1: MessageReceiver<REQUEST>,
289    > {
290        pub local_channel_id: ComponentId,
291        // These 2 are a functional group.
292        pub request_sender_map: MessageSenderMap<REQUEST, S0>,
293        pub reply_receiver: MessageWithSenderIdReceiver<REPLY, R0>,
294        // These 2 are a functional group.
295        pub request_receiver: MessageWithSenderIdReceiver<REQUEST, R1>,
296        pub reply_sender_map: MessageSenderMap<REPLY, S1>,
297    }
298
299    impl<
300            REQUEST,
301            REPLY,
302            S0: MessageSender<REQUEST>,
303            R0: MessageReceiver<REPLY>,
304            S1: MessageSender<REPLY>,
305            R1: MessageReceiver<REQUEST>,
306        > RequestAndReplySenderAndReceiver<REQUEST, REPLY, S0, R0, S1, R1>
307    {
308        pub fn new(
309            local_channel_id: ComponentId,
310            request_receiver: R1,
311            reply_receiver: R0,
312        ) -> Self {
313            Self {
314                local_channel_id,
315                request_receiver: request_receiver.into(),
316                reply_receiver: reply_receiver.into(),
317                request_sender_map: Default::default(),
318                reply_sender_map: Default::default(),
319            }
320        }
321
322        pub fn local_channel_id_generic(&self) -> ComponentId {
323            self.local_channel_id
324        }
325    }
326}
327
328#[cfg(feature = "std")]
329pub mod std_mod {
330
331    use super::*;
332    use std::sync::mpsc;
333
334    use crate::queue::{GenericReceiveError, GenericSendError};
335
336    impl<MSG: Send> MessageSender<MSG> for mpsc::Sender<GenericMessage<MSG>> {
337        fn send(&self, message: GenericMessage<MSG>) -> Result<(), GenericTargetedMessagingError> {
338            self.send(message)
339                .map_err(|_| GenericSendError::RxDisconnected)?;
340            Ok(())
341        }
342    }
343    impl<MSG: Send> MessageSender<MSG> for mpsc::SyncSender<GenericMessage<MSG>> {
344        fn send(&self, message: GenericMessage<MSG>) -> Result<(), GenericTargetedMessagingError> {
345            if let Err(e) = self.try_send(message) {
346                return match e {
347                    mpsc::TrySendError::Full(_) => Err(GenericSendError::QueueFull(None).into()),
348                    mpsc::TrySendError::Disconnected(_) => {
349                        Err(GenericSendError::RxDisconnected.into())
350                    }
351                };
352            }
353            Ok(())
354        }
355    }
356
357    pub type MessageSenderMapMpsc<MSG> = MessageReceiverWithId<MSG, mpsc::Sender<MSG>>;
358    pub type MessageSenderMapBoundedMpsc<MSG> = MessageReceiverWithId<MSG, mpsc::SyncSender<MSG>>;
359
360    impl<MSG> MessageReceiver<MSG> for mpsc::Receiver<GenericMessage<MSG>> {
361        fn try_recv(&self) -> Result<Option<GenericMessage<MSG>>, GenericTargetedMessagingError> {
362            match self.try_recv() {
363                Ok(msg) => Ok(Some(msg)),
364                Err(e) => match e {
365                    mpsc::TryRecvError::Empty => Ok(None),
366                    mpsc::TryRecvError::Disconnected => {
367                        Err(GenericReceiveError::TxDisconnected(None).into())
368                    }
369                },
370            }
371        }
372    }
373
374    pub type MessageReceiverWithIdMpsc<MSG> = MessageReceiverWithId<MSG, mpsc::Receiver<MSG>>;
375}
376
377#[cfg(test)]
378mod tests {
379    use std::sync::mpsc;
380
381    use alloc::string::ToString;
382    use spacepackets::{
383        ecss::tc::{PusTcCreator, PusTcSecondaryHeader},
384        ByteConversionError, SpHeader,
385    };
386
387    use crate::{
388        queue::{GenericReceiveError, GenericSendError, GenericTargetedMessagingError},
389        request::{MessageMetadata, MessageSenderMap},
390    };
391
392    use super::{GenericMessage, MessageReceiverWithId, UniqueApidTargetId};
393
394    const TEST_CHANNEL_ID_0: u64 = 1;
395    const TEST_CHANNEL_ID_1: u64 = 2;
396    const TEST_CHANNEL_ID_2: u64 = 3;
397
398    #[test]
399    fn test_basic_target_id_with_apid() {
400        let id = UniqueApidTargetId::new(0x111, 0x01);
401        assert_eq!(id.apid, 0x111);
402        assert_eq!(id.unique_id, 0x01);
403        assert_eq!(id.id(), id.raw());
404        assert_eq!(u64::from(id), id.raw());
405        let id_raw = id.raw();
406        let id_from_raw = UniqueApidTargetId::from(id_raw);
407        assert_eq!(id_from_raw, id);
408        assert_eq!(id.id(), (0x111 << 32) | 0x01);
409        let string = id.to_string();
410        assert_eq!(
411            string,
412            "Target and APID ID with  APID 0x111 and target 1".to_string()
413        );
414    }
415
416    #[test]
417    fn test_basic_target_id_with_apid_from_pus_tc() {
418        let sp_header = SpHeader::new_for_unseg_tc(0x111, 5, 0);
419        let app_data = 1_u32.to_be_bytes();
420        let pus_tc = PusTcCreator::new_simple(sp_header, 17, 1, &app_data, true);
421        let id = UniqueApidTargetId::from_pus_tc(&pus_tc).unwrap();
422        assert_eq!(id.apid, 0x111);
423        assert_eq!(id.unique_id, 1);
424    }
425
426    #[test]
427    fn test_basic_target_id_with_apid_from_pus_tc_invalid_app_data() {
428        let sp_header = SpHeader::new_for_unseg_tc(0x111, 5, 0);
429        let sec_header = PusTcSecondaryHeader::new_simple(17, 1);
430        let pus_tc = PusTcCreator::new_no_app_data(sp_header, sec_header, true);
431        let error = UniqueApidTargetId::from_pus_tc(&pus_tc);
432        assert!(error.is_err());
433        let error = error.unwrap_err();
434        if let ByteConversionError::FromSliceTooSmall { found, expected } = error {
435            assert_eq!(found, 0);
436            assert_eq!(expected, 4);
437        } else {
438            panic!("Unexpected error type");
439        }
440    }
441
442    #[test]
443    fn test_receiver_only() {
444        let (sender, receiver) = mpsc::channel();
445        // Test structure with only a receiver which has a channel ID.
446        let receiver = MessageReceiverWithId::new(TEST_CHANNEL_ID_0, receiver);
447        let request_id = 5;
448        sender
449            .send(GenericMessage::new(
450                MessageMetadata::new(request_id, TEST_CHANNEL_ID_1),
451                5,
452            ))
453            .unwrap();
454        let reply = receiver.try_recv_message().unwrap();
455        assert!(reply.is_some());
456        assert_eq!(receiver.local_channel_id(), TEST_CHANNEL_ID_0);
457        let reply = reply.unwrap();
458        assert_eq!(reply.requestor_info.request_id, request_id);
459        assert_eq!(reply.requestor_info.sender_id, TEST_CHANNEL_ID_1);
460        assert_eq!(reply.message, 5);
461    }
462
463    #[test]
464    fn test_receiver_empty() {
465        let (_sender, receiver) = mpsc::sync_channel::<GenericMessage<i32>>(2);
466        // Test structure with only a receiver which has a channel ID.
467        let receiver = MessageReceiverWithId::new(TEST_CHANNEL_ID_0, receiver);
468        let reply = receiver.try_recv_message().unwrap();
469        assert!(reply.is_none());
470    }
471
472    #[test]
473    fn test_all_tx_disconnected() {
474        let (sender, receiver) = mpsc::sync_channel::<GenericMessage<i32>>(2);
475        // Test structure with only a receiver which has a channel ID.
476        let receiver = MessageReceiverWithId::new(TEST_CHANNEL_ID_0, receiver);
477        drop(sender);
478        let reply = receiver.try_recv_message();
479        assert!(reply.is_err());
480        let error = reply.unwrap_err();
481        if let GenericTargetedMessagingError::Receive(GenericReceiveError::TxDisconnected(None)) =
482            error
483        {
484        } else {
485            panic!("unexpected error type");
486        }
487    }
488
489    #[test]
490    fn test_sender_map() {
491        let (sender0, receiver0) = mpsc::channel();
492        let (sender1, receiver1) = mpsc::channel();
493        let mut sender_map = MessageSenderMap::default();
494        sender_map.add_message_target(TEST_CHANNEL_ID_1, sender0);
495        sender_map.add_message_target(TEST_CHANNEL_ID_2, sender1);
496        sender_map
497            .send_message(
498                MessageMetadata::new(1, TEST_CHANNEL_ID_0),
499                TEST_CHANNEL_ID_1,
500                5,
501            )
502            .expect("sending message failed");
503        let mut reply = receiver0.recv().expect("receiving message failed");
504        assert_eq!(reply.request_id(), 1);
505        assert_eq!(reply.sender_id(), TEST_CHANNEL_ID_0);
506        assert_eq!(reply.message, 5);
507        sender_map
508            .send_message(
509                MessageMetadata::new(2, TEST_CHANNEL_ID_0),
510                TEST_CHANNEL_ID_2,
511                10,
512            )
513            .expect("sending message failed");
514        reply = receiver1.recv().expect("receiving message failed");
515        assert_eq!(reply.request_id(), 2);
516        assert_eq!(reply.sender_id(), TEST_CHANNEL_ID_0);
517        assert_eq!(reply.message, 10);
518    }
519
520    #[test]
521    fn test_sender_map_target_does_not_exist() {
522        let (sender0, _) = mpsc::channel();
523        let mut sender_map_with_id = MessageSenderMap::default();
524        sender_map_with_id.add_message_target(TEST_CHANNEL_ID_1, sender0);
525        let result = sender_map_with_id.send_message(
526            MessageMetadata::new(1, TEST_CHANNEL_ID_0),
527            TEST_CHANNEL_ID_2,
528            5,
529        );
530        assert!(result.is_err());
531        let error = result.unwrap_err();
532        if let GenericTargetedMessagingError::Send(GenericSendError::TargetDoesNotExist(target)) =
533            error
534        {
535            assert_eq!(target, TEST_CHANNEL_ID_2);
536        } else {
537            panic!("Unexpected error type");
538        }
539    }
540    #[test]
541    fn test_sender_map_queue_full() {
542        let (sender0, _receiver0) = mpsc::sync_channel(1);
543        let mut sender_map_with_id = MessageSenderMap::default();
544        sender_map_with_id.add_message_target(TEST_CHANNEL_ID_1, sender0);
545        sender_map_with_id
546            .send_message(
547                MessageMetadata::new(1, TEST_CHANNEL_ID_0),
548                TEST_CHANNEL_ID_1,
549                5,
550            )
551            .expect("sending message failed");
552        let result = sender_map_with_id.send_message(
553            MessageMetadata::new(1, TEST_CHANNEL_ID_0),
554            TEST_CHANNEL_ID_1,
555            5,
556        );
557        assert!(result.is_err());
558        let error = result.unwrap_err();
559        if let GenericTargetedMessagingError::Send(GenericSendError::QueueFull(capacity)) = error {
560            assert!(capacity.is_none());
561        } else {
562            panic!("Unexpected error type {}", error);
563        }
564    }
565
566    #[test]
567    fn test_sender_map_queue_receiver_disconnected() {
568        let (sender0, receiver0) = mpsc::sync_channel(1);
569        let mut sender_map_with_id = MessageSenderMap::default();
570        sender_map_with_id.add_message_target(TEST_CHANNEL_ID_1, sender0);
571        drop(receiver0);
572        let result = sender_map_with_id.send_message(
573            MessageMetadata::new(1, TEST_CHANNEL_ID_0),
574            TEST_CHANNEL_ID_1,
575            5,
576        );
577        assert!(result.is_err());
578        let error = result.unwrap_err();
579        if let GenericTargetedMessagingError::Send(GenericSendError::RxDisconnected) = error {
580        } else {
581            panic!("Unexpected error type {}", error);
582        }
583    }
584}