firewire_motu_protocols/
version_3.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocol used in version 3 devices of MOTU FireWire series.
5//!
6//! The modules includes structure, enumeration, and trait and its implementation for protocol
7//! used in version 3 devices of Mark of the Unicorn FireWire series.
8
9use super::{command_dsp::*, register_dsp::*, *};
10
11/// Signal source of sampling clock.
12#[derive(Debug, Copy, Clone, PartialEq, Eq)]
13pub enum V3ClkSrc {
14    /// Internal.
15    Internal,
16    /// S/PDIF on coaxial interface.
17    SpdifCoax,
18    /// Word clock on BNC interface.
19    WordClk,
20    /// AES/EBU on XLR interface.
21    AesEbuXlr,
22    /// Any signal on optical interface A.
23    SignalOptA,
24    /// Any signal on optical interface B.
25    SignalOptB,
26}
27
28impl Default for V3ClkSrc {
29    fn default() -> Self {
30        Self::Internal
31    }
32}
33
34/// The parameters of media and sampling clock.
35#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
36pub struct Version3ClockParameters {
37    /// The rate of media clock.
38    pub rate: ClkRate,
39    /// The source of sampling clock.
40    pub source: V3ClkSrc,
41}
42
43const CLK_RATE_LABEL: &str = "clock-rate-v3";
44const CLK_RATE_MASK: u32 = 0x0000ff00;
45const CLK_RATE_SHIFT: usize = 8;
46
47const CLK_SRC_LABEL: &str = "clock-source-v3";
48const CLK_SRC_MASK: u32 = 0x000000ff;
49const CLK_SRC_SHIFT: usize = 0;
50
51/// The trait for specification of sampling and media clocks.
52pub trait MotuVersion3ClockSpecification {
53    const CLOCK_RATES: &'static [ClkRate];
54    const CLOCK_RATE_VALS: &'static [u8];
55
56    const CLOCK_SRCS: &'static [V3ClkSrc];
57    const CLOCK_SRC_VALS: &'static [u8];
58}
59
60impl<O> MotuWhollyCacheableParamsOperation<Version3ClockParameters> for O
61where
62    O: MotuVersion3ClockSpecification,
63{
64    fn cache_wholly(
65        req: &mut FwReq,
66        node: &mut FwNode,
67        params: &mut Version3ClockParameters,
68        timeout_ms: u32,
69    ) -> Result<(), Error> {
70        let quad = read_quad(req, node, OFFSET_CLK, timeout_ms)?;
71
72        deserialize_flag(
73            &mut params.rate,
74            &quad,
75            CLK_RATE_MASK,
76            CLK_RATE_SHIFT,
77            Self::CLOCK_RATES,
78            Self::CLOCK_RATE_VALS,
79            CLK_RATE_LABEL,
80        )?;
81
82        deserialize_flag(
83            &mut params.source,
84            &quad,
85            CLK_SRC_MASK,
86            CLK_SRC_SHIFT,
87            Self::CLOCK_SRCS,
88            Self::CLOCK_SRC_VALS,
89            CLK_SRC_LABEL,
90        )?;
91
92        Ok(())
93    }
94}
95
96impl<O> MotuWhollyUpdatableParamsOperation<Version3ClockParameters> for O
97where
98    O: MotuVersion3ClockSpecification,
99{
100    fn update_wholly(
101        req: &mut FwReq,
102        node: &mut FwNode,
103        params: &Version3ClockParameters,
104        timeout_ms: u32,
105    ) -> Result<(), Error> {
106        let mut quad = read_quad(req, node, OFFSET_CLK, timeout_ms)?;
107
108        serialize_flag(
109            &params.rate,
110            &mut quad,
111            CLK_RATE_MASK,
112            CLK_RATE_SHIFT,
113            Self::CLOCK_RATES,
114            Self::CLOCK_RATE_VALS,
115            CLK_RATE_LABEL,
116        )?;
117
118        serialize_flag(
119            &params.source,
120            &mut quad,
121            CLK_SRC_MASK,
122            CLK_SRC_SHIFT,
123            Self::CLOCK_SRCS,
124            Self::CLOCK_SRC_VALS,
125            CLK_SRC_LABEL,
126        )?;
127
128        write_quad(req, node, OFFSET_CLK, quad, timeout_ms)
129    }
130}
131
132/// The parameters of port assignment.
133#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
134pub struct V3PortAssignParameters {
135    /// The main assignment.
136    pub main: TargetPort,
137    /// The mixer return assignment.
138    pub mixer_return: TargetPort,
139}
140
141const PORT_MAIN_LABEL: &str = "main-out-assign-v3";
142const PORT_MAIN_MASK: u32 = 0x000000f0;
143const PORT_MAIN_SHIFT: usize = 4;
144
145const PORT_RETURN_LABEL: &str = "return-assign-v3";
146const PORT_RETURN_MASK: u32 = 0x00000f00;
147const PORT_RETURN_SHIFT: usize = 8;
148
149impl<O> MotuWhollyCacheableParamsOperation<V3PortAssignParameters> for O
150where
151    O: MotuPortAssignSpecification,
152{
153    fn cache_wholly(
154        req: &mut FwReq,
155        node: &mut FwNode,
156        params: &mut V3PortAssignParameters,
157        timeout_ms: u32,
158    ) -> Result<(), Error> {
159        let quad = read_quad(req, node, OFFSET_PORT, timeout_ms)?;
160
161        deserialize_flag(
162            &mut params.main,
163            &quad,
164            PORT_MAIN_MASK,
165            PORT_MAIN_SHIFT,
166            Self::ASSIGN_PORT_TARGETS,
167            Self::ASSIGN_PORT_VALS,
168            PORT_MAIN_LABEL,
169        )?;
170
171        deserialize_flag(
172            &mut params.mixer_return,
173            &quad,
174            PORT_RETURN_MASK,
175            PORT_RETURN_SHIFT,
176            Self::ASSIGN_PORT_TARGETS,
177            Self::ASSIGN_PORT_VALS,
178            PORT_RETURN_LABEL,
179        )
180    }
181}
182
183impl<O> MotuWhollyUpdatableParamsOperation<V3PortAssignParameters> for O
184where
185    O: MotuPortAssignSpecification,
186{
187    fn update_wholly(
188        req: &mut FwReq,
189        node: &mut FwNode,
190        params: &V3PortAssignParameters,
191        timeout_ms: u32,
192    ) -> Result<(), Error> {
193        let mut quad = read_quad(req, node, OFFSET_PORT, timeout_ms)?;
194
195        serialize_flag(
196            &params.main,
197            &mut quad,
198            PORT_MAIN_MASK,
199            PORT_MAIN_SHIFT,
200            Self::ASSIGN_PORT_TARGETS,
201            Self::ASSIGN_PORT_VALS,
202            PORT_MAIN_LABEL,
203        )?;
204
205        serialize_flag(
206            &params.mixer_return,
207            &mut quad,
208            PORT_RETURN_MASK,
209            PORT_RETURN_SHIFT,
210            Self::ASSIGN_PORT_TARGETS,
211            Self::ASSIGN_PORT_VALS,
212            PORT_RETURN_LABEL,
213        )?;
214
215        write_quad(req, node, OFFSET_PORT, quad, timeout_ms)
216    }
217}
218
219/// Mode of optical interface.
220#[derive(Debug, Copy, Clone, PartialEq, Eq)]
221pub enum V3OptIfaceMode {
222    Disabled,
223    Adat,
224    Spdif,
225}
226
227impl Default for V3OptIfaceMode {
228    fn default() -> Self {
229        Self::Disabled
230    }
231}
232
233/// The parameters of optical input and output interfaces.
234#[derive(Debug, Clone, PartialEq, Eq)]
235pub struct V3OpticalIfaceParameters {
236    /// The mode of input interfaces.
237    pub input_modes: Vec<V3OptIfaceMode>,
238    /// The mode of output interfaces.
239    pub output_modes: Vec<V3OptIfaceMode>,
240}
241
242fn get_opt_iface_masks(is_b: bool, is_out: bool) -> (u32, u32) {
243    let mut enabled_mask = 0x00000001;
244    if is_out {
245        enabled_mask <<= 8;
246    }
247    if is_b {
248        enabled_mask <<= 1;
249    }
250
251    let mut no_adat_mask = 0x00010000;
252    if is_out {
253        no_adat_mask <<= 2;
254    }
255    if is_b {
256        no_adat_mask <<= 4;
257    }
258
259    (enabled_mask, no_adat_mask)
260}
261
262const OFFSET_OPT: u32 = 0x0c94;
263
264/// The trait for specification of optical input and output interfaces.
265pub trait MotuVersion3OpticalIfaceSpecification {
266    const OPT_IFACE_COUNT: usize;
267
268    const OPT_IFACE_MODES: &'static [V3OptIfaceMode; 3] = &[
269        V3OptIfaceMode::Disabled,
270        V3OptIfaceMode::Adat,
271        V3OptIfaceMode::Spdif,
272    ];
273
274    /// Instantiate parameters of optical input and output interfaces.
275    fn create_optical_iface_parameters() -> V3OpticalIfaceParameters {
276        V3OpticalIfaceParameters {
277            input_modes: vec![Default::default(); Self::OPT_IFACE_COUNT],
278            output_modes: vec![Default::default(); Self::OPT_IFACE_COUNT],
279        }
280    }
281}
282
283fn serialize_opt_iface_mode(mode: &V3OptIfaceMode, quad: &mut u32, is_b: bool, is_out: bool) {
284    let (enabled_mask, no_adat_mask) = get_opt_iface_masks(is_b, is_out);
285    *quad &= !(enabled_mask | no_adat_mask);
286    match *mode {
287        V3OptIfaceMode::Disabled => {}
288        V3OptIfaceMode::Adat => *quad |= enabled_mask,
289        V3OptIfaceMode::Spdif => *quad |= enabled_mask | no_adat_mask,
290    }
291}
292
293fn deserialize_opt_iface_mode(mode: &mut V3OptIfaceMode, quad: &u32, is_b: bool, is_out: bool) {
294    let (enabled_mask, no_adat_mask) = get_opt_iface_masks(is_b, is_out);
295    *mode = match (*quad & enabled_mask > 0, *quad & no_adat_mask > 0) {
296        (false, false) | (false, true) => V3OptIfaceMode::Disabled,
297        (true, false) => V3OptIfaceMode::Adat,
298        (true, true) => V3OptIfaceMode::Spdif,
299    };
300}
301
302impl<O> MotuWhollyCacheableParamsOperation<V3OpticalIfaceParameters> for O
303where
304    O: MotuVersion3OpticalIfaceSpecification,
305{
306    fn cache_wholly(
307        req: &mut FwReq,
308        node: &mut FwNode,
309        params: &mut V3OpticalIfaceParameters,
310        timeout_ms: u32,
311    ) -> Result<(), Error> {
312        assert_eq!(params.input_modes.len(), Self::OPT_IFACE_COUNT);
313        assert_eq!(params.output_modes.len(), Self::OPT_IFACE_COUNT);
314
315        let quad = read_quad(req, node, OFFSET_OPT, timeout_ms)?;
316        params
317            .input_modes
318            .iter_mut()
319            .enumerate()
320            .for_each(|(i, mode)| deserialize_opt_iface_mode(mode, &quad, i > 0, false));
321        params
322            .output_modes
323            .iter_mut()
324            .enumerate()
325            .for_each(|(i, mode)| deserialize_opt_iface_mode(mode, &quad, i > 0, true));
326        Ok(())
327    }
328}
329
330impl<O> MotuWhollyUpdatableParamsOperation<V3OpticalIfaceParameters> for O
331where
332    O: MotuVersion3OpticalIfaceSpecification,
333{
334    fn update_wholly(
335        req: &mut FwReq,
336        node: &mut FwNode,
337        params: &V3OpticalIfaceParameters,
338        timeout_ms: u32,
339    ) -> Result<(), Error> {
340        let mut quad = read_quad(req, node, OFFSET_OPT, timeout_ms)?;
341
342        params
343            .input_modes
344            .iter()
345            .enumerate()
346            .for_each(|(i, mode)| serialize_opt_iface_mode(mode, &mut quad, i > 0, false));
347
348        params
349            .output_modes
350            .iter()
351            .enumerate()
352            .for_each(|(i, mode)| serialize_opt_iface_mode(mode, &mut quad, i > 0, true));
353
354        write_quad(req, node, OFFSET_OPT, quad, timeout_ms)
355    }
356}
357
358/// The protocol implementation for Audio Express.
359#[derive(Default)]
360pub struct AudioExpressProtocol;
361
362impl MotuPortAssignSpecification for AudioExpressProtocol {
363    const ASSIGN_PORT_TARGETS: &'static [TargetPort] = &[
364        TargetPort::PhonePair,     // = Stream-1/2
365        TargetPort::MainPair,      // = Stream-5/6
366        TargetPort::AnalogPair(0), // = Stream-3/4
367        TargetPort::SpdifPair,     // = Stream-7/8
368                                   // Blank for Stream-9/10
369    ];
370    const ASSIGN_PORT_VALS: &'static [u8] = &[
371        0x01, // = Stream-1/2
372        0x02, // = Stream-5/6
373        0x06, // = Stream-3/4
374        0x07, // = Stream-7/8
375              // Blank for Stream-9/10
376    ];
377}
378
379impl MotuVersion3ClockSpecification for AudioExpressProtocol {
380    const CLOCK_RATES: &'static [ClkRate] = &[
381        ClkRate::R44100,
382        ClkRate::R48000,
383        ClkRate::R88200,
384        ClkRate::R96000,
385    ];
386    const CLOCK_RATE_VALS: &'static [u8] = &[0x00, 0x01, 0x02, 0x03];
387
388    const CLOCK_SRCS: &'static [V3ClkSrc] = &[V3ClkSrc::Internal, V3ClkSrc::SpdifCoax];
389    const CLOCK_SRC_VALS: &'static [u8] = &[0x00, 0x01];
390}
391
392impl MotuRegisterDspSpecification for AudioExpressProtocol {
393    const MIXER_OUTPUT_DESTINATIONS: &'static [TargetPort] = &[];
394}
395
396impl MotuRegisterDspMixerStereoSourceSpecification for AudioExpressProtocol {}
397
398impl MotuRegisterDspStereoInputSpecification for AudioExpressProtocol {
399    const MIC_COUNT: usize = 2;
400}
401
402impl MotuRegisterDspMeterSpecification for AudioExpressProtocol {
403    const INPUT_PORTS: &'static [TargetPort] = &[
404        TargetPort::Analog(0),
405        TargetPort::Analog(1),
406        TargetPort::Analog(2),
407        TargetPort::Analog(3),
408        TargetPort::Analog(0),
409        TargetPort::Analog(1),
410        TargetPort::Analog(2),
411        TargetPort::Analog(3),
412        TargetPort::Spdif(0),
413        TargetPort::Spdif(1),
414    ];
415    const OUTPUT_PORT_PAIRS: &'static [TargetPort] = &[
416        TargetPort::PhonePair,
417        TargetPort::MainPair,
418        TargetPort::AnalogPair(0),
419        TargetPort::SpdifPair,
420    ];
421    const OUTPUT_PORT_PAIR_POS: &'static [[usize; 2]] = &[[0, 1], [2, 3], [10, 11], [12, 13]];
422}
423
424impl AudioExpressProtocol {
425    /// Notification mask for footswitch.
426    pub const NOTIFY_FOOTSWITCH_MASK: u32 = 0x01000000;
427}
428
429/// The protocol implementation for 828mk3 (FireWire only).
430#[derive(Default, Debug)]
431pub struct F828mk3Protocol;
432
433const F828MK3_ASSIGN_PORT_TARGETS: &[TargetPort] = &[
434    TargetPort::MainPair,        // = Stream-10/13
435    TargetPort::AnalogPair(0),   // = Stream-2/3
436    TargetPort::AnalogPair(1),   // = Stream-4/5
437    TargetPort::AnalogPair(2),   // = Stream-6/7
438    TargetPort::AnalogPair(3),   // = Stream-8/9
439    TargetPort::SpdifPair,       // = Stream-12/13
440    TargetPort::PhonePair,       // = Stream-0/1
441    TargetPort::OpticalAPair(0), // = Stream-14/15
442    TargetPort::OpticalAPair(1), // = Stream-16/17
443    TargetPort::OpticalAPair(2), // = Stream-18/19
444    TargetPort::OpticalAPair(3), // = Stream-20/21
445    TargetPort::OpticalBPair(0), // = Stream-22/23
446    TargetPort::OpticalBPair(1), // = Stream-24/25
447    TargetPort::OpticalBPair(2), // = Stream-26/27
448    TargetPort::OpticalBPair(3), // = Stream-28/29
449];
450
451const F828MK3_ASSIGN_PORT_VALS: &[u8] = &[
452    0x00, // = Stream-10/13
453    0x01, // = Stream-2/3
454    0x02, // = Stream-4/5
455    0x03, // = Stream-6/7
456    0x04, // = Stream-8/9
457    0x05, // = Stream-12/13
458    0x06, // = Stream-0/1
459    0x07, // = Stream-14/15
460    0x08, // = Stream-16/17
461    0x09, // = Stream-18/19
462    0x0a, // = Stream-20/21
463    0x0b, // = Stream-22/23
464    0x0c, // = Stream-24/25
465    0x0d, // = Stream-26/27
466    0x0e, // = Stream-28/29
467];
468
469const F828MK3_CLOCK_RATES: &[ClkRate] = &[
470    ClkRate::R44100,
471    ClkRate::R48000,
472    ClkRate::R88200,
473    ClkRate::R96000,
474    ClkRate::R176400,
475    ClkRate::R192000,
476];
477
478const F828MK3_CLOCK_RATE_VALS: &[u8] = &[0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
479
480const F828MK3_CLOCK_SRCS: &[V3ClkSrc] = &[
481    V3ClkSrc::Internal,
482    V3ClkSrc::WordClk,
483    V3ClkSrc::SpdifCoax,
484    V3ClkSrc::SignalOptA,
485    V3ClkSrc::SignalOptB,
486];
487
488const F828MK3_CLOCK_SRC_VALS: &[u8] = &[0x00, 0x01, 0x10, 0x18, 0x19];
489
490const F828MK3_RETURN_ASSIGN_TARGETS: &[TargetPort] = &[
491    TargetPort::MainPair,
492    TargetPort::AnalogPair(0),
493    TargetPort::AnalogPair(1),
494    TargetPort::AnalogPair(2),
495    TargetPort::AnalogPair(3),
496    TargetPort::SpdifPair,
497    TargetPort::PhonePair,
498    TargetPort::OpticalAPair(0),
499    TargetPort::OpticalAPair(1),
500    TargetPort::OpticalAPair(2),
501    TargetPort::OpticalAPair(3),
502    TargetPort::OpticalBPair(0),
503    TargetPort::OpticalBPair(1),
504    TargetPort::OpticalBPair(2),
505    TargetPort::OpticalBPair(3),
506];
507
508const F828MK3_MIXER_SOURCE_PORTS: &[TargetPort] = &[
509    TargetPort::Analog(0), // Mic-0
510    TargetPort::Analog(1), // Mic-1
511    TargetPort::Analog(2),
512    TargetPort::Analog(3),
513    TargetPort::Analog(4),
514    TargetPort::Analog(5),
515    TargetPort::Analog(6),
516    TargetPort::Analog(7),
517    TargetPort::Analog(8),
518    TargetPort::Analog(9),
519    TargetPort::Spdif(0),
520    TargetPort::Spdif(1),
521    TargetPort::OpticalA(0),
522    TargetPort::OpticalA(1),
523    TargetPort::OpticalA(2),
524    TargetPort::OpticalA(3),
525    TargetPort::OpticalA(4),
526    TargetPort::OpticalA(5),
527    TargetPort::OpticalA(6),
528    TargetPort::OpticalA(7),
529    TargetPort::OpticalB(0),
530    TargetPort::OpticalB(1),
531    TargetPort::OpticalB(2),
532    TargetPort::OpticalB(3),
533    TargetPort::OpticalB(4),
534    TargetPort::OpticalB(5),
535    TargetPort::OpticalB(6),
536    TargetPort::OpticalB(7),
537];
538
539const F828MK3_MIXER_OUTPUT_PORTS: &[TargetPort] = &[
540    TargetPort::Disabled,
541    TargetPort::MainPair,
542    TargetPort::AnalogPair(0),
543    TargetPort::AnalogPair(1),
544    TargetPort::AnalogPair(2),
545    TargetPort::AnalogPair(3),
546    TargetPort::SpdifPair,
547    TargetPort::PhonePair,
548    TargetPort::OpticalAPair(0),
549    TargetPort::OpticalAPair(1),
550    TargetPort::OpticalAPair(2),
551    TargetPort::OpticalAPair(3),
552    TargetPort::OpticalBPair(0),
553    TargetPort::OpticalBPair(1),
554    TargetPort::OpticalBPair(2),
555    TargetPort::OpticalBPair(3),
556];
557
558const F828MK3_INPUT_PORTS: &[TargetPort] = &[
559    TargetPort::Analog(0), // Mic-0
560    TargetPort::Analog(1), // Mic-1
561    TargetPort::Analog(2),
562    TargetPort::Analog(3),
563    TargetPort::Analog(4),
564    TargetPort::Analog(5),
565    TargetPort::Analog(6),
566    TargetPort::Analog(7),
567    TargetPort::Analog(8),
568    TargetPort::Analog(9),
569    TargetPort::Spdif(0),
570    TargetPort::Spdif(1),
571    TargetPort::OpticalA(0),
572    TargetPort::OpticalA(1),
573    TargetPort::OpticalA(2),
574    TargetPort::OpticalA(3),
575    TargetPort::OpticalA(4),
576    TargetPort::OpticalA(5),
577    TargetPort::OpticalA(6),
578    TargetPort::OpticalA(7),
579    TargetPort::OpticalB(0),
580    TargetPort::OpticalB(1),
581    TargetPort::OpticalB(2),
582    TargetPort::OpticalB(3),
583    TargetPort::OpticalB(4),
584    TargetPort::OpticalB(5),
585    TargetPort::OpticalB(6),
586    TargetPort::OpticalB(7),
587];
588
589const F828MK3_OUTPUT_PORTS: &[TargetPort] = &[
590    TargetPort::MainPair,
591    TargetPort::AnalogPair(0),
592    TargetPort::AnalogPair(1),
593    TargetPort::AnalogPair(2),
594    TargetPort::AnalogPair(3),
595    TargetPort::SpdifPair,
596    TargetPort::PhonePair,
597    TargetPort::OpticalAPair(0),
598    TargetPort::OpticalAPair(1),
599    TargetPort::OpticalAPair(2),
600    TargetPort::OpticalAPair(3),
601    TargetPort::OpticalBPair(0),
602    TargetPort::OpticalBPair(1),
603    TargetPort::OpticalBPair(2),
604    TargetPort::OpticalBPair(3),
605];
606
607const F828MK3_METER_INPUT_PORTS: &[(TargetPort, usize)] = &[
608    (TargetPort::Analog(0), 2),
609    (TargetPort::Analog(1), 3),
610    (TargetPort::Analog(2), 4),
611    (TargetPort::Analog(3), 5),
612    (TargetPort::Analog(4), 6),
613    (TargetPort::Analog(5), 7),
614    (TargetPort::Analog(6), 8),
615    (TargetPort::Analog(7), 9),
616    (TargetPort::Analog(8), 10),
617    (TargetPort::Analog(9), 11),
618    (TargetPort::Spdif(0), 12),
619    (TargetPort::Spdif(1), 13),
620    (TargetPort::OpticalA(0), 14),
621    (TargetPort::OpticalA(1), 15),
622    (TargetPort::OpticalA(2), 16),
623    (TargetPort::OpticalA(3), 17),
624    (TargetPort::OpticalA(4), 18),
625    (TargetPort::OpticalA(5), 19),
626    (TargetPort::OpticalA(6), 20),
627    (TargetPort::OpticalA(7), 21),
628    (TargetPort::OpticalB(0), 22),
629    (TargetPort::OpticalB(1), 23),
630    (TargetPort::OpticalB(2), 24),
631    (TargetPort::OpticalB(3), 25),
632    (TargetPort::OpticalB(4), 26),
633    (TargetPort::OpticalB(5), 27),
634    (TargetPort::OpticalB(6), 28),
635    (TargetPort::OpticalB(7), 29),
636    (TargetPort::Analog(0), 46),
637    (TargetPort::Analog(1), 47),
638    (TargetPort::Analog(2), 48),
639    (TargetPort::Analog(3), 49),
640    (TargetPort::Analog(4), 50),
641    (TargetPort::Analog(5), 51),
642    (TargetPort::Analog(6), 52),
643    (TargetPort::Analog(7), 53),
644    (TargetPort::Analog(8), 54),
645    (TargetPort::Analog(9), 55),
646    (TargetPort::Spdif(0), 56),
647    (TargetPort::Spdif(1), 57),
648    (TargetPort::OpticalA(0), 58),
649    (TargetPort::OpticalA(1), 59),
650    (TargetPort::OpticalA(2), 60),
651    (TargetPort::OpticalA(3), 61),
652    (TargetPort::OpticalA(4), 62),
653    (TargetPort::OpticalA(5), 63),
654    (TargetPort::OpticalA(6), 64),
655    (TargetPort::OpticalA(7), 65),
656    (TargetPort::OpticalB(0), 66),
657    (TargetPort::OpticalB(1), 67),
658    (TargetPort::OpticalB(2), 68),
659    (TargetPort::OpticalB(3), 69),
660    (TargetPort::OpticalB(4), 70),
661    (TargetPort::OpticalB(5), 71),
662    (TargetPort::OpticalB(6), 72),
663    (TargetPort::OpticalB(7), 73),
664];
665
666const F828MK3_METER_OUTPUT_PORTS: &[(TargetPort, usize)] = &[
667    (TargetPort::Phone(0), 86),
668    (TargetPort::Phone(1), 87),
669    (TargetPort::Analog(0), 76),
670    (TargetPort::Analog(1), 77),
671    (TargetPort::Analog(2), 78),
672    (TargetPort::Analog(3), 79),
673    (TargetPort::Analog(4), 80),
674    (TargetPort::Analog(5), 81),
675    (TargetPort::Analog(6), 82),
676    (TargetPort::Analog(7), 83),
677    (TargetPort::Main(0), 74),
678    (TargetPort::Main(1), 75),
679    (TargetPort::Spdif(0), 84),
680    (TargetPort::Spdif(1), 85),
681    (TargetPort::OpticalA(0), 88),
682    (TargetPort::OpticalA(1), 89),
683    (TargetPort::OpticalA(2), 90),
684    (TargetPort::OpticalA(3), 91),
685    (TargetPort::OpticalA(4), 92),
686    (TargetPort::OpticalA(5), 93),
687    (TargetPort::OpticalA(6), 94),
688    (TargetPort::OpticalA(7), 95),
689    (TargetPort::OpticalB(0), 96),
690    (TargetPort::OpticalB(1), 97),
691    (TargetPort::OpticalB(2), 98),
692    (TargetPort::OpticalB(3), 99),
693    (TargetPort::OpticalB(4), 100),
694    (TargetPort::OpticalB(5), 101),
695    (TargetPort::OpticalB(6), 102),
696    (TargetPort::OpticalB(7), 103),
697];
698
699impl MotuPortAssignSpecification for F828mk3Protocol {
700    const ASSIGN_PORT_TARGETS: &'static [TargetPort] = F828MK3_ASSIGN_PORT_TARGETS;
701    const ASSIGN_PORT_VALS: &'static [u8] = F828MK3_ASSIGN_PORT_VALS;
702}
703
704impl MotuWordClockOutputSpecification for F828mk3Protocol {}
705
706impl MotuClockNameDisplaySpecification for F828mk3Protocol {}
707
708impl MotuVersion3ClockSpecification for F828mk3Protocol {
709    const CLOCK_RATES: &'static [ClkRate] = F828MK3_CLOCK_RATES;
710    const CLOCK_RATE_VALS: &'static [u8] = F828MK3_CLOCK_RATE_VALS;
711
712    const CLOCK_SRCS: &'static [V3ClkSrc] = F828MK3_CLOCK_SRCS;
713    const CLOCK_SRC_VALS: &'static [u8] = F828MK3_CLOCK_SRC_VALS;
714}
715
716impl MotuVersion3OpticalIfaceSpecification for F828mk3Protocol {
717    const OPT_IFACE_COUNT: usize = 2;
718}
719
720impl CommandDspOperation for F828mk3Protocol {}
721
722impl MotuCommandDspReverbSpecification for F828mk3Protocol {}
723
724impl MotuCommandDspMonitorSpecification for F828mk3Protocol {
725    const RETURN_ASSIGN_TARGETS: &'static [TargetPort] = F828MK3_RETURN_ASSIGN_TARGETS;
726}
727
728impl MotuCommandDspMixerSpecification for F828mk3Protocol {
729    const SOURCE_PORTS: &'static [TargetPort] = F828MK3_MIXER_SOURCE_PORTS;
730    const OUTPUT_PORTS: &'static [TargetPort] = F828MK3_MIXER_OUTPUT_PORTS;
731}
732
733impl MotuCommandDspEqualizerSpecification for F828mk3Protocol {}
734
735impl MotuCommandDspDynamicsSpecification for F828mk3Protocol {}
736
737impl MotuCommandDspInputSpecification for F828mk3Protocol {
738    const INPUT_PORTS: &'static [TargetPort] = F828MK3_INPUT_PORTS;
739    const MIC_COUNT: usize = 0;
740    const LINE_INPUT_COUNT: usize = 0;
741}
742
743impl MotuCommandDspOutputSpecification for F828mk3Protocol {
744    const OUTPUT_PORTS: &'static [TargetPort] = F828MK3_OUTPUT_PORTS;
745}
746
747impl MotuCommandDspMeterSpecification for F828mk3Protocol {
748    const INPUT_PORTS: &'static [(TargetPort, usize)] = F828MK3_METER_INPUT_PORTS;
749    const OUTPUT_PORTS: &'static [(TargetPort, usize)] = F828MK3_METER_OUTPUT_PORTS;
750}
751
752impl F828mk3Protocol {
753    /// Notification mask for main assignment, return assignment, and phone assignment. The change
754    /// of phone assignment is also notified in command message.
755    pub const NOTIFY_PORT_CHANGE: u32 = 0x40000000;
756
757    /// Notification mask for footswitch.
758    pub const NOTIFY_FOOTSWITCH_MASK: u32 = 0x01000000;
759}
760
761/// The protocol implementation for 828mk3 Hybrid.
762#[derive(Default, Debug)]
763pub struct F828mk3HybridProtocol;
764
765impl MotuPortAssignSpecification for F828mk3HybridProtocol {
766    const ASSIGN_PORT_TARGETS: &'static [TargetPort] = F828MK3_ASSIGN_PORT_TARGETS;
767    const ASSIGN_PORT_VALS: &'static [u8] = F828MK3_ASSIGN_PORT_VALS;
768}
769
770impl MotuWordClockOutputSpecification for F828mk3HybridProtocol {}
771
772impl MotuClockNameDisplaySpecification for F828mk3HybridProtocol {}
773
774impl MotuVersion3ClockSpecification for F828mk3HybridProtocol {
775    const CLOCK_RATES: &'static [ClkRate] = F828MK3_CLOCK_RATES;
776    const CLOCK_RATE_VALS: &'static [u8] = F828MK3_CLOCK_RATE_VALS;
777
778    const CLOCK_SRCS: &'static [V3ClkSrc] = F828MK3_CLOCK_SRCS;
779    const CLOCK_SRC_VALS: &'static [u8] = F828MK3_CLOCK_SRC_VALS;
780}
781
782impl MotuVersion3OpticalIfaceSpecification for F828mk3HybridProtocol {
783    const OPT_IFACE_COUNT: usize = 2;
784}
785
786impl CommandDspOperation for F828mk3HybridProtocol {}
787
788impl MotuCommandDspReverbSpecification for F828mk3HybridProtocol {}
789
790impl MotuCommandDspMonitorSpecification for F828mk3HybridProtocol {
791    const RETURN_ASSIGN_TARGETS: &'static [TargetPort] = F828MK3_RETURN_ASSIGN_TARGETS;
792}
793
794impl MotuCommandDspEqualizerSpecification for F828mk3HybridProtocol {}
795
796impl MotuCommandDspDynamicsSpecification for F828mk3HybridProtocol {}
797
798impl MotuCommandDspMixerSpecification for F828mk3HybridProtocol {
799    const SOURCE_PORTS: &'static [TargetPort] = F828MK3_MIXER_SOURCE_PORTS;
800    const OUTPUT_PORTS: &'static [TargetPort] = F828MK3_MIXER_OUTPUT_PORTS;
801}
802
803impl MotuCommandDspInputSpecification for F828mk3HybridProtocol {
804    const INPUT_PORTS: &'static [TargetPort] = F828MK3_INPUT_PORTS;
805    // The mic functions are not configureble by command. They are just hard-wired.
806    const MIC_COUNT: usize = 0;
807    const LINE_INPUT_COUNT: usize = 0;
808}
809
810impl MotuCommandDspOutputSpecification for F828mk3HybridProtocol {
811    const OUTPUT_PORTS: &'static [TargetPort] = F828MK3_OUTPUT_PORTS;
812}
813
814impl MotuCommandDspMeterSpecification for F828mk3HybridProtocol {
815    const INPUT_PORTS: &'static [(TargetPort, usize)] = F828MK3_METER_INPUT_PORTS;
816    const OUTPUT_PORTS: &'static [(TargetPort, usize)] = F828MK3_METER_OUTPUT_PORTS;
817}
818
819impl F828mk3HybridProtocol {
820    /// Notification mask for main assignment, return assignment, and phone assignment. The change
821    /// of phone assignment is also notified in command message.
822    pub const NOTIFY_PORT_CHANGE: u32 = 0x40000000;
823
824    /// Notification mask for footswitch.
825    pub const NOTIFY_FOOTSWITCH_MASK: u32 = 0x01000000;
826}
827
828/// The protocol implementation for 4pre.
829#[derive(Default)]
830pub struct H4preProtocol;
831
832impl MotuPortAssignSpecification for H4preProtocol {
833    const ASSIGN_PORT_TARGETS: &'static [TargetPort] = &[
834        TargetPort::PhonePair,     // = Stream-1/2
835        TargetPort::MainPair,      // = Stream-5/6
836        TargetPort::AnalogPair(0), // = Stream-3/4
837        TargetPort::SpdifPair,     // = Stream-7/8
838                                   // Blank for Stream-9/10
839    ];
840
841    const ASSIGN_PORT_VALS: &'static [u8] = &[
842        0x01, // = Stream-1/2
843        0x02, // = Stream-5/6
844        0x06, // = Stream-3/4
845        0x07, // = Stream-7/8
846              // Blank for Stream-9/10
847    ];
848}
849
850impl MotuVersion3ClockSpecification for H4preProtocol {
851    const CLOCK_RATES: &'static [ClkRate] = &[
852        ClkRate::R44100,
853        ClkRate::R48000,
854        ClkRate::R88200,
855        ClkRate::R96000,
856    ];
857    const CLOCK_RATE_VALS: &'static [u8] = &[0x00, 0x01, 0x02, 0x03];
858
859    const CLOCK_SRCS: &'static [V3ClkSrc] = &[V3ClkSrc::Internal, V3ClkSrc::SpdifCoax];
860    const CLOCK_SRC_VALS: &'static [u8] = &[0x00, 0x01];
861}
862
863impl MotuRegisterDspSpecification for H4preProtocol {
864    const MIXER_OUTPUT_DESTINATIONS: &'static [TargetPort] = &[];
865}
866
867impl MotuRegisterDspMixerStereoSourceSpecification for H4preProtocol {}
868
869impl MotuRegisterDspStereoInputSpecification for H4preProtocol {
870    const MIC_COUNT: usize = 4;
871}
872
873impl MotuRegisterDspMeterSpecification for H4preProtocol {
874    const INPUT_PORTS: &'static [TargetPort] = &[
875        TargetPort::Analog(0),
876        TargetPort::Analog(1),
877        TargetPort::Analog(2),
878        TargetPort::Analog(3),
879        TargetPort::Analog(0),
880        TargetPort::Analog(1),
881        TargetPort::Analog(2),
882        TargetPort::Analog(3),
883        TargetPort::Spdif(0),
884        TargetPort::Spdif(1),
885    ];
886    const OUTPUT_PORT_PAIRS: &'static [TargetPort] = &[
887        TargetPort::PhonePair,
888        TargetPort::MainPair,
889        TargetPort::AnalogPair(0),
890        TargetPort::SpdifPair,
891    ];
892    const OUTPUT_PORT_PAIR_POS: &'static [[usize; 2]] = &[[0, 1], [2, 3], [10, 11], [12, 13]];
893}
894
895const F896_MK3_ASSIGN_PORT_TARGETS: &[TargetPort] = &[
896    TargetPort::MainPair,      // = Stream-0/1
897    TargetPort::AnalogPair(0), // = Stream-2/3
898    TargetPort::AnalogPair(1), // = Stream-4/5
899    TargetPort::AnalogPair(2), // = Stream-6/7
900    TargetPort::AnalogPair(3), // = Stream-8/9
901    TargetPort::AesEbuPair,    // = Stream-10/11
902    TargetPort::SpdifPair,     // = Stream-12/13
903    TargetPort::PhonePair,     // = Stream-14/15
904    // = Stream-16/17 for dummy
905    TargetPort::OpticalAPair(0), // = Stream-18/19
906    TargetPort::OpticalAPair(1), // = Stream-20/21
907    TargetPort::OpticalAPair(2), // = Stream-22/23
908    TargetPort::OpticalAPair(3), // = Stream-24/25
909    TargetPort::OpticalBPair(0), // = Stream-26/27
910    TargetPort::OpticalBPair(1), // = Stream-28/29
911    TargetPort::OpticalBPair(2), // = Stream-30/31
912    TargetPort::OpticalBPair(3), // = Stream-32/33
913];
914
915const F896_MK3_ASSIGN_PORT_VALS: &[u8] = &[
916    0x00, // = Stream-0/1
917    0x01, // = Stream-2/3
918    0x02, // = Stream-4/5
919    0x03, // = Stream-6/7
920    0x04, // = Stream-8/9
921    0x05, // = Stream-10/11
922    0x06, // = Stream-12/13
923    0x07, // = Stream-14/15
924    0x08, // = Stream-18/19
925    0x09, // = Stream-20/21
926    0x0a, // = Stream-22/23
927    0x0b, // = Stream-24/25
928    0x0c, // = Stream-26/27
929    0x0d, // = Stream-28/29
930    0x0e, // = Stream-30/31
931    0x0f, // = Stream-32/33
932];
933
934const F896_MK3_CLOCK_RATES: &[ClkRate] = &[
935    ClkRate::R44100,
936    ClkRate::R48000,
937    ClkRate::R88200,
938    ClkRate::R96000,
939    ClkRate::R176400,
940    ClkRate::R192000,
941];
942
943const F896_MK3_CLOCK_RATE_VALS: &[u8] = &[0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
944
945const F896_MK3_CLOCK_SRCS: &[V3ClkSrc] = &[
946    V3ClkSrc::Internal,
947    V3ClkSrc::WordClk,
948    V3ClkSrc::AesEbuXlr,
949    V3ClkSrc::SpdifCoax,
950    V3ClkSrc::SignalOptA,
951    V3ClkSrc::SignalOptB,
952];
953
954const F896_MK3_CLOCK_SRC_VALS: &[u8] = &[0x00, 0x01, 0x08, 0x10, 0x18, 0x19];
955
956const F896_MK3_RETURN_ASSIGN_TARGETS: &[TargetPort] = &[
957    TargetPort::MainPair,
958    TargetPort::AnalogPair(0),
959    TargetPort::AnalogPair(1),
960    TargetPort::AnalogPair(2),
961    TargetPort::AnalogPair(3),
962    TargetPort::AesEbuPair,
963    TargetPort::SpdifPair,
964    TargetPort::PhonePair,
965    TargetPort::OpticalAPair(0),
966    TargetPort::OpticalAPair(1),
967    TargetPort::OpticalAPair(2),
968    TargetPort::OpticalAPair(3),
969    TargetPort::OpticalBPair(0),
970    TargetPort::OpticalBPair(1),
971    TargetPort::OpticalBPair(2),
972    TargetPort::OpticalBPair(3),
973];
974
975const F896_MK3_MIXER_SOURCE_PORTS: &[TargetPort] = &[
976    TargetPort::Analog(0),
977    TargetPort::Analog(1),
978    TargetPort::Analog(2),
979    TargetPort::Analog(3),
980    TargetPort::Analog(4),
981    TargetPort::Analog(5),
982    TargetPort::Analog(6),
983    TargetPort::Analog(7),
984    TargetPort::Analog(8),
985    TargetPort::Analog(9),
986    TargetPort::AesEbu(0),
987    TargetPort::AesEbu(1),
988    TargetPort::Spdif(0),
989    TargetPort::Spdif(1),
990    TargetPort::OpticalA(0),
991    TargetPort::OpticalA(1),
992    TargetPort::OpticalA(2),
993    TargetPort::OpticalA(3),
994    TargetPort::OpticalA(4),
995    TargetPort::OpticalA(5),
996    TargetPort::OpticalA(6),
997    TargetPort::OpticalA(7),
998    TargetPort::OpticalB(0),
999    TargetPort::OpticalB(1),
1000    TargetPort::OpticalB(2),
1001    TargetPort::OpticalB(3),
1002    TargetPort::OpticalB(4),
1003    TargetPort::OpticalB(5),
1004    TargetPort::OpticalB(6),
1005    TargetPort::OpticalB(7),
1006];
1007
1008const F896_MK3_MIXER_OUTPUT_PORTS: &[TargetPort] = &[
1009    TargetPort::Disabled,
1010    TargetPort::MainPair,
1011    TargetPort::AnalogPair(0),
1012    TargetPort::AnalogPair(1),
1013    TargetPort::AnalogPair(2),
1014    TargetPort::AnalogPair(3),
1015    TargetPort::AesEbuPair,
1016    TargetPort::SpdifPair,
1017    TargetPort::PhonePair,
1018    TargetPort::OpticalAPair(0),
1019    TargetPort::OpticalAPair(1),
1020    TargetPort::OpticalAPair(2),
1021    TargetPort::OpticalAPair(3),
1022    TargetPort::OpticalBPair(0),
1023    TargetPort::OpticalBPair(1),
1024    TargetPort::OpticalBPair(2),
1025    TargetPort::OpticalBPair(3),
1026];
1027
1028const F896_MK3_INPUT_PORTS: &[TargetPort] = &[
1029    TargetPort::Analog(0),
1030    TargetPort::Analog(1),
1031    TargetPort::Analog(2),
1032    TargetPort::Analog(3),
1033    TargetPort::Analog(4),
1034    TargetPort::Analog(5),
1035    TargetPort::Analog(6),
1036    TargetPort::Analog(7),
1037    TargetPort::Analog(8),
1038    TargetPort::Analog(9),
1039    TargetPort::AesEbu(0),
1040    TargetPort::AesEbu(1),
1041    TargetPort::Spdif(0),
1042    TargetPort::Spdif(1),
1043    TargetPort::OpticalA(0),
1044    TargetPort::OpticalA(1),
1045    TargetPort::OpticalA(2),
1046    TargetPort::OpticalA(3),
1047    TargetPort::OpticalA(4),
1048    TargetPort::OpticalA(5),
1049    TargetPort::OpticalA(6),
1050    TargetPort::OpticalA(7),
1051    TargetPort::OpticalB(0),
1052    TargetPort::OpticalB(1),
1053    TargetPort::OpticalB(2),
1054    TargetPort::OpticalB(3),
1055    TargetPort::OpticalB(4),
1056    TargetPort::OpticalB(5),
1057    TargetPort::OpticalB(6),
1058    TargetPort::OpticalB(7),
1059];
1060
1061const F896_MK3_OUTPUT_PORTS: &[TargetPort] = &[
1062    TargetPort::MainPair,
1063    TargetPort::AnalogPair(0),
1064    TargetPort::AnalogPair(1),
1065    TargetPort::AnalogPair(2),
1066    TargetPort::AnalogPair(3),
1067    TargetPort::AesEbuPair,
1068    TargetPort::SpdifPair,
1069    TargetPort::PhonePair,
1070    TargetPort::OpticalAPair(0),
1071    TargetPort::OpticalAPair(1),
1072    TargetPort::OpticalAPair(2),
1073    TargetPort::OpticalAPair(3),
1074    TargetPort::OpticalBPair(0),
1075    TargetPort::OpticalBPair(1),
1076    TargetPort::OpticalBPair(2),
1077    TargetPort::OpticalBPair(3),
1078];
1079
1080const F896_MK3_METER_INPUT_PORTS: &[(TargetPort, usize)] = &[
1081    (TargetPort::Analog(0), 8),
1082    (TargetPort::Analog(1), 9),
1083    (TargetPort::Analog(2), 10),
1084    (TargetPort::Analog(3), 11),
1085    (TargetPort::Analog(4), 12),
1086    (TargetPort::Analog(5), 13),
1087    (TargetPort::Analog(6), 14),
1088    (TargetPort::Analog(7), 15),
1089    (TargetPort::AesEbu(0), 18),
1090    (TargetPort::AesEbu(1), 19),
1091    (TargetPort::Spdif(0), 16),
1092    (TargetPort::Spdif(1), 17),
1093    (TargetPort::OpticalA(0), 20),
1094    (TargetPort::OpticalA(1), 21),
1095    (TargetPort::OpticalA(2), 22),
1096    (TargetPort::OpticalA(3), 23),
1097    (TargetPort::OpticalA(4), 24),
1098    (TargetPort::OpticalA(5), 25),
1099    (TargetPort::OpticalA(6), 26),
1100    (TargetPort::OpticalA(7), 27),
1101    (TargetPort::OpticalB(0), 28),
1102    (TargetPort::OpticalB(1), 29),
1103    (TargetPort::OpticalB(2), 30),
1104    (TargetPort::OpticalB(3), 31),
1105    (TargetPort::OpticalB(4), 32),
1106    (TargetPort::OpticalB(5), 33),
1107    (TargetPort::OpticalB(6), 34),
1108    (TargetPort::OpticalB(7), 35),
1109];
1110
1111const F896_MK3_METER_OUTPUT_PORTS: &[(TargetPort, usize)] = &[
1112    (TargetPort::Main(0), 82),
1113    (TargetPort::Main(1), 83),
1114    (TargetPort::Analog(0), 84),
1115    (TargetPort::Analog(1), 85),
1116    (TargetPort::Analog(2), 86),
1117    (TargetPort::Analog(3), 87),
1118    (TargetPort::Analog(4), 88),
1119    (TargetPort::Analog(5), 89),
1120    (TargetPort::Analog(6), 90),
1121    (TargetPort::Analog(7), 91),
1122    (TargetPort::AesEbu(0), 92),
1123    (TargetPort::AesEbu(1), 93),
1124    (TargetPort::Spdif(0), 80),
1125    (TargetPort::Spdif(1), 81),
1126    (TargetPort::Phone(0), 94),
1127    (TargetPort::Phone(1), 95),
1128    (TargetPort::OpticalA(0), 96),
1129    (TargetPort::OpticalA(1), 97),
1130    (TargetPort::OpticalA(2), 98),
1131    (TargetPort::OpticalA(3), 99),
1132    (TargetPort::OpticalA(4), 100),
1133    (TargetPort::OpticalA(5), 101),
1134    (TargetPort::OpticalA(6), 102),
1135    (TargetPort::OpticalA(7), 103),
1136    (TargetPort::OpticalB(0), 104),
1137    (TargetPort::OpticalB(1), 105),
1138    (TargetPort::OpticalB(2), 106),
1139    (TargetPort::OpticalB(3), 107),
1140    (TargetPort::OpticalB(4), 108),
1141    (TargetPort::OpticalB(5), 109),
1142    (TargetPort::OpticalB(6), 110),
1143    (TargetPort::OpticalB(7), 111),
1144];
1145
1146const F896_MK3_LEVEL_METERS_PROGRAMMABLE_MODES: &[LevelMetersProgrammableMode] = &[
1147    LevelMetersProgrammableMode::AnalogOutput,
1148    LevelMetersProgrammableMode::AdatAInput,
1149    LevelMetersProgrammableMode::AdatAOutput,
1150    LevelMetersProgrammableMode::AdatBInput,
1151    LevelMetersProgrammableMode::AdatBOutput,
1152    LevelMetersProgrammableMode::AesEbuInputOutput,
1153];
1154
1155const F896_MK3_OFFSET_AES_EBU_RATE_CONVERTER: u32 = 0x0c90;
1156
1157const F896_MK3_NOTIFY_PORT_CHANGE_MASK: u32 = 0x40000000;
1158
1159const F896_MK3_NOTIFY_FOOTSWITCH_MASK: u32 = 0x01000000;
1160
1161/// Mode of rate convert for AES/EBU input/output signals.
1162#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1163pub enum F896mk3AesebuRateConvertMode {
1164    /// Not available.
1165    None,
1166    /// The rate of input signal is converted to system rate.
1167    InputToSystem,
1168    /// The rate of output signal is slave to input, ignoring system rate.
1169    OutputDependsInput,
1170    /// The rate of output signal is at 44.1 kHz.
1171    Output441,
1172    /// The rate of output signal is at 48.0 kHz.
1173    Output480,
1174    /// The rate of output signal is at 88.2 kHz.
1175    Output882,
1176    /// The rate of output signal is at 96.0 kHz.
1177    Output960,
1178}
1179
1180impl Default for F896mk3AesebuRateConvertMode {
1181    fn default() -> Self {
1182        Self::None
1183    }
1184}
1185
1186/// The trait for specification of AES/EBU sampling rate converter in F896mk3.
1187pub trait F896mk3AesebuRateConvertSpecification {}
1188
1189fn serialize_f896mk3_aes_ebu_rate_converter_mode(
1190    mode: &F896mk3AesebuRateConvertMode,
1191    quad: &mut u32,
1192) {
1193    *quad = match mode {
1194        F896mk3AesebuRateConvertMode::Output960 => 6,
1195        F896mk3AesebuRateConvertMode::Output882 => 5,
1196        F896mk3AesebuRateConvertMode::Output480 => 4,
1197        F896mk3AesebuRateConvertMode::Output441 => 3,
1198        F896mk3AesebuRateConvertMode::OutputDependsInput => 2,
1199        F896mk3AesebuRateConvertMode::InputToSystem => 1,
1200        F896mk3AesebuRateConvertMode::None => 0,
1201    };
1202}
1203
1204fn deserialize_f896mk3_aes_ebu_rate_converter_mode(
1205    mode: &mut F896mk3AesebuRateConvertMode,
1206    quad: &u32,
1207) {
1208    *mode = match quad {
1209        6 => F896mk3AesebuRateConvertMode::Output960,
1210        5 => F896mk3AesebuRateConvertMode::Output882,
1211        4 => F896mk3AesebuRateConvertMode::Output480,
1212        3 => F896mk3AesebuRateConvertMode::Output441,
1213        2 => F896mk3AesebuRateConvertMode::OutputDependsInput,
1214        1 => F896mk3AesebuRateConvertMode::InputToSystem,
1215        _ => F896mk3AesebuRateConvertMode::None,
1216    }
1217}
1218
1219impl<O> MotuWhollyCacheableParamsOperation<F896mk3AesebuRateConvertMode> for O
1220where
1221    O: F896mk3AesebuRateConvertSpecification,
1222{
1223    fn cache_wholly(
1224        req: &mut FwReq,
1225        node: &mut FwNode,
1226        mode: &mut F896mk3AesebuRateConvertMode,
1227        timeout_ms: u32,
1228    ) -> Result<(), Error> {
1229        let quad = read_quad(
1230            req,
1231            node,
1232            F896_MK3_OFFSET_AES_EBU_RATE_CONVERTER,
1233            timeout_ms,
1234        )?;
1235        deserialize_f896mk3_aes_ebu_rate_converter_mode(mode, &quad);
1236        Ok(())
1237    }
1238}
1239
1240impl<O> MotuWhollyUpdatableParamsOperation<F896mk3AesebuRateConvertMode> for O
1241where
1242    O: F896mk3AesebuRateConvertSpecification,
1243{
1244    fn update_wholly(
1245        req: &mut FwReq,
1246        node: &mut FwNode,
1247        mode: &F896mk3AesebuRateConvertMode,
1248        timeout_ms: u32,
1249    ) -> Result<(), Error> {
1250        let mut quad = read_quad(
1251            req,
1252            node,
1253            F896_MK3_OFFSET_AES_EBU_RATE_CONVERTER,
1254            timeout_ms,
1255        )?;
1256        serialize_f896mk3_aes_ebu_rate_converter_mode(mode, &mut quad);
1257        write_quad(
1258            req,
1259            node,
1260            F896_MK3_OFFSET_AES_EBU_RATE_CONVERTER,
1261            quad,
1262            timeout_ms,
1263        )
1264    }
1265}
1266
1267/// The protocol implementation for 896 mk3 (FireWire only).
1268#[derive(Default, Debug)]
1269pub struct F896mk3Protocol;
1270
1271impl MotuPortAssignSpecification for F896mk3Protocol {
1272    const ASSIGN_PORT_TARGETS: &'static [TargetPort] = F896_MK3_ASSIGN_PORT_TARGETS;
1273    const ASSIGN_PORT_VALS: &'static [u8] = F896_MK3_ASSIGN_PORT_VALS;
1274}
1275
1276impl MotuWordClockOutputSpecification for F896mk3Protocol {}
1277
1278impl MotuClockNameDisplaySpecification for F896mk3Protocol {}
1279
1280impl MotuVersion3ClockSpecification for F896mk3Protocol {
1281    const CLOCK_RATES: &'static [ClkRate] = F896_MK3_CLOCK_RATES;
1282    const CLOCK_RATE_VALS: &'static [u8] = F896_MK3_CLOCK_RATE_VALS;
1283
1284    const CLOCK_SRCS: &'static [V3ClkSrc] = F896_MK3_CLOCK_SRCS;
1285    const CLOCK_SRC_VALS: &'static [u8] = F896_MK3_CLOCK_SRC_VALS;
1286}
1287
1288impl MotuVersion3OpticalIfaceSpecification for F896mk3Protocol {
1289    const OPT_IFACE_COUNT: usize = 2;
1290}
1291
1292impl CommandDspOperation for F896mk3Protocol {}
1293
1294impl MotuCommandDspReverbSpecification for F896mk3Protocol {}
1295
1296impl MotuCommandDspMonitorSpecification for F896mk3Protocol {
1297    const RETURN_ASSIGN_TARGETS: &'static [TargetPort] = F896_MK3_RETURN_ASSIGN_TARGETS;
1298}
1299
1300impl MotuCommandDspMixerSpecification for F896mk3Protocol {
1301    const SOURCE_PORTS: &'static [TargetPort] = F896_MK3_MIXER_SOURCE_PORTS;
1302    const OUTPUT_PORTS: &'static [TargetPort] = F896_MK3_MIXER_OUTPUT_PORTS;
1303}
1304
1305impl MotuCommandDspEqualizerSpecification for F896mk3Protocol {}
1306
1307impl MotuCommandDspDynamicsSpecification for F896mk3Protocol {}
1308
1309impl MotuCommandDspInputSpecification for F896mk3Protocol {
1310    const INPUT_PORTS: &'static [TargetPort] = F896_MK3_INPUT_PORTS;
1311    const MIC_COUNT: usize = 0;
1312    const LINE_INPUT_COUNT: usize = 0;
1313}
1314
1315impl MotuCommandDspOutputSpecification for F896mk3Protocol {
1316    const OUTPUT_PORTS: &'static [TargetPort] = F896_MK3_OUTPUT_PORTS;
1317}
1318
1319impl MotuCommandDspMeterSpecification for F896mk3Protocol {
1320    const INPUT_PORTS: &'static [(TargetPort, usize)] = F896_MK3_METER_INPUT_PORTS;
1321    const OUTPUT_PORTS: &'static [(TargetPort, usize)] = F896_MK3_METER_OUTPUT_PORTS;
1322}
1323
1324impl MotuLevelMetersSpecification for F896mk3Protocol {
1325    const LEVEL_METERS_PROGRAMMABLE_MODES: &'static [LevelMetersProgrammableMode] =
1326        F896_MK3_LEVEL_METERS_PROGRAMMABLE_MODES;
1327}
1328
1329impl F896mk3AesebuRateConvertSpecification for F896mk3Protocol {}
1330
1331impl F896mk3Protocol {
1332    /// Notification mask for main assignment, return assignment, and phone assignment, as well as
1333    /// programmable level meter. The change of phone assignment is also notified in command
1334    /// message.
1335    pub const NOTIFY_PORT_CHANGE_MASK: u32 = F896_MK3_NOTIFY_PORT_CHANGE_MASK;
1336
1337    /// Notification mask for footswitch.
1338    pub const NOTIFY_FOOTSWITCH_MASK: u32 = F896_MK3_NOTIFY_FOOTSWITCH_MASK;
1339}
1340
1341/// The protocol implementation for 896 mk3 (Hybrid).
1342#[derive(Default, Debug)]
1343pub struct F896mk3HybridProtocol;
1344
1345impl MotuPortAssignSpecification for F896mk3HybridProtocol {
1346    const ASSIGN_PORT_TARGETS: &'static [TargetPort] = F896_MK3_ASSIGN_PORT_TARGETS;
1347    const ASSIGN_PORT_VALS: &'static [u8] = F896_MK3_ASSIGN_PORT_VALS;
1348}
1349
1350impl MotuWordClockOutputSpecification for F896mk3HybridProtocol {}
1351
1352impl MotuClockNameDisplaySpecification for F896mk3HybridProtocol {}
1353
1354impl MotuVersion3ClockSpecification for F896mk3HybridProtocol {
1355    const CLOCK_RATES: &'static [ClkRate] = F896_MK3_CLOCK_RATES;
1356    const CLOCK_RATE_VALS: &'static [u8] = F896_MK3_CLOCK_RATE_VALS;
1357
1358    const CLOCK_SRCS: &'static [V3ClkSrc] = F896_MK3_CLOCK_SRCS;
1359    const CLOCK_SRC_VALS: &'static [u8] = F896_MK3_CLOCK_SRC_VALS;
1360}
1361
1362impl MotuVersion3OpticalIfaceSpecification for F896mk3HybridProtocol {
1363    const OPT_IFACE_COUNT: usize = 2;
1364}
1365
1366impl CommandDspOperation for F896mk3HybridProtocol {}
1367
1368impl MotuCommandDspReverbSpecification for F896mk3HybridProtocol {}
1369
1370impl MotuCommandDspMonitorSpecification for F896mk3HybridProtocol {
1371    const RETURN_ASSIGN_TARGETS: &'static [TargetPort] = F896_MK3_RETURN_ASSIGN_TARGETS;
1372}
1373
1374impl MotuCommandDspMixerSpecification for F896mk3HybridProtocol {
1375    const SOURCE_PORTS: &'static [TargetPort] = F896_MK3_MIXER_SOURCE_PORTS;
1376    const OUTPUT_PORTS: &'static [TargetPort] = F896_MK3_MIXER_OUTPUT_PORTS;
1377}
1378
1379impl MotuCommandDspEqualizerSpecification for F896mk3HybridProtocol {}
1380
1381impl MotuCommandDspDynamicsSpecification for F896mk3HybridProtocol {}
1382
1383impl MotuCommandDspInputSpecification for F896mk3HybridProtocol {
1384    const INPUT_PORTS: &'static [TargetPort] = F896_MK3_INPUT_PORTS;
1385    const MIC_COUNT: usize = 0;
1386    const LINE_INPUT_COUNT: usize = 0;
1387}
1388
1389impl MotuCommandDspOutputSpecification for F896mk3HybridProtocol {
1390    const OUTPUT_PORTS: &'static [TargetPort] = F896_MK3_OUTPUT_PORTS;
1391}
1392
1393impl MotuCommandDspMeterSpecification for F896mk3HybridProtocol {
1394    const INPUT_PORTS: &'static [(TargetPort, usize)] = F896_MK3_METER_INPUT_PORTS;
1395    const OUTPUT_PORTS: &'static [(TargetPort, usize)] = F896_MK3_METER_OUTPUT_PORTS;
1396}
1397
1398impl MotuLevelMetersSpecification for F896mk3HybridProtocol {
1399    const LEVEL_METERS_PROGRAMMABLE_MODES: &'static [LevelMetersProgrammableMode] =
1400        F896_MK3_LEVEL_METERS_PROGRAMMABLE_MODES;
1401}
1402
1403impl F896mk3AesebuRateConvertSpecification for F896mk3HybridProtocol {}
1404
1405impl F896mk3HybridProtocol {
1406    /// Notification mask for main assignment, return assignment, and phone assignment, as well as
1407    /// programmable level meter. The change of phone assignment is also notified in command
1408    /// message.
1409    pub const NOTIFY_PORT_CHANGE_MASK: u32 = F896_MK3_NOTIFY_PORT_CHANGE_MASK;
1410
1411    /// Notification mask for footswitch.
1412    pub const NOTIFY_FOOTSWITCH_MASK: u32 = F896_MK3_NOTIFY_FOOTSWITCH_MASK;
1413}
1414
1415/// The protocol implementation for Ultralite mk3 (FireWire only).
1416#[derive(Default, Debug)]
1417pub struct UltraliteMk3Protocol;
1418
1419const ULTRALITE_MK3_ASSIGN_PORT_TARGETS: &[TargetPort] = &[
1420    TargetPort::MainPair,      // = Stream-0/1
1421    TargetPort::AnalogPair(0), // = Stream-2/3
1422    TargetPort::AnalogPair(1), // = Stream-4/5
1423    TargetPort::AnalogPair(2), // = Stream-6/7
1424    TargetPort::AnalogPair(3), // = Stream-8/9
1425    TargetPort::SpdifPair,     // = Stream-12/13
1426    TargetPort::PhonePair,     // = Stream-10/11
1427];
1428
1429const ULTRALITE_MK3_ASSIGN_PORT_VALS: &[u8] = &[
1430    0x00, // = Stream-0/1
1431    0x01, // = Stream-2/3
1432    0x02, // = Stream-4/5
1433    0x03, // = Stream-6/7
1434    0x04, // = Stream-8/9
1435    0x05, // = Stream-12/13
1436    0x06, // = Stream-10/11
1437];
1438
1439const ULTRALITE_MK3_CLOCK_RATES: &[ClkRate] = &[
1440    ClkRate::R44100,
1441    ClkRate::R48000,
1442    ClkRate::R88200,
1443    ClkRate::R96000,
1444];
1445
1446const ULTRALITE_MK3_CLOCK_RATE_VALS: &[u8] = &[0x00, 0x01, 0x02, 0x03];
1447
1448const ULTRALITE_MK3_CLOCK_SRCS: &[V3ClkSrc] = &[V3ClkSrc::Internal, V3ClkSrc::SpdifCoax];
1449
1450const ULTRALITE_MK3_CLOCK_SRC_VALS: &[u8] = &[0x00, 0x01];
1451
1452const ULTRALITE_MK3_RETURN_ASSIGN_TARGETS: &[TargetPort] = &[
1453    TargetPort::MainPair,
1454    TargetPort::AnalogPair(0),
1455    TargetPort::AnalogPair(1),
1456    TargetPort::AnalogPair(2),
1457    TargetPort::AnalogPair(3),
1458    TargetPort::SpdifPair,
1459    TargetPort::PhonePair,
1460];
1461
1462const ULTRALITE_MK3_MIXER_SOURCE_PORTS: &[TargetPort] = &[
1463    TargetPort::Analog(0),
1464    TargetPort::Analog(1),
1465    TargetPort::Analog(2),
1466    TargetPort::Analog(3),
1467    TargetPort::Analog(4),
1468    TargetPort::Analog(5),
1469    TargetPort::Analog(6),
1470    TargetPort::Analog(7),
1471    TargetPort::Spdif(0),
1472    TargetPort::Spdif(1),
1473];
1474
1475const ULTRALITE_MK3_MIXER_OUTPUT_PORTS: &[TargetPort] = &[
1476    TargetPort::MainPair,
1477    TargetPort::AnalogPair(0),
1478    TargetPort::AnalogPair(1),
1479    TargetPort::AnalogPair(2),
1480    TargetPort::AnalogPair(3),
1481    TargetPort::SpdifPair,
1482    TargetPort::PhonePair,
1483];
1484
1485const ULTRALITE_MK3_INPUT_PORTS: &[TargetPort] = &[
1486    TargetPort::Analog(0),
1487    TargetPort::Analog(1),
1488    TargetPort::Analog(2),
1489    TargetPort::Analog(3),
1490    TargetPort::Analog(4),
1491    TargetPort::Analog(5),
1492    TargetPort::Analog(6),
1493    TargetPort::Analog(7),
1494    TargetPort::Spdif(0),
1495    TargetPort::Spdif(1),
1496];
1497
1498const ULTRALITE_MK3_OUTPUT_PORTS: &[TargetPort] = &[
1499    TargetPort::MainPair,
1500    TargetPort::AnalogPair(0),
1501    TargetPort::AnalogPair(1),
1502    TargetPort::AnalogPair(2),
1503    TargetPort::AnalogPair(3),
1504    TargetPort::SpdifPair,
1505    TargetPort::PhonePair,
1506];
1507
1508const ULTRALITEMK3_METER_INPUT_PORTS: &[(TargetPort, usize)] = &[
1509    (TargetPort::Analog(0), 2),
1510    (TargetPort::Analog(1), 3),
1511    (TargetPort::Analog(2), 4),
1512    (TargetPort::Analog(3), 5),
1513    (TargetPort::Analog(4), 6),
1514    (TargetPort::Analog(5), 7),
1515    (TargetPort::Analog(6), 8),
1516    (TargetPort::Analog(7), 9),
1517    (TargetPort::Spdif(0), 10),
1518    (TargetPort::Spdif(1), 11),
1519    (TargetPort::Analog(0), 28),
1520    (TargetPort::Analog(1), 29),
1521    (TargetPort::Analog(2), 30),
1522    (TargetPort::Analog(3), 31),
1523    (TargetPort::Analog(4), 32),
1524    (TargetPort::Analog(5), 33),
1525    (TargetPort::Analog(6), 34),
1526    (TargetPort::Analog(7), 35),
1527    (TargetPort::Spdif(0), 36),
1528    (TargetPort::Spdif(1), 37),
1529];
1530const ULTRALITEMK3_METER_OUTPUT_PORTS: &[(TargetPort, usize)] = &[
1531    (TargetPort::Spdif(0), 40),
1532    (TargetPort::Spdif(1), 41),
1533    (TargetPort::Analog(0), 42),
1534    (TargetPort::Analog(1), 43),
1535    (TargetPort::Analog(2), 44),
1536    (TargetPort::Analog(3), 45),
1537    (TargetPort::Analog(4), 46),
1538    (TargetPort::Analog(5), 47),
1539    (TargetPort::Analog(6), 48),
1540    (TargetPort::Analog(7), 49),
1541    (TargetPort::Phone(0), 50),
1542    (TargetPort::Phone(1), 51),
1543];
1544
1545impl MotuPortAssignSpecification for UltraliteMk3Protocol {
1546    const ASSIGN_PORT_TARGETS: &'static [TargetPort] = ULTRALITE_MK3_ASSIGN_PORT_TARGETS;
1547    const ASSIGN_PORT_VALS: &'static [u8] = ULTRALITE_MK3_ASSIGN_PORT_VALS;
1548}
1549
1550impl MotuClockNameDisplaySpecification for UltraliteMk3Protocol {}
1551
1552impl MotuVersion3ClockSpecification for UltraliteMk3Protocol {
1553    const CLOCK_RATES: &'static [ClkRate] = ULTRALITE_MK3_CLOCK_RATES;
1554    const CLOCK_RATE_VALS: &'static [u8] = ULTRALITE_MK3_CLOCK_RATE_VALS;
1555
1556    const CLOCK_SRCS: &'static [V3ClkSrc] = ULTRALITE_MK3_CLOCK_SRCS;
1557    const CLOCK_SRC_VALS: &'static [u8] = ULTRALITE_MK3_CLOCK_SRC_VALS;
1558}
1559
1560impl CommandDspOperation for UltraliteMk3Protocol {}
1561
1562impl MotuCommandDspReverbSpecification for UltraliteMk3Protocol {}
1563
1564impl MotuCommandDspMonitorSpecification for UltraliteMk3Protocol {
1565    const RETURN_ASSIGN_TARGETS: &'static [TargetPort] = ULTRALITE_MK3_RETURN_ASSIGN_TARGETS;
1566}
1567
1568impl MotuCommandDspEqualizerSpecification for UltraliteMk3Protocol {}
1569
1570impl MotuCommandDspDynamicsSpecification for UltraliteMk3Protocol {}
1571
1572impl MotuCommandDspMixerSpecification for UltraliteMk3Protocol {
1573    const SOURCE_PORTS: &'static [TargetPort] = ULTRALITE_MK3_MIXER_SOURCE_PORTS;
1574    const OUTPUT_PORTS: &'static [TargetPort] = ULTRALITE_MK3_MIXER_OUTPUT_PORTS;
1575}
1576
1577impl MotuCommandDspInputSpecification for UltraliteMk3Protocol {
1578    const INPUT_PORTS: &'static [TargetPort] = ULTRALITE_MK3_INPUT_PORTS;
1579    // The mic functions are not configureble by command. They are just hard-wired.
1580    const MIC_COUNT: usize = 0;
1581    const LINE_INPUT_COUNT: usize = 0;
1582}
1583
1584impl MotuCommandDspOutputSpecification for UltraliteMk3Protocol {
1585    const OUTPUT_PORTS: &'static [TargetPort] = ULTRALITE_MK3_OUTPUT_PORTS;
1586}
1587
1588impl UltraliteMk3Protocol {
1589    /// Notification mask for main assignment, return assignment, and phone assignment. The change
1590    /// of phone assignment is also notified in command message.
1591    pub const NOTIFY_PORT_CHANGE: u32 = 0x40000000;
1592}
1593
1594impl MotuCommandDspMeterSpecification for UltraliteMk3Protocol {
1595    const INPUT_PORTS: &'static [(TargetPort, usize)] = ULTRALITEMK3_METER_INPUT_PORTS;
1596    const OUTPUT_PORTS: &'static [(TargetPort, usize)] = ULTRALITEMK3_METER_OUTPUT_PORTS;
1597}
1598
1599/// The protocol implementation for Ultralite mk3 Hybrid.
1600#[derive(Default, Debug)]
1601pub struct UltraliteMk3HybridProtocol;
1602
1603impl MotuPortAssignSpecification for UltraliteMk3HybridProtocol {
1604    const ASSIGN_PORT_TARGETS: &'static [TargetPort] = ULTRALITE_MK3_ASSIGN_PORT_TARGETS;
1605    const ASSIGN_PORT_VALS: &'static [u8] = ULTRALITE_MK3_ASSIGN_PORT_VALS;
1606}
1607
1608impl MotuClockNameDisplaySpecification for UltraliteMk3HybridProtocol {}
1609
1610impl MotuVersion3ClockSpecification for UltraliteMk3HybridProtocol {
1611    const CLOCK_RATES: &'static [ClkRate] = ULTRALITE_MK3_CLOCK_RATES;
1612    const CLOCK_RATE_VALS: &'static [u8] = ULTRALITE_MK3_CLOCK_RATE_VALS;
1613
1614    const CLOCK_SRCS: &'static [V3ClkSrc] = ULTRALITE_MK3_CLOCK_SRCS;
1615    const CLOCK_SRC_VALS: &'static [u8] = ULTRALITE_MK3_CLOCK_SRC_VALS;
1616}
1617
1618impl CommandDspOperation for UltraliteMk3HybridProtocol {}
1619
1620impl MotuCommandDspReverbSpecification for UltraliteMk3HybridProtocol {}
1621
1622impl MotuCommandDspMonitorSpecification for UltraliteMk3HybridProtocol {
1623    const RETURN_ASSIGN_TARGETS: &'static [TargetPort] = ULTRALITE_MK3_RETURN_ASSIGN_TARGETS;
1624}
1625
1626impl MotuCommandDspEqualizerSpecification for UltraliteMk3HybridProtocol {}
1627
1628impl MotuCommandDspDynamicsSpecification for UltraliteMk3HybridProtocol {}
1629
1630impl MotuCommandDspMixerSpecification for UltraliteMk3HybridProtocol {
1631    const SOURCE_PORTS: &'static [TargetPort] = ULTRALITE_MK3_MIXER_SOURCE_PORTS;
1632    const OUTPUT_PORTS: &'static [TargetPort] = ULTRALITE_MK3_MIXER_OUTPUT_PORTS;
1633}
1634
1635impl MotuCommandDspInputSpecification for UltraliteMk3HybridProtocol {
1636    const INPUT_PORTS: &'static [TargetPort] = ULTRALITE_MK3_INPUT_PORTS;
1637    const MIC_COUNT: usize = 2;
1638    const LINE_INPUT_COUNT: usize = 0;
1639}
1640
1641impl MotuCommandDspOutputSpecification for UltraliteMk3HybridProtocol {
1642    const OUTPUT_PORTS: &'static [TargetPort] = ULTRALITE_MK3_OUTPUT_PORTS;
1643}
1644
1645impl MotuCommandDspMeterSpecification for UltraliteMk3HybridProtocol {
1646    const INPUT_PORTS: &'static [(TargetPort, usize)] = ULTRALITEMK3_METER_INPUT_PORTS;
1647    const OUTPUT_PORTS: &'static [(TargetPort, usize)] = ULTRALITEMK3_METER_OUTPUT_PORTS;
1648}
1649
1650impl UltraliteMk3HybridProtocol {
1651    /// Notification mask for main assignment, return assignment, and phone assignment. The change
1652    /// of phone assignment is also notified in command message.
1653    pub const NOTIFY_PORT_CHANGE: u32 = 0x40000000;
1654}
1655
1656/// The protocol implementation for Traveler mk3.
1657#[derive(Default, Debug)]
1658pub struct TravelerMk3Protocol;
1659
1660impl MotuPortAssignSpecification for TravelerMk3Protocol {
1661    const ASSIGN_PORT_TARGETS: &'static [TargetPort] = &[
1662        TargetPort::AnalogPair(0),   // = Stream-2/3
1663        TargetPort::AnalogPair(1),   // = Stream-4/5
1664        TargetPort::AnalogPair(2),   // = Stream-6/7
1665        TargetPort::AnalogPair(3),   // = Stream-8/9
1666        TargetPort::AesEbuPair,      // = Stream-10/11
1667        TargetPort::SpdifPair,       // = Stream-12/13
1668        TargetPort::PhonePair,       // = Stream-0/1
1669        TargetPort::OpticalAPair(0), // = Stream-14/15
1670        TargetPort::OpticalAPair(1), // = Stream-16/17
1671        TargetPort::OpticalAPair(2), // = Stream-18/19
1672        TargetPort::OpticalAPair(3), // = Stream-20/21
1673        TargetPort::OpticalBPair(0), // = Stream-22/23
1674        TargetPort::OpticalBPair(1), // = Stream-24/25
1675        TargetPort::OpticalBPair(2), // = Stream-26/27
1676        TargetPort::OpticalBPair(3), // = Stream-28/29
1677    ];
1678    const ASSIGN_PORT_VALS: &'static [u8] = &[
1679        0x00, // = Stream-2/3
1680        0x01, // = Stream-4/5
1681        0x02, // = Stream-6/7
1682        0x03, // = Stream-8/9
1683        0x04, // = Stream-10/11
1684        0x05, // = Stream-12/13
1685        0x06, // = Stream-0/1
1686        0x07, // = Stream-14/15
1687        0x08, // = Stream-16/17
1688        0x09, // = Stream-18/19
1689        0x0a, // = Stream-20/21
1690        0x0b, // = Stream-22/23
1691        0x0c, // = Stream-24/25
1692        0x0d, // = Stream-26/27
1693        0x0e, // = Stream-28/29
1694    ];
1695}
1696
1697impl MotuClockNameDisplaySpecification for TravelerMk3Protocol {}
1698
1699impl MotuVersion3ClockSpecification for TravelerMk3Protocol {
1700    const CLOCK_RATES: &'static [ClkRate] = &[
1701        ClkRate::R44100,
1702        ClkRate::R48000,
1703        ClkRate::R88200,
1704        ClkRate::R96000,
1705        ClkRate::R176400,
1706        ClkRate::R192000,
1707    ];
1708    const CLOCK_RATE_VALS: &'static [u8] = &[0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
1709
1710    const CLOCK_SRCS: &'static [V3ClkSrc] = &[
1711        V3ClkSrc::Internal,
1712        V3ClkSrc::WordClk,
1713        V3ClkSrc::AesEbuXlr,
1714        V3ClkSrc::SpdifCoax,
1715        V3ClkSrc::SignalOptA,
1716        V3ClkSrc::SignalOptB,
1717    ];
1718    const CLOCK_SRC_VALS: &'static [u8] = &[0x00, 0x01, 0x08, 0x10, 0x18, 0x19];
1719}
1720
1721impl MotuVersion3OpticalIfaceSpecification for TravelerMk3Protocol {
1722    const OPT_IFACE_COUNT: usize = 2;
1723}
1724
1725impl MotuWordClockOutputSpecification for TravelerMk3Protocol {}
1726
1727impl CommandDspOperation for TravelerMk3Protocol {}
1728
1729impl MotuCommandDspReverbSpecification for TravelerMk3Protocol {}
1730
1731impl MotuCommandDspMonitorSpecification for TravelerMk3Protocol {
1732    const RETURN_ASSIGN_TARGETS: &'static [TargetPort] = &[
1733        TargetPort::AnalogPair(0),
1734        TargetPort::AnalogPair(1),
1735        TargetPort::AnalogPair(2),
1736        TargetPort::AnalogPair(3),
1737        TargetPort::AesEbuPair,
1738        TargetPort::SpdifPair,
1739        TargetPort::PhonePair,
1740        TargetPort::OpticalAPair(0),
1741        TargetPort::OpticalAPair(1),
1742        TargetPort::OpticalAPair(2),
1743        TargetPort::OpticalAPair(3),
1744        TargetPort::OpticalBPair(0),
1745        TargetPort::OpticalBPair(1),
1746        TargetPort::OpticalBPair(2),
1747        TargetPort::OpticalBPair(3),
1748    ];
1749}
1750
1751impl MotuCommandDspMixerSpecification for TravelerMk3Protocol {
1752    const SOURCE_PORTS: &'static [TargetPort] = &[
1753        TargetPort::Analog(0), // Mic-0
1754        TargetPort::Analog(1), // Mic-1
1755        TargetPort::Analog(2), // Mic-2
1756        TargetPort::Analog(3), // Mic-3
1757        TargetPort::Analog(4),
1758        TargetPort::Analog(5),
1759        TargetPort::Analog(6),
1760        TargetPort::Analog(7),
1761        TargetPort::AesEbu(0),
1762        TargetPort::AesEbu(1),
1763        TargetPort::Spdif(0),
1764        TargetPort::Spdif(1),
1765        TargetPort::OpticalA(0),
1766        TargetPort::OpticalA(1),
1767        TargetPort::OpticalA(2),
1768        TargetPort::OpticalA(3),
1769        TargetPort::OpticalA(4),
1770        TargetPort::OpticalA(5),
1771        TargetPort::OpticalA(6),
1772        TargetPort::OpticalA(7),
1773        TargetPort::OpticalB(0),
1774        TargetPort::OpticalB(1),
1775        TargetPort::OpticalB(2),
1776        TargetPort::OpticalB(3),
1777        TargetPort::OpticalB(4),
1778        TargetPort::OpticalB(5),
1779        TargetPort::OpticalB(6),
1780        TargetPort::OpticalB(7),
1781    ];
1782    const OUTPUT_PORTS: &'static [TargetPort] = &[
1783        TargetPort::Disabled,
1784        TargetPort::AnalogPair(0),
1785        TargetPort::AnalogPair(1),
1786        TargetPort::AnalogPair(2),
1787        TargetPort::AnalogPair(3),
1788        TargetPort::AesEbuPair,
1789        TargetPort::SpdifPair,
1790        TargetPort::PhonePair,
1791        TargetPort::OpticalAPair(0),
1792        TargetPort::OpticalAPair(1),
1793        TargetPort::OpticalAPair(2),
1794        TargetPort::OpticalAPair(3),
1795        TargetPort::OpticalBPair(0),
1796        TargetPort::OpticalBPair(1),
1797        TargetPort::OpticalBPair(2),
1798        TargetPort::OpticalBPair(3),
1799    ];
1800}
1801
1802impl MotuCommandDspEqualizerSpecification for TravelerMk3Protocol {}
1803
1804impl MotuCommandDspDynamicsSpecification for TravelerMk3Protocol {}
1805
1806impl MotuCommandDspInputSpecification for TravelerMk3Protocol {
1807    const INPUT_PORTS: &'static [TargetPort] = &[
1808        TargetPort::Analog(0), // Mic-0
1809        TargetPort::Analog(1), // Mic-1
1810        TargetPort::Analog(2), // Mic-2
1811        TargetPort::Analog(3), // Mic-3
1812        TargetPort::Analog(4),
1813        TargetPort::Analog(5),
1814        TargetPort::Analog(6),
1815        TargetPort::Analog(7),
1816        TargetPort::AesEbu(0),
1817        TargetPort::AesEbu(1),
1818        TargetPort::Spdif(0),
1819        TargetPort::Spdif(1),
1820        TargetPort::OpticalA(0),
1821        TargetPort::OpticalA(1),
1822        TargetPort::OpticalA(2),
1823        TargetPort::OpticalA(3),
1824        TargetPort::OpticalA(4),
1825        TargetPort::OpticalA(5),
1826        TargetPort::OpticalA(6),
1827        TargetPort::OpticalA(7),
1828        TargetPort::OpticalB(0),
1829        TargetPort::OpticalB(1),
1830        TargetPort::OpticalB(2),
1831        TargetPort::OpticalB(3),
1832        TargetPort::OpticalB(4),
1833        TargetPort::OpticalB(5),
1834        TargetPort::OpticalB(6),
1835        TargetPort::OpticalB(7),
1836    ];
1837    const MIC_COUNT: usize = 4;
1838    const LINE_INPUT_COUNT: usize = 4;
1839}
1840
1841impl MotuCommandDspOutputSpecification for TravelerMk3Protocol {
1842    const OUTPUT_PORTS: &'static [TargetPort] = &[
1843        TargetPort::AnalogPair(0),
1844        TargetPort::AnalogPair(1),
1845        TargetPort::AnalogPair(2),
1846        TargetPort::AnalogPair(3),
1847        TargetPort::AesEbuPair,
1848        TargetPort::SpdifPair,
1849        TargetPort::PhonePair,
1850        TargetPort::OpticalAPair(0),
1851        TargetPort::OpticalAPair(1),
1852        TargetPort::OpticalAPair(2),
1853        TargetPort::OpticalAPair(3),
1854        TargetPort::OpticalBPair(0),
1855        TargetPort::OpticalBPair(1),
1856        TargetPort::OpticalBPair(2),
1857        TargetPort::OpticalBPair(3),
1858    ];
1859}
1860
1861impl MotuCommandDspMeterSpecification for TravelerMk3Protocol {
1862    const INPUT_PORTS: &'static [(TargetPort, usize)] = &[
1863        (TargetPort::Analog(0), 4),
1864        (TargetPort::Analog(1), 5),
1865        (TargetPort::Analog(2), 6),
1866        (TargetPort::Analog(3), 7),
1867        (TargetPort::Analog(4), 8),
1868        (TargetPort::Analog(5), 9),
1869        (TargetPort::Analog(6), 10),
1870        (TargetPort::Analog(7), 11),
1871        (TargetPort::AesEbu(0), 14),
1872        (TargetPort::AesEbu(1), 15),
1873        (TargetPort::Spdif(0), 12),
1874        (TargetPort::Spdif(1), 13),
1875        (TargetPort::OpticalA(0), 16),
1876        (TargetPort::OpticalA(1), 17),
1877        (TargetPort::OpticalA(2), 18),
1878        (TargetPort::OpticalA(3), 19),
1879        (TargetPort::OpticalA(4), 20),
1880        (TargetPort::OpticalA(5), 21),
1881        (TargetPort::OpticalA(6), 22),
1882        (TargetPort::OpticalA(7), 23),
1883        (TargetPort::OpticalB(0), 24),
1884        (TargetPort::OpticalB(1), 25),
1885        (TargetPort::OpticalB(2), 26),
1886        (TargetPort::OpticalB(3), 27),
1887        (TargetPort::OpticalB(4), 28),
1888        (TargetPort::OpticalB(5), 29),
1889        (TargetPort::OpticalB(6), 30),
1890        (TargetPort::OpticalB(7), 31),
1891        (TargetPort::Analog(0), 48),
1892        (TargetPort::Analog(1), 49),
1893        (TargetPort::Analog(2), 50),
1894        (TargetPort::Analog(3), 51),
1895        (TargetPort::Analog(4), 52),
1896        (TargetPort::Analog(5), 53),
1897        (TargetPort::Analog(6), 54),
1898        (TargetPort::Analog(7), 55),
1899        (TargetPort::AesEbu(0), 58),
1900        (TargetPort::AesEbu(1), 59),
1901        (TargetPort::Spdif(0), 56),
1902        (TargetPort::Spdif(1), 57),
1903        (TargetPort::OpticalA(0), 60),
1904        (TargetPort::OpticalA(1), 61),
1905        (TargetPort::OpticalA(2), 62),
1906        (TargetPort::OpticalA(3), 63),
1907        (TargetPort::OpticalA(4), 64),
1908        (TargetPort::OpticalA(5), 65),
1909        (TargetPort::OpticalA(6), 66),
1910        (TargetPort::OpticalA(7), 67),
1911        (TargetPort::OpticalB(0), 68),
1912        (TargetPort::OpticalB(1), 69),
1913        (TargetPort::OpticalB(2), 70),
1914        (TargetPort::OpticalB(3), 71),
1915        (TargetPort::OpticalB(4), 72),
1916        (TargetPort::OpticalB(5), 73),
1917        (TargetPort::OpticalB(6), 74),
1918        (TargetPort::OpticalB(7), 75),
1919    ];
1920    const OUTPUT_PORTS: &'static [(TargetPort, usize)] = &[
1921        (TargetPort::Phone(0), 88),
1922        (TargetPort::Phone(1), 89),
1923        (TargetPort::Analog(0), 78),
1924        (TargetPort::Analog(1), 79),
1925        (TargetPort::Analog(2), 80),
1926        (TargetPort::Analog(3), 81),
1927        (TargetPort::Analog(4), 82),
1928        (TargetPort::Analog(5), 83),
1929        (TargetPort::Analog(6), 84),
1930        (TargetPort::Analog(7), 85),
1931        (TargetPort::AesEbu(0), 86),
1932        (TargetPort::AesEbu(1), 87),
1933        (TargetPort::Spdif(0), 76),
1934        (TargetPort::Spdif(1), 77),
1935        (TargetPort::OpticalA(0), 90),
1936        (TargetPort::OpticalA(1), 91),
1937        (TargetPort::OpticalA(2), 92),
1938        (TargetPort::OpticalA(3), 93),
1939        (TargetPort::OpticalA(4), 94),
1940        (TargetPort::OpticalA(5), 95),
1941        (TargetPort::OpticalA(6), 96),
1942        (TargetPort::OpticalA(7), 97),
1943        (TargetPort::OpticalB(0), 98),
1944        (TargetPort::OpticalB(1), 99),
1945        (TargetPort::OpticalB(2), 100),
1946        (TargetPort::OpticalB(3), 101),
1947        (TargetPort::OpticalB(4), 102),
1948        (TargetPort::OpticalB(5), 103),
1949        (TargetPort::OpticalB(6), 104),
1950        (TargetPort::OpticalB(7), 105),
1951    ];
1952}
1953
1954impl TravelerMk3Protocol {
1955    /// Notification mask for main assignment, return assignment, and phone assignment. The change
1956    /// of phone assignment is also notified in command message.
1957    pub const NOTIFY_PORT_CHANGE: u32 = 0x40000000;
1958}
1959
1960/// The protocol implementation for Track 16.
1961#[derive(Default, Debug)]
1962pub struct Track16Protocol;
1963
1964impl MotuPortAssignSpecification for Track16Protocol {
1965    const ASSIGN_PORT_TARGETS: &'static [TargetPort] = &[
1966        TargetPort::AnalogPair(0),   // = Stream-2/3
1967        TargetPort::AnalogPair(1),   // = Stream-4/5
1968        TargetPort::PhonePair,       // = Stream-0/1
1969        TargetPort::OpticalAPair(0), // = Stream-14/15
1970        TargetPort::OpticalAPair(1), // = Stream-16/17
1971        TargetPort::OpticalAPair(2), // = Stream-18/19
1972        TargetPort::OpticalAPair(3), // = Stream-20/21
1973    ];
1974
1975    const ASSIGN_PORT_VALS: &'static [u8] = &[
1976        0x00, // = Stream-2/3
1977        0x01, // = Stream-4/5
1978        0x02, // = Stream-0/1
1979        0x07, // = Stream-14/15
1980        0x08, // = Stream-16/17
1981        0x09, // = Stream-18/19
1982        0x0a, // = Stream-20/21
1983    ];
1984}
1985
1986impl MotuVersion3ClockSpecification for Track16Protocol {
1987    const CLOCK_RATES: &'static [ClkRate] = &[
1988        ClkRate::R44100,
1989        ClkRate::R48000,
1990        ClkRate::R88200,
1991        ClkRate::R96000,
1992        ClkRate::R176400,
1993        ClkRate::R192000,
1994    ];
1995    const CLOCK_RATE_VALS: &'static [u8] = &[0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
1996
1997    const CLOCK_SRCS: &'static [V3ClkSrc] = &[V3ClkSrc::Internal, V3ClkSrc::SignalOptA];
1998    const CLOCK_SRC_VALS: &'static [u8] = &[0x00, 0x18];
1999}
2000
2001impl MotuVersion3OpticalIfaceSpecification for Track16Protocol {
2002    const OPT_IFACE_COUNT: usize = 1;
2003}
2004
2005impl MotuWordClockOutputSpecification for Track16Protocol {}
2006
2007impl CommandDspOperation for Track16Protocol {}
2008
2009impl MotuCommandDspReverbSpecification for Track16Protocol {}
2010
2011impl MotuCommandDspMonitorSpecification for Track16Protocol {
2012    const RETURN_ASSIGN_TARGETS: &'static [TargetPort] = &[
2013        TargetPort::AnalogPair(0),
2014        TargetPort::AnalogPair(1),
2015        TargetPort::PhonePair,
2016        TargetPort::OpticalAPair(0),
2017        TargetPort::OpticalAPair(1),
2018        TargetPort::OpticalAPair(2),
2019        TargetPort::OpticalAPair(3),
2020    ];
2021}
2022
2023impl MotuCommandDspMixerSpecification for Track16Protocol {
2024    const SOURCE_PORTS: &'static [TargetPort] = &[
2025        TargetPort::Analog(0), // Mic-0
2026        TargetPort::Analog(1), // Mic-1
2027        TargetPort::Analog(2),
2028        TargetPort::Analog(3),
2029        TargetPort::Analog(4),
2030        TargetPort::Analog(5),
2031        TargetPort::Analog(6),
2032        TargetPort::Analog(7),
2033        TargetPort::OpticalA(0),
2034        TargetPort::OpticalA(1),
2035        TargetPort::OpticalA(2),
2036        TargetPort::OpticalA(3),
2037        TargetPort::OpticalA(4),
2038        TargetPort::OpticalA(5),
2039        TargetPort::OpticalA(6),
2040        TargetPort::OpticalA(7),
2041    ];
2042    const OUTPUT_PORTS: &'static [TargetPort] = &[
2043        TargetPort::Disabled,
2044        TargetPort::AnalogPair(0),
2045        TargetPort::AnalogPair(1),
2046        TargetPort::AnalogPair(2),
2047        TargetPort::AnalogPair(3),
2048        TargetPort::PhonePair,
2049        TargetPort::OpticalAPair(0),
2050        TargetPort::OpticalAPair(1),
2051        TargetPort::OpticalAPair(2),
2052        TargetPort::OpticalAPair(3),
2053    ];
2054}
2055
2056impl MotuCommandDspEqualizerSpecification for Track16Protocol {}
2057
2058impl MotuCommandDspDynamicsSpecification for Track16Protocol {}
2059
2060impl MotuCommandDspInputSpecification for Track16Protocol {
2061    const INPUT_PORTS: &'static [TargetPort] = &[
2062        TargetPort::Analog(0), // Mic-0
2063        TargetPort::Analog(1), // Mic-1
2064        TargetPort::Analog(2),
2065        TargetPort::Analog(3),
2066        TargetPort::Analog(4),
2067        TargetPort::Analog(5),
2068        TargetPort::Analog(6),
2069        TargetPort::Analog(7),
2070        TargetPort::OpticalA(0),
2071        TargetPort::OpticalA(1),
2072        TargetPort::OpticalA(2),
2073        TargetPort::OpticalA(3),
2074        TargetPort::OpticalA(4),
2075        TargetPort::OpticalA(5),
2076        TargetPort::OpticalA(6),
2077        TargetPort::OpticalA(7),
2078    ];
2079    const MIC_COUNT: usize = 2;
2080    const LINE_INPUT_COUNT: usize = 0;
2081}
2082
2083impl MotuCommandDspOutputSpecification for Track16Protocol {
2084    const OUTPUT_PORTS: &'static [TargetPort] = &[
2085        TargetPort::AnalogPair(0),
2086        TargetPort::AnalogPair(1),
2087        TargetPort::PhonePair,
2088        TargetPort::OpticalAPair(0),
2089        TargetPort::OpticalAPair(1),
2090        TargetPort::OpticalAPair(2),
2091        TargetPort::OpticalAPair(3),
2092    ];
2093}
2094
2095impl MotuCommandDspMeterSpecification for Track16Protocol {
2096    const INPUT_PORTS: &'static [(TargetPort, usize)] = &[
2097        (TargetPort::Analog(0), 2),
2098        (TargetPort::Analog(1), 3),
2099        (TargetPort::Analog(2), 4),
2100        (TargetPort::Analog(3), 5),
2101        (TargetPort::Analog(4), 6),
2102        (TargetPort::Analog(5), 7),
2103        (TargetPort::Adat(0), 10),
2104        (TargetPort::Adat(1), 11),
2105        (TargetPort::Adat(2), 12),
2106        (TargetPort::Adat(3), 13),
2107        (TargetPort::Adat(4), 14),
2108        (TargetPort::Adat(5), 15),
2109        (TargetPort::Adat(6), 16),
2110        (TargetPort::Adat(7), 17),
2111    ];
2112    const OUTPUT_PORTS: &'static [(TargetPort, usize)] = &[
2113        (TargetPort::Main(0), 50),
2114        (TargetPort::Main(1), 51),
2115        (TargetPort::Analog(0), 52),
2116        (TargetPort::Analog(1), 53),
2117        (TargetPort::Phone(0), 54),
2118        (TargetPort::Adat(0), 55),
2119        (TargetPort::Adat(1), 56),
2120        (TargetPort::Adat(2), 57),
2121        (TargetPort::Adat(3), 58),
2122        (TargetPort::Adat(4), 59),
2123        (TargetPort::Adat(5), 60),
2124        (TargetPort::Adat(6), 61),
2125        (TargetPort::Adat(7), 62),
2126    ];
2127}
2128
2129impl Track16Protocol {
2130    /// Notification mask for main assignment, return assignment, and phone assignment. The change
2131    /// of phone assignment is also notified in command message.
2132    pub const NOTIFY_PORT_CHANGE: u32 = 0x40000000;
2133}
2134
2135#[cfg(test)]
2136mod test {
2137    use super::*;
2138
2139    #[test]
2140    fn opt_iface_mode_serdes() {
2141        [
2142            // For input A.
2143            (V3OptIfaceMode::Disabled, false, false, 0x00000000),
2144            (V3OptIfaceMode::Adat, false, false, 0x00000001),
2145            (V3OptIfaceMode::Spdif, false, false, 0x00010001),
2146            // For input B.
2147            (V3OptIfaceMode::Disabled, true, false, 0x00000000),
2148            (V3OptIfaceMode::Adat, true, false, 0x00000002),
2149            (V3OptIfaceMode::Spdif, true, false, 0x00100002),
2150            // For output A.
2151            (V3OptIfaceMode::Disabled, false, true, 0x00000000),
2152            (V3OptIfaceMode::Adat, false, true, 0x00000100),
2153            (V3OptIfaceMode::Spdif, false, true, 0x00040100),
2154            // For output B.
2155            (V3OptIfaceMode::Disabled, true, true, 0x00000000),
2156            (V3OptIfaceMode::Adat, true, true, 0x00000200),
2157            (V3OptIfaceMode::Spdif, true, true, 0x00400200),
2158        ]
2159        .iter()
2160        .for_each(|&(mode, is_b, is_out, val)| {
2161            let mut target = V3OptIfaceMode::default();
2162            deserialize_opt_iface_mode(&mut target, &val, is_b, is_out);
2163            assert_eq!(target, mode, "{:?},0x{:08x},{},{}", mode, val, is_b, is_out);
2164
2165            let mut quad = 0;
2166            serialize_opt_iface_mode(&mode, &mut quad, is_b, is_out);
2167            assert_eq!(quad, val, "{:?},0x{:08x},{},{}", mode, val, is_b, is_out);
2168        });
2169    }
2170
2171    #[test]
2172    fn f896mk3_aesebu_rate_convert_mode_serdes() {
2173        [
2174            F896mk3AesebuRateConvertMode::None,
2175            F896mk3AesebuRateConvertMode::InputToSystem,
2176            F896mk3AesebuRateConvertMode::OutputDependsInput,
2177            F896mk3AesebuRateConvertMode::Output441,
2178            F896mk3AesebuRateConvertMode::Output480,
2179            F896mk3AesebuRateConvertMode::Output882,
2180            F896mk3AesebuRateConvertMode::Output960,
2181        ]
2182        .iter()
2183        .for_each(|mode| {
2184            let mut quad = 0;
2185            serialize_f896mk3_aes_ebu_rate_converter_mode(mode, &mut quad);
2186
2187            let mut target = F896mk3AesebuRateConvertMode::default();
2188            deserialize_f896mk3_aes_ebu_rate_converter_mode(&mut target, &quad);
2189
2190            assert_eq!(&target, mode);
2191        });
2192    }
2193
2194    #[test]
2195    fn common_assign_port_specification() {
2196        assert_eq!(
2197            F828mk3Protocol::ASSIGN_PORT_TARGETS.len(),
2198            F828mk3Protocol::ASSIGN_PORT_VALS.len()
2199        );
2200
2201        assert_eq!(
2202            F828mk3HybridProtocol::ASSIGN_PORT_TARGETS.len(),
2203            F828mk3HybridProtocol::ASSIGN_PORT_VALS.len()
2204        );
2205
2206        assert_eq!(
2207            F896mk3Protocol::ASSIGN_PORT_TARGETS.len(),
2208            F896mk3Protocol::ASSIGN_PORT_VALS.len()
2209        );
2210
2211        assert_eq!(
2212            F896mk3HybridProtocol::ASSIGN_PORT_TARGETS.len(),
2213            F896mk3HybridProtocol::ASSIGN_PORT_VALS.len()
2214        );
2215
2216        assert_eq!(
2217            H4preProtocol::ASSIGN_PORT_TARGETS.len(),
2218            H4preProtocol::ASSIGN_PORT_VALS.len()
2219        );
2220
2221        assert_eq!(
2222            UltraliteMk3Protocol::ASSIGN_PORT_TARGETS.len(),
2223            UltraliteMk3Protocol::ASSIGN_PORT_VALS.len()
2224        );
2225
2226        assert_eq!(
2227            UltraliteMk3HybridProtocol::ASSIGN_PORT_TARGETS.len(),
2228            UltraliteMk3HybridProtocol::ASSIGN_PORT_VALS.len()
2229        );
2230
2231        assert_eq!(
2232            TravelerMk3Protocol::ASSIGN_PORT_TARGETS.len(),
2233            TravelerMk3Protocol::ASSIGN_PORT_VALS.len()
2234        );
2235
2236        assert_eq!(
2237            Track16Protocol::ASSIGN_PORT_TARGETS.len(),
2238            Track16Protocol::ASSIGN_PORT_VALS.len()
2239        );
2240    }
2241
2242    #[test]
2243    fn v3_clock_specification() {
2244        assert_eq!(
2245            AudioExpressProtocol::CLOCK_RATES.len(),
2246            AudioExpressProtocol::CLOCK_RATE_VALS.len(),
2247        );
2248        assert_eq!(
2249            AudioExpressProtocol::CLOCK_SRCS.len(),
2250            AudioExpressProtocol::CLOCK_SRC_VALS.len(),
2251        );
2252
2253        assert_eq!(
2254            F828mk3Protocol::CLOCK_RATES.len(),
2255            F828mk3Protocol::CLOCK_RATE_VALS.len(),
2256        );
2257        assert_eq!(
2258            F828mk3Protocol::CLOCK_SRCS.len(),
2259            F828mk3Protocol::CLOCK_SRC_VALS.len(),
2260        );
2261
2262        assert_eq!(
2263            F828mk3HybridProtocol::CLOCK_RATES.len(),
2264            F828mk3HybridProtocol::CLOCK_RATE_VALS.len(),
2265        );
2266        assert_eq!(
2267            F828mk3HybridProtocol::CLOCK_SRCS.len(),
2268            F828mk3HybridProtocol::CLOCK_SRC_VALS.len(),
2269        );
2270
2271        assert_eq!(
2272            F896mk3Protocol::CLOCK_RATES.len(),
2273            F896mk3Protocol::CLOCK_RATE_VALS.len(),
2274        );
2275        assert_eq!(
2276            F828mk3Protocol::CLOCK_SRCS.len(),
2277            F828mk3Protocol::CLOCK_SRC_VALS.len(),
2278        );
2279
2280        assert_eq!(
2281            F896mk3HybridProtocol::CLOCK_RATES.len(),
2282            F896mk3HybridProtocol::CLOCK_RATE_VALS.len(),
2283        );
2284        assert_eq!(
2285            F828mk3HybridProtocol::CLOCK_SRCS.len(),
2286            F828mk3HybridProtocol::CLOCK_SRC_VALS.len(),
2287        );
2288
2289        assert_eq!(
2290            H4preProtocol::CLOCK_RATES.len(),
2291            H4preProtocol::CLOCK_RATE_VALS.len(),
2292        );
2293        assert_eq!(
2294            H4preProtocol::CLOCK_SRCS.len(),
2295            H4preProtocol::CLOCK_SRC_VALS.len(),
2296        );
2297
2298        assert_eq!(
2299            UltraliteMk3Protocol::CLOCK_RATES.len(),
2300            UltraliteMk3Protocol::CLOCK_RATE_VALS.len(),
2301        );
2302        assert_eq!(
2303            UltraliteMk3Protocol::CLOCK_SRCS.len(),
2304            UltraliteMk3Protocol::CLOCK_SRC_VALS.len(),
2305        );
2306
2307        assert_eq!(
2308            UltraliteMk3HybridProtocol::CLOCK_RATES.len(),
2309            UltraliteMk3HybridProtocol::CLOCK_RATE_VALS.len(),
2310        );
2311        assert_eq!(
2312            UltraliteMk3HybridProtocol::CLOCK_SRCS.len(),
2313            UltraliteMk3HybridProtocol::CLOCK_SRC_VALS.len(),
2314        );
2315
2316        assert_eq!(
2317            TravelerMk3Protocol::CLOCK_RATES.len(),
2318            TravelerMk3Protocol::CLOCK_RATE_VALS.len(),
2319        );
2320        assert_eq!(
2321            TravelerMk3Protocol::CLOCK_SRCS.len(),
2322            TravelerMk3Protocol::CLOCK_SRC_VALS.len(),
2323        );
2324
2325        assert_eq!(
2326            Track16Protocol::CLOCK_RATES.len(),
2327            Track16Protocol::CLOCK_RATE_VALS.len(),
2328        );
2329        assert_eq!(
2330            Track16Protocol::CLOCK_SRCS.len(),
2331            Track16Protocol::CLOCK_SRC_VALS.len(),
2332        );
2333    }
2334
2335    #[test]
2336    fn register_dsp_meter_specification() {
2337        assert_eq!(
2338            AudioExpressProtocol::OUTPUT_PORT_PAIRS.len(),
2339            AudioExpressProtocol::OUTPUT_PORT_PAIR_POS.len()
2340        );
2341
2342        assert_eq!(
2343            H4preProtocol::OUTPUT_PORT_PAIRS.len(),
2344            H4preProtocol::OUTPUT_PORT_PAIR_POS.len()
2345        );
2346    }
2347}