1 use std::time::Duration;
2
3 use rusb::{
4 Context, Device, DeviceDescriptor, DeviceHandle, Direction, Result, TransferType, UsbContext,
5 };
6
7 #[derive(Debug)]
8 struct Endpoint {
9 config: u8,
10 iface: u8,
11 setting: u8,
12 address: u8,
13 }
14
convert_argument(input: &str) -> u1615 fn convert_argument(input: &str) -> u16 {
16 if input.starts_with("0x") {
17 return u16::from_str_radix(input.trim_start_matches("0x"), 16).unwrap();
18 }
19 u16::from_str_radix(input, 10)
20 .expect("Invalid input, be sure to add `0x` for hexadecimal values.")
21 }
22
main()23 fn main() {
24 let args: Vec<String> = std::env::args().collect();
25
26 if args.len() < 3 {
27 println!("usage: read_device <base-10/0xbase-16> <base-10/0xbase-16>");
28 return;
29 }
30
31 let vid = convert_argument(args[1].as_ref());
32 let pid = convert_argument(args[2].as_ref());
33
34 match Context::new() {
35 Ok(mut context) => match open_device(&mut context, vid, pid) {
36 Some((mut device, device_desc, mut handle)) => {
37 read_device(&mut device, &device_desc, &mut handle).unwrap()
38 }
39 None => println!("could not find device {:04x}:{:04x}", vid, pid),
40 },
41 Err(e) => panic!("could not initialize libusb: {}", e),
42 }
43 }
44
open_device<T: UsbContext>( context: &mut T, vid: u16, pid: u16, ) -> Option<(Device<T>, DeviceDescriptor, DeviceHandle<T>)>45 fn open_device<T: UsbContext>(
46 context: &mut T,
47 vid: u16,
48 pid: u16,
49 ) -> Option<(Device<T>, DeviceDescriptor, DeviceHandle<T>)> {
50 let devices = match context.devices() {
51 Ok(d) => d,
52 Err(_) => return None,
53 };
54
55 for device in devices.iter() {
56 let device_desc = match device.device_descriptor() {
57 Ok(d) => d,
58 Err(_) => continue,
59 };
60
61 if device_desc.vendor_id() == vid && device_desc.product_id() == pid {
62 match device.open() {
63 Ok(handle) => return Some((device, device_desc, handle)),
64 Err(e) => panic!("Device found but failed to open: {}", e),
65 }
66 }
67 }
68
69 None
70 }
71
read_device<T: UsbContext>( device: &mut Device<T>, device_desc: &DeviceDescriptor, handle: &mut DeviceHandle<T>, ) -> Result<()>72 fn read_device<T: UsbContext>(
73 device: &mut Device<T>,
74 device_desc: &DeviceDescriptor,
75 handle: &mut DeviceHandle<T>,
76 ) -> Result<()> {
77 handle.reset()?;
78
79 let timeout = Duration::from_secs(1);
80 let languages = handle.read_languages(timeout)?;
81
82 println!("Active configuration: {}", handle.active_configuration()?);
83 println!("Languages: {:?}", languages);
84
85 if !languages.is_empty() {
86 let language = languages[0];
87
88 println!(
89 "Manufacturer: {:?}",
90 handle
91 .read_manufacturer_string(language, device_desc, timeout)
92 .ok()
93 );
94 println!(
95 "Product: {:?}",
96 handle
97 .read_product_string(language, device_desc, timeout)
98 .ok()
99 );
100 println!(
101 "Serial Number: {:?}",
102 handle
103 .read_serial_number_string(language, device_desc, timeout)
104 .ok()
105 );
106 }
107
108 match find_readable_endpoint(device, device_desc, TransferType::Interrupt) {
109 Some(endpoint) => read_endpoint(handle, endpoint, TransferType::Interrupt),
110 None => println!("No readable interrupt endpoint"),
111 }
112
113 match find_readable_endpoint(device, device_desc, TransferType::Bulk) {
114 Some(endpoint) => read_endpoint(handle, endpoint, TransferType::Bulk),
115 None => println!("No readable bulk endpoint"),
116 }
117
118 Ok(())
119 }
120
find_readable_endpoint<T: UsbContext>( device: &mut Device<T>, device_desc: &DeviceDescriptor, transfer_type: TransferType, ) -> Option<Endpoint>121 fn find_readable_endpoint<T: UsbContext>(
122 device: &mut Device<T>,
123 device_desc: &DeviceDescriptor,
124 transfer_type: TransferType,
125 ) -> Option<Endpoint> {
126 for n in 0..device_desc.num_configurations() {
127 let config_desc = match device.config_descriptor(n) {
128 Ok(c) => c,
129 Err(_) => continue,
130 };
131
132 for interface in config_desc.interfaces() {
133 for interface_desc in interface.descriptors() {
134 for endpoint_desc in interface_desc.endpoint_descriptors() {
135 if endpoint_desc.direction() == Direction::In
136 && endpoint_desc.transfer_type() == transfer_type
137 {
138 return Some(Endpoint {
139 config: config_desc.number(),
140 iface: interface_desc.interface_number(),
141 setting: interface_desc.setting_number(),
142 address: endpoint_desc.address(),
143 });
144 }
145 }
146 }
147 }
148 }
149
150 None
151 }
152
read_endpoint<T: UsbContext>( handle: &mut DeviceHandle<T>, endpoint: Endpoint, transfer_type: TransferType, )153 fn read_endpoint<T: UsbContext>(
154 handle: &mut DeviceHandle<T>,
155 endpoint: Endpoint,
156 transfer_type: TransferType,
157 ) {
158 println!("Reading from endpoint: {:?}", endpoint);
159
160 let has_kernel_driver = match handle.kernel_driver_active(endpoint.iface) {
161 Ok(true) => {
162 handle.detach_kernel_driver(endpoint.iface).ok();
163 true
164 }
165 _ => false,
166 };
167
168 println!(" - kernel driver? {}", has_kernel_driver);
169
170 match configure_endpoint(handle, &endpoint) {
171 Ok(_) => {
172 let mut buf = [0; 256];
173 let timeout = Duration::from_secs(1);
174
175 match transfer_type {
176 TransferType::Interrupt => {
177 match handle.read_interrupt(endpoint.address, &mut buf, timeout) {
178 Ok(len) => {
179 println!(" - read: {:?}", &buf[..len]);
180 }
181 Err(err) => println!("could not read from endpoint: {}", err),
182 }
183 }
184 TransferType::Bulk => match handle.read_bulk(endpoint.address, &mut buf, timeout) {
185 Ok(len) => {
186 println!(" - read: {:?}", &buf[..len]);
187 }
188 Err(err) => println!("could not read from endpoint: {}", err),
189 },
190 _ => (),
191 }
192 }
193 Err(err) => println!("could not configure endpoint: {}", err),
194 }
195
196 if has_kernel_driver {
197 handle.attach_kernel_driver(endpoint.iface).ok();
198 }
199 }
200
configure_endpoint<T: UsbContext>( handle: &mut DeviceHandle<T>, endpoint: &Endpoint, ) -> Result<()>201 fn configure_endpoint<T: UsbContext>(
202 handle: &mut DeviceHandle<T>,
203 endpoint: &Endpoint,
204 ) -> Result<()> {
205 handle.set_active_configuration(endpoint.config)?;
206 handle.claim_interface(endpoint.iface)?;
207 handle.set_alternate_setting(endpoint.iface, endpoint.setting)?;
208 Ok(())
209 }
210