12.3. パケット形式¶
カメラとホストの間でワイヤを越えるすべてのバイトは、パケットの一部です。パケットは10バイトのヘッダーで始まり、可変長のペイロードが続き、4バイトの末尾CRCで終わります。それ以外のバイトはワイヤ上に現れません。ホストが2バイトの同期ワードを見つけたら、続くバイトはこの正確な順序のヘッダーです。
12.3.1. ヘッダー¶
パディングなしで詰め込まれた10バイトです。各フィールドは次のとおりです。
sync-- リトルエンディアン順の16ビットワード0xD5AA。ワイヤ上のバイト0は0xAA、バイト1は0xD5です。バイトをスキャンする受信側は、AA D5のペアを探すことでパケットの先頭を見つけられます。その前にあるものはすべてゴミとして扱われます。この値の選択は意図的です。0xAAと0xD5は印刷可能なテキストにめったに現れず、このペアがペイロードの途中に偶然現れる可能性は低いからです。seq-- 1バイト。所定の方向に送信される各パケットごとに1ずつ増加するカウンタです。受信側は次のパケットのシーケンス番号が期待どおりかを確認します。そうでなければ、信頼性レイヤーが再送を要求します。chan-- 1バイト。このパケットが属するチャネルIDです。チャネル0~31が使用可能です。組み込みのstdin、stdout、stream、そして(オプションで)profileチャネルは、カメラが予約する固定IDを使用します。flags-- 1バイト。受信側にパケットの解釈方法を伝えるビットフィールドです。ビット0
ACK-- このパケットは直前のパケットに対する確認応答です。ビット1
NAK-- このパケットは直前のパケットを拒否します。ビット2
RTX-- このパケットは再送です。ビット3
ACK_REQ-- 送信側はこのパケットの確認応答を求めています。ビット4
FRAGMENT-- より大きなメッセージの中で、このパケットの後にさらにフラグメントが続きます。ビット5
EVENT-- このパケットはデータではなくチャネルイベントを運びます。ビット6と7は予約済みです。
opcode-- 1バイト。コマンドまたは応答のコードです。プロトコルライブラリは、用途別にオペコードの範囲を予約しています。0x00..0x0F-- プロトコルコマンド(SYNC、GET_CAPS、SET_CAPS、STATS、VERSION)。0x10..0x1F-- システムコマンド(RESET、BOOT、INFO、EVENT、MEMORY)。0x20..0x2F-- チャネルコマンド(LIST、POLL、LOCK、UNLOCK、SHAPE、SIZE、READ、WRITE、IOCTL、EVENT)。
len-- 2バイト、リトルエンディアン。ヘッダーに続くペイロードバイトの数です。長さゼロは正当です。多くの確認応答や小さなコマンドはペイロードを持ちません。crc-- 2バイト。直前の8バイトのヘッダーに対するCRC-16です。不正なCRCを持つヘッダーを受け取った受信側は、ペイロードを見ることすらせずにパケット全体を破棄します。
12.3.2. ペイロード¶
0バイト以上で、フレーミングレイヤーからは不透明なものとして扱われます。ペイロードの中身はオペコードに依存します。CHANNEL_READ の応答では実際のチャネルデータであり、GET_CAPS の応答では小さな固定構造であり、チャネル書き込みではホストが送ったものそのままです。
最大ペイロードサイズはカメラのプロトコルバッファサイズに依存します(protocol.init() のボードごとの表を参照してください)。上限より長いメッセージは、最後を除くすべてに FRAGMENT フラグを立てたフラグメントに分割されます。
12.3.3. 末尾CRC¶
4バイト、ペイロードに対するCRC-32です。ヘッダーCRCでは検出できない破損、特にフレーム途中の1ビットエラーがすり抜けてしまうような長いペイロードでの破損を捕捉します。
整合性チェックを2つのCRCに分割しているのは意図的です。ヘッダーCRCはフレーミングフィールド自体、特にペイロード長を保護します。別個のヘッダーCRCがないと、長さバイトの1ビット反転によって受信側がペイロードに対して誤った数のバイトを読み込み、バイトストリームから完全に同期を失ってしまいます。ヘッダーCRCがあれば、破損したヘッダーは即座に拒否され、受信側は次の同期ワードを再スキャンします。そしてペイロードCRCはメッセージ本体を別個の関心事として保護するため、データのビット反転はフレーミングエラーと誤認されるのではなく、破損したペイロードとして報告されます。
この形式は1バイトずつ追えるほど小さく、すべてのパケットが同じレイアウト(同期、ヘッダー、ペイロード、CRCの順)を持つという事実は、手書きのパーサーが画面1枚分のコードに収まることを意味します。だからこそ、C、Python、Rustによる小さなホスト実装は週末プロジェクトで済むのです。プロトコルライブラリは、各側でメンテナンスされているPython版にあたります。