12.4. ハンドシェイクと機能ネゴシエーション

カメラとホストはどちらも、プロトコルをどう動かすべきかについて独自の考えを持ってトランスポートにたどり着きます。どのCRCモードを使うか、ACKが必須かどうか、バッファできる最大ペイロードはどれくらいか、などです。本格的な通信が始まる前に、両者はこれらのパラメータをセッションの残りの間固定するハンドシェイクを交換します。

12.4.1. ホストが接続を開く

カメラ側は起動時にプロトコルスタックを開始し(あるいはアプリケーションがパラメータを変更するために protocol.init() で再起動し)、その後はホストを静かに待ちます。カメラの視点から見ると、パケットが到着するまで何もすることはありません。

ホスト側はトランスポート(USBポートまたはUART)を開き、ただちに PROTO_SYNC パケット(オペコード 0x00)を送信します。このパケットには、両者の同期が外れていてもカメラが認識できるようにするマジックペイロードが含まれており、機能がネゴシエートされる前にカメラが応答する唯一のパケットです。

カメラが再送タイムアウト以内に応答しない場合、ホストは PROTO_SYNCrtx_retries 回まで再送します。それでも応答がなければあきらめ、接続失敗を報告します。この再送こそが、「抜いて、挿し直して、ホストスクリプトを再起動する」という操作を、カメラがホストの離脱を知る必要なしに機能させる仕組みです。

12.4.2. 機能の交換

カメラが同期を確認応答すると、ホストは PROTO_GET_CAPS(オペコード 0x01)を送り、カメラが何をサポートしているかを尋ねます。応答ペイロードは次の内容を報告します。

  • CRC検証の有効/無効

  • シーケンス番号追跡の有効/無効

  • ACKの有効/無効

  • イベント通知の有効/無効

  • カメラの最大ペイロードサイズ(バイト単位)

  • 現在の再送リトライ回数、タイムアウト、ポーリングパラメータ

ホストはこれらを自身の設定と比較します。ホストがいずれかを変更する必要がある場合(たとえば、受信バッファがカメラより小さいため、より小さい最大ペイロードをネゴシエートする場合)、ホストは新しい値を伴って PROTO_SET_CAPS(オペコード 0x02)を送信します。カメラはスタックを再構成して確認応答します。以後、ワイヤを越えるすべてのパケットはその共有された取り決めに従います。

ホストが何も上書きしなければ、デフォルトはすべて有効です。CRC検証、シーケンス番号追跡、ACK、イベント通知です。デフォルトの最大ペイロードは、カメラのボードごとのバッファからフレーミングのオーバーヘッド14バイト(10バイトのヘッダーと4バイトの末尾ペイロードCRC)を引いた値です。ほとんどのカメラとノートPC間の作業では、デフォルトが適切な出発点です。信頼性のページでは、アプリケーションがそれらの一部をいつ、なぜオフにするのかを解説します。

12.4.3. チャネルの探索

機能の交換のあと、ホストは CHANNEL_LIST(オペコード 0x20)を送信します。カメラは登録済みチャネルのリストで応答します。4つの組み込みチャネル(stdinstdoutstreamprofile)に加え、アプリケーションが protocol.register() で登録したものすべてです。各エントリには、チャネルのID、名前、そして機能フラグ(読み取り専用、書き込み専用、ロック可能)が含まれます。

ホストはこのリストを保存し、後でアプリケーションコードが channel_read("frame")channel_write("config", ...) を要求したときに使用します。名前は一度だけチャネルIDに解決され、その後そのチャネル上の以降のすべてのパケットはIDを直接使用します。

カメラが最初のリストのあとで新しいチャネルを登録する場合(ハンドシェイク後にアプリケーションが実行を開始するときによくあります)、カメラは CHANNEL_REGISTERED イベントパケットを送出します。ホストはそれを監視して内部のチャネルリストを更新するため、早期に接続したホストスクリプトは、再起動することなく新しく登録されたチャネルが現れるのを確認できます。

ハンドシェイクは接続セットアップ時に数回のラウンドトリップを要しますが、その後は二度と繰り返されません。定常状態の通信は単なるパケットのやり取りです。フレーミングされたバイトが入り、フレーミングされたバイトが出ていき、チャネルIDは両側ですでに既知です。