### Perform Control Transfers (IN/OUT) Source: https://context7.com/kevinmehall/nusb/llms.txt Use ControlIn and ControlOut for device configuration and vendor-specific commands. Specify transfer type, recipient, request, value, index, and data. Includes examples for vendor-specific and class-specific transfers. ```rust use nusb::transfer::{ControlIn, ControlOut, ControlType, Recipient}; use nusb::MaybeFuture; use std::time::Duration; fn main() -> Result<(), std::io::Error> { let device_info = nusb::list_devices() .wait()? .find(|d| d.vendor_id() == 0x1234 && d.product_id() == 0x5678) .expect("device not found"); let device = device_info.open().wait()?; let interface = device.claim_interface(0).wait()?; // Send vendor-specific control OUT transfer (host to device) interface.control_out( ControlOut { control_type: ControlType::Vendor, recipient: Recipient::Device, request: 0x10, // bRequest: vendor-defined command value: 0x0001, // wValue index: 0x0000, // wIndex data: &[0x01, 0x02, 0x03, 0x04], }, Duration::from_millis(1000), ).wait()?; println!("Control OUT transfer completed"); // Receive data via control IN transfer (device to host) let response: Vec = interface.control_in( ControlIn { control_type: ControlType::Vendor, recipient: Recipient::Device, request: 0x20, // bRequest: vendor-defined query value: 0x0000, // wValue index: 0x0000, // wIndex length: 64, // Maximum bytes to read }, Duration::from_millis(1000), ).wait()?; println!("Control IN received {} bytes: {:02x?}", response.len(), response); // Class-specific control transfer example (e.g., HID set report) interface.control_out( ControlOut { control_type: ControlType::Class, recipient: Recipient::Interface, request: 0x09, // SET_REPORT value: 0x0200, // Report type and ID index: 0x0000, // Interface number data: &[0x00, 0x01], }, Duration::from_millis(500), ).wait()?; Ok(()) } ``` -------------------------------- ### Find and Open a USB Device Source: https://context7.com/kevinmehall/nusb/llms.txt Filter devices by vendor and product ID, then open a handle to access device descriptors and configuration details. ```rust use nusb::MaybeFuture; use std::io::{Error, ErrorKind}; fn main() -> Result<(), std::io::Error> { const VENDOR_ID: u16 = 0x1234; const PRODUCT_ID: u16 = 0x5678; // Find device by VID/PID let device_info = nusb::list_devices() .wait()? .find(|dev| dev.vendor_id() == VENDOR_ID && dev.product_id() == PRODUCT_ID) .ok_or(Error::new(ErrorKind::NotFound, "device not connected"))?; println!("Found device: {:?}", device_info); println!("Serial: {:?}", device_info.serial_number()); // Open the device let device = device_info.open().wait()?; // Get device descriptor information let descriptor = device.device_descriptor(); println!("USB version: 0x{:04X}", descriptor.usb_version()); println!("Max packet size EP0: {}", descriptor.max_packet_size_0()); println!("Num configurations: {}", descriptor.num_configurations()); // Get active configuration info match device.active_configuration() { Ok(config) => { println!("Active config: {}", config.configuration_value()); println!("Max power: {} mA", config.max_power() * 2); } Err(e) => println!("No active configuration: {}", e), } Ok(()) } ``` -------------------------------- ### Enumerate USB Buses and Devices Source: https://context7.com/kevinmehall/nusb/llms.txt Use list_buses() to retrieve host controller information and associate devices with their respective bus connections. ```rust use nusb::MaybeFuture; use std::collections::HashMap; fn main() -> Result<(), nusb::Error> { // Get all devices let devices: Vec<_> = nusb::list_devices().wait()?.collect(); // Get all buses and group devices let buses: HashMap<_, _> = nusb::list_buses() .wait()? .map(|bus| { let bus_id = bus.bus_id().to_owned(); let bus_devices: Vec<_> = devices.iter() .filter(|d| d.bus_id() == bus_id) .collect(); (bus_id, (bus, bus_devices)) }) .collect(); for (bus_id, (bus, devices)) in &buses { println!("Bus {}: {:?}", bus_id, bus.controller_type()); if let Some(name) = bus.system_name() { println!(" Name: {}", name); } if let Some(driver) = bus.driver() { println!(" Driver: {}", driver); } for device in devices { println!(" Device {}: {:04x}:{:04x} {}", device.device_address(), device.vendor_id(), device.product_id(), device.product_string().unwrap_or("Unknown")); } } Ok(()) } ``` -------------------------------- ### Perform Async Transfers with Tokio Source: https://context7.com/kevinmehall/nusb/llms.txt Demonstrates low-level async endpoint submission and high-level buffered I/O using Tokio's async traits. Requires the 'tokio' feature flag. ```rust use nusb::transfer::{Bulk, In, Out, Buffer}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; #[tokio::main] async fn main() -> Result<(), std::io::Error> { let device_info = nusb::list_devices() .await? .find(|d| d.vendor_id() == 0x1234 && d.product_id() == 0x5678) .expect("device not found"); let device = device_info.open().await?; let interface = device.claim_interface(0).await?; // Low-level async endpoint API let mut ep_out = interface.endpoint::(0x02)?; let mut ep_in = interface.endpoint::(0x82)?; // Submit and await transfer completion ep_out.submit(vec![0x01, 0x02, 0x03].into()); let completion = ep_out.next_complete().await; completion.status?; ep_in.submit(Buffer::new(64)); let completion = ep_in.next_complete().await; println!("Received: {:02x?}", &completion.buffer[..completion.actual_len]); // High-level async I/O with Tokio traits let mut writer = interface.endpoint::(0x02)? .writer(4096) .with_num_transfers(4); let mut reader = interface.endpoint::(0x82)? .reader(4096) .with_num_transfers(4); // Use Tokio's AsyncWriteExt writer.write_all(b"Hello async USB!").await?; writer.flush().await?; // Use Tokio's AsyncReadExt let mut buf = vec![0u8; 64]; let n = reader.read(&mut buf).await?; println!("Read {} bytes: {:02x?}", n, &buf[..n]); Ok(()) } ``` -------------------------------- ### List Connected USB Devices Source: https://context7.com/kevinmehall/nusb/llms.txt Iterate through all connected USB devices to retrieve vendor, product, and interface information. ```rust use nusb::MaybeFuture; fn main() { // List all connected USB devices (blocking) for device in nusb::list_devices().wait().unwrap() { println!( "Device {}.{:03} - VID:{:04x} PID:{:04x} {} {}", device.bus_id(), device.device_address(), device.vendor_id(), device.product_id(), device.manufacturer_string().unwrap_or("Unknown"), device.product_string().unwrap_or("Unknown") ); // Show interface information for interface in device.interfaces() { println!( " Interface {}: class=0x{:02X} subclass=0x{:02X}", interface.interface_number(), interface.class(), interface.subclass() ); } } } ``` -------------------------------- ### Perform Low-Level Bulk Transfers Source: https://context7.com/kevinmehall/nusb/llms.txt Open bulk endpoints using Interface::endpoint() and perform transfers with submit() and wait_next_complete() for streaming. transfer_blocking is convenient for single transfers. ```rust use nusb::transfer::{Bulk, In, Out, Buffer}; use nusb::MaybeFuture; use std::time::Duration; fn main() -> Result<(), std::io::Error> { let device_info = nusb::list_devices() .wait()? .find(|d| d.vendor_id() == 0x1234 && d.product_id() == 0x5678) .expect("device not found"); let device = device_info.open().wait()?; let interface = device.claim_interface(0).wait()?; // Open bulk OUT endpoint (address 0x02) let mut ep_out = interface.endpoint::(0x02)?; // Open bulk IN endpoint (address 0x82) let mut ep_in = interface.endpoint::(0x82)?; println!("EP OUT max packet size: {}", ep_out.max_packet_size()); println!("EP IN max packet size: {}", ep_in.max_packet_size()); // Send data using transfer_blocking (convenient for single transfers) let send_data = vec![0x01, 0x02, 0x03, 0x04, 0x05]; let completion = ep_out.transfer_blocking(send_data.into(), Duration::from_secs(1)); completion.status?; println!("Sent {} bytes", completion.actual_len); // Receive data using transfer_blocking let recv_buffer = Buffer::new(64); // Request 64 bytes let completion = ep_in.transfer_blocking(recv_buffer, Duration::from_secs(1)); completion.status?; println!("Received {} bytes: {:02x?}", completion.actual_len, &completion.buffer[..completion.actual_len]); // Low-level API: submit multiple transfers for streaming // Submit 4 IN transfers to keep the pipeline full for _ in 0..4 { let buffer = ep_in.allocate(4096); // Use zero-copy buffer on Linux ep_in.submit(buffer); } // Process completions as they arrive for _ in 0..4 { let completion = ep_in.wait_next_complete(Duration::from_secs(5)).unwrap(); if completion.status.is_ok() { println!("Received {} bytes", completion.actual_len); // Re-submit buffer for continuous streaming ep_in.submit(completion.buffer); } } // Cancel pending transfers when done ep_in.cancel_all(); Ok(()) } ``` -------------------------------- ### Monitor USB Hotplug Events Source: https://context7.com/kevinmehall/nusb/llms.txt Use `watch_devices()` to receive notifications for USB device connections and disconnections. It's recommended to create the watcher before listing devices to prevent race conditions. Combine with `list_devices()` to maintain an up-to-date device list. ```rust use nusb::{DeviceId, DeviceInfo, MaybeFuture}; use nusb::hotplug::HotplugEvent; use std::collections::HashMap; use futures_lite::stream::StreamExt; fn main() -> Result<(), nusb::Error> { // Create hotplug watcher BEFORE listing to avoid race conditions let mut watch = nusb::watch_devices()?; // Get initial device list let mut devices: HashMap = nusb::list_devices() .wait()? .map(|d| (d.id(), d)) .collect(); println!("Initial devices:"); for device in devices.values() { println!(" {:04x}:{:04x} {}", device.vendor_id(), device.product_id(), device.product_string().unwrap_or("Unknown")); } println!("\nWatching for hotplug events..."); // Block on stream of events while let Some(event) = futures_lite::future::block_on(watch.next()) { match event { HotplugEvent::Connected(device) => { println!("+ Connected: {:04x}:{:04x} {}", device.vendor_id(), device.product_id(), device.product_string().unwrap_or("Unknown")); devices.insert(device.id(), device); } HotplugEvent::Disconnected(id) => { if let Some(device) = devices.remove(&id) { println!("- Disconnected: {:04x}:{:04x}", device.vendor_id(), device.product_id()); } } } } Ok(()) } ``` -------------------------------- ### Implement Buffered I/O with EndpointRead and EndpointWrite Source: https://context7.com/kevinmehall/nusb/llms.txt Uses EndpointRead and EndpointWrite wrappers to perform streaming operations via standard I/O traits. Requires configuring transfer buffers and timeouts. ```rust use nusb::transfer::{Bulk, In, Out}; use nusb::MaybeFuture; use std::io::{Read, Write}; use std::time::Duration; fn main() -> Result<(), std::io::Error> { let device_info = nusb::list_devices() .wait()? .find(|d| d.vendor_id() == 0x1234 && d.product_id() == 0x5678) .expect("device not found"); let device = device_info.open().wait()?; let interface = device.claim_interface(0).wait()?; // Create buffered writer for bulk OUT endpoint let mut writer = interface.endpoint::(0x02)? .writer(4096) // 4KB transfer buffer .with_num_transfers(4) // Queue up to 4 transfers .with_write_timeout(Duration::from_secs(5)); // Create buffered reader for bulk IN endpoint let mut reader = interface.endpoint::(0x82)? .reader(4096) // 4KB transfer buffer .with_num_transfers(4) // Queue up to 4 transfers .with_read_timeout(Duration::from_secs(5)); // Send data using Write trait writer.write_all(&[0x01, 0x02, 0x03, 0x04])?; writer.flush()?; // Ensure all data is sent // For protocols using short packets as delimiters writer.write_all(b"Hello, USB device!")?; writer.flush_end()?; // Send with short/ZLP packet delimiter // Read data using Read trait let mut response = vec![0u8; 256]; let bytes_read = reader.read(&mut response)?; response.truncate(bytes_read); println!("Received: {:?}", response); // Read until short packet (for packet-delimited protocols) let mut message = Vec::new(); { let mut short_reader = reader.until_short_packet(); short_reader.read_to_end(&mut message)?; short_reader.consume_end()?; // Acknowledge end of message } println!("Message: {:?}", message); Ok(()) } ``` -------------------------------- ### Read USB Device and Configuration Descriptors Source: https://context7.com/kevinmehall/nusb/llms.txt Access detailed USB descriptors including device, configuration, interface, and endpoint information for protocol analysis and debugging. This snippet iterates through all connected devices, opens them, and prints their descriptor details. ```rust use nusb::MaybeFuture; use nusb::descriptors::language_id; use std::time::Duration; fn main() -> Result<(), std::io::Error> { for device_info in nusb::list_devices().wait()? { println!("\n=== Device {:04x}:{:04x} ===", device_info.vendor_id(), device_info.product_id()); let device = match device_info.open().wait() { Ok(d) => d, Err(e) => { println!(" Cannot open: {}", e); continue; } }; // Device descriptor let desc = device.device_descriptor(); println!("Device Descriptor:"); println!(" USB Version: {:04x}", desc.usb_version()); println!(" Class/Subclass/Protocol: {:02x}/{:02x}/{:02x}", desc.class(), desc.subclass(), desc.protocol()); println!(" Configurations: {}", desc.num_configurations()); // Read string descriptors if let Some(idx) = desc.manufacturer_string_index() { if let Ok(s) = device.get_string_descriptor(idx, language_id::US_ENGLISH, Duration::from_millis(100)).wait() { println!(" Manufacturer: {}", s); } } // Iterate configurations for config in device.configurations() { println!("\nConfiguration {}:", config.configuration_value()); println!(" Interfaces: {}", config.num_interfaces()); println!(" Max Power: {} mA", config.max_power() * 2); // Iterate interfaces and alternate settings for interface in config.interfaces() { println!("\n Interface {}:", interface.interface_number()); for alt in interface.alt_settings() { println!(" Alt Setting {}:", alt.alternate_setting()); println!(" Class/Subclass/Protocol: {:02x}/{:02x}/{:02x}", alt.class(), alt.subclass(), alt.protocol()); // Iterate endpoints for ep in alt.endpoints() { println!(" Endpoint 0x{:02X}: {:?} {:?} max_packet={}", ep.address(), ep.direction(), ep.transfer_type(), ep.max_packet_size()); } } } } } Ok(()) } ``` -------------------------------- ### Claim a USB Interface Source: https://context7.com/kevinmehall/nusb/llms.txt Obtain exclusive access to a specific interface before performing data transfers. Use detach_and_claim_interface on Linux to handle kernel driver conflicts. ```rust use nusb::MaybeFuture; fn main() -> Result<(), std::io::Error> { let device_info = nusb::list_devices() .wait()? .find(|d| d.vendor_id() == 0x1234 && d.product_id() == 0x5678) .expect("device not found"); let device = device_info.open().wait()?; // Claim interface 0 (standard claim) let interface = device.claim_interface(0).wait()?; println!("Claimed interface {}", interface.interface_number()); // Get interface descriptor for current alternate setting if let Some(desc) = interface.descriptor() { println!(" Class: 0x{:02X}", desc.class()); println!(" Subclass: 0x{:02X}", desc.subclass()); println!(" Num endpoints: {}", desc.num_endpoints()); for ep in desc.endpoints() { println!( " Endpoint 0x{:02X}: {:?} max_packet_size={}", ep.address(), ep.transfer_type(), ep.max_packet_size() ); } } // On Linux, detach kernel driver and claim // let interface = device.detach_and_claim_interface(0).wait()?; // Change alternate setting if needed // interface.set_alt_setting(1).wait()?; Ok(()) } ``` -------------------------------- ### Handle USB Transfer Errors Source: https://context7.com/kevinmehall/nusb/llms.txt Manage transfer statuses such as timeouts, stalls, and disconnections, using clear_halt() to recover from endpoint stalls. ```rust use nusb::transfer::{Bulk, In, Out, Buffer, TransferError}; use nusb::MaybeFuture; use std::time::Duration; fn main() -> Result<(), Box> { let device_info = nusb::list_devices() .wait()? .find(|d| d.vendor_id() == 0x1234 && d.product_id() == 0x5678) .ok_or("device not found")?; let device = device_info.open().wait()?; let interface = device.claim_interface(0).wait()?; let mut ep_in = interface.endpoint::(0x82)?; // Submit transfer with timeout handling ep_in.submit(Buffer::new(64)); match ep_in.wait_next_complete(Duration::from_secs(1)) { Some(completion) => { match completion.status { Ok(()) => { println!("Success: {} bytes received", completion.actual_len); } Err(TransferError::Cancelled) => { println!("Transfer was cancelled"); } Err(TransferError::Stall) => { println!("Endpoint stalled, clearing..."); ep_in.clear_halt().wait()?; // Retry transfer... } Err(TransferError::Disconnected) => { println!("Device disconnected"); return Ok(()); } Err(TransferError::Fault) => { println!("Hardware fault or protocol error"); } Err(TransferError::InvalidArgument) => { println!("Invalid transfer parameters"); } Err(TransferError::Unknown(code)) => { println!("Unknown error: {}", code); } } } None => { println!("Timeout waiting for transfer"); ep_in.cancel_all(); // Drain cancelled transfers while ep_in.pending() > 0 { let _ = ep_in.wait_next_complete(Duration::from_secs(1)); } } } Ok(()) } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.