Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CCITT CRC 16 Bit Start Value 0xffff

I need to calculate a CCITT 16 bit checksum value for data passed as a parameter together with the length. If I fill my array TempStr with the test data "123456789", use the polynomial 0x8408 with the length excluding the null termination character, I get the result string 6E90(Hex). Together with the null termination char I get 907A. When I swap out the polynomial to 0x1201 then I get results 29E2(Hex) and EFE8(Hex) with and without termination character.

My questions are: Do I need to calculate the CRC with or without the null termination character to obtain the correct value? Do I use the polynomial 0x1201 or the reverse polynomial 0x8408 in the algorithm? Is the correct CRC of the given data 0x29B1? I need the correct value to determine if the function works correctly.. Is the algorithm to calculate this specific CRC type correct? wData=(unsigned int)0xff & *pData++?? If someone can explain to me what is wrong and how to fix my problem I would much appreciate it. Thank you

This is the code that uses and displays the calculate_CRC16 function:

CHAR_t TestStr[] = {"123456789"};
unsigned short CrcTest = calculate_CRC16(TestStr,sizeof(TestStr)-1);
QString CrcDisplay = QString("CrcTest : %1").arg(CrcTest);
ui->txtDebug->setText(CrcDisplay);

This is the calculate_CRC16 function:

UINT16_t MainWindow::calculate_CRC16(CHAR_t* pData, UINT16_t wLength)
{

  UCHAR_t i;
  UINT16_t wData;
  UINT16_t wCrc = 0xffff;

  if (wLength == 0)
    return (~wCrc);

  do
  {
    for (i=0, wData=(unsigned int)0xff & *pData++; i < 8; i++, wData >>= 1)
    {
        if ((wCrc & 0x0001) ^ (wData & 0x0001))
            wCrc = (wCrc >> 1) ^ CRC_POLY;
        else  wCrc >>= 1;
    }
  } while (--wLength);

  wCrc = ~wCrc;
  wData = wCrc;
  wCrc = (wCrc << 8) | (wData >> 8 & 0xff);

  return (wCrc);
}
like image 400
Ruaan Volschenk Avatar asked Jan 21 '14 07:01

Ruaan Volschenk


People also ask

What is CRC CCITT 16 bit?

The CRC- 16 bits code computes a 16-bit cyclical redundancy check (CRC) algorithm on an input serial data stream. The polynomial can be defined to implement CRC functions, such as the CRC-16 or CCITT algorithm. A seed value can be specified to initialize the starting data value.

How is CRC 16 checksum calculated?

a) run the data bits through the CRC loop starting from the least significant bit instead of from the most significant bit. b) push the last 16 bits of the CRC out of the CRC register after you've finished with the input data. c) reverse the CRC bits (I'm guessing this bit is a carry over from hardware implementations)

How is CRC value calculated?

A CRC is pretty simple; you take a polynomial represented as bits and the data, and divide the polynomial into the data (or you represent the data as a polynomial and do the same thing). The remainder, which is between 0 and the polynomial is the CRC.

What is the polynomial used in CRC CCITT?

The CRC generation code uses the generator polynomial 0x1021 which was chosen as one it is one version of CRC 16-CCITT [1]. The initial value used for the CRC buffer was all zeros. The algorithm then runs through the message byte by byte.


2 Answers

The result of 0x29b1 is for the "false" CCITT CRC-16 (link to CRC catalog). Which is apparently the one you need. From the catalog:

width=16 poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1 name="CRC-16/CCITT-FALSE"

So there is no bit reversal (refin, refout false). The CRC is initialized with 0xffff and is not post-processed.

To fix your code with the least changes:

if (wLength == 0)
    return wCrc;

do
{
    for (i=0, wData=((unsigned int)0xff & *pData++) << 8; i < 8; i++, wData <<= 1)
    {

        if ((wCrc & 0x8000) ^ (wData & 0x8000))
            wCrc = (wCrc << 1) ^ 0x1021;
        else  wCrc <<= 1;
    }
} while (--wLength);

return wCrc & 0xffff;

or to do it more reasonably:

while (wLength--) {
    wCrc ^= *(unsigned char *)pData++ << 8;
    for (i=0; i < 8; i++)
        wCrc = wCrc & 0x8000 ? (wCrc << 1) ^ 0x1021 : wCrc << 1;
}
return wCrc & 0xffff;
like image 141
Mark Adler Avatar answered Sep 26 '22 14:09

Mark Adler


If you have a look at, it will calculate the CRC for different strings (or hex sequences, for checking with or without NUL) http://www.lammertbies.nl/comm/info/crc-calculation.html

According to that, you should NOT calculate including the terminating zero to get the value of 0x29B1 for your calculation.

Since you are starting with the low bit, you should be using the "non-reverse" polynomial.

I think the problem is that you are shifting the wrong way when you are shifting the "wCrc" in your calculation.

In other words:

wCrc = (wCrc >> 1) ^ CRC_POLY;

should be:

wCrc = (wCrc << 1) ^ CRC_POLY;

and likewise:

wCrc >>= 1;

should be:

wCrc <<= 1;

However, I'm not 100% certain.

like image 29
Mats Petersson Avatar answered Sep 23 '22 14:09

Mats Petersson