76 lines
1.8 KiB
Rust
76 lines
1.8 KiB
Rust
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<Self> {
|
|
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<u8>,
|
|
}
|
|
|
|
#[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<u8> {
|
|
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<Frame, FrameDecodeError> {
|
|
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,
|
|
})
|
|
} |