diff --git a/src/lib.rs b/src/lib.rs index 756d729..f7fa47b 100644 --- a/src/lib.rs +++ b/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, verbose: bool, @@ -51,14 +64,14 @@ impl<'t, Ctx: rusb::UsbContext> Controller<'t, Ctx> { } fn write(&self, data: &[u8], timeout: Duration) -> rusb::Result { - 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 { - self.device.read_bulk(0x82, buf, timeout) + self.device.read_bulk(READ | CON, buf, timeout) } - pub fn init(&self) -> rusb::Result { + pub fn init(&self, imu: bool) -> rusb::Result { 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 --- \\ diff --git a/src/main.rs b/src/main.rs index 26ee0a4..ee8d919 100644 --- a/src/main.rs +++ b/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, } fn main() -> Result<(), Box> { - 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> { 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(device: &rusb::DeviceHandle) -> rusb::R Ok(out_path) } + +fn hid_dump(device: Controller, 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(()) +}