Add HID report dumper
This commit is contained in:
parent
0bb97b167f
commit
24539a95d2
43
src/lib.rs
43
src/lib.rs
@ -18,6 +18,19 @@ pub mod descriptor {
|
||||
}
|
||||
}
|
||||
|
||||
mod endpoint {
|
||||
/// READ from the endpoint
|
||||
pub const READ: u8 = 0x80;
|
||||
/// WRITE to the endpoint
|
||||
pub const WRITE: u8 = 0x00;
|
||||
/// HID endpoint for getting HID data
|
||||
pub const HID: u8 = 0x01;
|
||||
/// Control endpoint for control transactions
|
||||
pub const CON: u8 = 0x02;
|
||||
}
|
||||
|
||||
use endpoint::*;
|
||||
|
||||
pub struct Controller<'t, Ctx: rusb::UsbContext> {
|
||||
device: &'t DeviceHandle<Ctx>,
|
||||
verbose: bool,
|
||||
@ -51,14 +64,14 @@ impl<'t, Ctx: rusb::UsbContext> Controller<'t, Ctx> {
|
||||
}
|
||||
|
||||
fn write(&self, data: &[u8], timeout: Duration) -> rusb::Result<usize> {
|
||||
self.device.write_bulk(0x02, data, timeout)
|
||||
self.device.write_bulk(WRITE | CON, data, timeout)
|
||||
}
|
||||
|
||||
fn read(&self, buf: &mut [u8], timeout: Duration) -> rusb::Result<usize> {
|
||||
self.device.read_bulk(0x82, buf, timeout)
|
||||
self.device.read_bulk(READ | CON, buf, timeout)
|
||||
}
|
||||
|
||||
pub fn init(&self) -> rusb::Result<usize> {
|
||||
pub fn init(&self, imu: bool) -> rusb::Result<usize> {
|
||||
let mut out: usize = 0;
|
||||
let timeout = Duration::from_secs(1);
|
||||
|
||||
@ -74,10 +87,14 @@ impl<'t, Ctx: rusb::UsbContext> Controller<'t, Ctx> {
|
||||
out += self.dbg_write(UNKNOWN_COMMAND_0x15_ARG_0x03, timeout)?;
|
||||
|
||||
out += self.set_player_led(0)?;
|
||||
out += self.dbg_write(IMU_COMMAND_0x02, timeout)?;
|
||||
if imu {
|
||||
out += self.dbg_write(IMU_COMMAND_0x02, timeout)?; // Enable IMU?
|
||||
}
|
||||
out += self.dbg_write(OUT_UNKNOWN_COMMAND_0x11, timeout)?;
|
||||
out += self.dbg_write(UNKNOWN_COMMAND_0x0A, timeout)?;
|
||||
out += self.dbg_write(IMU_COMMAND_0x04, timeout)?;
|
||||
if imu {
|
||||
out += self.dbg_write(IMU_COMMAND_0x04, timeout)?; // Lock and enable IMU output?
|
||||
}
|
||||
out += self.dbg_write(ENABLE_HAPTICS, timeout)?;
|
||||
out += self.dbg_write(OUT_UNKNOWN_COMMAND_0x10, timeout)?;
|
||||
out += self.dbg_write(OUT_UNKNOWN_COMMAND_0x01, timeout)?;
|
||||
@ -141,6 +158,22 @@ impl<'t, Ctx: rusb::UsbContext> Controller<'t, Ctx> {
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn detach(&self) -> rusb::Result<()> {
|
||||
self.device.detach_kernel_driver(0)
|
||||
}
|
||||
|
||||
pub fn attach(&self) -> rusb::Result<()> {
|
||||
self.device.attach_kernel_driver(0)
|
||||
}
|
||||
|
||||
pub fn read_hid(&self) -> rusb::Result<[u8; 64]> {
|
||||
let mut buf = [0; 64];
|
||||
|
||||
self.device
|
||||
.read_bulk(READ | HID, &mut buf, Duration::from_secs(10))?;
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
|
||||
// --- Here there be raw USB bullshit --- \\
|
||||
|
41
src/main.rs
41
src/main.rs
@ -6,6 +6,7 @@ use procon2::{
|
||||
Controller,
|
||||
descriptor::{VID, pid},
|
||||
};
|
||||
use rusb::UsbContext;
|
||||
|
||||
#[rustfmt::skip]
|
||||
const PLAYER: [u8; 16] = [
|
||||
@ -33,10 +34,16 @@ struct Args {
|
||||
verbose: bool,
|
||||
/// Dumps the firmware of all connected controllers
|
||||
dump: bool,
|
||||
|
||||
/// If set, doesn't init the IMU
|
||||
imu_off: bool,
|
||||
/// Dumps every N hid messages
|
||||
hid: Option<usize>,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let Args { verbose, dump } = Args::from_args();
|
||||
#[rustfmt::skip]
|
||||
let Args { verbose, dump, imu_off, hid } = Args::from_args();
|
||||
|
||||
let mut devices = vec![];
|
||||
|
||||
@ -47,13 +54,18 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
println!("Found player {}: {device:?}!", devices.len() + 1);
|
||||
let device = device.open()?;
|
||||
let controller = Controller::new(&device);
|
||||
controller.verbose(verbose).init()?;
|
||||
controller.verbose(verbose).init(!imu_off)?;
|
||||
device.claim_interface(1)?;
|
||||
|
||||
devices.push(device);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(get_nth) = hid {
|
||||
hid_dump(Controller::new(&devices[0]), get_nth)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if dump {
|
||||
for device in &devices {
|
||||
let path = make_path(device)?;
|
||||
@ -135,3 +147,28 @@ fn make_path<Ctx: rusb::UsbContext>(device: &rusb::DeviceHandle<Ctx>) -> rusb::R
|
||||
|
||||
Ok(out_path)
|
||||
}
|
||||
|
||||
fn hid_dump<Ctx: UsbContext>(device: Controller<Ctx>, every_nth: usize) -> rusb::Result<()> {
|
||||
device.detach().ok(); // may or may not have a kernel driver
|
||||
let mut stdout = std::io::stdout().lock();
|
||||
let mut leds = 0xe1u8;
|
||||
loop {
|
||||
for _ in 0..(every_nth.saturating_sub(1)) {
|
||||
device.read_hid()?;
|
||||
}
|
||||
device.set_player_led(leds)?;
|
||||
leds = leds.rotate_right(1);
|
||||
|
||||
let report = device.read_hid()?;
|
||||
for (idx, byte) in report.iter().enumerate() {
|
||||
if idx % 16 == 0 {
|
||||
write!(stdout, "\n{idx:02x}: ").ok();
|
||||
}
|
||||
write!(stdout, " {byte:02x}").ok();
|
||||
}
|
||||
writeln!(stdout).ok();
|
||||
}
|
||||
|
||||
// device.attach()?;
|
||||
// Ok(())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user