搜刮了下github,找到两个比较权威的仓库有crc5函数,其中CRC5_MSBfirst计算结果和图中一致可以参考下
opentitan/hw/dv/dpi/usbdpi/usb_crc.c at master · lowRISC/opentitan
wireshark/wsutil/crc5.c at master · wireshark/wireshark
示例代码:
- #include <stdint.h>
- #include <stdio.h>
- #define INT_SIZE 32 // Assumes 32-bit integer size
- uint32_t CRC5_MSBfirst(uint32_t dwInput, int iBitcnt) {
- const uint32_t poly5 = (0x05 << (INT_SIZE - 5));
- uint32_t crc5 = (0x1f << (INT_SIZE - 5));
- uint32_t udata = (dwInput << (INT_SIZE - iBitcnt));
-
- if ((iBitcnt < 1) || (iBitcnt > INT_SIZE)) { // Validate iBitcnt
- return 0xffffffff;
- }
-
- while (iBitcnt--) {
- if ((udata ^ crc5) & (0x1 << (INT_SIZE - 1))) { // bit4 != bit4?
- crc5 <<= 1;
- crc5 ^= poly5;
- } else {
- crc5 <<= 1;
- }
-
- udata <<= 1;
- }
-
- // Shift back into position
- crc5 >>= (INT_SIZE - 5);
-
- // Invert contents to generate crc field
- crc5 ^= 0x1f;
-
- return crc5;
- } // CRC5()
-
-
- /* This is the little endian version, so you can feed an 11 bit data
- * value and get back 5 bits to OR in to the top to construct 16 bits
- *
- * Adapted by mdhayter
- */
-
- uint32_t CRC5(uint32_t dwInput, int iBitcnt) {
- const uint32_t poly5 = 0x14;
- uint32_t crc5 = 0x1f;
- uint32_t udata = dwInput;
-
- if ((iBitcnt < 1) || (iBitcnt > INT_SIZE)) { // Validate iBitcnt
- return 0xffffffff;
- }
-
- while (iBitcnt--) {
- if ((udata ^ crc5) & 0x01) {
- crc5 >>= 1;
- crc5 ^= poly5;
- } else {
- crc5 >>= 1;
- }
-
- udata >>= 1;
- }
-
- // Invert contents to generate crc field
- crc5 ^= 0x1f;
-
- return crc5;
- } // CRC5()
-
- static uint8_t crc5_usb_bits(uint32_t v, int vl, uint8_t ival)
- {
- /* This function is based on code posted by John Sullivan to Wireshark-dev
- * mailing list on Jul 21, 2019.
- *
- * "One of the properties of LFSRs is that a 1 bit in the input toggles a
- * completely predictable set of register bits *at any point in the
- * future*. This isn't often useful for most CRC caculations on variable
- * sized input, as the cost of working out which those bits are vastly
- * outweighs most other methods."
- *
- * In USB 2.0, the CRC5 is calculated on either 11 or 19 bits inputs,
- * and thus this approach is viable.
- */
- uint8_t rv = ival;
- static const uint8_t bvals[19] = {
- 0x1e, 0x15, 0x03, 0x06, 0x0c, 0x18, 0x19, 0x1b,
- 0x1f, 0x17, 0x07, 0x0e, 0x1c, 0x11, 0x0b, 0x16,
- 0x05, 0x0a, 0x14
- };
- for (int i = 0; i < vl; i++) {
- if (v & (1 << i)) {
- rv ^= bvals[19 - vl + i];
- }
- }
- return rv;
- }
- uint8_t crc5_usb_11bit_input(uint16_t input)
- {
- return crc5_usb_bits(input, 11, 0x02);
- }
-
- int main() {
- uint8_t addr = 0x20;
- uint8_t endp = 0;
- uint32_t combined_data = ((uint32_t)addr << 4) | (endp & 0x0F); // 组合 7 位 ADDR 和 4 位 ENDP
- printf("combined_data 结果: 0x%04X\n", combined_data);
- uint8_t result = CRC5_MSBfirst(combined_data,11);
- printf("MSB CRC5 结果: 0x%02X\n", result);
- printf("MSB CRC5 ~结果: 0x%02X\n", (~result) & 0xFF);
- result = CRC5(combined_data,11);
- printf("LSB CRC5 结果: 0x%02X\n", result);
- printf("LSB CRC5 ~结果: 0x%02X\n", (~result) & 0xFF);
-
- auto x = crc5_usb_11bit_input(combined_data);
- printf("crc5_usb_11bit_input LSB 结果: 0x%02X\n", x);
- return 0;
- }
复制代码
|