use crate::constants::PAYLOAD_SIZE_IN_BYTES;
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Header<const N: u8>;
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Data {
buf: [u8; 36],
idx: u8,
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Complete {
pub buf: [u8; 36],
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct StateMachine<S> {
state: S,
}
impl StateMachine<Header<0x55>> {
fn new() -> Self {
Self {
state: Header::<0x55>,
}
}
}
impl From<StateMachine<Header<0x55>>> for StateMachine<Header<0xAA>> {
fn from(_a: StateMachine<Header<0x55>>) -> Self {
Self {
state: Header::<0xAA>,
}
}
}
impl From<StateMachine<Header<0xAA>>> for StateMachine<Header<0x03>> {
fn from(_a: StateMachine<Header<0xAA>>) -> Self {
Self {
state: Header::<0x03>,
}
}
}
impl From<StateMachine<Header<0x03>>> for StateMachine<Header<0x08>> {
fn from(_a: StateMachine<Header<0x03>>) -> Self {
Self {
state: Header::<0x08>,
}
}
}
impl From<StateMachine<Header<0x08>>> for StateMachine<Data> {
fn from(_: StateMachine<Header<0x08>>) -> Self {
let mut buf = [0u8; PAYLOAD_SIZE_IN_BYTES];
buf[0..4].copy_from_slice(&[0x55, 0xAA, 0x03, 0x08]);
Self {
state: Data { buf, idx: 4 },
}
}
}
impl StateMachine<Data> {
pub fn push(mut self, byte: u8) -> Result<Self, StateMachine<Complete>> {
self.state.buf[self.state.idx as usize] = byte;
self.state.idx += 1;
if self.state.idx == PAYLOAD_SIZE_IN_BYTES as u8 {
Err(StateMachine {
state: Complete {
buf: self.state.buf,
},
})
} else {
Ok(self)
}
}
}
impl StateMachine<Complete> {
pub fn buf(&self) -> &[u8; PAYLOAD_SIZE_IN_BYTES] {
&self.state.buf
}
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum StateMachineWrapper {
Header55(StateMachine<Header<0x55>>),
HeaderAA(StateMachine<Header<0xAA>>),
Header03(StateMachine<Header<0x03>>),
Header08(StateMachine<Header<0x08>>),
Data(StateMachine<Data>),
Complete(StateMachine<Complete>),
}
impl StateMachineWrapper {
pub fn new() -> Self {
Self::Header55(StateMachine::new())
}
pub fn reset(&mut self) {
*self = Self::new();
}
pub fn step(self, value: u8) -> Self {
match self {
Self::Header55(state) if value == 0xAA => Self::HeaderAA(state.into()),
Self::HeaderAA(state) if value == 0x03 => Self::Header03(state.into()),
Self::Header03(state) if value == 0x08 => Self::Header08(state.into()),
Self::Header08(s) => {
let data_sm: StateMachine<Data> = s.into();
match data_sm.push(value) {
Ok(d) => Self::Data(d),
Err(c) => Self::Complete(c),
}
}
Self::Data(s) => match s.push(value) {
Ok(d) => Self::Data(d),
Err(c) => Self::Complete(c),
},
_ => Self::Header55(StateMachine::new()),
}
}
pub fn take_buffer(&self) -> Option<&[u8; PAYLOAD_SIZE_IN_BYTES]> {
if let Self::Complete(s) = self {
Some(s.buf())
} else {
None
}
}
}