|
楼主 |
发表于 2019-9-20 23:33:56
|
显示全部楼层
本帖最后由 canspider 于 2019-9-20 23:49 编辑
本文中的CRC计算都是右移计算的,实际上有左移也有右移,这些计算都可以通过右移来实现。完整的CRC计算代码如下:
- uint32_t crc_calc(const void* data, int len, uint32_t init, uint32_t xor_out, uint32_t polynomial, int bit_count, uint32_t shift_right)
- {
- const uint8_t* pdata = (const uint8_t*)data;
- bits = bit_count;
- poly = rev_bits(polynomial, bit_count);
- init = rev_bits(init, bit_count);
- if (shift_right) {
- init = crc_fast(init, data, len);
- }
- else {
- for (int i = 0; i < len; i++) {
- init = crc_1byte(init, rev_bits(pdata[i], 8) & 0xfful);
- }
- init = rev_bits(init, bit_count);
- }
- init ^= xor_out;
- init &= (uint32_t)((1ull << bit_count) - 1);
- return init;
- }
复制代码
指定初始值,输出是否需要异或,多项式,位数以及右移计算还是左移计算。
一般多项式的最高位在左边,因此右移计算时需要先将多项式和初始值反向。如果是右移计算,直接调用快速计算函数。
如果是左移计算,按字节反转后再进行计算,并在计算完成后将结果反转。
最后根据需要将输出值进行异或。
此计算方式与网站 https://crccalc.com/ 上的计算结果一致。网站上默认为左移,所以RefIn为true的时候表示反向,是右移。
如果采用标准CRC,能在这里面找到结果。
一些计算标准CRC值的例子
- printf("============== CRC8 results ============\n");
- printf("CRC8 = 0x%02X\n", crc_calc(data, len, 0x00, 0x00, 0x07, 8, LEFT));
- printf("CRC8/CDMA200 = 0x%02X\n", crc_calc(data, len, 0xff, 0x00, 0x9b, 8, LEFT));
- printf("CRC8/DARC = 0x%02X\n", crc_calc(data, len, 0x00, 0x00, 0x39, 8, RIGHT));
- printf("CRC8/DVB-S2 = 0x%02X\n", crc_calc(data, len, 0x00, 0x00, 0xd5, 8, LEFT));
- printf("CRC8/EBU = 0x%02X\n", crc_calc(data, len, 0xff, 0x00, 0x1d, 8, RIGHT));
- printf("CRC8/I-CODE = 0x%02X\n", crc_calc(data, len, 0xfd, 0x00, 0x1d, 8, LEFT));
- printf("CRC8/ITU = 0x%02X\n", crc_calc(data, len, 0x00, 0x55, 0x07, 8, LEFT));
- printf("CRC8/MAXIM = 0x%02X\n", crc_calc(data, len, 0x00, 0x00, 0x31, 8, RIGHT));
- printf("CRC8/ROHC = 0x%02X\n", crc_calc(data, len, 0xff, 0x00, 0x07, 8, RIGHT));
- printf("CRC8/WCDA = 0x%02X\n", crc_calc(data, len, 0x00, 0x00, 0x9b, 8, RIGHT));
复制代码
- printf("============== CRC32 results ===========\n");
- printf("CRC-32 = 0x%08X\n", crc_calc(data, len, 0xFFFFFFFF, 0xFFFFFFFF, 0x04C11DB7, 32, RIGHT));
- printf("CRC-32/BZIP2 = 0x%08X\n", crc_calc(data, len, 0xFFFFFFFF, 0xFFFFFFFF, 0x04C11DB7, 32, LEFT));
- printf("CRC-32C = 0x%08X\n", crc_calc(data, len, 0xFFFFFFFF, 0xFFFFFFFF, 0x1EDC6F41, 32, RIGHT));
- printf("CRC-32D = 0x%08X\n", crc_calc(data, len, 0xFFFFFFFF, 0xFFFFFFFF, 0xA833982B, 32, RIGHT));
- printf("CRC-32/MPEG-2 = 0x%08X\n", crc_calc(data, len, 0xFFFFFFFF, 0x00000000, 0x04C11DB7, 32, LEFT));
- printf("CRC-32/POSIX = 0x%08X\n", crc_calc(data, len, 0x00000000, 0xFFFFFFFF, 0x04C11DB7, 32, LEFT));
- printf("CRC-32Q = 0x%08X\n", crc_calc(data, len, 0x00000000, 0x00000000, 0x814141AB, 32, LEFT));
- printf("CRC-32/JAMCRC = 0x%08X\n", crc_calc(data, len, 0xFFFFFFFF, 0x00000000, 0x04C11DB7, 32, RIGHT));
- printf("CRC-32/XFER = 0x%08X\n", crc_calc(data, len, 0x00000000, 0x00000000, 0x000000AF, 32, LEFT));
复制代码
根据CRC结果凑数据
当我们需要得到指定的CRC结果时,可以用反向计算的方式来凑出需要的数据。
具体做法是,先给出CRC计算方式、一串数据和一个结果,指定在数据中插入调整数据的位置,调整数据的长度与CRC位数一致。
先从头开始计算直到调整数据前CRC值,再从后向先前算出经过调整数据之后的CRC值,根据一前一后的CRC值得到调整数据。代码如下:
- uint32_t crc_patch(const void* pre_data, int pre_len, const void* post_data, int post_len, uint32_t init, uint32_t result)
- {
- uint32_t pre_result = crc_data(init, pre_data, pre_len);
- uint32_t post_result = result;
- int data_len = bits / 8;
- while (post_len >= data_len) {
- uint32_t data = 0;
- memcpy(&data, (char*)post_data + post_len - data_len, data_len);
- post_result = crc_rev(0, post_result) ^ data;
- post_len -= data_len;
- }
- while (post_len > 0) {
- uint32_t data = 0;
- memcpy(&data, (char*)post_data + post_len - 1, 1);
- data = rev_bits(data, 8);
- for (int i = 0; i < 8; i++) {
- post_result = crc_rev_1bit_init(data, post_result);
- data >>= 1;
- }
- post_len--;
- }
- return crc_rev(pre_result, post_result);
- }
复制代码 |
|