Search code examples
c#pythoncrcmodbus

Port Modbus RTU CRC to python from C#


I'm trying to port the CRC calculation function for Modbus RTU from C# to Python.

C#

private static ushort CRC(byte[] data)
{
    ushort crc = 0xFFFF;
    for (int pos = 0; pos < data.Length; pos++)
    {
        crc ^= (UInt16)data[pos];
        for (int i = 8; i != 0; i--)
        {
           if ((crc & 0x0001) != 0)
           {
               crc >>= 1;
               crc ^= 0xA001;
           }
           else
           {
               crc >>= 1;
           }
       }
    }
    return crc;
}

Which I run like this:

byte[] array = { 0x01, 0x03, 0x00, 0x01, 0x00, 0x01 };
ushort u = CRC(array);
Console.WriteLine(u.ToString("X4"));

Python

def CalculateCRC(data):
    crc = 0xFFFF
    for pos in data:
        crc ^= pos
        for i in range(len(data)-1, -1, -1):
            if ((crc & 0x0001) != 0):
                crc >>= 1
                crc ^= 0xA001
            else:
                crc >>= 1
    return crc

Which I run like this:

data = bytearray.fromhex("010300010001")
crc = CalculateCRC(data)
print("%04X"%(crc))
  • The result from the C# example is: 0xCAD5.
  • The result from the Python example is: 0x8682.

I know from fact by other applications that the CRC should be 0xCAD5, as the C#-example provides.

When I debug both examples step-by-step, the variable 'crc' has difference values after these code lines:

crc ^= (UInt16)data[pos];

VS

crc ^= pos

What am I missing?

/Mc_Topaz


Solution

  • Your inner loop uses the size of the data array instead of a fixed 8 iterations. Try this:

    def calc_crc(data):
        crc = 0xFFFF
        for pos in data:
            crc ^= pos 
            for i in range(8):
                if ((crc & 1) != 0):
                    crc >>= 1
                    crc ^= 0xA001
                else:
                    crc >>= 1
        return crc
    
    data = bytearray.fromhex("010300010001")
    crc = calc_crc(data)
    print("%04X"%(crc))