CRCアルゴリズムの導出とc++コードの実現(エッセンス)
26017 ワード
CRCアルゴリズムの導出とc++コードの実現(エッセンス)
背景知識:
ウィキペディア
CRC計算の関係式:
M(x)∗(x n)=Q(x)∗K(x)−R(x)M(x)*(x^n)=Q(x)*K(x)−R(x)M(x)∗(xn)=Q(x)∗K(x)−R(x)のうち: M(x)は元の情報多項式であり、元の情報は2進数で表される.例えば101は多項式に対応する係数1∗(x 2)+0∗(x 1)+1∗(x 0)=x 2+1∗(x^2)+0*(x^1)+1*(x^0)=x^2+1∗(x 2)+0∗(x 0)=x^2+1 K(x)はn次の特徴多項式である.すなわち、K(x)の最上位はnであり、CRC 16,n=16のようなx n x^n xn項を必ず含む.最上位はx 16 x^{16}x 16 を含む. R(x)は、剰余多項式、すなわちCRC検査結果 である. Q(x)はM(x)∗(x)/K(x)M(x)*(x^n)/K(x)M(x)∗(xn)/K(x)の商 である
送信側送信データ:M(x)∗(x n)+R(x)M(x)*(x^n)+R(x)M(x)∗(xn)+R(x)、すなわちM(x)左シフトnビット+CRCチェックR(x)
受信者検証データ:1計算M(x)∗(xn)+R(x)M(x)*(x^{n})+R(x)M(x)∗(xn)+R(x)がK(x)で割り切れるかどうか、残数は0、正しいデータが受信され、残数は0ではなく、エラーデータ が受信される2計算M(x)のCRC検査結果がR(x)であるかどうか、検査は同じ、データは正しい、検査は異なるデータエラー である.
例CRC-16-BM、Modbusプロトコル:特徴多項式x 16+x 15+x 2+1 x^{16}+x^{15}+x^{2}+1 x 16+x 15+x 25+x 2+1対応多項式係数=1 1,000,000,000,000,0101すなわち2進法16,15,22 0位それぞれ1 16進式特徴多項式係数POLY=0 x 18005 CRC-16-つまり16ビット2進法を採用して16ビット下を切り取るのでPOLY=0 x 8005 入力データ: 以下は通信双方の約束です.計算の初期値:0 xFFFF 結果排他的論理和値:0 x 0000で計算された(CRC-16)排他的論理和0 x 0000 入力データ反転:true 出力データ(CRC-16)反転:true 分析計算:入力データ:M(x)= 特徴多項式:K(x)= nの値:K(x)の最高次n=16 M(x)∗x n=M(x)∗x 16 M(x)*x^{n}=M(x)*x^{16}M(x)*x^{16}M(x)∗xn=M(x)∗x 16は、M(x)左シフト16ビットに相当する:M(x)∗x 16 M(x)*x^{16}M(x)*x^{16}M(x)∗x 16= 型2除算:M(x)∗x 16<型2÷>K(x)*x^{16}<型2÷>K(x)M(x)∗x 16<型2÷>K(x)= 商Q(x)=0 xfcae 141 a 剰余R(x)=0 xa 239 出力データ0 xa 239反転=0 x 9 c 45 結果(0 x 9 c 45異または0 x 0000)=0 x 9 c 45、すなわち最終的なCRC結果 多項式除算の例
入力データM(x)=1111 M(x)=1111 M(x)=1111 M(x)=1111除数K(x)=1101 K(x)=1101 K(x)=1101は最高次n=3次であり、x 3 x^{3}x 3 n=3 n=3 n=3 n=3を含むので、左シフト3ビット被除数M(x){8727; x 3)=1111000 M(x)*(x^{3})=1111 000 M(x){8727; x 3)=111000
したがって、CRCは、剰余CRC=01111(2進)=0 x 07(16進)である
C++コードは以下の通りです.
背景知識:
ウィキペディア
CRC計算の関係式:
M(x)∗(x n)=Q(x)∗K(x)−R(x)M(x)*(x^n)=Q(x)*K(x)−R(x)M(x)∗(xn)=Q(x)∗K(x)−R(x)のうち:
送信側送信データ:M(x)∗(x n)+R(x)M(x)*(x^n)+R(x)M(x)∗(xn)+R(x)、すなわちM(x)左シフトnビット+CRCチェックR(x)
受信者検証データ:
例CRC-16-BM、Modbusプロトコル:
0x7e 0x01 0x11 0x00
( , , 1100 0100 0010 0011)
(16 ) ( , , 1010 0010 0011 1001 1001 1100 0100 0101 )
0x7e 0x01 0x11 0x00
バイト毎反転M(x)=0x7e 0x80 0x88 0x00
2進数表示:M(x)=0111 1110 - 1000 0000 -1000 1000 - 0000 0000
0x80 0x05
2進数表現:K(x)=1000 0000 - 0000 0101
0x7e 0x80 0x88 0x00 0x00 0x00
2進数をM(x)*x^{16}M(x)*x^{16}M(x)*x^{16}M(x)M(x(x)*x^{16}M(x)M(x(x)x^x^∗x 16=0111 1110 - 1000 0000 - 1000 1000 - 0000 0000 - 0000 0000 - 0000 0000
0111 1110 - 1000 0000 - 1000 1000 - 0000 0000 - 0000 0000 - 0000 0000
/1000 0000 - 0000 0101
=0 xfcae 141 a+0 xa 239 入力データM(x)=1111 M(x)=1111 M(x)=1111 M(x)=1111除数K(x)=1101 K(x)=1101 K(x)=1101は最高次n=3次であり、x 3 x^{3}x 3 n=3 n=3 n=3 n=3を含むので、左シフト3ビット被除数M(x){8727; x 3)=1111000 M(x)*(x^{3})=1111 000 M(x){8727; x 3)=111000
111 1000 ---- M(x)=1111 ,n=3 , 3 M(x)*(x^3) = 1111 000
110 1 ---- K(x), n=3 , x^{3}
001 0000 1 1 , ( 2 ), 1
----------------------------------------------------------------------
-01 0000
-11 01
-01 0000 0 0 , ( 2 ), , 1
----------------------------------------------------------------------
--1 0000
--1 101
--0 1010 1 1 , ( 2 ), 1
----------------------------------------------------------------------
--- 1010
--- 1101
--- 0111 1 1 , ( 2 ),
: 1011 , 0111
したがって、CRCは、剰余CRC=01111(2進)=0 x 07(16進)である
C++コードは以下の通りです.
//--creater by wmx 2020 - 6 -14
#include
#include
typedef signed char qint8; /* 8 bit signed */
typedef unsigned char quint8; /* 8 bit unsigned */
typedef short qint16; /* 16 bit signed */
typedef unsigned short quint16; /* 16 bit unsigned */
typedef int qint32; /* 32 bit signed */
typedef unsigned int quint32; /* 32 bit unsigned */
/*!
* \brief calculate_crc16 16 CRC
* \param CRC_INIT CRC16
* \param CRC_POLY
* \param CRC_RESULT_XOR
* \param input_invert
* \param ouput_invert
* \param inputData
* \param inputDataLen
* \return 16 CRC
*/
quint16 calculate_crc16(quint16 CRC_INIT,quint16 CRC_POLY,quint16 CRC_RESULT_XOR,bool input_invert,bool ouput_invert,const char *inputData, int inputDataLen)
{
quint8 data_item = 0;
//--
quint32 ans = 0;
while (inputDataLen--)
{
data_item = *(inputData++);
// ( , , 1100 0100 0010 0011)
if(input_invert)
{
printf(" data_item = %02x
",data_item);
quint8 temp_char = data_item;
data_item=0;
for(int i=0;i<8;++i)
{
if(temp_char&0x01)
data_item|=0x01<<(7-i);
temp_char>>=1;
}
printf(" data_item = %02x
",data_item);
}
//--- ----------------------
//--- 2
//--- 2 CRC
// R(x)=CRC, CRC_INIT,
//data_item 16 , ,
CRC_INIT ^= (data_item << 8);
//-- 2
for (int i = 0; i < 8; i++)
{
//-- 16 2
if (CRC_INIT & 0x8000){//-- 1, 1, 2
CRC_INIT = (CRC_INIT << 1) ^ CRC_POLY;
ans += 1;
}
else{//-- 0, 0, , 2
CRC_INIT = CRC_INIT << 1;
ans += 0;
}
ans = ans<<1;
}
ans<<1;
}
printf(" ans = %02x
",ans);
printf(" CRC_INIT = %02x
",CRC_INIT);
// (16 ) ( , , 1010 0010 0011 1001 1001 1100 0100 0101 )
if(ouput_invert)
{
printf(" CRC_INIT = %02x
",CRC_INIT);
quint16 temp_short = CRC_INIT;
CRC_INIT=0;
for(int i=0;i<16;++i)
{
if(temp_short&0x01)
CRC_INIT|=0x01<<(15-i);
temp_short>>=1;
}
printf(" CRC_INIT = %02x
",CRC_INIT);
}
printf(" CRC_INIT^CRC_RESULT_XOR = %02x
",CRC_INIT^CRC_RESULT_XOR);
return (CRC_INIT^CRC_RESULT_XOR);
}
using namespace std;
int main(int argc, char *argv[])
{
char buf4[4]={0x7e,0x01,0x11,0x00};
char buf5[4]={0x7e,0x80,0x88,0x00};
quint16 result4 =calculate_crc16(0xFFFF,0x8005,0x0000,true,true,buf4,sizeof (buf4));
// quint16 result5 =calculate_crc16(0xFFFF,0x8005,0x0000,false,true,buf5,sizeof (buf5));
printf("result4 = %04x
",result4);
// printf("result5 = %04x
",result5);
return 0;
}