I'm sending and receiving raw binary data via the serial port, so I have a predefined message stored in a u8
vector. I need to calculate the 16bit CRC and append that onto the end before sending it, however I keep running into issues with casting and integer overflows. This is how I have previously done the calculation in C:
void Serial::AddCRC(void *data, int len, void *checksum)
{
uint8_t *dataPtr = (uint8_t *)data;
uint8_t *crcPtr = (uint8_t *)checksum;
uint16_t crc = 0x0;
unsigned char x;
int byteCount = 0;
while ((len--) > 0) {
x = (unsigned char)(crc >> 8 ^ dataPtr[byteCount++]);
x ^= (unsigned char)(x >> 4);
crc = (uint16_t)((crc << 8) ^ (x << 12) ^ (x << 5) ^ x);
}
crcPtr[0] = crc >> 8;
crcPtr[1] = crc &0x00ff;
}
I tried to do something similar in rust, but first ran into some borrow checker issues, so I tried to simplify it and just write a function to calculate the crc and return the u16
result, without needing to mutate the vector:
#[allow(overflowing_literals)]
pub fn checksum(msg: &Vec<u8>) -> u16{
if msg.len() == 0 {return 0}
let crc: u16 = 0x0;
let x: u16;
for byte in msg.iter() {
x = crc >> 8 ^ byte;
x ^= x >> 4;
crc = (crc << 8) ^ (x << 12) ^ (x << 5) ^ x;
}
crc
}
however I can't find a way to make this work. The code posted above fails to compile because I can't perform a bitwise xor between a u8
and a u16
, however the data is treated as u8
s because its raw bytes, so that can't change. I could add the mut
to the vector and make it mutable then cast to a u16
but that seems like a risky way of doing it, and I shouldn't need to mutate the vector to calculate the checksum:
error[E0308]: mismatched types
--> vips_interface/src\beacon_comms.rs:14:24
|
14 | x = crc >> 8 ^ byte;
| ^^^^ expected `u16`, found `u8`
error[E0277]: no implementation for `u16 ^ &u8`
--> vips_interface/src\beacon_comms.rs:14:22
|
14 | x = crc >> 8 ^ byte;
| ^ no implementation for `u16 ^ &u8`
What is the best way of implementing a similar function in rust? The rust compiler is great for catching integer type overflows, but unfortunately that's a key part of how the CRC works, hence why I allowed the overflowing literals, but this didn't seem to fix it. I had a look at some of the crates that mentioned CRC calculations but none of them offered what I wanted, plus its a fairly simple calculation so I'd rather use this as a learning exercise.