diff --git a/Cargo.lock b/Cargo.lock index d00e863..a8e03ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -492,6 +492,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -786,6 +796,19 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-lite" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -1107,6 +1130,16 @@ dependencies = [ "syn 2.0.50", ] +[[package]] +name = "io-kit-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b" +dependencies = [ + "core-foundation-sys", + "mach2", +] + [[package]] name = "is-terminal" version = "0.4.12" @@ -1177,18 +1210,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "libusb1-sys" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d0e2afce4245f2c9a418511e5af8718bcaf2fa408aefb259504d1a9cb25f27" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -1220,6 +1241,15 @@ dependencies = [ "imgref", ] +[[package]] +name = "mach2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +dependencies = [ + "libc", +] + [[package]] name = "matchit" version = "0.7.3" @@ -1394,6 +1424,25 @@ dependencies = [ "libc", ] +[[package]] +name = "nusb" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99a726776e551f3ee9b467fe47202f26e64b9bbf715df5443b0904df6f2dcc41" +dependencies = [ + "atomic-waker", + "core-foundation", + "core-foundation-sys", + "futures-core", + "io-kit-sys", + "libc", + "log", + "once_cell", + "rustix", + "slab", + "windows-sys 0.48.0", +] + [[package]] name = "object" version = "0.32.2" @@ -1409,6 +1458,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1803,16 +1858,6 @@ dependencies = [ "nix", ] -[[package]] -name = "rusb" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45fff149b6033f25e825cbb7b2c625a11ee8e6dac09264d49beb125e39aa97bf" -dependencies = [ - "libc", - "libusb1-sys", -] - [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1916,7 +1961,8 @@ dependencies = [ name = "serial" version = "0.1.0" dependencies = [ - "rusb", + "futures-lite", + "nusb", ] [[package]] @@ -2350,12 +2396,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version-compare" version = "0.2.0" diff --git a/serial/Cargo.toml b/serial/Cargo.toml index fa711e5..2a84842 100644 --- a/serial/Cargo.toml +++ b/serial/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rusb = { version = "0.9.3", features = ["vendored"] } +futures-lite = "2.6.0" +nusb = "0.1.13" diff --git a/serial/src/main.rs b/serial/src/main.rs index 05b53c7..5441fac 100644 --- a/serial/src/main.rs +++ b/serial/src/main.rs @@ -7,22 +7,12 @@ //! //! No device found - make sure your device is plugged in and turned on. If it is, it's possible you have a device with a different //! usb id, file a bug with the output of `lsusb` attached. -//! -//! # Examples -//! ``` -//! match rusb::Context::new() { -//! Ok(mut context) => match open_orbic(&mut context) { -//! Some(mut handle) => { -//! send_command(&mut handle, &args[1]) -//! }, -//! None => panic!("No Orbic device found"), -//! }, -//! Err(e) => panic!("Failed to initialize libusb: {0}", e), -//! ```` use std::str; use std::time::Duration; -use rusb::{Context, DeviceHandle, UsbContext}; +use futures_lite::future::block_on; +use nusb::transfer::{Control, ControlType, Recipient, RequestBuffer}; +use nusb::{Device, Interface}; fn main() { let args: Vec = std::env::args().collect(); @@ -32,50 +22,52 @@ fn main() { return; } - match Context::new() { - Ok(mut context) => { - if args[1] == "--root" { - enable_command_mode(&mut context); - } else { - match open_orbic(&mut context) { - Some(mut handle) => send_command(&mut handle, &args[1]), - None => panic!("No Orbic device found"), - } - } - }, - Err(e) => panic!("Failed to initialize libusb: {0}", e), + if args[1] == "--root" { + enable_command_mode(); + } else { + match open_orbic() { + Some(interface) => send_command(interface, &args[1]), + None => panic!("No Orbic device found"), + } } } /// Sends an AT command to the usb device over the serial port /// /// First establish a USB handle and context by calling `open_orbic() -fn send_command(handle: &mut DeviceHandle, command: &str) { +fn send_command(interface: Interface, command: &str) { let mut data = String::new(); data.push_str("\r\n"); data.push_str(command); data.push_str("\r\n"); let timeout = Duration::from_secs(1); - let mut response = [0; 256]; + + let enable_serial_port = Control { + control_type: ControlType::Class, + recipient: Recipient::Interface, + request: 0x22, + value: 3, + index: 1, + }; // Set up the serial port appropriately - handle - .write_control(0x21, 0x22, 3, 1, &[], timeout) + interface + .control_out_blocking(enable_serial_port, &[], timeout) .expect("Failed to send control request"); // Send the command - handle - .write_bulk(0x2, data.as_bytes(), timeout) + block_on(interface.bulk_out(0x2, data.as_bytes().to_vec())) + .into_result() .expect("Failed to write command"); // Consume the echoed command - handle - .read_bulk(0x82, &mut response, timeout) + block_on(interface.bulk_in(0x82, RequestBuffer::new(256))) + .into_result() .expect("Failed to read submitted command"); // Read the actual response - handle - .read_bulk(0x82, &mut response, timeout) + let response = block_on(interface.bulk_in(0x82, RequestBuffer::new(256))) + .into_result() .expect("Failed to read response"); // For some reason, on macOS the response buffer gets filled with garbage data that's @@ -91,18 +83,26 @@ fn send_command(handle: &mut DeviceHandle, command: &str) { /// Send a command to switch the device into generic mode, exposing serial /// /// If the device reboots while the command is still executing you may get a pipe error here, not sure what to do about this race condition. -fn enable_command_mode(context: &mut T) { - if open_orbic(context).is_some() { +fn enable_command_mode() { + if open_orbic().is_some() { println!("Device already in command mode. Doing nothing..."); return; } let timeout = Duration::from_secs(1); - if let Some(handle) = open_device(context, 0x05c6, 0xf626) { - if let Err(e) = handle.write_control(0x40, 0xa0, 0, 0, &[], timeout) { + + if let Some(interface) = open_device(0x05c6, 0xf626) { + let enable_command_mode = Control { + control_type: ControlType::Vendor, + recipient: Recipient::Device, + request: 0xa0, + value: 0, + index: 0, + }; + if let Err(e) = interface.control_out_blocking(enable_command_mode, &[], timeout) { // If the device reboots while the command is still executing we // may get a pipe error here - if e == rusb::Error::Pipe { + if e == nusb::transfer::TransferError::Stall { return; } panic!("Failed to send device switch control request: {0}", e) @@ -113,41 +113,38 @@ fn enable_command_mode(context: &mut T) { panic!("No Orbic device found"); } -/// Get a handle and contet for the orbic device -fn open_orbic(context: &mut T) -> Option> { +/// Get an Interface for the orbic device +fn open_orbic() -> Option { // Device after initial mode switch - if let Some(mut handle) = open_device(context, 0x05c6, 0xf601) { - handle.set_auto_detach_kernel_driver(true).expect("set_auto_detach_kernel_driver failed"); - handle.claim_interface(1).expect("claim_interface(1) failed"); - return Some(handle); + if let Some(device) = open_device(0x05c6, 0xf601) { + let interface = device + .detach_and_claim_interface(1) // will reattach drivers on release + .expect("detach_and_claim_interface(1) failed"); + return Some(interface); } // Device with rndis enabled as well - if let Some(mut handle) = open_device(context, 0x05c6, 0xf622) { - handle.set_auto_detach_kernel_driver(true).expect("set_auto_detach_kernel_driver failed"); - handle.claim_interface(1).expect("claim_interface(1) failed"); - return Some(handle); + if let Some(device) = open_device(0x05c6, 0xf622) { + let interface = device + .detach_and_claim_interface(1) // will reattach drivers on release + .expect("detach_and_claim_interface(1) failed"); + return Some(interface); } None } -/// Generic function to open a USB device -fn open_device(context: &mut T, vid: u16, pid: u16) -> Option> { - let devices = match context.devices() { +/// General function to open a USB device +fn open_device(vid: u16, pid: u16) -> Option { + let devices = match nusb::list_devices() { Ok(d) => d, Err(_) => return None, }; - for device in devices.iter() { - let device_desc = match device.device_descriptor() { - Ok(d) => d, - Err(_) => continue, - }; - - if device_desc.vendor_id() == vid && device_desc.product_id() == pid { + for device in devices { + if device.vendor_id() == vid && device.product_id() == pid { match device.open() { - Ok(handle) => return Some(handle), + Ok(d) => return Some(d), Err(e) => panic!("device found but failed to open: {}", e), } }