2021/12/14
C#でCRCを計算する
CRCとはCyclic Redundancy Checkの略で、通信データの破損検出の仕組みの一つです。
通信データをある値(生成多項式)で割り算して、余りをデータに付与して送信します。
受信側で再度計算して付与された余りが合っているかどうか確認し、合致しない場合は通信データ破損とみなします。
同じような誤り検出にチェックサムがありますが、チェックサムはデータを足し算した結果を付与します。
足し算よりは割り算の方が複雑なアルゴリズムとなり、その分信頼度は向上します。
Modbus通信やイーサネット通信などで使われているようです。
CRCの種類
CRCには以下のパラメータがあり、これらの値により計算値が異なってきます。
そのため、CRCと一言で言ってもたくさんの種類が存在しています。
- 計算bit数
- 生成多項式
- 初期値
- ビットシフト方向
例) CRC-16-IBM
- 計算bit数 : 16
- 生成多項式 : x16+x15+x2+1
- 初期値 : 0xFFFF
- ビットシフト方向 : 右
その他の種類については wikipediaに記述がありますので参照ください。
CRCの計算方法
CRCの計算方法は、「ビット演算方式」と「テーブル演算方式」があります。
ビット演算方法: 通信データをその都度割り算して余りを求める方法
テーブル演算方法: あらかじめ計算結果のテーブルを準備して、計算負荷を軽くする方法
以降は、CRC-16-IBMのビット演算方式の計算をC#で実施してみます。
(Modbus-RTUで使われているものです)
計算コード
//CRC計算(CRC16-IBM / 生成多項式:x16+x15+x2+1, initial value is 0xFFFF, 右回り)
int[] DATA;
int CRC = 0xffff;
int CRC16POLY = 0xa001;
foreach (byte i in Data)
{
CRC ^= i;
for (var j = 0; j < 8; j++)
{
if ((CRC & 1) == 1)
{
CRC >>= 1;
CRC ^= CRC16POLY;
}
else
{
CRC >>= 1;
}
}
}
//最終的に、CRCに計算結果が代入されています。
githubにサンプルコードを上げていますので、よろしければ参照ください。
github
計算コードの解説
コードで実施している内容は下記になります。
データを生成多項式で割り算しています。
- 初期値”0xFFFF”と、送信データ値の最初の1byte目をXORする。
- 右へ1ビットシフトする。
- CF(キャリーフラグ)=1の場合、”0xA001”とXORする。CF=0の場合、何もしない。
- 上記2と3を8回繰り返す。
- 送信データの次の1byteとXORする。
- 上記2から5を、送信データの最後のbyteまで繰り返す。
以上です。