2023年1月1日日曜日

Bluefrullt nrf52をxboxのコントローラーに接続する


背景

ESP32をxboxのコントローラーに接続するライブラリは接続時に不具合が頻繁に発生しており、それは回路がBLE5に対応していないのが原因ではないかと意見がありました。
検証のためにAdafruitのnrf52842 Bluefruit Featherでxboxのコントローラーに接続したところESP32で発生するような問題なく毎回5秒弱で接続できました。

その際に把握したBluefruitの扱い方を備忘録として記事に残します。

使ったもの


書いたコードは全て貼り付けると長いのでgithubに置きました

300行以上あります。
https://github.com/asukiaaa/nrf52-bluefluit-xbox-controller-practice/blob/master/src/main.cpp

上記のプログラムをFeather nrf52842に書き込んでシリアルモニタでログを確認しつつコントローラーとペアリングすると、このような情報を出力しつつコントローラーと繋がります。
Scanning ...
[ADV 3719] Packet received from 44:16:22:5E:B2:D4
PAYLOAD 19 bytes
02-01-04-02-0A-14-03-19-C4-03-04-FF-06-00-00-03-03-12-18
RSSI -52 dBm
ADV TYPE Connectable undirected
APPEARANCE C4-03
TX PWR LEVEL 20
16-Bit UUID 1812
MAN SPEC DATA 06-00-00

Connected
Found HID service
Secured
Discovering characteristic report map ... Found it
05 01 09 05 a1 01 85 01 09 01 a1 00 09 30 09 31 15 00 27 ff ff 00 00 95 02 75 10 81 02 c0 09 01 a1 00 09 32 09 35 15 00 27 ff ff 00 00 95 02 75 10 81 02 c0 05 02 09 c5 15 00 26 ff 03 95 01 75 0a 81 02 15 00 25 00 75 06 95 01 81 03 05 02 09 c4 15 00 26 ff 03 95 01 75 0a 81 02 15 00 25 00 75 06 95 01 81 03 05 01 09 39 15 01 25 08 35 00 46 3b 01 66 14 00 75 04 95 01 81 42 75 04 95 01 15 00 25 00 35 00 45 00 65 00 81 03 05 09 19 01 29 0f 15 00 25 01 75 01 95 0f 81 02 15 00 25 00 75 01 95 01 81 03 05 0c 0a b2 00 15 00 25 01 95 01 75 01 81 02 15 00 25 00 75 07 95 01 81 03 05 0f 09 21 85 03 a1 02 09 97 15 00 25 01 75 04 95 01 91 02 15 00 25 00 75 04 95 01 91 03 09 70 15 00 25 64 75 08 95 04 91 02 09 50 66 01 10 55 0e 15 00 26 ff 00 75 08 95 01 91 02 09 a7 15 00 26 ff 00 75 08 95 01 91 02 65 00 55 00 09 7c 15 00 26 ff 00 75 08 95 01 91 02 c0 c0
Discovering characteristic report ... Found it
Ready to receive report value
report_notification_callback
ea 80 ec 7f 52 7f d3 7e 00 00 00 00 00 00 00 00
report_notification_callback
ea 80 55 7f 52 7f d3 7e 00 00 00 00 00 00 00 00

要所解説

必要なserviceとcharacteristicを定義

bluefruitはserviceとcharacteristicを予め定義しておき、接続後にそれを介して通信したい内容を扱います。
reportのnotificationとしてコントローラーのボタンの状態を受け取れます。
Xboxのコントローラーの仕様としてreportMapを読み込んでないと接続したと認識してくれないため、配信内容は把握していますがreport mapを読み込んでいます。
BLEClientService serviceHid(UUID16_SVC_HUMAN_INTERFACE_DEVICE);
BLEClientCharacteristic charaReport(UUID16_CHR_REPORT);
BLEClientCharacteristic charaReportMap(UUID16_CHR_REPORT_MAP);

report(コントローラーのボタン情報)受信のためにcallbackを登録

notificationの受信のためにcallback関数をreportのcharacteristicに登録します。
void report_notification_callback(BLEClientCharacteristic* chr, uint8_t* data,
uint16_t len) {
Serial.println("report_notification_callback");
for (int i = 0; i < len; ++i) {
Serial.printf("%02x ", data[i]);
}
Serial.println();
}

void setup() {
charaReport.setNotifyCallback(report_notification_callback);
}

ペアリングのためのcallbackを登録

reportのnotification有効化やreport mapの読み込みはペアリングした状態で行う必要があるため、下記の流れでペアリングします。

  1. Bluefruit.Scanner.startで検索開始
  2. 検索結果をBluefruit.Scanner.setRxCallbackで登録した関数で受け取り、advertiginsの情報を解釈して期待する接続先の場合はBluefruit.Central.connectを呼んでペアリングしてない状態の接続に進む
  3. ペアリングしてない状態の接続をBluefruit.Central.setConnectCallback に登録した関数で受け取り、Bluefruit.Connection(conn_handle)のrequestPairingを呼んでペアリングに進む
  4. ペアリング状態の接続をBluefruit.Security.setSecuredCallbackで受け取り、Bluefruit.Connectionがsecuredだったら接続できたと判断

void setup() {
Bluefruit.Central.setConnectCallback(connect_callback);
Bluefruit.Central.setDisconnectCallback(disconnect_callback);
Bluefruit.Security.setSecuredCallback(connection_secured_callback);
Bluefruit.Scanner.setRxCallback(scan_callback);
Bluefruit.Scanner.start(0);
}

ペアリングしたらreport map読み込みとreportのnotification有効化

ペアリングしたらcharacteristicの読み書きやnotification有効化が可能になるので、コントローラーとの情報やりとり確立のためにreport mapの読み込みとnotificationの有効化を行います。
  if (!charaReportMap.discover()) {
// Measurement chr is mandatory, if it is not found (valid), then disconnect
Serial.println("not found !!!");
Bluefruit.disconnect(conn_handle);
return;
}
Serial.println("Found it");
read_and_print_chara(conn_handle, &charaReportMap);

Serial.print("Discovering characteristic report ... ");
if (!charaReport.discover()) {
// Measurement chr is mandatory, if it is not found (valid), then disconnect
Serial.println("not found !!!");
Bluefruit.disconnect(conn_handle);
return;
}
Serial.println("Found it");
charaReport.enableNotify();

上記の処理を行うと、コントローラーのLEDの点滅が消えてコントローラーのボタン状態がnotificationとして送信されます。

終わり

nrf52とxboxのコントローラーを接続できました。
ESP32に比べるとエラー無く接続できて安定していました。

参考

今回作成したプログラムです。
https://github.com/asukiaaa/nrf52-bluefluit-xbox-controller-practice

プログラム作成の参考にしたbluefruitのサンプルプログラムです。
examples/Central/central_scan/central_scan.ino
examples/Central/central_scan_advanced/central_scan_advanced.ino
examples/Central/central_custom_hrm/central_custom_hrm.ino
examples/Central/central_hid/central_hid.ino

0 件のコメント :