1#[cfg(feature = "usb")]
7use crate::U3vError;
8use crate::descriptor::U3vInterfaceInfo;
9
10#[derive(Debug, Clone)]
12pub struct U3vDeviceInfo {
13 pub bus: u8,
15 pub address: u8,
17 pub vendor_id: u16,
19 pub product_id: u16,
21 pub serial: Option<String>,
23 pub manufacturer: Option<String>,
25 pub model: Option<String>,
27 pub interface_info: U3vInterfaceInfo,
29}
30
31impl std::fmt::Display for U3vDeviceInfo {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 write!(
34 f,
35 "USB3V {:04x}:{:04x} bus={} addr={} {}",
36 self.vendor_id,
37 self.product_id,
38 self.bus,
39 self.address,
40 self.model.as_deref().unwrap_or("(unknown)"),
41 )
42 }
43}
44
45#[cfg(feature = "usb")]
50pub fn discover() -> Result<Vec<U3vDeviceInfo>, U3vError> {
51 use crate::descriptor::{is_likely_u3v_device, parse_u3v_interfaces};
52 use rusb::UsbContext;
53
54 let context = rusb::Context::new().map_err(|e| U3vError::Usb(e.to_string()))?;
55 let devices = context
56 .devices()
57 .map_err(|e| U3vError::Usb(e.to_string()))?;
58
59 let mut found = Vec::new();
60
61 for device in devices.iter() {
62 let desc = match device.device_descriptor() {
63 Ok(d) => d,
64 Err(_) => continue,
65 };
66
67 if !is_likely_u3v_device(&desc) {
68 continue;
69 }
70
71 let config = match device.active_config_descriptor() {
72 Ok(c) => c,
73 Err(_) => continue,
74 };
75
76 let interface_info = match parse_u3v_interfaces(&config) {
77 Some(info) => info,
78 None => continue,
79 };
80
81 let (serial, manufacturer, model) = match device.open() {
83 Ok(handle) => {
84 let timeout = std::time::Duration::from_millis(500);
85 let serial = desc
86 .serial_number_string_index()
87 .and_then(|i| handle.read_string_descriptor_ascii(i).ok());
88 let manufacturer = desc
89 .manufacturer_string_index()
90 .and_then(|i| handle.read_string_descriptor_ascii(i).ok());
91 let model = desc
92 .product_string_index()
93 .and_then(|i| handle.read_string_descriptor_ascii(i).ok());
94 let _ = timeout;
95 (serial, manufacturer, model)
96 }
97 Err(_) => (None, None, None),
98 };
99
100 found.push(U3vDeviceInfo {
101 bus: device.bus_number(),
102 address: device.address(),
103 vendor_id: desc.vendor_id(),
104 product_id: desc.product_id(),
105 serial,
106 manufacturer,
107 model,
108 interface_info,
109 });
110 }
111
112 Ok(found)
113}