1pub use rusb::{
7 Context as UsbContext, Device as UsbDevice, DeviceDescriptor, DeviceList, UsbContext as _,
8};
9
10#[cfg(feature = "clap")]
11use std::num::ParseIntError;
12
13#[cfg(feature = "clap")]
14use clap::Parser;
15
16use log::{debug, error, trace};
17
18use crate::device::{PID, VID};
19use crate::Error;
20
21lazy_static::lazy_static! {
22 static ref CONTEXT: UsbContext = {
24 UsbContext::new().unwrap()
25 };
26}
27
28pub struct Manager {
31 }
33
34#[derive(Debug, Clone, PartialEq)]
35#[cfg_attr(feature = "clap", derive(Parser))]
36pub struct Filter {
37 #[cfg_attr(feature = "clap", clap(long, default_value="10c4", value_parser=parse_hex))]
38 pub vid: u16,
40
41 #[cfg_attr(feature = "clap", clap(long, default_value="87a0", value_parser=parse_hex))]
42 pub pid: u16,
44}
45
46#[cfg(feature = "clap")]
47fn parse_hex(src: &str) -> Result<u16, ParseIntError> {
48 u16::from_str_radix(src, 16)
49}
50
51impl Default for Filter {
52 fn default() -> Self {
53 Filter { vid: VID, pid: PID }
54 }
55}
56
57impl Manager {
58 pub fn devices() -> Result<DeviceList<UsbContext>, Error> {
60 debug!("Fetching available USB devices");
61
62 let devices = match CONTEXT.devices() {
64 Ok(v) => v,
65 Err(e) => {
66 error!("Fetching devices: {}", e);
67 return Err(Error::Usb(e));
68 }
69 };
70
71 Ok(devices)
72 }
73
74 pub fn devices_filtered(
75 filter: Filter,
76 ) -> Result<Vec<(UsbDevice<UsbContext>, DeviceDescriptor)>, Error> {
77 let devices = Self::devices()?;
78
79 let mut matches = vec![];
80
81 for device in devices.iter() {
82 let device_desc = match device.device_descriptor() {
84 Ok(d) => d,
85 Err(_) => continue,
86 };
87
88 trace!("Device: {:?}", device_desc);
89
90 if device_desc.vendor_id() == filter.vid && device_desc.product_id() == filter.pid {
92 matches.push((device, device_desc));
93 }
94 }
95
96 debug!("Found {} matching devices", matches.len());
97
98 Ok(matches)
99 }
100
101 pub fn device(
102 filter: Filter,
103 index: usize,
104 ) -> Result<(UsbDevice<UsbContext>, DeviceDescriptor), Error> {
105 let mut matches = Self::devices_filtered(filter)?;
107
108 if matches.len() < index || matches.len() == 0 {
110 error!(
111 "Device index ({}) exceeds number of discovered devices ({})",
112 index,
113 matches.len()
114 );
115 return Err(Error::InvalidIndex);
116 }
117
118 Ok(matches.remove(index))
120 }
121}