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 DOA / VAD / parameter facade.

use crate::error::{Error, Result};
use crate::lite::Lite;
use crate::model::Model;
use crate::v2::params::{ParamValue, Parameter, PARAMETERS as V2_PARAMETERS};
use crate::v2::tuning::Tuning as V2Tuning;
use crate::xvf3800::params::{Command as XvfCommand, XvfValue, COMMANDS as XVF_COMMANDS};
use crate::xvf3800::protocol::Xvf3800;
use rusb::{DeviceHandle, UsbContext};

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

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

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

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

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

    pub fn model(&self) -> Model {
        self.model
    }

    /// Direction of arrival in degrees.
    pub fn doa_angle(&self) -> Result<i32> {
        match self.model {
            Model::MicArrayV2 => self.v2().doa_angle(),
            Model::Xvf3800 => self.xvf().doa_angle(),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    /// Whether voice / speech is currently detected.
    pub fn is_voice(&self) -> Result<bool> {
        match self.model {
            Model::MicArrayV2 => self.v2().is_voice(),
            Model::Xvf3800 => self.xvf().is_voice(),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    /// Human-readable firmware / protocol version.
    pub fn version_string(&self) -> Result<String> {
        match self.model {
            Model::MicArrayV2 => Ok(self.v2().version()?.to_string()),
            Model::Xvf3800 => self.xvf().version_string(),
            Model::Lite => self.lite().version_string(),
        }
    }

    /// Mic Array v2 single-byte protocol version. Errors on XVF3800.
    pub fn version(&self) -> Result<u8> {
        match self.model {
            Model::MicArrayV2 => self.v2().version(),
            Model::Xvf3800 => Err(Error::Unsupported(
                "version() byte is Mic Array v2 only; use version_string() on XVF3800",
            )),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    /// Mic Array v2 parameter table (empty slice on XVF3800 — use [`Self::xvf_commands`]).
    pub fn parameters(&self) -> &'static [Parameter] {
        match self.model {
            Model::MicArrayV2 => V2_PARAMETERS,
            Model::Xvf3800 => &[],
            Model::Lite => &[],
        }
    }

    /// XVF3800 command table (empty on Mic Array v2).
    pub fn xvf_commands(&self) -> &'static [XvfCommand] {
        match self.model {
            Model::Xvf3800 => XVF_COMMANDS,
            Model::MicArrayV2 => &[],
            Model::Lite => &[],
        }
    }

    /// Read a Mic Array v2 tuning parameter.
    pub fn read(&self, name: &str) -> Result<ParamValue> {
        match self.model {
            Model::MicArrayV2 => self.v2().read(name),
            Model::Xvf3800 => Err(Error::Unsupported(
                "read() is Mic Array v2 API; use read_xvf() on XVF3800",
            )),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    pub fn write(&self, name: &str, value: ParamValue) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => self.v2().write(name, value),
            Model::Xvf3800 => Err(Error::Unsupported(
                "write() is Mic Array v2 API; use write_xvf() on XVF3800",
            )),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    pub fn write_str(&self, name: &str, text: &str) -> Result<()> {
        self.write_strs(name, &[text])
    }

    /// Write a parameter from one or more numeric/hex string tokens.
    pub fn write_strs(&self, name: &str, texts: &[&str]) -> Result<()> {
        match self.model {
            Model::MicArrayV2 => {
                if texts.len() != 1 {
                    return Err(Error::InvalidValue(
                        "Mic Array v2 parameters take exactly one value".into(),
                    ));
                }
                self.v2().write_str(name, texts[0])
            }
            Model::Xvf3800 => self.xvf().write_str(name, texts),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    pub fn read_xvf(&self, name: &str) -> Result<XvfValue> {
        match self.model {
            Model::Xvf3800 => self.xvf().read_cmd(name),
            Model::MicArrayV2 => Err(Error::Unsupported(
                "read_xvf() is XVF3800 only; use read() on Mic Array v2",
            )),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

    pub fn write_xvf(&self, name: &str, values: &[f64]) -> Result<()> {
        match self.model {
            Model::Xvf3800 => self.xvf().write_cmd(name, values),
            Model::MicArrayV2 => Err(Error::Unsupported(
                "write_xvf() is XVF3800 only; use write() on Mic Array v2",
            )),
            Model::Lite => Err(Error::Unsupported(crate::lite::NO_USB_CONTROL)),
        }
    }

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

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