respeaker 0.3.0

USB control library for Seeed ReSpeaker Mic Array v2.0 and XVF3800 (LEDs + DSP tuning), with reSpeaker Lite identification
Documentation
//! Model-agnostic LED facade.

use crate::color::Rgb;
use crate::error::{Error, Result};
use crate::model::Model;
use crate::v2::led::{PixelRing, VadLed};
use crate::xvf3800::led::{LedEffect, Xvf3800Led};
use crate::xvf3800::protocol::Xvf3800;
use rusb::{DeviceHandle, UsbContext};

/// LED ring controller that dispatches to the active hardware model.
pub struct Led<'a, T: UsbContext> {
    model: Model,
    handle: &'a DeviceHandle<T>,
}

impl<'a, T: UsbContext> Led<'a, T> {
    pub(crate) fn new(model: Model, handle: &'a DeviceHandle<T>) -> Self {
        Self { model, handle }
    }

    fn v2(&self) -> PixelRing<'a, T> {
        PixelRing::new(self.handle)
    }

    fn xvf(&self) -> Xvf3800Led<'a, T> {
        Xvf3800Led::new(Xvf3800::new(self.handle))
    }

    pub fn off(&self) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => self.v2().off(),
            Model::Xvf3800 => self.xvf().off(),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    pub fn mono(&self, color: Rgb) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => self.v2().mono(color),
            Model::Xvf3800 => self.xvf().mono(color),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    /// Listen / active indication. On XVF3800 this selects DoA mode.
    pub fn listen(&self) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => self.v2().listen(),
            Model::Xvf3800 => self.xvf().doa(),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    pub fn wakeup(&self) -> Result<()> {
        self.listen()
    }

    /// Trace / DoA-follow mode.
    pub fn trace(&self) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => self.v2().trace(),
            Model::Xvf3800 => self.xvf().doa(),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    /// Speak / breath indication.
    pub fn speak(&self) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => self.v2().speak(),
            Model::Xvf3800 => self.xvf().breath(),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    pub fn think(&self) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => self.v2().think(),
            Model::Xvf3800 => self.xvf().breath(),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    pub fn wait(&self) -> Result<()> {
        self.think()
    }

    /// Spin / rainbow animation.
    pub fn spin(&self) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => self.v2().spin(),
            Model::Xvf3800 => self.xvf().rainbow(),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    pub fn customize(&self, colors: &[Rgb; 12]) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => self.v2().customize(colors),
            Model::Xvf3800 => self.xvf().set_ring(colors),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    /// Brightness. Mic Array v2 uses `0..=31`; XVF3800 uses `0..=255`.
    /// Values above 31 on v2 are rejected; on XVF3800 the full range is accepted.
    pub fn set_brightness(&self, brightness: u8) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => self.v2().set_brightness(brightness),
            Model::Xvf3800 => self.xvf().set_brightness(brightness),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    pub fn set_color_palette(&self, a: Rgb, b: Rgb) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => self.v2().set_color_palette(a, b),
            Model::Xvf3800 => self.xvf().set_doa_colors(a, b),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    pub fn set_vad_led(&self, state: VadLed) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => self.v2().set_vad_led(state),
            Model::Xvf3800 => Err(Error::Unsupported(
                "set_vad_led is Mic Array v2 only; use LED DoA mode on XVF3800",
            )),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    pub fn set_volume(&self, volume: u8) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => self.v2().set_volume(volume),
            Model::Xvf3800 => Err(Error::Unsupported(
                "set_volume is Mic Array v2 only",
            )),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    /// XVF3800-only effect setter.
    pub fn set_effect(&self, effect: LedEffect) -> Result<()> {
        match self.model {
            Model::Xvf3800 => self.xvf().set_effect(effect),
            Model::MicArrayV2 => Err(Error::Unsupported(
                "set_effect is XVF3800 only; use mono/listen/spin/… on Mic Array v2",
            )),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    pub fn set_speed(&self, speed: u8) -> Result<()> {
        match self.model {
            Model::Xvf3800 => self.xvf().set_speed(speed),
            Model::MicArrayV2 => Err(Error::Unsupported("set_speed is XVF3800 only")),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }
}