use bytes::BufMut;
const CRC_TABLE: [u16; 256] = {
let mut table = [0u16; 256];
let mut i = 0;
while i < 256 {
let mut crc = i as u16;
let mut j = 0;
while j < 8 {
if crc & 0x0001 != 0 {
crc = (crc >> 1) ^ 0xA001;
} else {
crc >>= 1;
}
j += 1;
}
table[i] = crc;
i += 1;
}
table
};
#[inline]
pub fn calculate_crc(data: &[u8]) -> u16 {
let mut crc = 0xFFFFu16;
for &byte in data {
let idx = ((crc as u8) ^ byte) as usize;
crc = (crc >> 8) ^ CRC_TABLE[idx];
}
crc
}
#[inline]
pub fn encode_rtu_frame(data: &[u8], buf: &mut bytes::BytesMut) {
let crc = calculate_crc(data);
buf.reserve(data.len() + 2);
buf.put_slice(data);
buf.put_u16_le(crc);
}
const ASCII_START: u8 = b':';
const CR: u8 = b'\r';
const LF: u8 = b'\n';
#[inline]
pub fn calculate_lrc(data: &[u8]) -> u8 {
let sum: u8 = data.iter().fold(0u8, |acc, &b| acc.wrapping_add(b));
sum.wrapping_neg()
}
#[inline]
fn hex_encode_byte(byte: u8) -> [u8; 2] {
const HEX: &[u8; 16] = b"0123456789ABCDEF";
[HEX[(byte >> 4) as usize], HEX[(byte & 0x0F) as usize]]
}
pub fn encode_ascii_frame_into(data: &[u8], buf: &mut impl BufMut) {
let lrc = calculate_lrc(data);
buf.put_u8(ASCII_START);
for &byte in data {
buf.put_slice(&hex_encode_byte(byte));
}
buf.put_slice(&hex_encode_byte(lrc));
buf.put_u8(CR);
buf.put_u8(LF);
}
pub fn encode_ascii_frame(data: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(1 + (data.len() + 1) * 2 + 2);
encode_ascii_frame_into(data, &mut out);
out
}