firewire_bebob_protocols/focusrite/
saffireproio.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocol implementation for Focusrite Saffire Pro 10 i/o and Pro 26 i/o.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for protocol
7//! defined by Focusrite Audio Engineering for Saffire Pro 10 i/o and Pro 26 i/o.
8//!
9//! DM1500E ASIC is used for Saffire Pro 26 i/o, while DM1500 is used for Saffire Pro 10 i/o.
10//!
11//! ## Diagram of internal signal flow for Saffire Pro 26 i/o.
12//!
13//! ```text
14//! analog-input-1/2 ------+-----------------------> stream-output-1/2
15//! analog-input-3/4 ------|-+---------------------> stream-output-3/4
16//! analog-input-5/6 ------|-|-+-------------------> stream-output-5/6
17//! analog-input-7/8 ------|-|-|-+-----------------> stream-output-7/8
18//! spdif-input-1/2  ------|-|-|-|-+---------------> stream-output-9/10
19//! adat-input-1/2   ------|-|-|-|-|-+-------------> stream-output-11/12
20//! adat-input-3/4   ------|-|-|-|-|-|-+-----------> stream-output-13/14
21//! adat-input-5/6   ------|-|-|-|-|-|-|-+---------> stream-output-15/16
22//! adat-input-7/8   ------|-|-|-|-|-|-|-|-+-------> stream-output-17/18
23//!                        | | | | | | | | |
24//!                        v v v v v v v v v
25//!                      ++=================++
26//!                      ||     monitor     ||
27//!                      ||                 ||
28//!                      ||     18 x 2      ||
29//!                      ++=================++
30//!                                 |
31//!                                 v
32//!                        monitor-output-1/2
33//!                                 |
34//! stream-input-1/2   ------+------|-------------->
35//!                          |      +--------------> analog-output-1/2
36//!                          |      |
37//! stream-input-3/4   ------|------|-------------->
38//!                          +------|--------------> analog-output-3/4
39//!                          |      +-------------->
40//!                          |      |
41//! stream-input-5/6   ------|------|-------------->
42//!                          +------|--------------> analog-output-5/6
43//!                          |      +-------------->
44//!                          |      |
45//! stream-input-7/8   ------|------|-------------->
46//!                          +---------------------> analog-output-7/8
47//!                          |      +-------------->
48//!                          |      |
49//! stream-input-9/10  ------|------|-------------->
50//!                          +---------------------> spdif-output-1/2
51//!                          |      +-------------->
52//!                          |      |
53//! stream-input-11/12 ------|------|-------------->
54//!                          +---------------------> adat-output-1/2
55//!                          |      +-------------->
56//!                          |      |
57//! stream-input-13/14 ------|------|-------------->
58//!                          +---------------------> adat-output-3/4
59//!                          |      +-------------->
60//!                          |      |
61//! stream-input-15/16 ------|------|-------------->
62//!                          +---------------------> adat-output-5/6
63//!                          |      +-------------->
64//!                          |      |
65//! stream-input-17/18 ------|------|-------------->
66//!                          +---------------------> adat-output-7/8
67//!                                 +-------------->
68//! ```
69//!
70//! The protocol implementation for Saffire Pro 26 i/o is done with firmware version below:
71//!
72//! ```sh
73//! $ cargo run --bin bco-bootloader-info -- /dev/fw1
74//! protocol:
75//!   version: 3
76//! bootloader:
77//!   timestamp: 2006-05-30T02:56:34+0000
78//!   version: 0.0.0
79//! hardware:
80//!   GUID: 0x00030cdd00130e01
81//!   model ID: 0x000013
82//!   revision: 0.0.0
83//! software:
84//!   timestamp: 2008-09-10T03:51:13+0000
85//!   ID: 3
86//!   revision: 2.1.8386
87//! image:
88//!   base address: 0x400c0080
89//!   maximum size: 0x149334
90//! ```
91//!
92//! The protocol implementation for Saffire Pro 10 i/o is done with firmware version below:
93//!
94//! ```sh
95//! $ cargo run --bin bco-bootloader-info -- /dev/fw1
96//! protocol:
97//!   version: 3
98//! bootloader:
99//!   timestamp: 2006-11-03T11:54:44+0000
100//!   version: 0.0.0
101//! hardware:
102//!   GUID: 0x000606e000130e01
103//!   model ID: 0x000014
104//!   revision: 0.0.0
105//! software:
106//!   timestamp: 2008-09-10T03:51:12+0000
107//!   ID: 6
108//!   revision: 2.1.8386
109//! image:
110//!   base address: 0x400c0080
111//!   maximum size: 0x149174
112//! ```
113
114use super::*;
115
116/// The protocol implementation of media and sampling clocks for Saffire Pro 26 i/o. Write
117/// operation corresponding to any change takes the unit to disappear from the bus, then
118/// appears again with new configurations.
119#[derive(Default, Debug)]
120pub struct SaffirePro26ioClkProtocol;
121
122impl SaffireProioMediaClockSpecification for SaffirePro26ioClkProtocol {
123    const FREQ_LIST: &'static [u32] = &[44100, 48000, 88200, 96000, 176400, 192000];
124}
125
126impl SaffireProioSamplingClockSpecification for SaffirePro26ioClkProtocol {
127    const SRC_LIST: &'static [SaffireProioSamplingClockSource] = &[
128        SaffireProioSamplingClockSource::Internal,
129        SaffireProioSamplingClockSource::Spdif,
130        SaffireProioSamplingClockSource::Adat0,
131        SaffireProioSamplingClockSource::Adat1,
132        SaffireProioSamplingClockSource::WordClock,
133    ];
134}
135
136/// The protocol implementation of meter information in Saffire Pro 26 i/o.
137#[derive(Default, Debug)]
138pub struct SaffirePro26ioMeterProtocol;
139
140impl SaffireProioMeterOperation for SaffirePro26ioMeterProtocol {
141    const SRC_LIST: &'static [SaffireProioSamplingClockSource] = &[
142        SaffireProioSamplingClockSource::Internal,
143        SaffireProioSamplingClockSource::Spdif,
144        SaffireProioSamplingClockSource::Adat0,
145        SaffireProioSamplingClockSource::Adat1,
146        SaffireProioSamplingClockSource::WordClock,
147    ];
148}
149
150/// The protocol implementation of input monitor for Saffire Pro i/o 26.
151#[derive(Default, Debug)]
152pub struct SaffirePro26ioMonitorProtocol;
153
154impl SaffireProioMonitorSpecification for SaffirePro26ioMonitorProtocol {
155    const HAS_ADAT: bool = true;
156}
157
158/// The protocol implementaion of function specific to Saffire Pro 26 i/o
159#[derive(Default, Debug)]
160pub struct SaffirePro26ioSpecificProtocol;
161
162impl SaffireProioSpecificSpecification for SaffirePro26ioSpecificProtocol {
163    const PHANTOM_POWERING_COUNT: usize = 2;
164    const INSERT_SWAP_COUNT: usize = 2;
165}
166
167/// The protocol implementation of media and sampling clocks for Saffire Pro 10 i/o. Write
168/// operation corresponding to any change takes the unit to disappear from the bus, then
169/// appears again with new configurations.
170#[derive(Default, Debug)]
171pub struct SaffirePro10ioClkProtocol;
172
173impl SaffireProioMediaClockSpecification for SaffirePro10ioClkProtocol {
174    const FREQ_LIST: &'static [u32] = &[44100, 48000, 88200, 96000];
175}
176
177/// The protocol implementation of input monitor for Saffire Pro i/o 10.
178#[derive(Default, Debug)]
179pub struct SaffirePro10ioMonitorProtocol;
180
181impl SaffireProioMonitorSpecification for SaffirePro10ioMonitorProtocol {
182    const HAS_ADAT: bool = false;
183}
184
185/// The protocol implementaion of function specific to Saffire Pro 26 i/o
186#[derive(Default, Debug)]
187pub struct SaffirePro10ioSpecificProtocol;
188
189impl SaffireProioSpecificSpecification for SaffirePro10ioSpecificProtocol {
190    const PHANTOM_POWERING_COUNT: usize = 0;
191    const INSERT_SWAP_COUNT: usize = 0;
192}
193
194/// The protocol implementation for operation of output parameters in Saffire Pro i/o series.
195#[derive(Default, Debug)]
196pub struct SaffireProioOutputProtocol;
197
198impl SaffireOutputSpecification for SaffireProioOutputProtocol {
199    // analog-output-1/2, 3/4, 5/6, 7/8.
200    const OUTPUT_OFFSETS: &'static [usize] = &[0x140, 0x144, 0x148, 0x14c];
201
202    const MUTE_COUNT: usize = 4;
203    const VOL_COUNT: usize = 4;
204    const HWCTL_COUNT: usize = 4;
205    const DIM_COUNT: usize = 4;
206    const PAD_COUNT: usize = 4;
207}
208
209impl SaffireProioSamplingClockSpecification for SaffirePro10ioClkProtocol {
210    const SRC_LIST: &'static [SaffireProioSamplingClockSource] = &[
211        SaffireProioSamplingClockSource::Internal,
212        SaffireProioSamplingClockSource::Spdif,
213    ];
214}
215
216/// The protocol implementation of meter information in Saffire Pro 10 i/o.
217#[derive(Default, Debug)]
218pub struct SaffirePro10ioMeterProtocol;
219
220impl SaffireProioMeterOperation for SaffirePro10ioMeterProtocol {
221    const SRC_LIST: &'static [SaffireProioSamplingClockSource] = &[
222        SaffireProioSamplingClockSource::Internal,
223        SaffireProioSamplingClockSource::Spdif,
224    ];
225}
226
227/// The protocol implementation for operation of mixer in Saffire Pro i/o series.
228#[derive(Default, Debug)]
229pub struct SaffireProioMixerProtocol;
230
231/// The specification of media clock.
232pub trait SaffireProioMediaClockSpecification {
233    /// The list of supported frequency.
234    const FREQ_LIST: &'static [u32];
235}
236
237impl<O: SaffireProioMediaClockSpecification> SaffireParametersSerdes<MediaClockParameters> for O {
238    const OFFSETS: &'static [usize] = &[0x0150];
239
240    fn serialize(params: &MediaClockParameters, raw: &mut [u8]) {
241        raw.copy_from_slice(&(params.freq_idx as u32).to_be_bytes());
242    }
243
244    fn deserialize(params: &mut MediaClockParameters, raw: &[u8]) {
245        let mut quadlet = [9u8; 4];
246        quadlet.copy_from_slice(&raw[..4]);
247        let idx = u32::from_be_bytes(quadlet) as usize;
248        if idx < Self::FREQ_LIST.len() {
249            params.freq_idx = idx;
250        }
251    }
252}
253
254/// Signal source of sampling clock in Saffire Pro series.
255#[derive(Debug, Copy, Clone, PartialEq, Eq)]
256pub enum SaffireProioSamplingClockSource {
257    /// Internal source.
258    Internal,
259    /// S/PDIF input in coaxial interface.
260    Spdif,
261    /// ADAT input in 1st optical interface.
262    Adat0,
263    /// ADAT input in 2nd optical interface.
264    Adat1,
265    /// Word clock input in BNX interface.
266    WordClock,
267}
268
269impl Default for SaffireProioSamplingClockSource {
270    fn default() -> Self {
271        Self::Internal
272    }
273}
274
275/// The specification of sampling clock.
276pub trait SaffireProioSamplingClockSpecification {
277    /// The list of supported sources.
278    const SRC_LIST: &'static [SaffireProioSamplingClockSource];
279}
280
281impl<O: SaffireProioSamplingClockSpecification> SaffireParametersSerdes<SamplingClockParameters>
282    for O
283{
284    const OFFSETS: &'static [usize] = &[0x0174];
285
286    fn serialize(params: &SamplingClockParameters, raw: &mut [u8]) {
287        if let Some(val) = Self::SRC_LIST
288            .iter()
289            .nth(params.src_idx)
290            .and_then(|&src| match src {
291                SaffireProioSamplingClockSource::Internal => Some(CLK_SRC_INTERNAL),
292                SaffireProioSamplingClockSource::Spdif => Some(CLK_SRC_SPDIF),
293                SaffireProioSamplingClockSource::Adat0 => Some(CLK_SRC_ADAT0),
294                SaffireProioSamplingClockSource::Adat1 => Some(CLK_SRC_ADAT1),
295                SaffireProioSamplingClockSource::WordClock => Some(CLK_SRC_WORD_CLOCK),
296            })
297        {
298            raw.copy_from_slice(&val.to_be_bytes());
299        }
300    }
301
302    fn deserialize(params: &mut SamplingClockParameters, raw: &[u8]) {
303        let mut quadlet = [0u8; 4];
304        quadlet.copy_from_slice(&raw[..4]);
305        let val = u32::from_be_bytes(quadlet) & CLK_SRC_CONF_MASK;
306        if let Some(src_idx) = match val {
307            CLK_SRC_INTERNAL => Some(SaffireProioSamplingClockSource::Internal),
308            CLK_SRC_SPDIF => Some(SaffireProioSamplingClockSource::Spdif),
309            CLK_SRC_ADAT0 => Some(SaffireProioSamplingClockSource::Adat0),
310            CLK_SRC_ADAT1 => Some(SaffireProioSamplingClockSource::Adat1),
311            CLK_SRC_WORD_CLOCK => Some(SaffireProioSamplingClockSource::WordClock),
312            _ => None,
313        }
314        .and_then(|src| Self::SRC_LIST.iter().position(|s| s.eq(&src)))
315        {
316            params.src_idx = src_idx;
317        }
318    }
319}
320
321const CLK_SRC_EFFECTIVE_MASK: u32 = 0x0000ff00;
322const CLK_SRC_CONF_MASK: u32 = 0x000000ff;
323const CLK_SRC_INTERNAL: u32 = 0x00;
324const CLK_SRC_SPDIF: u32 = 0x02;
325const CLK_SRC_ADAT0: u32 = 0x03;
326const CLK_SRC_ADAT1: u32 = 0x04;
327const CLK_SRC_WORD_CLOCK: u32 = 0x05;
328
329/// The prorocol implementation of AC3 and MIDI signal through.
330#[derive(Default, Debug)]
331pub struct SaffireProioThroughProtocol;
332
333impl SaffireThroughSpecification for SaffireProioThroughProtocol {
334    const THROUGH_OFFSETS: &'static [usize] = &[0x019c, 0x01a0];
335}
336
337/// Information of hardware metering in Saffire Pro i/o.
338#[derive(Default, Debug)]
339pub struct SaffireProioMeterState {
340    /// The value of hardware knob.
341    pub monitor_knob: u8,
342    /// The state of mute LED.
343    pub mute_led: bool,
344    /// The state of dim LED.
345    pub dim_led: bool,
346    /// The effective source of sampling clock.
347    pub effective_clk_srcs: SaffireProioSamplingClockSource,
348}
349
350/// The trait of operation for meter information. The value of monitor knob is available only when
351/// any of hwctl in output parameter is enabled, else it's always 0x8f.
352pub trait SaffireProioMeterOperation {
353    /// The set of supported sources for sampling clock.
354    const SRC_LIST: &'static [SaffireProioSamplingClockSource];
355
356    const OFFSETS: &'static [usize] = &[
357        0x0158, // The value of hardware knob.
358        0x015c, // The state of dim LED.
359        0x0160, // The state of mute LED.
360        0x0174, // The effective source of sampling clock.
361    ];
362
363    /// Cache the state of hardware to the parameter.
364    fn cache(
365        req: &FwReq,
366        node: &FwNode,
367        state: &mut SaffireProioMeterState,
368        timeout_ms: u32,
369    ) -> Result<(), Error> {
370        let mut buf = vec![0; Self::OFFSETS.len() * 4];
371        saffire_read_quadlets(req, node, &Self::OFFSETS, &mut buf, timeout_ms).and_then(|_| {
372            let mut quadlet = [0; 4];
373            let vals = (0..Self::OFFSETS.len()).fold(Vec::new(), |mut vals, i| {
374                let pos = i * 4;
375                quadlet.copy_from_slice(&buf[pos..(pos + 4)]);
376                vals.push(u32::from_be_bytes(quadlet));
377                vals
378            });
379
380            state.monitor_knob = (vals[0] & 0xff) as u8;
381            state.mute_led = vals[1] > 0;
382            state.dim_led = vals[2] > 0;
383
384            state.effective_clk_srcs = match (vals[3] & CLK_SRC_EFFECTIVE_MASK) >> 8 {
385                CLK_SRC_INTERNAL => Ok(SaffireProioSamplingClockSource::Internal),
386                CLK_SRC_SPDIF => Ok(SaffireProioSamplingClockSource::Spdif),
387                CLK_SRC_ADAT0 => Ok(SaffireProioSamplingClockSource::Adat0),
388                CLK_SRC_ADAT1 => Ok(SaffireProioSamplingClockSource::Adat1),
389                CLK_SRC_WORD_CLOCK => Ok(SaffireProioSamplingClockSource::WordClock),
390                _ => {
391                    let msg = format!("Unexpected value for source of sampling clock: {}", vals[0]);
392                    Err(Error::new(FileError::Io, &msg))
393                }
394            }?;
395
396            Ok(())
397        })
398    }
399}
400
401/// The parameters of input monitor in Saffire Pro i/o.
402#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
403pub struct SaffireProioMonitorParameters {
404    /// The source level of analog inputs.
405    pub analog_inputs: [[i16; 8]; 2],
406    /// The source level of S/PDIF inputs.
407    pub spdif_inputs: [[i16; 2]; 2],
408    /// The source level of ADAT inputs.
409    pub adat_inputs: Option<[[i16; 16]; 2]>,
410}
411
412/// The specification of protocol for hardware metering.
413pub trait SaffireProioMonitorSpecification {
414    /// Whether to have a pair of optical interface for ADAT signal.
415    const HAS_ADAT: bool;
416
417    /// The address offsets to operate for the parameters.
418    const MONITOR_OFFSETS: &'static [usize] = &[
419        // From analog inputs, at 16 address offsets.
420        0x00, // level from analog-input-0 to monitor-output-0
421        0x04, // level from analog-input-0 to monitor-output-1
422        0x08, // level from analog-input-1 to monitor-output-0
423        0x0c, // level from analog-input-1 to monitor-output-1
424        0x10, // level from analog-input-2 to monitor-output-0
425        0x14, // level from analog-input-2 to monitor-output-1
426        0x18, // level from analog-input-3 to monitor-output-0
427        0x1c, // level from analog-input-3 to monitor-output-1
428        0x20, // level from analog-input-4 to monitor-output-0
429        0x24, // level from analog-input-4 to monitor-output-1
430        0x28, // level from analog-input-5 to monitor-output-0
431        0x2c, // level from analog-input-5 to monitor-output-1
432        0x30, // level from analog-input-6 to monitor-output-0
433        0x34, // level from analog-input-6 to monitor-output-1
434        0x38, // level from analog-input-7 to monitor-output-0
435        0x3c, // level from analog-input-7 to monitor-output-1
436        // From S/PDIF inputs, at 4 address offsets.
437        0x40, // level from spdif-input-0 to monitor-output-0
438        0x44, // level from spdif-input-1 to monitor-output-0
439        0x48, // level from spdif-input-0 to monitor-output-1
440        0x4c, // level from spdif-input-1 to monitor-output-1
441        // From ADAT inputs, at 32 address offsets.
442        0x50, // level from adat-input-a-0 to monitor-output-0
443        0x54, // level from adat-input-a-0 to monitor-output-1
444        0x58, // level from adat-input-a-1 to monitor-output-0
445        0x5c, // level from adat-input-a-1 to monitor-output-1
446        0x60, // level from adat-input-a-2 to monitor-output-0
447        0x64, // level from adat-input-a-2 to monitor-output-1
448        0x68, // level from adat-input-a-3 to monitor-output-0
449        0x6c, // level from adat-input-a-3 to monitor-output-1
450        0x70, // level from adat-input-a-4 to monitor-output-0
451        0x74, // level from adat-input-a-4 to monitor-output-1
452        0x78, // level from adat-input-a-5 to monitor-output-0
453        0x7c, // level from adat-input-a-5 to monitor-output-1
454        0x80, // level from adat-input-a-6 to monitor-output-0
455        0x84, // level from adat-input-a-6 to monitor-output-1
456        0x88, // level from adat-input-a-7 to monitor-output-0
457        0x8c, // level from adat-input-a-7 to monitor-output-1
458        0x90, // level from adat-input-b-0 to monitor-output-0
459        0x94, // level from adat-input-b-0 to monitor-output-1
460        0x98, // level from adat-input-b-1 to monitor-output-0
461        0x9c, // level from adat-input-b-1 to monitor-output-1
462        0xa0, // level from adat-input-b-2 to monitor-output-0
463        0xa4, // level from adat-input-b-2 to monitor-output-1
464        0xa8, // level from adat-input-b-3 to monitor-output-0
465        0xac, // level from adat-input-b-3 to monitor-output-1
466        0xb0, // level from adat-input-b-4 to monitor-output-0
467        0xb4, // level from adat-input-b-4 to monitor-output-1
468        0xb8, // level from adat-input-b-5 to monitor-output-0
469        0xbc, // level from adat-input-b-5 to monitor-output-1
470        0xc0, // level from adat-input-b-6 to monitor-output-0
471        0xc4, // level from adat-input-b-6 to monitor-output-1
472        0xc8, // level from adat-input-b-7 to monitor-output-0
473        0xcc, // level from adat-input-b-7 to monitor-output-1
474    ];
475}
476
477impl<O: SaffireProioMonitorSpecification> SaffireParametersSerdes<SaffireProioMonitorParameters>
478    for O
479{
480    const OFFSETS: &'static [usize] = Self::MONITOR_OFFSETS;
481
482    fn serialize(params: &SaffireProioMonitorParameters, raw: &mut [u8]) {
483        params
484            .analog_inputs
485            .iter()
486            .enumerate()
487            .for_each(|(i, gains)| {
488                gains.iter().enumerate().for_each(|(j, &gain)| {
489                    let pos = (i + j * 2) * 4;
490                    let gain = gain as i32;
491                    raw[pos..(pos + 4)].copy_from_slice(&gain.to_be_bytes());
492                });
493            });
494
495        params
496            .spdif_inputs
497            .iter()
498            .enumerate()
499            .for_each(|(i, gains)| {
500                gains.iter().enumerate().for_each(|(j, &gain)| {
501                    let pos = (16 + i + j * 2) * 4;
502                    let gain = gain as i32;
503                    raw[pos..(pos + 4)].copy_from_slice(&gain.to_be_bytes());
504                });
505            });
506
507        if let Some(adat_inputs) = &params.adat_inputs {
508            adat_inputs.iter().enumerate().for_each(|(i, gains)| {
509                gains.iter().enumerate().for_each(|(j, &gain)| {
510                    let pos = (20 + i + j * 2) * 4;
511                    let gain = gain as i32;
512                    raw[pos..(pos + 4)].copy_from_slice(&gain.to_be_bytes());
513                });
514            });
515        }
516    }
517
518    fn deserialize(params: &mut SaffireProioMonitorParameters, raw: &[u8]) {
519        let mut quadlet = [0; 4];
520
521        let quads: Vec<i16> = (0..raw.len())
522            .step_by(4)
523            .map(|pos| {
524                quadlet.copy_from_slice(&raw[pos..(pos + 4)]);
525                i32::from_be_bytes(quadlet) as i16
526            })
527            .collect();
528
529        params
530            .analog_inputs
531            .iter_mut()
532            .enumerate()
533            .for_each(|(i, gains)| {
534                gains.iter_mut().enumerate().for_each(|(j, gain)| {
535                    let pos = i + j * 2;
536                    *gain = quads[pos];
537                });
538            });
539
540        params
541            .spdif_inputs
542            .iter_mut()
543            .enumerate()
544            .for_each(|(i, gains)| {
545                gains.iter_mut().enumerate().for_each(|(j, gain)| {
546                    let pos = 16 + i + j * 2;
547                    *gain = quads[pos];
548                });
549            });
550
551        if let Some(adat_inputs) = &mut params.adat_inputs {
552            adat_inputs.iter_mut().enumerate().for_each(|(i, gains)| {
553                gains.iter_mut().enumerate().for_each(|(j, gain)| {
554                    let pos = 20 + i + j * 2;
555                    *gain = quads[pos];
556                });
557            });
558        }
559    }
560}
561
562/// The trait for input monitor protocol in Saffire Pro i/o.
563pub trait SaffireProioMonitorProtocol: SaffireProioMonitorSpecification {
564    /// The minimum value of source level.
565    const LEVEL_MIN: i16 = 0;
566    /// The maximum value of source level.
567    const LEVEL_MAX: i16 = 0x7fff;
568    /// The step value of source level.
569    const LEVEL_STEP: i16 = 0x100;
570
571    fn create_params() -> SaffireProioMonitorParameters {
572        SaffireProioMonitorParameters {
573            analog_inputs: Default::default(),
574            spdif_inputs: Default::default(),
575            adat_inputs: if Self::HAS_ADAT {
576                Some(Default::default())
577            } else {
578                None
579            },
580        }
581    }
582}
583
584impl<O: SaffireProioMonitorSpecification> SaffireProioMonitorProtocol for O {}
585
586/// The parameters of signal multiplexer in Saffire Pro i/o.
587#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
588pub struct SaffireProioMixerParameters {
589    /// The level of input sources.
590    pub monitor_sources: [i16; 10],
591    /// The level of 1st pair of stream inputs.
592    pub stream_source_pair0: [i16; 10],
593    /// The level of stream inputs.
594    pub stream_sources: [i16; 10],
595}
596
597impl SaffireParametersSerdes<SaffireProioMixerParameters> for SaffireProioMixerProtocol {
598    const OFFSETS: &'static [usize] = &[
599        // level to analog-output-0
600        0x0d0, // from stream-input-0
601        0x0d4, // from monitor-output-0
602        // level to analog-output-1
603        0x0d8, // from stream-input-1
604        0x0dc, // from monitor-output-1
605        // level to analog-out-2
606        0x0e0, // from stream-input-0
607        0x0e4, // from stream-input-2
608        0x0e8, // from monitor-output-0
609        // level to analog-out-3
610        0x0ec, // from stream-input-1
611        0x0f0, // from stream-input-3
612        0x0f4, // from monitor-output-1
613        // level to analog-out-4
614        0x0f8, // from stream-input-0
615        0x0fc, // from stream-input-4
616        0x100, // from monitor-output-0
617        // level to analog-out-5
618        0x104, // from stream-input-1
619        0x108, // from stream-input-5
620        0x10c, // from monitor-output-1
621        // level to analog-out-6
622        0x110, // from stream-input-0
623        0x114, // from stream-input-6
624        0x118, // from monitor-output-0
625        // level to analog-out-7
626        0x11c, // from stream-input-1
627        0x120, // from stream-input-7
628        0x124, // from monitor-output-1
629        // level to analog-out-8
630        0x128, // from stream-input-0
631        0x12c, // from stream-input-8
632        0x130, // from monitor-output-0
633        // level to analog-out-9
634        0x134, // from stream-input-1
635        0x138, // from stream-input-9
636        0x13c, // from monitor-output-1
637    ];
638
639    fn serialize(params: &SaffireProioMixerParameters, raw: &mut [u8]) {
640        params
641            .monitor_sources
642            .iter()
643            .enumerate()
644            .for_each(|(i, &level)| {
645                let pos = calc_monitor_source_pos(i) * 4;
646                let level = level as i32;
647                raw[pos..(pos + 4)].copy_from_slice(&level.to_be_bytes());
648            });
649
650        params
651            .stream_source_pair0
652            .iter()
653            .enumerate()
654            .for_each(|(i, &level)| {
655                let pos = calc_stream_source_pair0_pos(i) * 4;
656                let level = level as i32;
657                raw[pos..(pos + 4)].copy_from_slice(&level.to_be_bytes());
658            });
659
660        params
661            .stream_sources
662            .iter()
663            .enumerate()
664            .for_each(|(i, &level)| {
665                let pos = calc_stream_source_pos(i) * 4;
666                let level = level as i32;
667                raw[pos..(pos + 4)].copy_from_slice(&level.to_be_bytes());
668            });
669    }
670
671    fn deserialize(params: &mut SaffireProioMixerParameters, raw: &[u8]) {
672        let mut quadlet = [0; 4];
673
674        let quads: Vec<i16> = (0..raw.len())
675            .step_by(4)
676            .map(|pos| {
677                quadlet.copy_from_slice(&raw[pos..(pos + 4)]);
678                i32::from_be_bytes(quadlet) as i16
679            })
680            .collect();
681
682        params
683            .monitor_sources
684            .iter_mut()
685            .enumerate()
686            .for_each(|(i, level)| {
687                let pos = calc_monitor_source_pos(i);
688                *level = quads[pos];
689            });
690
691        params
692            .stream_source_pair0
693            .iter_mut()
694            .enumerate()
695            .for_each(|(i, level)| {
696                let pos = calc_stream_source_pair0_pos(i);
697                *level = quads[pos];
698            });
699
700        params
701            .stream_sources
702            .iter_mut()
703            .enumerate()
704            .for_each(|(i, level)| {
705                let pos = calc_stream_source_pos(i);
706                *level = quads[pos];
707            });
708    }
709}
710
711impl SaffireProioMixerProtocol {
712    /// The minimum value of source level.
713    pub const LEVEL_MIN: i16 = 0;
714    /// The maximum value of source level.
715    pub const LEVEL_MAX: i16 = 0x7fff;
716    /// The step value of source level.
717    pub const LEVEL_STEP: i16 = 0x100;
718}
719
720fn calc_monitor_source_pos(i: usize) -> usize {
721    if i < 2 {
722        1 + i * 2
723    } else {
724        6 + (i - 2) * 3
725    }
726}
727
728fn calc_stream_source_pair0_pos(i: usize) -> usize {
729    if i < 2 {
730        i * 2
731    } else {
732        4 + (i - 2) * 3
733    }
734}
735
736fn calc_stream_source_pos(i: usize) -> usize {
737    if i < 2 {
738        i * 2
739    } else {
740        5 + (i - 2) * 3
741    }
742}
743
744/// Working mode at standalone mode.
745#[derive(Debug, Copy, Clone, Eq, PartialEq)]
746pub enum SaffireProioStandaloneMode {
747    /// For mixing.
748    Mix,
749    /// For tracking.
750    Track,
751}
752
753impl Default for SaffireProioStandaloneMode {
754    fn default() -> Self {
755        Self::Mix
756    }
757}
758
759/// Parameters specific to Saffire Pro i/o series.
760#[derive(Debug, Clone, PartialEq, Eq)]
761pub struct SaffireProioSpecificParameters {
762    /// Whether to increase head room for analog inputs.
763    pub head_room: bool,
764    /// Whether to enable/disable phantom powering for microphone inputs.
765    pub phantom_powerings: Vec<bool>,
766    /// Whether to use line input 5/6 for inserts to input 1/2.
767    pub insert_swaps: Vec<bool>,
768    /// The mode of standalone.
769    pub standalone_mode: SaffireProioStandaloneMode,
770    /// Whether to use ADAT or not.
771    pub adat_enabled: bool,
772    /// Whether to enable direct monitoring.
773    pub direct_monitoring: bool,
774}
775
776/// The specification of protocol for function specific to Pro i/o.
777pub trait SaffireProioSpecificSpecification {
778    /// The address offsets to operate for the parameters.
779    const SPECIFIC_OFFSETS: &'static [usize] = &[
780        0x016c, 0x0188, // Phantom powering for microphone input 5-8.
781        0x018c, // Phantom powering for microphone input 1-4.
782        0x0190, // Ese 5th line input as insert.
783        0x0194, // Ese 6th line input as insert.
784        // 0x0198, any write operation blights LED.
785        0x01bc, // The mode at standalone.
786        0x01c0, // Enable/Disable ADAT inputs/outputs.
787        0x01c8, // Enable/Disable direct monitoring.
788    ];
789
790    /// The number of microphone inputs supporting phantom powering.
791    const PHANTOM_POWERING_COUNT: usize;
792
793    /// The number of line inputs supporting polarity.
794    const INSERT_SWAP_COUNT: usize;
795}
796
797// MEMO: The write transaction to enable/disable ADAT inputs/outputs generates bus reset.
798impl<O: SaffireProioSpecificSpecification> SaffireParametersSerdes<SaffireProioSpecificParameters>
799    for O
800{
801    const OFFSETS: &'static [usize] = Self::SPECIFIC_OFFSETS;
802
803    fn serialize(params: &SaffireProioSpecificParameters, raw: &mut [u8]) {
804        raw[..4].copy_from_slice(&(params.head_room as u32).to_be_bytes());
805
806        params
807            .phantom_powerings
808            .iter()
809            .rev()
810            .enumerate()
811            .for_each(|(i, &enabled)| {
812                let pos = 4 + i * 4;
813                raw[pos..(pos + 4)].copy_from_slice(&(enabled as u32).to_be_bytes());
814            });
815
816        params
817            .insert_swaps
818            .iter()
819            .enumerate()
820            .for_each(|(i, &enabled)| {
821                let pos = 12 + i * 4;
822                raw[pos..(pos + 4)].copy_from_slice(&(enabled as u32).to_be_bytes());
823            });
824
825        let val = (params.standalone_mode == SaffireProioStandaloneMode::Track) as u32;
826        raw[20..24].copy_from_slice(&val.to_be_bytes());
827
828        raw[24..28].copy_from_slice(&(!params.adat_enabled as u32).to_be_bytes());
829        raw[28..32].copy_from_slice(&(params.direct_monitoring as u32).to_be_bytes());
830    }
831
832    fn deserialize(params: &mut SaffireProioSpecificParameters, raw: &[u8]) {
833        let mut quadlet = [0; 4];
834
835        let quads: Vec<i16> = (0..raw.len())
836            .step_by(4)
837            .map(|pos| {
838                quadlet.copy_from_slice(&raw[pos..(pos + 4)]);
839                i32::from_be_bytes(quadlet) as i16
840            })
841            .collect();
842
843        params.head_room = quads[0] > 0;
844
845        params
846            .phantom_powerings
847            .iter_mut()
848            .rev()
849            .enumerate()
850            .for_each(|(i, enabled)| *enabled = quads[1 + i] > 0);
851
852        params
853            .insert_swaps
854            .iter_mut()
855            .enumerate()
856            .for_each(|(i, enabled)| *enabled = quads[3 + i] > 0);
857
858        params.standalone_mode = if quads[5] > 0 {
859            SaffireProioStandaloneMode::Track
860        } else {
861            SaffireProioStandaloneMode::Mix
862        };
863
864        params.adat_enabled = quads[6] == 0;
865        params.direct_monitoring = quads[7] > 0;
866    }
867}
868
869/// The protocol implementation for functions specific to Saffire Pro i/o series. The change
870/// operation to enable/disable ADAT corresponds to bus reset.
871pub trait SaffireProioSpecificOperation: SaffireProioSpecificSpecification {
872    fn create_params() -> SaffireProioSpecificParameters {
873        SaffireProioSpecificParameters {
874            head_room: Default::default(),
875            phantom_powerings: vec![Default::default(); Self::PHANTOM_POWERING_COUNT],
876            insert_swaps: vec![Default::default(); Self::INSERT_SWAP_COUNT],
877            standalone_mode: Default::default(),
878            adat_enabled: Default::default(),
879            direct_monitoring: Default::default(),
880        }
881    }
882}
883
884impl<O: SaffireProioSpecificSpecification> SaffireProioSpecificOperation for O {}
885
886/// The protocol implementation to store configuration in Saffire.
887#[derive(Default, Debug)]
888pub struct SaffireProioStoreConfigProtocol;
889
890impl SaffireStoreConfigSpecification for SaffireProioStoreConfigProtocol {
891    const STORE_CONFIG_OFFSETS: &'static [usize] = &[0x1b0];
892}
893
894#[cfg(test)]
895mod test {
896    use super::*;
897
898    #[test]
899    fn saffireproio_output_protocol_serdes() {
900        let mut params = SaffireProioOutputProtocol::create_output_parameters();
901
902        params
903            .mutes
904            .iter_mut()
905            .step_by(2)
906            .for_each(|mute| *mute = true);
907
908        params
909            .vols
910            .iter_mut()
911            .enumerate()
912            .for_each(|(i, vol)| *vol = i as u8);
913
914        params
915            .hwctls
916            .iter_mut()
917            .step_by(2)
918            .for_each(|hwctl| *hwctl = true);
919
920        params
921            .dims
922            .iter_mut()
923            .step_by(2)
924            .for_each(|dim| *dim = true);
925
926        params
927            .pads
928            .iter_mut()
929            .step_by(2)
930            .for_each(|pad| *pad = true);
931
932        let mut raw = vec![0u8; SaffireProioOutputProtocol::OFFSETS.len() * 4];
933        SaffireProioOutputProtocol::serialize(&params, &mut raw);
934        let mut p = SaffireProioOutputProtocol::create_output_parameters();
935        SaffireProioOutputProtocol::deserialize(&mut p, &raw);
936
937        assert_eq!(params, p);
938    }
939
940    #[test]
941    fn saffirepro10io_monitor_protocol_serdes() {
942        let params = SaffireProioMonitorParameters {
943            analog_inputs: [
944                [45, 89, -17, -90, -28, 95, 32, -51],
945                [-2, -43, -34, 69, 27, 14, 37, 10],
946            ],
947            spdif_inputs: [[84, 46], [42, -20]],
948            adat_inputs: None,
949        };
950        let mut raw = vec![0u8; SaffirePro10ioMonitorProtocol::OFFSETS.len() * 4];
951        SaffirePro10ioMonitorProtocol::serialize(&params, &mut raw);
952        let mut p = SaffirePro10ioMonitorProtocol::create_params();
953        SaffirePro10ioMonitorProtocol::deserialize(&mut p, &raw);
954
955        assert_eq!(params, p);
956    }
957
958    #[test]
959    fn saffirepro26io_monitor_protocol_serdes() {
960        let params = SaffireProioMonitorParameters {
961            analog_inputs: [
962                [45, 89, -17, -90, -28, 95, 32, -51],
963                [-2, -43, -34, 69, 27, 14, 37, 10],
964            ],
965            spdif_inputs: [[84, 46], [42, -20]],
966            adat_inputs: Some([
967                [
968                    38, 9, 20, 4, -9, 82, -41, -14, 88, -18, 58, 1, -98, -26, 54, 21,
969                ],
970                [
971                    58, 66, 42, -36, -50, 36, 50, -77, -99, -49, 52, -78, -51, -80, -40, 94,
972                ],
973            ]),
974        };
975        let mut raw = vec![0u8; SaffirePro26ioMonitorProtocol::OFFSETS.len() * 4];
976        SaffirePro26ioMonitorProtocol::serialize(&params, &mut raw);
977        let mut p = SaffirePro26ioMonitorProtocol::create_params();
978        SaffirePro26ioMonitorProtocol::deserialize(&mut p, &raw);
979
980        assert_eq!(params, p);
981    }
982
983    #[test]
984    fn saffirepro10io_specific_protocol_serdes() {
985        let mut params = SaffirePro10ioSpecificProtocol::create_params();
986        params.standalone_mode = SaffireProioStandaloneMode::Track;
987        params.adat_enabled = true;
988        params.direct_monitoring = true;
989        let mut raw = vec![0u8; SaffirePro10ioSpecificProtocol::OFFSETS.len() * 4];
990        SaffirePro10ioSpecificProtocol::serialize(&params, &mut raw);
991        let mut p = SaffirePro10ioSpecificProtocol::create_params();
992        SaffirePro10ioSpecificProtocol::deserialize(&mut p, &raw);
993
994        assert_eq!(params, p);
995    }
996
997    #[test]
998    fn saffirepro26io_specific_protocol_serdes() {
999        let mut params = SaffirePro26ioSpecificProtocol::create_params();
1000        params.phantom_powerings[0] = true;
1001        params.phantom_powerings[1] = false;
1002        params.insert_swaps[0] = false;
1003        params.insert_swaps[1] = true;
1004        params.standalone_mode = SaffireProioStandaloneMode::Track;
1005        params.adat_enabled = true;
1006        params.direct_monitoring = true;
1007        let mut raw = vec![0u8; SaffirePro26ioSpecificProtocol::OFFSETS.len() * 4];
1008        SaffirePro26ioSpecificProtocol::serialize(&params, &mut raw);
1009        let mut p = SaffirePro26ioSpecificProtocol::create_params();
1010        SaffirePro26ioSpecificProtocol::deserialize(&mut p, &raw);
1011
1012        assert_eq!(params, p);
1013    }
1014
1015    #[test]
1016    #[should_panic(expected = "expected to fail")]
1017    fn saffireproio_mixer_protocol_serdes() {
1018        let params = SaffireProioMixerParameters {
1019            monitor_sources: [-6, 25, 32, 76, 91, 57, -21, 88, 9, -87],
1020            stream_source_pair0: [84, -65, 59, 2, -21, 96, 40, 67, 72, 30],
1021            stream_sources: [-78, -75, -58, 86, 16, 59, 41, 88, 57, 24],
1022        };
1023        let mut raw = vec![0u8; SaffireProioMixerProtocol::OFFSETS.len() * 4];
1024        SaffireProioMixerProtocol::serialize(&params, &mut raw);
1025        let mut p = SaffireProioMixerParameters::default();
1026        SaffireProioMixerProtocol::deserialize(&mut p, &raw);
1027
1028        assert_eq!(params, p, "expected to fail");
1029    }
1030
1031    #[test]
1032    fn saffireproio_through_protocol_serdes() {
1033        let params = SaffireThroughParameters {
1034            midi: true,
1035            ac3: true,
1036        };
1037        let mut raw = vec![0u8; SaffireProioThroughProtocol::OFFSETS.len() * 4];
1038        SaffireProioThroughProtocol::serialize(&params, &mut raw);
1039        let mut p = SaffireThroughParameters::default();
1040        SaffireProioThroughProtocol::deserialize(&mut p, &raw);
1041
1042        assert_eq!(params, p);
1043    }
1044
1045    #[test]
1046    fn saffirepro10io_media_clock_serdes() {
1047        let mut raw = [0u8; 4];
1048        (0..SaffirePro10ioClkProtocol::FREQ_LIST.len()).for_each(|freq_idx| {
1049            let params = MediaClockParameters { freq_idx };
1050            SaffirePro10ioClkProtocol::serialize(&params, &mut raw);
1051            let mut p = MediaClockParameters::default();
1052            SaffirePro10ioClkProtocol::deserialize(&mut p, &raw);
1053            assert_eq!(params, p);
1054        });
1055    }
1056
1057    #[test]
1058    fn saffirepro26io_media_clock_serdes() {
1059        let mut raw = [0u8; 4];
1060        (0..SaffirePro26ioClkProtocol::FREQ_LIST.len()).for_each(|freq_idx| {
1061            let params = MediaClockParameters { freq_idx };
1062            SaffirePro26ioClkProtocol::serialize(&params, &mut raw);
1063            let mut p = MediaClockParameters::default();
1064            SaffirePro26ioClkProtocol::deserialize(&mut p, &raw);
1065            assert_eq!(params, p);
1066        });
1067    }
1068
1069    #[test]
1070    fn saffirepro10io_sampling_clock_serdes() {
1071        let mut raw = [0u8; 4];
1072        (0..SaffirePro10ioClkProtocol::SRC_LIST.len()).for_each(|src_idx| {
1073            let params = SamplingClockParameters { src_idx };
1074            SaffirePro10ioClkProtocol::serialize(&params, &mut raw);
1075            let mut p = SamplingClockParameters::default();
1076            SaffirePro10ioClkProtocol::deserialize(&mut p, &raw);
1077            assert_eq!(params, p);
1078        });
1079    }
1080
1081    #[test]
1082    fn saffirepro26io_sampling_clock_serdes() {
1083        let mut raw = [0u8; 4];
1084        (0..SaffirePro26ioClkProtocol::SRC_LIST.len()).for_each(|src_idx| {
1085            let params = SamplingClockParameters { src_idx };
1086            SaffirePro26ioClkProtocol::serialize(&params, &mut raw);
1087            let mut p = SamplingClockParameters::default();
1088            SaffirePro26ioClkProtocol::deserialize(&mut p, &raw);
1089            assert_eq!(params, p);
1090        });
1091    }
1092
1093    #[test]
1094    fn test_mixer_offset_helpers() {
1095        assert_eq!(calc_monitor_source_pos(0), 1);
1096        assert_eq!(calc_monitor_source_pos(1), 3);
1097        assert_eq!(calc_monitor_source_pos(2), 6);
1098        assert_eq!(calc_monitor_source_pos(3), 9);
1099        assert_eq!(calc_monitor_source_pos(4), 12);
1100        assert_eq!(calc_monitor_source_pos(5), 15);
1101        assert_eq!(calc_monitor_source_pos(6), 18);
1102        assert_eq!(calc_monitor_source_pos(7), 21);
1103        assert_eq!(calc_monitor_source_pos(8), 24);
1104        assert_eq!(calc_monitor_source_pos(9), 27);
1105
1106        assert_eq!(calc_stream_source_pair0_pos(0), 0);
1107        assert_eq!(calc_stream_source_pair0_pos(1), 2);
1108        assert_eq!(calc_stream_source_pair0_pos(2), 4);
1109        assert_eq!(calc_stream_source_pair0_pos(3), 7);
1110        assert_eq!(calc_stream_source_pair0_pos(4), 10);
1111        assert_eq!(calc_stream_source_pair0_pos(5), 13);
1112        assert_eq!(calc_stream_source_pair0_pos(6), 16);
1113        assert_eq!(calc_stream_source_pair0_pos(7), 19);
1114        assert_eq!(calc_stream_source_pair0_pos(8), 22);
1115        assert_eq!(calc_stream_source_pair0_pos(9), 25);
1116
1117        assert_eq!(calc_stream_source_pos(0), 0);
1118        assert_eq!(calc_stream_source_pos(1), 2);
1119        assert_eq!(calc_stream_source_pos(2), 5);
1120        assert_eq!(calc_stream_source_pos(3), 8);
1121        assert_eq!(calc_stream_source_pos(4), 11);
1122        assert_eq!(calc_stream_source_pos(5), 14);
1123        assert_eq!(calc_stream_source_pos(6), 17);
1124        assert_eq!(calc_stream_source_pos(7), 20);
1125        assert_eq!(calc_stream_source_pos(8), 23);
1126        assert_eq!(calc_stream_source_pos(9), 26);
1127    }
1128}