pycrc.py でCRC計算コードを生成する
pycrc.py でCRC計算コードを生成する
CRC(=Cyclic Redundancy Code) は誤り検出符号の一種だが、用途によっていろんな方法が存在する。
CRC計算によっては、計算に必要なパラメータが異なり、必要になるたびに自前で実装するのは面倒だし、既存のコードを利用するにもライセンスに気を付ける必要がある。
pycrcはCRC計算を行うC言語のソースコードを生成してくれるジェネレータである。
引数を指定して実行することで、Cのソースコードと対応するヘッダを生成してくれる。
https://pycrc.org/ から tar.gz または zip ファイルをダウンロードして展開する。
注意
ややこしいのですが、pycrc とは別に、PyCRC というモジュールもある。
この記事で紹介するのは、pycrcでこちらは MIT ライセンスである。
PyCRC は GPLv3 ライセンスである。PyCRC に関しては調査してない。
コード生成
CRC-32 の計算コードを生成する
python3 の場合
python3 pycrc.py --model crc-32 --algorithm table-driven --generate h -o crc.h
python3 pycrc.py --model crc-32 --algorithm table-driven --generate c -o crc.c
このコードでは python の binascii.crc32 および zlib の crc32 と同じ CRC の計算コードを生成する。
参考: python の場合
python pycrc.py --model crc-32 --algorithm table-driven --generate h -o crc.h
python pycrc.py --model crc-32 --algorithm table-driven --generate c -o crc.c
または
./pycrc.py --model crc-32 --algorithm table-driven --generate h -o crc.h
./pycrc.py --model crc-32 --algorithm table-driven --generate c -o crc.c
生成したコードを利用する
生成したヘッダファイルにサンプルコードが記載されている、また tutorial の Write the main file にもあるとおり、crc_init
で初期化して、crc_update
で入力データを与えて、crc_finalize
で最終結果を確定する。
#include <stdio.h>
#include <string.h>
#include "crc.h"
crc_t get_crc(const unsigned char* data, size_t data_len)
{
crc_t crc = crc_init();
crc = crc_update(crc, data, data_len);
crc = crc_finalize(crc);
return crc;
}
int main(void)
{
const char * data[] = {
"ABC",
"12345",
};
for (int i = 0; i < sizeof(data) / sizeof(data[0]); i++)
{
printf("%s: %08lx\n", data[i],
get_crc(data[i], strlen(data[i]))
);
}
return 0;
}
関数の prefix
通常は生成されるコードの関数名は crc_init
、 crc_update
および、crc_finalize
だが、--symbol-prefix=
を指定すると関数名につけるプレフィックスを変更できる。
以下のように --symbol-prefix=HogeHoge_
を指定すると、
python3 pycrc.py --model crc-32 --algorithm table-driven --generate c -o crc.c --symbol-prefix=HogeHoge_
python3 pycrc.py --model crc-32 --algorithm table-driven --generate h -o crc.h --symbol-prefix=HogeHoge_
HogeHoge_init
、 HogeHoge_update
、 HogeHoge_finalize
の関数名で生成される。
デフォルトでは、crc_init
、 crc_update
、 crc_finalize
が生成されるので --symbol-prefix=
の引数を省略した場合は、--symbol-prefix=crc_
が指定されているのと同じ動作をすることになる。
生成したコードのライセンス
https://pycrc.org/faq.html#code-ownership には
The sloppy answer is: you are free to do whatever you like
with the generated code, as long as you don't blame the author
for any malfunction or damage caused by the program.
However, as a courtesy, please keep the line that states
that the code was generated by pycrc.
とある。
実証コード
に動作するコードを登録している。
pycrc.py のヘルプ
以下は pycrc.py
のヘルプです。
$ python3 pycrc.py --help
Usage: python pycrc.py [OPTIONS]
To calculate the checksum of a string or hexadecimal data:
python pycrc.py [model] --check-string "123456789"
python pycrc.py [model] --check-hexstring "313233343536373839"
To calculate the checksum of a file:
python pycrc.py [model] --check-file filename
To generate the C source code and write it to filename:
python pycrc.py [model] --generate c -o filename
The model can be defined either with the --model switch or by specifying each
of the following parameters:
--width --poly --reflect-in --xor-in --reflect-out --xor-out
Options:
--version show program's version number and exit
-h, --help show this help message and exit
-v, --verbose be more verbose; print the value of the parameters and
the chosen model to stdout
--check-string=STRING
calculate the checksum of a string (default:
'123456789')
--check-hexstring=STRING
calculate the checksum of a hexadecimal number string
--check-file=FILE calculate the checksum of a file
--generate=CODE generate C source code; choose the type from {h, c,
c-main, table}
--std=STD choose the C dialect of the generated code from {C89,
ANSI, C99}
--algorithm=ALGO choose an algorithm from {bit-by-bit, bbb, bit-by-bit-
fast, bbf, table-driven, tbl, all}
--model=MODEL choose a parameter set from {crc-5, crc-8,
dallas-1-wire, crc-12-3gpp, crc-15, crc-16,
crc-16-usb, crc-16-modbus, crc-16-genibus,
crc-16-ccitt, r-crc-16, kermit, x-25, xmodem, zmodem,
crc-24, crc-32, crc-32c, crc-32-mpeg, crc-32-bzip2,
posix, jam, xfer, crc-64, crc-64-jones, crc-64-xz}
--width=NUM use NUM bits in the polynomial
--poly=HEX use HEX as polynomial
--reflect-in=BOOL reflect the octets in the input message
--xor-in=HEX use HEX as initial value
--reflect-out=BOOL reflect the resulting checksum before applying the
--xor-out value
--xor-out=HEX xor the final CRC value with HEX
--slice-by=NUM read NUM bytes at a time from the input. NUM must be
one of the values {4, 8, 16}
--table-idx-width=NUM
use NUM bits to index the CRC table; NUM must be one
of the values {1, 2, 4, 8}
--force-poly override any errors about possibly unsuitable polynoms
--symbol-prefix=STRING
when generating source code, use STRING as prefix to
the exported C symbols
--crc-type=STRING when generating source code, use STRING as crc_t type
--include-file=FILE when generating source code, include also FILE as
header file; can be specified multiple times
-o FILE, --output=FILE
write the generated code to file instead to stdout
Discussion