了解 CRC8 SAE J1850(正常)与 "Zero" 的结果

Understanding results of CRC8 SAE J1850 (normal) vs. "Zero"

我需要验证 CRC8-SAE-J1850 消息,因此编写了一个脚本,该脚本读取日志并需要从那里计算 CRC8(非零)以将它们与日志中的 CRC8 值匹配,然后检查哪个工具链中的步骤造成了麻烦。

无论如何,我花了一些时间研究文档、SO 帖子和其他人的源代码,但我想坚持使用 python 以便更轻松地进行文本处理和与我的其他工具的接口。

我在 sourceforge evansneath's Python CRC Implementation 上找到了一些非常直接的代码,想试一试,但我认为它没有按预期工作(也许我完全理解错误,但我被卡住了这里):

def crc(msg, div, code='11111111'):
    """Cyclic Redundancy Check
        Generates an error detecting code based on an inputted message and divisor in the form of a polynomial representation.
        Arguments:
        msg: The input message of which to generate the output code.
        div: The divisor in polynomial form. For example, if the polynomial of x^3 + x + 1 is given, this should be represented as '1011' in the div argument.
        code: This is an option argument where a previously generated code may be passed in. This can be used to check validity. If the inputted code produces an outputted code of all zeros, then the message has        no errors.
    Returns:
        An error-detecting code generated by the message and the given divisor.
    """

    msg = msg + code
    msg = list (msg)
    div = list (div)

    for i in range (len (msg) - len (code)):
        if msg[i] == '1':
            for j in range (len (div)):
               msg[i+j] = str ((int (msg[i+j])+int (div[j]))%2)

    return ''.join (msg[-len (code):])

#Testing:
# Use a divisor that simulates: CRC8 SAE J1850 x^8+x^4+x^3+x^2+x^0
div = '100011101'#0x1D with leading 1 as given by polynomial
msg = '10101001' # 0xA9, just for a Test

print('Input message:', hex(int(msg,2)))
print('Polynomial:', hex(int(div,2)))

o = '11111111'
z = '00000000'

code = crc(msg, div, o)

print('CRC8 code:', hex(int(code,2)))

# Test for output code of '00000000' respectively '11111111' proving that the function worked correctly
print('Success:', crc(msg, div, code) == o)

我使用这个生成器检查了结果: CRC Generator 这似乎是唯一具有 CRC8 SAE J1850 零和非零功能的。

现在是有趣的部分:对于零,上面的代码工作得很好。

不幸的是,我从我要检查的软件中获得的 CRC 代码已初始化并针对 0xFF ('11111111') 进行了检查,这两种工具都提供了完全不同的结果。 到目前为止,我什至无法在上面的脚本计算出的解决方案与网站计算出的解决方案之间找到一些不一致的问题(我认为这是最有可能的情况)或数学 link . 该网站符合软件的结果,但上面的 python 部分不符合。

任何人都可以指出我可能遗漏的文档还是另一个问题? 在网站上输入消息时,我已经检查了 MSB/LSB 问题,并尝试按照其他一些代码建议的那样使用 0xFE 进行初始化。但没有成功...然而,大多数示例都是零基础的,我没有问题。

编辑:

我检查了计算并手动完成了一个示例,并打印了每一步并取得了同样的效果。所以在数学上它似乎是正确的,但是除了附加一行“11111111”然后按位异或,然后移位直到再次出现前导,异或等...并吐出其余部分之外,SAE 在做什么?这一定是我这边的理解问题。

Test 1 ---------------------------
Input message: 0xa9
Polynome: 0x11d
['1', '0', '1', '0', '1', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', 1']
 /
['1', '0', '0', '0', '1', '1', '1', '0', '1']
 =
current message: ['1', '0', '1', '0', '1', '0', '0', '1', '1', '1', '1', '1', '1 ', '1', '1', '1']
shift 0 Bits
1 XOR 1 = 0
0 XOR 0 = 0
1 XOR 0 = 1
0 XOR 0 = 0
1 XOR 1 = 0
0 XOR 1 = 1
0 XOR 1 = 1
1 XOR 0 = 1
1 XOR 1 = 0
current message: ['0', '0', '1', '0', '0', '1', '1', '1', '0', '1', '1', '1', '1 ', '1', '1', '1']
shift 2 Bits
1 XOR 1 = 0
0 XOR 0 = 0
0 XOR 0 = 0
1 XOR 0 = 1
1 XOR 1 = 0
1 XOR 1 = 0
0 XOR 1 = 1
1 XOR 0 = 1
1 XOR 1 = 0
current message: ['0', '0', '0', '0', '0', '1', '0', '0', '1', '1', '0', '1', '1 ', '1', '1', '1']
shift 5 Bits
1 XOR 1 = 0
0 XOR 0 = 0
0 XOR 0 = 0
1 XOR 0 = 1
1 XOR 1 = 0
0 XOR 1 = 1
1 XOR 1 = 0
1 XOR 0 = 1
1 XOR 1 = 0
CRC8 code: 0xab

Reverse Calculation: Check
['1', '0', '1', '0', '1', '0', '0', '1', '1', '0', '1', '0', '1', '0', '1', '1']
 /
