1

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

协议手册说数据包的最后 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,然后比较这两个数字对吗?

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

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 循环获取每个最后一个字节,并使用 toBinaryString() 将所有这些字节以二进制形式组合成一个字符串!所以我得到了类似 0000000000000000101011011101001 的内容(手册指出前两个字节始终为零,因为它是 16 位 CRC)

所以我只是将二进制字符串解析为有符号整数并比较两个 CRC……!

然而我得到的结果如下:

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

或者

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

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

我在这一切中缺少什么?

4

3 回答 3

0

文档措辞(或您对它的理解)可能有问题。如果数据包中有 16 位 CRC,它很可能占用两个字节,而不是四个(二进制形式)。如果它是十进制,那么即使是四个字节也不够(您需要 5 个 didgt 将其存储为无符号十进制字符串)。

您的代码显示您进行了转换(但我看不出它应该进行什么样的转换):

BinaryRecievedCRC+= toBinaryString(AvlPacket[index]);

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

编辑:从您的评论来看,您需要像这样提取 CRC:

public int getCRC(byte[] data, int index) {
    return ((data[index] & 0xFF) << 8)) | (data[index + 1] & 0xFF);
}
于 2012-09-24T13:28:36.707 回答
0

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

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

于 2012-09-25T01:54:55.883 回答
0

问题解决了!

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

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

谢谢大家的时间!

于 2012-09-25T10:28:00.833 回答