我这几天看了下CRC具体校验原理,我看网上都没有一个通用的CRC库,都是一个函数写一种校验方式的那种,以下代码是随手写的一个通用的CRC软件模块, 支持最小单位字节的输入,有问题大家一起讨论。
#ifndef __CRC_H
#define __CRC_H
#include <stdint.h>
typedef enum
{
CRC4_ITU,
CRC5_EPC,
CRC5_ITU,
CRC5_USB,
CRC6_ITU,
CRC7_MMC,
CRC8,
CRC8_ITU,
CRC8_ROHC,
CRC8_MAXIM,
CRC16_IBM,
CRC16_MAXIM,
CRC16_USB,
CRC16_MODBUS,
CRC16_CCITT,
CRC16_CCITT_FALSE,
CRC16_X25,
CRC16_XMODEM,
CRC16_DNP,
CRC32,
CRC32_MPEG2,
CRC_TYPE_NUM,
} E_CRC_TYPE;
typedef struct
{
E_CRC_TYPE Crc_Type;
uint8_t Crc_Width;
uint8_t Crc_InputInvert;
uint8_t Crc_OutputInvert;
uint32_t Crc_Poly;
uint32_t Crc_Init_Value;
uint32_t Crc_Xorout;
} CRC_TYPE;
uint32_t calc_crc(E_CRC_TYPE crc_type, uint8_t *pData, uint16_t u16Len);
#endif
#include "crc.h"
CRC_TYPE crc_map[] = {
{CRC4_ITU, 4, TRUE, TRUE, 0x03, 0x00, 0x00},
{CRC5_EPC, 5, FALSE, FALSE, 0x09, 0x09, 0x00},
{CRC5_ITU, 5, TRUE, TRUE, 0x15, 0x00, 0x00},
{CRC5_USB, 5, TRUE, TRUE, 0x05, 0x1F, 0x1F},
{CRC6_ITU, 6, TRUE, TRUE, 0x03, 0x00, 0x00},
{CRC7_MMC, 7, FALSE, FALSE, 0x09, 0x00, 0x00},
{CRC8, 8, FALSE, FALSE, 0x07, 0x00, 0x00},
{CRC8_ITU, 8, FALSE, FALSE, 0x07, 0x00, 0x55},
{CRC8_ROHC, 8, TRUE, TRUE, 0x07, 0xFF, 0x00},
{CRC8_MAXIM, 8, TRUE, TRUE, 0x31, 0x00, 0x00},
{CRC16_IBM, 16, TRUE, TRUE, 0x8005, 0x0000, 0x0000},
{CRC16_MAXIM, 16, TRUE, TRUE, 0x8005, 0x0000, 0xFFFF},
{CRC16_USB, 16, TRUE, TRUE, 0x8005, 0xFFFF, 0xFFFF},
{CRC16_MODBUS, 16, TRUE, TRUE, 0x8005, 0xFFFF, 0x0000},
{CRC16_CCITT, 16, TRUE, TRUE, 0x1021, 0x0000, 0x0000},
{CRC16_CCITT_FALSE, 16, FALSE, FALSE, 0x1021, 0xFFFF, 0x0000},
{CRC16_X25, 16, TRUE, TRUE, 0x1021, 0xFFFF, 0xFFFF},
{CRC16_XMODEM, 16, FALSE, FALSE, 0x1021, 0x0000, 0x0000},
{CRC16_DNP, 16, TRUE, TRUE, 0x3D65, 0x0000, 0xFFFF},
{CRC32, 32, TRUE, TRUE, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF},
{CRC32_MPEG2, 32, FALSE, FALSE, 0x04C11DB7, 0xFFFFFFFF, 0x00000000},
};
static void Data_Bit_Invert(uint8_t *OutBuf, uint8_t *InBuf, uint8_t Bit_Len)
{
uint8_t i;
uint32_t Intmp = 0;
uint32_t Outtmp = 0;
if((void*)0 == OutBuf || (void*)0 == InBuf || 32 < Bit_Len)
{
return;
}
for(i = 0; i < Bit_Len / 8; i++)
{
Intmp |= (InBuf[i] << (i * 8));
}
if(0 != Bit_Len%8)
{
Intmp |= ((InBuf[i] << (i * 8)) & ((0xFF >> (8 - (Bit_Len % 8))) << (i * 8)));
}
for(i = 0; i < Bit_Len; i++)
{
if(Intmp & (1 << i))
{
Outtmp |= (1 << (Bit_Len - 1 - i));
}
}
for(i = 0; i < Bit_Len / 8; i++)
{
OutBuf[i] = ((Outtmp >> (i * 8)) & 0xFF);
}
if(0 != Bit_Len % 8)
{
OutBuf[i] &= (~(0xFF >> (8 - (Bit_Len % 8))));
OutBuf[i] |= ((Outtmp >> (i * 8)) & (0xFF >> (8 - (Bit_Len % 8))));
}
}
uint32_t calc_crc(E_CRC_TYPE crc_type, uint8_t *pData, uint16_t u16Len)
{
uint8_t tmpdata = 0;
uint8_t Crc_Width = crc_map[crc_type].Crc_Width;
uint8_t Crc_InputInvert = crc_map[crc_type].Crc_InputInvert;
uint8_t Crc_OutputInvert = crc_map[crc_type].Crc_OutputInvert;
uint32_t Crc_Poly = crc_map[crc_type].Crc_Poly;
uint32_t Crc_Init_Value = crc_map[crc_type].Crc_Init_Value;
uint32_t Crc_Xorout = crc_map[crc_type].Crc_Xorout;
uint32_t u32CrcVal = 0;
if ((void*)0 == pData || 0 == u16Len || CRC_TYPE_NUM <= crc_type)
{
return u32CrcVal;
}
u32CrcVal = Crc_Init_Value;
while(u16Len--)
{
if(TRUE == Crc_InputInvert)
{
Data_Bit_Invert(&tmpdata, pData, 8);
}
else
{
tmpdata = *pData;
}
if(Crc_Width >= 8)
{
u32CrcVal ^= (tmpdata << (Crc_Width - 8));
}
else
{
u32CrcVal <<= (8 - Crc_Width);
u32CrcVal ^= tmpdata;
}
for (uint8_t i = 0; i < 8; i++)
{
if(Crc_Width >= 8)
{
if (u32CrcVal & (0x00000001 << (Crc_Width - 1)))
{
u32CrcVal <<= 1;
u32CrcVal ^= Crc_Poly;
}
else
{
u32CrcVal <<= 1;
}
}
else
{
if (u32CrcVal & (0x00000001 << 7))
{
u32CrcVal <<= 1;
u32CrcVal ^= (Crc_Poly << (8 - Crc_Width));
}
else
{
u32CrcVal <<= 1;
}
}
}
if(Crc_Width >= 8)
{
}
else
{
u32CrcVal >>= (8 - Crc_Width);
}
u32CrcVal &= (0xFFFFFFFF >> (8 * sizeof(uint32_t) - Crc_Width));
pData++;
}
if(TRUE == Crc_OutputInvert)
{
Data_Bit_Invert((uint8_t*)&u32CrcVal, (uint8_t*)&u32CrcVal, Crc_Width);
}
u32CrcVal ^= Crc_Xorout;
return u32CrcVal;
}