From 434e61c231e142b6f5f8d81eb25f4ef97686d85a Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Sat, 27 Mar 2021 16:10:53 +0100 Subject: Initial commit --- src/devices/pro.rs | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/devices/pro.rs (limited to 'src/devices/pro.rs') diff --git a/src/devices/pro.rs b/src/devices/pro.rs new file mode 100644 index 0000000..f986f6b --- /dev/null +++ b/src/devices/pro.rs @@ -0,0 +1,99 @@ +use std::fmt; + +use crate::{devices, hid, features, DeviceInfo, Error, Model}; +use crate::devices::RawDevice as _; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u8)] +enum Command { + GetStatus = 0x00, + GetPasswordRetryCount = 0x09, + GetUserPasswordRetryCount = 0x0F, +} + +impl From for u8 { + fn from(command: Command) -> u8 { + command as u8 + } +} + +pub struct Pro { + hid_device: hidapi::HidDevice, + path: std::ffi::CString, +} + +impl Pro { + pub(crate) fn new(hid_device: hidapi::HidDevice, device_info: &DeviceInfo<'_>) -> Self { + Self { + hid_device, + path: device_info.device_info.path().to_owned(), + } + } +} + +impl features::Basic for Pro { + fn get_model(&self) -> Model { + Model::Pro + } + + fn get_status(&self) -> Result { + self.execute(Command::GetStatus, ()) + } + + fn get_user_retry_count(&self) -> Result { + self.execute(Command::GetPasswordRetryCount, ()) + } + + fn get_admin_retry_count(&self) -> Result { + self.execute(Command::GetUserPasswordRetryCount, ()) + } +} + +impl devices::RawDevice for Pro { + fn execute(&self, command_id: impl Into, data: T) -> Result + where + T: serde::Serialize, + U: serde::de::DeserializeOwned, + { + use hid::HidDeviceExt as _; + + let command_id = command_id.into(); + let crc = self.hid_device.send(&hid::Request::new(command_id, data))?; + + let mut response = self.hid_device.receive()?; + let mut retry_count = 0; + while response.device_status == hid::DeviceStatus::Busy && retry_count < 3 { + std::thread::sleep(std::time::Duration::from_millis(100)); + response = self.hid_device.receive()?; + retry_count += 1; + } + + if response.device_status != hid::DeviceStatus::Ok { + return Err(format!("Got device status {:?}", response.device_status).into()); + } + if response.command_id != command_id { + return Err(format!( + "Expected command ID {}, got {}", + command_id, response.command_id + ) + .into()); + } + if response.command_status != hid::CommandStatus::Ok { + return Err(format!("Got command status {:?}", response.command_status).into()); + } + if response.last_crc() != crc { + return Err(format!("Expected last_crc {}, got {}", crc, response.last_crc()).into()); + } + + Ok(response.data) + } +} + +impl fmt::Debug for Pro { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Pro") + .field("path", &self.path) + .finish() + } +} + -- cgit v1.2.1