use {
super::{super::tcat::global_section::*, *},
std::ops::Range,
};
#[derive(Default, Debug)]
pub struct FStudioProtocol;
impl TcatOperation for FStudioProtocol {}
impl TcatGlobalSectionSpecification for FStudioProtocol {
const CLOCK_SOURCE_LABEL_TABLE: &'static [ClockSource] = &[
ClockSource::Aes1,
ClockSource::Adat,
ClockSource::WordClock,
ClockSource::Arx1,
ClockSource::Arx2,
ClockSource::Arx3,
ClockSource::Arx4,
ClockSource::Internal,
];
}
impl FStudioOperation for FStudioProtocol {}
const OFFSET: usize = 0x00700000;
const MIXER_PHYS_SRC_PARAMS_OFFSET: usize = 0x0038;
const MIXER_STREAM_SRC_PARAMS_OFFSET: usize = 0x07d0;
const MIXER_SELECTABLE_SRC_PARAMS_OFFSET: usize = 0x0c08;
const OUTPUT_PARAMS_OFFSET: usize = 0x0f68;
const MIXER_OUTPUT_PARAMS_OFFSET: usize = 0x1040;
const OUTPUT_SRC_OFFSET: usize = 0x10ac;
const OUTPUT_ASSIGN_OFFSET: usize = 0x10f4;
const OUTPUT_BNC_TERMINATE_OFFSET: usize = 0x1118;
const MIXER_EXPANSION_MODE_OFFSET: usize = 0x1128;
const MIXER_SRC_LINK_OFFSET: usize = 0x112c;
const OUTPUT_LINK_OFFSET: usize = 0x1150;
const METER_OFFSET: usize = 0x13e8;
const OUTPUT_PARAMS_SIZE: usize = 4 * 3 * (8 + 8 + 2);
const OUTPUT_SRC_SIZE: usize = 4 * (8 + 8 + 2);
const OUTPUT_ASSIGN_SIZE: usize = 4 * 4;
const OUTPUT_BNC_TERMINATE_SIZE: usize = 4;
const OUTPUT_LINK_SIZE: usize = 4;
const MIXER_PHYS_SRC_PARAMS_SIZE: usize = 4 * 9 * 3 * (8 + 8 + 2);
const MIXER_STREAM_SRC_PARAMS_SIZE: usize = 4 * 9 * 3 * 10;
const MIXER_SELECTABLE_SRC_PARAMS_SIZE: usize = 4 * 9 * 3 * 8;
const MIXER_OUTPUT_PARAMS_SIZE: usize = 4 * 9 * 3;
const MIXER_EXPANSION_MODE_SIZE: usize = 4;
const MIXER_SRC_LINK_SIZE: usize = 4 * 9;
pub trait FStudioParametersSerdes<T> {
const NAME: &'static str;
const OFFSET_RANGES: &'static [Range<usize>];
fn serialize_params(params: &T, raw: &mut [u8]) -> Result<(), String>;
fn deserialize_params(params: &mut T, raw: &[u8]) -> Result<(), String>;
}
fn compute_params_size(ranges: &[Range<usize>]) -> usize {
ranges
.iter()
.fold(0usize, |size, range| size + range.end - range.start)
}
fn generate_err(name: &str, cause: &str, raw: &[u8]) -> Error {
let msg = format!("params: {}, cause: {}, raw: {:02x?}", name, cause, raw);
Error::new(GeneralProtocolError::VendorDependent, &msg)
}
pub trait FStudioOperation: TcatOperation {
fn read_parameters(
req: &FwReq,
node: &FwNode,
offset: usize,
raw: &mut [u8],
timeout_ms: u32,
) -> Result<(), Error> {
Self::read(req, node, OFFSET + offset, raw, timeout_ms)
}
fn write_parameters(
req: &FwReq,
node: &FwNode,
offset: usize,
raw: &mut [u8],
timeout_ms: u32,
) -> Result<(), Error> {
Self::write(req, node, OFFSET + offset, raw, timeout_ms)
}
}
pub trait FStudioParametersOperation<T>: FStudioOperation + FStudioParametersSerdes<T> {
fn cache_whole_parameters(
req: &FwReq,
node: &FwNode,
params: &mut T,
timeout_ms: u32,
) -> Result<(), Error> {
let size = compute_params_size(Self::OFFSET_RANGES);
let mut raw = vec![0u8; size];
let mut pos = 0;
Self::OFFSET_RANGES.iter().try_for_each(|range| {
let size = range.end - range.start;
Self::read_parameters(
req,
node,
range.start,
&mut raw[pos..(pos + size)],
timeout_ms,
)
.map(|_| pos += size)
})?;
Self::deserialize_params(params, &raw)
.map_err(|cause| generate_err(Self::NAME, &cause, &raw))
}
}
impl<O: FStudioOperation + FStudioParametersSerdes<T>, T> FStudioParametersOperation<T> for O {}
pub trait FStudioMutableParametersOperation<T>:
FStudioOperation + FStudioParametersSerdes<T>
{
fn update_partial_parameters(
req: &FwReq,
node: &FwNode,
params: &T,
prev: &mut T,
timeout_ms: u32,
) -> Result<(), Error> {
let size = compute_params_size(Self::OFFSET_RANGES);
let mut new = vec![0u8; size];
let mut old = vec![0u8; size];
Self::serialize_params(params, &mut new)
.map_err(|cause| generate_err(Self::NAME, &cause, &new))?;
Self::serialize_params(prev, &mut old)
.map_err(|cause| generate_err(Self::NAME, &cause, &old))?;
let mut pos = 0;
Self::OFFSET_RANGES.iter().try_for_each(|range| {
let size = range.end - range.start;
if new[pos..(pos + size)] != old[pos..(pos + size)] {
(0..size).step_by(4).try_for_each(|offset| {
let p = pos + offset;
if new[p..(p + 4)] != old[p..(p + 4)] {
Self::write_parameters(
req,
node,
range.start + offset,
&mut new[p..(p + 4)],
timeout_ms,
)
} else {
Ok(())
}
})
} else {
Ok(())
}
.map(|_| pos += size)
})?;
Self::deserialize_params(prev, &new).map_err(|cause| generate_err(Self::NAME, &cause, &new))
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct FStudioMeter {
pub analog_inputs: [u8; 8],
pub stream_inputs: [u8; 18],
pub mixer_outputs: [u8; 18],
}
impl FStudioMeter {
const SIZE: usize = 64;
}
impl FStudioParametersSerdes<FStudioMeter> for FStudioProtocol {
const NAME: &'static str = "meter";
const OFFSET_RANGES: &'static [Range<usize>] = &[Range {
start: METER_OFFSET,
end: METER_OFFSET + FStudioMeter::SIZE,
}];
fn serialize_params(params: &FStudioMeter, raw: &mut [u8]) -> Result<(), String> {
[
(8, ¶ms.analog_inputs[..]),
(16, ¶ms.stream_inputs[..]),
(40, ¶ms.mixer_outputs[..]),
]
.iter()
.for_each(|(offset, meters)| {
meters.iter().enumerate().for_each(|(i, &meter)| {
let pos = *offset + (i / 4) * 4 + (3 - i % 4);
raw[pos] = meter;
});
});
Ok(())
}
fn deserialize_params(params: &mut FStudioMeter, raw: &[u8]) -> Result<(), String> {
[
(8, &mut params.analog_inputs[..]),
(16, &mut params.stream_inputs[..]),
(40, &mut params.mixer_outputs[..]),
]
.iter_mut()
.for_each(|(offset, meters)| {
meters.iter_mut().enumerate().for_each(|(i, meter)| {
let pos = *offset + (i / 4) * 4 + (3 - i % 4);
*meter = raw[pos];
});
});
Ok(())
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum OutputSrc {
Analog(usize),
Adat0(usize),
Spdif(usize),
Stream(usize),
StreamAdat1(usize),
MixerOut(usize),
}
impl Default for OutputSrc {
fn default() -> Self {
Self::Analog(0)
}
}
fn serialize_output_source(src: &OutputSrc, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let val = (match src {
OutputSrc::Analog(val) => *val,
OutputSrc::Adat0(val) => *val + 0x08,
OutputSrc::Spdif(val) => *val + 0x10,
OutputSrc::Stream(val) => *val + 0x12,
OutputSrc::StreamAdat1(val) => *val + 0x1c,
OutputSrc::MixerOut(val) => *val + 0x24,
}) as u32;
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_output_source(src: &mut OutputSrc, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0usize;
deserialize_usize(&mut val, raw);
*src = match val {
0x00..=0x07 => OutputSrc::Analog(val),
0x08..=0x0f => OutputSrc::Adat0(val - 0x08),
0x10..=0x11 => OutputSrc::Spdif(val - 0x10),
0x12..=0x1b => OutputSrc::Stream(val - 0x12),
0x1c..=0x23 => OutputSrc::StreamAdat1(val - 0x1c),
0x24..=0x35 => OutputSrc::MixerOut(val - 0x24),
_ => Err(format!("Output source not found for value {}", val))?,
};
Ok(())
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct OutputPair {
pub volumes: [u8; 2],
pub mutes: [bool; 2],
pub src: OutputSrc,
pub link: bool,
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct OutputParameters {
pub pairs: [OutputPair; 9],
pub main_assign: AssignTarget,
pub headphone_assigns: [AssignTarget; 3],
pub bnc_terminate: bool,
}
impl FStudioParametersSerdes<OutputParameters> for FStudioProtocol {
const NAME: &'static str = "output-state";
const OFFSET_RANGES: &'static [Range<usize>] = &[
Range {
start: OUTPUT_PARAMS_OFFSET,
end: OUTPUT_PARAMS_OFFSET + OUTPUT_PARAMS_SIZE,
},
Range {
start: OUTPUT_SRC_OFFSET,
end: OUTPUT_SRC_OFFSET + OUTPUT_SRC_SIZE,
},
Range {
start: OUTPUT_ASSIGN_OFFSET,
end: OUTPUT_ASSIGN_OFFSET + OUTPUT_ASSIGN_SIZE,
},
Range {
start: OUTPUT_BNC_TERMINATE_OFFSET,
end: OUTPUT_BNC_TERMINATE_OFFSET + OUTPUT_BNC_TERMINATE_SIZE,
},
Range {
start: OUTPUT_LINK_OFFSET,
end: OUTPUT_LINK_OFFSET + OUTPUT_LINK_SIZE,
},
];
fn serialize_params(params: &OutputParameters, raw: &mut [u8]) -> Result<(), String> {
params.pairs.iter().enumerate().try_for_each(|(i, pair)| {
pair.volumes.iter().enumerate().for_each(|(j, vol)| {
let pos = 4 * 3 * (i * 2 + j);
serialize_u8(vol, &mut raw[pos..(pos + 4)]);
});
pair.mutes.iter().enumerate().for_each(|(j, mute)| {
let pos = 4 * (3 * (i * 2 + j) + 2);
serialize_bool(mute, &mut raw[pos..(pos + 4)]);
});
let pos = 216 + 4 * i;
serialize_output_source(&pair.src, &mut raw[pos..(pos + 4)])
})?;
serialize_assign_target(¶ms.main_assign, &mut raw[288..292])?;
serialize_assign_target(¶ms.headphone_assigns[0], &mut raw[292..296])?;
serialize_assign_target(¶ms.headphone_assigns[1], &mut raw[296..300])?;
serialize_assign_target(¶ms.headphone_assigns[2], &mut raw[300..304])?;
serialize_bool(¶ms.bnc_terminate, &mut raw[304..308]);
let mut val = 0u32;
params
.pairs
.iter()
.enumerate()
.filter(|(_, pair)| pair.link)
.for_each(|(i, _)| {
val |= 1 << i;
});
serialize_u32(&val, &mut raw[308..312]);
Ok(())
}
fn deserialize_params(params: &mut OutputParameters, raw: &[u8]) -> Result<(), String> {
params
.pairs
.iter_mut()
.enumerate()
.try_for_each(|(i, pair)| {
pair.volumes.iter_mut().enumerate().for_each(|(j, vol)| {
let pos = 4 * 3 * (i * 2 + j);
deserialize_u8(vol, &raw[pos..(pos + 4)]);
});
pair.mutes.iter_mut().enumerate().for_each(|(j, mute)| {
let pos = 4 * (3 * (i * 2 + j) + 2);
deserialize_bool(mute, &raw[pos..(pos + 4)]);
});
let pos = 216 + 4 * i;
deserialize_output_source(&mut pair.src, &raw[pos..(pos + 4)])
})?;
deserialize_assign_target(&mut params.main_assign, &raw[288..292])?;
deserialize_assign_target(&mut params.headphone_assigns[0], &raw[292..296])?;
deserialize_assign_target(&mut params.headphone_assigns[1], &raw[296..300])?;
deserialize_assign_target(&mut params.headphone_assigns[2], &raw[300..304])?;
deserialize_bool(&mut params.bnc_terminate, &raw[304..308]);
let mut val = 0u32;
deserialize_u32(&mut val, &raw[308..312]);
params.pairs.iter_mut().enumerate().for_each(|(i, pair)| {
pair.link = (val & (1 << i)) > 0;
});
Ok(())
}
}
impl<O: FStudioOperation + FStudioParametersSerdes<OutputParameters>>
FStudioMutableParametersOperation<OutputParameters> for O
{
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AssignTarget {
Analog01,
Analog23,
Analog56,
Analog78,
AdatA01,
AdatA23,
AdatA45,
AdatA67,
Spdif01,
}
impl Default for AssignTarget {
fn default() -> Self {
Self::Analog01
}
}
fn serialize_assign_target(target: &AssignTarget, raw: &mut [u8]) -> Result<(), String> {
let val = match target {
AssignTarget::Analog01 => 0x00u32,
AssignTarget::Analog23 => 0x02,
AssignTarget::Analog56 => 0x04,
AssignTarget::Analog78 => 0x06,
AssignTarget::AdatA01 => 0x08,
AssignTarget::AdatA23 => 0x0a,
AssignTarget::AdatA45 => 0x0c,
AssignTarget::AdatA67 => 0x0e,
AssignTarget::Spdif01 => 0x10,
};
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_assign_target(target: &mut AssignTarget, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
*target = match val {
0x00 => AssignTarget::Analog01,
0x02 => AssignTarget::Analog23,
0x04 => AssignTarget::Analog56,
0x06 => AssignTarget::Analog78,
0x08 => AssignTarget::AdatA01,
0x0a => AssignTarget::AdatA23,
0x0c => AssignTarget::AdatA45,
0x0e => AssignTarget::AdatA67,
0x10 => AssignTarget::Spdif01,
_ => Err(format!("Assign target not found for value {}", val))?,
};
Ok(())
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ExpansionMode {
StreamB0_7,
AdatB0_7,
}
impl Default for ExpansionMode {
fn default() -> Self {
Self::StreamB0_7
}
}
fn serialize_expansion_mode(mode: &ExpansionMode, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let val = match mode {
ExpansionMode::StreamB0_7 => 0u32,
ExpansionMode::AdatB0_7 => 1,
};
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_expansion_mode(mode: &mut ExpansionMode, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
*mode = match val {
0 => ExpansionMode::StreamB0_7,
1 => ExpansionMode::AdatB0_7,
_ => Err(format!("Expansion mode not found for value {}", val))?,
};
Ok(())
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct MixerSourcePair {
pub gains: [u8; 2],
pub balances: [u8; 2],
pub mutes: [bool; 2],
pub link: bool,
}
fn serialize_mixer_source_pair(pair: &MixerSourcePair, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 24);
serialize_u8(&pair.gains[0], &mut raw[..4]);
serialize_u8(&pair.balances[0], &mut raw[4..8]);
serialize_bool(&pair.mutes[0], &mut raw[8..12]);
serialize_u8(&pair.gains[1], &mut raw[12..16]);
serialize_u8(&pair.balances[1], &mut raw[16..20]);
serialize_bool(&pair.mutes[1], &mut raw[20..24]);
Ok(())
}
fn deserialize_mixer_source_pair(pair: &mut MixerSourcePair, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 24);
deserialize_u8(&mut pair.gains[0], &raw[..4]);
deserialize_u8(&mut pair.balances[0], &raw[4..8]);
deserialize_bool(&mut pair.mutes[0], &raw[8..12]);
deserialize_u8(&mut pair.gains[1], &raw[12..16]);
deserialize_u8(&mut pair.balances[1], &raw[16..20]);
deserialize_bool(&mut pair.mutes[1], &raw[20..24]);
Ok(())
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct MixerSources {
pub analog_pairs: [MixerSourcePair; 4],
pub adat_0_pairs: [MixerSourcePair; 4],
pub spdif_pairs: [MixerSourcePair; 1],
pub stream_pairs: [MixerSourcePair; 5],
pub selectable_pairs: [MixerSourcePair; 4],
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct MixerOutputPair {
pub volume: u8,
pub mute: bool,
}
fn serialize_mixer_output_pair(pair: &MixerOutputPair, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 12);
serialize_u8(&pair.volume, &mut raw[..4]);
serialize_bool(&pair.mute, &mut raw[8..12]);
Ok(())
}
fn deserialize_mixer_output_pair(pair: &mut MixerOutputPair, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 12);
deserialize_u8(&mut pair.volume, &raw[..4]);
deserialize_bool(&mut pair.mute, &raw[8..12]);
Ok(())
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct MixerParameters {
pub sources: [MixerSources; 9],
pub outputs: [MixerOutputPair; 9],
pub expansion_mode: ExpansionMode,
}
impl FStudioParametersSerdes<MixerParameters> for FStudioProtocol {
const NAME: &'static str = "mixer-parameters";
const OFFSET_RANGES: &'static [Range<usize>] = &[
Range {
start: MIXER_PHYS_SRC_PARAMS_OFFSET,
end: MIXER_PHYS_SRC_PARAMS_OFFSET + MIXER_PHYS_SRC_PARAMS_SIZE,
},
Range {
start: MIXER_STREAM_SRC_PARAMS_OFFSET,
end: MIXER_STREAM_SRC_PARAMS_OFFSET + MIXER_STREAM_SRC_PARAMS_SIZE,
},
Range {
start: MIXER_SELECTABLE_SRC_PARAMS_OFFSET,
end: MIXER_SELECTABLE_SRC_PARAMS_OFFSET + MIXER_SELECTABLE_SRC_PARAMS_SIZE,
},
Range {
start: MIXER_OUTPUT_PARAMS_OFFSET,
end: MIXER_OUTPUT_PARAMS_OFFSET + MIXER_OUTPUT_PARAMS_SIZE,
},
Range {
start: MIXER_EXPANSION_MODE_OFFSET,
end: MIXER_EXPANSION_MODE_OFFSET + MIXER_EXPANSION_MODE_SIZE,
},
Range {
start: MIXER_SRC_LINK_OFFSET,
end: MIXER_SRC_LINK_OFFSET + MIXER_SRC_LINK_SIZE,
},
];
fn serialize_params(params: &MixerParameters, raw: &mut [u8]) -> Result<(), String> {
params
.sources
.iter()
.enumerate()
.try_for_each(|(i, srcs)| {
srcs.analog_pairs
.iter()
.chain(srcs.adat_0_pairs.iter())
.chain(srcs.spdif_pairs.iter())
.enumerate()
.try_for_each(|(j, pair)| {
let pos = 4 * (3 * (i * 18 + j * 2));
serialize_mixer_source_pair(pair, &mut raw[pos..(pos + 24)])
})?;
srcs.stream_pairs
.iter()
.enumerate()
.try_for_each(|(j, pair)| {
let pos = 4 * (3 * (9 * 18 + i * 10 + j * 2));
serialize_mixer_source_pair(pair, &mut raw[pos..(pos + 24)])
})?;
srcs.selectable_pairs
.iter()
.enumerate()
.try_for_each(|(j, pair)| {
let pos = 4 * (3 * (9 * 28 + i * 8 + j * 2));
serialize_mixer_source_pair(pair, &mut raw[pos..(pos + 24)])
})
})?;
params
.outputs
.iter()
.enumerate()
.try_for_each(|(i, pair)| {
let pos = 4 * 3 * (9 * 36 + i);
serialize_mixer_output_pair(pair, &mut raw[pos..(pos + 12)])
})?;
let pos = 4 * (3 * 9 * 36 + 3 * 9);
serialize_expansion_mode(¶ms.expansion_mode, &mut raw[pos..(pos + 4)])?;
params.sources.iter().enumerate().for_each(|(i, srcs)| {
let mut val = 0u32;
srcs.analog_pairs
.iter()
.chain(srcs.adat_0_pairs.iter())
.chain(srcs.spdif_pairs.iter())
.enumerate()
.filter(|(_, pair)| pair.link)
.for_each(|(j, _)| val |= 1 << j);
srcs.stream_pairs
.iter()
.chain(srcs.selectable_pairs.iter())
.enumerate()
.filter(|(_, pair)| pair.link)
.for_each(|(j, _)| val |= 1 << (16 + j));
let pos = 4 * (3 * 9 * 36 + 3 * 9 + 1 + i);
serialize_u32(&val, &mut raw[pos..(pos + 4)]);
});
Ok(())
}
fn deserialize_params(params: &mut MixerParameters, raw: &[u8]) -> Result<(), String> {
params
.sources
.iter_mut()
.enumerate()
.try_for_each(|(i, srcs)| {
srcs.analog_pairs
.iter_mut()
.chain(srcs.adat_0_pairs.iter_mut())
.chain(srcs.spdif_pairs.iter_mut())
.enumerate()
.try_for_each(|(j, pair)| {
let pos = 4 * (3 * (i * 18 + j * 2));
deserialize_mixer_source_pair(pair, &raw[pos..(pos + 24)])
})?;
srcs.stream_pairs
.iter_mut()
.enumerate()
.try_for_each(|(j, pair)| {
let pos = 4 * (3 * (9 * 18 + i * 10 + j * 2));
deserialize_mixer_source_pair(pair, &raw[pos..(pos + 24)])
})?;
srcs.selectable_pairs
.iter_mut()
.enumerate()
.try_for_each(|(j, pair)| {
let pos = 4 * (3 * (9 * 28 + i * 8 + j * 2));
deserialize_mixer_source_pair(pair, &raw[pos..(pos + 24)])
})
})?;
params
.outputs
.iter_mut()
.enumerate()
.try_for_each(|(i, pair)| {
let pos = 4 * 3 * (9 * 36 + i);
deserialize_mixer_output_pair(pair, &raw[pos..(pos + 12)])
})?;
let pos = 4 * (3 * 9 * 36 + 3 * 9);
deserialize_expansion_mode(&mut params.expansion_mode, &raw[pos..(pos + 4)])?;
params.sources.iter_mut().enumerate().for_each(|(i, srcs)| {
let pos = 4 * (3 * 9 * 36 + 3 * 9 + 1 + i);
let mut val = 0u32;
deserialize_u32(&mut val, &raw[pos..(pos + 4)]);
srcs.analog_pairs
.iter_mut()
.chain(srcs.adat_0_pairs.iter_mut())
.chain(srcs.spdif_pairs.iter_mut())
.enumerate()
.for_each(|(j, pair)| pair.link = val & (1 << j) > 0);
srcs.stream_pairs
.iter_mut()
.chain(srcs.selectable_pairs.iter_mut())
.enumerate()
.for_each(|(j, pair)| pair.link = val & (1 << (16 + j)) > 0);
});
Ok(())
}
}
impl<O: FStudioOperation + FStudioParametersSerdes<MixerParameters>>
FStudioMutableParametersOperation<MixerParameters> for O
{
}
pub const MIXER_COUNT: usize = 9;
#[cfg(test)]
mod test {
use super::*;
#[test]
fn meter_params_serdes() {
let target = FStudioMeter {
analog_inputs: [0, 1, 2, 3, 4, 5, 6, 7],
stream_inputs: [17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0],
mixer_outputs: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
};
let size = compute_params_size(
<FStudioProtocol as FStudioParametersSerdes<FStudioMeter>>::OFFSET_RANGES,
);
let mut raw = vec![0; size];
assert!(FStudioProtocol::serialize_params(&target, &mut raw).is_ok());
let mut params = FStudioMeter::default();
assert!(FStudioProtocol::deserialize_params(&mut params, &raw).is_ok());
assert_eq!(target, params);
}
#[test]
fn output_params_serdes() {
let target = OutputParameters {
pairs: [Default::default(); 9],
main_assign: AssignTarget::AdatA67,
headphone_assigns: [
AssignTarget::Analog78,
AssignTarget::Spdif01,
AssignTarget::AdatA45,
],
bnc_terminate: true,
};
let size = compute_params_size(
<FStudioProtocol as FStudioParametersSerdes<OutputParameters>>::OFFSET_RANGES,
);
let mut raw = vec![0; size];
assert!(FStudioProtocol::serialize_params(&target, &mut raw).is_ok());
let mut params = OutputParameters::default();
assert!(FStudioProtocol::deserialize_params(&mut params, &raw).is_ok());
assert_eq!(target, params, "{:02x?}", raw);
}
#[test]
fn mixer_params_serdes() {
let mut target = MixerParameters::default();
target.sources.iter_mut().enumerate().for_each(|(i, srcs)| {
srcs.analog_pairs
.iter_mut()
.chain(srcs.adat_0_pairs.iter_mut())
.chain(srcs.spdif_pairs.iter_mut())
.chain(srcs.stream_pairs.iter_mut())
.chain(srcs.selectable_pairs.iter_mut())
.enumerate()
.for_each(|(j, pair)| {
pair.gains[0] = (i * 9 + j * 3) as u8;
pair.gains[1] = (i * 11 + j * 1) as u8;
pair.balances[0] = (i * 7 + j * 5) as u8;
pair.balances[1] = (i * 5 + j * 7) as u8;
pair.mutes[0] = (i + j * 2) % 2 > 0;
pair.mutes[1] = (i * 2 + j) % 2 > 0;
pair.link = (i + j) % 2 > 0;
});
});
target.outputs.iter_mut().enumerate().for_each(|(i, pair)| {
pair.volume = 3 * i as u8;
pair.mute = i % 2 > 0;
});
target.expansion_mode = ExpansionMode::AdatB0_7;
let size = compute_params_size(
<FStudioProtocol as FStudioParametersSerdes<MixerParameters>>::OFFSET_RANGES,
);
let mut raw = vec![0; size];
assert!(FStudioProtocol::serialize_params(&target, &mut raw).is_ok());
let mut params = MixerParameters::default();
assert!(FStudioProtocol::deserialize_params(&mut params, &raw).is_ok());
assert_eq!(target, params);
}
}