简体   繁体   English

在C#中计算CRC16

[英]Calculating CRC16 in C#

I'm trying to port an old code from C to C# which basically receives a string and returns a CRC16 of it... 我正在尝试将旧代码从C移植到C#,该代码基本上接收一个字符串并返回它的CRC16 ...

The C method is as follow: C方法如下:

#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: 我移植的C#代码是这样的:

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. 测试字符串是“ OPN” ...它必须返回一个uof,它是(ofc)2个字节A8 A9,并且#CRC_MASK是用于该计算的多项式。 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. 我确实在网络上和网络上找到了多个CRC16的示例,但是没有一个能达到这个结果,因为此CRC计算必须与我们所连接的设备相匹配。

WHere is the mistake? 这是哪里的错误? I really appreciate any help. 我非常感谢您的帮助。

Thanks! 谢谢! best regards 最好的祝福

Gutemberg Gutemberg

UPDATE UPDATE

Following the answer from @rcgldr, I put together the following sample: 按照@rcgldr的回答,我整理了以下示例:

_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. cmd变量的值就是我要发送到设备的值。 If you have a look the the commented cmd value, this is a working string. 如果您查看注释的cmd值,这是一个有效的字符串。 The 2 bytes of the CRC16, goes in the last two parameters (msb and lsb). CRC16的2个字节位于最后两个参数(msb和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). 因此,在此处的示例中,为了使命令起作用(设备上的CRC16匹配),msb务必为“ \\ xA8”,而lsb务必为“ \\ xA9”。

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: 更新2对于那些属于相同情况的人,您需要使用\\ x格式化字符串,这是我为使其正常工作的工作:

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. 这向我返回了我需要在其中包含\\ x的完整消息。 The SYN variable is '\\x16' and ETB is '\\x17' SYN变量为“ \\ x16”,ETB为“ \\ x17”

Thank you all for the help! 谢谢大家的帮助!

Gutemberg 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. 这里的问题是包括ETB(\\ x17)的消息长4个字节(CRC不使用前导同步字节):“ OPN \\ x17” == {'O','P','N ',0x17},导致将{0xA8,0xA9}的CRC附加到消息中。 So the CRC function is correct, but the original test data wasn't including the 4th byte which is 0x17. 因此,CRC功能是正确的,但是原始测试数据不包括第四个字节0​​x17。

This is a working example (at least with VS2015 express). 这是一个有效的示例(至少在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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM