M5-StickC(ESP32)をBLE MIDI Centralにして電子ピアノと繋ぐ

M5 Stick-CとRoland HP603をBLE MIDIで接続してデータ送受信するまで

経緯

Grove端子でつなげるMIDIシールド(necobit電子)を買ってみた。これで家の電子ピアノと繋いで子供に自慢しようとしたところ、どうやら有線のMIDI端子はないことに気づいた。とりあえずBluetooth MIDIとしては使えるようだ。マニュアル見るとAppleのみ接続を保証とかいてあるが、そんなことはないはず?

Arduinoのライブラリとかは一通りそろっていそうなので、簡単に接続できると思ったのだけど、そうでもなかったので記録しておく。

設定~接続まで

ここは特にサンプルコードどおりに勧めて苦労せず。スキャンしてMIDIのサービス持っているデバイスを探して接続して……

送信

その後、Note Onとか送ってみたら全然認識しない。色々調べたらとりあえず暗号化しないとダメとの事。以下を適切に追加すればOKだった。

BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);

M5-StickCのボタン押せば音が鳴るところまではできた。

受信

これがどうもうまくいかない。よく追加されている以下のコードを追加したけどだめ。

        const uint8_t notifyOn[] = {0x1, 0x0};
        pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notifyOn, 2, true);     

比較のためにnRF connect をAndroid端末に入れてみる。

connectして、MIDI serviceのIDをひらいてNotificationをenable. ちゃんと鍵盤ひいたらNotification経由でMIDIメッセージが読み込めている。

ここでようやく、電子ピアノ側の表示が、自分のM5 StickCで接続したときと違っていることに気づく。うまく拾えているnRF connectで接続したときは、こう。

M5Stickで接続しているときはこう。

と、M5 Stickの時には液晶のbluetoothマークの横にP+MIDIが出ていない。

差分がないかと、bluetooth snifferを作ってしらべようとSeeed Studio XIAO nRF52840 を買ってきた。いろいろ苦労はしたが、無事sniffer化できたので比較。比較前にM5 StickCのほうは暗号化を一時停止。

M5 StickC(自前)とnRF connectとの違いは、下の赤枠部分の有無。nRF connectで接続したあとは、IntervalのネゴシエーションがMasterとSlaveとの間でやりとりされている。

どうやったらこのシーケンスが走るかよくわからなかったが、ライブラリの中に、esp_err_t esp_ble_gap_update_conn_params(esp_ble_conn_update_params_t *params)というのを見つけた。

パラメータを見ると、

/// Connection update parameters
typedef struct {
    esp_bd_addr_t bda;                              /*!< Bluetooth device address */
    uint16_t min_int;                               /*!< Min connection interval */
    uint16_t max_int;                               /*!< Max connection interval */
    uint16_t latency;                               /*!< Slave latency for the connection in number of connection events. Range: 0x0000 to 0x01F3 */
    uint16_t timeout;                               /*!< Supervision timeout for the LE Link. Range: 0x000A to 0x0C80.
                                                      Mandatory Range: 0x000A to 0x0C80 Time = N * 10 msec
                                                      Time Range: 100 msec to 32 seconds */
} esp_ble_conn_update_params_t;

となっており、ここのmin/max intervalを設定して呼び出せば何かやってくれそう。適当に、以下のコードをconnect処理の後、notify handlerを登録した後辺りに追加。

    esp_ble_conn_update_params_t conn_params;
    memcpy(conn_params.bda, (device->getAddress()).getNative(), sizeof(esp_bd_addr_t));
    conn_params.timeout = 400;
    conn_params.latency = 0;
    conn_params.min_int = 30;
    conn_params.max_int = 36;
    Serial.println("try to update param");
    if(::esp_ble_gap_update_conn_params(&amp;conn_params)==ESP_OK){
        Serial.println("update param completed");
    }

今度は無事 nRFの時と同じように液晶にp+MIDIの表示が出るようになり、NotificationをがHP603から出て、M5 Stickで読み出せるようになった。snifferで見てみても、

と、なんとなくinrtervalをネゴって決めるような動作が見られた。

まとめ

  • 送信は暗号化
  • 受信はInterval parameterの更新

をそれぞれ追加すれば送受信は大丈夫そう。とりあえずGrove MIDIシールド+M5 stickCで有線MIDIとBLE MIDIの変換器を作るところまではがんばろう。

