use crate::{Error, Result};
pub const SYNC_COB_ID: u16 = 0x080;
pub const fn is_valid_counter_overflow(overflow: u8) -> bool {
overflow == 0 || (2 <= overflow && overflow <= 240)
}
pub fn decode(data: &[u8]) -> Result<Option<u8>> {
match data.len() {
0 => Ok(None),
1 => Ok(Some(data[0])),
_ => Err(Error::BadLength),
}
}
pub fn encode_counter(count: u8) -> [u8; 1] {
[count]
}
#[derive(Debug, Clone, Copy)]
pub struct SyncCounter {
overflow: u8,
value: u8,
}
impl SyncCounter {
pub fn new(overflow: u8) -> Result<Self> {
if !is_valid_counter_overflow(overflow) {
return Err(Error::InvalidSyncCounter);
}
Ok(Self { overflow, value: 0 })
}
pub const fn is_counting(&self) -> bool {
self.overflow >= 2
}
pub fn advance(&mut self) -> Option<u8> {
if !self.is_counting() {
return None;
}
self.value = if self.value >= self.overflow {
1
} else {
self.value + 1
};
Some(self.value)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cob_id_is_default() {
assert_eq!(SYNC_COB_ID, 0x080);
}
#[test]
fn counter_overflow_validation() {
assert!(is_valid_counter_overflow(0));
assert!(!is_valid_counter_overflow(1)); assert!(is_valid_counter_overflow(2));
assert!(is_valid_counter_overflow(240));
assert!(!is_valid_counter_overflow(241));
}
#[test]
fn decode_empty_and_counting_frames() {
assert_eq!(decode(&[]).unwrap(), None);
assert_eq!(decode(&[7]).unwrap(), Some(7));
assert_eq!(decode(&[1, 2]), Err(Error::BadLength));
}
#[test]
fn encode_counter_frame() {
assert_eq!(encode_counter(5), [5]);
}
#[test]
fn counter_disabled_yields_none() {
let mut c = SyncCounter::new(0).unwrap();
assert!(!c.is_counting());
assert_eq!(c.advance(), None);
}
#[test]
fn counter_cycles_and_wraps() {
let mut c = SyncCounter::new(3).unwrap();
assert_eq!(c.advance(), Some(1));
assert_eq!(c.advance(), Some(2));
assert_eq!(c.advance(), Some(3));
assert_eq!(c.advance(), Some(1)); }
#[test]
fn new_rejects_reserved_overflow() {
assert_eq!(SyncCounter::new(1).err(), Some(Error::InvalidSyncCounter));
assert_eq!(SyncCounter::new(241).err(), Some(Error::InvalidSyncCounter));
}
}