Question

Based Online CRC calculation, when I entered hex string data =

503002080000024400003886030400000000010100

I get result CRC-CCITT (0xFFFF) =

0x354E (Expected Result)

.

I use the code below, but the results of CalcCRC16() are 0xACEE. What the lack of script below?

using System;
using System.Windows.Forms;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using System.Diagnostics;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {

        public Form1() {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e) {
            string result = CalcCRC16("503002080000024400003886030400000000010100");            
            Debug.Print(result);
            // result = ACEE
            // result expected = 354E
        }

        // CRC-CCITT (0xFFFF) with poly 0x1021
        // input (hex string) =  "503002080000024400003886030400000000010100"
        // result expected (hex string) = "354E"
        public string CalcCRC16(string strInput) {
            ushort temp = 0;
            ushort crc = 0xFFFF;
            byte[] bytes = GetBytesFromHexString(strInput);
            for (int j = 0; j < bytes.Length; j++) {
                crc = (ushort)(crc ^ bytes[j]);
                for (int i = 0; i < 8; i++) {
                    if ((crc & 0x0001) == 1)
                        crc = (ushort)((crc >> 1) ^ 0x1021);
                    else
                        crc >>= 1;
                }
            }
            crc = (ushort)~(uint)crc;
            temp = crc;
            crc = (ushort)((crc << 8) | (temp >> 8 & 0xFF));
            return crc.ToString("X4");
        }

        public Byte[] GetBytesFromHexString(string strInput) {
            Byte[] bytArOutput = new Byte[] { };
            if (!string.IsNullOrEmpty(strInput) && strInput.Length % 2 == 0) {
                SoapHexBinary hexBinary = null;
                try {
                    hexBinary = SoapHexBinary.Parse(strInput);
                    if (hexBinary != null)
                        bytArOutput = hexBinary.Value;
                }
                catch (Exception ex) {
                    MessageBox.Show(ex.Message);
                }
            }
            return bytArOutput;
        }

    }
}
Was it helpful?

Solution

I found the answer and I will share here.. may be useful to others.

strInput = 503002080000024400003886030400000000010100

initial = 0xFFFF

poly = 0x1021

strOutput = 354E

reference = Online CRC Calc

public string CalcCRC16(string strInput) {
    ushort crc = 0xFFFF;
    byte[] data = GetBytesFromHexString(strInput);
    for (int i = 0; i < data.Length; i++) {
        crc ^= (ushort)(data[i] << 8);
        for (int j = 0; j < 8; j++) {
            if ((crc & 0x8000) > 0)
                crc = (ushort)((crc << 1) ^ 0x1021);
            else
                crc <<= 1;
        }
    }
    return crc.ToString("X4");
}

public Byte[] GetBytesFromHexString(string strInput) {
    Byte[] bytArOutput = new Byte[] { };
    if (!string.IsNullOrEmpty(strInput) && strInput.Length % 2 == 0) {
        SoapHexBinary hexBinary = null;
        try {
            hexBinary = SoapHexBinary.Parse(strInput);
            if (hexBinary != null) {
                bytArOutput = hexBinary.Value;
            }
        }
        catch (Exception ex) {
            MessageBox.Show(ex.Message);
        }
    }
    return bytArOutput;
}

OTHER TIPS

Here's an example which works in my application. I struggled somewhat, now I know its because I had to use char ptrs in stead of 16bit int pointers (because CCIT is LSB order first, so we pick 1 byte from the buffer, shift it 8 times to make it 16bit to validate the upper MSB bit 0x8000).

Most causes found when people struggle with 16bit CRC (while 8bit most of the time works):

  • Buffer should be called by 8bit ptr
  • Shifting BEFORE the XOR!
  • Never use int or unsigned int.. but use short! My application runs on 16 and 32bit Microchip PIC's and using ints results in 16bit values on the 16bit pic and 32bit values (so lot of zeros!) on 32bit platforms.

BOOL = unsigned char. UINT16 = unsigned short. The function runs in code, so not a while/forloop. When done, the CRC is copied to the address pointed by *crc. This way all ather tasks (M95 modem, MCP's I2C, Flash logs, TCP/IP etc. will be handled without too large delays).

BOOL CRC_16(UINT16 ui16_Bytes, char *src, UINT16 *crc)
{    
    static BOOL bNew = FALSE;
    static UINT16  remainder = 0;   
    static UINT16 i = 0;
    static UINT16 ui16_Loc_bytes;
    static char *ptr;
    static char locData;
    if(!bNew)
    {
    ui16_Loc_bytes = ui16_Bytes;
    ptr = src;
    locData = *ptr;
    i = 8;
    remainder = 0x0000;
    bNew = TRUE;
    }
    if(ui16_Loc_bytes)
    {
    if(i == 8)
    {
        remainder ^= (((UINT16)locData)<<8);                //Only 8bits at a time filled with zeros
    }
    if(i)
    {
        if (remainder & 0x8000)
        {
        remainder = (remainder << 1);
        remainder ^= POLYNOMIAL_16;
        }
        else
        {       
        remainder = (remainder << 1);
        }       
        i--;
    }
    else
    {
        ui16_Loc_bytes--;
        ptr++;
        locData = *ptr;
        //ptr++;
        i = 8;
    }

    }
    else
    {
    bNew = FALSE;
    *crc = remainder;
    return TRUE;
    }
    return FALSE;
}


if(SDKaart.ui16_RecBytes >= SDKaart.ui16_ByteLen)//30-5-2018 edited SDKaart.CMD[SDKaart.ui8_ActiefCMD].ui16_RecLen)
                    {
                    SD_DESELECT;
                    if(SDKaart.bInitReady && SDKaart.b_BlockRead)
                    {
                        if(CRC_16(512,(char*)&SDKaart.Mem_Block.SD_Buffer[0], &SDKaart.ui16_MemBlock_CRC))
                        {                       
                        if((((UINT16)SDKaart.Mem_Block.SD_Buffer[512]<<8)|(UINT16)SDKaart.Mem_Block.SD_Buffer[513]) == SDKaart.ui16_MemBlock_CRC)
                        {
                            SDKaart.bRXReady = TRUE;
                            SDKaart.TXStat = SPI_IDLE;
                            printf("CRC16 OK %x\r\n",SDKaart.ui16_MemBlock_CRC);
                        }
                        else
                        {
                            SDKaart.bRXReady = TRUE;
                            SDKaart.TXStat = SPI_IDLE;
                            printf("CRC16 %u != 0x%x 0x%x\r\n",SDKaart.ui16_MemBlock_CRC,SDKaart.Mem_Block.SD_Buffer[512], SDKaart.Mem_Block.SD_Buffer[513] );
                        }
                        //printf("CRC citt: %u\r\n", Calculate_CRC_CCITT((char *)&SDKaart.Mem_Block.SD_Buffer[0],512));
                        }
                    }
                    else
                    {
                        SDKaart.bRXReady = TRUE;
                        SDKaart.TXStat = SPI_IDLE;
                    }
                    }
                    else
                    {                       
                    if(SD_SPI_TX_READY)
                    {
                        SDKaart.bNewSPIByte = TRUE;
                        SPI1BUF = SD_EMPTY_BYTE;                        
                    }
                }

I have used many crcs found online, but a lottt didn't work. Be aware a lot of online "examples" do use <<1 behind the XOR, but it must be done before xor.

POLY_16 is 0x1021. Next oppurtunity is to build a table picker. :)

Greetz, John

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top