['1', '0', '0', '0', '1', '1', '1', '0', '1']
 =
current message: ['1', '0', '1', '0', '1', '0', '0', '1', '1', '0', '1', '0', '1', '0', '1', '1']
shift 0 Bits
1 XOR 1 = 0
0 XOR 0 = 0
1 XOR 0 = 1
0 XOR 0 = 0
1 XOR 1 = 0
0 XOR 1 = 1
0 XOR 1 = 1
1 XOR 0 = 1
1 XOR 1 = 0
current message: ['0', '0', '1', '0', '0', '1', '1', '1', '0', '0', '1', '0', '1', '0', '1', '1']
shift 2 Bits
1 XOR 1 = 0
0 XOR 0 = 0
0 XOR 0 = 0
1 XOR 0 = 1
1 XOR 1 = 0
1 XOR 1 = 0
0 XOR 1 = 1
0 XOR 0 = 0
1 XOR 1 = 0
current message: ['0', '0', '0', '0', '0', '1', '0', '0', '1', '0', '0', '0', '1', '0', '1', '1']
shift 5 Bits
1 XOR 1 = 0
0 XOR 0 = 0
0 XOR 0 = 0
1 XOR 0 = 1
0 XOR 1 = 1
0 XOR 1 = 1
0 XOR 1 = 1
1 XOR 0 = 1
0 XOR 1 = 1
CRC correct: True

通常使用这些参数定义 CRC:

width=8 poly=0x1d init=0xff refin=false refout=false xorout=0xff check=0x4b name="CRC-8/SAE-J1850"

crcgen 将采用它并生成 C 代码来计算 CRC。如果愿意,您可以轻松地将其翻译为 Python。这是来自 crcgen 的 C 中的按位例程:

#include <stdint.h>

unsigned crc8sae_j1850_bit(unsigned crc, unsigned char const *data, size_t len) {
    if (data == NULL)
        return 0;
    crc ^= 0xff;
    while (len--) {
        crc ^= *data++;
        for (unsigned k = 0; k < 8; k++)
            crc = crc & 0x80 ? (crc << 1) ^ 0x1d : crc << 1;
    }
    crc &= 0xff;
    crc ^= 0xff;
    return crc;
}

链接的 CRC 计算器页面上列出的 "ZERO" 版本具有这些参数,只需将初始值和 xorout 值更改为零即可:

width=8 poly=0x1d init=0x00 refin=false refout=false xorout=0x00 check=0x37 name="CRC-8/SAE-J1850-ZERO"

这是来自 crcgen 的 C 中的按位例程:

#include <stdint.h>

unsigned crc8sae_j1850_zero_bit(unsigned crc, unsigned char const *data, size_t len) {
    if (data == NULL)
        return 0;
    while (len--) {
        crc ^= *data++;
        for (unsigned k = 0; k < 8; k++)
            crc = crc & 0x80 ? (crc << 1) ^ 0x1d : crc << 1;
    }
    crc &= 0xff;
    return crc;
}

我解决了。

从未提及对于 SAE J1850,输入与 0xFF 异或。尽管 Mark Adler 提供的 C 代码在 crc ^= 0xff; 中准确说明了这一点,但它并没有帮助我理解我的问题所在。

这不是错误,我的代码工作正常,但这是我假设的前提。

这就是为什么 C 代码没有帮助我解决问题的原因,因为我从一开始就不明白这就是问题所在。

SAE J1850 计算的更正代码(XORin 0xFF,XORout 0xFF,非反射,非反向,多项式 0x1D)逐位如下。

代码的来源保留在 evensneath on github,我只是更改了输入。

def crc(msg, div, code='11111111'):
"""Cyclic Redundancy Check
Generates an error detecting code based on an inputted message
and divisor in the form of a polynomial representation.
Arguments:
    msg: The input message of which to generate the output code.
    div: The divisor in polynomial form. For example, if the polynomial
        of x^3 + x + 1 is given, this should be represented as '1011' in
        the div argument.
    code: This is an option argument where a previously generated code may
        be passed in. This can be used to check validity. If the inputted
        code produces an outputted code of all zeros, then the message has
        no errors.
Returns:
    An error-detecting code generated by the message and the given divisor.
"""
# Append the code to the message. If no code is given, default to '1111111'
# Uncomment every occurence of msg_XORIN if not CRC-8 SAE J1850 
msg_XORIN = [] # XOR the input before appending the code
msg_XORIN = [str((int(msg[i])+1) %2) for i in range(len(list(msg)))]
msg = msg_XORIN

div = list(div)
msg = list(msg) + list(code) # Convert msg and div into list form for easier handling

# Loop over every message bit (minus the appended code)
for i in range(len(msg)-len(code)):
    # If that messsage bit is not one, shift until it is.
    if msg[i] == '1':
        for j in range(len(div)):
            # Perform modulo 2 ( == XOR) on each index of the divisor
            msg[i+j] = str((int(msg[i+j])+int(div[j]))%2)

# Output the last error-checking code portion of the message generated

return ''.join(msg[-len(code):])

题中的测试用例可以继承。调用一次生成CRC,再次调用msg+生成的crc校验

好的来源:http://reveng.sourceforge.net/crc-catalogue/1-15.htm#crc.cat-bits.8