メッセージ構造定義

独自プロトコルの TCP/UDP 通信では、固定ヘッダ+可変ボディや、コマンドごとに異なるバイナリ構造を扱うことがよくあります。メッセージ構造定義を使うと、受信データの構造をフィールド単位で定義しておき、

  • 受信ログをフィールド単位に分解して表示する(どのバイトが何の値か一目でわかる)
  • フィールドの値で応答を出し分ける(→ バイナリ構造応答

ことができます。構造体定義・バイト順序(エンディアン)・メッセージ分割方式(フレーミング)はプロジェクト全体で共有され、プロジェクトファイルに保存されます。

この機能は主にバイナリプロトコル(HEX)向けです。テキスト行ベースの通信はオートメーションで十分なことが多いです。

まず試すメッセージ構造定義を白紙から作る:小さな自作プロトコルを構造エディタでゼロから組み立て、プレビューで検算し、応答テンプレートの自動 CRC まで通しでたどるハンズオン・チュートリアルです。

全体の流れ

  1. メニューバーの 「プロジェクト」→「プロジェクト設定…」 を開き、プロジェクトのエンディアンフレーミング方式(TCP ストリームの区切り方)を設定する。
  2. メニューバーの 「プロジェクト」→「構造体定義…」 を開き、メッセージの構造体定義を 1 つ以上作る(フィールドを並べる)。
  3. セッションを起動して受信すると、ログペインでパース結果が確認できる(「構造体パース表示」をオン)。
  4. フィールドの値に応じて応答を返したい場合は、「バイナリ構造応答」タブで構造体ルールを追加する(→ バイナリ構造応答)。

プロジェクト設定(データ形式・エンディアン・フレーミング)

メニューバーの 「プロジェクト」→「プロジェクト設定…」 で開くダイアログで設定します。ここはプロジェクト全体(全セッション共通)の設定です。

各画面項目の詳細説明は プロジェクト設定 を参照してください。

既定データ形式(テキスト/バイナリ)

このプロジェクトで新規に作る項目(送信ステップ等)の既定の解釈方式です。UTF-8 / ASCII = テキストRawHex = バイナリ(HEX) を選びます。各セッション側で個別に上書きできます。

エンディアン

数値フィールド(u16/i32/f32 など)を解釈するバイト順序です。接続する機器の仕様に合わせてリトルエンディアン / ビッグエンディアンのどちらかを選びます。

フレーミング方式(TCP ストリームの区切り)

TCP は連続したバイトストリームのため、「どこからどこまでが 1 メッセージか」を決める必要があります。次のいずれかを選びます。

方式説明
None区切らない。受信したチャンクをそのまま 1 メッセージとして扱う(UDP やデータグラム的な使い方向け)
LengthPrefixedヘッダ内の長さフィールドでメッセージ長を判定する(最も一般的)
FixedLength毎メッセージ固定長
Delimiter区切りバイト列で分割

フレーミング方式を選ぶと、その方式で意味を持たない設定項目は自動的にグレーアウト(編集不可)になります。有効になっている欄だけを入力すれば設定できます。

方式有効になる詳細項目
Noneなし(詳細項目はすべてグレーアウト)
LengthPrefixed共通ヘッダ長 / 長さフィールドのオフセット・サイズ / 長さ基準 / 長さ補正
FixedLength固定メッセージ長
Delimiterデリミタ HEX(例 0D 0A

各詳細項目の意味:

項目説明
共通ヘッダ長全メッセージに共通する固定長ヘッダのバイト数
長さフィールド: オフセットヘッダ先頭から長さフィールドまでのバイト位置
長さフィールド: サイズ長さフィールド自体のバイト数(1 / 2 / 4 など)
長さ基準長さフィールドの値が指す範囲(メッセージ全体長 / 長さフィールド以降 / ボディのみ)
長さ補正長さ基準に対する補正値(±整数)。長さフィールドの値と実測長が合わないときに調整
固定メッセージ長1 メッセージとして切り出すバイト数
デリミタ HEX区切りバイト列を HEX で指定(例 0D 0A

前提: LengthPrefixed は、全メッセージに共通する固定長ヘッダが先頭にあることを前提にしています(ヘッダ内の整数フィールドからメッセージ長や種別を読み取るため)。

構造体定義の作成

メニューバーの 「プロジェクト」→「構造体定義…」 で開くダイアログで管理します。

  • 追加 / 編集 / 複製 / 削除: 定義の作成・編集(行をダブルクリックでも編集)・複製・削除。
  • インポート / エクスポート: 定義を .commsim-struct ファイルとして書き出し/読み込み。別プロジェクトへ定義を再利用できます。

「追加」「編集」で開く 「構造体定義の編集」 ウィンドウで、フィールドを先頭から順に並べます。

フィールド表

説明
名前フィールド名(「長さ元 / 個数元」や応答テンプレートから参照される)
u8〜u64 / i8〜i64(符号付き)/ f32・f64(浮動小数点)/ ascii(文字列)/ hex(生バイト)/ bcd(パック BCD)/ array(配列)/ nested(入れ子)
役割None / Length(長さフィールド)/ Checksum(チェックサム)/ Discriminator(判別)
固定長ascii / hex / bcd の固定バイト数(可変長なら空にして「長さ元」を使う)
長さ元可変長フィールドの長さを、先に出てくる整数フィールドの値から取る場合にそのフィールド名を指定
個数元array の要素数を、整数フィールドの値から取る場合にそのフィールド名を指定

行は 行追加 / 行削除 / ↑ / ↓ で編集・並べ替えします。

長さ元 / 個数元の参照名は、入れ子内でもフラットなフィールド名(プレフィックスなし)で指定します。

判別フィールド(複数定義の出し分け)

コマンドごとに構造が違う場合、定義を複数作り、判別フィールドで適用する定義を選びます。

  • 「判別フィールドで適用を分岐する」をオンにし、判別フィールド名一致値0x10 または 16 の形式)を指定します。
  • 受信時、ヘッダの判別フィールド値が一致する定義が適用されます。
  • 複数の定義が一致した場合は先頭(定義一覧の上から最初)を採用します。
  • どの定義にも一致しない場合は、判別なしの定義(あれば最後の受け皿)→ それも無ければ生 HEX 表示にフォールバックします。

プレビュー

編集ウィンドウ下部の「プレビュー」にサンプル HEX(例 00 10 00 05 48 65 6C 6C 6F)を入力して「パース」を押すと、その定義でどう分解されるかを確認できます。設計しながら検証できます。

プレビュー入力欄は専用のバイト入力(HEX エディタ)です。ログ・キャプチャの HEX ダンプをそのまま貼り付けて検証できます。

受信ログでのパース表示

セッションを起動して受信すると、ログペインの「構造体パース表示」チェックボックス(既定オン)がオンのとき、フレーミングで切り出した各メッセージがフィールドごとに分解されてログに表示されます。

  • 数値フィールドは 値 (0x..) 形式で表示されます。
  • 一致する定義がない場合は生 HEX で表示されます(警告付き)。

チェックをオフにすると従来どおりの生データ表示に戻ります。

保存と共有

エンディアン・フレーミング・構造体定義はプロジェクト共有リソースとしてプロジェクトファイルに保存されます。保存・読込の操作は通常のプロジェクト保存と同じです(→ セッションと通信)。

定義そのものを他プロジェクトと共有したいときは、構造体定義ダイアログのエクスポート / インポート.commsim-struct)を使います。

設定例

フレーミング設定例

LengthPrefixed:先頭 2 バイトが「以降のデータ長」を示す形式

ヘッダ 4 バイト(コマンド 1B + 予約 1B + 長さ 2B)+ ボディという構成で、長さフィールドがボディのバイト数を格納している場合の例です。

項目設定値
フレーミング方式LengthPrefixed
共通ヘッダ長4
長さフィールド: オフセット2
長さフィールド: サイズ2
長さ基準共通ヘッダ以降のボディ長
長さ補正0
エンディアンBig

受信バイト例: 01 00 00 05 48 65 6C 6C 6F(ヘッダ 4B + ボディ 48 65 6C 6C 6F 5B)

FixedLength:16 バイト固定のメッセージ形式

コマンドと応答が常に 16 バイトで送受信されるプロトコルの場合です。

項目設定値
フレーミング方式FixedLength
固定メッセージ長16

Delimiter:行末 \r\n0D 0A)で区切るテキスト寄りのバイナリ形式

