tags:

views:

689

answers:

3
+1  Q: 

CRC Calculation

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.

+1  A: 

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

Dead account
C integers and shift in this case are not affected by endianness.
Diego Sevilla
@Diego, agreed. But the code includes byte reading; "crctbl[pos]"
Dead account
The server and client are both windows computers so it doesn't appear that it would be the endianness.
Jeff
+1  A: 

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... :)

Diego Sevilla
I think you are right that something is either missing or incorrect in the calc_crc algorithm. I am in conact with the vendor right now trying to sort out. I'm thinking the crc should be 470f for the string XYZ, but calc_crc has something wrong with it.
Jeff
Technically, I think the constants should actually both be 0x0fff. They're to ensure that the 4 highest bits are clear after the 4-bit right-shift. But since `crc` is unsigned, and the way the algorithm works, the AND with 0x0fff is redundant.
Craig McQueen
+1  A: 

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.

Jeff
""specs from the vendor were incorrect""... I'm glad I live far far away from you :-)
Dead account