mod crc32; mod hid; pub mod devices; pub mod features; use std::fmt; pub type Error = Box; const VID_NITROKEY: u16 = 0x20a0; const PID_NITROKEY_PRO: u16 = 0x4108; const PID_NITROKEY_STORAGE: u16 = 0x4109; pub fn connect() -> Result { let manager = Manager::new()?; if let Some(device) = manager.devices().first() { device.connect() } else { Err("No device connected".into()) } } pub fn connect_model(model: Model) -> Result { let manager = Manager::new()?; if let Some(device) = manager.devices().iter().filter(|i| i.model == model).next() { device.connect() } else { Err(format!("No {:?} device connected", model).into()) } } pub struct Manager { hidapi: hidapi::HidApi, } impl Manager { pub fn new() -> Result { let hidapi = hidapi::HidApi::new()?; Ok(Manager { hidapi }) } pub fn devices(&self) -> Vec> { self.hidapi .device_list() .flat_map(|device_info| { Model::from_vid_pid(device_info.vendor_id(), device_info.product_id()).map( |model| DeviceInfo { hidapi: &self.hidapi, device_info, model, }, ) }) .collect() } } #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum Model { Pro, Storage, } impl Model { fn from_vid_pid(vid: u16, pid: u16) -> Option { match vid { VID_NITROKEY => match pid { PID_NITROKEY_PRO => Some(Model::Pro), PID_NITROKEY_STORAGE => Some(Model::Storage), _ => None, }, _ => None, } } } pub struct DeviceInfo<'a> { hidapi: &'a hidapi::HidApi, device_info: &'a hidapi::DeviceInfo, model: Model, } impl<'a> DeviceInfo<'a> { pub fn connect(&self) -> Result { let hid_device = self.device_info.open_device(self.hidapi)?; match self.model { Model::Pro => Ok(devices::Pro::new(hid_device, self).into()), Model::Storage => unimplemented!(), } } } impl<'a> fmt::Debug for DeviceInfo<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DeviceInfo") .field("model", &self.model) .field("path", &self.device_info.path()) .finish() } }