如何查找消息的校验和(CRC16?)

问题描述 投票:0回答:1

我有来自 CAN 总线日志的消息列表。 有些消息似乎有 2 个字节,其中似乎是校验和,然后是一个序列(或计数器字节)......然后还有 5 个字节。 这是一个示例列表。前两个字节是消息 ID,然后是长度(08),然后是消息内容,其中包含 2 个字节校验和(列表中第一个为 65 AB)、1 个字节序列(第一个为 00) )然后是内容。

0185    Rx  8   65  AB  00  00  00  00  00  00
0185    Rx  8   B6  EC  01  00  00  00  00  00
0185    Rx  8   C3  24  02  00  00  00  00  00
0185    Rx  8   10  63  03  00  00  00  00  00
0185    Rx  8   08  A4  04  00  00  00  00  00
0185    Rx  8   DB  E3  05  00  00  00  00  00
0185    Rx  8   AE  2B  06  00  00  00  00  00
0185    Rx  8   7D  6C  07  00  00  00  00  00
0185    Rx  8   BF  B5  08  00  00  00  00  00
0185    Rx  8   6C  F2  09  00  00  00  00  00
0185    Rx  8   19  3A  0A  00  00  00  00  00
0185    Rx  8   CA  7D  0B  00  00  00  00  00
0185    Rx  8   D2  BA  0C  00  00  00  00  00
0185    Rx  8   01  FD  0D  00  00  00  00  00
0185    Rx  8   74  35  0E  00  00  00  00  00
0185    Rx  8   A7  72  0F  00  00  00  00  00
0185    Rx  8   D1  96  10  00  00  00  00  00
0185    Rx  8   02  D1  11  00  00  00  00  00
0185    Rx  8   77  19  12  00  00  00  00  00
0185    Rx  8   A4  5E  13  00  00  00  00  00
0185    Rx  8   BC  99  14  00  00  00  00  00
0185    Rx  8   6F  DE  15  00  00  00  00  00
0185    Rx  8   1A  16  16  00  00  00  00  00
0185    Rx  8   C9  51  17  00  00  00  00  00
0185    Rx  8   0B  88  18  00  00  00  00  00
0185    Rx  8   D8  CF  19  00  00  00  00  00
0185    Rx  8   AD  07  1A  00  00  00  00  00
0185    Rx  8   7E  40  1B  00  00  00  00  00
0185    Rx  8   66  87  1C  00  00  00  00  00
0185    Rx  8   B5  C0  1D  00  00  00  00  00
0185    Rx  8   C0  08  1E  00  00  00  00  00
0185    Rx  8   13  4F  1F  00  00  00  00  00
0185    Rx  8   0D  D0  20  00  00  00  00  00
0185    Rx  8   DE  97  21  00  00  00  00  00
                                        
0180    Rx  8   43  13  01  00  00  00  00  00
0180    Rx  8   36  DB  02  00  00  00  00  00
0180    Rx  8   E5  9C  03  00  00  00  00  00
0180    Rx  8   FD  5B  04  00  00  00  00  00
0180    Rx  8   2E  1C  05  00  00  00  00  00
0180    Rx  8   5B  D4  06  00  00  00  00  00
0180    Rx  8   88  93  07  00  00  00  00  00
0180    Rx  8   4A  4A  08  00  00  00  00  00
0180    Rx  8   99  0D  09  00  00  00  00  00
0180    Rx  8   EC  C5  0A  00  00  00  00  00
0180    Rx  8   3F  82  0B  00  00  00  00  00
0180    Rx  8   27  45  0C  00  00  00  00  00
0180    Rx  8   F4  02  0D  00  00  00  00  00
0180    Rx  8   81  CA  0E  00  00  00  00  00
0180    Rx  8   52  8D  0F  00  00  00  00  00
0180    Rx  8   24  69  10  00  00  00  00  00
0180    Rx  8   F7  2E  11  00  00  00  00  00
0180    Rx  8   82  E6  12  00  00  00  00  00
0180    Rx  8   51  A1  13  00  00  00  00  00
0180    Rx  8   49  66  14  00  00  00  00  00
0180    Rx  8   9A  21  15  00  00  00  00  00
0180    Rx  8   EF  E9  16  00  00  00  00  00
0180    Rx  8   3C  AE  17  00  00  00  00  00
0180    Rx  8   FE  77  18  00  00  00  00  00
0180    Rx  8   2D  30  19  00  00  00  00  00
0180    Rx  8   58  F8  1A  00  00  00  00  00
0180    Rx  8   8B  BF  1B  00  00  00  00  00
0180    Rx  8   93  78  1C  00  00  00  00  00
0180    Rx  8   40  3F  1D  00  00  00  00  00
0180    Rx  8   35  F7  1E  00  00  00  00  00
0180    Rx  8   E6  B0  1F  00  00  00  00  00
0180    Rx  8   F8  2F  20  00  00  00  00  00

