use crate::{Error, Result};
pub const TIME_COB_ID: u16 = 0x100;
pub const MS_PER_DAY: u32 = 86_400_000;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TimeOfDay {
pub milliseconds: u32,
pub days: u16,
}
impl TimeOfDay {
pub const fn new(milliseconds: u32, days: u16) -> Self {
Self { milliseconds, days }
}
pub fn encode(&self) -> [u8; 6] {
let ms = self.milliseconds & 0x0FFF_FFFF;
let mut frame = [0u8; 6];
frame[0..4].copy_from_slice(&ms.to_le_bytes());
frame[4..6].copy_from_slice(&self.days.to_le_bytes());
frame
}
pub fn decode(data: &[u8]) -> Result<Self> {
if data.len() < 6 {
return Err(Error::BadLength);
}
Ok(Self {
milliseconds: u32::from_le_bytes([data[0], data[1], data[2], data[3]]) & 0x0FFF_FFFF,
days: u16::from_le_bytes([data[4], data[5]]),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cob_id_is_default() {
assert_eq!(TIME_COB_ID, 0x100);
}
#[test]
fn encode_decode_roundtrips() {
let t = TimeOfDay::new(45_000_000, 15_600); assert_eq!(TimeOfDay::decode(&t.encode()).unwrap(), t);
}
#[test]
fn masks_reserved_millisecond_bits() {
let t = TimeOfDay::new(0xF000_0001, 1);
assert_eq!(t.encode()[..4], [0x01, 0x00, 0x00, 0x00]);
assert_eq!(TimeOfDay::decode(&t.encode()).unwrap().milliseconds, 1);
}
#[test]
fn decode_rejects_short_frame() {
assert_eq!(TimeOfDay::decode(&[0; 5]), Err(Error::BadLength));
}
}