mod error;
mod led;
mod params;
mod tuning;
pub use error::{Error, Result};
pub use led::{PixelRing, Rgb, VadLed};
pub use params::{
find_parameter, Access, ParamKind, ParamValue, Parameter, PARAMETERS,
};
pub use tuning::Tuning;
use rusb::{Context, DeviceHandle, Direction, Recipient, RequestType, UsbContext};
pub const VENDOR_ID: u16 = 0x2886;
pub const PRODUCT_ID: u16 = 0x0018;
const LED_INDEX: u16 = 0x1C;
const LED_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(8000);
const TUNING_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(5000);
const VENDOR_OUT: u8 = rusb::request_type(Direction::Out, RequestType::Vendor, Recipient::Device);
const VENDOR_IN: u8 = rusb::request_type(Direction::In, RequestType::Vendor, Recipient::Device);
pub struct ReSpeaker<T: UsbContext = Context> {
handle: DeviceHandle<T>,
}
impl ReSpeaker<Context> {
pub fn open() -> Result<Self> {
let context = Context::new()?;
Self::open_with_context(&context)
}
}
impl<T: UsbContext> ReSpeaker<T> {
pub fn open_with_context(context: &T) -> Result<Self> {
let devices = context.devices()?;
let mut matched = None;
for device in devices.iter() {
let Ok(desc) = device.device_descriptor() else {
continue;
};
if desc.vendor_id() == VENDOR_ID && desc.product_id() == PRODUCT_ID {
matched = Some(device);
break;
}
}
let device = matched.ok_or(Error::NotFound {
vid: VENDOR_ID,
pid: PRODUCT_ID,
})?;
let handle = match device.open() {
Ok(h) => h,
Err(rusb::Error::Access) => return Err(Error::Access),
Err(e) => return Err(Error::Usb(e)),
};
Ok(Self { handle })
}
pub fn from_handle(handle: DeviceHandle<T>) -> Self {
Self { handle }
}
pub fn led(&self) -> PixelRing<'_, T> {
PixelRing::new(&self.handle)
}
pub fn tuning(&self) -> Tuning<'_, T> {
Tuning::new(&self.handle)
}
pub fn handle(&self) -> &DeviceHandle<T> {
&self.handle
}
}