CRC 32 calculation - arduino / python

Hello folks,

having some trouble generating the right crc on the python side, sending some parameter and struct data via serial to a python program. I tested the struct data and it´s compatible with ctypes giving me the results i expected. Just the crc is bugging me for some day, on the arduino side i tried 2 different methods resulting in the same crc.

const uint32_t Polynomial = 0xEDB88320;

/// compute CRC32
uint32_t crc32_bitwise(const void* data, uint16_t length, uint32_t previousCrc32 = 0)
{
  uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF
  uint8_t* current = (uint8_t*) data;

  while (length--)
  {
    crc ^= *current++;
    for (uint8_t j = 0; j < 8; j++)
    {
      uint8_t lowestBit = crc & 1;
      crc >>= 1;
      if (lowestBit)
        crc ^= Polynomial;
    }
  }
  return ~crc; // same as crc ^ 0xFFFFFFFF
}

and

const uint32_t PROGMEM crc_table[16] = {
  0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
  0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
  0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
  0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};

unsigned long crc_update(unsigned long crc, byte data)
{
  byte tbl_idx;
  tbl_idx = crc ^ (data >> (0 * 4));
  crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f)) ^ (crc >> 4);
  tbl_idx = crc ^ (data >> (1 * 4));
  crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f)) ^ (crc >> 4);
  return crc;
}

unsigned long crc_bytearray(byte *s, unsigned int length)
{
  unsigned long crc = ~0L;
  byte x= 0;
  while (x<length){
    crc = crc_update(crc, *s++);
    x++;
  }  
  crc = ~crc;
  return crc;
}

This is how i send the data:

#define BMS_ID 3
struct BMS
{
  unsigned int cells[13];
  unsigned int bms_total_voltage;
  unsigned int current;  
  unsigned int rsense;
  byte cellreference;  //1.22 for cell type 0/1, for 2/3 0.61
  byte cellcount;
  boolean bms_mode;
};

struct BMS bms;

byte write_struct_serial(uint8_t* struct_ptr, uint8_t struct_length, uint8_t struct_id){
  byte data_out[struct_length + 2];  // msg_length1, struct_id1, struct[], crc4 defined as message
  data_out[0] =  2 + struct_length + 4; // Mesage length
  data_out[1] =  struct_id;
  for(byte i=0; i<struct_length; i++){    
    data_out[i+2] = *(struct_ptr+i);
  }  
  unsigned long crc = crc_string_byte((byte*)data_out, sizeof data_out);
  Serial.write(start);
  Serial.write(data_out, sizeof data_out);
  Serial.write(crc);
  Serial.write(crc>>8);
  Serial.write(crc>>16);
  Serial.write(crc>>24);
}

write_struct_serial((byte*)&bms, sizeof(bms), BMS_ID);

On the python side :

class BMS_Struct(LittleEndianStructure):
     _fields_ = [("cells", c_uint16 * 13),
                 ("total_voltage", c_uint16),
                 ("current", c_uint16),
                 ("rsense", c_uint16),
                 ("cellreference", c_uint8),
                 ("cellcount", c_uint8),
                 ("bms_mode", c_bool)]

ctype_struct = BMS_Struct()
arduino = serial.Serial()

def receive_struct():
  start = 0x85
  detected_start = False
  message_length = 0
  data_in = 0
  crc = 0
  arduino.baudrate = 57600
  arduino.timeout = 0
  arduino.port = 'COM8'
  try:
      arduino.open()
  except serial.SerialException, e:
    print e

  while True:
    if(arduino.inWaiting() > 1 and detected_start == False):
        data = ord(arduino.read())
        if data == start:
          detected_start = True
        else: print data
    elif(arduino.inWaiting() > 1 and detected_start == True and message_length == 0):
      message_length = ord(arduino.read())
      data_in = c_uint8 * message_length
      data_in = data_in()
      data_in[0] = message_length
    elif(arduino.inWaiting() >= message_length-1 and detected_start == True and message_length != 0):
      for index in range(message_length-5):
        data_in[index+1] = ord(arduino.read())

      for index in range(4):
        crc |= (ord(arduino.read())<<(index*8) )
      print "CRC arduino = ",hex(crc), format(crc, '032b')
      crc_python = (binascii.crc32(data_in) & 0xffffffff)
      print "CRC pyhton =  ", hex(crc_python),format(crc_python, '032b')


      test = c_uint8 * (message_length -6)
      test = test()
      for index in range(sizeof(test)):
        test[index] = data_in[index+2]
      memmove(pointer(ctype_struct),pointer(test), len(test))


      detected_start = False
      message_length = 0
      crc = 0

The initial crc seems to be (unsigned long crc = ~0L; / uint32_t crc = ~previousCrc32; resulting in 4294967295) even if i use crc_python = (binascii.crc32( data_in, 4294967295) & 0xffffffff, same with zlib) i am getting wrong results. I used (http://excamera.com/sphinx/article-crc.html) this example for ascii data and i got correct results, only when i use bytearray there seems to be a problem.
What am i missing ?

smithy

I tried the fix from here : http://forum.arduino.cc/index.php/topic,91179.0.html but i get exactly the same result (using 1.05).

Found the solution my bytearray was bigger than it needed to be .. :frowning: