use hidapi::{HidApi, HidDevice, HidError};
use super::HingeAngle;
#[derive(Debug)]
pub struct Hinge {
device: HidDevice,
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Device not available")]
DeviceNotAvailable(#[source] HidError),
#[error("Failed to read from device")]
ReadFailed(#[source] HidError),
#[error("Sensor not found")]
SensorNotFound,
#[error("Insufficient data length")]
InsufficientDataLength,
}
impl HingeAngle for Hinge {
type Output = Result<u16, Error>;
fn angle(&self) -> Self::Output {
let mut buf = [1, 0, 0];
let len = self
.device
.get_feature_report(&mut buf)
.map_err(Error::ReadFailed)?;
if len == buf.len() {
let [_, low, high] = buf;
let raw = u16::from_le_bytes([low, high]);
Ok(raw)
} else {
Err(Error::InsufficientDataLength)
}
}
}
impl Hinge {
const VENDOR_ID: u16 = 0x05AC;
const PRODUCT_ID: u16 = 0x8104;
const USAGE_PAGE: u16 = 0x0020;
const USAGE: u16 = 0x008A;
pub fn new() -> Result<Self, Error> {
let api = HidApi::new().map_err(Error::DeviceNotAvailable)?;
let device_info = api
.device_list()
.find(|d| {
d.vendor_id() == Self::VENDOR_ID
&& d.product_id() == Self::PRODUCT_ID
&& d.usage_page() == Self::USAGE_PAGE
&& d.usage() == Self::USAGE
})
.ok_or(Error::SensorNotFound)?;
let device = device_info
.open_device(&api)
.map_err(Error::DeviceNotAvailable)?;
Ok(Hinge { device })
}
}
impl From<HidDevice> for Hinge {
fn from(device: HidDevice) -> Self {
Hinge { device }
}
}