Raspberry Pi 3 + PS3 Eyemotion

rpi-updateでraspberry Pi3 の firmware アップデートが必要。

Fluiddの導入でwebカメラとして家に沢山あるPS3 Eyemotionをつなげようとした。サポートしているはずなのに中々認識されない。

いろいろ探していると、以下の情報があって、rpi-updateを実行して再起動したところ何事もなく認識された。

https://forums.raspberrypi.com/viewtopic.php?t=7397#p123185

ちなみにwebcam.txtの設定は、以下の通り。

camera="usb"
camera_usb_options="-f 1 -q 75 -y"

nRF Sniffer with Seeed XIAO BLE (J-Link無し)

Seeed XIAO BLEがJ-Linkとか無しに Snifferとして使えたという記録。

ESP32のBLE-MIDIライブラリをつかって家の電子ピアノを制御しようとしたところ、どうもうまくいかない。Google Playにあるアプリだと一応音が出る。とりあえず差分を見たい。Bluetoothだとお手軽なSnifferが結構あるのではないかと調べてみた。

BLE Sniffer調査

世の中でどういうものがあるかというと、

が無償で使えそうなところ。どちらもそれぞれの提供するチップの開発キットやドングルで動作。nRF52840とかCC2540とかその手のチップ。CC2540使ったドングルのほうがお安め?

nRF SnifferはWiresharkのプラグインとして提供されているが、PACKET-SNIFFERは独自のツール。Wiresharkベースのほうが後々良さそうなので、nRF Snifferにしてみる。

nRF Sniffer導入

HW購入

HWはnRF系のチップの乗ったドングルや開発キット、場合によってはFWを書き込む環境が必要とのこと。一番簡単そうなのは、Adafruit社の以下のドングル。SnifferのFWが書き込まれているとのこと。

ただAmazonで4,000円(2022/9)とちと値がはる。というわけで汎用のドングルを調べると、Seeed社の

が安くて入手性もよさそう。とりあえずこれにしてみる。すぐに欲しかったのでマルツで頼んだ。翌日配送で送料いれると2,400円くらい。

FW/SW導入

「nRF Sniffer for Bluetooth LE でデータ解析」を参考にすすめてみる。

FWやSWはNordicのページからダウンロードすればよいらしい。まずは関連ツール類としてnRF Connect for Desktopとかいうのをインストールした。

とりあえず、立ち上げて上記のようにBluetoothとProgrammerをインストール(必要かどうか不明)。Snifferを書き込むためProgrammerを立ち上げる。

ここで、seeed studioのXIAO nRF52840のwikiページを見てProgramming方法を調べると、boot loader書き換えにはJ-Linkを使えと書いてある。とりあえず持っていないのと、安く手に入るらしいJ-Link EDU miniとかはずっと欠品中。

ただ、先の、「nRF Sniffer for Bluetooth LE でデータ解析」を見ると

DFU モードで起動して書き込む方法と、J-Link Lite に接続してデバッグピンから書き込む方法があります。

とあった。

DFU(UF2)によるFW書き込み

Nordic 系のチップでの、Device Firmware Upgrade(DFU) は、bootloaderのサポート状況にもよるが、OTA/Serial/USB CDC経由でいけるとの事。また、UF2によるFWアップデートというのもあるらしく、これはDFUモードで起動するとFlash driveに見えるようになり、バイナリをドラッグアンドロップでコピーするだけというお手軽さ。

これ使っている人いないかと見たら、Nordicのドングルでやっている人がいた。幸いなことに、Seed XIAOもUF2アップデートに対応しているらしいとのこと。早速PCに接続して、Type-Cコネクタの直近の小さいボタンを素早く二回押す。

pir
https://wiki.seeedstudio.com/XIAO_BLE/ より

すると以下のようにドライブとして認識される。

もともとあるファイルを消したくなるが、そのままここにバイナリをコピーすればOKらしい。バイナリの準備の方法は、uf2のレポジトリから、uf2conf.pyとuf2families.jsonをとってきて(pythonある前提)、hexと同じディレクトリにおいて、

python uf2conv.py sniffer_nrf52840dongle_nrf52840_7cc811f.hex -c -f 0xada52840

などで変換。コピーしてから抜き差しすると、nRF connect等から無事 Snifferとして認識された。

そのあとのWiresharkの設定などはいろいろなページを参考に特に詰まることなく進められて、無事パケットのキャプチャーまで進められた。