I have an incoming packet that reads 7E0302403F387E from a serial port.
start and end flag is 7E, FCS/CRC is 3F38 and the data is 030240. The FCS is calculated per the algorithm specified in RFC 1662. https://www.rfc-editor.org/rfc/rfc1662#appendix-A
This is the code I'm using to generate the FCS for 030240:
static byte[] HexToBytes(string input)
{
byte[] result = new byte[input.Length / 2];
for (int i = 0; i < result.Length; i++)
{
result[i] = Convert.ToByte(input.Substring(2 * i, 2), 16);
}
return result;
}
public static class Crc16
{
const ushort polynomial = 0x8408;
static readonly ushort[] table = new ushort[256];
public static 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;
}
static 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;
}
}
}
This is how I call it:
//string input = "00 03 00 02 04 00";
string input = "030240";
var bytes = HexToBytes(input);
string hexe = Crc16.ComputeChecksum(bytes).ToString("x2");
I should get an FCS of 3F38 but instead I'm getting 9ED0. What am I doing wrong?
Edit 1:
I'm reading ~\0\u0003\0\u0002\u0004\0?8~
from the serial port. I am able to convert that into either 7E-03-02-40-3F-38-7E
or 7e-5c-30-5c-75-30-30-30-33-5c-30-5c-75-30-30-30-32-5c-75-30-30-30-34-5c-30-3f-38-7e
. The first is too short and the second is too long. I should be getting 10 bytes. Any tips?
Edit 2:
I am using ASCII_To_Hex to convert ~\0\u0003\0\u0002\u0004\0?8~
to 7E-03-02-40-3F-38-7E
public string ASCII_To_Hex(string ASCII)
{
char[] charValues = dataIN.ToCharArray();
string hexOutput = "";
foreach (char _eachChar in charValues)
{
// Get the integral value of the character.
int value = Convert.ToInt32(_eachChar);
// Convert the decimal value to a hexadecimal value in string form.
hexOutput += String.Format("{0:X}", value);
// to make output as your eg
// hexOutput +=" "+ String.Format("{0:X}", value);
}
return hexOutput;
}
What changes can I make here to correctly decipher the incoming packet?
Edit 3:
I made the following changes based on Mark's suggestion:
public static class Crc16
{
const ushort polynomial = 0x1021;
static readonly ushort[] table = new ushort[256];
public static ushort ComputeChecksum(byte[] bytes)
{
ushort crc = 0xffff;
for (int i = 0; i < bytes.Length; ++i)
{
byte index = (byte)(crc ^ bytes[i]);
crc = (ushort)((crc >> 8) ^ table[index]);
}
return (ushort)~crc;
}
static 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;
}
}
}
This is how I'm calling it:
string hex = "00-03-00-02-04-00";
hex = hex.Replace("-", "");
var bytes = HexToBytes(hex);
string hexe = Crc16.ComputeChecksum(bytes).ToString("X2");
I'm getting FO93
instead of 389B
Based on the linked appendix, the initial value of the CRC is 0xffff
, not 0, and you need to exclusive-or the result with 0xffff
to get the FCS to put in the packet.
However that still doesn't work for your example packet. I can only guess that your example packet was not correctly extracted or identified.
Update:
From the OP comment below and some deduction, the actual data in the message is "~\x00\x03\x00\x02\x04\x00\x9b\x38~"
. The OP left out three zero bytes for some reason, and the OP printed it in a way that obscured one byte as a question mark.
Now the CRC calculates correctly as 0x389b
, stored in the message little-endian as 0x9b
0x38
. To get that, you must apply my comments above on the initial value and final exclusive-or.