Search code examples
c#crc16

How to Implement CRC-16-DNP using C#?


I'm trying to implement a 16-CRC [DNP] using c#, the generator polynomial is given as

enter image description here

I found a standard solution for 16-crc : [ Source ]

public class Crc16
{
    const ushort polynomial = 0xA001;
    ushort[] table = new ushort[256];

    public ushort ComputeChecksum ( byte[] bytes )
    {
        ushort crc = 0;
        for ( int i = 0; i < bytes.Length; ++i )
        {
            byte index = ( byte ) ( crc ^ bytes[i] );
            crc = ( ushort ) ( ( crc >> 8 ) ^ table[index] );
        }
        return crc;
    }

    public byte[] ComputeChecksumBytes ( byte[] bytes )
    {
        ushort crc = ComputeChecksum ( bytes );
        return BitConverter.GetBytes ( crc );
    }

    public Crc16 ()
    {
        ushort value;
        ushort temp;
        for ( ushort i = 0; i < table.Length; ++i )
        {
            value = 0;
            temp = i;
            for ( byte j = 0; j < 8; ++j )
            {
                if ( ( ( value ^ temp ) & 0x0001 ) != 0 )
                {
                    value = ( ushort ) ( ( value >> 1 ) ^ polynomial );
                }
                else
                {
                    value >>= 1;
                }
                temp >>= 1;
            }
            table[i] = value;
        }
    }
}

Now, If I convert my polynomial I get 1 0011 1101 0110 0111 => (3D65)h & my question is what do I need to change to work the above solution for the given polynomial.

Edit: I also need to consider two things,

1) The initial value will be 0 &
2) The final CRC has to be complemented.


Solution

  • Finally, I ended up using the following solution & thought it's worth sharing & it may be useful for someone.

    private static int GetCrc ( string BitString )
        {
            bool[] Res = new bool[17];
            bool[] CRC = new bool[16];
            int i;
            bool DoInvert = false;
            string crcBits = string.Empty;
    
            for ( i = 0; i < 16; ++i ) // Init before calculation
                CRC[i] = false;
    
            for ( i = 0; i < BitString.Length; ++i )
            {
                DoInvert = ('1' == BitString[i]) ^ CRC[15]; // XOR required?
    
                CRC[15] = CRC[14];
                CRC[14] = CRC[13];
                CRC[13] = CRC[12] ^ DoInvert;
                CRC[12] = CRC[11] ^ DoInvert;
                CRC[11] = CRC[10] ^ DoInvert;
                CRC[10] = CRC[9] ^ DoInvert;
                CRC[9] = CRC[8];
                CRC[8] = CRC[7] ^ DoInvert;
                CRC[7] = CRC[6];
                CRC[6] = CRC[5] ^ DoInvert;
                CRC[5] = CRC[4] ^ DoInvert;
                CRC[4] = CRC[3];
                CRC[3] = CRC[2];
                CRC[2] = CRC[1] ^ DoInvert;
                CRC[1] = CRC[0];
                CRC[0] = DoInvert;
            }
    
            for ( i = 0; i < 16; ++i )
                Res[15 - i] = CRC[i] ? true : false;
    
            Res[16] = false;
    
            // The final result must be Complemented            
            for ( i = 0; i < 16; i++ )
            {
                if ( Res[i] )
                    crcBits += "0";
                else
                    crcBits += "1";
            }
    
            return Convert.ToInt32 ( crcBits, 2 );
        }
    

    The above C# solution is converted from C based auto generated code from here.