Bootstrap DD3 Rust port workspace with host-first compatibility tests
This commit is contained in:
76
crates/dd3_protocol/src/frame.rs
Normal file
76
crates/dd3_protocol/src/frame.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
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,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user