プロトコル仕様

bleRPCはBLE GATTの上に階層化されたプロトコルスタックを使用します。コマンド層はProtocol BuffersペイロードをRPCメタデータで包み、オプションの暗号化層はシリアライズされたコマンドを暗号化し、コンテナ層はMTUサイズのパケットに分割してBLE伝送します。

graph TD
    A["Application"] --> B["Command Layer<br/>Protobuf encode/decode + command metadata"]
    B --> E["Encryption Layer (optional)<br/>AES-128-GCM encrypt/decrypt"]
    E --> C["Container Layer<br/>MTU-based split/reassemble + sequencing"]
    C --> D["BLE GATT<br/>(single characteristic)"]
      

BLEトランスポート

すべての通信は単一のGATT Characteristicを使用します:

MTUはBLE ATT MTU Exchangeプロシージャにより自動的にネゴシエーションされます。アプリケーションはネゴシエーションされたMTU(ATTオーバーヘッドの3バイトを引いた値)を使用して、コンテナペイロードの最大サイズを決定

デフォルトタイムアウトは100msで、タイムアウト制御コンテナで設定可能

コンテナ層

コンテナ層は、大きなペイロードをMTUサイズのパケットに分割し、受信側で再組み立てします。各コンテナは追跡と順序付けのためにトランザクションIDとシーケンス番号を持ちます。

コンテナフォーマット

すべてのマルチバイトフィールドはリトルエンディアンです。

最初のコンテナ (type=0b00)

トランザクションの最初のコンテナには、ペイロードの合計長が含まれます:

transaction_id
8 bits
sequence_number
8 bits
type
2
ctrl_cmd
4
rsv
2
total_length
16 bits (LE)
payload_len
8 bits
payload
variable
フィールドビット数説明
transaction_id8このリクエスト/レスポンスペアの一意のID。トランザクションごとにリセットされます。
sequence_number8コンテナ送信ごとにインクリメント。トランザクションごとにリセットされます。
type20b00 = 最初
control_cmd40x0(データコンテナでは未使用)
reserved2ゼロ埋め
total_length16全コンテナにわたるペイロードの合計サイズ(バイト、リトルエンディアン)
payload_len8このコンテナ内のペイロードサイズ(バイト)
payload可変コマンドデータのフラグメント

ヘッダーサイズ: 6バイト(transaction_id + sequence_number + flags + total_length + payload_len)

後続コンテナ (type=0b01)

継続コンテナはtotal_lengthを省略します:

transaction_id
8 bits
sequence_number
8 bits
type
2
ctrl_cmd
4
rsv
2
payload_len
8 bits
payload
variable

ヘッダーサイズ: 4バイト(total_lengthフィールドなし)

バイト2のビットフィールド詳細

各コンテナの3バイト目は、タイプ、コントロールコマンド、および予約ビットをエンコードします:

type
bits 7-6
control_cmd
bits 5-2
reserved
bits 1-0

コンテナ分割の例

MTU=247(ATTオーバーヘッド後の利用可能サイズ244)で500バイトのコマンドペイロードの場合:

コンテナタイプヘッダーペイロード合計
1FIRST6バイト238バイト244バイト
2SUBSEQUENT4バイト240バイト244バイト
3SUBSEQUENT4バイト22バイト26バイト

ペイロード合計: 500バイト(238 + 240 + 22)

最大ペイロード

sequence_numberは8ビットであるため、単一トランザクションは約255コンテナに制限されます。一般的なMTU 247(後続コンテナあたり240バイト)の場合、トランザクションあたりの実用的な最大ペイロードは約60 KBです。より大きな転送には、複数のリクエスト/レスポンスサイクルを使用してください。

制御コンテナ

制御コンテナ(type=0b11)は、アプリケーションデータの代わりにプロトコルレベルのコマンドを運びます。

タイムアウト共有 (control_cmd=0x1)

ペリフェラルが処理タイムアウトをセントラルに伝えることができます。

リクエスト (Central → Peripheral)

フィールド
type0b11(制御)
control_cmd0x1
payload_len0x00

レスポンス (Peripheral → Central)

フィールド
type0b11(制御)
control_cmd0x1
payload_len0x02
payloadtimeout_ms(16ビットLE、ミリ秒)

ケイパビリティ共有 (control_cmd=0x4)

ペリフェラルがバッファ制約と機能フラグをセントラルに伝えることができます。

リクエスト (Central → Peripheral)

フィールド
type0b11(制御)
control_cmd0x4
payload_len0x06
payload[0:2]max_request_payload_size(16ビットLE、通常0)
payload[2:4]max_response_payload_size(16ビットLE、通常0)
payload[4:6]flags(16ビットLE、通常0)

レスポンス (Peripheral → Central)

フィールド
type0b11(制御)
control_cmd0x4
payload_len0x06
payload[0:2]max_request_payload_size(16ビットLE)
payload[2:4]max_response_payload_size(16ビットLE)
payload[4:6]flags(16ビットLE) — ビット0: 暗号化サポート

flagsが存在しない場合(後方互換性のための4バイトペイロード)、オプション機能は利用不可

ストリーム終了 (control_cmd=0x2, 0x3)

ストリーミングシーケンスの終了を通知します。どちら側からでもストリームを終了できます。

control_cmd方向説明
0x2Central → PeripheralCentralがアップロードストリームを終了
0x3Peripheral → CentralPeripheralがダウンロードストリームを終了

どちらもpayload_len=0x00(ペイロードなし)

