前回はmicro:bitからの垂れ流し(broadcast)パケットをラズパイで一方的に受信してみました。今回は、micro:bitとラズパイをpairingいたし、双方向のBLE通信をラズパイ上のWiresharkで覗き見してみようと思います。とはいえ、BLEプロトコル素人なので、まずは遠くからやり取りの様子を眺めてみた、というところ。
※「ブロックを積みながら」投稿順 index はこちら
ここまで、ペアリングを行ってmicro:bitを使用する場合には、スマホ上の「micro:bitアプリ」を使ってペアリングを行っていました。ラズパイ3/4の場合はどうしたらよいのか。Raspbean OS(Raspberry Pi OS) のDesktopを使っている場合は簡単でした。Desktopの右肩のところにある Bluetoothマーク「Bluetoothデバイスの管理」をクリックすれば、アイキャッチ画像のようなメニュー、但し、まだBBC micro:bitの行が無い、ものが現れます。そこから「デバイスを追加」で以下のようなウインドウが開きます。
micro:bit側で、A+Bキー押しながらRESETボタンを押して、離せばペアリング可能な状態となり、ラズパイ側の下のウインドウにmicro:bitのデバイスアドレスが現れるはずであります。
- ラズパイ側では、該当のデバイスを選択の上「ペア」ボタンを押す
- micro:bit側でもAボタンを押す
でペアリングができます(Raspbian busterで確認。)
ただ、ペアリングに成功しても以下のようなつれないメッセージがでます。また、アイキャッチ画像のように、Bluetoothメニューの中にBBC micro:bitが登場しますが、頭には赤くバツ印がついています。
しかし、この状態で、Python上でbluepyモジュールを使って connect()してやればちゃんと接続され、以降の操作が可能となります。
ただ、後になって気づいたのですが、micro:bitのプログラミングに利用しているMakeCodeエディタは、「ペアリングなしでコネクト」できるモードもサポートしていたのでした。オブジェクトファイル(HEXファイル)を生成する前に、MakeCodeエディタの右上の歯車アイコンからProject Settingsを呼び出して、以下のメニューを開けば、ペアリングに関するオプションを設定できるようです。なお、上記のラズパイとのペアリングは以下の「デフォルト」設定の場合。
今回もまた「ブロックは積んで」おりません。第14回で作った micro:bit V2用のオブジェクトファイル(HEX)をそのまま使っています。micro:bit上ではBLE uartサービスが動作しています。
さて、ペアリングができているので、ラズパイ側では、前回同様 bluepyモジュールをPythonから呼び出して connect()以下、BLE操作のプログラムを書かないとなりません。さて bluepyのドキュメントを読むと多数のクラスがあります。さてどのクラスを使うべきか。。。ここはBLEの「言葉」に慣れておくしかありません。
- Central
- Peripheral
です。ぶっちゃけ、スマホとmicro:bitをコネクトして使っているようなケースでは、micro:bitがPeripheral、スマホがCentralです。当然、ラズパイもCentral(コネクトする側がCentralです。)
よって、Peripheralであるmicro:bitをモデル化するオブジェクトとして生成するのは
bluepy.btle.Peripheral()
で生成できるオブジェクトです。このオブジェクトの connect()メソッドを呼び出す(micro:bitのBLEアドレスを与える)ことで micro:bitとの通信路を確立することができます。
ちょっと脱線しますが、上のCentralとPeripheralの関係以外に、BLEのクライアントとサーバーという関係も出てくるのでちょっと混乱します。どうもBLEにおけるクライアントとサーバーというのは、データを要求する側と応答する側ということでしかないようです。つまりあるデータではクライアントだが、別なデータについてはサーバーということがあり得るのでした。それと比べると、PeripheralはアドバタイズしてCentralに「見つけて」もらう存在、コネクションは常にCentral主導と非対称であります。ただ、リンクレイヤでは、MasterとSlaveみたいな呼び方もされているみたい。レイヤ層毎に用語を押さえていかないとならないようです。
さて connect()とその後の通信の様子を覗き見するには、いつもLANなどでお世話になっております wireshark 殿にお願いです。定番ツールなのでインストールしてある方も多いでしょう。
$ sudo wireshark &
私の環境では、bluetooth0 というデバイスをキャプチャすると通信の様子を覗き見することができました。SCANのキャプチャのためにはsudo必須だと思います。
キャプチャしたパケットの最初の方のSourceとDestinationを見ると、hostとcontrollerというものがやり取りしているのが見えます。ここでまた、BLE独特の用語に慣れねばなりません。
- BLEのプロトコルインタフェースは、HCI(ホスト・コントローラ・インタフェース)というものを境に大きく上下の2階層に分かれる
- HCIは物理デバイス間の境のUART的な通信のイメージだが、実態は本当に物理デバイス間であることも、1つのデバイスの中でのソフト間での場合もある。
- HCIの上にあるのがhostであり、その最上位はアプリである
- HCIの下にあるのがcontrollerであり、その最下位は PHY(物理層)である
つまり Wiresharkで見えているhostとcontrollerのやりとりは、ラズパイのボード内でのやりとりであって、micro:bitとの通信そのものが見えているわけではないということです。controller側にはリンク層(LL)というものまで含まれており、こいつが、アドバタイズとか、スキャンとか、コネクションとかを管理しているようです。hostは、HCIを経由してスキャンしてくれ、コネクトしてくだされ、とお願いをする立場みたい。
それが分かって、最初のパケットを見てみます。hostが、BLEスキャンをかけるときのパラメータ、どんな時間間隔でスキャンするなどをcontrollerにお願いしているみたい。こんな感じ。
コントローラは、律儀に?返事してきますが、省略。なお、Wiresharkは関連するパケットの左端に矢印をつけてくれるので、要求と応答の関係はすぐ見つかるので楽です。その次のステップを観察すると、ホストからSCANをイネーブルにしています。これを受けてコントローラ側でSCANが行われるのでしょうが、SCANそのものはコントローラ内に閉じているので、hostに1個1個のアドバタイズパケットそのものが到来するわけではないようです。
しかし以下のように、コントローラからはスキャンの結果にあたる Report が提出されてきます。中を見ると、コネクト対象になるmicro:bitのBLEデバイスアドレスが発見されていることが分かります。
その後、コネクション(無線通信の暗号化などのためにhost, controller間でのやりとりが有り)が張られ、ようやく実体のあるラズパイ、micro:bit間の通信が始まります。今回は、ターゲットのmicro:bitが保持するcharacterristics(これまたBLE用語だ)を知るためにgetCharacteristics()メソッドを呼んでいるので、その問いかけの一部です。なお、下の方に見えている L2CAPというのはHCIの直上に位置する「論理リンク制御及びアダプテーションプロトコル」で、その上(下のキャプチャでは下)にATT(アトリビュート・プロトコル)があり、さらにその上にGATT(汎用アトリビュート・プロファイル)がありとな。まだまだ勉強追いついていないので、プロトコルを掘っていくのはまた今度か。
試みに、micro:bitからの上記への返信(下のキャプチャ)を見れば、
- Handle
- UUID
- Characteristic
トホホの連続です。何が何やら。しかしこのあたりを解読できないと理解できませぬ。
ちゃんとドキュメント読まないと。でも、かなり読み応えあるというか、分かりにくいというか。Bluetoothの専門家、ホンとすごいな。。。