1use anyhow::{Context, Result, ensure};
6use rusb::{self, UsbContext};
7use std::time::{Duration, Instant};
8
9use crate::transport::TransportError;
10
11pub struct UsbBackend {
13 device: rusb::Device<rusb::Context>,
14 handle: rusb::DeviceHandle<rusb::Context>,
15 serial_number: String,
16 timeout: Duration,
17}
18
19impl UsbBackend {
20 pub fn scan(
23 usb_vid_pid: Option<(u16, u16)>,
24 usb_protocol: Option<(u8, u8, u8)>,
25 usb_serial: Option<&str>,
26 ) -> Result<Vec<(rusb::Device<rusb::Context>, String)>> {
27 let mut devices = Vec::new();
28 let mut deferred_log_messages = Vec::new();
29 for device in rusb::Context::new()?.devices().context("USB error")?.iter() {
30 let descriptor = match device.device_descriptor() {
31 Ok(desc) => desc,
32 Err(e) => {
33 deferred_log_messages.push(format!(
34 "Could not read device descriptor for device at bus={} address={}: {}",
35 device.bus_number(),
36 device.address(),
37 e,
38 ));
39 continue;
40 }
41 };
42
43 if let Some((vid, pid)) = usb_vid_pid {
44 if descriptor.vendor_id() != vid {
45 continue;
46 }
47 if descriptor.product_id() != pid {
48 continue;
49 }
50 }
51 if let Some((class, subclass, protocol)) = usb_protocol {
52 let config = match device.active_config_descriptor() {
53 Ok(desc) => desc,
54 Err(e) => {
55 deferred_log_messages.push(format!(
56 "Could not read config descriptor for device at bus={} address={}: {}",
57 device.bus_number(),
58 device.address(),
59 e,
60 ));
61 continue;
62 }
63 };
64 let mut found = false;
65 for intf in config.interfaces() {
66 for desc in intf.descriptors() {
67 if desc.class_code() == class
68 && desc.sub_class_code() == subclass
69 && desc.protocol_code() == protocol
70 {
71 found = true;
72 }
73 }
74 }
75 if !found {
76 continue;
77 }
78 }
79 let handle = match device.open() {
80 Ok(handle) => handle,
81 Err(e) => {
82 deferred_log_messages.push(format!(
83 "Could not open device at bus={} address={}: {}",
84 device.bus_number(),
85 device.address(),
86 e,
87 ));
88 continue;
89 }
90 };
91
92 let serial_number = match handle.read_serial_number_string_ascii(&descriptor) {
93 Ok(sn) => sn,
94 Err(e) => {
95 deferred_log_messages.push(format!(
96 "Could not read serial number from device at bus={} address={}: {}",
97 device.bus_number(),
98 device.address(),
99 e,
100 ));
101 continue;
102 }
103 };
104 if let Some(sn) = &usb_serial
105 && &serial_number != sn
106 {
107 continue;
108 }
109 devices.push((device, serial_number));
110 }
111
112 let severity = match devices.len() {
117 1 => log::Level::Info,
118 _ => log::Level::Error,
119 };
120 for s in deferred_log_messages {
121 log::log!(severity, "{}", s);
122 }
123 Ok(devices)
124 }
125
126 pub fn new(usb_vid: u16, usb_pid: u16, usb_serial: Option<&str>) -> Result<Self> {
128 let mut devices = UsbBackend::scan(Some((usb_vid, usb_pid)), None, usb_serial)?;
129 ensure!(!devices.is_empty(), TransportError::NoDevice);
130 ensure!(devices.len() == 1, TransportError::MultipleDevices);
131
132 let (device, serial_number) = devices.remove(0);
133 Ok(UsbBackend {
134 handle: device.open().context("USB open error")?,
135 device,
136 serial_number,
137 timeout: Duration::from_millis(500),
138 })
139 }
140
141 pub fn from_interface(
142 class: u8,
143 subclass: u8,
144 protocol: u8,
145 usb_serial: Option<&str>,
146 ) -> Result<Self> {
147 Self::from_interface_with_timeout(class, subclass, protocol, usb_serial, Duration::ZERO)
148 }
149
150 pub fn from_interface_with_timeout(
151 class: u8,
152 subclass: u8,
153 protocol: u8,
154 usb_serial: Option<&str>,
155 timeout: Duration,
156 ) -> Result<Self> {
157 let deadline = Instant::now() + timeout;
158 loop {
159 let mut devices =
160 UsbBackend::scan(None, Some((class, subclass, protocol)), usb_serial)?;
161 if devices.is_empty() {
162 if Instant::now() < deadline {
163 std::thread::sleep(Duration::from_millis(100));
164 continue;
165 } else {
166 return Err(TransportError::NoDevice.into());
167 }
168 }
169 ensure!(devices.len() == 1, TransportError::MultipleDevices);
170
171 let (device, serial_number) = devices.remove(0);
172 return Ok(UsbBackend {
173 handle: device.open().context("USB open error")?,
174 device,
175 serial_number,
176 timeout: Duration::from_millis(500),
177 });
178 }
179 }
180
181 pub fn handle(&self) -> &rusb::DeviceHandle<rusb::Context> {
182 &self.handle
183 }
184
185 pub fn get_vendor_id(&self) -> u16 {
186 self.device.device_descriptor().unwrap().vendor_id()
187 }
188
189 pub fn get_product_id(&self) -> u16 {
190 self.device.device_descriptor().unwrap().product_id()
191 }
192
193 pub fn get_serial_number(&self) -> &str {
195 self.serial_number.as_str()
196 }
197
198 pub fn set_active_configuration(&self, config: u8) -> Result<()> {
199 self.handle
200 .set_active_configuration(config)
201 .context("USB error")
202 }
203
204 pub fn claim_interface(&self, iface: u8) -> Result<()> {
205 self.handle.claim_interface(iface).context("USB error")
206 }
207
208 pub fn release_interface(&self, iface: u8) -> Result<()> {
209 self.handle.release_interface(iface).context("USB error")
210 }
211
212 pub fn set_alternate_setting(&self, iface: u8, setting: u8) -> Result<()> {
213 self.handle
214 .set_alternate_setting(iface, setting)
215 .context("USB error")
216 }
217
218 pub fn kernel_driver_active(&self, iface: u8) -> Result<bool> {
219 self.handle.kernel_driver_active(iface).context("USB error")
220 }
221
222 pub fn detach_kernel_driver(&self, iface: u8) -> Result<()> {
223 self.handle.detach_kernel_driver(iface).context("USB error")
224 }
225
226 pub fn attach_kernel_driver(&self, iface: u8) -> Result<()> {
227 self.handle.attach_kernel_driver(iface).context("USB error")
228 }
229
230 pub fn active_config_descriptor(&self) -> Result<rusb::ConfigDescriptor> {
237 self.device.active_config_descriptor().context("USB error")
238 }
239
240 pub fn bus_number(&self) -> u8 {
241 self.device.bus_number()
242 }
243
244 pub fn port_numbers(&self) -> Result<Vec<u8>> {
245 self.device.port_numbers().context("USB error")
246 }
247
248 pub fn read_string_descriptor_ascii(&self, idx: u8) -> Result<String> {
249 self.handle
250 .read_string_descriptor_ascii(idx)
251 .context("USB error")
252 }
253
254 pub fn reset(&self) -> Result<()> {
255 self.handle.reset().context("USB Error")
256 }
257
258 pub fn write_control(
264 &self,
265 request_type: u8,
266 request: u8,
267 value: u16,
268 index: u16,
269 buf: &[u8],
270 ) -> Result<usize> {
271 self.handle
272 .write_control(request_type, request, value, index, buf, self.timeout)
273 .context("USB error")
274 }
275
276 pub fn read_control(
278 &self,
279 request_type: u8,
280 request: u8,
281 value: u16,
282 index: u16,
283 buf: &mut [u8],
284 ) -> Result<usize> {
285 self.handle
286 .read_control(request_type, request, value, index, buf, self.timeout)
287 .context("USB error")
288 }
289
290 pub fn read_bulk(&self, endpoint: u8, data: &mut [u8]) -> Result<usize> {
292 let len = self
293 .handle
294 .read_bulk(endpoint, data, self.timeout)
295 .context("USB error")?;
296 Ok(len)
297 }
298
299 pub fn read_bulk_timeout(
301 &self,
302 endpoint: u8,
303 data: &mut [u8],
304 timeout: Duration,
305 ) -> Result<usize> {
306 let len = self
307 .handle
308 .read_bulk(endpoint, data, timeout)
309 .context("USB error")?;
310 Ok(len)
311 }
312
313 pub fn write_bulk(&self, endpoint: u8, data: &[u8]) -> Result<usize> {
315 let len = self
316 .handle
317 .write_bulk(endpoint, data, self.timeout)
318 .context("USB error")?;
319 Ok(len)
320 }
321}