Skip to main content

driver_cp2130/
manager.rs

1//! CP2130 Driver Device Manager
2//!
3//!
4//! Copyright 2019 Ryan Kurte
5
6pub 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    // LibUSB context created automagically
23    static ref CONTEXT: UsbContext = {
24        UsbContext::new().unwrap()
25    };
26}
27
28/// Manager object maintains libusb context and provides
29/// methods for connecting to matching devices
30pub struct Manager {
31    //context: rusb::Context,
32}
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    /// Device Vendor ID (VID) in hex
39    pub vid: u16,
40
41    #[cfg_attr(feature = "clap", clap(long, default_value="87a0", value_parser=parse_hex))]
42    /// Device Product ID (PID) in hex
43    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    /// Fetch a libusb device list (for filtering and connecting to devices)
59    pub fn devices() -> Result<DeviceList<UsbContext>, Error> {
60        debug!("Fetching available USB devices");
61
62        // Attempt to fetch device list
63        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            // Fetch descriptor
83            let device_desc = match device.device_descriptor() {
84                Ok(d) => d,
85                Err(_) => continue,
86            };
87
88            trace!("Device: {:?}", device_desc);
89
90            // Check for VID/PID match
91            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        // Find matching devices
106        let mut matches = Self::devices_filtered(filter)?;
107
108        // Check index is valid
109        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        // Return match
119        Ok(matches.remove(index))
120    }
121}