firewire_dice_protocols/tcat/extension/
mixer_section.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! Mixer section in protocol extension defined by TCAT for ASICs of DICE.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for mixer section
7//! in protocol extension defined by TCAT for ASICs of DICE.
8use super::{caps_section::*, *};
9
10/// Parameters of saturation in mixer section.
11#[derive(Default, Debug, Clone, PartialEq, Eq)]
12pub struct MixerSaturationParams(pub Vec<bool>);
13
14/// Parameters of coefficients in mixer section.
15#[derive(Default, Debug, Clone, PartialEq, Eq)]
16pub struct MixerCoefficientParams(pub Vec<Vec<u16>>);
17
18const SATURATION_OFFSET: usize = 0x00;
19const COEFF_OFFSET: usize = 0x04;
20
21const MAX_OUTPUT_COUNT: usize = 16;
22const MAX_INPUT_COUNT: usize = 18;
23
24fn calculate_mixer_coefficients_size() -> usize {
25    4 * MAX_OUTPUT_COUNT * MAX_INPUT_COUNT
26}
27
28fn serialize_mixer_coefficients<T: AsRef<[u16]>>(
29    coefs: &[T],
30    caps: &MixerCaps,
31    raw: &mut [u8],
32) -> Result<(), String> {
33    assert!(raw.len() >= calculate_mixer_coefficients_size());
34
35    coefs
36        .iter()
37        .take(caps.output_count as usize)
38        .enumerate()
39        .for_each(|(i, entries)| {
40            entries
41                .as_ref()
42                .iter()
43                .take(caps.input_count as usize)
44                .enumerate()
45                .for_each(|(j, &coef)| {
46                    let pos = 4 * (i * MAX_INPUT_COUNT + j);
47                    serialize_u32(&(coef as u32), &mut raw[pos..(pos + 4)]);
48                });
49        });
50
51    Ok(())
52}
53
54fn deserialize_mixer_coefficients<T: AsMut<[u16]>>(
55    coefs: &mut [T],
56    caps: &MixerCaps,
57    raw: &[u8],
58) -> Result<(), String> {
59    assert!(raw.len() >= calculate_mixer_coefficients_size());
60
61    coefs
62        .iter_mut()
63        .take(caps.output_count as usize)
64        .enumerate()
65        .for_each(|(i, entries)| {
66            entries
67                .as_mut()
68                .iter_mut()
69                .take(caps.input_count as usize)
70                .enumerate()
71                .for_each(|(j, coef)| {
72                    let pos = 4 * (i * MAX_INPUT_COUNT + j);
73                    let mut val = 0u32;
74                    deserialize_u32(&mut val, &raw[pos..(pos + 4)]);
75                    *coef = val as u16
76                });
77        });
78
79    Ok(())
80}
81
82impl<O: TcatExtensionOperation> TcatExtensionSectionParamsOperation<MixerSaturationParams> for O {
83    fn cache_extension_whole_params(
84        req: &FwReq,
85        node: &FwNode,
86        sections: &ExtensionSections,
87        caps: &ExtensionCaps,
88        params: &mut MixerSaturationParams,
89        timeout_ms: u32,
90    ) -> Result<(), Error> {
91        if !caps.mixer.is_exposed {
92            Err(Error::new(
93                ProtocolExtensionError::Mixer,
94                "Mixer is not available",
95            ))?
96        }
97
98        let mut raw = [0; 4];
99        Self::read_extension(
100            req,
101            node,
102            &sections.mixer,
103            SATURATION_OFFSET,
104            &mut raw,
105            timeout_ms,
106        )?;
107
108        let mut val = 0u32;
109        deserialize_u32(&mut val, &raw);
110
111        params
112            .0
113            .resize_with(caps.mixer.output_count as usize, Default::default);
114        params
115            .0
116            .iter_mut()
117            .enumerate()
118            .for_each(|(i, saturation)| *saturation = val & (1 << i) > 0);
119
120        Ok(())
121    }
122}
123
124impl<O: TcatExtensionOperation> TcatExtensionSectionParamsOperation<MixerCoefficientParams> for O {
125    fn cache_extension_whole_params(
126        req: &FwReq,
127        node: &FwNode,
128        sections: &ExtensionSections,
129        caps: &ExtensionCaps,
130        params: &mut MixerCoefficientParams,
131        timeout_ms: u32,
132    ) -> Result<(), Error> {
133        if !caps.mixer.is_exposed {
134            Err(Error::new(
135                ProtocolExtensionError::Mixer,
136                "Mixer is not available",
137            ))?
138        }
139
140        let mut raw = vec![0u8; calculate_mixer_coefficients_size()];
141        Self::read_extension(
142            req,
143            node,
144            &sections.mixer,
145            COEFF_OFFSET,
146            &mut raw,
147            timeout_ms,
148        )?;
149
150        params
151            .0
152            .resize_with(caps.mixer.output_count as usize, Default::default);
153        params
154            .0
155            .iter_mut()
156            .for_each(|coefs| coefs.resize_with(caps.mixer.input_count as usize, Default::default));
157        deserialize_mixer_coefficients(&mut params.0, &caps.mixer, &raw)
158            .map_err(|cause| Error::new(ProtocolExtensionError::Mixer, &cause))
159    }
160}
161
162impl<O: TcatExtensionOperation>
163    TcatExtensionSectionPartialMutableParamsOperation<MixerCoefficientParams> for O
164{
165    fn update_extension_partial_params(
166        req: &FwReq,
167        node: &FwNode,
168        sections: &ExtensionSections,
169        caps: &ExtensionCaps,
170        params: &MixerCoefficientParams,
171        prev: &mut MixerCoefficientParams,
172        timeout_ms: u32,
173    ) -> Result<(), Error> {
174        let mut new = vec![0u8; calculate_mixer_coefficients_size()];
175        serialize_mixer_coefficients(&params.0, &caps.mixer, &mut new)
176            .map_err(|cause| Error::new(ProtocolExtensionError::Mixer, &cause))?;
177
178        let mut old = vec![0u8; calculate_mixer_coefficients_size()];
179        serialize_mixer_coefficients(&prev.0, &caps.mixer, &mut old)
180            .map_err(|cause| Error::new(ProtocolExtensionError::Mixer, &cause))?;
181
182        (0..calculate_mixer_coefficients_size())
183            .step_by(4)
184            .try_for_each(|pos| {
185                if new[pos..(pos + 4)] != old[pos..(pos + 4)] {
186                    Self::write_extension(
187                        req,
188                        node,
189                        &sections.mixer,
190                        COEFF_OFFSET + pos,
191                        &mut new[pos..(pos + 4)],
192                        timeout_ms,
193                    )
194                } else {
195                    Ok(())
196                }
197            })?;
198
199        deserialize_mixer_coefficients(&mut prev.0, &caps.mixer, &new)
200            .map_err(|cause| Error::new(ProtocolExtensionError::Mixer, &cause))
201    }
202}