mod color;
mod error;
mod led;
mod model;
mod tuning;
pub mod lite;
pub mod v2;
pub mod xvf3800;
pub use color::Rgb;
pub use error::{Error, Result};
pub use led::Led;
pub use lite::{FirmwareVersion, Lite};
pub use model::Model;
pub use tuning::Tuning;
pub use v2::{
find_parameter, Access as V2Access, ParamKind, ParamValue, Parameter, PixelRing, VadLed,
PARAMETERS as V2_PARAMETERS,
};
pub use xvf3800::{
find_command, Access as XvfAccess, Command as XvfCommand, LedEffect, ValueType, Xvf3800,
Xvf3800Led, XvfValue, COMMANDS as XVF_COMMANDS,
};
pub use v2::Access;
pub use v2::PARAMETERS;
use rusb::{Context, DeviceHandle, Direction, Recipient, RequestType, UsbContext};
pub const VENDOR_ID: u16 = 0x2886;
pub const PRODUCT_ID_V2: u16 = 0x0018;
pub const PRODUCT_ID_XVF3800: u16 = 0x001A;
pub const PRODUCT_ID_LITE: u16 = 0x0019;
pub const PRODUCT_ID: u16 = PRODUCT_ID_V2;
pub(crate) const LED_INDEX: u16 = 0x1C;
pub(crate) const LED_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(8000);
pub(crate) const TUNING_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(5000);
pub(crate) const VENDOR_OUT: u8 =
rusb::request_type(Direction::Out, RequestType::Vendor, Recipient::Device);
pub(crate) const VENDOR_IN: u8 =
rusb::request_type(Direction::In, RequestType::Vendor, Recipient::Device);
pub struct ReSpeaker<T: UsbContext = Context> {
handle: DeviceHandle<T>,
model: Model,
}
impl ReSpeaker<Context> {
pub fn open() -> Result<Self> {
let context = Context::new()?;
Self::open_with_context(&context)
}
pub fn open_model(model: Model) -> Result<Self> {
let context = Context::new()?;
Self::open_model_with_context(&context, model)
}
}
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 {
continue;
}
let model = match desc.product_id() {
PRODUCT_ID_V2 => Model::MicArrayV2,
PRODUCT_ID_XVF3800 => Model::Xvf3800,
PRODUCT_ID_LITE => Model::Lite,
_ => continue,
};
matched = Some((device, model));
break;
}
let (device, model) = matched.ok_or(Error::NotFound {
vid: VENDOR_ID,
pids: format!(
"{PRODUCT_ID_V2:04x}/{PRODUCT_ID_XVF3800:04x}/{PRODUCT_ID_LITE:04x}"
),
})?;
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, model })
}
pub fn open_model_with_context(context: &T, model: Model) -> Result<Self> {
let devices = context.devices()?;
let pid = model.product_id();
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() == pid {
matched = Some(device);
break;
}
}
let device = matched.ok_or(Error::NotFound {
vid: VENDOR_ID,
pids: format!("{pid:04x}"),
})?;
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, model })
}
pub fn from_handle(handle: DeviceHandle<T>, model: Model) -> Self {
Self { handle, model }
}
pub fn model(&self) -> Model {
self.model
}
pub fn led(&self) -> Led<'_, T> {
Led::new(self.model, &self.handle)
}
pub fn tuning(&self) -> Tuning<'_, T> {
Tuning::new(self.model, &self.handle)
}
pub fn pixel_ring(&self) -> Result<PixelRing<'_, T>> {
match self.model {
Model::MicArrayV2 => Ok(PixelRing::new(&self.handle)),
Model::Xvf3800 => Err(Error::Unsupported("pixel_ring is Mic Array v2 only")),
Model::Lite => Err(Error::Unsupported(lite::NO_USB_CONTROL)),
}
}
pub fn xvf3800(&self) -> Result<Xvf3800<'_, T>> {
match self.model {
Model::Xvf3800 => Ok(Xvf3800::new(&self.handle)),
Model::MicArrayV2 => Err(Error::Unsupported("xvf3800() is XVF3800 only")),
Model::Lite => Err(Error::Unsupported(lite::NO_USB_CONTROL)),
}
}
pub fn lite(&self) -> Result<Lite<'_, T>> {
match self.model {
Model::Lite => Ok(Lite::new(&self.handle)),
_ => Err(Error::Unsupported("lite() is reSpeaker Lite only")),
}
}
pub fn handle(&self) -> &DeviceHandle<T> {
&self.handle
}
}