4
votes

I'm trying to interface with a 3rd party system and they have provided a code sample to calculate a CRC value when sending text data.

The C code the vendor provided looks like this:

#define CRCRES 0xf0b8  /* residue for good verify */ 
#define DEBUG 

unsigned crctbl[] = {0x0000, 0x1081, 0x2102, 0x3183, 
                     0x4204, 0x5285, 0x6306, 0x7387, 
                     0x8408, 0x9489, 0xa50a, 0xb58b, 
                     0xc60c, 0xd68d, 0xe70e, 0xf78f}; 

/* 
 * This uses a 32 byte table to lookup the crc 4 bits at a time. 
 * The CRC CCITT is used. 
 */ 


unsigned short calc_crc(unsigned char *ptr, unsigned length) 

{ 
  unsigned short crc; 
  unsigned short i; 
  unsigned char pos,ch; 

  crc = 0xffff;  /* precondition crc */ 
  for (i = 0; i < length; i++,ptr++) { 
    ch = *ptr; 
    pos = (crc ^ ch) & 15; 
    crc = ((crc >> 4) & 0x0fff) ^ crctbl[pos]; 
    ch >>= 4; 
    pos = (crc^ch) & 15; 
    crc = ((crc >> 4) & 0xffff) ^ crctbl[pos]; 
  } 
  crc = ~crc;  /* post condition */ 
  crc = (crc << 8) | (crc >> 8); /* bytewise reverse */ 
  return crc; 
} 


/* 
 * tests the block of code containing the crc to verify it's 
 * content.  This compares to the reversed and inverted 
 * residue. 
 */ 

int test_crc(unsigned char *ptr, unsigned length) 

{ 
  unsigned short crc; 
  unsigned char arr [] = {'X','Y','Z'}; 

  crc = calc_crc(arr,3); 
  printf("Calced crc of test to be %04x, (should be 470f)\n", crc); 
  return (crc == 0x470f); 
} 

I've copied this code and put in a sample C program. The test_crc method is not calculating the CRC to be 470f (its calculating it as DD7A).

I'm hoping someone can either verify that this code doesn't work as the vendor is saying it should or help me get test_crc to return the correct value.

Thanks for the help.

3
FWIW - I do see the test on "XYZ" producing 0xdd7a, but I don't see either of your other 2 test strings producing the result you talk about (neither produce the same value or the value you mention). You might want to post the test code for those strings, too - Michael Burr
Question edited. The two test strings do not return what I said in the question an do in fact return different results. That was my error. - Jeff
Also, Thanks for verifying for me that XYZ does produce dd7a. At least I know I got that part right. - Jeff
FWIW, I've run this under 64-bit little endian OpenBSD and get the same "incorrect" 0xdd7a results. Can't test on big endian at the moment, but if this is meant to be Windows-only then endianness isn't an issue. - dwc
Endianess should not be an issue - there are not any byte accesses to data elements larger than a byte (that I can see, anyway). - Michael Burr

3 Answers

4
votes

Problem solved. The specs from the vendor were incorrect. The correct checksum for XYZ is DD7A. The documentation was incorrect.

Add that to the fact that on the page before when they explain what data to pass to the calc_crc method to get the crc for an actual message is also incorrect it made it a tricky project.

Thanks for the help.

3
votes

The calculation, as it goes, don't show any error that comes to my mind. Just review again the algorithm. In particular, looking for possible problems, note that constants being anded in different parts of the algorithm are 0x0fff and 0xffff. Maybe should it be 0x0fff and 0xfff0 to be more symmetric... Sometimes we think the real problem may come from another place, and forget to double check the obvious things... :)

2
votes

Are the hardware platforms the same? Could it be you have different endianness? (You have x86 they have 68000 cpu for example.)