15
votes

I am trying to integrate a Serial-port device into my application, which needs CRC-CCTT validation for the bytes that I send to it. I'm kinda new into managing byte packets, and need help for this.

It uses this formula for making the CRC calculus:

[CRC-CCITT P(X)= X16 + C12 + C8 + 1]

So for example for the packet: 0xFC 0x05 0x11, the CRC is 0x5627. Then I send this packet to the device: 0xFC 0x05 0x11 0x27 0x56

Also, packet lenghts will vary from 5 to 255 (including CRC checks bytes)

I don't know how to implement this, so any idea/suggestions will be welcome.

Hope I made myself clear, Thanks in Advance.

EDIT: here is the specification of what I need to do:

enter image description here

5

5 Answers

23
votes

standard crc-ccitt is x16 + x12 + x5 + 1 I wrote the one @ http://www.sanity-free.com/133/crc_16_ccitt_in_csharp.html If I have time I'll see if I can't modify it to run with the x16 + x12 + x8 + 1 poly.

EDIT:

here you go:

public class Crc16CcittKermit {
    private static ushort[] table = {
      0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
      0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
      0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
      0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
      0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
      0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
      0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
      0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
      0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
      0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
      0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
      0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
      0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
      0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
      0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
      0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
      0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
      0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
      0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
      0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
      0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
      0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
      0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
      0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
      0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
      0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
      0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
      0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
      0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
      0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
      0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
      0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
    };

    public static ushort ComputeChecksum( params byte[] buffer ) {
        if ( buffer == null ) throw new ArgumentNullException( );
        ushort crc = 0;
        for ( int i = 0; i < buffer.Length; ++i ) {
            crc = (ushort)( ( crc >> 8 ) ^ table[( crc ^ buffer[i] ) & 0xff] );
        }
        return crc;
    }

    public static byte[] ComputeChecksumBytes( params byte[] buffer ) {
        return BitConverter.GetBytes( ComputeChecksum( buffer ) );
    }
}

sample:

ushort crc = Crc16CcittKermit.ComputeChecksum( 0xFC, 0x05, 0x11 );
byte[] crcBuffer = Crc16CcittKermit.ComputeChecksumBytes( 0xFC, 0x05, 0x11 )
// crc = 0x5627
// crcBuffer = { 0x27, 0x56 }
2
votes

LOL, I've encountered exactly the same STATUS REQUEST sequense, i'm currently developing software to use with CashCode Bill Validator:). Here's the code worked for me, it's CRC16-CCITT with reversed polynomial equals 0x8408 (BDPConstants.Polynomial in the code). That's the code worked for me:

    // TableCRC16Size is 256 of course, don't forget to set in somewhere
    protected ushort[] TableCRC16 = new ushort[BDPConstants.TableCRC16Size];
    protected void InitCRC16Table()
    {
        for (ushort i = 0; i < BDPConstants.TableCRC16Size; ++i)
        {
            ushort CRC = 0;
            ushort c = i;
            for (int j = 0; j < 8; ++j)
            {
                if (((CRC ^ c) & 0x0001) > 0)
                    CRC = (ushort)((CRC >> 1) ^ BDPConstants.Polynominal);
                else
                    CRC = (ushort)(CRC >> 1);
                c = (ushort)(c >> 1);
            }
            TableCRC16[i] = CRC;
        }
    }

    protected ushort CalcCRC16(byte[] aData)
    {
        ushort CRC = 0;
        for (int i = 0; i < aData.Length; ++i)
            CRC = (ushort)(TableCRC16[(CRC ^ aData[i]) & 0xFF] ^ (CRC >> 8));
        return CRC;
    }

Initialize the table somewhere (e.g. Form constructor):

InitCRC16Table();

then use it in your code just like that,

You can use List of bytes instead of array, more convinient to pack byte data in the 'packet' for sending

uint CRC = CalcCRC16(byte[] aByte)
// You need to split your CRC in two bytes of course
byte CRCHW = (byte)((CRC) / 256); // that's your 0x56
byte CRCLW = (byte)(CRC);         // that's your 0x27
2
votes

it works and dose not need table:

    /// <summary>
    /// Gens the CRC16.
    /// CRC-1021 = X(16)+x(12)+x(5)+1
    /// </summary>
    /// <param name="c">The c.</param>
    /// <param name="nByte">The n byte.</param>
    /// <returns>System.Byte[][].</returns>
    public ushort GenCrc16(byte[] c, int nByte)
    {
        ushort Polynominal = 0x1021;
        ushort InitValue = 0x0;

        ushort i, j, index = 0;
        ushort CRC = InitValue;
        ushort Remainder, tmp, short_c;
        for (i = 0; i < nByte; i++)
        {
            short_c = (ushort)(0x00ff & (ushort) c[index]);
            tmp = (ushort)((CRC >> 8) ^ short_c);
            Remainder = (ushort)(tmp << 8);
            for (j = 0; j < 8; j++)
            {

                if ((Remainder & 0x8000) != 0)
                {
                    Remainder = (ushort)((Remainder << 1) ^ Polynominal);
                }
                else
                {
                    Remainder = (ushort)(Remainder << 1);
                }
            }
            CRC = (ushort)((CRC << 8) ^ Remainder);
            index++;
        }
        return CRC;
    }
2
votes

You are actually using CRC-XMODEM LSB-reverse (with 0x8408 coefficient). C# code for this calculus is:

public void crc_bytes(int[] int_input)
{    
   int_array = int_input;
   int int_crc = 0x0; // or 0xFFFF;

   int int_lsb;
   for (int int_i = 0; int_i < int_array.Length; int_i++)
   {
      int_crc = int_crc ^ int_array[int_i];
      for (int int_j = 0; int_j < 8; int_j ++ )
      {
         int_lsb = int_crc & 0x0001; // Mask of LSB
         int_crc = int_crc >> 1;
         int_crc = int_crc & 0x7FFF;
         if (int_lsb == 1)
            int_crc = int_crc ^ 0x8408;
      }
   }

   int_crc_byte_a = int_crc & 0x00FF;
   int_crc_byte_b = (int_crc >> 8) & 0x00FF;
}

Read more (or download project):

http://www.cirvirlab.com/index.php/c-sharp-code-examples/141-c-sharp-crc-computation.html