CRC循环冗余校验详解
简介
参考:
https://www.bilibili.com/video/BV1V4411Z7VA?from=search&seid=3373767585328853317&spm_id_from=333.337.0.0 [引用1]
这个视频里讲的很明了透彻,本文章前两节主要是对该视频内容做的笔记。
CRC循环冗余校验在线计算:http://www.ip33.com/crc.html [引用二]
https://blog.youkuaiyun.com/C_Silence_K/article/details/105791642?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163323676916780261969661%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=163323676916780261969661&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-2-105791642.first_rank_v2_pc_rank_v29&utm_term=crc%E5%88%9D%E5%A7%8B%E5%80%BC%E8%AF%A6%E7%BB%86%E8%A7%A3%E9%87%8A&spm=1018.2226.3001.4187 [引用三]
第三、四节以网上的CRC校验在线计算为例,进行详细分析和实现。
1、CRC手动演算
2、CRC的直观运算过程
3、在线计算网站界面各要素分析
INIT:这是算法开始时寄存器(crc)的初始化预置值,十六进制表示。 Init 的位数和多项式的位数相同,它的值为全0或者全F,当全为0时,在算法开始前对数据(这个数据是根据RefIn的值得到的)后面补上CRC位数个0后就可以进行后续计算了。当全为1时,表示在算法开始前对数据的前CRC位数(高位)先和对应位数个1进行异或(即:前CRC位数的值按位取反),再在后面补上CRC位数个0,才进行后续计算。
RefIn为False表示,输入的原始数据的每个字节的第7位作为最高有效位,第0为作为最低有效位,即正常计算即可。
当RefIn为True时,输入的原始数据的每个字节需要做个逆序的处理,注意:针对的每个字节,而不是整个数据。
当Refout为False时,输出不做处理,当Refout为True,需要对输出数据做一次整个数据的逆序处理,注意:这里做的逆序和RefIn不同,它不是按字节逆序,而是整个逆序。
参考自[引用三]
crc_4的代码实现
crc.h
#include <stdio.h>
#define DEBUG_CRC
uint8_t crc_4(uint32_t* pdata, uint32_t len);
uint8_t crc_8(uint32_t* pdata, uint32_t len);
enum CRC_NUM{
CRC_DATA_FORMAT_ERROR = 0,
CRC_SUCCESS
};
crc.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "crc.h"
uint32_t crc_polynomical_4[4] = {0,0,1,1};
uint32_t crc_polynomical_8[8] = {0,0,0,0,0,1,1,1};
uint8_t crc_4(uint32_t* pdata, uint32_t len){
uint32_t i = 0,j = 0,k = 0,tmp = 0;
uint8_t crc = 0;
uint32_t crc_tmp[4] = {0};
if((len-4) % 8 != 0) return CRC_DATA_FORMAT_ERROR;
#ifdef DEBUG_CRC
printf("original bit stream:");
for(i=0;i<len-4;i++){printf("%d ",pdata[i]);}
printf("\n");
#endif
for(i=0;i<(len-4)/8;i++){ /* reverse bit of input data in a byte */
for(j=0;j<4;j++){
tmp = pdata[i+j];
pdata[i+j] = pdata[i+7-j];
pdata[i+7-j] = tmp;
}
}
#ifdef DEBUG_CRC
printf("reverse bit stream:");
for(i=0;i<len-4;i++){printf("%d ",pdata[i]);}
printf("\n");
#endif
for (i=0;i<(len-4);i++) /* crc calculate process */
{
if(pdata[i] == 1){
for(j=i+1,k=0;j<=i+4,k<4;j++,k++){
pdata[j] ^= crc_polynomical_4[k];
}
}
}
for(j=0;j<4;j++){ /* get result in byte */
crc_tmp[j] = pdata[i+j];
}
#ifdef DEBUG_CRC
printf("original result:");
for(j=0;j<4;j++){
printf("%d ",crc_tmp[j]);
if(j == 3) printf("\n");
}
#endif
for(i=0;i<2;i++){ /* reverse result,get final result */
tmp = crc_tmp[i];
crc_tmp[i] = crc_tmp[3-i];
crc_tmp[3-i] = tmp;
}
#ifdef DEBUG_CRC
printf("reverse result:");
for(j=0;j<4;j++){
printf("%d ",crc_tmp[j]);
if(j == 3) printf("\n");
}
#endif
return CRC_SUCCESS;
}
uint8_t crc_8(uint32_t* pdata, uint32_t len)
{
}
main.c
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include "crc.h"
/* mainly function */
uint8_t crc_original_data_analysize(char* data,uint32_t len,uint8_t* recv_data,uint32_t recv_len,uint32_t* real_len);
uint8_t crc_bit_int(uint8_t* bit_data,uint32_t bit_len,uint32_t* int_data,uint32_t int_len);
/* tool function */
uint8_t char2value_hex(char c){
if(c >= '0' && c<= '9') return (c-'0');
else if(c >= 'a' && c <= 'f') return (c-'a'+10);
else if(c >= 'A' && c <= 'F') return (c-'A'+10);
else return -1;
}
int main(){
char crc_char[1024] = {0};
uint8_t crc_data[1024] = {0};
uint32_t real_len;
uint32_t crc_int[1024*8] = {0};
printf("Please input original data(hex):");
scanf("%s",crc_char);
crc_original_data_analysize(crc_char,strlen(crc_char),crc_data,1024,&real_len);
#ifdef DEBUG_CRC
printf("the data(dec,previous length:%ld (char),real length:%d (uint8_t):",strlen(crc_char),real_len);
for(uint32_t i=0;i<real_len;i++){
printf("%02d ",crc_data[i]);
}
printf("\n");
#endif
crc_bit_int(crc_data,real_len,crc_int,1024*8);
#ifdef DEBUG_CRC
printf("now every bit occupies a int:");
for(uint32_t i=0;i<real_len * 8;i++){
printf("%d ",crc_int[i]);
}
printf("\n");
#endif
/* '+4' mean that append four zero in the end,notice that real_len*8 must be smaller than 1024*8-4 */
crc_4(crc_int,real_len*8+4);
return 0;
}
uint8_t crc_original_data_analysize(char *data,uint32_t len,uint8_t* recv_data,uint32_t recv_len,uint32_t* real_len){
uint32_t cnt=0,recv_cnt = 0;
char data_tmp[2] = {0};
uint8_t status = 0;
if(recv_len < len)
return 1;
while(cnt<len){
if(data[cnt] == ' '){
if(status == 0){cnt++;}
else {return 2;}
}
else{
if(status == 0){status = 1;data_tmp[0] = data[cnt];cnt++;continue;}
if(status == 1){
status = 0;
data_tmp[1] = data[cnt];
recv_data[recv_cnt] = char2value_hex(data_tmp[0])*16+char2value_hex(data_tmp[1]);
cnt++;recv_cnt++;
}
}
}
*real_len = recv_cnt;
return 0;
}
uint8_t crc_bit_int(uint8_t* bit_data,uint32_t bit_len,uint32_t* int_data,uint32_t int_len){
if(int_len < bit_len*8) return 1;
for(uint32_t i=0;i<bit_len;i++){
for(uint32_t j=0;j<8;j++){
int_data[i*8+j] |= (bit_data[i] >> (7-j)) & 0x01;
}
}
return 0;
}
代码中我之所以把比特改为uint32_t类型进行处理,是因为4字节长度,现在的处理器更容易处理。
本来想把CRC-32的代码也写了,但是就是有点懒。。