Robin Mueller
de4e6183b3
All checks were successful
Rust/sat-rs/pipeline/pr-main This commit looks good
- Add new shared subcrate satrs-shared to split off some shared components not expected to change very often. - Renmame `satrs-core` to `satrs`. It is expected that sat-rs will remain the primary crate, so the core information is superfluous, and core also implies stability, which will not be the case for some time.
251 lines
7.7 KiB
Rust
251 lines
7.7 KiB
Rust
use core::cell::Cell;
|
|
#[cfg(feature = "alloc")]
|
|
use dyn_clone::DynClone;
|
|
use paste::paste;
|
|
use spacepackets::MAX_SEQ_COUNT;
|
|
#[cfg(feature = "std")]
|
|
pub use stdmod::*;
|
|
|
|
/// Core trait for objects which can provide a sequence count.
|
|
///
|
|
/// The core functions are not mutable on purpose to allow easier usage with
|
|
/// static structs when using the interior mutability pattern. This can be achieved by using
|
|
/// [Cell], [core::cell::RefCell] or atomic types.
|
|
pub trait SequenceCountProviderCore<Raw> {
|
|
fn get(&self) -> Raw;
|
|
|
|
fn increment(&self);
|
|
|
|
fn get_and_increment(&self) -> Raw {
|
|
let val = self.get();
|
|
self.increment();
|
|
val
|
|
}
|
|
}
|
|
|
|
/// Extension trait which allows cloning a sequence count provider after it was turned into
|
|
/// a trait object.
|
|
#[cfg(feature = "alloc")]
|
|
pub trait SequenceCountProvider<Raw>: SequenceCountProviderCore<Raw> + DynClone {}
|
|
#[cfg(feature = "alloc")]
|
|
dyn_clone::clone_trait_object!(SequenceCountProvider<u16>);
|
|
#[cfg(feature = "alloc")]
|
|
impl<T, Raw> SequenceCountProvider<Raw> for T where T: SequenceCountProviderCore<Raw> + Clone {}
|
|
|
|
#[derive(Default, Clone)]
|
|
pub struct SeqCountProviderSimple<T: Copy> {
|
|
seq_count: Cell<T>,
|
|
max_val: T,
|
|
}
|
|
|
|
macro_rules! impl_for_primitives {
|
|
($($ty: ident,)+) => {
|
|
$(
|
|
paste! {
|
|
impl SeqCountProviderSimple<$ty> {
|
|
pub fn [<new_ $ty _max_val>](max_val: $ty) -> Self {
|
|
Self {
|
|
seq_count: Cell::new(0),
|
|
max_val,
|
|
}
|
|
}
|
|
|
|
pub fn [<new_ $ty>]() -> Self {
|
|
Self {
|
|
seq_count: Cell::new(0),
|
|
max_val: $ty::MAX
|
|
}
|
|
}
|
|
}
|
|
|
|
impl SequenceCountProviderCore<$ty> for SeqCountProviderSimple<$ty> {
|
|
fn get(&self) -> $ty {
|
|
self.seq_count.get()
|
|
}
|
|
|
|
fn increment(&self) {
|
|
self.get_and_increment();
|
|
}
|
|
|
|
fn get_and_increment(&self) -> $ty {
|
|
let curr_count = self.seq_count.get();
|
|
|
|
if curr_count == self.max_val {
|
|
self.seq_count.set(0);
|
|
} else {
|
|
self.seq_count.set(curr_count + 1);
|
|
}
|
|
curr_count
|
|
}
|
|
}
|
|
}
|
|
)+
|
|
}
|
|
}
|
|
|
|
impl_for_primitives!(u8, u16, u32, u64,);
|
|
|
|
/// This is a sequence count provider which wraps around at [MAX_SEQ_COUNT].
|
|
pub struct CcsdsSimpleSeqCountProvider {
|
|
provider: SeqCountProviderSimple<u16>,
|
|
}
|
|
|
|
impl CcsdsSimpleSeqCountProvider {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
provider: SeqCountProviderSimple::new_u16_max_val(MAX_SEQ_COUNT),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for CcsdsSimpleSeqCountProvider {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl SequenceCountProviderCore<u16> for CcsdsSimpleSeqCountProvider {
|
|
delegate::delegate! {
|
|
to self.provider {
|
|
fn get(&self) -> u16;
|
|
fn increment(&self);
|
|
fn get_and_increment(&self) -> u16;
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "std")]
|
|
pub mod stdmod {
|
|
use super::*;
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
macro_rules! sync_clonable_seq_counter_impl {
|
|
($($ty: ident,)+) => {
|
|
$(paste! {
|
|
/// These sequence counters can be shared between threads and can also be
|
|
/// configured to wrap around at specified maximum values. Please note that
|
|
/// that the API provided by this class will not panic und [Mutex] lock errors,
|
|
/// but it will yield 0 for the getter functions.
|
|
#[derive(Clone, Default)]
|
|
pub struct [<SeqCountProviderSync $ty:upper>] {
|
|
seq_count: Arc<Mutex<$ty>>,
|
|
max_val: $ty
|
|
}
|
|
|
|
impl [<SeqCountProviderSync $ty:upper>] {
|
|
pub fn new() -> Self {
|
|
Self::new_with_max_val($ty::MAX)
|
|
}
|
|
|
|
pub fn new_with_max_val(max_val: $ty) -> Self {
|
|
Self {
|
|
seq_count: Arc::default(),
|
|
max_val
|
|
}
|
|
}
|
|
}
|
|
impl SequenceCountProviderCore<$ty> for [<SeqCountProviderSync $ty:upper>] {
|
|
fn get(&self) -> $ty {
|
|
match self.seq_count.lock() {
|
|
Ok(counter) => *counter,
|
|
Err(_) => 0
|
|
}
|
|
}
|
|
|
|
fn increment(&self) {
|
|
self.get_and_increment();
|
|
}
|
|
|
|
fn get_and_increment(&self) -> $ty {
|
|
match self.seq_count.lock() {
|
|
Ok(mut counter) => {
|
|
let val = *counter;
|
|
if val == self.max_val {
|
|
*counter = 0;
|
|
} else {
|
|
*counter += 1;
|
|
}
|
|
val
|
|
}
|
|
Err(_) => 0,
|
|
}
|
|
}
|
|
}
|
|
})+
|
|
}
|
|
}
|
|
sync_clonable_seq_counter_impl!(u8, u16, u32, u64,);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::seq_count::{
|
|
CcsdsSimpleSeqCountProvider, SeqCountProviderSimple, SeqCountProviderSyncU8,
|
|
SequenceCountProviderCore,
|
|
};
|
|
use spacepackets::MAX_SEQ_COUNT;
|
|
|
|
#[test]
|
|
fn test_u8_counter() {
|
|
let u8_counter = SeqCountProviderSimple::new_u8();
|
|
assert_eq!(u8_counter.get(), 0);
|
|
assert_eq!(u8_counter.get_and_increment(), 0);
|
|
assert_eq!(u8_counter.get_and_increment(), 1);
|
|
assert_eq!(u8_counter.get(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_u8_counter_overflow() {
|
|
let u8_counter = SeqCountProviderSimple::new_u8();
|
|
for _ in 0..256 {
|
|
u8_counter.increment();
|
|
}
|
|
assert_eq!(u8_counter.get(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_ccsds_counter() {
|
|
let ccsds_counter = CcsdsSimpleSeqCountProvider::default();
|
|
assert_eq!(ccsds_counter.get(), 0);
|
|
assert_eq!(ccsds_counter.get_and_increment(), 0);
|
|
assert_eq!(ccsds_counter.get_and_increment(), 1);
|
|
assert_eq!(ccsds_counter.get(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_ccsds_counter_overflow() {
|
|
let ccsds_counter = CcsdsSimpleSeqCountProvider::default();
|
|
for _ in 0..MAX_SEQ_COUNT + 1 {
|
|
ccsds_counter.increment();
|
|
}
|
|
assert_eq!(ccsds_counter.get(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_atomic_ref_counters() {
|
|
let sync_u8_counter = SeqCountProviderSyncU8::new();
|
|
assert_eq!(sync_u8_counter.get(), 0);
|
|
assert_eq!(sync_u8_counter.get_and_increment(), 0);
|
|
assert_eq!(sync_u8_counter.get_and_increment(), 1);
|
|
assert_eq!(sync_u8_counter.get(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_atomic_ref_counters_overflow() {
|
|
let sync_u8_counter = SeqCountProviderSyncU8::new();
|
|
for _ in 0..u8::MAX as u16 + 1 {
|
|
sync_u8_counter.increment();
|
|
}
|
|
assert_eq!(sync_u8_counter.get(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_atomic_ref_counters_overflow_custom_max_val() {
|
|
let sync_u8_counter = SeqCountProviderSyncU8::new_with_max_val(128);
|
|
for _ in 0..129 {
|
|
sync_u8_counter.increment();
|
|
}
|
|
assert_eq!(sync_u8_counter.get(), 0);
|
|
}
|
|
}
|