1use std::env;
14
15use hidra::{DeviceInfo, HidResult, Hidra, MaybeFuture, Native, Nusb};
16
17enum Api {
18 Native(Hidra<Native>),
19 Nusb(Hidra<Nusb>),
20}
21
22impl Api {
23 fn name(&self) -> &'static str {
24 match self {
25 Api::Native(_) => "native",
26 Api::Nusb(_) => "nusb",
27 }
28 }
29
30 fn device_list(&self) -> Vec<&DeviceInfo> {
31 match self {
32 Api::Native(api) => api.device_list().collect(),
33 Api::Nusb(api) => api.device_list().collect(),
34 }
35 }
36
37 fn product_string_of(&self, vid: u16, pid: u16) -> HidResult<Option<String>> {
38 match self {
39 Api::Native(api) => api.open(vid, pid).wait()?.get_product_string().wait(),
40 Api::Nusb(api) => api.open(vid, pid).wait()?.get_product_string().wait(),
41 }
42 }
43}
44
45fn main() -> HidResult<()> {
46 let mut args = env::args().skip(1);
47 let target = match (args.next(), args.next()) {
48 (Some(vid), Some(pid)) => Some((
49 u16::from_str_radix(&vid, 16).expect("vid must be hex"),
50 u16::from_str_radix(&pid, 16).expect("pid must be hex"),
51 )),
52 _ => None,
53 };
54
55 let mut apis = Vec::new();
56 match Hidra::<Native>::builder().build() {
57 Ok(api) => apis.push(Api::Native(api)),
58 Err(e) => println!("native: {e}"),
59 }
60 match Hidra::<Nusb>::builder().build() {
61 Ok(api) => apis.push(Api::Nusb(api)),
62 Err(e) => println!("nusb: {e}"),
63 }
64
65 for api in &apis {
66 let count = api
67 .device_list()
68 .into_iter()
69 .filter(|d| {
70 target.is_none_or(|(vid, pid)| d.vendor_id() == vid && d.product_id() == pid)
71 })
72 .count();
73 println!("{}: {count} device(s)", api.name());
74 }
75
76 let Some((vid, pid)) = target else {
77 return Ok(());
78 };
79
80 for api in &apis {
81 match api.product_string_of(vid, pid) {
82 Ok(product) => {
83 println!("opened {vid:04x}:{pid:04x} on {}", api.name());
84 println!("product: {product:?}");
85 return Ok(());
86 }
87 Err(e) => println!("{}: {e}", api.name()),
88 }
89 }
90 println!("{vid:04x}:{pid:04x} not reachable through either backend");
91 Ok(())
92}