Why
生バイトの解釈を 1 箇所に閉じる。ここが純関数であれば、以降のフレーム換算とイベント化を実機なしでテストできる。
What
src/report_decode.rs を作る。依存は bitflags だけにする。hidapi と windows に依存させない。
公開する型は以下。
pub struct PadState {
pub buttons: Buttons,
pub dpad: Option<Direction>,
pub left_stick: (u8, u8),
pub device_ts: u32,
pub seq: u8,
}
pub enum Direction { N, NE, E, SE, S, SW, W, NW }
pub enum Device { DualSense, DualShock4 }
pub fn decode(device: Device, report: &[u8]) -> Option<PadState>;
Buttons は bitflags で定義する。SQUARE、CROSS、CIRCLE、TRIANGLE、L1、R1、L2、R2、CREATE、OPTIONS、L3、R3、PS、TOUCHPAD。
DualSense の USB 入力レポート (report id 0x01、64 バイト) のオフセット。
| byte |
内容 |
| 0 |
report id 0x01 |
| 1, 2 |
左スティック X, Y |
| 3, 4 |
右スティック X, Y |
| 5, 6 |
L2, R2 アナログ |
| 7 |
seq_number |
| 8 |
下位 4bit が dpad hat、bit4 が SQUARE、bit5 が CROSS、bit6 が CIRCLE、bit7 が TRIANGLE |
| 9 |
bit0 が L1、bit1 が R1、bit2 が L2、bit3 が R2、bit4 が CREATE、bit5 が OPTIONS、bit6 が L3、bit7 が R3 |
| 10 |
bit0 が PS、bit1 が TOUCHPAD |
| 12-15 |
reserved |
| 16-21 |
gyro |
| 22-27 |
accel |
| 28-31 |
sensor_timestamp (little endian u32) |
DualShock 4 の USB 入力レポート (report id 0x01) のオフセット。
| byte |
内容 |
| 0 |
report id 0x01 |
| 1, 2 |
左スティック X, Y |
| 3, 4 |
右スティック X, Y |
| 5 |
下位 4bit が dpad hat、bit4 が SQUARE、bit5 が CROSS、bit6 が CIRCLE、bit7 が TRIANGLE |
| 6 |
bit0 が L1、bit1 が R1、bit2 が L2、bit3 が R2、bit4 が SHARE、bit5 が OPTIONS、bit6 が L3、bit7 が R3 |
| 7 |
bit0 が PS、bit1 が TOUCHPAD、上位 6bit が 6bit カウンタ |
| 8, 9 |
L2, R2 アナログ |
| 10, 11 |
sensor_timestamp (little endian u16) |
| 12 |
温度 |
| 13-18 |
gyro |
| 19-24 |
accel |
dpad hat の値は 0 が上。時計回りに 1 が右上、2 が右、3 が右下、4 が下、5 が左下、6 が左、7 が左上、8 がニュートラル。8 のとき dpad は None にする。
DualShock 4 は seq 専用のバイトを持たない。byte 7 の上位 6bit を seq に入れる。
このオフセット表は Linux の hid-playstation の構造体定義から書いた。DualSense の実機ダンプは #10 (comment) にある。突き合わせは済んでいて、byte 12 を除いて一致した。
byte 12 は reserved ではなく、レポートごとに 1 進む 2 本目のカウンタになる。上の表はまだ reserved と書いてあるので、実装では byte 12 を読まない。
ダンプは先頭 32 バイトまでなので、byte 32 以降は未検証のまま残る。DualShock 4 の表は実機で検証していない。ダンプと食い違う箇所を見つけたらダンプを正としてオフセットを直し、この表との差分を issue にコメントする。
report[0] が 0x01 でなければ None を返す。レポート長が必要なオフセットに足りなければ None を返す。
ゴール
cargo test で、DualSense と DualShock 4 それぞれについて固定バイト列から期待する PadState が得られるテストが通る。DualSense のテストデータは上のダンプの 3 件を使う
L1 と R1 の同時押し、dpad の 8 方向すべて、dpad のニュートラル、レポート長不足、report id 不一致のケースがテストされている
report_decode.rs の依存が bitflags だけである
cargo coupling --check --min-grade=B --max-circular=0 ./src が通る
分解: #1 (comment) / Task 2 / 3c812e1b19b2
Why
生バイトの解釈を 1 箇所に閉じる。ここが純関数であれば、以降のフレーム換算とイベント化を実機なしでテストできる。
What
src/report_decode.rsを作る。依存はbitflagsだけにする。hidapiとwindowsに依存させない。公開する型は以下。
Buttonsはbitflagsで定義する。SQUARE、CROSS、CIRCLE、TRIANGLE、L1、R1、L2、R2、CREATE、OPTIONS、L3、R3、PS、TOUCHPAD。DualSense の USB 入力レポート (report id
0x01、64 バイト) のオフセット。0x01seq_numbersensor_timestamp(little endian u32)DualShock 4 の USB 入力レポート (report id
0x01) のオフセット。0x01sensor_timestamp(little endian u16)dpad hat の値は
0が上。時計回りに1が右上、2が右、3が右下、4が下、5が左下、6が左、7が左上、8がニュートラル。8のときdpadはNoneにする。DualShock 4 は
seq専用のバイトを持たない。byte 7 の上位 6bit をseqに入れる。このオフセット表は Linux の
hid-playstationの構造体定義から書いた。DualSense の実機ダンプは #10 (comment) にある。突き合わせは済んでいて、byte 12 を除いて一致した。byte 12 は reserved ではなく、レポートごとに 1 進む 2 本目のカウンタになる。上の表はまだ reserved と書いてあるので、実装では byte 12 を読まない。
ダンプは先頭 32 バイトまでなので、byte 32 以降は未検証のまま残る。DualShock 4 の表は実機で検証していない。ダンプと食い違う箇所を見つけたらダンプを正としてオフセットを直し、この表との差分を issue にコメントする。
report[0]が0x01でなければNoneを返す。レポート長が必要なオフセットに足りなければNoneを返す。ゴール
cargo testで、DualSense と DualShock 4 それぞれについて固定バイト列から期待するPadStateが得られるテストが通る。DualSense のテストデータは上のダンプの 3 件を使うL1とR1の同時押し、dpad の 8 方向すべて、dpad のニュートラル、レポート長不足、report id 不一致のケースがテストされているreport_decode.rsの依存がbitflagsだけであるcargo coupling --check --min-grade=B --max-circular=0 ./srcが通る分解: #1 (comment) / Task 2 / 3c812e1b19b2