エラー通知 (control_cmd=0x5)

エラー発生時(例: レスポンスがバッファ制限を超えた場合)にペリフェラルから送信されます。

フィールド
type0b11(制御)
control_cmd0x5
payload_len0x01
payload[0]エラーコード

エラーコード:

鍵交換 (control_cmd=0x6)

暗号化セッションを確立するための鍵交換ハンドシェイクペイロードを運びます。ペリフェラルがケイパビリティのflagsフィールドで暗号化サポートをアドバタイズした場合に使用されます。

フィールド
type0b11(制御)
control_cmd0x6
payload_len可変
payload鍵交換ステップデータ(暗号化を参照)

ハンドシェイクを完了するために4つのコンテナ(ステップ1〜4)が交換されます。完了後、すべての後続データコンテナは暗号化されたペイロードを運ぶ

暗号化データコンテナ

暗号化が有効な場合、データコンテナ(FIRST / SUBSEQUENT)のペイロードは、シリアライズされたコマンドの暗号化形式に置き換えられます:

counter
32 bits (LE)
ciphertext
variable
tag
128 bits
フィールドサイズ説明
counter4バイト単調増加カウンター(リトルエンディアン)。AES-GCMのnonceおよびリプレイ検出に使用。
ciphertextNバイトAES-128-GCMで暗号化されたシリアライズ済みコマンド
tag16バイトAES-GCM認証タグ

合計オーバーヘッド: 20バイト(カウンター4バイト + タグ16バイト)。暗号文は通常通りコンテナに分割されます。

コマンド層

コマンド層は、Protocol Buffersでエンコードされたデータをメタデータで包みます。コマンドは名前(ASCII文字列)で識別され、柔軟で人間が読みやすいディスパッチを可能にします。

コマンドフォーマット

T
1 bit
reserved
7 bits
cmd_name_len
8 bits
cmd_name
variable
data_len
16 bits (LE)
data
variable
フィールドビット数説明
type10 = リクエスト、1 = レスポンス
reserved7ゼロ埋め
cmd_name_len8コマンド名の長さ(バイト)
cmd_name可変ASCIIコマンド名(例: echoflash_read
data_len16protobufデータの長さ(バイト、リトルエンディアン)
data可変Protocol Buffersでエンコードされたペイロード

コマンド検出

コマンドは.protoファイルの定義から自動的に生成されます。*Request / *Responseメッセージのペアから、プレフィックスをsnake_caseに変換したコマンド名が生成されます:

メッセージペアコマンド名
EchoRequest + EchoResponseecho
FlashReadRequest + FlashReadResponseflash_read
DataWriteRequest + DataWriteResponsedata_write

リクエスト/レスポンスフロー

完全なRPC呼び出しは、コマンド層でのエンコード、コンテナ層での分割、BLE伝送、そして受信側での逆処理で構成されます:

sequenceDiagram
    participant C as Central
    participant P as Peripheral
    Note over C: 1. Protobuf encode request
    Note over C: 2. Wrap in command header
    Note over C: 3. Split into containers
    C->>P: Write Without Response (FIRST)
    C->>P: Write Without Response (SUBSEQUENT...)
    Note over P: 4. Reassemble containers
    Note over P: 5. Decode command + Protobuf
    Note over P: 6. Execute handler
    Note over P: 7. Encode response + split
    P->>C: Notify (FIRST)
    P->>C: Notify (SUBSEQUENT...)
    Note over C: 8. Reassemble + decode response
      

ストリーミング

bleRPCは、単純なリクエスト/レスポンスに加えて、2つのストリーミングパターンをサポートしています:

Peripheral → Central ストリーム(サーバーストリーミング)

1つのリクエストが複数のレスポンスをトリガーします。ストリームはSTREAM_END_P2C制御コンテナで終了します。

sequenceDiagram
    participant C as Central
    participant P as Peripheral
    C->>P: Request
    P->>C: Response 1 (Notify)
    P->>C: Response 2 (Notify)
    P->>C: Response 3 (Notify)
    P-->>C: STREAM_END_P2C (control)
      

Central → Peripheral ストリーム(クライアントストリーミング)

複数のリクエストが送信され、STREAM_END_C2P制御コンテナが続きます。ペリフェラルは最終メッセージで応答します。

sequenceDiagram
    participant C as Central
    participant P as Peripheral
    C->>P: Request 1
    C->>P: Request 2
    C->>P: Request 3
    C-->>P: STREAM_END_C2P (control)
    P->>C: Final Response (Notify)
      

接続セットアップシーケンス

セントラルがペリフェラルに接続する際、以下の初期化ステップを実行します:

sequenceDiagram
    participant C as Central
    participant P as Peripheral
    C->>P: BLE Connect
    C->>P: MTU Exchange
    C->>P: Discover Services
    C->>P: Enable Notifications
    C->>P: Timeout Request (ctrl)
    P->>C: Timeout Response (e.g. 100ms)
    C->>P: Capability Request (ctrl)
    P->>C: Capability Response (max_req, max_resp, flags)
    opt Encryption (flags & 0x01)
        C->>P: Key Exchange Step 1 (ctrl 0x6)
        P->>C: Key Exchange Step 2 (ctrl 0x6)
        C->>P: Key Exchange Step 3 (ctrl 0x6)
        P->>C: Key Exchange Step 4 (ctrl 0x6)
        Note over C,P: AES-128-GCM session established
    end
    Note over C,P: Ready for RPC calls