テキスト行に近いが構造体パースも使いたい場合(改行区切りのセンサーログなど)の例です。

項目設定値
フレーミング方式Delimiter
デリミタ HEX0D 0A

構造体定義例:コマンド + 長さ + 可変ボディ(コマンドで出し分け)

01 00 00 05 48 65 6C 6C 6F のようなメッセージを想定した定義例です。

フィールド名役割固定長長さ元
Commandu8Discriminator
Reservedu8None
BodyLenu16Length
BodyhexNoneBodyLen
  • Command を Discriminator(役割: Discriminator)にすることで、コマンド値ごとに別の構造体定義を選択できます。
  • BodyBodyLen の値をバイト数として参照する可変長フィールドです。

コマンドで定義を出し分ける場合(例: Command = 0x01Command = 0x02 で異なる定義を使う):

  1. 定義 A: 「判別フィールドで適用を分岐する」をオン → 判別フィールド名: Command、一致値: 0x01
  2. 定義 B: 同様に一致値 0x02
  3. どちらにも一致しない場合は判別なしの定義(受け皿)または生 HEX 表示にフォールバックします。

プレビュー欄にサンプル HEX(例 01 00 00 05 48 65 6C 6C 6F)を貼り付けて「パース」を押すと、定義通りに分解されるかその場で確認できます。

次に読む