So I ran into a bit of a challenge. With a bad read I sometimes see a boat load of zeros. Its not a problem if I reject the read but taking a CRC over zeros with a zero CRC passes! I'm temped to look at the raw CRC bytes to check for zero and reject on that before taking the real CRC. I added 2 test cases to the sample code.
// Calculates the 16 bit CRC value of the byte buffer
// Note: Some algorithms require a bit wise reversal of the returned CRC to match
unsigned int crc16(unsigned char *bytes, int len)
{
unsigned int crc = 0x0; // initial value
int polynomial = 0x1021;
for (int idx=0; idx<len; idx++)
{
char b = bytes[idx];
for (int i = 0; i < 8; i++)
{
boolean bit = ((b >> (7 - i) & 1) == 1);
boolean c15 = ((crc >> 15 & 1) == 1);
crc <<= 1;
if (c15 ^ bit)
crc ^= polynomial;
}
}
crc &= 0xffff;
return crc;
}
void setup()
{
Serial.begin(9600);
// Test all zeros
unsigned char data_zero[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
unsigned int z = crc16(data_zero, 10);
Serial.print("Z: ");
Serial.println(z, HEX);
unsigned char data_zero1[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
unsigned z1 = crc16(data_zero1, 8);
Serial.print("Z1: ");
Serial.println(z1, HEX);
unsigned char datay[8] = { 19, 130, 28, 40, 90, 111, 0, 1 };
// datay with CRC on the end
unsigned char datay_crc[10] = { 19, 130, 28, 40, 90, 111, 0, 1, 0x9F, 0xCE };
// Should return 0x9FCE
unsigned int y = crc16(datay, 8);
Serial.print("Y: ");
Serial.println(y, HEX);
// do a CRC over 8 data bytes and 2 CRC bytes
unsigned int x = crc16(datay_crc, 10);
Serial.print("X: ");
Serial.println(x, HEX);
// So in the actual code, the "real" way to code it would be:
if(crc16(datay_crc, 10))
{
// A CRC over data+CRC must return zero for success.
// This has returned non-zero and has failed.
Serial.println("CRC FAILED!");
// Code to handle CRC failure
// Usually you would try reading the tag again
// or return an error
}
else
{
Serial.println("CRC MATCHED");
// Handle CRC success - decode the data
}
}
void loop()
{
delay(250);
}