use alloc::vec::Vec; use crate::crc16_ccitt; #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum MsgKind { BatchUp = 0, AckDown = 1, } impl MsgKind { pub fn from_u8(value: u8) -> Option { match value { 0 => Some(Self::BatchUp), 1 => Some(Self::AckDown), _ => None, } } pub fn as_u8(self) -> u8 { self as u8 } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct Frame { pub msg_kind: MsgKind, pub short_id: u16, pub payload: Vec, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum FrameDecodeError { LengthMismatch, CrcFail, InvalidMsgKind, } pub fn encode_frame(msg_kind: MsgKind, short_id: u16, payload: &[u8]) -> Vec { let mut out = Vec::with_capacity(payload.len() + 5); out.push(msg_kind.as_u8()); out.extend_from_slice(&short_id.to_be_bytes()); out.extend_from_slice(payload); let crc = crc16_ccitt(&out); out.extend_from_slice(&crc.to_be_bytes()); out } pub fn decode_frame(frame: &[u8], max_msg_kind: u8) -> Result { if frame.len() < 5 { return Err(FrameDecodeError::LengthMismatch); } let payload_len = frame.len() - 5; let crc_calc = crc16_ccitt(&frame[..frame.len() - 2]); let crc_rx = u16::from_be_bytes([frame[frame.len() - 2], frame[frame.len() - 1]]); if crc_calc != crc_rx { return Err(FrameDecodeError::CrcFail); } let raw_kind = frame[0]; if raw_kind > max_msg_kind { return Err(FrameDecodeError::InvalidMsgKind); } let msg_kind = MsgKind::from_u8(raw_kind).ok_or(FrameDecodeError::InvalidMsgKind)?; let short_id = u16::from_be_bytes([frame[1], frame[2]]); let payload = frame[3..3 + payload_len].to_vec(); Ok(Frame { msg_kind, short_id, payload, }) }