Java 16bit CRC数据包验证

时间:2012-09-24 12:59:19

标签: java validation crc crc16

我有一个Avl数据包,我通过GPRS从设备接收。

协议手册说该数据包在最后4个字节上有一个16位CRC,并给出了CRC计算的源代码:

public static int getCrc16(Byte[] buffer) {
    return getCrc16(buffer, 0, buffer.length, 0xA001, 0);
    }

public synchronized static int getCrc16(Byte[] buffer, int offset, int bufLen, int polynom, int preset) {
    preset &= 0xFFFF;
    polynom &= 0xFFFF;
    int crc = preset;
    for (int i = 0; i < bufLen; i++) {
        int data = buffer[i + offset] & 0xFF;
        crc ^= data;
        for (int j = 0; j < 8; j++) {
            if ((crc & 0x0001) != 0) {
                crc = (crc >> 1) ^ polynom;
            } else {
                crc = crc >> 1;
            }
        }
    }
    return crc & 0xFFFF;
}

所以我得到数据包发送给我的CRC编号,然后我调用getCrc16作为Byte数组,我已经存储了数据包,然后比较这两个数字吧?

以下是我在程序中使用的代码:

public static String toBinaryString(byte n) {
    StringBuilder sb = new StringBuilder("00000000");
    for (int bit = 0; bit < 8; bit++) {
        if (((n >> bit) & 1) > 0) {
            sb.setCharAt(7 - bit, '1');
        }
    }
    return sb.toString();
}

    int CalculatedCRC = getCrc16(AvlPacket);
    System.out.println("Calculated CRC= " + CalculatedCRC);

    int index = (AvlPacket.length)-4;
    String BinaryRecievedCRC = "";

    for (int j = 0; j < 4; j++) {
        BinaryRecievedCRC+= toBinaryString(AvlPacket[index]);
        index+=1;
    }

    int RecievedCRC = Integer.parseInt(BinaryRecievedCRC, 2);
    System.out.println("Recieved CRC= " + RecievedCRC);

toBinaryString()将一个字节转换为它的二进制文件并将其放入一个字符串中!

所以我通过手册中给出的getCrc16()来计算CRC。然后在数据包结束前取4个字节的索引,这样我就可以读取最后4个字节并获得随数据包发送的CRC!

for循环获取每个最后一个字节,并且withBinaryString()将所有它们以二进制形式组合成一个String!所以我得到类似0000000000000000101011011101001(手册指出前两个字节总是零,因为它是一个16位CRC )

所以我只是将Binary String解析为signed int并比较两个CRC ......!

然而我得到的结果如下:

计算的CRC = 21395 -----收到的CRC = 30416

计算的CRC = 56084 -----收到的CRC = 10504

我已经测试了很多数据包,并且它们不能全部丢失数据......我也在解析数据所以我知道我得到的数据是正确的!

我在这一切中缺少什么?

3 个答案:

答案 0 :(得分:0)

文档措辞可能有问题(或者你对它的理解)。如果数据包中存在16位CRC,则最有可能占用两个字节,而不是(以二进制形式)。如果它是一个小数,即使四个字节也不够(你需要5个didgts来存储它作为无符号十进制字符串)。

您的代码显示您进行了转换(但我无法看到它应该执行的转换类型):

BinaryRecievedCRC+= toBinaryString(AvlPacket[index]);

我希望CRC能够以二进制形式存储在数据中,所以我假设您唯一需要弄清楚的是使用了哪个字节顺序以及CRC存储在数据中的位置。

编辑:根据您的评论判断,您需要像这样提取CRC:

public int getCRC(byte[] data, int index) {
    return ((data[index] & 0xFF) << 8)) | (data[index + 1] & 0xFF);
}

答案 1 :(得分:0)

  

所以我得到数据包发给我的CRC号,然后我调用getCrc16   我已经存储数据包然后比较的字节数组   两个号码对吧?

错误。您计算整个消息的CRC,包括CRC字节,结果应为零。

答案 2 :(得分:0)

解决了问题!

问题是数据包在进入数据部分之前有8个其他字节! 所以在计算CRC之前,我必须排除前8个字节以及发送CRC的最后4个字节!

现在数字一致并且上面的代码是正确的,除了getCrc16函数中的for循环从i = 8开始(以便跳过不属于Data部分的数据包的前8个字节! )

谢谢大家的时间!