use crate::codes::StatusCode;
use crate::error::ProtocolError;
const HEADER: u8 = 0xFF;
const MAX_DATA_LEN: usize = 255;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReaderFrame {
pub command: u8,
pub status_raw: u16,
pub status: Option<StatusCode>,
pub data: Vec<u8>,
}
pub fn parse_reader_frame(packet: &[u8]) -> Result<ReaderFrame, ProtocolError> {
if packet.len() < 7 {
return Err(ProtocolError::PacketTooShort);
}
if packet[0] != HEADER {
return Err(ProtocolError::InvalidHeader(packet[0]));
}
let declared_len = packet[1] as usize;
let expected_total = 1 + 1 + 1 + 2 + declared_len + 2;
if packet.len() != expected_total {
return Err(ProtocolError::LengthMismatch {
declared: declared_len,
actual: packet.len().saturating_sub(7),
});
}
let crc_actual = u16::from_be_bytes([packet[packet.len() - 2], packet[packet.len() - 1]]);
let crc_expected = protocol_crc16(&packet[..packet.len() - 2]);
if crc_actual != crc_expected {
return Err(ProtocolError::InvalidCrc {
expected: crc_expected,
actual: crc_actual,
});
}
let command = packet[2];
let status_raw = u16::from_be_bytes([packet[3], packet[4]]);
let data_start = 5;
let data_end = data_start + declared_len;
let data = packet[data_start..data_end].to_vec();
Ok(ReaderFrame {
command,
status_raw,
status: StatusCode::from_u16(status_raw),
data,
})
}
pub fn build_host_frame(command: u8, data: &[u8]) -> Result<Vec<u8>, ProtocolError> {
if data.len() > MAX_DATA_LEN {
return Err(ProtocolError::DataTooLong(data.len()));
}
let mut out = Vec::with_capacity(1 + 1 + 1 + data.len() + 2);
out.push(HEADER);
out.push(data.len() as u8);
out.push(command);
out.extend_from_slice(data);
let crc = protocol_crc16(&out);
out.extend_from_slice(&crc.to_be_bytes());
Ok(out)
}
pub fn protocol_crc16(data: &[u8]) -> u16 {
let mut crc: u16 = 0xFFFF;
for byte in data.iter().skip(1) {
let mut mask: u8 = 0x80;
for _ in 0..8 {
let xor_flag = (crc & 0x8000) != 0;
crc <<= 1;
if (*byte & mask) != 0 {
crc |= 0x0001;
}
if xor_flag {
crc ^= 0x1021;
}
mask >>= 1;
}
}
crc
}
pub(crate) fn push_u16_be(buf: &mut Vec<u8>, v: u16) {
buf.extend_from_slice(&v.to_be_bytes());
}
pub(crate) fn push_u32_be(buf: &mut Vec<u8>, v: u32) {
buf.extend_from_slice(&v.to_be_bytes());
}