use super::{global_section::*, *};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AdatParam {
Normal,
SMUX2,
SMUX4,
Auto,
}
impl Default for AdatParam {
fn default() -> Self {
AdatParam::Auto
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum WordClockMode {
Normal,
Low,
Middle,
High,
}
impl Default for WordClockMode {
fn default() -> Self {
WordClockMode::Normal
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct WordClockRate {
pub numerator: u16,
pub denominator: u16,
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct WordClockParam {
pub mode: WordClockMode,
pub rate: WordClockRate,
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct StandaloneParameters {
pub clock_source: ClockSource,
pub aes_high_rate: bool,
pub adat_mode: AdatParam,
pub word_clock_param: WordClockParam,
pub internal_rate: ClockRate,
}
#[derive(Default)]
pub struct StandaloneSectionProtocol;
const MIN_SIZE: usize = 20;
fn serialize(params: &StandaloneParameters, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= MIN_SIZE);
let mut val = 0u8;
serialize_clock_source(¶ms.clock_source, &mut val)?;
serialize_u8(&val, &mut raw[..4]);
serialize_bool(¶ms.aes_high_rate, &mut raw[4..8]);
let val = match params.adat_mode {
AdatParam::Normal => 0x00u32,
AdatParam::SMUX2 => 0x01,
AdatParam::SMUX4 => 0x02,
AdatParam::Auto => 0x03,
};
serialize_u32(&val, &mut raw[8..12]);
let mut val = match params.word_clock_param.mode {
WordClockMode::Normal => 0x00u32,
WordClockMode::Low => 0x01,
WordClockMode::Middle => 0x02,
WordClockMode::High => 0x03,
};
if params.word_clock_param.rate.numerator < 1 || params.word_clock_param.rate.denominator < 1 {
let msg = format!(
"Invalid parameters for rate of word clock: {} / {}",
params.word_clock_param.rate.numerator, params.word_clock_param.rate.denominator
);
Err(msg)?;
}
val |= ((params.word_clock_param.rate.numerator as u32) - 1) << 4;
val |= ((params.word_clock_param.rate.denominator as u32) - 1) << 16;
serialize_u32(&val, &mut raw[12..16]);
let mut val = 0u8;
serialize_clock_rate(¶ms.internal_rate, &mut val)?;
serialize_u8(&val, &mut raw[16..20]);
Ok(())
}
fn deserialize(params: &mut StandaloneParameters, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= MIN_SIZE);
let mut val = 0u8;
deserialize_u8(&mut val, &raw[..4]);
deserialize_clock_source(&mut params.clock_source, &val)?;
deserialize_bool(&mut params.aes_high_rate, &raw[4..8]);
let mut val = 0u32;
deserialize_u32(&mut val, &raw[8..12]);
params.adat_mode = match val {
0x01 => AdatParam::SMUX2,
0x02 => AdatParam::SMUX4,
0x03 => AdatParam::Auto,
_ => AdatParam::Normal,
};
deserialize_u32(&mut val, &raw[12..16]);
params.word_clock_param.mode = match val & 0x03 {
0x01 => WordClockMode::Low,
0x02 => WordClockMode::Middle,
0x03 => WordClockMode::High,
_ => WordClockMode::Normal,
};
params.word_clock_param.rate.numerator = 1 + ((val >> 4) & 0x0fff) as u16;
params.word_clock_param.rate.denominator = 1 + ((val >> 16) & 0xffff) as u16;
let mut val = 0u8;
deserialize_u8(&mut val, &raw[16..20]);
deserialize_clock_rate(&mut params.internal_rate, &val)?;
Ok(())
}
impl<O: TcatExtensionOperation> TcatExtensionSectionParamsOperation<StandaloneParameters> for O {
fn cache_extension_whole_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &mut StandaloneParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let mut raw = vec![0; sections.standalone.size];
Self::read_extension(req, node, §ions.standalone, 0, &mut raw, timeout_ms)?;
deserialize(params, &raw)
.map_err(|msg| Error::new(ProtocolExtensionError::Standalone, &msg))
}
}
impl<O: TcatExtensionOperation>
TcatExtensionSectionPartialMutableParamsOperation<StandaloneParameters> for O
{
fn update_extension_partial_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &StandaloneParameters,
prev: &mut StandaloneParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let mut new = vec![0; sections.standalone.size];
serialize(params, &mut new)
.map_err(|e| Error::new(ProtocolExtensionError::Standalone, &e.to_string()))?;
let mut old = vec![0; sections.standalone.size];
serialize(params, &mut old)
.map_err(|e| Error::new(ProtocolExtensionError::Standalone, &e.to_string()))?;
(0..sections.standalone.size)
.step_by(4)
.try_for_each(|pos| {
if new[pos] != old[pos] {
Self::write_extension(
req,
node,
§ions.standalone,
pos,
&mut new[pos..(pos + 4)],
timeout_ms,
)
} else {
Ok(())
}
})?;
deserialize(prev, &new)
.map_err(|e| Error::new(ProtocolExtensionError::Standalone, &e.to_string()))
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn standalone_params_serdes() {
let params = StandaloneParameters {
clock_source: ClockSource::Tdif,
aes_high_rate: true,
adat_mode: AdatParam::SMUX4,
word_clock_param: WordClockParam {
mode: WordClockMode::Middle,
rate: WordClockRate {
numerator: 12,
denominator: 7,
},
},
internal_rate: ClockRate::R88200,
};
let mut raw = [0u8; MIN_SIZE];
assert!(serialize(¶ms, &mut raw).is_ok());
let mut p = StandaloneParameters::default();
assert!(deserialize(&mut p, &raw).is_ok());
assert_eq!(params, p);
}
}