Problems with CRC16 calculation

jremington:
I think you mean, what your incorrect use of Serial.print shows you.

Perhaps. Well, that's why I'm here. But what I meant here was the reply to the PieterP post, since the "software" does not print leading zeros.

PieterP:
Serial.print(x, HEX) doesn't print leading zeros, so if you do

Serial.print(0x0A, HEX); 

Serial.print(0x0B, HEX);



It'll print "AB" instead of "0A0B".

Pieter

aarg:
I don't see results for crc16.h in your list.

One with "buildin".

It is not a problem that Serial.print omits leading zeros, if you print separators between the bytes.

Maybe I wasn't clear enough: The only problem with your code is the way you're printing your data. If you enter the wrong data (without leading zeros) into the online calculators, you'll get the wrong result.

If I enter the data with leading zeros, I get the correct result: 0xB944

First of all, I made a fatal mistake in my function. Which is the reason why it's loosing the last byte:

This only writes one single byte: Serial.write(CRC::crc16(buf, sizeof(buf))); But I need two.

Using Python I can confirm that it works:

>>> data = bytearray(b'\x9a\xf9y\xc4\x00\x00\x00@\x00\x00@@\x00\x00\x80@I\x0c')
>>> import struct
>>> struct.unpack('f', data[0:4])
(-999.9000244140625,)
>>> struct.unpack('f', data[4:8])
(2.0,)
>>> struct.unpack('f', data[8:12])
(3.0,)
>>> struct.unpack('f', data[12:16])
(4.0,)
>>> import binascii
>>> binascii.hexlify(data[16:18])
b'490c'

This is the final test sketch which works:

#include "FastCRC.h"

FastCRC16 CRC16;

float valueA = -999.9;
float valueB = 2.0;
float valueC = 3.0;
float valueD = 4.0;

void printDataWithCRC(float *data1, float *data2, float *data3, float *data4) {
  byte *byteData1 = (byte *)(data1);
  byte *byteData2 = (byte *)(data2);
  byte *byteData3 = (byte *)(data3);
  byte *byteData4 = (byte *)(data4);
  byte buf[16] = {
    byteData1[0], byteData1[1], byteData1[2], byteData1[3],
    byteData2[0], byteData2[1], byteData2[2], byteData2[3],
    byteData3[0], byteData3[1], byteData3[2], byteData3[3],
    byteData4[0], byteData4[1], byteData4[2], byteData4[3]
  };
  Serial.write(buf, 16);
  uint16_t crc = CRC16.ccitt(buf, sizeof(buf));
  Serial.write((byte) (crc >> 8));
  Serial.write((byte) crc);
}

void setup() {
  delay(100);
  Serial.begin(230400);
}

void loop() {
  printDataWithCRC(&valueA, &valueB, &valueC, &valueD);
  delay(1000);
}

If anyone is interested in trying it out, here is the Python code for debugging:

import serial
import struct
import binascii

serialPort = 'COM3'
serialBaud = 230400
rawData = bytearray(18)
numSensors = 4
dataNumBytes = 4
data = []

ser = serial.Serial(serialPort, serialBaud, timeout=1)

ser.reset_input_buffer()
data = [0 for x in range(numSensors)]

ser.readinto(rawData)
payload = binascii.hexlify(rawData[0:16])
print("Payload:", payload)

crc = binascii.hexlify(rawData[16:18])
print("CRC16:", crc)

print("Values unpacked back:")
for i in range(numSensors):
    bytedata = rawData[(i * dataNumBytes):(dataNumBytes + i * dataNumBytes)]
    data[i], = struct.unpack('f', bytedata)
print(data)

Additionally, if you want to calculate the CRC for comparison, just add these lines below the code I shared in my previous post.

crc16 = crcmod.mkCrcFun(0x11021, rev=False, initCrc=0xFFFF, xorOut=0x0000)
print("Calculated Python CRC16:", hex(crc16(binascii.unhexlify(payload))))

Note: Python "crcmod" uses the complete polynomial. Therefore 0x11021 is the correct one for Python. But FastCRC library uses 0x1021 without the high term.