diff --git a/Cargo.lock b/Cargo.lock index e91aa0c..fc9182f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,26 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "auto-args" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40797fd8889b7625595cb391d6f8428802b65c22023ada3dc08d67953ac5e5e2" +dependencies = [ + "auto-args-derive", +] + +[[package]] +name = "auto-args-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d4cbc684c4d4c80b06cd1009b7b78fe5a910187d1daeda1cc04319207b5894f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "cc" version = "1.2.31" @@ -35,13 +55,32 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid", +] + [[package]] name = "procon2" version = "0.1.0" dependencies = [ + "auto-args", "rusb", ] +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rusb" version = "0.9.4" @@ -58,6 +97,23 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index 0263a3d..3da1164 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" edition = "2024" [dependencies] +auto-args = "0.3.2" rusb = "0.9.4" diff --git a/src/lib.rs b/src/lib.rs index 8ad106c..756d729 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -133,7 +133,7 @@ impl<'t, Ctx: rusb::UsbContext> Controller<'t, Ctx> { // debug-print the header if self.verbose { - println!("HEAD: {:02x?}", &buf[..16]); + println!("CMD: {:02x?}\n => {:02x?}", command, &buf[..16]); } let mut data = [0; 64]; diff --git a/src/main.rs b/src/main.rs index 84671cb..26ee0a4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ use std::{error::Error, fmt::Display, io::Write, path::Path, thread::sleep, time::Duration}; +use auto_args::AutoArgs; + use procon2::{ Controller, descriptor::{VID, pid}, @@ -25,16 +27,16 @@ const PLAYER: [u8; 16] = [ 0b1010, ]; -fn main() -> Result<(), Box> { - let (mut dump, mut verbose) = (false, false); +#[derive(Debug, AutoArgs)] +struct Args { + /// Prints the sent and received messages + verbose: bool, + /// Dumps the firmware of all connected controllers + dump: bool, +} - for arg in std::env::args() { - match arg.as_str() { - "dump" => dump = true, - "verbose" => verbose = true, - _ => {} - } - } +fn main() -> Result<(), Box> { + let Args { verbose, dump } = Args::from_args(); let mut devices = vec![]; @@ -53,20 +55,9 @@ fn main() -> Result<(), Box> { } if dump { - for (player, device) in devices.iter().enumerate() { + for device in &devices { + let path = make_path(device)?; let controller = Controller::new(device).verbose(verbose); - let descriptor = device.device().device_descriptor()?; - let name = if let Some(nid) = descriptor.product_string_index() { - device.read_string_descriptor_ascii(nid)? - } else { - String::from("procon") - }; - let path = format!( - "{name} {:04x}_{:04x}_{}-{player:x}.bin", - descriptor.vendor_id(), - descriptor.product_id(), - descriptor.device_version() - ); procon_dump(controller, path)?; } return Ok(()); @@ -92,6 +83,7 @@ fn main() -> Result<(), Box> { Ok(()) } +/// Dumps a Controller's firmware to a file at the given path fn procon_dump( controller: Controller<'_, Ctx>, path: impl AsRef + Display, @@ -105,11 +97,12 @@ fn procon_dump( file.write_all(&data)?; // progress bar - if addr % 0x8000 == 0 { - controller.set_player_led(PLAYER[7 - (addr >> 15 & 7)])?; + if addr % 0x40000 == 0 { print!("."); std::io::stdout().flush()?; - sleep(Duration::from_millis(0)); + } + if addr % 0x8000 == 0 { + controller.set_player_led(PLAYER[7 - ((addr / 0x8000) & 7)])?; } } @@ -117,3 +110,28 @@ fn procon_dump( println!("\nDumped to file {path}"); Ok(()) } + +/// Creates a path to store a given device's firmware at, avoiding naming collisions +fn make_path(device: &rusb::DeviceHandle) -> rusb::Result { + let descriptor = device.device().device_descriptor()?; + let name = match descriptor.product_string_index() { + Some(nid) => device.read_string_descriptor_ascii(nid)?, + None => String::from("procon"), + }; + + let path = format!( + "{name} {:04x}_{:04x}_{}", + descriptor.vendor_id(), + descriptor.product_id(), + descriptor.device_version() + ); + + let mut count = 1; + let mut out_path = format!("{path}.bin"); + while std::fs::exists(&out_path).unwrap_or(true) { + out_path = format!("{path}({count}).bin"); + count += 1; + } + + Ok(out_path) +}