【问题标题】:ISO/IEC13239 CRC16 ImplementationISO/IEC13239 CRC16 实施
【发布时间】:2013-08-20 08:45:00
【问题描述】:

我需要 NFC 标签的 CRC16 实现。正如标准告诉我的那样,这是 ISO/IEC13239 并提供了示例 C 代码。 我将这段代码翻译成 Java,但它给了我错误的结果:

private static final char POLYNOMIAL = 0x8404;
private static final char PRESET_VALUE = 0xFFFF;

public static int crc16(byte[] data) {
char current_crc_value = PRESET_VALUE;
for (int i = 0; i < data.length; i++) {
    current_crc_value = (char) (current_crc_value ^ ((char) data[i]));
    for (int j = 0; j < 8; j++) {
    if ((current_crc_value & 0x0001) == 0x0001) {
        current_crc_value = (char) ((current_crc_value >>> 1) ^ POLYNOMIAL);
    } else {
        current_crc_value = (char) (current_crc_value >>> 1);
    }
    }
}
current_crc_value = (char) ~current_crc_value;

return current_crc_value;
}

正如标准告诉我的那样,1,2,3,4 的字节序列应该创建0x3991 的 CRC 值 C 版本在第 42 页:http://www.waazaa.org/download/fcd-15693-3.pdf

其他 CRC 实现也不起作用:crc16 implementation java 第一个给我0x9e33,第二个给我0x0FA1(我的实现顺便说一下0xE1E5

是否有人在我的示例中发现了错误,或者是否有另一个真正有效的 CRC16 实现?

【问题讨论】:

  • CRC 需要使用 16 位宽且无符号的变量进行操作。您的变量 crc_current_value 是一个字符。你也有很多演员要通过例行程序来完成......
  • 你需要知道有一个比这更快的算法,使用预先计算的表。
  • @EJP:你的意思是链接中的那个?这给了我完全不同的结果......
  • 您必须调整多项式和初始值以适合您的情况。它确实有效,我已经使用了 25 年,在 Java 中使用了 17 年。

标签: java crc16


【解决方案1】:

您的答案非常接近,但我认为掩蔽和多项式可能存在一些问题。以下是一些似乎对我有用的调整:

private static final int POLYNOMIAL   = 0x8408;
private static final int PRESET_VALUE = 0xFFFF;

public static int crc16(byte[] data)
{
  int current_crc_value = PRESET_VALUE;
  for (int i = 0; i < data.length; i++ )
  {
    current_crc_value ^= data[i] & 0xFF;
    for (int j = 0; j < 8; j++)
    {
      if ((current_crc_value & 1) != 0)
      {
        current_crc_value = (current_crc_value >>> 1) ^ POLYNOMIAL;
      }
      else
      {
        current_crc_value = current_crc_value >>> 1;
      }
    }
  }
  current_crc_value = ~current_crc_value;

  return current_crc_value & 0xFFFF;
}

【讨论】:

  • 这里((char) data[i])的原代码确实有问题。当数据字节设置了最高位时,这会给出错误的值。例如。 0x80 -> 0xff80
  • 但是对于字节序列{1,2,3,4} 仍然得到0xE1E5。你能确认你收到0x3991吗?
  • 添加更正后的 POLYNOMIAL 定义 (0x8408),我想你会知道答案的。
  • @OldCurmudgeon - 是的,确实如此。哎呀。为清楚起见添加。
  • 谢谢,这对我有用!字节被颠倒了,所以我确实需要为我的用例转换为 little-endian。
【解决方案2】:

首先 - PDF 有:

#define POLYNOMIAL 0x8408 // x^16 + x^12 + x^5 + 1

当你有的时候

private static final char POLYNOMIAL = 0x8404;

这肯定会导致问题 - 请解决这个问题并让我们知道这是否是问题所在。

我有点担心他们说0x8408 等价于x^16 + x^12 + x^5 + 1,因为事实并非如此,多项式将由0x8811 表示。 0x8408 将代表 x^16 + x^11 + x^4 这不太可能是正确的,因为它既不是素数也不是原始的。就此而言,0x8404 也不是。

【讨论】:

  • 多项式值0x8408是正确的,你必须从LSB读取位模式到MSB(并且x^16没有表示)
  • 反转位模式并在前面添加一个 1:0x11021,然后在多项式中存在指数的每个位置都有一个 1。
  • 谢谢 - 这很有道理 - 所以 0x8408 正确的多边形。
  • 是的,这和新代码似乎可以工作!所以我不知道该接受哪个答案:)
【解决方案3】:

这是一个更快的实现 (source)。

使用初始值为 0xFFFF 的 ccittPoly 并对结果求补。这为new byte[]{1, 2, 3, 4} 提供了 0x3991。

public class Crc16 {

// Generator polynom codes:
public static final int stdPoly    = 0xA001; // standard CRC-16 x16+x15+x2+1 (CRC-16-IBM)
public static final int stdRPoly   = 0xC002; // standard reverse x16+x14+x+1 (CRC-16-IBM)
public static final int ccittPoly  = 0x8408; // CCITT/SDLC/HDLC X16+X12+X5+1 (CRC-16-CCITT)
   // The initial CRC value is usually 0xFFFF and the result is complemented.
public static final int ccittRPoly = 0x8810; // CCITT reverse X16+X11+X4+1   (CRC-16-CCITT)
public static final int lrcPoly    = 0x8000; // LRCC-16 X16+1

private short[] crcTable;

public Crc16 (int polynom) {
   crcTable = genCrc16Table(polynom); }

public int calculate (byte[] data, int initialCrcValue) {
   int crc = initialCrcValue;
   for (int p = 0; p < data.length; p++) {
      crc = (crc >> 8) ^ (crcTable[(crc & 0xFF) ^ (data[p] & 0xFF)] & 0xFFFF); }
   return crc; }

private static short[] genCrc16Table (int polynom) {
   short[] table = new short[256];
   for (int x = 0; x < 256; x++) {
      int w = x;
      for (int i = 0; i < 8; i++) {
         if ((w & 1) != 0) {
            w = (w >> 1) ^ polynom; }
          else {
            w = w >> 1; }}
      table[x] = (short)w; }
   return table; }

}

【讨论】:

    猜你喜欢
    • 2013-09-06
    • 1970-01-01
    • 2013-10-21
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多