use super::{tcat::tcd22xx_spec::*, *};
#[derive(Default, Debug)]
pub struct LiquidS56Protocol;
impl TcatOperation for LiquidS56Protocol {}
impl TcatGlobalSectionSpecification for LiquidS56Protocol {}
impl TcatExtensionOperation for LiquidS56Protocol {}
impl Tcd22xxSpecification for LiquidS56Protocol {
const INPUTS: &'static [Input] = &[
Input {
id: SrcBlkId::Ins0,
offset: 0,
count: 2,
label: None,
},
Input {
id: SrcBlkId::Ins1,
offset: 2,
count: 6,
label: None,
},
Input {
id: SrcBlkId::Adat,
offset: 0,
count: 8,
label: None,
},
Input {
id: SrcBlkId::Aes,
offset: 0,
count: 2,
label: Some("S/PDIF-coax"),
},
Input {
id: SrcBlkId::Adat,
offset: 8,
count: 8,
label: None,
},
Input {
id: SrcBlkId::Aes,
offset: 6,
count: 2,
label: Some("S/PDIF-opt"),
},
];
const OUTPUTS: &'static [Output] = &[
Output {
id: DstBlkId::Ins0,
offset: 0,
count: 2,
label: None,
},
Output {
id: DstBlkId::Ins1,
offset: 0,
count: 8,
label: None,
},
Output {
id: DstBlkId::Adat,
offset: 0,
count: 8,
label: None,
},
Output {
id: DstBlkId::Aes,
offset: 0,
count: 2,
label: Some("S/PDIF-coax"),
},
Output {
id: DstBlkId::Adat,
offset: 8,
count: 8,
label: None,
},
Output {
id: DstBlkId::Aes,
offset: 6,
count: 2,
label: Some("S/PDIF-opt"),
},
];
const FIXED: &'static [SrcBlk] = &[
SrcBlk {
id: SrcBlkId::Ins1,
ch: 0,
},
SrcBlk {
id: SrcBlkId::Ins1,
ch: 1,
},
SrcBlk {
id: SrcBlkId::Ins1,
ch: 2,
},
SrcBlk {
id: SrcBlkId::Ins1,
ch: 3,
},
SrcBlk {
id: SrcBlkId::Ins1,
ch: 4,
},
SrcBlk {
id: SrcBlkId::Ins1,
ch: 5,
},
SrcBlk {
id: SrcBlkId::Ins1,
ch: 6,
},
SrcBlk {
id: SrcBlkId::Ins1,
ch: 7,
},
SrcBlk {
id: SrcBlkId::Aes,
ch: 0,
},
SrcBlk {
id: SrcBlkId::Aes,
ch: 1,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 0,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 1,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 2,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 3,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 4,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 5,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 6,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 7,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 8,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 9,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 10,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 11,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 12,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 13,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 14,
},
SrcBlk {
id: SrcBlkId::Adat,
ch: 15,
},
];
}
impl SaffireproSwNoticeOperation for LiquidS56Protocol {
const SW_NOTICE_OFFSET: usize = 0x02c8;
}
const SRC_SW_NOTICE: u32 = 0x00000001;
const DIM_MUTE_SW_NOTICE: u32 = 0x00000003;
const MIC_AMP_1_HARMONICS_SW_NOTICE: u32 = 0x00000006;
const MIC_AMP_2_HARMONICS_SW_NOTICE: u32 = 0x00000007;
const MIC_AMP_1_EMULATION_SW_NOTICE: u32 = 0x00000008;
const MIC_AMP_2_EMULATION_SW_NOTICE: u32 = 0x00000009;
const MIC_AMP_POLARITY_SW_NOTICE: u32 = 0x0000000a;
const INPUT_LEVEL_SW_NOTICE: u32 = 0x0000000b;
impl SaffireproOutGroupSpecification for LiquidS56Protocol {
const OUT_GROUP_STATE_OFFSET: usize = 0x000c;
const ENTRY_COUNT: usize = 10;
const HAS_VOL_HWCTL: bool = true;
const SRC_NOTICE: u32 = SRC_SW_NOTICE;
const DIM_MUTE_NOTICE: u32 = DIM_MUTE_SW_NOTICE;
}
impl SaffireproIoParamsSpecification for LiquidS56Protocol {
const AESEBU_IS_SUPPORTED: bool = true;
const MIC_PREAMP_TRANSFORMER_IS_SUPPORTED: bool = true;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MicAmpEmulationType {
Flat,
Trany1h,
Silver2,
FfRed1h,
Savillerow,
Dunk,
ClassA2a,
OldTube,
Deutsch72,
Stellar1b,
NewAge,
}
impl Default for MicAmpEmulationType {
fn default() -> Self {
Self::Flat
}
}
impl MicAmpEmulationType {
const FLAT_VALUE: u32 = 0;
const TRANY1H_VALUE: u32 = 1;
const SILVER2_VALUE: u32 = 2;
const FFRED1H_VALUE: u32 = 3;
const SAVILLEROW_VALUE: u32 = 4;
const DUNK_VALUE: u32 = 5;
const CLASSA2A_VALUE: u32 = 6;
const OLDTUBE_VALUE: u32 = 7;
const DEUTSCH72_VALUE: u32 = 8;
const STELLAR1B_VALUE: u32 = 9;
const NEWAGE_VALUE: u32 = 10;
}
fn serialize_mic_amp_emulation_types(
emulation_types: &[MicAmpEmulationType; 2],
raw: &mut [u8],
) -> Result<(), String> {
assert!(raw.len() >= 8);
emulation_types
.iter()
.enumerate()
.for_each(|(i, emulation_type)| {
let pos = i * 4;
let val = match emulation_type {
MicAmpEmulationType::Flat => MicAmpEmulationType::FLAT_VALUE,
MicAmpEmulationType::Trany1h => MicAmpEmulationType::TRANY1H_VALUE,
MicAmpEmulationType::Silver2 => MicAmpEmulationType::SILVER2_VALUE,
MicAmpEmulationType::FfRed1h => MicAmpEmulationType::FFRED1H_VALUE,
MicAmpEmulationType::Savillerow => MicAmpEmulationType::SAVILLEROW_VALUE,
MicAmpEmulationType::Dunk => MicAmpEmulationType::DUNK_VALUE,
MicAmpEmulationType::ClassA2a => MicAmpEmulationType::CLASSA2A_VALUE,
MicAmpEmulationType::OldTube => MicAmpEmulationType::OLDTUBE_VALUE,
MicAmpEmulationType::Deutsch72 => MicAmpEmulationType::DEUTSCH72_VALUE,
MicAmpEmulationType::Stellar1b => MicAmpEmulationType::STELLAR1B_VALUE,
MicAmpEmulationType::NewAge => MicAmpEmulationType::NEWAGE_VALUE,
};
serialize_u32(&val, &mut raw[pos..(pos + 4)]);
});
Ok(())
}
fn deserialize_mic_amp_emulation_types(
emulation_types: &mut [MicAmpEmulationType; 2],
raw: &[u8],
) -> Result<(), String> {
assert!(raw.len() >= 8);
let mut val = 0u32;
emulation_types
.iter_mut()
.enumerate()
.try_for_each(|(i, emulation_type)| {
let pos = i * 4;
deserialize_u32(&mut val, &raw[pos..(pos + 4)]);
*emulation_type = match val {
MicAmpEmulationType::FLAT_VALUE => MicAmpEmulationType::Flat,
MicAmpEmulationType::TRANY1H_VALUE => MicAmpEmulationType::Trany1h,
MicAmpEmulationType::SILVER2_VALUE => MicAmpEmulationType::Silver2,
MicAmpEmulationType::FFRED1H_VALUE => MicAmpEmulationType::FfRed1h,
MicAmpEmulationType::SAVILLEROW_VALUE => MicAmpEmulationType::Savillerow,
MicAmpEmulationType::DUNK_VALUE => MicAmpEmulationType::Dunk,
MicAmpEmulationType::CLASSA2A_VALUE => MicAmpEmulationType::ClassA2a,
MicAmpEmulationType::OLDTUBE_VALUE => MicAmpEmulationType::OldTube,
MicAmpEmulationType::DEUTSCH72_VALUE => MicAmpEmulationType::Deutsch72,
MicAmpEmulationType::STELLAR1B_VALUE => MicAmpEmulationType::Stellar1b,
MicAmpEmulationType::NEWAGE_VALUE => MicAmpEmulationType::NewAge,
_ => Err(format!(
"Mic amplifier emulation type not found for value: {}",
val
))?,
};
Ok(())
})
}
fn serialize_mic_amp_harmonics(harmonics: &[u8; 2], raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 8);
harmonics.iter().enumerate().for_each(|(i, h)| {
let pos = i * 4;
serialize_u8(h, &mut raw[pos..(pos + 4)]);
});
Ok(())
}
fn deserialize_mic_amp_harmonics(harmonics: &mut [u8; 2], raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 8);
harmonics.iter_mut().enumerate().for_each(|(i, h)| {
let pos = i * 4;
deserialize_u8(h, &raw[pos..(pos + 4)]);
});
Ok(())
}
fn serialize_mic_amp_polarities(polarities: &[bool; 2], raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 8);
polarities.iter().enumerate().for_each(|(i, polarity)| {
let pos = i * 4;
serialize_bool(polarity, &mut raw[pos..(pos + 4)]);
});
Ok(())
}
fn deserialize_mic_amp_polarities(polarities: &mut [bool; 2], raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 8);
polarities.iter_mut().enumerate().for_each(|(i, polarity)| {
let pos = i * 4;
deserialize_bool(polarity, &raw[pos..(pos + 4)]);
});
Ok(())
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AnalogInputLevel {
Line,
Mic,
Inst,
}
impl Default for AnalogInputLevel {
fn default() -> Self {
Self::Line
}
}
impl AnalogInputLevel {
const LINE_VALUE: u8 = 0;
const MIC_VALUE: u8 = 1;
const INST_VALUE: u8 = 2;
}
fn serialize_analog_input_levels(
levels: &[AnalogInputLevel; 8],
raw: &mut [u8],
) -> Result<(), String> {
assert!(raw.len() >= 8);
(0..levels.len()).step_by(4).for_each(|pos| {
let mut val = 0u32;
levels[pos..(pos + 4)]
.iter()
.enumerate()
.for_each(|(j, level)| {
let v = match level {
AnalogInputLevel::Line => AnalogInputLevel::LINE_VALUE,
AnalogInputLevel::Mic => AnalogInputLevel::MIC_VALUE,
AnalogInputLevel::Inst => AnalogInputLevel::INST_VALUE,
};
val |= (v as u32) << (j * 8);
});
serialize_u32(&val, &mut raw[pos..(pos + 4)]);
});
Ok(())
}
fn deserialize_analog_input_levels(
levels: &mut [AnalogInputLevel; 8],
raw: &[u8],
) -> Result<(), String> {
assert!(raw.len() >= 8);
let mut val = 0u32;
(0..levels.len()).step_by(4).try_for_each(|pos| {
deserialize_u32(&mut val, &raw[pos..(pos + 4)]);
levels[pos..(pos + 4)]
.iter_mut()
.enumerate()
.try_for_each(|(j, level)| {
let v = ((val >> (j * 8)) & 0x000000ff) as u8;
*level = match v {
AnalogInputLevel::LINE_VALUE => AnalogInputLevel::Line,
AnalogInputLevel::MIC_VALUE => AnalogInputLevel::Mic,
AnalogInputLevel::INST_VALUE => AnalogInputLevel::Inst,
_ => Err(format!("Analog input level not found for value: {}", val))?,
};
Ok(())
})
})
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct LedState {
pub adat1: bool,
pub adat2: bool,
pub spdif: bool,
pub midi_in: bool,
}
impl LedState {
const ADAT1_FLAG: u32 = 0x00000001;
const ADAT2_FLAG: u32 = 0x00000002;
const SPDIF_FLAG: u32 = 0x00000004;
const MIDI_IN_FLAG: u32 = 0x00000008;
}
fn serialize_led_state(state: &LedState, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
[
(&state.adat1, LedState::ADAT1_FLAG),
(&state.adat2, LedState::ADAT2_FLAG),
(&state.spdif, LedState::SPDIF_FLAG),
(&state.midi_in, LedState::MIDI_IN_FLAG),
]
.iter_mut()
.filter(|(&on, _)| on)
.for_each(|(_, flag)| val |= *flag);
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_led_state(state: &mut LedState, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
[
(&mut state.adat1, LedState::ADAT1_FLAG),
(&mut state.adat2, LedState::ADAT2_FLAG),
(&mut state.spdif, LedState::SPDIF_FLAG),
(&mut state.midi_in, LedState::MIDI_IN_FLAG),
]
.iter_mut()
.for_each(|(on, flag)| **on = val & *flag > 0);
Ok(())
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MeterDisplayTarget {
AnalogInput0,
AnalogInput1,
AnalogInput2,
AnalogInput3,
AnalogInput4,
AnalogInput5,
AnalogInput6,
AnalogInput7,
SpdifInput0,
SpdifInput1,
AdatInput0,
AdatInput1,
AdatInput2,
AdatInput3,
AdatInput4,
AdatInput5,
AdatInput6,
AdatInput7,
AdatInput8,
AdatInput9,
AdatInput10,
AdatInput11,
AdatInput12,
AdatInput13,
AdatInput14,
AdatInput15,
}
impl Default for MeterDisplayTarget {
fn default() -> Self {
MeterDisplayTarget::AnalogInput0
}
}
const METER_DISPLAY_TARGETS: &[MeterDisplayTarget] = &[
MeterDisplayTarget::AnalogInput0,
MeterDisplayTarget::AnalogInput1,
MeterDisplayTarget::AnalogInput2,
MeterDisplayTarget::AnalogInput3,
MeterDisplayTarget::AnalogInput4,
MeterDisplayTarget::AnalogInput5,
MeterDisplayTarget::AnalogInput6,
MeterDisplayTarget::AnalogInput7,
MeterDisplayTarget::SpdifInput0,
MeterDisplayTarget::SpdifInput1,
MeterDisplayTarget::AdatInput0,
MeterDisplayTarget::AdatInput1,
MeterDisplayTarget::AdatInput2,
MeterDisplayTarget::AdatInput3,
MeterDisplayTarget::AdatInput4,
MeterDisplayTarget::AdatInput5,
MeterDisplayTarget::AdatInput6,
MeterDisplayTarget::AdatInput7,
MeterDisplayTarget::AdatInput8,
MeterDisplayTarget::AdatInput9,
MeterDisplayTarget::AdatInput10,
MeterDisplayTarget::AdatInput11,
MeterDisplayTarget::AdatInput12,
MeterDisplayTarget::AdatInput13,
MeterDisplayTarget::AdatInput14,
MeterDisplayTarget::AdatInput15,
];
fn serialize_meter_display_targets(
targets: &[MeterDisplayTarget; 8],
raw: &mut [u8],
) -> Result<(), String> {
assert!(raw.len() >= 8);
(0..targets.len()).step_by(4).for_each(|pos| {
let mut val = 0u32;
targets[pos..(pos + 4)]
.iter()
.enumerate()
.for_each(|(j, target)| {
let pos = METER_DISPLAY_TARGETS
.iter()
.position(|t| target.eq(t))
.unwrap();
val |= (pos as u32) << (j * 8);
});
serialize_u32(&val, &mut raw[pos..(pos + 4)]);
});
Ok(())
}
fn deserialize_meter_display_targets(
targets: &mut [MeterDisplayTarget; 8],
raw: &[u8],
) -> Result<(), String> {
assert!(raw.len() >= 8);
let mut val = 0u32;
(0..targets.len()).step_by(4).try_for_each(|pos| {
deserialize_u32(&mut val, &raw[pos..(pos + 4)]);
targets[pos..(pos + 4)]
.iter_mut()
.enumerate()
.try_for_each(|(j, target)| {
let pos = ((val >> (j * 8)) & 0x000000ff) as usize;
METER_DISPLAY_TARGETS
.iter()
.nth(pos)
.ok_or_else(|| format!("Meter display target not found for position {}", pos))
.map(|&t| *target = t)
})
})
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct LiquidS56SpecificParams {
pub mic_amp_emulation_types: [MicAmpEmulationType; 2],
pub mic_amp_harmonics: [u8; 2],
pub mic_amp_polarities: [bool; 2],
pub analog_input_levels: [AnalogInputLevel; 8],
pub led_states: LedState,
pub meter_display_targets: [MeterDisplayTarget; 8],
}
const SPECIFIC_PARAMS_OFFSET: usize = 0x0278;
const SPECIFIC_PARAMS_SIZE: usize = 0x48;
fn serialize_specific_params(
params: &LiquidS56SpecificParams,
raw: &mut [u8],
) -> Result<(), String> {
assert!(raw.len() >= SPECIFIC_PARAMS_SIZE);
serialize_mic_amp_emulation_types(¶ms.mic_amp_emulation_types, &mut raw[..0x08])?;
serialize_mic_amp_harmonics(¶ms.mic_amp_harmonics, &mut raw[0x08..0x10])?;
serialize_mic_amp_polarities(¶ms.mic_amp_polarities, &mut raw[0x10..0x18])?;
serialize_meter_display_targets(¶ms.meter_display_targets, &mut raw[0x24..0x3c])?;
serialize_analog_input_levels(¶ms.analog_input_levels, &mut raw[0x3c..0x44])?;
serialize_led_state(¶ms.led_states, &mut raw[0x44..0x48])?;
Ok(())
}
fn deserialize_specific_params(
params: &mut LiquidS56SpecificParams,
raw: &[u8],
) -> Result<(), String> {
assert!(raw.len() >= SPECIFIC_PARAMS_SIZE);
deserialize_mic_amp_emulation_types(&mut params.mic_amp_emulation_types, &raw[..0x08])?;
deserialize_mic_amp_harmonics(&mut params.mic_amp_harmonics, &raw[0x08..0x10])?;
deserialize_mic_amp_polarities(&mut params.mic_amp_polarities, &raw[0x10..0x18])?;
deserialize_meter_display_targets(&mut params.meter_display_targets, &raw[0x24..0x3c])?;
deserialize_analog_input_levels(&mut params.analog_input_levels, &raw[0x3c..0x44])?;
deserialize_led_state(&mut params.led_states, &raw[0x44..0x48])?;
Ok(())
}
impl LiquidS56Protocol {
pub const MIC_AMP_HARMONICS_MIN: u8 = 0;
pub const MIC_AMP_HARMONICS_MAX: u8 = 21;
}
impl TcatExtensionSectionParamsOperation<LiquidS56SpecificParams> for LiquidS56Protocol {
fn cache_extension_whole_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &mut LiquidS56SpecificParams,
timeout_ms: u32,
) -> Result<(), Error> {
let mut raw = vec![0u8; SPECIFIC_PARAMS_SIZE];
Self::read_extension(
req,
node,
§ions.application,
SPECIFIC_PARAMS_OFFSET,
&mut raw,
timeout_ms,
)?;
deserialize_specific_params(params, &raw)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
}
}
impl TcatExtensionSectionPartialMutableParamsOperation<LiquidS56SpecificParams>
for LiquidS56Protocol
{
fn update_extension_partial_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &LiquidS56SpecificParams,
prev: &mut LiquidS56SpecificParams,
timeout_ms: u32,
) -> Result<(), Error> {
let mut new = vec![0u8; SPECIFIC_PARAMS_SIZE];
serialize_specific_params(params, &mut new)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
let mut old = vec![0u8; SPECIFIC_PARAMS_SIZE];
serialize_specific_params(prev, &mut old)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
(0..SPECIFIC_PARAMS_SIZE).step_by(4).try_for_each(|pos| {
if new[pos..(pos + 4)] != old[pos..(pos + 4)] {
Self::write_extension(
req,
node,
§ions.application,
SPECIFIC_PARAMS_OFFSET + pos,
&mut new[pos..(pos + 4)],
timeout_ms,
)
} else {
Ok(())
}
})?;
[
(0x00, MIC_AMP_1_EMULATION_SW_NOTICE),
(0x04, MIC_AMP_2_EMULATION_SW_NOTICE),
(0x08, MIC_AMP_1_HARMONICS_SW_NOTICE),
(0x0c, MIC_AMP_2_HARMONICS_SW_NOTICE),
(0x10, MIC_AMP_POLARITY_SW_NOTICE),
(0x14, MIC_AMP_POLARITY_SW_NOTICE),
(0x38, INPUT_LEVEL_SW_NOTICE),
(0x3c, INPUT_LEVEL_SW_NOTICE),
]
.iter()
.filter(|(pos, _)| &new[*pos..(*pos + 4)] != &old[*pos..(*pos + 4)])
.try_for_each(|(_, msg)| Self::write_sw_notice(req, node, sections, *msg, timeout_ms))?;
deserialize_specific_params(prev, &new)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn serdes_specific_params() {
let params = LiquidS56SpecificParams {
mic_amp_emulation_types: [MicAmpEmulationType::Savillerow, MicAmpEmulationType::Dunk],
mic_amp_harmonics: [0x59, 0xb2],
mic_amp_polarities: [false, true],
analog_input_levels: [
AnalogInputLevel::Line,
AnalogInputLevel::Mic,
AnalogInputLevel::Inst,
AnalogInputLevel::Line,
AnalogInputLevel::Mic,
AnalogInputLevel::Inst,
AnalogInputLevel::Line,
AnalogInputLevel::Mic,
],
led_states: LedState {
adat1: false,
adat2: true,
spdif: false,
midi_in: true,
},
meter_display_targets: [
MeterDisplayTarget::AdatInput8,
MeterDisplayTarget::AdatInput11,
MeterDisplayTarget::AdatInput2,
MeterDisplayTarget::AdatInput5,
MeterDisplayTarget::AnalogInput5,
MeterDisplayTarget::SpdifInput1,
MeterDisplayTarget::AnalogInput0,
MeterDisplayTarget::AnalogInput3,
],
};
let mut raw = vec![0u8; SPECIFIC_PARAMS_SIZE];
serialize_specific_params(¶ms, &mut raw).unwrap();
let mut p = LiquidS56SpecificParams::default();
deserialize_specific_params(&mut p, &raw).unwrap();
assert_eq!(params, p);
}
}