I'm trying to port an old code from C to C# which basically receives a string and returns a CRC16 of it...
The C method is as follow:
#define CRC_MASK 0x1021 /* x^16 + x^12 + x^5 + x^0 */
UINT16 CRC_Calc (unsigned char *pbData, int iLength)
{
UINT16 wData, wCRC = 0;
int i;
for ( ;iLength > 0; iLength--, pbData++) {
wData = (UINT16) (((UINT16) *pbData) << 8);
for (i = 0; i < 8; i++, wData <<= 1) {
if ((wCRC ^ wData) & 0x8000)
wCRC = (UINT16) ((wCRC << 1) ^ CRC_MASK);
else
wCRC <<= 1;
}
}
return wCRC;
}
My ported C# code is this:
private static ushort Calc(byte[] data)
{
ushort wData, wCRC = 0;
for (int i = 0; i < data.Length; i++)
{
wData = Convert.ToUInt16(data[i] << 8);
for (int j = 0; j < 8; j++, wData <<= 1)
{
var a = (wCRC ^ wData) & 0x8000;
if ( a != 0)
{
var c = (wCRC << 1) ^ 0x1021;
wCRC = Convert.ToUInt16(c);
}
else
{
wCRC <<= 1;
}
}
}
return wCRC;
}
The test string is "OPN"... It must return a uint which is (ofc) 2 bytes A8 A9 and the #CRC_MASK is the polynomial for that calculation. I did found several examples of CRC16 here and around the web, but none of them achieve this result since this CRC calculation must match the one that the device we are connecting to.
WHere is the mistake? I really appreciate any help.
Thanks! best regards
Gutemberg
UPDATE
Following the answer from #rcgldr, I put together the following sample:
_serial = new SerialPort("COM6", 19200, Parity.None, 8, StopBits.One);
_serial.Open();
_serial.Encoding = Encoding.GetEncoding(1252);
_serial.DataReceived += Serial_DataReceived;
var msg = "OPN";
var data = Encoding.GetEncoding(1252).GetBytes(msg);
var crc = BitConverter.GetBytes(Calc(data));
var msb = crc[0].ToString("X");
var lsb = crc[1].ToString("X");
//The following line must be something like: \x16OPN\x17\xA8\xA9
var cmd = string.Format(#"{0}{1}{2}\x{3}\x{4}", SYN, msg, ETB, msb, lsb);
//var cmd = "\x16OPN\x17\xA8\xA9";
_serial.Write(cmd);
The value of the cmd variable is what I'm trying to send to the device. If you have a look the the commented cmd value, this is a working string. The 2 bytes of the CRC16, goes in the last two parameters (msb and lsb). So, in the sample here, msb MUST be "\xA8" and lsb MUST be "\xA9" in order to the command to work(the CRC16 match on the device).
Any clues?
Thanks again.
UPDATE 2
For those who fall in the same case were you need to format the string with \x this is what I did to get it working:
protected string ToMessage(string data)
{
var msg = data + ETB;
var crc = CRC16.Compute(msg);
var fullMsg = string.Format(#"{0}{1}{2:X}{3:X}", SYN, msg, crc[0], crc[1]);
return fullMsg;
}
This return to me the full message that I need inclusing the \x on it. The SYN variable is '\x16' and ETB is '\x17'
Thank you all for the help!
Gutemberg
The problem here is that the message including the ETB (\x17) is 4 bytes long (the leading sync byte isn't used for the CRC): "OPN\x17" == {'O', 'P', 'N', 0x17}, which results in a CRC of {0xA8, 0xA9} to be appended to the message. So the CRC function is correct, but the original test data wasn't including the 4th byte which is 0x17.
This is a working example (at least with VS2015 express).
private static ushort Calc(byte[] data)
{
ushort wCRC = 0;
for (int i = 0; i < data.Length; i++)
{
wCRC ^= (ushort)(data[i] << 8);
for (int j = 0; j < 8; j++)
{
if ((wCRC & 0x8000) != 0)
wCRC = (ushort)((wCRC << 1) ^ 0x1021);
else
wCRC <<= 1;
}
}
return wCRC;
}
Related
I have this code which calculate CRC-32, I need to edit this code with: Polynomial 0x04C11DB7 ,Initial value: 0xFFFFFFFF , XOR:0 .
So CRC32 for string "123456789" should be"0376E6E7", I found a code, it's very slow , But it works any way.
```internal static class Crc32
{
internal static uint[] MakeCrcTable()
{
uint c;
uint[] crcTable = new uint[256];
for (uint n = 0; n < 256; n++)
{
c = n;
for (int k = 0; k < 8; k++)
{
var res = c & 1;
c = (res == 1) ? (0xEDB88320 ^ (c >> 1)) : (c >> 1);
}
crcTable[n] = c;
}
return crcTable;
}
internal static uint CalculateCrc32(byte[] str)
{
uint[] crcTable = Crc32.MakeCrcTable();
uint crc = 0xffffffff;
for (int i = 0; i < str.Length; i++)
{
byte c = str[i];
crc = (crc >> 8) ^ crcTable[(crc ^ c) & 0xFF];
}
return ~crc; //(crc ^ (-1)) >> 0;
}
}```
Based on the added comments, what you are looking for is CRC-32/MPEG-2, which reverses the direction of the CRC, and eliminates the final exclusive-or, compared to the implementation you have, which is a CRC-32/ISO-HDLC.
To get there, you need to flip the CRC from reflected to forward. You bit-flip the polynomial to get 0x04c11db7, check the high bit instead of the low bit, reverse the shifts, both in the table generation and use of the table, and exclusive-or with the high byte of the CRC instead of the low byte.
To remove the final exclusive-or, remove the tilde at the end.
I have a terminal that communicates through RS232 COM with the computer. The protocol that I was given says that I have to send a certain combination of bytes and the CRC 16 IBM calculation of the data sent at the end
I was also given a C written application that I can test with, that application writes a log with send data and received data. In that log I see if I send the terminal this string hexString = "02 00 04 a0 00 01 01 03". I must also send this CRC16 IBM result of data 06 35.
I have managed to somehow translate the C method that was given as an example, into C#. But my result is far away from what I know I must receive.
I have tested sending the data from the log and everything is fine. I must have my calculation done wrong. Am I doing anything wrong here?
Here is my code:
CRC class:
public enum Crc16Mode : ushort
{
ARINC_NORMAL = 0XA02B, ARINC_REVERSED = 0xD405, ARINC_REVERSED_RECIPROCAL = 0XD015,
CCITT_NORMAL = 0X1021, CCITT_REVERSED = 0X8408, CCITT_REVERSED_RECIPROCAL = 0X8810,
CDMA2000_NORMAL = 0XC867, CDMA2000_REVERSED = 0XE613, CDMA2000_REVERSED_RECIPROCAL = 0XE433,
DECT_NORMAL = 0X0589, DECT_REVERSED = 0X91A0, DECT_REVERSED_RECIPROCAL = 0X82C4,
T10_DIF_NORMAL = 0X8BB7, T10_DIF_REVERSED = 0XEDD1, T10_DIF_REVERSED_RECIPROCAL = 0XC5DB,
DNP_NORMAL = 0X3D65, DNP_REVERSED = 0XA6BC, DNP_REVERSED_RECIPROCAL = 0X9EB2,
IBM_NORMAL = 0X8005, IBM_REVERSED = 0XA001, IBM_REVERSED_RECIPROCAL = 0XC002,
OPENSAFETY_A_NORMAL = 0X5935, OPENSAFETY_A_REVERSED = 0XAC9A, OPENSAFETY_A_REVERSED_RECIPROCAL = 0XAC9A,
OPENSAFETY_B_NORMAL = 0X755B, OPENSAFETY_B_REVERSED = 0XDDAE, OPENSAFETY_B_REVERSED_RECIPROCAL = 0XBAAD,
PROFIBUS_NORMAL = 0X1DCF, PROFIBUS_REVERSED = 0XF3B8, PROFIBUS_REVERSED_RECIPROCAL = 0X8EE7
}
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;
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;
}
}
}
Method to process the bytes received:
public ushort CalculateCRC(byte[] data)
{
Crc16 crcCalc = new Crc16(Crc16Mode.IBM_NORMAL);
ushort crc = crcCalc.ComputeChecksum(data);
return crc;
}
In this method you can select polynomial from the Enum.
Main in Program Class:
static void Main(string[] args)
{
try
{
Metode m = new Metode();
string hexString = "02 00 04 a0 00 01 01 03";
byte[] bytes = m.HexStringToByteArray(hexString);
ushort crc = m.CalculateCRC(bytes);
string hexResult;
int myInt = crc;
hexResult = myInt.ToString("X");
//Console.WriteLine(crc.ToString());
Console.WriteLine(hexResult);
Console.ReadLine();
}
catch (Exception ex)
{
Metode m = new Metode();
m.writeError(ex.Message);
}
}
Convert from hexstring to byte array:
public byte[] HexStringToByteArray(string hexString)
{
hexString = hexString.Replace(" ", "");
return Enumerable.Range(0, hexString.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hexString.Substring(x, 2), 16))
.ToArray();
}
Convert from byte array to hex string:
public string ByteArrayToHexString(byte[] byteArray)
{
return BitConverter.ToString(byteArray);
}
What am I doing wrong here?
UPDATE:
Thanks to #MarkAdler I have managed to translate the calculation. What I didn't notice until late was the fact that the CRC calculation should have been for online the DATA sent to the terminal, NOT the entire message!
So the hexString should have been in fact "a0 00 01 01", the data without the STX/length/ETX.
Here is the code for this particular CRC16 Calculus in C#:
public ushort CalculateCRC(byte[] data, int len)
{
int crc = 0, i = 0;
while (len-- != 0)
{
crc ^= data[i++] << 8;
for (int k = 0; k < 8; k++)
crc = ((crc & 0x8000) != 0) ? (crc << 1) ^ 0x8005 : (crc << 1);
}
return (ushort)(crc & 0xffff);
}
You'd need to provide more information on the specification you are trying to implement. However I can tell right away that you are using the wrong polynomial. The CRC routines are shifting right, which means that the polynomial should be bit-reversed. As a result, IBM_NORMAL cannot be correct.
While IBM_REVERSED would be an appropriate polynomial for shifting right, that may or may not be the polynomial you need to meet your specification. Also there could be exclusive-or's coming into or leaving the CRC routine that are needed.
Update:
The linked documentation provides actual code to compute the CRC. Why aren't you looking at that? Finding random code on the interwebs to compute a CRC without looking at what's in the documentation is not likely to get you far. And it didn't.
The documented code shifts the CRC left, opposite of the code that you posted in the question. You need to shift left. The polynomial is 0x8005. There is no final exclusive-or, and the initial CRC value is zero.
Here is a simplified version of the code in the document, written in C (this code avoids the little-endian assumption that is built into the code in the document):
#include <stddef.h>
typedef unsigned char byte;
typedef unsigned short ushort;
ushort crc16ecr(byte data[], int len) {
ushort crc = 0;
for (int i = 0; i < len; i++) {
crc ^= (ushort)(data[i]) << 8;
for (int k = 0; k < 8; k++)
crc = crc & 0x8000 ? (crc << 1) ^ 0x8005 : crc << 1;
}
return crc;
}
Per the document, the CRC is computed on the tag, len, and data, which for your message is a0 00 01 01. Not the whole thing. (Reading the documentation thoroughly is always an excellent first step.) Running that through the CRC code in the document, you get 0x0635. The document says that that is transmitted most significant byte first, so 0x06 0x35.
I'm trying to implement a 16-CRC [DNP] using c#, the generator polynomial is given as
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.
This was actually very helpful for me. However, I did not use the solution SanVEE did, I actually modified the code from his original post as described by Mark Adler and it works great. At least, so far the result matches up with the DNP3 checksum calculator found here: http://www.lammertbies.nl/comm/info/crc-calculation.html
The code posted as the answer for SanVEE looks like it might be very inefficient (e.g. using bools to store each bit), though I have not tested them to compare. Anyone facing the same question may want to examine both answers to see which works better for them.
public class Crc16DNP3
{
const ushort polynomial = 0xA6BC; //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]);
}
crc = SwapBytes((ushort)(crc ^ 0xffff));
return crc;
}
public byte[] ComputeChecksumBytes(byte[] bytes)
{
ushort crc = ComputeChecksum(bytes);
return BitConverter.GetBytes(crc);
}
// SwapBytes taken from http://stackoverflow.com/questions/19560436/bitwise-endian-swap-for-various-types
private ushort SwapBytes(ushort x)
{
return (ushort)((ushort)((x & 0xff) << 8) | ((x >> 8) & 0xff));
}
public Crc16DNP3()
{
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;
}
}
}
What's wrong with the code at your first link? That also specifies how the CRC bytes are ordered in the message.
You need to reverse the polynomial below x16. The polynomial in bit form is 10011110101100101. Drop the leading 1 (x16), and you have in groups of four: 0011 1101 0110 0101. Reversed that is: 1010 0110 1011 1100. So you should set polynomial = 0xA6BC.
The initial value is already zero. Complementing the final CRC can be done simply with ^ 0xffff.
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.
Using C#.net,WPF application.I'm going to connect to a device (MODBUS protocol), I have to calculate CRC (CRC16).
Function which i use calculate normal crc16 and value is correct,but i want the value for CRC16(modbus) one.
Help me to sort out.
There are a lot of resources online about the calculation of the crc16 for the modbus protocol.
For example:
http://www.ccontrolsys.com/w/How_to_Compute_the_Modbus_RTU_Message_CRC
http://www.modbustools.com/modbus_crc16.htm
I think that translating that code in c# should be simple.
You can use this library:
https://github.com/meetanthony/crccsharp
It contains several CRC algorithms included ModBus.
Usage:
Download source code and add it to your project:
public byte[] CalculateCrc16Modbus(byte[] bytes)
{
CrcStdParams.StandartParameters.TryGetValue(CrcAlgorithms.Crc16Modbus, out Parameters crc_p);
Crc crc = new Crc(crc_p);
crc.Initialize();
var crc_bytes = crc.ComputeHash(bytes);
return crc_bytes;
}
Just use:
public static ushort Modbus(byte[] buf)
{
ushort crc = 0xFFFF;
int len = buf.Length;
for (int pos = 0; pos < len; pos++)
{
crc ^= buf[pos];
for (int i = 8; i != 0; i--)
{
if ((crc & 0x0001) != 0)
{
crc >>= 1;
crc ^= 0xA001;
}
else
crc >>= 1;
}
}
// lo-hi
//return crc;
// ..or
// hi-lo reordered
return (ushort)((crc >> 8) | (crc << 8));
}
(curtesy of https://www.cyberforum.ru/csharp-beginners/thread2329096.html)
Boost CRC (Added due to title)
auto v = std::vector< std::uint8_t > { 0x12, 0x34, 0x56, 0x78 };
auto result = boost::crc_optimal<16, 0x8005, 0xFFFF, 0, true, true> {};
result.process_bytes(v.data(), v.size());
After looking into a bug in the original jBCrypt v0.1 C# port: BCrypt.net (Related Question). I decided to compare the new jBCrypt code against the old C# port to look for discrepancies and potential issues like the related question's bug.
Here is what I've found:
// original java (jBCrypt v0.3):
private static int streamtoword(byte data[], int offp[]) {
int i;
int word = 0;
int off = offp[0];
for (i = 0; i < 4; i++) {
word = (word << 8) | (data[off] & 0xff);
off = (off + 1) % data.length;
}
offp[0] = off;
return word;
}
// port to C# :
private static uint StreamToWord(byte[] data, ref int offset)
{
uint word = 0;
for (int i = 0; i < 4; i++)
{
// note the difference with the omission of "& 0xff"
word = (word << 8) | data[offset];
offset = (offset + 1) % data.Length;
}
return word;
}
if the prior is incorrect would the following fix it?
private static uint StreamToWord(byte[] data, ref int[] offsetp)
{
uint word = 0;
int offset = offsetp[0];
for (int i = 0; i < 4; i++)
{
word = (word << 8) | (uint)(data[offset] & 0xff);
offset = (offset + 1) % data.Length;
}
offsetp[0] = offset;
return word;
}
The & 0xff is required in the Java version because in Java, bytes are signed. (Some argue that this is a bug.)
In C#, bytes are unsigned, so the & 0xff is unnecessary.