CRC-CCITT

以前、チェックサムについて記述しましたが、単なるチェックサムでは、少々、信頼性が低いということで、もう少し頑張ったエラーチェック方法としてCRC-CCITTというのがあります。
そもそも、チェックサムが駄目で、CRC-CCITTならOKというシステムでは、通信の信頼性の観点からは、もっと根本的な所(配線まわりやノイズ)をチェックすべし!という突っ込みもありますが、ひとつの手法として紹介します。

          • -

(1) 計算方法
1. CRC格納レジスタ(2byte)を0でクリアする
2. 計算するメモリ長分ループ処理を行う
[ループ処理]
1. データ(1byte)を読みこむ
2. 8回(8bit分)ループ
 [ループ処理]
1. CRC格納レジスタを1ビット左シフト
2. 読み込みデータに対しLSBからMSBの方向に値の捜査を行う。読み込みデータの操作対象ビットが1の場合CRC格納レジスタの値を+1
3.捜査対象ビットを1ビット右シフト
4. 1.の左シフトの結果MSBがキャリーオーバーしている場合0x1021をCRC格納レジスタの値に対しXOR
[ループ処理終了]
[ループ処理終了]
3. 完成

(2) 実装アルゴリズム
unsigned short getCRCCCITT(unsigned char in_array[], int in_arraySize) {
unsigned short vCRC = 0x0000;
unsigned char vData = 0x00;

int i = 0;
int j = 0;

for (i = 0; i < in_arraySize; i++) {
unsigned char tmpShifter = 0x80;
vData = in_array[i];

for (j = 0; j < 8; j++) {
unsigned char tmpCarryFlag = 0x00;

// vCRC操作
if ((vCRC & 0x8000) != 0x0000) {
tmpCarryFlag = 0x01;
}
vCRC <<= 1;

// vData操作
if ((vData & tmpShifter) != 0x00) {
vCRC ^= 0x0001;
}
tmpShifter >>= 1;

if (tmpCarryFlag == 0x01) {
vCRC ^= 0x1021;
}
}
}
return vCRC;
}

(3) 計算例
ACKパケットの生成例
ACKパケット構造:{ 0x06, 0x01, 0x**, 0x** }
CRC生成配列:{ 0x06, 0x01, 0x00, 0x00 }(CRCが入る箇所は0でクリア)

CRC:0xBA87
ACKパケット:{ 0x06, 0x01, 0x87, 0xBA }

          • -