Files
DD3-LoRa-Bridge-MultiSender…/crates/dd3_protocol/src/frame.rs

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,
})
}