satrs_core/
seq_count.rs

1use core::cell::Cell;
2#[cfg(feature = "alloc")]
3use dyn_clone::DynClone;
4use paste::paste;
5use spacepackets::MAX_SEQ_COUNT;
6#[cfg(feature = "std")]
7pub use stdmod::*;
8
9/// Core trait for objects which can provide a sequence count.
10///
11/// The core functions are not mutable on purpose to allow easier usage with
12/// static structs when using the interior mutability pattern. This can be achieved by using
13/// [Cell], [core::cell::RefCell] or atomic types.
14pub trait SequenceCountProviderCore<Raw> {
15    fn get(&self) -> Raw;
16
17    fn increment(&self);
18
19    fn get_and_increment(&self) -> Raw {
20        let val = self.get();
21        self.increment();
22        val
23    }
24}
25
26/// Extension trait which allows cloning a sequence count provider after it was turned into
27/// a trait object.
28#[cfg(feature = "alloc")]
29pub trait SequenceCountProvider<Raw>: SequenceCountProviderCore<Raw> + DynClone {}
30#[cfg(feature = "alloc")]
31dyn_clone::clone_trait_object!(SequenceCountProvider<u16>);
32#[cfg(feature = "alloc")]
33impl<T, Raw> SequenceCountProvider<Raw> for T where T: SequenceCountProviderCore<Raw> + Clone {}
34
35#[derive(Default, Clone)]
36pub struct SeqCountProviderSimple<T: Copy> {
37    seq_count: Cell<T>,
38    max_val: T,
39}
40
41macro_rules! impl_for_primitives {
42    ($($ty: ident,)+) => {
43        $(
44            paste! {
45                impl SeqCountProviderSimple<$ty> {
46                    pub fn [<new_ $ty _max_val>](max_val: $ty) -> Self {
47                        Self {
48                            seq_count: Cell::new(0),
49                            max_val,
50                        }
51                    }
52
53                    pub fn [<new_ $ty>]() -> Self {
54                        Self {
55                            seq_count: Cell::new(0),
56                            max_val: $ty::MAX
57                        }
58                    }
59                }
60
61                impl SequenceCountProviderCore<$ty> for SeqCountProviderSimple<$ty> {
62                    fn get(&self) -> $ty {
63                        self.seq_count.get()
64                    }
65
66                    fn increment(&self) {
67                        self.get_and_increment();
68                    }
69
70                    fn get_and_increment(&self) -> $ty {
71                        let curr_count = self.seq_count.get();
72
73                        if curr_count == self.max_val {
74                            self.seq_count.set(0);
75                        } else {
76                            self.seq_count.set(curr_count + 1);
77                        }
78                        curr_count
79                    }
80                }
81            }
82        )+
83    }
84}
85
86impl_for_primitives!(u8, u16, u32, u64,);
87
88/// This is a sequence count provider which wraps around at [MAX_SEQ_COUNT].
89pub struct CcsdsSimpleSeqCountProvider {
90    provider: SeqCountProviderSimple<u16>,
91}
92
93impl CcsdsSimpleSeqCountProvider {
94    pub fn new() -> Self {
95        Self {
96            provider: SeqCountProviderSimple::new_u16_max_val(MAX_SEQ_COUNT),
97        }
98    }
99}
100
101impl Default for CcsdsSimpleSeqCountProvider {
102    fn default() -> Self {
103        Self::new()
104    }
105}
106
107impl SequenceCountProviderCore<u16> for CcsdsSimpleSeqCountProvider {
108    delegate::delegate! {
109        to self.provider {
110            fn get(&self) -> u16;
111            fn increment(&self);
112            fn get_and_increment(&self) -> u16;
113        }
114    }
115}
116
117#[cfg(feature = "std")]
118pub mod stdmod {
119    use super::*;
120    use std::sync::{Arc, Mutex};
121
122    macro_rules! sync_clonable_seq_counter_impl {
123         ($($ty: ident,)+) => {
124             $(paste! {
125                 /// These sequence counters can be shared between threads and can also be
126                 /// configured to wrap around at specified maximum values. Please note that
127                 /// that the API provided by this class will not panic und [Mutex] lock errors,
128                 /// but it will yield 0 for the getter functions.
129                 #[derive(Clone, Default)]
130                 pub struct [<SeqCountProviderSync $ty:upper>] {
131                     seq_count: Arc<Mutex<$ty>>,
132                     max_val: $ty
133                 }
134
135                 impl [<SeqCountProviderSync $ty:upper>] {
136                     pub fn new() -> Self {
137                        Self::new_with_max_val($ty::MAX)
138                     }
139
140                     pub fn new_with_max_val(max_val: $ty) -> Self {
141                         Self {
142                             seq_count: Arc::default(),
143                             max_val
144                         }
145                     }
146                 }
147                 impl SequenceCountProviderCore<$ty> for [<SeqCountProviderSync $ty:upper>] {
148                    fn get(&self) -> $ty {
149                        match self.seq_count.lock() {
150                            Ok(counter) => *counter,
151                            Err(_) => 0
152                        }
153                    }
154
155                    fn increment(&self) {
156                        self.get_and_increment();
157                    }
158
159                    fn get_and_increment(&self) -> $ty {
160                        match self.seq_count.lock() {
161                            Ok(mut counter) => {
162                                let val = *counter;
163                                if val == self.max_val {
164                                    *counter = 0;
165                                } else {
166                                    *counter += 1;
167                                }
168                                val
169                            }
170                            Err(_) => 0,
171                        }
172                    }
173                 }
174             })+
175         }
176    }
177    sync_clonable_seq_counter_impl!(u8, u16, u32, u64,);
178}
179
180#[cfg(test)]
181mod tests {
182    use crate::seq_count::{
183        CcsdsSimpleSeqCountProvider, SeqCountProviderSimple, SeqCountProviderSyncU8,
184        SequenceCountProviderCore,
185    };
186    use spacepackets::MAX_SEQ_COUNT;
187
188    #[test]
189    fn test_u8_counter() {
190        let u8_counter = SeqCountProviderSimple::new_u8();
191        assert_eq!(u8_counter.get(), 0);
192        assert_eq!(u8_counter.get_and_increment(), 0);
193        assert_eq!(u8_counter.get_and_increment(), 1);
194        assert_eq!(u8_counter.get(), 2);
195    }
196
197    #[test]
198    fn test_u8_counter_overflow() {
199        let u8_counter = SeqCountProviderSimple::new_u8();
200        for _ in 0..256 {
201            u8_counter.increment();
202        }
203        assert_eq!(u8_counter.get(), 0);
204    }
205
206    #[test]
207    fn test_ccsds_counter() {
208        let ccsds_counter = CcsdsSimpleSeqCountProvider::default();
209        assert_eq!(ccsds_counter.get(), 0);
210        assert_eq!(ccsds_counter.get_and_increment(), 0);
211        assert_eq!(ccsds_counter.get_and_increment(), 1);
212        assert_eq!(ccsds_counter.get(), 2);
213    }
214
215    #[test]
216    fn test_ccsds_counter_overflow() {
217        let ccsds_counter = CcsdsSimpleSeqCountProvider::default();
218        for _ in 0..MAX_SEQ_COUNT + 1 {
219            ccsds_counter.increment();
220        }
221        assert_eq!(ccsds_counter.get(), 0);
222    }
223
224    #[test]
225    fn test_atomic_ref_counters() {
226        let sync_u8_counter = SeqCountProviderSyncU8::new();
227        assert_eq!(sync_u8_counter.get(), 0);
228        assert_eq!(sync_u8_counter.get_and_increment(), 0);
229        assert_eq!(sync_u8_counter.get_and_increment(), 1);
230        assert_eq!(sync_u8_counter.get(), 2);
231    }
232
233    #[test]
234    fn test_atomic_ref_counters_overflow() {
235        let sync_u8_counter = SeqCountProviderSyncU8::new();
236        for _ in 0..u8::MAX as u16 + 1 {
237            sync_u8_counter.increment();
238        }
239        assert_eq!(sync_u8_counter.get(), 0);
240    }
241
242    #[test]
243    fn test_atomic_ref_counters_overflow_custom_max_val() {
244        let sync_u8_counter = SeqCountProviderSyncU8::new_with_max_val(128);
245        for _ in 0..129 {
246            sync_u8_counter.increment();
247        }
248        assert_eq!(sync_u8_counter.get(), 0);
249    }
250}