firewire_dice_protocols/tcat/extension/
standalone_section.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! Standalone section in protocol extension defined by TCAT for ASICs of DICE.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for standalone
7//! section in protocol extension defined by TCAT for ASICs of DICE.
8
9use super::{global_section::*, *};
10
11// const CLK_SRC_OFFSET: usize = 0x00;
12// const AES_CFG_OFFSET: usize = 0x04;
13// const ADAT_CFG_OFFSET: usize = 0x08;
14// const WC_CFG_OFFSET: usize = 0x0c;
15// const INTERNAL_CFG_OFFSET: usize = 0x10;
16
17/// Parameter of ADAT input/output.
18#[derive(Debug, Copy, Clone, PartialEq, Eq)]
19pub enum AdatParam {
20    Normal,
21    SMUX2,
22    SMUX4,
23    Auto,
24}
25
26impl Default for AdatParam {
27    fn default() -> Self {
28        AdatParam::Auto
29    }
30}
31
32/// Mode of word clock input/output.
33#[derive(Debug, Copy, Clone, PartialEq, Eq)]
34pub enum WordClockMode {
35    Normal,
36    Low,
37    Middle,
38    High,
39}
40
41impl Default for WordClockMode {
42    fn default() -> Self {
43        WordClockMode::Normal
44    }
45}
46
47/// Rate of word clock input/output by enumerator and denominator.
48#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
49pub struct WordClockRate {
50    pub numerator: u16,
51    pub denominator: u16,
52}
53
54/// Parameter of word clock input/output.
55#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
56pub struct WordClockParam {
57    pub mode: WordClockMode,
58    pub rate: WordClockRate,
59}
60
61/// Parameters in standalone configuration section.
62#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
63pub struct StandaloneParameters {
64    /// Source of sampling clock.
65    pub clock_source: ClockSource,
66    /// Mode of AES input at high rate.
67    pub aes_high_rate: bool,
68    /// Mode of ADAT input for supported rates.
69    pub adat_mode: AdatParam,
70    /// Mode of word clock input.
71    pub word_clock_param: WordClockParam,
72    /// Internally generated sampling clock.
73    pub internal_rate: ClockRate,
74}
75
76/// Protocol implementation of standalone section.
77#[derive(Default)]
78pub struct StandaloneSectionProtocol;
79
80const MIN_SIZE: usize = 20;
81
82fn serialize(params: &StandaloneParameters, raw: &mut [u8]) -> Result<(), String> {
83    assert!(raw.len() >= MIN_SIZE);
84
85    let mut val = 0u8;
86    serialize_clock_source(&params.clock_source, &mut val)?;
87    serialize_u8(&val, &mut raw[..4]);
88
89    serialize_bool(&params.aes_high_rate, &mut raw[4..8]);
90
91    let val = match params.adat_mode {
92        AdatParam::Normal => 0x00u32,
93        AdatParam::SMUX2 => 0x01,
94        AdatParam::SMUX4 => 0x02,
95        AdatParam::Auto => 0x03,
96    };
97    serialize_u32(&val, &mut raw[8..12]);
98
99    let mut val = match params.word_clock_param.mode {
100        WordClockMode::Normal => 0x00u32,
101        WordClockMode::Low => 0x01,
102        WordClockMode::Middle => 0x02,
103        WordClockMode::High => 0x03,
104    };
105    if params.word_clock_param.rate.numerator < 1 || params.word_clock_param.rate.denominator < 1 {
106        let msg = format!(
107            "Invalid parameters for rate of word clock: {} / {}",
108            params.word_clock_param.rate.numerator, params.word_clock_param.rate.denominator
109        );
110        Err(msg)?;
111    }
112    val |= ((params.word_clock_param.rate.numerator as u32) - 1) << 4;
113    val |= ((params.word_clock_param.rate.denominator as u32) - 1) << 16;
114    serialize_u32(&val, &mut raw[12..16]);
115
116    let mut val = 0u8;
117    serialize_clock_rate(&params.internal_rate, &mut val)?;
118    serialize_u8(&val, &mut raw[16..20]);
119
120    Ok(())
121}
122
123fn deserialize(params: &mut StandaloneParameters, raw: &[u8]) -> Result<(), String> {
124    assert!(raw.len() >= MIN_SIZE);
125
126    let mut val = 0u8;
127    deserialize_u8(&mut val, &raw[..4]);
128    deserialize_clock_source(&mut params.clock_source, &val)?;
129
130    deserialize_bool(&mut params.aes_high_rate, &raw[4..8]);
131
132    let mut val = 0u32;
133    deserialize_u32(&mut val, &raw[8..12]);
134    params.adat_mode = match val {
135        0x01 => AdatParam::SMUX2,
136        0x02 => AdatParam::SMUX4,
137        0x03 => AdatParam::Auto,
138        _ => AdatParam::Normal,
139    };
140
141    deserialize_u32(&mut val, &raw[12..16]);
142    params.word_clock_param.mode = match val & 0x03 {
143        0x01 => WordClockMode::Low,
144        0x02 => WordClockMode::Middle,
145        0x03 => WordClockMode::High,
146        _ => WordClockMode::Normal,
147    };
148    params.word_clock_param.rate.numerator = 1 + ((val >> 4) & 0x0fff) as u16;
149    params.word_clock_param.rate.denominator = 1 + ((val >> 16) & 0xffff) as u16;
150
151    let mut val = 0u8;
152    deserialize_u8(&mut val, &raw[16..20]);
153    deserialize_clock_rate(&mut params.internal_rate, &val)?;
154
155    Ok(())
156}
157
158impl<O: TcatExtensionOperation> TcatExtensionSectionParamsOperation<StandaloneParameters> for O {
159    fn cache_extension_whole_params(
160        req: &FwReq,
161        node: &FwNode,
162        sections: &ExtensionSections,
163        _: &ExtensionCaps,
164        params: &mut StandaloneParameters,
165        timeout_ms: u32,
166    ) -> Result<(), Error> {
167        let mut raw = vec![0; sections.standalone.size];
168        Self::read_extension(req, node, &sections.standalone, 0, &mut raw, timeout_ms)?;
169
170        deserialize(params, &raw)
171            .map_err(|msg| Error::new(ProtocolExtensionError::Standalone, &msg))
172    }
173}
174
175impl<O: TcatExtensionOperation>
176    TcatExtensionSectionPartialMutableParamsOperation<StandaloneParameters> for O
177{
178    fn update_extension_partial_params(
179        req: &FwReq,
180        node: &FwNode,
181        sections: &ExtensionSections,
182        _: &ExtensionCaps,
183        params: &StandaloneParameters,
184        prev: &mut StandaloneParameters,
185        timeout_ms: u32,
186    ) -> Result<(), Error> {
187        let mut new = vec![0; sections.standalone.size];
188        serialize(params, &mut new)
189            .map_err(|e| Error::new(ProtocolExtensionError::Standalone, &e.to_string()))?;
190
191        let mut old = vec![0; sections.standalone.size];
192        serialize(params, &mut old)
193            .map_err(|e| Error::new(ProtocolExtensionError::Standalone, &e.to_string()))?;
194
195        (0..sections.standalone.size)
196            .step_by(4)
197            .try_for_each(|pos| {
198                if new[pos] != old[pos] {
199                    Self::write_extension(
200                        req,
201                        node,
202                        &sections.standalone,
203                        pos,
204                        &mut new[pos..(pos + 4)],
205                        timeout_ms,
206                    )
207                } else {
208                    Ok(())
209                }
210            })?;
211
212        deserialize(prev, &new)
213            .map_err(|e| Error::new(ProtocolExtensionError::Standalone, &e.to_string()))
214    }
215}
216
217#[cfg(test)]
218mod test {
219    use super::*;
220
221    #[test]
222    fn standalone_params_serdes() {
223        let params = StandaloneParameters {
224            clock_source: ClockSource::Tdif,
225            aes_high_rate: true,
226            adat_mode: AdatParam::SMUX4,
227            word_clock_param: WordClockParam {
228                mode: WordClockMode::Middle,
229                rate: WordClockRate {
230                    numerator: 12,
231                    denominator: 7,
232                },
233            },
234            internal_rate: ClockRate::R88200,
235        };
236
237        let mut raw = [0u8; MIN_SIZE];
238        assert!(serialize(&params, &mut raw).is_ok());
239
240        let mut p = StandaloneParameters::default();
241        assert!(deserialize(&mut p, &raw).is_ok());
242
243        assert_eq!(params, p);
244    }
245}