メッセージ構造定義を白紙から作る
このサンプルは 自分の独自バイナリプロトコルの「構造定義」を、白紙の構造エディタから組み立てて検証するためのものです。題材は小さな自作プロトコル MiniCtrl。フィールドを 1 つずつ並べ、プレビューでフィールド分解を検算し、最後に(任意で)バイナリ構造応答ルールに載せて、応答テンプレートにチェックサムを自動計算させるところまでを一本の動線でたどれます。
自作プロトコル MiniCtrlTCP 7300構造定義をゼロからプレビュー検証自動 CRC実機不要
このページでできること
- 白紙の構造エディタから、自作プロトコル MiniCtrl のフィールドを 1 つずつ定義する(型・役割・長さ駆動・判別)。
- プレビューにサンプル電文を貼って、各フィールドが正しい位置・長さで分解され、長さフィールドが可変ペイロードを駆動することを検算する。
- 完成形をインポートして自分の定義と答え合わせする。
- (任意)定義をバイナリ構造応答ルールに載せ、クライアント役が送る電文をライブでパース・応答させる。応答テンプレートの
{crc:Crc16Modbus}がチェックサムを自動計算する様子を見る。 - 最後に「自分のプロトコルではどう作るか」を判断フローで掴む。
structure-builder.commsim を開きます。題材プロトコル MiniCtrl
MiniCtrl は、本チュートリアル用の小さな機器制御プロトコルです。先頭マーカ 0x7E で始まり、コマンド・連番・長さ・可変ペイロード・CRC が並びます。これを白紙から組み立てます。
| # | フィールド | 型 | 役割 | 意味・エディタでの設定 |
|---|---|---|---|---|
| 1 | Stx | U8 | 判別(Discriminator) | フレーム先頭マーカ 0x7E。「判別フィールドで適用を分岐する」を ON にし、判別フィールド名 Stx・一致値 0x7E |
| 2 | Cmd | U8 | なし | コマンド(0x10 Open/0x20 Status/0x90 Ack/0xA0 Report)。ラベルは完成形に同梱(白紙では数値のまま) |
| 3 | Seq | U8 | なし | 連番。応答で {field:Seq} としてエコーする |
| 4 | Len | U8 | Length | ペイロードのバイト数。役割を Length にする |
| 5 | Payload | Hex | なし | 可変長データ部。「長さ元」欄に Len と入力して可変長を駆動する |
| 6 | Crc | U16 | Checksum | CRC16/Modbus。役割を Checksum にする(後述:チェックサムの検証はプレビューでは行われません。実 CRC は応答テンプレートが計算します) |
①
Len が Payload 長を駆動します(Len=1 なら Payload は 1 バイト)。可変長プロトコルの肝です。② チェックサムは「送信時に CommSim が計算してくれる」ものです。受信パース(プレビュー)では CRC を検証しません。CRC の確認はステップ C の応答(
{crc:Crc16Modbus})で行います。用意するもの
| ファイル | 内容 |
|---|---|
structure-builder/structure-builder.commsim-struct | MiniCtrl 構造定義の完成形(答え合わせ用にインポートする) |
structure-builder/structure-builder.commsim | ステップ C 用のプロジェクト(TCP 7300 スタブ・MiniCtrl 構造・Status→Report 応答ルール・フレーミングが設定済み) |
これらは CommSim.Sample の実行フォルダ内 samples/structure-builder/ に同梱されています。ステップ A・B(白紙から作る・答え合わせ)は CommSim 本体 1 本だけで行えます。ステップ C(ライブ実演)のときだけ CommSim.Sample を相手役として使います(実機は不要)。
ステップA:白紙から構造を組んでプレビューで検証する(まず動かす)
新規プロジェクトを作り、構造エディタを白紙から開いて MiniCtrl の 6 フィールドを並べます。
- CommSim 本体で新規プロジェクトを作成する(「ファイル」→「新規」)。
- 「構造体定義(プロジェクト共有)」を開く → 「追加」をクリックすると、白紙の構造エディタが開く。
- 「行追加」で 6 行作り、題材プロトコル MiniCtrl の表のとおり各行の名前・型・役割を設定する。
Stx:型 U8。上部の「判別フィールドで適用を分岐する」を ON にし、判別フィールド名Stx・一致値0x7E。Len:型 U8・役割 Length。Payload:型 Hex・「長さ元」欄にLen。Crc:型 U16・役割 Checksum。
- エディタ下部のプレビュー欄(スペース区切り HEX)に、Status 要求フレームを入れて「パース」を押す。
7E 20 01 00 18 56
Stx=0x7E)を ON にし、Len の役割を Length、Payload の長さ元を Len にしているのがポイント。下部のプレビューに 7E 20 01 00 18 56 を入れて「パース」すると、各フィールドが 名前 = 値 @オフセット+長さ で分解される(Crc 行はグリッドを下にスクロールすると現れる)。観察できること(プレビュー結果)
各フィールドが 名前 = 値 @オフセット+長さ の形で分解されます。
- --OK
- ·Stx = 126 @0+1先頭マーカ 0x7E
- ·Cmd = 32 @1+10x20 = Status
- ·Seq = 1 @2+1連番
- ·Len = 0 @3+1ペイロード長 = 0
- ·Payload = @4+0Len=0 なので 0 バイト
- ·Crc = … @4+2末尾 2 バイト
7E 10 02 01 01 69 5A も貼ってみてください。Len = 1 になり Payload が @4+1(1 バイト)に変わります。さらに Len を含むどこか 1 バイトを書き換えると、後続のオフセットがずれるのが分かります。なお、プレビューはフィールドの並び・位置・長さ駆動を検証するもので、チェックサムは検証しません(CRC の確認はステップ C で)。
ステップB:完成形と答え合わせ(オプション)
自作した定義を、同梱の完成形と見比べます。
- 「構造体定義(プロジェクト共有)」で「インポート」をクリックし、
samples/structure-builder/structure-builder.commsim-structを取り込む。 - 取り込まれた「MiniCtrl フレーム」を開いて、フィールド構成・型・役割・長さ元・判別が自分の定義と一致するか確認する。
Cmd の 0x20→Status など)が入っています。受信ログでコマンドが数値ではなく名前で読めるようになり可読性が上がります。Enum ラベルやチェックサム種別は定義に含めて持ち回れる仕上げ要素で、白紙のエディタではまず構造の骨格(並び・型・役割・長さ駆動・判別)を作ります。ステップC:実トラフィックで動かす(自動 CRC 応答)(オプション)
作った構造定義をバイナリ構造応答ルールに載せ、実際の通信でパース・応答させます。ここで CommSim がチェックサムを自動計算してくれるうれしさを確認します。実機は要りません(クライアント役は CommSim.Sample が演じます)。
- CommSim 本体で同梱の
samples/structure-builder/structure-builder.commsimを開く(構造・フレーミング・応答ルールが設定済みのスタータ)。 - 「バイナリ構造応答」タブを開き、ルール「Status(0x20) → Report(0xA0) 応答」を確認する。応答テンプレートは次のとおり。
7E A0 {field:Seq} 01 2A {crc:Crc16Modbus}{field:Seq}が受信の連番をエコーし、末尾の{crc:Crc16Modbus}がそれ以前の全バイトの CRC を自動計算して付けます。
Cmd Eq 32(=0x20 Status)でこのルールが発火し、応答テンプレートの {field:Seq} が受信連番をエコー、末尾の {crc:Crc16Modbus} が CRC を自動計算する。Open(0x10)は条件に合わないので応答しない。- セッション「MiniCtrl スタブ TCP 7300」を「起動」する。
- CommSim.Sample を起動し、「動かすサンプル」で「構造定義(自作プロトコルを白紙から)」を選ぶ。① ペインを「起動」(7300 へ接続)→「デモ送信」を押す。MiniCtrl の Status/Open 要求が連投される。
- CommSim 本体の「ログ」で、受信フレームが MiniCtrl にパース・デコード表示され、Status にだけ Report 応答が返る(Open には返らない)のを確認する。
観察できること
- ▶受信 Status:7E 20 01 00 18 56Cmd=0x20
- ◀応答 Report:7E A0 01 01 2A FF 85末尾 FF 85 = 自動計算された CRC16
- ▶受信 Open:7E 10 02 01 01 69 5ACmd=0x10 → 応答なし
7E 20 01 00 18 56 が [構造体] MiniCtrl フレームにパース・デコードされ、自動応答 7E A0 01 01 2A FF 85(末尾 FF 85 =自動計算された CRC16)を返す。Open 受信(7E 10 …)には応答が出ない。連番が変わった 2 回目の Status(Seq=03)では応答 CRC が 5E 45 に付け直される——テンプレートが毎回 CRC を再計算している証拠。FF 85 は手で計算したものではなく、{crc:Crc16Modbus} が送信時に自動で求めたものです。ペイロードや連番を変えても、CRC は常に正しく付き直します。なぜ Status だけ応答するのか:ルールのフィールド条件が
Cmd == 0x20(Status) だからです。Open(0x10)は条件に合わないので応答しません。複数のコマンドや定義を出し分ける判別・優先度・重複の詳しい扱いは メッセージ構造定義 を参照してください。自分のケースへの当てはめ方
このサンプルの流れを、自分の独自プロトコルに応用するときの判断の糸口です。
| 問い | はい | いいえ |
|---|---|---|
| プロトコルにフレーム同期(STX・固定ヘッダ)はあるか? | 判別フィールド+プロジェクトのフレーミング設定で先頭を合わせる | フレーミングを None に(受信チャンク=1 メッセージ) |
| 可変長のペイロードはあるか? | 長さフィールドに役割 Length、ペイロードの「長さ元」にその名前を指定する | 固定長(型 Hex +固定長)で表す |
| 応答も返すか? | バイナリ構造応答ルール(フィールド条件+テンプレート {field:}/{len:}/{crc:KIND})。チェックサムはテンプレートが自動計算 | 受信のパース表示だけでよい(ルール不要) |
次に読む
- メッセージ構造定義 — フィールド種別・フレーミング方式・チェックサム・判別の詳細(設定の正)
- バイナリ構造応答 — フィールド条件・応答テンプレート・優先度の詳細
- Modbus/TCP サンプル — 完成済みの構造定義で複数コマンドを判別する実例
- ← チュートリアル一覧に戻る