I found an example of working CRC-16/CCITT KERMIT python code shown below:
def make_crc_table():
poly = 0x8408
table = []
for byte in range(256):
crc = 0
for bit in range(8):
if (byte ^ crc) & 1:
crc = (crc >> 1) ^ poly
else:
crc >>= 1
byte >>= 1
table.append(crc)
return table
table = make_crc_table()
def crc_16_fast(msg):
crc = 0xffff
for byte in msg:
crc = table[(byte ^ crc) & 0xff] ^ (crc >> 8)
return crc ^ 0xffff
# Test
packet = "64 23 2F 36 27 2F 2F 23 1F 25"
# Perform CRC16 (Kermit - with poly of 0x8408)
msg = bytes.fromhex(packet)
out = crc_16_fast(msg)
hi, lo = out >> 8, out & 0xff
print('{:04x} = {:02x} {:02x}'.format(out, hi, lo))
The output is shown below and matches what I expect:
a40e = a4 0e
I am trying to reproduce this in C#. I found the following code snippet, however it returns differing results from the python code. So far I have not been able to figure out what the difference is. How can I get the C# code to produce the same expected output?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public enum Crc16Mode : ushort { Standard = 0xA001, CcittKermit = 0x8408 }
namespace CollinsWirelessTransModule
{
public class Crc16
{
readonly ushort[] table = new ushort[256];
public ushort ComputeChecksum(params 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(params byte[] bytes)
{
ushort crc = ComputeChecksum(bytes);
return BitConverter.GetBytes(crc);
}
public Crc16(Crc16Mode mode)
{
ushort polynomial = (ushort)mode;
Console.WriteLine("Polynomial: " + polynomial.ToString("X"));
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;
}
}
}
class Program
{
static void Main(string[] args)
{
var commsCrc = new Crc16(Crc16Mode.CcittKermit);
var checkBytes = new byte[] { 0x64, 0x23, 0x2F, 0x36, 0x27, 0x2F, 0x2F, 0x23, 0x1F, 0x25 };
var valueToPrint = commsCrc.ComputeChecksum(checkBytes);
var bytesToPrint = BitConverter.GetBytes(valueToPrint);
string hex = BitConverter.ToString(bytesToPrint);
Console.WriteLine("Hex bytes: " + hex);
// Wait for the user to respond before closing.
Console.ReadKey();
}
}
}
The output here does not match Python and looks like:
Polynomial: 8408
Hex bytes: 76-C7
I made sure the polynomial and starting values were the same.
We can try rewriting Python code, if it's the one we must follow (so not to try getting ready solution and see if it is doing the same, instead we are writing C# code accordingly to Python code).
Here's C# snippet with some comments that point out, which Python code is related in particular code block:
var poly = 0x8408;
var table = new List<int>();
int crc;
// start make_crc_table
for (int @byte = 0; @byte < 256; @byte++)
{
var b = @byte;
crc = 0;
for (byte bit = 0; bit < 8; bit++)
{
crc = ((b ^ crc) & 1) != 0
? (crc >> 1) ^ poly
: crc >>= 1;
b >>= 1;
}
table.Add(crc);
}
// end make_crc_table
// Test
var packet = "64 23 2F 36 27 2F 2F 23 1F 25";
var bytes = packet.Split(' ')
.Select(x => Convert.ToByte(x, 16))
.ToArray();
// start crc_16_fast
crc = 0xFFFF;
foreach (var @byte in bytes)
{
crc = table[(@byte ^ crc) & 0xFF] ^ (crc >> 8);
}
var @out = crc ^ 0xFFFF;
var hi = @out >> 8;
var low = @out & 0xFF;
// end crc_16_fast
Console.WriteLine("out = " + @out.ToString("x4")
+ Environment.NewLine + "hi = " + hi.ToString("x2")
+ Environment.NewLine + "low = " + low.ToString("x2"));