Python学习笔记10:CRC32

基本概念
CRC全称是循环冗余校验(Cyclic Redundancy Check)。
在数据传输过程中,无论传输系统的设计再怎么完美,差错总会存在,这种差错可能会导致在链路上传输的一个或者多个帧被破坏(出现比特差错,0变为1,或者1变为0),从而接受方接收到错误的数据。为尽量提高接受方收到数据的正确率,在接收方接收数据之前需要对数据进行差错检测,当且仅当检测的结果为正确时接收方才真正收下数据。
CRC是一种用于校验通信链路上数字传输准确性的计算方法(通过某种数学运算来建立数据位和校验位的约定关系)。发送方计算机使用某公式计算出被传送数据所含信息的一个值,并将此值附在被传送数据后,接收方计算机则对同一数据进行相同的计算,应该得到相同的结果。如果这两个CRC结果不一致,则说明发送中出现了差错,接收方计算机可要求发送方计算机重新发送该数据。
CRC是一种数据错误检查技术,是一种常用的检错码,但并不能用于自动纠错。

多项式
了解了CRC的基本概念,那么接下来就要知道多项式的概念了。
以这个IEEE802.3标准CRC32多项式为例:x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x+ 1
x32则对应32bit = 1, x26则对应26bit=1,得出一个值:(1<<32)|(1<<26)|(1<<23)|(1<<22)|…|(1<<1)|(1)=0x104C11DB7,对于CRC32取低32位,则=0x4C11DB7
一般是用这个值通过一定方法生成长度为256的码表,对于CRC32,表内每个元素都为32bit。然后再用一定的方法查表最后得出CRC32值。

为什么用查表这种方法呢?因为,世界上一共就256个字符,每装载一个就运算一遍,很浪费CPU资源,不如直接把每个字符的CRC都算出来存入数组。因此,就有了CRC编码字符表。

接下来我们看下最终实现代码:

# 定义一个256个元素的全0数组
custom_crc32_table = [0 for x in range(0,256)]

def generate_crc32_table():
    for i in range(256):
        c = i << 24

        for j in range(8):
            if (c & 0x80000000):
                c = (c << 1) ^ 0x04C11DB7
            else:
                c = c << 1

        custom_crc32_table[i] = c & 0xffffffff


def getCrc32(bytes_arr):
    length = len(bytes_arr)

    if bytes_arr != None:
        crc = 0xffffffff
        for i in range(0, length):
            crc = (crc << 8) ^ custom_crc32_table[(getReverse(bytes_arr[i], 8) ^ (crc >> 24)) & 0xff]
    else:
        crc = 0xffffffff

    # - 返回计算的CRC值 
    crc = getReverse(crc ^ 0xffffffff, 32)
    return crc


def getReverse(tempData, byte_length):
    reverseData = 0
    for i in range(0, byte_length):
        reverseData += ((tempData>>i)&1)<<(byte_length-1-i)
    return reverseData

我们再来看看使用反转后的多项式(0xEDB88320)代码实现:

# 定义一个256个元素的全0数组
reversal_crc32_table = [0 for x in range(0,256)]

def reversal_init_crc32_table():
    for i in range(256):
        c = i

        for j in range(8):
            if (c & 0x00000001):
                c = (c >> 1) ^ 0xEDB88320
            else:
                c = c >> 1

        reversal_crc32_table[i] = c & 0xffffffff


def reversal_getCrc32(bytes_arr):
    length = len(bytes_arr)

    if bytes_arr != None:
        crc = 0xffffffff
        for i in range(0, length):
            crc = (crc >> 8) ^ reversal_crc32_table[ (bytes_arr[i] ^ crc) & 0xff ]
    else:
        crc = 0xffffffff

    crc = crc ^ 0xffffffff
    return crc

测试代码:

if __name__ == "__main__":    
    import struct
    import zlib
    import binascii

    s = struct.pack('>i', 400)
    print('当前CRC输入初始值:', (s, type(s)))
    test = binascii.crc32(s) & 0xffffffff
    print('算出来的CRC值:', '0x'+"{:0>8s}".format(str('%x'%test)))
    test = zlib.crc32(s) & 0xffffffff
    print('算出来的CRC值:', '0x'+"{:0>8s}".format(str('%x'%test)))

    
    buf_s = [0x00, 0x00, 0x01, 0x90]

    generate_crc32_table()
    crc_stm = getCrc32(bytearray(buf_s)) & 0xffffffff
    print('算出来的CRC值:', '0x' + "{:0>8s}".format(str('%x' % crc_stm)))


    reversal_init_crc32_table()
    crc_stm = reversal_getCrc32(bytearray(buf_s)) & 0xffffffff
    print('反转算出来的CRC值:', '0x' + "{:0>8s}".format(str('%x' % crc_stm)))

再看看最终的运行结果:

当前CRC输入初始值: (b'\x00\x00\x01\x90', <class 'bytes'>)
算出来的CRC值: 0xc8507d19
算出来的CRC值: 0xc8507d19
算出来的CRC值: 0xc8507d19
反转算出来的CRC值: 0xc8507d19
上一篇:我的Modbus Slave/Client开发历程(Rtu/AscII/Tcp)


下一篇:痞子衡嵌入式:探析开启CRC完整性校验的IAR工程生成.out和.bin文件先后顺序