Progress Log:データ送受信プロトコル概要¶
タスク説明¶
既存のデータi送受信プロトコル(バイナリープロトコルとテキストプロトコル)を分析し、現在の実装を理解してプロトコル拡張の準備を進めました。
以下の内容について整理しました。
- 現在使用されているデータ形式
- プロトコルの選択とコンパイル方法
- 検出イベント時に送信されるセンサーデータ
- 相互排他性の制約
現在のプロトコルアーキテクチャ¶
kurikintonsは、相互排他的な2つのシリアルプロトコルを実装しています。 それぞれ バイナリープロトコルと テキストプロトコルと 呼びます。
どちらのプロトコルを利用するかは、ビルド時のフラグ(ENABLE_TEXT_COMMANDS)で選択できます。
現在、
本番環境ではバイナリープロトコル、
開発環境ではテキストプロトコル、
がデフォルトになっています。
1. バイナリープロトコル¶
- 目的: バイナリコマンドでDAC閾値を直接制御
- フラグ:
ENABLE_TEXT_COMMANDS=0 - デフォルト: 本番環境
コマンド形式¶
- 形式:
<ch> <val1> <val2> - バイト数:1コマンド3バイト
- 詳細
byte[0]:チャンネルID(1-3)byte[1]:第1データバイトbyte[2]:第2データバイト- 特殊ケース
val1 == 0xFFの場合、エラー応答として「dame」を送信
実装¶
- 受信:
serial_read_command() - 送信:
serial_send_response() - レスポンス形式: バイナリエコー(ch、val1、val2)の後、DAC実行
- 安定性機能
- バッファー同期による部分コマンド受信防止
- 不完全コマンドのタイムアウト処理
- 堅牢受信のための再試行メカニズム
- コマンド処理後の入力バッファフラッシュ
重要:PCソフトウェア側でのエンコーディング処理が必要¶
バイナリープロトコルでは、ESP32が受け取ったval1とval2のバイナリー形式のデータをそのままDACに送信します。
そのため、PCソフトウェア側であらかじめエンコード処理を実施してから、設定したい値をバイナリー値で送信する必要があります。
エンコーディング式¶
12ビット(0-4095)の閾値thresholdをバイナリープロトコルに変換式です。
ch = 1(or 2 or 3): そのままbyte1 = 0x10 + (threshold >> 6): 閾値の上位6ビットを取得し、プロトコルヘッダー(0x10)を追加byte2 = (threshold << 2) & 0xFF: 閾値の下位6ビットを取得し、8ビット(0xFF)マスクを適用
計算例:
threshold = 1234→byte1=0x23、byte2=0x4Athreshold = 0→byte1=0x10、byte2=0x00threshold = 4095→byte1=0x3F、byte2=0xFC
2. テキストプロトコル¶
- 目的: 人間が読めるテキスト形式でDAC閾値を制御
- フラグ:
ENABLE_TEXT_COMMANDS=1 - デフォルト: 開発環境(将来的にバイナリープロトコルを置き換え)
コマンド形式¶
- 形式:
COMMAND arg1 arg2 - 終端記号:改行(
\nまたは\r\n) - タイムアウト:500ms(シリアルモニター互換)
- キュー:最大10項目(満杯時はエラー)
利用可能なコマンド¶
[H] HELP: 利用可能なコマンドをすべて表示[S] STATUS: システム構成とファームウェアバージョンを表示[V] GET_VERSION: ファームウェアバージョンを表示[C] SET_POLL_COUNT <count>: ポーリング回数を設定(1-1000、デフォルト100)[G] GET_THRESHOLD <ch>: 指定したチャンネルのスレッショルド値を取得[T] SET_THRESHOLD <ch> <val>: 指定したチャンネルにスレッショルド値を設定(0-4095)[I] SET_INTERVAL <ms>: デバッグモードでの測定間隔をミリ秒で設定[L] LED <ch|ALL> <ON|OFF>: LEDを手動で制御[R] RESET: デフォルトの設定にリセット
ユーザーの利便性を考えて、コマンド名は大文字と小文字を区別しないようにしました。 また、それぞれのコマンドは短い1文字エイリアスをサポートしています。
実装¶
- 関数:
process_text_commands()、process_queued_text_command() - キュー処理:コマンドをFIFOにキュー、1ループに1個処理
- バイナリープロトコル関数:ビルドから完全に除外される
- レスポンス形式: 改行で終わる人間が読める形式
PCソフトウェア側でのエンコーディング処理が不要¶
テキストプロトコルでは、kurikintonsの内部でエンコードしてからDAC制御を実行します。
SET_THRESHOLDコマンドで12ビット閾値値(0-4095)をそのまま指定してOKです。
エンコーディング関数¶
- ファイル:
src/spi_control.cpp - 関数:
encode_dac_threshold() - (当たり前ですが)エンコーディング式はバイナリープロトコルと同じです
センサーデータ出力(両プロトコル共通)¶
宇宙線検出イベント発生時(detection.detected == true)にデータを送信します。
データにはBME280センサーのデータも追加されます。
出力形式はスペース区切り値(改行で終了)です。
signal1 signal2 signal3 adcValue temperature pressure humidity
例:100 85 92 2048 25.35 1013.25 45.67
データ型と範囲:
| フィールド | 型 | 範囲 | ソース |
|---|---|---|---|
| signal1 | int | 0-100 | GPIO12検出カウント(100ポーリング) |
| signal2 | int | 0-100 | GPIO19検出カウント(100ポーリング) |
| signal3 | int | 0-100 | GPIO27検出カウント(100ポーリング) |
| adcValue | int | 0-4095 | GPIO32からADC(signal1 > 0時のみ) |
| temperature | float | 可変 | BME280センサー(℃) |
| pressure | float | 可変 | BME280センサー(Pa) |
| humidity | float | 可変 | BME280センサー(%) |
条件付きロジック:
signal1 == 0の場合、ADC値は強制的に0に設定(ハードウェア制約)- センサー読み取りは検出イベント時のみ(イベント駆動)
- 出力は検出時のみ、周期的出力なし
コンパイル時の相互排他性¶
どうして2つのプロトコルが存在するのか?¶
2つのプロトコルが存在するのは開発経緯による理由です。
kurikintonsのプロトタイプ実装では、バイナリープロトコルのみでした。
そこに、ユーザーの利便性を考えてテキストプロトコルを追加しました。
当初は2つのプロトコルを共存させようとしましたが、 改行処理がうまくいかなかったため、ビルドフラグを追加し、 独立したプロトコルとして実装することにしました。
ビルド方法¶
- 開発プロファイル(
task dev:build):ENABLE_TEXT_COMMANDS=1(テキストプロトコル) - 本番プロファイル(
task prod:build):ENABLE_TEXT_COMMANDS=0(バイナリープロトコル) - ビルドフラグ:
platformio.iniで-DENABLE_TEXT_COMMANDS=0/1に設定
シリアル通信定数¶
- ボーレート: 115200 bps(すべてのビルドで固定)
- 最大テキストコマンド長: 64バイト
- 最大コマンド引数数: 1コマンド2個
- コマンドキュー容量: 最大10項目
- コマンドタイムアウト: 500ms(部分コマンド受信)
- 検出サイクルのポーリング数: 100(
DETECT_POLL_COUNTで設定可能)
Learnings¶
-
相互排他性が強い: プロトコルはコンパイル時に完全に分離される。無効なプロトコルの関数はバイナリから完全に除外される。メモリ効率は良いが、プロトコル切り替えには再コンパイルが必要。
-
データ出力はイベント駆動: センサーデータ送信は宇宙線検出時のみ。周期的なハートビートやステータス出力はない。これは周期ベンチテストモードとは異なる。
-
ADCフィルタリングロジックはハードウェア依存: ADCが
signal1 > 0時のみ有効なのは、元のハードウェア設計がADC入力をチャンネル1に結合しているため。この制約はadc_read_with_channel_filter()関数で実装されている。 -
テキストコマンドキューは非同期: コマンドは10項目FIFOにキューイングされ、1ループに1個処理される。キューが満杯の場合、受信コマンドは拒否される。これはシリアルI/Oのブロッキングを防止する。
-
バッファー管理が重要: バイナリープロトコルには部分/破損コマンド処理のための広範なバッファー同期とタイムアウト処理がある。 テキストコマンドはシリアルモニター互換性のために500msタイムアウトを使用する。
次のステップ¶
- プロトコル拡張の検討:
- センサーデータ出力にタイムスタンプを追加(時間解像度向上)
- メッセージ型インジケーター追加(例:
D:検出、E:エラー) - バイナリプロトコルにチェックサム/CRC追加(エラー検出)
-
プロトコルヘッダーにバージョン番号追加(前方互換性)
-
テスト・検証:
- 両プロトコルのテストベクトル文書化
- PC側パーサーのリファレンス実装
-
本番ビルドで両プロトコルが正しく動作することを検証
-
今後の開発:
- 相互排他性が限定的になった場合、実行時に両プロトコルをサポートするハイブリッドプロトコルを検討
- 各プロトコルのパフォーマンス特性を文書化
- ストリーミング検出モード検討(送信あたり複数イベント)