2022年11月21日月曜日

Xbox SeriesXのコントローラーをBLEで振動させる


背景

XboxのコントローラーをESP32でBLE通信して使うライブラリを更新していたところ、HID(service: 0x1812)のReport(characteristic: 0x2a4d)が書き込み可能と気づきました。
XboxのコントローラーにはLEDは無いものの振動(バイブレーション)機能はあるのでそれの制御口と期待して試行錯誤したところ、期待通り制御できました。

分かったことを記事にまとめます。

対象

Xboxのコントローラー
【純正品】Xbox ワイヤレス コントローラー + USB-C ケーブル

9000円弱出して2週間ほど待って良いのならxbox design labで色を選んで買えます。
Xbox Design Lab

コントローラーのファームウェアはxbox accessoriesで最新版にしてください。
この記事では2022年9月に公開されたであろうxbox accessoriesを利用して、バージョン5.15.3168のファームウェアをコントーローラーに書き込んで動作確認しています。

把握した書き込み内容

試行錯誤の末把握したHID Reportの内容がこちらです。
byte順役割設定範囲
0モーターの選択
0bit: 中央モーター
1bit: 揺さぶりモーター
2bit: 右モーター
3bit: 左モーター
4-7bit:未使用
0:無効
1:有効
1左モーターの強さ0~100
2右モーターの強さ0~100
3揺さぶりモーターの強さ0~100
4中央左モーターの強さ0~100
5振動時間0~255(最長2.55秒)
6休止時間0~255(最長2.55秒)
7繰り返し回数0~255(回)

範囲が0~100の領域に100以上の値を書き込むと100と同じ動作をします。
0byteの4-7bitは後半で解説するReport Mapでも用途が示されない最大値が0の区画なので、使用されていないようです。

上記の設定により下記の動作をします。
  1. 休止時間分待つ
  2. 振動時間分選択したモーターを指定された強さで駆動
  3. 繰り返し回数が1回以上の場合、上記1と2を指定回数分繰り返す

動作中に書き込みがあった場合、動作を止めて新しい指示に従います。
通信が途切れると動作停止します。

全てのビットを1にして8byteを送信すると2.55秒毎に全てのモーターの全力振動が255回繰り返されるので、意図せずそうなった場合は通信を切るか新しく何かを書き込むのが良いです。

書き込み先はservice: 0x1812, characteristic 0x2a4dの書き込み可能な方

ESP32でNimBLEを利用してHID(service: 0x1812)に紐づくcharacteristicを表示すると、下記の情報を確認できます。
Service: uuid: 0x1812, start_handle: 22 0x0016, end_handle: 35 0x0023
Characteristic: uuid: 0x2a4a, handle: 24 0x0018, props: 0x02
Characteristic: uuid: 0x2a4c, handle: 26 0x001a, props: 0x04
Characteristic: uuid: 0x2a4b, handle: 28 0x001c, props: 0x02
Characteristic: uuid: 0x2a4d, handle: 30 0x001e, props: 0x12
Descriptor: uuid: 0x2902, handle: 31
Characteristic: uuid: 0x2a4d, handle: 34 0x0022, props: 0x0e

Reportである0x2a4dは2つありまして、その片方のhandleが34のものが書き込み可能なReportのcharacteristicです。
2つあるのが詰まりどころで、serviceとcharacteristicのidで取得を試みると書き込みできない方のcharacteristicが先にあるためそちらが取り出されてしまいます。

characteristicの絞り込み条件に書き込み可能の有無を指定できない場合は、一覧を出して書き込み可能なものを取り出すのが良いです。

書き込み内容はReport MapのReport ID3として説明がある

s:0x1812 c:0x2a4b h:28で読み取れる情報はReport Mapと言う情報の構造説明になっています。
これをReport Mapの解析webサービスに渡して見やすくしてもらい、Report ID3を抜粋したのが下記です。
0x05, 0x0F,        //   Usage Page (PID Page)
0x09, 0x21, // Usage (0x21)
0x85, 0x03, // Report ID (3)
0xA1, 0x02, // Collection (Logical)
0x09, 0x97, // Usage (0x97)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x00, // Logical Maximum (0)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x09, 0x70, // Usage (0x70)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x64, // Logical Maximum (100)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x09, 0x50, // Usage (0x50)
0x66, 0x01, 0x10, // Unit (System: SI Linear, Time: Seconds)
0x55, 0x0E, // Unit Exponent (-2)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x09, 0xA7, // Usage (0xA7)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x65, 0x00, // Unit (None)
0x55, 0x00, // Unit Exponent (0)
0x09, 0x7C, // Usage (0x7C)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection

これを解釈すると
Report IDのPageの用途は0x21 Physical Interface Devices 物理装置
各Unitの解釈は
用途試行錯誤して分かった用途ビット数組数最大値その他
0x97
System Function Shift
モーターの選択141
空欄不明140
0x70
Magnitude
大きさ
モーターの強さ84100
0x50
Duration
期間
モーターの駆動時間81255単位0.01
0x7a
System Speaker Mute
消音
休止時間81255単位0.01
0x7c
Loop Count
繰り返し回数
繰り返し回数81255

用途の把握はHID Usage Tables (PDF)Device Class Definition for Physical Interface Devices(PDF)を参照しました。

Report Mapだけを見たときは意味を解釈できなかったのですが、試行錯誤して機能を把握した上で読み解くと試行錯誤して分かったのと同様の用途や数値などが指定されていたと分かりました。

ESP32で振動させました

何をどこに送ればコントローラーをどのように振動させられるか分かったので、ESP32のライブラリにも機能を追加しました。
横で下記のプログラムを書き込んだESP32とxboxのコントローラーを接続すれば振動します。

examples/vibration/vibration.ino


終わり

Report ID3として管理される0x2a4dのcharactaristicに情報を書き込みxboxのコントローラーを振動させれました。
BLEのReport IDの読み方を大まかに把握できました。
成果としてESP32のライブラリでコントローラーを振動させれました。

参考

BLE Keyboard(Surface キーボード) の Report Map
USB Descriptor and Request Parser(Report Mapの解析webサービス)
examples/vibration/vibration.ino

変更履歴

2024.10.05
iframeのamazonへのリンクが無効になっていたので張り直しました。

0 件のコメント :