use super::*;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum V1ClkSrc {
Internal,
Spdif,
WordClk,
AdatOpt,
AdatDsub,
AesebuXlr,
}
impl Default for V1ClkSrc {
fn default() -> Self {
Self::Internal
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum V1OptIfaceMode {
Adat,
Spdif,
}
impl Default for V1OptIfaceMode {
fn default() -> Self {
Self::Adat
}
}
const CONF_828_OFFSET: u32 = 0x00000b00;
const CONF_828_OPT_IN_IFACE_MASK: u32 = 0x00008000;
const CONF_828_OPT_IN_IFACE_SHIFT: usize = 15;
const CONF_828_OPT_OUT_IFACE_MASK: u32 = 0x00004000;
const CONF_828_OPT_OUT_IFACE_SHIFT: usize = 14;
const CONF_828_OPT_IFACE_VALS: [u8; 2] = [0x00, 0x01];
const CONF_828_MONITOR_INPUT_CH_MASK: u32 = 0x00003f00;
const CONF_828_MONITOR_INPUT_CH_SHIFT: usize = 8;
const CONF_828_MONITOR_INPUT_CH_VALS: &[u8] = &[
0x08, 0x1a, 0x2c, 0x3e, 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, ];
const CONF_828_STREAM_INPUT_ENABLE_MASK: u32 = 0x00000080;
const CONF_828_MONITOR_INPUT_DISABLE_MASK: u32 = 0x00000040;
const CONF_828_OUTPUT_ENABLE_MASK: u32 = 0x00000008;
const CONF_828_CLK_RATE_MASK: u32 = 0x00000004;
const CONF_828_CLK_RATE_SHIFT: usize = 2;
const CONF_828_CLK_SRC_MASK: u32 = 0x00000023;
const CONF_828_CLK_SRC_SHIFT: usize = 0;
const CONF_896_MONITOR_INPUT_AESEBU_MASK: u32 = 0x00100000;
const CONF_896_MONITOR_INPUT_AESEBU_SHIFT: usize = 20;
const CONF_896_MONITOR_INPUT_CH_VALS: &[u8] = &[
0x00, 0x48, 0x5a, 0x6c, 0x7e, 0x40, 0x49, 0x52, 0x5b, 0x64, 0x6d, 0x76, 0x7f, ];
const CONF_896_MONITOR_INPUT_CH_MASK: u32 = 0x0000ff00;
const CONF_896_MONITOR_INPUT_CH_SHIFT: usize = 8;
const CONF_896_MONITOR_INPUT_VALS: &[(usize, usize)] = &[
(0, 0),
(1, 0),
(2, 0),
(3, 0),
(4, 0),
(1, 1),
(5, 0),
(6, 0),
(7, 0),
(8, 0),
(9, 0),
(10, 0),
(11, 0),
(12, 0),
(5, 1),
];
const CONF_896_CLK_RATE_MASK: u32 = 0x00000018;
const CONF_896_CLK_RATE_SHIFT: usize = 3;
const CONF_896_CLK_SRC_MASK: u32 = 0x00000007;
const CONF_896_CLK_SRC_SHIFT: usize = 0;
const CLK_RATE_LABEL: &str = "clock-rate-v1";
const CLK_SRC_LABEL: &str = "clock-source-v1";
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct Version1ClockParameters {
pub rate: ClkRate,
pub source: V1ClkSrc,
}
pub trait MotuVersion1ClockSpecification {
const CLK_OFFSET: u32;
const CLK_RATE_MASK: u32;
const CLK_RATE_SHIFT: usize;
const CLK_RATE_VALS: &'static [u8];
const CLK_RATES: &'static [ClkRate];
const CLK_SRC_MASK: u32;
const CLK_SRC_SHIFT: usize;
const CLK_SRC_VALS: &'static [u8];
const CLK_SRCS: &'static [V1ClkSrc];
}
impl<O> MotuWhollyCacheableParamsOperation<Version1ClockParameters> for O
where
O: MotuVersion1ClockSpecification,
{
fn cache_wholly(
req: &mut FwReq,
node: &mut FwNode,
params: &mut Version1ClockParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let quad = read_quad(req, node, Self::CLK_OFFSET, timeout_ms)?;
deserialize_flag(
&mut params.rate,
&quad,
Self::CLK_RATE_MASK,
Self::CLK_RATE_SHIFT,
Self::CLK_RATES,
Self::CLK_RATE_VALS,
CLK_RATE_LABEL,
)?;
deserialize_flag(
&mut params.source,
&quad,
Self::CLK_SRC_MASK,
Self::CLK_SRC_SHIFT,
Self::CLK_SRCS,
Self::CLK_SRC_VALS,
CLK_SRC_LABEL,
)
}
}
impl<O> MotuWhollyUpdatableParamsOperation<Version1ClockParameters> for O
where
O: MotuVersion1ClockSpecification,
{
fn update_wholly(
req: &mut FwReq,
node: &mut FwNode,
params: &Version1ClockParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let mut quad = read_quad(req, node, Self::CLK_OFFSET, timeout_ms)?;
serialize_flag(
¶ms.rate,
&mut quad,
Self::CLK_RATE_MASK,
Self::CLK_RATE_SHIFT,
Self::CLK_RATES,
Self::CLK_RATE_VALS,
CLK_RATE_LABEL,
)?;
serialize_flag(
¶ms.source,
&mut quad,
Self::CLK_SRC_MASK,
Self::CLK_SRC_SHIFT,
Self::CLK_SRCS,
Self::CLK_SRC_VALS,
CLK_SRC_LABEL,
)?;
write_quad(req, node, Self::CLK_OFFSET, quad, timeout_ms)
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct Version1MonitorInputParameters(pub TargetPort);
pub trait MotuVersion1MonitorInputSpecification {
const MONITOR_INPUT_MODES: &'static [TargetPort];
}
const MONITOR_INPUT_CH_LABEL: &str = "monitor-input-ch-v1";
#[derive(Default)]
pub struct F828Protocol;
impl MotuVersion1ClockSpecification for F828Protocol {
const CLK_OFFSET: u32 = CONF_828_OFFSET;
const CLK_RATE_MASK: u32 = CONF_828_CLK_RATE_MASK;
const CLK_RATE_SHIFT: usize = CONF_828_CLK_RATE_SHIFT;
const CLK_RATE_VALS: &'static [u8] = &[0x00, 0x01];
const CLK_RATES: &'static [ClkRate] = &[ClkRate::R44100, ClkRate::R48000];
const CLK_SRC_MASK: u32 = CONF_828_CLK_SRC_MASK;
const CLK_SRC_SHIFT: usize = CONF_828_CLK_SRC_SHIFT;
const CLK_SRC_VALS: &'static [u8] = &[0x00, 0x01, 0x02, 0x21];
const CLK_SRCS: &'static [V1ClkSrc] = &[
V1ClkSrc::Internal,
V1ClkSrc::AdatDsub,
V1ClkSrc::Spdif,
V1ClkSrc::AdatOpt,
];
}
impl MotuVersion1MonitorInputSpecification for F828Protocol {
const MONITOR_INPUT_MODES: &'static [TargetPort] = &[
TargetPort::Disabled,
TargetPort::AnalogPair(0),
TargetPort::AnalogPair(1),
TargetPort::AnalogPair(2),
TargetPort::AnalogPair(3),
TargetPort::Analog(0),
TargetPort::Analog(1),
TargetPort::Analog(2),
TargetPort::Analog(3),
TargetPort::Analog(4),
TargetPort::Analog(5),
TargetPort::Analog(6),
TargetPort::Analog(7),
];
}
impl MotuWhollyCacheableParamsOperation<Version1MonitorInputParameters> for F828Protocol {
fn cache_wholly(
req: &mut FwReq,
node: &mut FwNode,
params: &mut Version1MonitorInputParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
if quad & CONF_828_MONITOR_INPUT_DISABLE_MASK > 0 {
params.0 = TargetPort::Disabled;
Ok(())
} else {
deserialize_flag(
&mut params.0,
&quad,
CONF_828_MONITOR_INPUT_CH_MASK,
CONF_828_MONITOR_INPUT_CH_SHIFT,
&Self::MONITOR_INPUT_MODES[1..],
CONF_828_MONITOR_INPUT_CH_VALS,
MONITOR_INPUT_CH_LABEL,
)
}
}
}
impl MotuWhollyUpdatableParamsOperation<Version1MonitorInputParameters> for F828Protocol {
fn update_wholly(
req: &mut FwReq,
node: &mut FwNode,
params: &Version1MonitorInputParameters,
timeout_ms: u32,
) -> Result<(), Error> {
if Self::MONITOR_INPUT_MODES
.iter()
.find(|m| params.0.eq(m))
.is_none()
{
let msg = format!("{:?} is not supported for monitor input", params.0);
Err(Error::new(FileError::Inval, &msg))?;
}
let mut quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
if params.0 == TargetPort::Disabled {
quad |= CONF_828_MONITOR_INPUT_DISABLE_MASK;
} else {
quad &= !CONF_828_MONITOR_INPUT_DISABLE_MASK;
serialize_flag(
¶ms.0,
&mut quad,
CONF_828_MONITOR_INPUT_CH_MASK,
CONF_828_MONITOR_INPUT_CH_SHIFT,
&<F828Protocol as MotuVersion1MonitorInputSpecification>::MONITOR_INPUT_MODES[1..],
CONF_828_MONITOR_INPUT_CH_VALS,
MONITOR_INPUT_CH_LABEL,
)?;
}
write_quad(req, node, CONF_828_OFFSET, quad, timeout_ms)
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct F828OpticalIfaceParameters {
pub input_mode: V1OptIfaceMode,
pub output_mode: V1OptIfaceMode,
}
const CONF_828_OPT_OUT_IFACE_LABEL: &str = "opt-out-iface-v1";
const CONF_828_OPT_IN_IFACE_LABEL: &str = "opt-in-iface-v1";
impl F828Protocol {
pub const OPT_IFACE_MODES: &[V1OptIfaceMode] = &[V1OptIfaceMode::Adat, V1OptIfaceMode::Spdif];
}
impl MotuWhollyCacheableParamsOperation<F828OpticalIfaceParameters> for F828Protocol {
fn cache_wholly(
req: &mut FwReq,
node: &mut FwNode,
params: &mut F828OpticalIfaceParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
deserialize_flag(
&mut params.input_mode,
&quad,
CONF_828_OPT_IN_IFACE_MASK,
CONF_828_OPT_IN_IFACE_SHIFT,
Self::OPT_IFACE_MODES,
&CONF_828_OPT_IFACE_VALS,
CONF_828_OPT_IN_IFACE_LABEL,
)?;
deserialize_flag(
&mut params.output_mode,
&quad,
CONF_828_OPT_OUT_IFACE_MASK,
CONF_828_OPT_OUT_IFACE_SHIFT,
Self::OPT_IFACE_MODES,
&CONF_828_OPT_IFACE_VALS,
CONF_828_OPT_OUT_IFACE_LABEL,
)
}
}
impl MotuWhollyUpdatableParamsOperation<F828OpticalIfaceParameters> for F828Protocol {
fn update_wholly(
req: &mut FwReq,
node: &mut FwNode,
params: &F828OpticalIfaceParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let mut quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
serialize_flag(
¶ms.input_mode,
&mut quad,
CONF_828_OPT_IN_IFACE_MASK,
CONF_828_OPT_IN_IFACE_SHIFT,
Self::OPT_IFACE_MODES,
&CONF_828_OPT_IFACE_VALS,
CONF_828_OPT_IN_IFACE_LABEL,
)?;
serialize_flag(
¶ms.output_mode,
&mut quad,
CONF_828_OPT_OUT_IFACE_MASK,
CONF_828_OPT_OUT_IFACE_SHIFT,
Self::OPT_IFACE_MODES,
&CONF_828_OPT_IFACE_VALS,
CONF_828_OPT_OUT_IFACE_LABEL,
)?;
write_quad(req, node, CONF_828_OFFSET, quad, timeout_ms)
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct F828StreamInputParameters(pub bool);
impl MotuWhollyCacheableParamsOperation<F828StreamInputParameters> for F828Protocol {
fn cache_wholly(
req: &mut FwReq,
node: &mut FwNode,
params: &mut F828StreamInputParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
params.0 = quad & CONF_828_STREAM_INPUT_ENABLE_MASK > 0;
Ok(())
}
}
impl MotuWhollyUpdatableParamsOperation<F828StreamInputParameters> for F828Protocol {
fn update_wholly(
req: &mut FwReq,
node: &mut FwNode,
params: &F828StreamInputParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let mut quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
quad &= !CONF_828_STREAM_INPUT_ENABLE_MASK;
if params.0 {
quad |= CONF_828_STREAM_INPUT_ENABLE_MASK;
}
write_quad(req, node, CONF_828_OFFSET, quad, timeout_ms)
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct F828OutputParameters(pub bool);
impl MotuWhollyCacheableParamsOperation<F828OutputParameters> for F828Protocol {
fn cache_wholly(
req: &mut FwReq,
node: &mut FwNode,
params: &mut F828OutputParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
params.0 = quad & CONF_828_OUTPUT_ENABLE_MASK > 0;
Ok(())
}
}
impl MotuWhollyUpdatableParamsOperation<F828OutputParameters> for F828Protocol {
fn update_wholly(
req: &mut FwReq,
node: &mut FwNode,
params: &F828OutputParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let mut quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
quad &= !CONF_828_OUTPUT_ENABLE_MASK;
if params.0 {
quad |= CONF_828_OUTPUT_ENABLE_MASK;
}
write_quad(req, node, CONF_828_OFFSET, quad, timeout_ms)
}
}
#[derive(Default)]
pub struct F896Protocol;
impl F896Protocol {
pub const NOTIFY_FOOTSWITCH_MASK: u32 = 0x01000000;
}
impl MotuWordClockOutputSpecification for F896Protocol {}
impl MotuVersion1ClockSpecification for F896Protocol {
const CLK_OFFSET: u32 = OFFSET_CLK;
const CLK_RATE_MASK: u32 = CONF_896_CLK_RATE_MASK;
const CLK_RATE_SHIFT: usize = CONF_896_CLK_RATE_SHIFT;
const CLK_RATE_VALS: &'static [u8] = &[0x00, 0x01, 0x02, 0x03];
const CLK_RATES: &'static [ClkRate] = &[
ClkRate::R44100,
ClkRate::R48000,
ClkRate::R88200,
ClkRate::R96000,
];
const CLK_SRC_MASK: u32 = CONF_896_CLK_SRC_MASK;
const CLK_SRC_SHIFT: usize = CONF_896_CLK_SRC_SHIFT;
const CLK_SRC_VALS: &'static [u8] = &[0x00, 0x01, 0x02, 0x04, 0x05];
const CLK_SRCS: &'static [V1ClkSrc] = &[
V1ClkSrc::Internal,
V1ClkSrc::AdatOpt,
V1ClkSrc::AesebuXlr,
V1ClkSrc::WordClk,
V1ClkSrc::AdatDsub,
];
}
impl MotuVersion1MonitorInputSpecification for F896Protocol {
const MONITOR_INPUT_MODES: &'static [TargetPort] = &[
TargetPort::Disabled,
TargetPort::AnalogPair(0),
TargetPort::AnalogPair(1),
TargetPort::AnalogPair(2),
TargetPort::AnalogPair(3),
TargetPort::AesEbuPair,
TargetPort::Analog(0),
TargetPort::Analog(1),
TargetPort::Analog(2),
TargetPort::Analog(3),
TargetPort::Analog(4),
TargetPort::Analog(5),
TargetPort::Analog(6),
TargetPort::Analog(7),
TargetPort::AesEbu(0),
TargetPort::AesEbu(1),
];
}
impl MotuWhollyCacheableParamsOperation<Version1MonitorInputParameters> for F896Protocol {
fn cache_wholly(
req: &mut FwReq,
node: &mut FwNode,
params: &mut Version1MonitorInputParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let quad = read_quad(req, node, OFFSET_CLK, timeout_ms)?;
let aesebu_idx = ((quad & CONF_896_MONITOR_INPUT_AESEBU_MASK)
>> CONF_896_MONITOR_INPUT_AESEBU_SHIFT) as usize;
let ch_idx =
((quad & CONF_896_MONITOR_INPUT_CH_MASK) >> CONF_896_MONITOR_INPUT_CH_SHIFT) as usize;
Self::MONITOR_INPUT_MODES
.iter()
.zip(CONF_896_MONITOR_INPUT_VALS)
.find(|(_, entry)| (ch_idx, aesebu_idx).eq(entry))
.ok_or_else(|| {
let label = "Detect invalid value for monitor input";
Error::new(FileError::Io, &label)
})
.map(|(&mode, _)| params.0 = mode)
}
}
impl MotuWhollyUpdatableParamsOperation<Version1MonitorInputParameters> for F896Protocol {
fn update_wholly(
req: &mut FwReq,
node: &mut FwNode,
params: &Version1MonitorInputParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let (ch_idx, aesebu_idx) = Self::MONITOR_INPUT_MODES
.iter()
.zip(CONF_896_MONITOR_INPUT_VALS)
.find(|(m, _)| params.0.eq(m))
.ok_or_else(|| {
let msg = format!("{:?} is not supported for monitor input", params.0);
Error::new(FileError::Io, &msg)
})
.map(|(_, &entry)| entry)?;
let mut quad = read_quad(req, node, OFFSET_CLK, timeout_ms)?;
quad &= !CONF_896_MONITOR_INPUT_AESEBU_MASK;
if aesebu_idx > 0 {
quad |= (aesebu_idx as u32) << CONF_896_MONITOR_INPUT_AESEBU_SHIFT;
}
quad &= !CONF_896_MONITOR_INPUT_CH_MASK;
quad |= (CONF_896_MONITOR_INPUT_CH_VALS[ch_idx] as u32) << CONF_896_MONITOR_INPUT_CH_SHIFT;
write_quad(req, node, OFFSET_CLK, quad, timeout_ms)
}
}
impl MotuAesebuRateConvertSpecification for F896Protocol {
const AESEBU_RATE_CONVERT_MASK: u32 = 0x00000060;
const AESEBU_RATE_CONVERT_SHIFT: usize = 5;
}
impl MotuLevelMetersSpecification for F896Protocol {}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn v1_clock_specification() {
assert_eq!(
F828Protocol::CLK_RATE_VALS.len(),
F828Protocol::CLK_RATES.len()
);
assert_eq!(
F828Protocol::CLK_SRC_VALS.len(),
F828Protocol::CLK_SRCS.len()
);
assert_eq!(
F896Protocol::CLK_RATE_VALS.len(),
F896Protocol::CLK_RATES.len()
);
assert_eq!(
F896Protocol::CLK_SRC_VALS.len(),
F896Protocol::CLK_SRCS.len()
);
}
}