I am trying to write a unit test for a CRC16 checksum for a P1 meter message (and having a hard time getting it right...).
What I have is:
Given the fact that I posted a question on SO, the result is not OK...
Please bear with me, I will share what I have below:
private static readonly string telegramText =
"/KFM5KAIFA-METER\n" +
"\n" +
"1-3:0.2.8(42)\n" +
"0-0:1.0.0(170124213128W)\n" +
"0-0:96.1.1(4530303236303030303234343934333135)\n" +
"1-0:1.8.1(000306.946*kWh)\n" +
"1-0:1.8.2(000210.088*kWh)\n" +
"1-0:2.8.1(000000.000*kWh)\n" +
"1-0:2.8.2(000000.000*kWh)\n" +
"0-0:96.14.0(0001)\n" +
"1-0:1.7.0(02.793*kW)\n" +
"1-0:2.7.0(00.000*kW)\n" +
"0-0:96.7.21(00001)\n" +
"0-0:96.7.9(00001)\n" +
"1-0:99.97.0(1)(0-0:96.7.19)(000101000006W)(2147483647*s)\n" +
"1-0:32.32.0(00000)\n" +
"1-0:52.32.0(00000)\n" +
"1-0:72.32.0(00000)\n" +
"1-0:32.36.0(00000)\n" +
"1-0:52.36.0(00000)\n" +
"1-0:72.36.0(00000)\n" +
"0-0:96.13.1()\n" +
"0-0:96.13.0()\n" +
"1-0:31.7.0(003*A)\n" +
"1-0:51.7.0(005*A)\n" +
"1-0:71.7.0(005*A)\n" +
"1-0:21.7.0(00.503*kW)\n" +
"1-0:41.7.0(01.100*kW)\n" +
"1-0:61.7.0(01.190*kW)\n" +
"1-0:22.7.0(00.000*kW)\n" +
"1-0:42.7.0(00.000*kW)\n" +
"1-0:62.7.0(00.000*kW)\n" +
"0-1:24.1.0(003)\n" +
"0-1:96.1.0(4730303331303033333738373931363136)\n" +
"0-1:24.2.1(170124210000W)(00671.790*m3)\n" +
"!29ED\n";
Source can be found here
CRC is a CRC16 value calculated over the preceding characters in the data message (from “/” to “!” using the polynomial: x16 + x15 + x2 + 1).
CRC16 uses no XOR in, no XOR out and is computed with least significant bit first. The value is represented as 4 hexadecimal characters (MSB first).
The read message is the P1 message above, but then from '/' to '!' (including the '/' and including the '!'), as dictated by above spec.
var bytes = Encoding.ASCII.GetBytes(_readMessage);
var computeChecksum = new Crc16().ComputeChecksum(bytes);
Source can be found here
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;
}
}
}
The checksum of the P1 telegram should be: 0x29ED, but unfortunately I calculate 0x6500.
Can somebody point me in the right direction?
@Mark Adler, I fixed the issue you found, but I still calculate the wrong checksum. I stripped all irrelevant parts below, could you be so kind to have another look? You can simply copy paste the code below if you like. Or, post back the code that does calculate the correct checksum.
Thanks a lot in advance!
class Program
{
private static readonly string telegramText =
"/KFM5KAIFA-METER\r\n" +
"\r\n" +
"1-3:0.2.8(42)\r\n" +
"0-0:1.0.0(170124213128W)\r\n" +
"0-0:96.1.1(4530303236303030303234343934333135)\r\n" +
"1-0:1.8.1(000306.946*kWh)\r\n" +
"1-0:1.8.2(000210.088*kWh)\r\n" +
"1-0:2.8.1(000000.000*kWh)\r\n" +
"1-0:2.8.2(000000.000*kWh)\r\n" +
"0-0:96.14.0(0001)\r\n" +
"1-0:1.7.0(02.793*kW)\r\n" +
"1-0:2.7.0(00.000*kW)\r\n" +
"0-0:96.7.21(00001)\r\n" +
"0-0:96.7.9(00001)\r\n" +
"1-0:99.97.0(1)(0-0:96.7.19)(000101000006W)(2147483647*s)\r\n" +
"1-0:32.32.0(00000)\r\n" +
"1-0:52.32.0(00000)\r\n" +
"1-0:72.32.0(00000)\r\n" +
"1-0:32.36.0(00000)\r\n" +
"1-0:52.36.0(00000)\r\n" +
"1-0:72.36.0(00000)\r\n" +
"0-0:96.13.1()\r\n" +
"0-0:96.13.0()\r\n" +
"1-0:31.7.0(003*A)\r\n" +
"1-0:51.7.0(005*A)\r\n" +
"1-0:71.7.0(005*A)\r\n" +
"1-0:21.7.0(00.503*kW)\r\n" +
"1-0:41.7.0(01.100*kW)\r\n" +
"1-0:61.7.0(01.190*kW)\r\n" +
"1-0:22.7.0(00.000*kW)\r\n" +
"1-0:42.7.0(00.000*kW)\r\n" +
"1-0:62.7.0(00.000*kW)\r\n" +
"0-1:24.1.0(003)\r\n" +
"0-1:96.1.0(4730303331303033333738373931363136)\r\n" +
"0-1:24.2.1(170124210000W)(00671.790*m3)\r\n" +
"!";
static void Main(string[] args)
{
var bytes = Encoding.ASCII.GetBytes(telegramText);
var computeChecksum = new Crc16().ComputeChecksum(bytes);
}
}
public class Crc16
{
const ushort polynomial = 0x8005;
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;
}
}
}
The CRC code looks fine. The problem is that it is expecting carriage return-line feeds, not just line feeds. If you precede each \n
with a \r
, then you get 0x29ed
for the CRC of the bytes from the /
to the !
, inclusive.