1

我正在尝试使用 c#实现16-CRC [DNP]generator polynomial ,给出为

在此处输入图像描述

我找到了 16-crc 的标准解决方案:[来源]

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;
        }
    }
}

现在,如果我转换我的多项式,我得到1 0011 1101 0110 0111=> (3D65)h& 我的问题是我需要改变什么来为给定多项式工作上述解决方案。

Edit: 我还需要考虑两件事,

1) 初始值为 0 &
2) 最终的 CRC 必须补码。

4

3 回答 3

3

这实际上对我很有帮助。但是,我没有使用 SanVEE 所做的解决方案,实际上我按照 Mark Adler 的描述从他的原始帖子中修改了代码,并且效果很好。至少,到目前为止,结果与此处的 DNP3 校验和计算器相匹配:http: //www.lammertbies.nl/comm/info/crc-calculation.html

作为 SanVEE 的答案发布的代码看起来可能非常低效(例如,使用布尔值来存储每个位),尽管我没有测试它们进行比较。任何面临相同问题的人都可能想检查这两个答案,看看哪个更适合他们。

    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;
            }
        }
    }
于 2016-03-15T01:18:33.603 回答
2

第一个链接的代码有什么问题?这还指定了 CRC 字节在消息中的排序方式。

您需要反转 x 16以下的多项式。位形式的多项式是10011110101100101。删除前导1(x 16 ),您将拥有四个一组:0011 1101 0110 0101. 反过来就是:1010 0110 1011 1100。所以你应该设置polynomial = 0xA6BC.

初始值已经为零。补充最终的 CRC 可以简单地使用^ 0xffff.

于 2014-09-19T14:57:22.480 回答
1

最后,我最终使用了以下解决方案并认为它值得分享并且它可能对某人有用。

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 );
    }

上面的 C# 解决方案是C based auto generated code这里转换而来的。

于 2014-09-24T10:25:05.697 回答