firewire_fireface_protocols/latter/
ff802.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocol defined by RME GmbH for Fireface 802.
5
6use super::*;
7
8/// Unique protocol for 802.
9#[derive(Default, Debug)]
10pub struct Ff802Protocol;
11
12// For configuration register (0x'ffff'0000'0014).
13const CFG_CLK_SRC_MASK: u32 = 0x00001c00;
14const CFG_CLK_SRC_ADAT_B_FLAG: u32 = 0x00001000;
15const CFG_CLK_SRC_ADAT_A_FLAG: u32 = 0x00000c00;
16const CFG_CLK_SRC_AESEBU_FLAG: u32 = 0x00000800;
17const CFG_CLK_SRC_WORD_CLK_FLAG: u32 = 0x00000400;
18const CFG_CLK_SRC_INTERNAL_FLAG: u32 = 0x00000000;
19const CFG_AESEBU_INPUT_FROM_OPT_IFACE_MASK: u32 = 0x00000200;
20const CFG_AESEBU_OUTPUT_TO_OPT_IFACE_MASK: u32 = 0x00000100;
21const CFG_DSP_EFFECT_ON_INPUT_MASK: u32 = 0x00000040;
22const CFG_AESEBU_OUT_PRO_MASK: u32 = 0x00000020;
23const CFG_WORD_OUT_SINGLE_MASK: u32 = 0x00000010;
24
25/// Signal source of sampling clock.
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum Ff802ClkSrc {
28    Internal,
29    AdatA,
30    AdatB,
31    AesEbu,
32    WordClk,
33}
34
35impl Default for Ff802ClkSrc {
36    fn default() -> Self {
37        Self::Internal
38    }
39}
40
41fn serialize_clock_source(src: &Ff802ClkSrc, quad: &mut u32) {
42    *quad &= !CFG_CLK_SRC_MASK;
43    *quad |= match src {
44        Ff802ClkSrc::AdatB => CFG_CLK_SRC_ADAT_B_FLAG,
45        Ff802ClkSrc::AdatA => CFG_CLK_SRC_ADAT_A_FLAG,
46        Ff802ClkSrc::AesEbu => CFG_CLK_SRC_AESEBU_FLAG,
47        Ff802ClkSrc::WordClk => CFG_CLK_SRC_WORD_CLK_FLAG,
48        Ff802ClkSrc::Internal => CFG_CLK_SRC_INTERNAL_FLAG,
49    };
50}
51
52fn deserialize_clock_source(src: &mut Ff802ClkSrc, quad: &u32) {
53    *src = match *quad & CFG_CLK_SRC_MASK {
54        CFG_CLK_SRC_ADAT_B_FLAG => Ff802ClkSrc::AdatB,
55        CFG_CLK_SRC_ADAT_A_FLAG => Ff802ClkSrc::AdatA,
56        CFG_CLK_SRC_AESEBU_FLAG => Ff802ClkSrc::AesEbu,
57        CFG_CLK_SRC_WORD_CLK_FLAG => Ff802ClkSrc::WordClk,
58        CFG_CLK_SRC_INTERNAL_FLAG => Ff802ClkSrc::Internal,
59        _ => unreachable!(),
60    };
61}
62
63/// Digital interface of S/PDIF signal for 802.
64#[derive(Debug, Copy, Clone, PartialEq, Eq)]
65pub enum Ff802SpdifIface {
66    Xlr,
67    Optical,
68}
69
70impl Default for Ff802SpdifIface {
71    fn default() -> Self {
72        Self::Xlr
73    }
74}
75
76/// Unique protocol for 802.
77#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
78pub struct Ff802Config {
79    /// The low offset of destination address for MIDI messages.
80    midi_tx_low_offset: FfLatterMidiTxLowOffset,
81    /// The source of sampling clock.
82    pub clk_src: Ff802ClkSrc,
83    /// The input interface of S/PDIF signal.
84    pub spdif_in_iface: Ff802SpdifIface,
85    /// The type of signal to optical output interface.
86    pub opt_out_signal: OpticalOutputSignal,
87    /// Whether to enable DSP effect on inputs.
88    pub effect_on_inputs: bool,
89    /// For signal format of S/PDIF output.
90    pub spdif_out_format: SpdifFormat,
91    /// Whether to fix speed to single even if at double/quadruple rate.
92    pub word_out_single: bool,
93}
94
95impl RmeFfOffsetParamsSerialize<Ff802Config> for Ff802Protocol {
96    fn serialize_offsets(state: &Ff802Config) -> Vec<u8> {
97        let mut quad = 0;
98
99        serialize_midi_tx_low_offset(&state.midi_tx_low_offset, &mut quad);
100        serialize_clock_source(&state.clk_src, &mut quad);
101
102        quad &= !CFG_AESEBU_INPUT_FROM_OPT_IFACE_MASK;
103        if state.spdif_in_iface == Ff802SpdifIface::Optical {
104            quad |= CFG_AESEBU_INPUT_FROM_OPT_IFACE_MASK;
105        }
106
107        quad &= !CFG_AESEBU_OUTPUT_TO_OPT_IFACE_MASK;
108        if state.opt_out_signal == OpticalOutputSignal::Spdif {
109            quad |= CFG_AESEBU_OUTPUT_TO_OPT_IFACE_MASK;
110        }
111
112        quad &= !CFG_DSP_EFFECT_ON_INPUT_MASK;
113        if state.effect_on_inputs {
114            quad |= CFG_DSP_EFFECT_ON_INPUT_MASK;
115        }
116
117        quad &= !CFG_AESEBU_OUT_PRO_MASK;
118        if state.spdif_out_format == SpdifFormat::Professional {
119            quad |= CFG_AESEBU_OUT_PRO_MASK;
120        }
121
122        quad &= !CFG_WORD_OUT_SINGLE_MASK;
123        if state.word_out_single {
124            quad |= CFG_WORD_OUT_SINGLE_MASK;
125        }
126
127        quad.to_le_bytes().to_vec()
128    }
129}
130
131impl RmeFfOffsetParamsDeserialize<Ff802Config> for Ff802Protocol {
132    fn deserialize_offsets(state: &mut Ff802Config, raw: &[u8]) {
133        assert!(raw.len() >= LATTER_CONFIG_SIZE);
134
135        let mut r = [0; 4];
136        r.copy_from_slice(&raw[..4]);
137        let quad = u32::from_le_bytes(r);
138
139        deserialize_midi_tx_low_offset(&mut state.midi_tx_low_offset, &quad);
140        deserialize_clock_source(&mut state.clk_src, &quad);
141
142        state.spdif_in_iface = if quad & CFG_AESEBU_INPUT_FROM_OPT_IFACE_MASK > 0 {
143            Ff802SpdifIface::Optical
144        } else {
145            Ff802SpdifIface::Xlr
146        };
147
148        state.opt_out_signal = if quad & CFG_AESEBU_OUTPUT_TO_OPT_IFACE_MASK > 0 {
149            OpticalOutputSignal::Spdif
150        } else {
151            OpticalOutputSignal::Adat
152        };
153
154        state.effect_on_inputs = quad & CFG_DSP_EFFECT_ON_INPUT_MASK > 0;
155        state.spdif_out_format = if quad & CFG_AESEBU_OUT_PRO_MASK > 0 {
156            SpdifFormat::Professional
157        } else {
158            SpdifFormat::Consumer
159        };
160        state.word_out_single = quad & CFG_WORD_OUT_SINGLE_MASK > 0;
161    }
162}
163
164impl RmeFfWhollyUpdatableParamsOperation<Ff802Config> for Ff802Protocol {
165    fn update_wholly(
166        req: &mut FwReq,
167        node: &mut FwNode,
168        params: &Ff802Config,
169        timeout_ms: u32,
170    ) -> Result<(), Error> {
171        write_config::<Ff802Protocol, Ff802Config>(req, node, params, timeout_ms)
172    }
173}
174// For status register (0x'ffff'0000'001c).
175const STATUS_ACTIVE_CLK_RATE_MASK: u32 = 0xf0000000;
176const STATUS_ADAT_B_RATE_MASK: u32 = 0x0f000000;
177const STATUS_ADAT_A_RATE_MASK: u32 = 0x00f00000;
178const STATUS_SPDIF_RATE_MASK: u32 = 0x000f0000;
179const STATUS_WORD_CLK_RATE_MASK: u32 = 0x0000f000;
180const STATUS_ACTIVE_CLK_SRC_MASK: u32 = 0x00000e00;
181const STATUS_ACTIVE_CLK_SRC_INTERNAL_FLAG: u32 = 0x00000e00;
182const STATUS_ACTIVE_CLK_SRC_ADAT_A_FLAG: u32 = 0x00000800;
183const STATUS_ACTIVE_CLK_SRC_ADAT_B_FLAG: u32 = 0x00000600;
184const STATUS_ACTIVE_CLK_SRC_AESEBU_FLAG: u32 = 0x00000400;
185const STATUS_ACTIVE_CLK_SRC_WORD_CLK_FLAG: u32 = 0x00000200;
186const STATUS_SYNC_MASK: u32 = 0x000000f0;
187const STATUS_SYNC_ADAT_B_MASK: u32 = 0x00000080;
188const STATUS_SYNC_ADAT_A_MASK: u32 = 0x00000040;
189const STATUS_SYNC_SPDIF_MASK: u32 = 0x00000020;
190const STATUS_SYNC_WORD_CLK_MASK: u32 = 0x00000010;
191const STATUS_LOCK_MASK: u32 = 0x0000000f;
192const STATUS_LOCK_ADAT_B_MASK: u32 = 0x00000008;
193const STATUS_LOCK_ADAT_A_MASK: u32 = 0x00000004;
194const STATUS_LOCK_SPDIF_MASK: u32 = 0x00000002;
195const STATUS_LOCK_WORD_CLK_MASK: u32 = 0x00000001;
196
197/// Lock status of 802.
198#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
199pub struct Ff802ExtLockStatus {
200    pub word_clk: bool,
201    pub spdif: bool,
202    pub adat_b: bool,
203    pub adat_a: bool,
204}
205
206fn serialize_external_lock_status(status: &Ff802ExtLockStatus, quad: &mut u32) {
207    *quad &= !STATUS_LOCK_MASK;
208
209    if status.word_clk {
210        *quad |= STATUS_LOCK_WORD_CLK_MASK;
211    }
212    if status.spdif {
213        *quad |= STATUS_LOCK_SPDIF_MASK;
214    }
215    if status.adat_b {
216        *quad |= STATUS_LOCK_ADAT_B_MASK;
217    }
218    if status.adat_a {
219        *quad |= STATUS_LOCK_ADAT_A_MASK;
220    }
221}
222
223fn deserialize_external_lock_status(status: &mut Ff802ExtLockStatus, quad: &u32) {
224    status.word_clk = *quad & STATUS_LOCK_WORD_CLK_MASK > 0;
225    status.spdif = *quad & STATUS_LOCK_SPDIF_MASK > 0;
226    status.adat_b = *quad & STATUS_LOCK_ADAT_B_MASK > 0;
227    status.adat_a = *quad & STATUS_LOCK_ADAT_A_MASK > 0;
228}
229
230/// Sync status of 802.
231#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
232pub struct Ff802ExtSyncStatus {
233    pub word_clk: bool,
234    pub spdif: bool,
235    pub adat_b: bool,
236    pub adat_a: bool,
237}
238
239fn serialize_external_sync_status(status: &Ff802ExtSyncStatus, quad: &mut u32) {
240    *quad &= !STATUS_SYNC_MASK;
241
242    if status.word_clk {
243        *quad |= STATUS_SYNC_WORD_CLK_MASK;
244    }
245    if status.spdif {
246        *quad |= STATUS_SYNC_SPDIF_MASK;
247    }
248    if status.adat_b {
249        *quad |= STATUS_SYNC_ADAT_B_MASK;
250    }
251    if status.adat_a {
252        *quad |= STATUS_SYNC_ADAT_A_MASK;
253    }
254}
255
256fn deserialize_external_sync_status(status: &mut Ff802ExtSyncStatus, quad: &u32) {
257    status.word_clk = *quad & STATUS_SYNC_WORD_CLK_MASK > 0;
258    status.spdif = *quad & STATUS_SYNC_SPDIF_MASK > 0;
259    status.adat_b = *quad & STATUS_SYNC_ADAT_B_MASK > 0;
260    status.adat_a = *quad & STATUS_SYNC_ADAT_A_MASK > 0;
261}
262
263/// Sync status of 802.
264#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
265pub struct Ff802ExtRateStatus {
266    pub word_clk: Option<ClkNominalRate>,
267    pub spdif: Option<ClkNominalRate>,
268    pub adat_b: Option<ClkNominalRate>,
269    pub adat_a: Option<ClkNominalRate>,
270}
271
272fn serialize_external_rate(
273    rate: &Option<ClkNominalRate>,
274    quad: &mut u32,
275    shift: usize,
276    lock_flag: u32,
277) {
278    serialize_clock_rate_optional(rate, quad, shift);
279
280    // NOTE: The lock flag should stand.
281    if rate.is_some() {
282        *quad |= lock_flag;
283    }
284}
285
286// NOTE: The call of function touches lock flags in the quad argument when detecting corresponding rate.
287fn serialize_external_rate_status(status: &Ff802ExtRateStatus, quad: &mut u32) {
288    *quad &= !(STATUS_WORD_CLK_RATE_MASK
289        | STATUS_SPDIF_RATE_MASK
290        | STATUS_ADAT_A_RATE_MASK
291        | STATUS_ADAT_B_RATE_MASK);
292    serialize_external_rate(&status.word_clk, quad, 12, STATUS_LOCK_WORD_CLK_MASK);
293    serialize_external_rate(&status.spdif, quad, 16, STATUS_LOCK_SPDIF_MASK);
294    serialize_external_rate(&status.adat_a, quad, 20, STATUS_LOCK_ADAT_A_MASK);
295    serialize_external_rate(&status.adat_b, quad, 24, STATUS_LOCK_ADAT_B_MASK);
296}
297
298fn deserialize_external_rate_status(status: &mut Ff802ExtRateStatus, quad: &u32) {
299    if *quad & (STATUS_SYNC_WORD_CLK_MASK | STATUS_LOCK_WORD_CLK_MASK) > 0 {
300        if *quad & (STATUS_SYNC_WORD_CLK_MASK | STATUS_LOCK_WORD_CLK_MASK) > 0 {
301            deserialize_clock_rate_optional(&mut status.word_clk, quad, 12);
302        } else {
303            status.word_clk = None;
304        }
305        if *quad & (STATUS_SYNC_SPDIF_MASK | STATUS_LOCK_SPDIF_MASK) > 0 {
306            deserialize_clock_rate_optional(&mut status.spdif, quad, 16);
307        } else {
308            status.spdif = None;
309        }
310        if *quad & (STATUS_SYNC_ADAT_B_MASK | STATUS_LOCK_ADAT_B_MASK) > 0 {
311            deserialize_clock_rate_optional(&mut status.adat_b, quad, 24);
312        } else {
313            status.adat_b = None;
314        }
315        if *quad & (STATUS_SYNC_ADAT_A_MASK | STATUS_LOCK_ADAT_A_MASK) > 0 {
316            deserialize_clock_rate_optional(&mut status.adat_a, quad, 20);
317        } else {
318            status.adat_a = None;
319        }
320    }
321}
322
323/// Status of 802.
324#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
325pub struct Ff802Status {
326    pub ext_lock: Ff802ExtLockStatus,
327    pub ext_sync: Ff802ExtSyncStatus,
328    pub ext_rate: Ff802ExtRateStatus,
329    pub active_clk_src: Ff802ClkSrc,
330    pub active_clk_rate: ClkNominalRate,
331}
332
333impl RmeFfOffsetParamsSerialize<Ff802Status> for Ff802Protocol {
334    fn serialize_offsets(status: &Ff802Status) -> Vec<u8> {
335        let mut quad = 0;
336
337        serialize_external_lock_status(&status.ext_lock, &mut quad);
338        serialize_external_sync_status(&status.ext_sync, &mut quad);
339        serialize_external_rate_status(&status.ext_rate, &mut quad);
340
341        quad &= !STATUS_ACTIVE_CLK_RATE_MASK;
342        serialize_clock_rate(&status.active_clk_rate, &mut quad, 28);
343
344        quad &= !STATUS_ACTIVE_CLK_SRC_MASK;
345        let val = match status.active_clk_src {
346            Ff802ClkSrc::Internal => STATUS_ACTIVE_CLK_SRC_INTERNAL_FLAG,
347            Ff802ClkSrc::AdatA => STATUS_ACTIVE_CLK_SRC_ADAT_A_FLAG,
348            Ff802ClkSrc::AdatB => STATUS_ACTIVE_CLK_SRC_ADAT_B_FLAG,
349            Ff802ClkSrc::AesEbu => STATUS_ACTIVE_CLK_SRC_AESEBU_FLAG,
350            Ff802ClkSrc::WordClk => STATUS_ACTIVE_CLK_SRC_WORD_CLK_FLAG,
351        };
352        quad |= val;
353
354        quad.to_le_bytes().to_vec()
355    }
356}
357
358impl RmeFfOffsetParamsDeserialize<Ff802Status> for Ff802Protocol {
359    fn deserialize_offsets(status: &mut Ff802Status, raw: &[u8]) {
360        assert!(raw.len() >= LATTER_STATUS_SIZE);
361
362        let mut r = [0; 4];
363        r.copy_from_slice(&raw[..4]);
364        let quad = u32::from_le_bytes(r);
365
366        deserialize_external_lock_status(&mut status.ext_lock, &quad);
367        deserialize_external_sync_status(&mut status.ext_sync, &quad);
368        deserialize_external_rate_status(&mut status.ext_rate, &quad);
369
370        deserialize_clock_rate(&mut status.active_clk_rate, &quad, 28);
371
372        status.active_clk_src = match quad & STATUS_ACTIVE_CLK_SRC_MASK {
373            STATUS_ACTIVE_CLK_SRC_INTERNAL_FLAG => Ff802ClkSrc::Internal,
374            STATUS_ACTIVE_CLK_SRC_ADAT_A_FLAG => Ff802ClkSrc::AdatA,
375            STATUS_ACTIVE_CLK_SRC_ADAT_B_FLAG => Ff802ClkSrc::AdatB,
376            STATUS_ACTIVE_CLK_SRC_AESEBU_FLAG => Ff802ClkSrc::AesEbu,
377            STATUS_ACTIVE_CLK_SRC_WORD_CLK_FLAG => Ff802ClkSrc::WordClk,
378            _ => unreachable!(),
379        };
380    }
381}
382
383impl RmeFfCacheableParamsOperation<Ff802Status> for Ff802Protocol {
384    fn cache_wholly(
385        req: &mut FwReq,
386        node: &mut FwNode,
387        status: &mut Ff802Status,
388        timeout_ms: u32,
389    ) -> Result<(), Error> {
390        read_status::<Ff802Protocol, Ff802Status>(req, node, status, timeout_ms)
391    }
392}
393
394impl RmeFfLatterSpecification for Ff802Protocol {
395    const LINE_INPUT_COUNT: usize = 8;
396    const MIC_INPUT_COUNT: usize = 4;
397    const SPDIF_INPUT_COUNT: usize = 2;
398    const ADAT_INPUT_COUNT: usize = 16;
399    const STREAM_INPUT_COUNT: usize = 30;
400
401    const LINE_OUTPUT_COUNT: usize = 8;
402    const HP_OUTPUT_COUNT: usize = 4;
403    const SPDIF_OUTPUT_COUNT: usize = 2;
404    const ADAT_OUTPUT_COUNT: usize = 16;
405}
406
407#[cfg(test)]
408mod test {
409    use super::*;
410
411    #[test]
412    fn clock_source_serdes() {
413        [
414            Ff802ClkSrc::AdatB,
415            Ff802ClkSrc::AdatA,
416            Ff802ClkSrc::AesEbu,
417            Ff802ClkSrc::WordClk,
418            Ff802ClkSrc::Internal,
419        ]
420        .iter()
421        .for_each(|orig| {
422            let mut quad = 0;
423            serialize_clock_source(&orig, &mut quad);
424            let mut target = Ff802ClkSrc::default();
425            deserialize_clock_source(&mut target, &quad);
426
427            assert_eq!(&target, orig);
428        });
429    }
430
431    #[test]
432    fn config_serdes() {
433        let orig = Ff802Config {
434            midi_tx_low_offset: FfLatterMidiTxLowOffset::A0180,
435            clk_src: Ff802ClkSrc::AesEbu,
436            spdif_in_iface: Ff802SpdifIface::Optical,
437            opt_out_signal: OpticalOutputSignal::Spdif,
438            effect_on_inputs: true,
439            spdif_out_format: SpdifFormat::Professional,
440            word_out_single: true,
441        };
442        let quads = Ff802Protocol::serialize_offsets(&orig);
443        let mut target = Ff802Config::default();
444        Ff802Protocol::deserialize_offsets(&mut target, &quads);
445
446        assert_eq!(target, orig);
447    }
448
449    #[test]
450    fn external_lock_status_serdes() {
451        let orig = Ff802ExtLockStatus {
452            word_clk: true,
453            spdif: true,
454            adat_b: true,
455            adat_a: true,
456        };
457        let mut quad = 0;
458        serialize_external_lock_status(&orig, &mut quad);
459        let mut target = Ff802ExtLockStatus::default();
460        deserialize_external_lock_status(&mut target, &quad);
461
462        assert_eq!(target, orig);
463    }
464
465    #[test]
466    fn external_sync_status_serdes() {
467        let orig = Ff802ExtSyncStatus {
468            word_clk: true,
469            spdif: true,
470            adat_b: true,
471            adat_a: true,
472        };
473        let mut quad = 0;
474        serialize_external_sync_status(&orig, &mut quad);
475        let mut target = Ff802ExtSyncStatus::default();
476        deserialize_external_sync_status(&mut target, &quad);
477
478        assert_eq!(target, orig);
479    }
480
481    #[test]
482    fn external_rate_status_serdes() {
483        let orig = Ff802ExtRateStatus {
484            word_clk: Some(ClkNominalRate::R88200),
485            spdif: Some(ClkNominalRate::R192000),
486            adat_b: Some(ClkNominalRate::R44100),
487            adat_a: None,
488        };
489        let mut quad = 0;
490        serialize_external_rate_status(&orig, &mut quad);
491        let mut target = Ff802ExtRateStatus::default();
492        deserialize_external_rate_status(&mut target, &quad);
493
494        assert_eq!(target, orig);
495    }
496
497    #[test]
498    fn status_serdes() {
499        let orig = Ff802Status {
500            ext_lock: Ff802ExtLockStatus {
501                word_clk: true,
502                spdif: false,
503                adat_b: true,
504                adat_a: false,
505            },
506            ext_sync: Ff802ExtSyncStatus {
507                word_clk: true,
508                spdif: false,
509                adat_b: false,
510                adat_a: false,
511            },
512            ext_rate: Ff802ExtRateStatus {
513                word_clk: Some(ClkNominalRate::R88200),
514                spdif: None,
515                adat_b: Some(ClkNominalRate::R44100),
516                adat_a: None,
517            },
518            active_clk_src: Ff802ClkSrc::AdatA,
519            active_clk_rate: ClkNominalRate::R96000,
520        };
521        let raw = Ff802Protocol::serialize_offsets(&orig);
522        let mut target = Ff802Status::default();
523        Ff802Protocol::deserialize_offsets(&mut target, &raw);
524
525        assert_eq!(target, orig);
526    }
527}