const CRC_TABLE: [u16; 256] = compute_crc_table();
const fn compute_crc_table() -> [u16; 256] {
let mut table = [0u16; 256];
let mut i = 0;
while i < 256 {
let mut crc = (i as u16) << 8;
let mut j = 0;
while j < 8 {
if crc & 0x8000 != 0 {
crc = (crc << 1) ^ 0x1021;
} else {
crc <<= 1;
}
j += 1;
}
table[i] = crc;
i += 1;
}
table
}
pub fn crc16_ccitt(data: &[u8]) -> u16 {
let mut crc: u16 = 0;
for &byte in data {
let table_index = ((crc >> 8) ^ (byte as u16)) as usize;
crc = (crc << 8) ^ CRC_TABLE[table_index];
}
crc
}
pub fn validate_block(block_data: &[u8]) -> bool {
if block_data.len() < 8 {
return false;
}
if block_data[0] != 0x24 || block_data[1] != 0x40 {
return false;
}
let stored_crc = u16::from_le_bytes([block_data[2], block_data[3]]);
let length = u16::from_le_bytes([block_data[6], block_data[7]]) as usize;
if block_data.len() < length {
return false;
}
let calculated_crc = crc16_ccitt(&block_data[4..length]);
stored_crc == calculated_crc
}
pub fn calculate_block_crc(id_length_body: &[u8]) -> u16 {
crc16_ccitt(id_length_body)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_crc_empty() {
assert_eq!(crc16_ccitt(&[]), 0);
}
#[test]
fn test_crc_known_value() {
let data = b"123456789";
assert_eq!(crc16_ccitt(data), 0x31C3);
}
#[test]
fn test_crc_table_generation() {
assert_eq!(CRC_TABLE[0], 0x0000);
assert_eq!(CRC_TABLE[1], 0x1021);
assert_eq!(CRC_TABLE[255], 0x1EF0);
}
#[test]
fn test_validate_block_too_short() {
let short_data = [0x24, 0x40, 0x00, 0x00];
assert!(!validate_block(&short_data));
}
#[test]
fn test_validate_block_wrong_sync() {
let bad_sync = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00];
assert!(!validate_block(&bad_sync));
}
}