2013-08-20 112 views
3

我需要NFC標籤的CRC16實現。正如標準告訴我的那樣,這是ISO/IEC13239,並提供了示例C代碼。 我翻譯這個代碼轉換成Java,但它給了我錯誤的結果:ISO/IEC13239 CRC16實施

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 AC版本的CRC值是這裏第42頁:http://www.waazaa.org/download/fcd-15693-3.pdf

而且其他CRC實現不起作用:crc16 implementation java 第一個給我0x9e33,第二0x0FA1(我實現的方式說0xE1E5

是否有人在我的示例中發現錯誤,或者是否有另一個CRC16實現真的起作用?

+0

CRC需要使用變量16位寬和無符號操作。你的變量crc_current_value是一個字符。您還需要大量的工作來查看例程... – guga

+0

您需要了解的是,使用預先計算的表格有比這更快的算法。 – EJP

+0

@EJP:你指的是鏈接中的一個?這給了我完全不同的結果... – reox

回答

4

你的答案非常接近,但我認爲掩蔽和多項式可能存在一些問題。這裏有一些似乎適用於我的調整:

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

這裏的原始代碼確實存在一個問題'((char)data [i])'。當數據字節具有最高位設置時,這會給出錯誤的值。例如。 0x80 - > 0xff80 – Henry

+0

,但字節順序「{1,2,3,4}」仍然得到'0xE1E5'。你能確認你得到了'0x3991'嗎? – reox

+0

添加更正後的POLYNOMIAL定義(0x8408),我想你會得到答案。 – OldCurmudgeon

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

+1

多項式值0x8408是正確的,你必須讀取從LSB到MSB的位模式(並且不顯示x^16) – Henry

+0

@亨利 - 我看不出如何,但我希望你是對的。 – OldCurmudgeon

+0

反轉位模式並在前面添加1:0x11021,那麼在多項式中存在指數的每個位置上都有1。 – Henry

0

這是一個更快的實現(source)。

使用ccittPoly初始值0xFFFF並補充結果。這給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; } 

}