firewire_dice_protocols/tcelectronic/shell/
k8.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! Protocol defined by TC Electronic for Konnekt 8.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for protocol
7//! defined by TC Electronic for Konnekt 8.
8//!
9//! ## Diagram of internal signal flow
10//!
11//! ```text
12//!
13//! XLR input 1 ----or---+
14//! Phone input 1 --+    |
15//!                      +--> analog-input-1/2----------------> stream-output-1/2
16//!                      |     |                       +------> stream-output-3/4
17//! XLR input 2 ----or---+     |                       |
18//! Phone input 2 --+          |                       |
19//!                            |                       |
20//! Phone input 3/4  ------------> analog-input-3/4 ------+
21//!                            |                       |  |
22//! Coaxial input 1/2 ---------|-> digital-input-1/2 --+  |
23//!                            |         |                |
24//!                            v         v                |
25//!                        ++===============++            |
26//!                        ||     6 x 2     ||            |
27//! stream-input-1/2 ----> ||               ||            |
28//!                        ||     mixer     ||            |
29//!                        ++===============++            |
30//!                                 |                     |
31//!                          mixer-output-1/2 ------------+---> analog-output-1/2
32//!
33//! stream-input-3/4 -----------------------------------------> digital-output-1/2
34//! ```
35
36use super::*;
37
38/// Protocol implementation of Konnekt 8.
39#[derive(Default, Debug)]
40pub struct K8Protocol;
41
42impl TcatOperation for K8Protocol {}
43
44impl TcatGlobalSectionSpecification for K8Protocol {}
45
46/// Segment for knob. 0x0000..0x0027 (36 quads).
47pub type K8KnobSegment = TcKonnektSegment<K8Knob>;
48
49/// Segment for configuration. 0x0028..0x0073 (19 quads).
50pub type K8ConfigSegment = TcKonnektSegment<K8Config>;
51
52/// Segment for state of mixer. 0x0074..0x01cf (87 quads).
53pub type K8MixerStateSegment = TcKonnektSegment<K8MixerState>;
54
55/// Segment for mixer meter. 0x105c..0x10b7 (23 quads).
56pub type K8MixerMeterSegment = TcKonnektSegment<K8MixerMeter>;
57
58/// Segment tor state of hardware. 0x100c..0x1027 (7 quads).
59pub type K8HwStateSegment = TcKonnektSegment<K8HwState>;
60
61macro_rules! segment_default {
62    ($p:ty, $t:ty) => {
63        impl Default for TcKonnektSegment<$t> {
64            fn default() -> Self {
65                Self {
66                    data: <$t>::default(),
67                    raw: vec![0; <$p as TcKonnektSegmentSerdes<$t>>::SIZE],
68                }
69            }
70        }
71    };
72}
73
74segment_default!(K8Protocol, K8Knob);
75segment_default!(K8Protocol, K8Config);
76segment_default!(K8Protocol, K8MixerState);
77segment_default!(K8Protocol, K8MixerMeter);
78segment_default!(K8Protocol, K8HwState);
79
80/// State of knob.
81#[derive(Debug, Copy, Clone, PartialEq, Eq)]
82pub struct K8Knob {
83    /// Target of 1st knob.
84    pub knob0_target: ShellKnob0Target,
85    /// Target of 2nd knob.
86    pub knob1_target: ShellKnob1Target,
87}
88
89impl Default for K8Knob {
90    fn default() -> Self {
91        Self {
92            knob0_target: K8Protocol::KNOB0_TARGETS[0],
93            knob1_target: K8Protocol::KNOB1_TARGETS[0],
94        }
95    }
96}
97
98impl ShellKnob0TargetSpecification for K8Protocol {
99    const KNOB0_TARGETS: &'static [ShellKnob0Target] = &[
100        ShellKnob0Target::Analog0,
101        ShellKnob0Target::Analog1,
102        ShellKnob0Target::Spdif0_1,
103        ShellKnob0Target::Configurable,
104    ];
105}
106
107impl ShellKnob1TargetSpecification for K8Protocol {
108    const KNOB1_TARGETS: &'static [ShellKnob1Target] =
109        &[ShellKnob1Target::Stream, ShellKnob1Target::Mixer];
110}
111
112impl TcKonnektSegmentSerdes<K8Knob> for K8Protocol {
113    const NAME: &'static str = "knob";
114    const OFFSET: usize = 0x0004;
115    const SIZE: usize = SHELL_KNOB_SEGMENT_SIZE;
116
117    fn serialize(params: &K8Knob, raw: &mut [u8]) -> Result<(), String> {
118        serialize_knob0_target::<K8Protocol>(&params.knob0_target, &mut raw[..4])?;
119        serialize_knob1_target::<K8Protocol>(&params.knob1_target, &mut raw[4..8])?;
120        Ok(())
121    }
122
123    fn deserialize(params: &mut K8Knob, raw: &[u8]) -> Result<(), String> {
124        deserialize_knob0_target::<K8Protocol>(&mut params.knob0_target, &raw[..4])?;
125        deserialize_knob1_target::<K8Protocol>(&mut params.knob1_target, &raw[4..8])?;
126        Ok(())
127    }
128}
129
130impl TcKonnektMutableSegmentOperation<K8Knob> for K8Protocol {}
131
132impl TcKonnektNotifiedSegmentOperation<K8Knob> for K8Protocol {
133    const NOTIFY_FLAG: u32 = SHELL_KNOB_NOTIFY_FLAG;
134}
135
136impl AsRef<ShellKnob0Target> for K8Knob {
137    fn as_ref(&self) -> &ShellKnob0Target {
138        &self.knob0_target
139    }
140}
141
142impl AsMut<ShellKnob0Target> for K8Knob {
143    fn as_mut(&mut self) -> &mut ShellKnob0Target {
144        &mut self.knob0_target
145    }
146}
147
148impl AsRef<ShellKnob1Target> for K8Knob {
149    fn as_ref(&self) -> &ShellKnob1Target {
150        &self.knob1_target
151    }
152}
153
154impl AsMut<ShellKnob1Target> for K8Knob {
155    fn as_mut(&mut self) -> &mut ShellKnob1Target {
156        &mut self.knob1_target
157    }
158}
159
160/// Configuration.
161#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
162pub struct K8Config {
163    /// Source of coaxial output.
164    pub coax_out_src: ShellCoaxOutPairSrc,
165    /// Source of sampling clock at standalone mode.
166    pub standalone_src: ShellStandaloneClockSource,
167    /// Rate of sampling clock at standalone mode.
168    pub standalone_rate: TcKonnektStandaloneClockRate,
169}
170
171impl ShellStandaloneClockSpecification for K8Protocol {
172    const STANDALONE_CLOCK_SOURCES: &'static [ShellStandaloneClockSource] = &[
173        ShellStandaloneClockSource::Coaxial,
174        ShellStandaloneClockSource::Internal,
175    ];
176}
177
178impl TcKonnektSegmentSerdes<K8Config> for K8Protocol {
179    const NAME: &'static str = "configuration";
180    const OFFSET: usize = 0x0028;
181    const SIZE: usize = 76;
182
183    fn serialize(params: &K8Config, raw: &mut [u8]) -> Result<(), String> {
184        serialize_coax_out_pair_source(&params.coax_out_src, &mut raw[12..16])?;
185        serialize_standalone_clock_source::<K8Protocol>(&params.standalone_src, &mut raw[20..24])?;
186        serialize_standalone_clock_rate(&params.standalone_rate, &mut raw[24..28])?;
187        Ok(())
188    }
189
190    fn deserialize(params: &mut K8Config, raw: &[u8]) -> Result<(), String> {
191        deserialize_coax_out_pair_source(&mut params.coax_out_src, &raw[12..16])?;
192        deserialize_standalone_clock_source::<K8Protocol>(
193            &mut params.standalone_src,
194            &raw[20..24],
195        )?;
196        deserialize_standalone_clock_rate(&mut params.standalone_rate, &raw[24..28])?;
197        Ok(())
198    }
199}
200
201impl TcKonnektMutableSegmentOperation<K8Config> for K8Protocol {}
202
203impl TcKonnektNotifiedSegmentOperation<K8Config> for K8Protocol {
204    const NOTIFY_FLAG: u32 = SHELL_CONFIG_NOTIFY_FLAG;
205}
206
207impl AsRef<ShellCoaxOutPairSrc> for K8Config {
208    fn as_ref(&self) -> &ShellCoaxOutPairSrc {
209        &self.coax_out_src
210    }
211}
212
213impl AsMut<ShellCoaxOutPairSrc> for K8Config {
214    fn as_mut(&mut self) -> &mut ShellCoaxOutPairSrc {
215        &mut self.coax_out_src
216    }
217}
218
219impl AsRef<ShellStandaloneClockSource> for K8Config {
220    fn as_ref(&self) -> &ShellStandaloneClockSource {
221        &self.standalone_src
222    }
223}
224
225impl AsMut<ShellStandaloneClockSource> for K8Config {
226    fn as_mut(&mut self) -> &mut ShellStandaloneClockSource {
227        &mut self.standalone_src
228    }
229}
230
231impl AsRef<TcKonnektStandaloneClockRate> for K8Config {
232    fn as_ref(&self) -> &TcKonnektStandaloneClockRate {
233        &self.standalone_rate
234    }
235}
236
237impl AsMut<TcKonnektStandaloneClockRate> for K8Config {
238    fn as_mut(&mut self) -> &mut TcKonnektStandaloneClockRate {
239        &mut self.standalone_rate
240    }
241}
242
243/// State of mixer.
244#[derive(Debug, Clone, PartialEq, Eq)]
245pub struct K8MixerState {
246    /// The common structure for state of mixer.
247    pub mixer: ShellMixerState,
248    /// Whether to use mixer function.
249    pub enabled: bool,
250}
251
252impl Default for K8MixerState {
253    fn default() -> Self {
254        K8MixerState {
255            mixer: K8Protocol::create_mixer_state(),
256            enabled: Default::default(),
257        }
258    }
259}
260
261impl ShellMixerStateSpecification for K8Protocol {
262    const MONITOR_SRC_MAP: [Option<ShellMixerMonitorSrcType>; SHELL_MIXER_MONITOR_SRC_COUNT] = [
263        Some(ShellMixerMonitorSrcType::Stream),
264        None,
265        None,
266        None,
267        Some(ShellMixerMonitorSrcType::Analog),
268        None,
269        None,
270        None,
271        None,
272        Some(ShellMixerMonitorSrcType::Spdif),
273    ];
274}
275
276impl TcKonnektSegmentSerdes<K8MixerState> for K8Protocol {
277    const NAME: &'static str = "mixer-state";
278    const OFFSET: usize = 0x0074;
279    const SIZE: usize = ShellMixerState::SIZE + 32;
280
281    fn serialize(params: &K8MixerState, raw: &mut [u8]) -> Result<(), String> {
282        serialize_mixer_state::<K8Protocol>(&params.mixer, raw)?;
283        serialize_bool(&params.enabled, &mut raw[340..344]);
284        Ok(())
285    }
286
287    fn deserialize(params: &mut K8MixerState, raw: &[u8]) -> Result<(), String> {
288        deserialize_mixer_state::<K8Protocol>(&mut params.mixer, raw)?;
289        deserialize_bool(&mut params.enabled, &raw[340..344]);
290        Ok(())
291    }
292}
293
294impl TcKonnektMutableSegmentOperation<K8MixerState> for K8Protocol {}
295
296impl TcKonnektNotifiedSegmentOperation<K8MixerState> for K8Protocol {
297    const NOTIFY_FLAG: u32 = SHELL_MIXER_NOTIFY_FLAG;
298}
299
300impl AsRef<ShellMixerState> for K8MixerState {
301    fn as_ref(&self) -> &ShellMixerState {
302        &self.mixer
303    }
304}
305
306impl AsMut<ShellMixerState> for K8MixerState {
307    fn as_mut(&mut self) -> &mut ShellMixerState {
308        &mut self.mixer
309    }
310}
311
312/// General state of hardware.
313#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
314pub struct K8HwState {
315    /// Common state of hardware.
316    pub hw_state: ShellHwState,
317    /// Whether to enable aux input or not.
318    pub aux_input_enabled: bool,
319}
320
321impl TcKonnektSegmentSerdes<K8HwState> for K8Protocol {
322    const NAME: &'static str = "hardware-state";
323    const OFFSET: usize = 0x100c;
324    const SIZE: usize = ShellHwState::SIZE;
325
326    fn serialize(params: &K8HwState, raw: &mut [u8]) -> Result<(), String> {
327        serialize_hw_state(&params.hw_state, raw)?;
328        serialize_bool(&params.aux_input_enabled, &mut raw[8..12]);
329        Ok(())
330    }
331
332    fn deserialize(params: &mut K8HwState, raw: &[u8]) -> Result<(), String> {
333        deserialize_hw_state(&mut params.hw_state, raw)?;
334        deserialize_bool(&mut params.aux_input_enabled, &raw[8..12]);
335        Ok(())
336    }
337}
338
339impl TcKonnektMutableSegmentOperation<K8HwState> for K8Protocol {}
340
341impl TcKonnektNotifiedSegmentOperation<K8HwState> for K8Protocol {
342    const NOTIFY_FLAG: u32 = SHELL_HW_STATE_NOTIFY_FLAG;
343}
344
345impl AsRef<ShellHwState> for K8HwState {
346    fn as_ref(&self) -> &ShellHwState {
347        &self.hw_state
348    }
349}
350
351impl AsMut<ShellHwState> for K8HwState {
352    fn as_mut(&mut self) -> &mut ShellHwState {
353        &mut self.hw_state
354    }
355}
356
357impl AsRef<FireWireLedState> for K8HwState {
358    fn as_ref(&self) -> &FireWireLedState {
359        &self.hw_state.firewire_led
360    }
361}
362
363impl AsMut<FireWireLedState> for K8HwState {
364    fn as_mut(&mut self) -> &mut FireWireLedState {
365        &mut self.hw_state.firewire_led
366    }
367}
368
369const K8_METER_ANALOG_INPUT_COUNT: usize = 2;
370const K8_METER_DIGITAL_INPUT_COUNT: usize = 2;
371
372/// Hardware metering.
373#[derive(Debug, Clone, PartialEq, Eq)]
374pub struct K8MixerMeter(pub ShellMixerMeter);
375
376impl Default for K8MixerMeter {
377    fn default() -> Self {
378        K8MixerMeter(K8Protocol::create_meter_state())
379    }
380}
381
382impl ShellMixerMeterSpecification for K8Protocol {
383    const ANALOG_INPUT_COUNT: usize = K8_METER_ANALOG_INPUT_COUNT;
384    const DIGITAL_INPUT_COUNT: usize = K8_METER_DIGITAL_INPUT_COUNT;
385}
386
387impl TcKonnektSegmentSerdes<K8MixerMeter> for K8Protocol {
388    const NAME: &'static str = "mixer-meter";
389    const OFFSET: usize = 0x100c;
390    const SIZE: usize = ShellMixerMeter::SIZE;
391
392    fn serialize(params: &K8MixerMeter, raw: &mut [u8]) -> Result<(), String> {
393        serialize_mixer_meter::<K8Protocol>(&params.0, raw)
394    }
395
396    fn deserialize(params: &mut K8MixerMeter, raw: &[u8]) -> Result<(), String> {
397        deserialize_mixer_meter::<K8Protocol>(&mut params.0, raw)
398    }
399}
400
401impl AsRef<ShellMixerMeter> for K8MixerMeter {
402    fn as_ref(&self) -> &ShellMixerMeter {
403        &self.0
404    }
405}
406
407impl AsMut<ShellMixerMeter> for K8MixerMeter {
408    fn as_mut(&mut self) -> &mut ShellMixerMeter {
409        &mut self.0
410    }
411}