2014-09-19 152 views
0

我试图实现16-CRC [DNP]使用C#中,generator polynomial给出如何使用C#实现CRC-16-DNP?

enter image description here

我发现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; 
     } 
    } 
} 

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

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

1)初始值为0 &
2)最后的CRC必须加以补充。

回答

0

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

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 codehere转换。

2

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

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

初始值已经为零。完成最终的CRC可以简单地用^ 0xffff完成。

+0

对不起,我以前没有清楚,请参阅上面的编辑部分,也请你解释你是如何得到'0XA6BC'? – SanVEE 2014-09-19 16:07:36

1

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

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

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

非常感谢 – JohnLaird 2016-09-02 16:00:40