firewire_fireworks_protocols/
phys_output.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocol about physical output.
5//!
6//! The module includes protocol about physical output defined by Echo Audio Digital Corporation for
7//! Fireworks board module.
8
9use super::*;
10
11const CATEGORY_PHYS_OUTPUT: u32 = 4;
12
13const CMD_SET_VOL: u32 = 0;
14const CMD_GET_VOL: u32 = 1;
15const CMD_SET_MUTE: u32 = 2;
16const CMD_GET_MUTE: u32 = 3;
17const CMD_SET_NOMINAL: u32 = 8;
18const CMD_GET_NOMINAL: u32 = 9;
19
20/// The parameters of all outputs.
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct EfwOutputParameters {
23    /// The volume of physical output. The value is unsigned fixed-point number of 8.24 format;
24    /// i.e. Q24. It is 0x00000000..0x02000000 for -144.0..+6.0 dB.
25    pub volumes: Vec<i32>,
26    /// Whether to mute the physical output.
27    pub mutes: Vec<bool>,
28}
29
30impl<O, P> EfwWhollyCachableParamsOperation<P, EfwOutputParameters> for O
31where
32    O: EfwHardwareSpecification,
33    P: EfwProtocolExtManual,
34{
35    fn cache_wholly(
36        proto: &mut P,
37        states: &mut EfwOutputParameters,
38        timeout_ms: u32,
39    ) -> Result<(), Error> {
40        assert_eq!(states.volumes.len(), Self::phys_output_count());
41        assert_eq!(states.mutes.len(), Self::phys_output_count());
42
43        states
44            .volumes
45            .iter_mut()
46            .enumerate()
47            .try_for_each(|(ch, volume)| {
48                let args = [ch as u32, 0];
49                let mut params = vec![0; 2];
50                proto
51                    .transaction(
52                        CATEGORY_PHYS_OUTPUT,
53                        CMD_GET_VOL,
54                        &args,
55                        &mut params,
56                        timeout_ms,
57                    )
58                    .map(|_| *volume = params[1] as i32)
59            })?;
60
61        states
62            .mutes
63            .iter_mut()
64            .enumerate()
65            .try_for_each(|(ch, mute)| {
66                let args = [ch as u32, 0];
67                let mut params = vec![0; 2];
68                proto
69                    .transaction(
70                        CATEGORY_PHYS_OUTPUT,
71                        CMD_GET_MUTE,
72                        &args,
73                        &mut params,
74                        timeout_ms,
75                    )
76                    .map(|_| *mute = params[1] > 0)
77            })
78    }
79}
80
81impl<O, P> EfwPartiallyUpdatableParamsOperation<P, EfwOutputParameters> for O
82where
83    O: EfwHardwareSpecification,
84    P: EfwProtocolExtManual,
85{
86    fn update_partially(
87        proto: &mut P,
88        states: &mut EfwOutputParameters,
89        updates: EfwOutputParameters,
90        timeout_ms: u32,
91    ) -> Result<(), Error> {
92        assert_eq!(states.volumes.len(), Self::phys_output_count());
93        assert_eq!(states.mutes.len(), Self::phys_output_count());
94
95        states
96            .volumes
97            .iter_mut()
98            .zip(updates.volumes.iter())
99            .enumerate()
100            .filter(|(_, (o, n))| !o.eq(n))
101            .try_for_each(|(ch, (curr, &vol))| {
102                let args = [ch as u32, vol as u32];
103                let mut params = vec![0; 2];
104                proto
105                    .transaction(
106                        CATEGORY_PHYS_OUTPUT,
107                        CMD_SET_VOL,
108                        &args,
109                        &mut params,
110                        timeout_ms,
111                    )
112                    .map(|_| *curr = vol)
113            })?;
114
115        states
116            .mutes
117            .iter_mut()
118            .zip(updates.mutes.iter())
119            .enumerate()
120            .filter(|(_, (o, n))| !o.eq(n))
121            .try_for_each(|(ch, (curr, &mute))| {
122                let args = [ch as u32, mute as u32];
123                let mut params = vec![0; 2];
124                proto
125                    .transaction(
126                        CATEGORY_PHYS_OUTPUT,
127                        CMD_SET_MUTE,
128                        &args,
129                        &mut params,
130                        timeout_ms,
131                    )
132                    .map(|_| *curr = mute)
133            })
134    }
135}
136
137/// The parameters of physical outputs.
138#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct EfwPhysOutputParameters {
140    /// The nominal signal level of physical output.
141    pub nominals: Vec<NominalSignalLevel>,
142}
143
144/// The specification of physical output.
145pub trait EfwPhysOutputSpecification: EfwHardwareSpecification {
146    fn phys_analog_output_count() -> usize {
147        Self::PHYS_INPUT_GROUPS
148            .iter()
149            .filter(|(group_type, _)| PhysGroupType::Analog.eq(group_type))
150            .fold(0, |total, (_, count)| total + count)
151    }
152
153    fn create_phys_output_parameters() -> EfwPhysOutputParameters {
154        EfwPhysOutputParameters {
155            nominals: vec![Default::default(); Self::phys_analog_output_count()],
156        }
157    }
158}
159
160impl<O, P> EfwWhollyCachableParamsOperation<P, EfwPhysOutputParameters> for O
161where
162    O: EfwPhysOutputSpecification,
163    P: EfwProtocolExtManual,
164{
165    fn cache_wholly(
166        proto: &mut P,
167        states: &mut EfwPhysOutputParameters,
168        timeout_ms: u32,
169    ) -> Result<(), Error> {
170        assert_eq!(states.nominals.len(), Self::phys_analog_output_count());
171
172        states
173            .nominals
174            .iter_mut()
175            .enumerate()
176            .try_for_each(|(ch, level)| {
177                let args = [ch as u32, 0];
178                let mut params = vec![0; 2];
179                proto
180                    .transaction(
181                        CATEGORY_PHYS_OUTPUT,
182                        CMD_GET_NOMINAL,
183                        &args,
184                        &mut params,
185                        timeout_ms,
186                    )
187                    .map(|_| deserialize_nominal_signal_level(level, params[1]))
188            })
189    }
190}
191
192impl<O, P> EfwPartiallyUpdatableParamsOperation<P, EfwPhysOutputParameters> for O
193where
194    O: EfwPhysOutputSpecification,
195    P: EfwProtocolExtManual,
196{
197    fn update_partially(
198        proto: &mut P,
199        states: &mut EfwPhysOutputParameters,
200        updates: EfwPhysOutputParameters,
201        timeout_ms: u32,
202    ) -> Result<(), Error> {
203        assert_eq!(states.nominals.len(), Self::phys_analog_output_count());
204        assert_eq!(updates.nominals.len(), Self::phys_analog_output_count());
205
206        states
207            .nominals
208            .iter_mut()
209            .zip(updates.nominals.iter())
210            .enumerate()
211            .filter(|(_, (o, n))| !o.eq(n))
212            .try_for_each(|(ch, (curr, &level))| {
213                let args = [ch as u32, serialize_nominal_signal_level(&level)];
214                let mut params = vec![0; 2];
215                proto
216                    .transaction(
217                        CATEGORY_PHYS_OUTPUT,
218                        CMD_SET_NOMINAL,
219                        &args,
220                        &mut params,
221                        timeout_ms,
222                    )
223                    .map(|_| *curr = level)
224            })
225    }
226}