HIDについて調べものメモ
Human Interface Device(HID)がPCとどんなやりとりをしているのか気になったので調べる。
HIDのドキュメントや仕様書は以下のものがあったけど全体像が見えていないのであまりピンとこない。
- Introduction to Human Interface Devices (HID) - Windows Hardware Developer, https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/
- Device Class Definition for HID 1.11 - USB-IF, https://www.usb.org/document-library/device-class-definition-hid-111
とっかかりとして以下の技術解説記事がわかりやすい。(ほかのUSBの解説記事も参考になる)
- HID (Human Interface Device) クラスについて - インターフェイス株式会社, https://www.itf.co.jp/tech/road-to-usb-master/hid_class
HID (Human Interface Device) クラスでは、レポートと呼ばれる単位でデータを転送します。例えばマウスの場合、各ボタンが押されているかどうか、水平方向の移動量、垂直方向の移動量、ホイールの移動量といった情報をまとめたレポートを定期的に転送します。
wio-terminalのサンプルにHIDマウスの実装例があった。これはArduinoのライブラリを使っているので、ライブラリの実装を追っていく。
まずサンプルをコンパイルすると以下のログが出るので使っているライブラリがMouse.cppとHID.cppであることがわかる。HID.cppはパスにsamdが入っているのでマイコンごとの実装っぽい。
Using cached library dependencies for file: C:\Program Files (x86)\Arduino\libraries\Mouse\src\Mouse.cpp
Using cached library dependencies for file: C:\Users\user\AppData\Local\Arduino15\packages\Seeeduino\hardware\samd\1.8.3\libraries\HID\HID.cpp
ライブラリの呼び出しをさかのぼっていくと、だいたい以下のソースが見つかった。
以下の部分がレポートディスクリプタというものの定義っぽい。HIDはレポートという単位でデータをやり取りする。レポートディスクリプタはレポートの構造を定義するバイト列。
マウスの例だと以下でレポートを送信している。
まずはレポートディスクリプタのバイト列の構造についてみていく。仕様書の"6.2.2 Report Descriptor"あたりから説明されている。
- Device Class Definition for Human Interface Devices (HID) Version 1.11
https://www.usb.org/sites/default/files/hid1_11.pdf
レポートディスクリプタはItemというデータが並んでいるもので、Itemのフォーマットは下のようになっていうる。(ItemにはShort ItemとLong Itemがあって、下のはShort Item)
Mouse.cppで定義されているレポートディスクリプタの一部をフォーマットに当てはめると次のようになる。
Tag Type Size Data
0000| 01| 01 (0x05), 0x01, // USAGE_PAGE (Generic Desktop) // 54
0000| 10| 01 (0x09), 0x02, // USAGE (Mouse)
1010| 00| 01 (0xa1), 0x01, // COLLECTION (Application)
0000| 10| 01 (0x09), 0x01, // USAGE (Pointer)
1010| 00| 01 (0xa1), 0x00, // COLLECTION (Physical)
1000| 01| 01 (0x85), 0x01, // REPORT_ID (1)
...
1000| 00| 01 (0x81), 0x06, // INPUT (Data,Var,Rel)
1100| 00| 00 (0xc0), // END_COLLECTION
1100| 00| 00 (0xc0), // END_COLLECTION
- Sizeが後ろに続くDataの数を表している。この例だとEND_COLLECTIONというItem以外はすべてSizeが1なのでデータは1byteのみである。
- TypeとTagでItemの種別を表し、Dataが種別ごとのItemで使われる値を表している。これから各Type/Tag/Dataの定義を見ていく。
ちょっと気になっていたのだけど、M5Stamp C3U(esp32-c3)はHIDデバイスとして扱えないのかな?ボードにUSBポートがついていて、マイコンからアクセスできるならホストと接続したときに自分はHID Classのデバイスだと返せばいける?
esp32-c3のドキュメントを見るとどうもハード的にUSB Serial/JTAG Controller(というClassがある?)に固定されているっぽいので、HIDとして扱うことはできなさそう。
Note that, in contrast with the USB OTG peripheral in some Espressif chips, the USB Serial/JTAG Controller is a fixed function device, implemented entirely in hardware. This means it cannot be reconfigured to perform any function other than to provide a serial channel and JTAG debugging functionality.
https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-guides/usb-serial-jtag-console.html
じゃあwio-terminal(ATSAMD51N19A)はどうやってHIDデバイスとして見せているのか気になるところ。
接続したデバイスのディスクリプタを解析できるUSB Device Tree Viewerというツールがあるらしい。便利。
Itemごとの意味を見てみる。まずUSAGE_PAGEとUSAGEについて。
tag名 | Tag | Type | Size |
---|---|---|---|
USAGE_PAGE | 0000 | 01(Global) | nn |
USAGE | 0000 | 10(Local) | nn |
Usageはデータがどう使われるかを決めている。例えば、レポートが3つの8bitフィールドで構成されていたとすると、Usageはそれらがx, y, zの入力であることを定義したりする。
HIDデバイスの用途?ごとにUsage Pageが割り振られていて、その中でさらにUsage IDが割り振られているイメージ。
HID Usage Tables, https://usb.org/document-library/hid-usage-tables-13
Usage Pageの例:
- Generic Desktop Page (0x01)
- 01 Pointer
- 02 Mouse
- 03 Reserved
- 04 Joystick
- 05 Gamepad
- Simulation Controls Page (0x02)
- VR Controls Page (0x03)
- ...