firewire_fireworks_protocols/
hw_ctl.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocol about hardware control.
5//!
6//! The module includes protocol about hardware control defined by Echo Audio Digital Corporation
7//! for Fireworks board module.
8
9use super::*;
10
11const CATEGORY_HWCTL: u32 = 3;
12
13const CMD_SET_CLOCK: u32 = 0;
14const CMD_GET_CLOCK: u32 = 1;
15const CMD_SET_FLAGS: u32 = 3;
16const CMD_GET_FLAGS: u32 = 4;
17const CMD_BLINK_LED: u32 = 5;
18const CMD_RECONNECT: u32 = 6;
19
20/// The parameters of sampling clock configuration.
21#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
22pub struct EfwSamplingClockParameters {
23    /// The frequency.
24    pub rate: u32,
25    /// The source.
26    pub source: ClkSrc,
27}
28
29impl<O, P> EfwWhollyCachableParamsOperation<P, EfwSamplingClockParameters> for O
30where
31    O: EfwHardwareSpecification,
32    P: EfwProtocolExtManual,
33{
34    fn cache_wholly(
35        proto: &mut P,
36        states: &mut EfwSamplingClockParameters,
37        timeout_ms: u32,
38    ) -> Result<(), Error> {
39        let args = Vec::new();
40        let mut params = vec![0; 3];
41        proto
42            .transaction(
43                CATEGORY_HWCTL,
44                CMD_GET_CLOCK,
45                &args,
46                &mut params,
47                timeout_ms,
48            )
49            .map(|_| {
50                deserialize_clock_source(&mut states.source, params[0]);
51                states.rate = params[1];
52            })
53    }
54}
55
56impl<O, P> EfwWhollyUpdatableParamsOperation<P, EfwSamplingClockParameters> for O
57where
58    O: EfwHardwareSpecification,
59    P: EfwProtocolExtManual,
60{
61    fn update_wholly(
62        proto: &mut P,
63        states: &EfwSamplingClockParameters,
64        timeout_ms: u32,
65    ) -> Result<(), Error> {
66        let args = [serialize_clock_source(&states.source), states.rate, 0];
67        let mut params = vec![0; 3];
68        proto.transaction(
69            CATEGORY_HWCTL,
70            CMD_SET_CLOCK,
71            &args,
72            &mut params,
73            timeout_ms,
74        )
75    }
76}
77
78/// The type of hardware control.
79#[derive(Debug, Copy, Clone, PartialEq, Eq)]
80pub enum HwCtlFlag {
81    /// Whether multiplexer is enabled or not for audio signal.
82    MixerEnabled,
83    /// Whether channel status block of IEC 60958-1 is for professional use or not.
84    SpdifPro,
85    /// Whether main data field of IEC 60958-1 is not for linear PCM samples.
86    SpdifNoneAudio,
87    /// Whether control room B is selected or not.
88    CtlRoomSelect,
89    /// Whether physical knob is bypass to adjust any output.
90    OutputLevelBypass,
91    /// The mode of metering for input in surface.
92    MeterInMode,
93    /// The mode of metering for output in surface.
94    MeterOutMode,
95    /// Whether to enable soft clip.
96    SoftClip,
97    /// The hex mode of robot guitar.
98    GuitarHexInput,
99    /// Whether to enable automatic charging or not.
100    GuitarAutoCharging,
101    /// Whether to enable phantom powering or not.
102    PhantomPowering,
103    Reserved(usize),
104}
105
106impl Default for HwCtlFlag {
107    fn default() -> Self {
108        Self::Reserved(usize::MAX)
109    }
110}
111
112fn serialize_hw_ctl_flag(flag: &HwCtlFlag) -> usize {
113    match flag {
114        HwCtlFlag::MixerEnabled => 0,
115        HwCtlFlag::SpdifPro => 1,
116        HwCtlFlag::SpdifNoneAudio => 2,
117        HwCtlFlag::CtlRoomSelect => 8, // B if it stands, else A.
118        HwCtlFlag::OutputLevelBypass => 9,
119        HwCtlFlag::MeterInMode => 12,
120        HwCtlFlag::MeterOutMode => 13,
121        HwCtlFlag::SoftClip => 18,
122        HwCtlFlag::GuitarHexInput => 29,
123        HwCtlFlag::GuitarAutoCharging => 30,
124        HwCtlFlag::PhantomPowering => 31,
125        HwCtlFlag::Reserved(pos) => *pos,
126    }
127}
128
129fn deserialize_hw_ctl_flag(flag: &mut HwCtlFlag, pos: usize) {
130    *flag = match pos {
131        0 => HwCtlFlag::MixerEnabled,
132        1 => HwCtlFlag::SpdifPro,
133        2 => HwCtlFlag::SpdifNoneAudio,
134        8 => HwCtlFlag::CtlRoomSelect,
135        9 => HwCtlFlag::OutputLevelBypass,
136        12 => HwCtlFlag::MeterInMode,
137        13 => HwCtlFlag::MeterOutMode,
138        18 => HwCtlFlag::SoftClip,
139        29 => HwCtlFlag::GuitarHexInput,
140        30 => HwCtlFlag::GuitarAutoCharging,
141        31 => HwCtlFlag::PhantomPowering,
142        _ => HwCtlFlag::Reserved(pos),
143    };
144}
145
146/// The parameter of flags for hardware control;
147#[derive(Default, Debug, Clone, PartialEq, Eq)]
148pub struct EfwHwCtlFlags(pub Vec<HwCtlFlag>);
149
150impl<O, P> EfwWhollyCachableParamsOperation<P, EfwHwCtlFlags> for O
151where
152    O: EfwHardwareSpecification,
153    P: EfwProtocolExtManual,
154{
155    fn cache_wholly(
156        proto: &mut P,
157        states: &mut EfwHwCtlFlags,
158        timeout_ms: u32,
159    ) -> Result<(), Error> {
160        let args = Vec::new();
161        let mut params = vec![0];
162        proto.transaction(
163            CATEGORY_HWCTL,
164            CMD_GET_FLAGS,
165            &args,
166            &mut params,
167            timeout_ms,
168        )?;
169
170        (0..32).filter(|i| params[0] & (1 << i) > 0).for_each(|i| {
171            let mut flag = HwCtlFlag::default();
172            deserialize_hw_ctl_flag(&mut flag, i);
173            if states.0.iter().find(|f| flag.eq(f)).is_none() {
174                states.0.push(flag);
175            }
176        });
177
178        Ok(())
179    }
180}
181
182impl<O, P> EfwPartiallyUpdatableParamsOperation<P, EfwHwCtlFlags> for O
183where
184    O: EfwHardwareSpecification,
185    P: EfwProtocolExtManual,
186{
187    fn update_partially(
188        proto: &mut P,
189        states: &mut EfwHwCtlFlags,
190        updates: EfwHwCtlFlags,
191        timeout_ms: u32,
192    ) -> Result<(), Error> {
193        let mut args = [0; 2];
194        let mut params = Vec::new();
195        // Enable.
196        updates
197            .0
198            .iter()
199            .for_each(|flag| args[0] |= 1 << serialize_hw_ctl_flag(flag));
200        // Disable.
201        states.0.iter().for_each(|flag| {
202            if updates.0.iter().find(|f| flag.eq(f)).is_none() {
203                args[1] = 1 << serialize_hw_ctl_flag(flag);
204            }
205        });
206        proto.transaction(
207            CATEGORY_HWCTL,
208            CMD_SET_FLAGS,
209            &args,
210            &mut params,
211            timeout_ms,
212        )
213    }
214}
215
216/// The parameter to blink LED.
217#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
218pub struct EfwLedBlink;
219
220impl<O, P> EfwWhollyUpdatableParamsOperation<P, EfwLedBlink> for O
221where
222    O: EfwHardwareSpecification,
223    P: EfwProtocolExtManual,
224{
225    fn update_wholly(proto: &mut P, _: &EfwLedBlink, timeout_ms: u32) -> Result<(), Error> {
226        let args = Vec::new();
227        let mut params = Vec::new();
228        proto.transaction(
229            CATEGORY_HWCTL,
230            CMD_BLINK_LED,
231            &args,
232            &mut params,
233            timeout_ms,
234        )
235    }
236}
237
238/// The parameter to disapper from IEEE 1394 bus and back.
239#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
240pub struct EfwReconnectPhy;
241
242impl<O, P> EfwWhollyUpdatableParamsOperation<P, EfwReconnectPhy> for O
243where
244    O: EfwHardwareSpecification,
245    P: EfwProtocolExtManual,
246{
247    fn update_wholly(proto: &mut P, _: &EfwReconnectPhy, timeout_ms: u32) -> Result<(), Error> {
248        let args = Vec::new();
249        let mut params = Vec::new();
250        proto.transaction(
251            CATEGORY_HWCTL,
252            CMD_RECONNECT,
253            &args,
254            &mut params,
255            timeout_ms,
256        )
257    }
258}
259
260#[cfg(test)]
261mod test {
262    use super::*;
263
264    #[test]
265    fn hw_ctl_flag_serdes() {
266        [
267            HwCtlFlag::MixerEnabled,
268            HwCtlFlag::SpdifPro,
269            HwCtlFlag::SpdifNoneAudio,
270            HwCtlFlag::CtlRoomSelect,
271            HwCtlFlag::OutputLevelBypass,
272            HwCtlFlag::MeterInMode,
273            HwCtlFlag::MeterOutMode,
274            HwCtlFlag::SoftClip,
275            HwCtlFlag::GuitarHexInput,
276            HwCtlFlag::GuitarAutoCharging,
277            HwCtlFlag::PhantomPowering,
278            HwCtlFlag::default(),
279        ]
280        .iter()
281        .for_each(|flag| {
282            let val = serialize_hw_ctl_flag(&flag);
283            let mut f = HwCtlFlag::default();
284            deserialize_hw_ctl_flag(&mut f, val);
285            assert_eq!(*flag, f);
286        });
287    }
288}