我包含了 id 0x180 和 0x185 的消息,它们具有相同的内容但不同的校验和,这使我相信消息 id 在某种程度上影响了校验和的计算。

我尝试使用reveng工具(https://reveng.sourceforge.io/)并可以获得“poly”,“init”和其他参数,这些参数是有效的并且适用于4条消息,但它们不起作用对于第 5 条消息,如果我对接下来的 4 条消息运行 reveng,我会得到相同的“poly”但不同的“init”参数。 例如:

reveng -w16 -s 00000000000065AB 010000000000B6EC 020000000000C324 0300000000001063
width=16  poly=0x887b  init=0xb372  refin=true  refout=true  xorout=0x0000  check=0x81e8  residue=0x0000  name=(none)

reveng -w16 -s 04000000000008A4 050000000000DBE3 060000000000AE2B 0700000000007D6C
width=16  poly=0x887b  init=0x1ea4  refin=true  refout=true  xorout=0x0000  check=0x35c0  residue=0x0000  name=(none)

每条消息的初始化参数似乎不太可能发生变化。所以我错过了一些东西。

我也阅读并尝试了本文中描述的方法(https://www.csse.canterbury.ac.nz/greg.ewing/essays/CRC-Reverse-Engineering.html),虽然校验和有相同位的相同异或结果发生了变化,它没有为我提供任何关于如何计算这些校验和的进一步线索。

我还在这里阅读了类似的问题(Unknown CRC Calculation),并编译了提供的答案,但无法复制问题中的结果。

#include <stddef.h>

// Return a with the low 16 bits reversed and any bits above that zeroed.
static unsigned rev16(unsigned a) {
    a = (a & 0xff00) >> 8 | (a & 0x00ff) << 8;
    a = (a & 0xf0f0) >> 4 | (a & 0x0f0f) << 4;
    a = (a & 0xcccc) >> 2 | (a & 0x3333) << 2;
    a = (a & 0xaaaa) >> 1 | (a & 0x5555) << 1;
    return a;
}

// Implement the CRC specified in the BASECAM SimpleBGC32 2.6x serial protocol
// specification. Return crc updated with the length bytes at message. If
// message is NULL, then return the initial CRC value. This CRC is like
// CRC-16/ARC, but with the bits reversed.
//
// This is a simple bit-wise implementation. Byte-wise and word-wise algorithms
// using tables exist for higher speed if needed. Also this implementation
// chooses to reverse the CRC bits as opposed to the data bits, as done in the
// specficiation appendix. The CRC only needs to be reversed once at the start
// and once at the end, whereas the alternative is reversing every data byte of
// the message. Reversing the CRC twice is faster for messages with length
// greater than two bytes.
unsigned crc16_simplebgc(unsigned crc, void const *message, size_t length) {
    if (message == NULL)
        return 0;
    unsigned char const *data = message;
    crc = rev16(crc);
    for (size_t i = 0; i < length; i++) {
        crc ^= data[i];
        for (int k = 0; k < 8; k++)
            crc = crc & 1 ? (crc >> 1) ^ 0x887b : crc >> 1;
            //crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1;
    }
    return rev16(crc);
}

#include <stdio.h>

// Example usage of crc_simplebgc(). A CRC can be computed all at once, or with
// portions of the data at a time.
int main(void) {
    unsigned crc = crc16_simplebgc(0, NULL, 0);         // set initial CRC
    //crc = crc16_simplebgc(crc, "\x01\x85", 2);      // message id
    //crc = crc16_simplebgc(crc, "\x08", 1);      // message length
    crc = crc16_simplebgc(crc, "\x00\x00\x00\x00\x00\x00", 6);      // message content
    printf("%04x\n", crc);                              // expecting 65AB
    return 0;
}

我在 python 中也有一些代码来测试数据列表,但是如果没有正确的 crc 函数参数,它是无用的。

最终我想在node-red函数中使用它,所以我需要在javascript中使用它,但我认为一旦我有了任何语言的工作代码,我就可以自己做到这一点。

crc crc16
1个回答
0
投票

这两个字节确实看起来是其他位的 GF(2) 的线性函数。 CRC 属于该类,但它比 CRC 更通用。我没有找到表明它们是 CRC 的位排序。我所能得到的只是变化的位的线性函数。

因此,对于在这些位中变化的一个数据字节的六位中的每一位,您将取每一位,并将此表中的 16 位值异或在一起以获得校验字节,对于地址

0180
:

20: 687b
10: b43d
08: da1e
04: 6d0f
02: a68f
01: d347

如果地址是

0185
,那么也异或这个值:

5: f5ff

然后将结果与

9054
进行异或。

这是简单地通过行减少来确定的。

© www.soinside.com 2019 - 2024. All rights reserved.