use super::{
tcat::{extension::*, tcd22xx_spec::*, *},
*,
};
#[derive(Default, Debug)]
pub struct Mbox3Protocol;
impl TcatOperation for Mbox3Protocol {}
impl TcatGlobalSectionSpecification for Mbox3Protocol {}
impl TcatExtensionOperation for Mbox3Protocol {}
impl Tcd22xxSpecification for Mbox3Protocol {
const INPUTS: &'static [Input] = &[
Input {
id: SrcBlkId::Ins0,
offset: 0,
count: 6,
label: None,
},
Input {
id: SrcBlkId::Ins1,
offset: 0,
count: 2,
label: Some("Reverb"),
},
Input {
id: SrcBlkId::Aes,
offset: 0,
count: 2,
label: None,
},
];
const OUTPUTS: &'static [Output] = &[
Output {
id: DstBlkId::Ins0,
offset: 0,
count: 6,
label: None,
},
Output {
id: DstBlkId::Ins1,
offset: 0,
count: 4,
label: Some("Headphone"),
},
Output {
id: DstBlkId::Ins1,
offset: 4,
count: 2,
label: Some("Reverb"),
},
Output {
id: DstBlkId::Aes,
offset: 0,
count: 2,
label: None,
},
Output {
id: DstBlkId::Reserved(0x08),
offset: 0,
count: 2,
label: Some("ControlRoom"),
},
];
const FIXED: &'static [SrcBlk] = &[
SrcBlk {
id: SrcBlkId::Ins0,
ch: 0,
},
SrcBlk {
id: SrcBlkId::Ins0,
ch: 1,
},
SrcBlk {
id: SrcBlkId::Ins0,
ch: 2,
},
SrcBlk {
id: SrcBlkId::Ins0,
ch: 3,
},
];
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum StandaloneUseCase {
Preamp,
AdDa,
Mixer,
Undefined,
}
impl Default for StandaloneUseCase {
fn default() -> Self {
Self::Preamp
}
}
impl StandaloneUseCase {
const MIXER: u32 = 0x00;
const AD_DA: u32 = 0x01;
const PREAMP: u32 = 0x02;
const UNDEFINED: u32 = 0x03;
const MASK: u32 = 0x03;
}
fn serialize_standalone_use_case(
use_case: &StandaloneUseCase,
raw: &mut [u8],
) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
let flag = match use_case {
StandaloneUseCase::Mixer => StandaloneUseCase::MIXER,
StandaloneUseCase::AdDa => StandaloneUseCase::AD_DA,
StandaloneUseCase::Preamp => StandaloneUseCase::PREAMP,
StandaloneUseCase::Undefined => StandaloneUseCase::UNDEFINED,
};
val &= !StandaloneUseCase::MASK;
val |= flag;
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_standalone_use_case(
use_case: &mut StandaloneUseCase,
raw: &[u8],
) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
val &= StandaloneUseCase::MASK;
*use_case = match val {
StandaloneUseCase::MIXER => StandaloneUseCase::Mixer,
StandaloneUseCase::AD_DA => StandaloneUseCase::AdDa,
StandaloneUseCase::PREAMP => StandaloneUseCase::Preamp,
_ => StandaloneUseCase::Undefined,
};
Ok(())
}
const MASTER_KNOB_MASK: u32 = 0x0000003f;
fn serialize_master_knob_assigns(assigns: &[bool; 6], raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
val &= !MASTER_KNOB_MASK;
assigns
.iter()
.enumerate()
.filter(|(_, &assign)| assign)
.for_each(|(i, _)| val |= 1 << i);
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_master_knob_assigns(assigns: &mut [bool; 6], raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
assigns
.iter_mut()
.enumerate()
.for_each(|(i, assign)| *assign = val & (1 << i) > 0);
Ok(())
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MuteLedState {
Off,
Blink,
On,
}
impl Default for MuteLedState {
fn default() -> Self {
Self::Off
}
}
impl MuteLedState {
const LED_MASK: u32 = 0x00000003;
const LED_BLINK_MASK: u32 = 0x00000001;
}
fn serialize_mute_led_state(state: &MuteLedState, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
val &= !MuteLedState::LED_MASK;
match state {
MuteLedState::Off => (),
MuteLedState::Blink => val |= MuteLedState::LED_BLINK_MASK,
MuteLedState::On => val |= MuteLedState::LED_MASK & !MuteLedState::LED_BLINK_MASK,
}
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_mute_led_state(state: &mut MuteLedState, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
*state = if val & MuteLedState::LED_MASK == 0 {
MuteLedState::Off
} else if val & MuteLedState::LED_BLINK_MASK > 0 {
MuteLedState::Blink
} else {
MuteLedState::On
};
Ok(())
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MonoLedState {
Off,
On,
}
impl Default for MonoLedState {
fn default() -> Self {
Self::Off
}
}
impl MonoLedState {
const LED_MASK: u32 = 0x0000000c;
}
fn serialize_mono_led_state(state: &MonoLedState, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
val &= !MonoLedState::LED_MASK;
match state {
MonoLedState::Off => (),
MonoLedState::On => val |= MonoLedState::LED_MASK,
}
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_mono_led_state(state: &mut MonoLedState, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
*state = if val & MonoLedState::LED_MASK > 0 {
MonoLedState::On
} else {
MonoLedState::Off
};
Ok(())
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum SpkrLedState {
Off,
Green,
GreenBlink,
Red,
RedBlink,
Orange,
OrangeBlink,
}
impl Default for SpkrLedState {
fn default() -> Self {
Self::Off
}
}
impl SpkrLedState {
const COLOR_MASK: u32 = 0x00000060;
const COLOR_SHIFT: usize = 5;
const BLINK_MASK: u32 = 0x00000010;
const BLINK_SHIFT: u32 = 4;
const NONE: u32 = 0;
const GREEN: u32 = 1;
const RED: u32 = 2;
const ORANGE: u32 = 3;
}
fn serialize_spkr_led_state(state: &SpkrLedState, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
val &= !(SpkrLedState::COLOR_MASK | SpkrLedState::BLINK_MASK);
let (color, blink) = match state {
SpkrLedState::GreenBlink => (SpkrLedState::GREEN, true),
SpkrLedState::Green => (SpkrLedState::GREEN, false),
SpkrLedState::RedBlink => (SpkrLedState::RED, true),
SpkrLedState::Red => (SpkrLedState::RED, false),
SpkrLedState::OrangeBlink => (SpkrLedState::RED, true),
SpkrLedState::Orange => (SpkrLedState::ORANGE, false),
SpkrLedState::Off => (SpkrLedState::NONE, false),
};
val |= color << SpkrLedState::COLOR_SHIFT;
if blink {
val |= SpkrLedState::BLINK_MASK;
}
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_spkr_led_state(state: &mut SpkrLedState, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
let color = (val & SpkrLedState::COLOR_MASK) >> SpkrLedState::COLOR_SHIFT;
let blink = (val & SpkrLedState::BLINK_MASK) >> SpkrLedState::BLINK_SHIFT > 0;
*state = match color {
SpkrLedState::NONE => SpkrLedState::Off,
SpkrLedState::GREEN => {
if blink {
SpkrLedState::GreenBlink
} else {
SpkrLedState::Green
}
}
SpkrLedState::RED => {
if blink {
SpkrLedState::RedBlink
} else {
SpkrLedState::Red
}
}
SpkrLedState::ORANGE => {
if blink {
SpkrLedState::OrangeBlink
} else {
SpkrLedState::Orange
}
}
_ => Err(format!("Speaker LED state not found for value {}", val))?,
};
Ok(())
}
const PHANTOM_POWERING_MASK: u32 = 0x00000001;
const INPUT_HPF_ENABLES_MASK: u32 = 0x000000f0;
const INPUT_HPF_ENABLES_SHIFT: usize = 4;
fn serialize_phantom_powering(enable: &bool, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
val &= !PHANTOM_POWERING_MASK;
if *enable {
val |= PHANTOM_POWERING_MASK;
}
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_phantom_powering(enable: &mut bool, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
*enable = val & PHANTOM_POWERING_MASK > 0;
Ok(())
}
fn serialize_hpf_enables(enables: &[bool; 4], raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
val &= !INPUT_HPF_ENABLES_MASK;
enables
.iter()
.enumerate()
.filter(|(_, &enabled)| enabled)
.for_each(|(i, _)| val |= 1 << (i + INPUT_HPF_ENABLES_SHIFT));
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_hpf_enables(enables: &mut [bool; 4], raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
enables
.iter_mut()
.enumerate()
.for_each(|(i, enabled)| *enabled = val & (1 << (i + INPUT_HPF_ENABLES_SHIFT)) > 0);
Ok(())
}
fn serialize_output_trims(trims: &[u8; 6], raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 24);
trims.iter().enumerate().for_each(|(i, &trim)| {
let pos = i * 4;
serialize_u8(&(u8::MAX - trim), &mut raw[pos..(pos + 4)]);
});
Ok(())
}
fn deserialize_output_trims(trims: &mut [u8; 6], raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 24);
let mut val = 0u8;
trims.iter_mut().enumerate().for_each(|(i, trim)| {
let pos = i * 4;
deserialize_u8(&mut val, &raw[pos..(pos + 4)]);
*trim = u8::MAX - val;
});
Ok(())
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ReverbType {
Room1,
Room2,
Room3,
Hall1,
Hall2,
Plate,
Delay,
Echo,
}
impl Default for ReverbType {
fn default() -> Self {
Self::Room1
}
}
impl ReverbType {
const ROOM_1: u32 = 0x01;
const ROOM_2: u32 = 0x04;
const ROOM_3: u32 = 0x05;
const HALL_1: u32 = 0x06;
const HALL_2: u32 = 0x08;
const PLATE: u32 = 0x0b;
const DELAY: u32 = 0x13;
const ECHO: u32 = 0x14;
}
fn serialize_reverb_type(reverb_type: &ReverbType, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let val = match reverb_type {
ReverbType::Room1 => ReverbType::ROOM_1,
ReverbType::Room2 => ReverbType::ROOM_2,
ReverbType::Room3 => ReverbType::ROOM_3,
ReverbType::Hall1 => ReverbType::HALL_1,
ReverbType::Hall2 => ReverbType::HALL_2,
ReverbType::Plate => ReverbType::PLATE,
ReverbType::Delay => ReverbType::DELAY,
ReverbType::Echo => ReverbType::ECHO,
};
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_reverb_type(reverb_type: &mut ReverbType, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
*reverb_type = match val {
ReverbType::ROOM_1 => ReverbType::Room1,
ReverbType::ROOM_2 => ReverbType::Room2,
ReverbType::ROOM_3 => ReverbType::Room3,
ReverbType::HALL_1 => ReverbType::Hall1,
ReverbType::HALL_2 => ReverbType::Hall2,
ReverbType::PLATE => ReverbType::Plate,
ReverbType::DELAY => ReverbType::Delay,
ReverbType::ECHO => ReverbType::Echo,
_ => Err(format!("Reverb type not found for value {}", val))?,
};
Ok(())
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct Mbox3SpecificParams {
pub standalone_use_case: StandaloneUseCase,
pub master_knob_value: u8,
pub master_knob_assigns: [bool; 6],
pub mute_led: MuteLedState,
pub mono_led: MonoLedState,
pub spkr_led: SpkrLedState,
pub dim_led: bool,
pub duration_hold: u8,
pub phantom_powering: bool,
pub hpf_enables: [bool; 4],
pub output_trims: [u8; 6],
pub reverb_type: ReverbType,
pub reverb_volume: u8,
pub reverb_duration: u8,
pub reverb_feedback: u8,
}
const MIN_SIZE: usize = 0x50;
fn serialize(params: &Mbox3SpecificParams, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= MIN_SIZE);
serialize_standalone_use_case(¶ms.standalone_use_case, &mut raw[..0x04])?;
serialize_u8(¶ms.master_knob_value, &mut raw[0x08..0x0c]);
serialize_master_knob_assigns(¶ms.master_knob_assigns, &mut raw[0x0c..0x10])?;
serialize_mute_led_state(¶ms.mute_led, &mut raw[0x10..0x14])?;
serialize_mono_led_state(¶ms.mono_led, &mut raw[0x14..0x18])?;
serialize_spkr_led_state(¶ms.spkr_led, &mut raw[0x14..0x18])?;
serialize_bool(¶ms.dim_led, &mut raw[0x1c..0x20]);
serialize_u8(¶ms.duration_hold, &mut raw[0x20..0x24]);
serialize_phantom_powering(¶ms.phantom_powering, &mut raw[0x24..0x28])?;
serialize_hpf_enables(¶ms.hpf_enables, &mut raw[0x24..0x28])?;
serialize_output_trims(¶ms.output_trims, &mut raw[0x28..0x40])?;
serialize_reverb_type(¶ms.reverb_type, &mut raw[0x40..0x44])?;
serialize_u8(¶ms.reverb_volume, &mut raw[0x44..0x48]);
serialize_u8(¶ms.reverb_duration, &mut raw[0x48..0x4c]);
serialize_u8(¶ms.reverb_feedback, &mut raw[0x4c..0x50]);
Ok(())
}
fn deserialize(params: &mut Mbox3SpecificParams, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= MIN_SIZE);
deserialize_standalone_use_case(&mut params.standalone_use_case, &raw[..0x04])?;
deserialize_u8(&mut params.master_knob_value, &raw[0x08..0x0c]);
deserialize_master_knob_assigns(&mut params.master_knob_assigns, &raw[0x0c..0x10])?;
deserialize_mute_led_state(&mut params.mute_led, &raw[0x10..0x14])?;
deserialize_mono_led_state(&mut params.mono_led, &raw[0x14..0x18])?;
deserialize_spkr_led_state(&mut params.spkr_led, &raw[0x14..0x18])?;
deserialize_bool(&mut params.dim_led, &raw[0x1c..0x20]);
deserialize_u8(&mut params.duration_hold, &raw[0x20..0x24]);
deserialize_phantom_powering(&mut params.phantom_powering, &raw[0x24..0x28])?;
deserialize_hpf_enables(&mut params.hpf_enables, &raw[0x24..0x28])?;
deserialize_output_trims(&mut params.output_trims, &raw[0x28..0x40])?;
deserialize_reverb_type(&mut params.reverb_type, &raw[0x40..0x44])?;
deserialize_u8(&mut params.reverb_volume, &raw[0x44..0x48]);
deserialize_u8(&mut params.reverb_duration, &raw[0x48..0x4c]);
deserialize_u8(&mut params.reverb_feedback, &raw[0x4c..0x50]);
Ok(())
}
const PHANTOM_POWERING_CHANGED: u32 = 0x10000000;
const MASTER_KNOB_CHANGED: u32 = 0x08000000;
const SPKR_BUTTON_PUSHED: u32 = 0x04000000;
const SPKR_BUTTON_HELD: u32 = 0x02000000;
const MONO_BUTTON_PUSHED: u32 = 0x00800000;
const MUTE_BUTTON_PUSHED: u32 = 0x00400000;
const MUTE_BUTTON_HELD: u32 = 0x00200000;
impl TcatExtensionSectionParamsOperation<Mbox3SpecificParams> for Mbox3Protocol {
fn cache_extension_whole_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &mut Mbox3SpecificParams,
timeout_ms: u32,
) -> Result<(), Error> {
let mut raw = vec![0u8; MIN_SIZE];
Self::read_extension(req, node, §ions.application, 0, &mut raw, timeout_ms)?;
deserialize(params, &raw).map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
}
}
impl TcatExtensionSectionPartialMutableParamsOperation<Mbox3SpecificParams> for Mbox3Protocol {
fn update_extension_partial_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &Mbox3SpecificParams,
prev: &mut Mbox3SpecificParams,
timeout_ms: u32,
) -> Result<(), Error> {
let mut new = vec![0u8; MIN_SIZE];
serialize(params, &mut new)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
let mut old = vec![0u8; MIN_SIZE];
serialize(prev, &mut old)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
(0..MIN_SIZE).step_by(4).try_for_each(|pos| {
if new[pos..(pos + 4)] != old[pos..(pos + 4)] {
Self::write_extension(
req,
node,
§ions.application,
pos,
&mut new[pos..(pos + 4)],
timeout_ms,
)
} else {
Ok(())
}
})?;
deserialize(prev, &new).map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
}
}
impl TcatExtensionSectionNotifiedParamsOperation<Mbox3SpecificParams> for Mbox3Protocol {
fn cache_extension_notified_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
caps: &ExtensionCaps,
params: &mut Mbox3SpecificParams,
msg: u32,
timeout_ms: u32,
) -> Result<(), Error> {
if msg & (PHANTOM_POWERING_CHANGED | MASTER_KNOB_CHANGED) > 0 {
Self::cache_extension_whole_params(req, node, sections, caps, params, timeout_ms)?;
}
let mut p = params.clone();
if msg & SPKR_BUTTON_PUSHED > 0 {
p.spkr_led = match params.spkr_led {
SpkrLedState::Off => SpkrLedState::Green,
SpkrLedState::GreenBlink => SpkrLedState::Green,
SpkrLedState::Green => SpkrLedState::Red,
SpkrLedState::RedBlink => SpkrLedState::Red,
SpkrLedState::Red => SpkrLedState::Orange,
SpkrLedState::OrangeBlink => SpkrLedState::Orange,
SpkrLedState::Orange => SpkrLedState::Off,
};
}
if msg & SPKR_BUTTON_HELD > 0 {
p.spkr_led = match params.spkr_led {
SpkrLedState::Off => SpkrLedState::Off,
SpkrLedState::GreenBlink => SpkrLedState::Green,
SpkrLedState::Green => SpkrLedState::GreenBlink,
SpkrLedState::RedBlink => SpkrLedState::Red,
SpkrLedState::Red => SpkrLedState::RedBlink,
SpkrLedState::OrangeBlink => SpkrLedState::Orange,
SpkrLedState::Orange => SpkrLedState::OrangeBlink,
};
}
if msg & MONO_BUTTON_PUSHED > 0 {
p.mono_led = match params.mono_led {
MonoLedState::Off => MonoLedState::On,
MonoLedState::On => MonoLedState::Off,
};
}
if msg & MUTE_BUTTON_PUSHED > 0 {
p.mute_led = match params.mute_led {
MuteLedState::Off => MuteLedState::On,
MuteLedState::Blink => MuteLedState::On,
MuteLedState::On => MuteLedState::Off,
};
}
if msg & MUTE_BUTTON_HELD > 0 {
p.mute_led = match params.mute_led {
MuteLedState::Off => MuteLedState::Off,
MuteLedState::Blink => MuteLedState::On,
MuteLedState::On => MuteLedState::Blink,
};
}
if !p.eq(params) {
Self::update_extension_partial_params(
req, node, sections, caps, &p, params, timeout_ms,
)?;
}
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn mbox3_specific_params_serdes() {
let params = Mbox3SpecificParams {
standalone_use_case: StandaloneUseCase::AdDa,
master_knob_value: 0xf9,
master_knob_assigns: [true, false, true, true, false, true],
mute_led: MuteLedState::Blink,
mono_led: MonoLedState::On,
spkr_led: SpkrLedState::RedBlink,
dim_led: false,
duration_hold: 10,
phantom_powering: true,
hpf_enables: [false, false, true, false],
output_trims: [0, 1, 2, 3, 4, 5],
reverb_type: ReverbType::Hall2,
reverb_volume: 0xb3,
reverb_duration: 0xa5,
reverb_feedback: 0x17,
};
let mut raw = [0; MIN_SIZE];
serialize(¶ms, &mut raw).unwrap();
let mut p = Mbox3SpecificParams::default();
deserialize(&mut p, &raw).unwrap();
assert_eq!(params, p);
}
}