Remove application-layer CRC from SRAM mailbox protocol

ISO15693 already provides CRC-16 at the transport layer, making
the application-layer CRC redundant. Simplifies header from 6 to
4 bytes, removes crc16_continue/verify_crc, and drops STATUS_BAD_CRC.
Also updates design doc and fixes markdown table formatting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
michael
2026-03-05 17:40:56 -08:00
parent 43cda8ac3d
commit f437e4e281
4 changed files with 45 additions and 101 deletions

View File

@@ -29,16 +29,15 @@ pub const RESPONSE_MARKER: u8 = 0xFF;
// Status codes
pub const STATUS_OK: u8 = 0x00;
pub const STATUS_BAD_CRC: u8 = 0x01;
pub const STATUS_BAD_CMD: u8 = 0x02;
pub const STATUS_EEPROM_FAIL: u8 = 0x03;
pub const STATUS_INVALID_INDEX: u8 = 0x04;
/// Command header size (cmd + seq + payload_len_u16 + crc_u16).
pub const CMD_HEADER_SIZE: usize = 6;
/// Command header size (cmd + seq + payload_len_u16).
pub const CMD_HEADER_SIZE: usize = 4;
/// Response header size (marker + seq + status + payload_len + crc_u16).
pub const RSP_HEADER_SIZE: usize = 6;
/// Response header size (marker + seq + status + payload_len).
pub const RSP_HEADER_SIZE: usize = 4;
// ---------------------------------------------------------------------------
// Mailbox state
@@ -73,34 +72,11 @@ impl MailboxState {
}
}
// ---------------------------------------------------------------------------
// CRC helpers
// ---------------------------------------------------------------------------
/// Compute CRC-16/CCITT-FALSE over the given data, starting from an
/// initial CRC value. This allows continuing a CRC computation across
/// multiple buffers.
fn crc16_continue(init: u16, data: &[u8]) -> u16 {
let mut crc = init;
for &b in data {
crc ^= (b as u16) << 8;
for _ in 0..8 {
if crc & 0x8000 != 0 {
crc = (crc << 1) ^ 0x1021;
} else {
crc <<= 1;
}
crc &= 0xFFFF;
}
}
crc
}
// ---------------------------------------------------------------------------
// Protocol parse / build
// ---------------------------------------------------------------------------
/// Parse the 6-byte command header. Returns (cmd, seq, payload_len) or None
/// Parse the 4-byte command header. Returns (cmd, seq, payload_len) or None
/// if the buffer is too short or the command ID is out of range.
fn parse_header(buf: &[u8]) -> Option<(u8, u8, u16)> {
if buf.len() < CMD_HEADER_SIZE {
@@ -115,20 +91,6 @@ fn parse_header(buf: &[u8]) -> Option<(u8, u8, u16)> {
Some((cmd, seq, payload_len))
}
/// Verify CRC over the command packet.
/// CRC is computed over bytes 0-3 (header minus CRC) + payload, then
/// compared to the big-endian CRC in bytes 4-5.
fn verify_crc(buf: &[u8], payload_len: u16) -> bool {
let total = CMD_HEADER_SIZE + payload_len as usize;
if buf.len() < total {
return false;
}
let expected = ((buf[4] as u16) << 8) | buf[5] as u16;
let crc = crc16_continue(0xFFFF, &buf[0..4]);
let crc = crc16_continue(crc, &buf[CMD_HEADER_SIZE..total]);
crc == expected
}
/// Build a response packet into `buf`. Returns the total number of bytes
/// written (padded to a multiple of 4 for SRAM block alignment).
fn build_response(buf: &mut [u8], seq: u8, status: u8, payload: &[u8]) -> usize {
@@ -137,18 +99,10 @@ fn build_response(buf: &mut [u8], seq: u8, status: u8, payload: &[u8]) -> usize
buf[1] = seq;
buf[2] = status;
buf[3] = plen as u8;
// CRC placeholder at [4..6], computed below
// Copy payload
buf[RSP_HEADER_SIZE..RSP_HEADER_SIZE + plen].copy_from_slice(payload);
// Compute CRC over bytes 0-3 + payload
let crc = crc16_continue(0xFFFF, &buf[0..4]);
let crc = crc16_continue(crc, payload);
buf[4] = (crc >> 8) as u8;
buf[5] = crc as u8;
// Pad total length to multiple of 4
let raw_len = RSP_HEADER_SIZE + plen;
let padded = (raw_len + 3) & !3;
// Zero padding bytes
for b in buf[raw_len..padded].iter_mut() {
*b = 0;
}
@@ -522,15 +476,6 @@ where
return Ok(false);
}
// Verify CRC
if !verify_crc(&sram, payload_len) {
// Write BAD_CRC response
let mut rsp = [0u8; SRAM_SIZE];
let len = build_response(&mut rsp, seq, STATUS_BAD_CRC, &[]);
ntag.write_sram_blocks(0, &rsp[..len])?;
return Ok(true);
}
let payload = &sram[CMD_HEADER_SIZE..total];
// Dispatch