firewire_dice_protocols/
avid.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! Hardware specification and application protocol specific to Avid Mbox 3 Pro
5//!
6//! The module includes structure, enumeration, and trait and its implementation for hardware
7//! specification and application protocol specific to Avid Mbox 3 Pro.
8//!
9//! ## Diagram of internal signal flow
10//!
11//! ```text
12//!
13//! XLR input 1 -----------------+-------+-------> analog-input-1/2
14//! Phone input 1 ---------------+       |
15//!                                      |
16//! XLR input 2 -----------------+-------+
17//! Phone input 2 ---------------+
18//!
19//! XLR input 3 -----------------+-------+-------> analog-input-3/4
20//! Phone input 3 ---------------+       |
21//!                                      |
22//! XLR input 4 -----------------+-------+
23//! Phone input 4 ---------------+
24//!
25//! RCA input 5/6 ---------------or--------------> analog-input-5/6
26//! Mini Phone ------------------+
27//! coaxial input 1/2 ---------------------------> spdif-input-1/2
28//!
29//!                          ++=============++
30//! analog-input-1/2 ------> ||             || --> analog-output-1/2
31//! analog-input-3/4 ------> ||             || --> analog-output-3/4
32//! analog-input-5/6 ------> ||             || --> analog-output-5/6
33//! spdif-input-1/2 -------> ||             || --> spdif-output-1/2
34//!                          ||             ||
35//!                          ||             || --> headphone-output-1/2
36//!                          ||             || --> headphone-output-3/4
37//!                          ||   34 x 42   ||
38//! reberb-output-1/2 -----> ||             || --> reverb-input-1/2
39//!                          ||   router    ||
40//! stream-input-1/2 ------> ||             || --> stream-output-1/2
41//! stream-input-3/4 ------> ||   up to     || --> stream-output-3/4
42//! stream-input-5/6 ------> ||             || --> stream-output-5/6
43//! stream-input-7/8 ------> || 128 entries || --> stream-output-7/8
44//!                          ||             ||
45//! mixer-output-1/2 ------> ||             || --> mixer-input-1/2
46//! mixer-output-3/4 ------> ||             || --> mixer-input-3/4
47//! mixer-output-5/6 ------> ||             || --> mixer-input-5/6
48//! mixer-output-7/8 ------> ||             || --> mixer-input-7/8
49//! mixer-output-9/10 -----> ||             || --> mixer-input-9/10
50//! mixer-output-11/12 ----> ||             || --> mixer-input-11/12
51//! mixer-output-13/14 ----> ||             || --> mixer-input-13/14
52//! mixer-output-15/16 ----> ||             || --> mixer-input-15/16
53//!                          ||             || --> mixer-input-17/18
54//!                          ||             ||
55//!                          ||             || --> control-room-output-1/2
56//!                          ++=============++
57//!
58//!                          ++=============++
59//! reverb-input-1/2 ------> ||    reverb   || --> reverb-output-1/2
60//!                          ||    effect   ||
61//!                          ++=============++
62//!
63//!                          ++=============++
64//! mixer-input-1/2 -------> ||             || --> mixer-output-1/2
65//! mixer-input-3/4 -------> ||             || --> mixer-output-3/4
66//! mixer-input-5/6 -------> ||             || --> mixer-output-5/6
67//! mixer-input-7/8 -------> ||   18 x 16   || --> mixer-output-7/8
68//! mixer-input-9/10 ------> ||             || --> mixer-output-9/10
69//! mixer-input-11/11 -----> ||    mixer    || --> mixer-output-11/12
70//! mixer-input-13/14 -----> ||             || --> mixer-output-13/14
71//! mixer-input-15/16 -----> ||             || --> mixer-output-15/16
72//! mixer-input-17/18 -----> ||             ||
73//!                          ++=============++
74//!
75//! analog-output-1/2 ---------------------------> Phone output 1/2
76//! analog-output-3/4 ---------------------------> Phone output 3/4
77//! analog-output-5/6 ---------------------------> Phone output 5/6
78//!
79//! headphone-output-1/2 ------------------------> Headphone output 1/2
80//! headphone-output-3/4 ------------------------> Headphone output 3/4
81//!
82//! spdif-output-1/2 ----------------------------> Coaxial output 1/2
83//!
84//! ```
85
86use super::{
87    tcat::{extension::*, tcd22xx_spec::*, *},
88    *,
89};
90
91// const USE_CASE_OFFSET: usize = 0x00;
92// (0x04 is unclear)
93// const MASTER_KNOB_VALUE_OFFSET: usize = 0x08;
94// const MASTER_KNOB_ASSIGN_OFFSET: usize = 0x0c;
95// const MUTE_BUTTON_LED_OFFSET: usize = 0x10;
96// const MONO_BUTTON_LED_OFFSET: usize = 0x14;  // 0x08 enables playback routing to analog input 3/4.
97// const SPKR_BUTTON_LED_OFFSET: usize = 0x14;
98// const ALL_LEDS_BRIGHTNESS_OFFSET: usize = 0x18;   // 0x00 - 0x7f.
99// const FORCE_LEDS_BRIGHTNESS_OFFSET: usize = 0x1c;   // 0x00 - 0x7f.
100// const BUTTON_HOLD_DURATION_OFFSET: usize = 0x20;
101// const HPF_ENABLE_OFFSET: usize = 0x24; // High pass filter for analog inputs.
102// const OUT_0_TRIM_OFFSET: usize = 0x28;
103// const OUT_1_TRIM_OFFSET: usize = 0x2c;
104// const OUT_2_TRIM_OFFSET: usize = 0x30;
105// const OUT_3_TRIM_OFFSET: usize = 0x34;
106// const OUT_4_TRIM_OFFSET: usize = 0x38;
107// const OUT_5_TRIM_OFFSET: usize = 0x3c;
108// const REVERB_TYPE_OFFSET: usize = 0x40;
109// const REVERB_VOLUME_OFFSET: usize = 0x44;
110// const REVERB_DURATION_OFFSET: usize = 0x48;
111// const REVERB_FEEDBACK_OFFSET: usize = 0x4c;
112
113/// Protocol implementation of Avid Mbox 3 Pro.
114#[derive(Default, Debug)]
115pub struct Mbox3Protocol;
116
117impl TcatOperation for Mbox3Protocol {}
118
119impl TcatGlobalSectionSpecification for Mbox3Protocol {}
120
121impl TcatExtensionOperation for Mbox3Protocol {}
122
123impl Tcd22xxSpecification for Mbox3Protocol {
124    const INPUTS: &'static [Input] = &[
125        Input {
126            id: SrcBlkId::Ins0,
127            offset: 0,
128            count: 6,
129            label: None,
130        },
131        Input {
132            id: SrcBlkId::Ins1,
133            offset: 0,
134            count: 2,
135            label: Some("Reverb"),
136        },
137        Input {
138            id: SrcBlkId::Aes,
139            offset: 0,
140            count: 2,
141            label: None,
142        },
143    ];
144    const OUTPUTS: &'static [Output] = &[
145        Output {
146            id: DstBlkId::Ins0,
147            offset: 0,
148            count: 6,
149            label: None,
150        },
151        Output {
152            id: DstBlkId::Ins1,
153            offset: 0,
154            count: 4,
155            label: Some("Headphone"),
156        },
157        Output {
158            id: DstBlkId::Ins1,
159            offset: 4,
160            count: 2,
161            label: Some("Reverb"),
162        },
163        Output {
164            id: DstBlkId::Aes,
165            offset: 0,
166            count: 2,
167            label: None,
168        },
169        Output {
170            id: DstBlkId::Reserved(0x08),
171            offset: 0,
172            count: 2,
173            label: Some("ControlRoom"),
174        },
175    ];
176    const FIXED: &'static [SrcBlk] = &[
177        SrcBlk {
178            id: SrcBlkId::Ins0,
179            ch: 0,
180        },
181        SrcBlk {
182            id: SrcBlkId::Ins0,
183            ch: 1,
184        },
185        SrcBlk {
186            id: SrcBlkId::Ins0,
187            ch: 2,
188        },
189        SrcBlk {
190            id: SrcBlkId::Ins0,
191            ch: 3,
192        },
193    ];
194}
195
196/// Usecase of standalone mode.
197#[derive(Debug, Copy, Clone, PartialEq, Eq)]
198pub enum StandaloneUseCase {
199    /// For microphone pre-amplifier.
200    Preamp,
201    /// For A/D and D/A conversion.
202    AdDa,
203    /// For signal mixing.
204    Mixer,
205    /// Not decided yet.
206    Undefined,
207}
208
209impl Default for StandaloneUseCase {
210    fn default() -> Self {
211        Self::Preamp
212    }
213}
214
215impl StandaloneUseCase {
216    const MIXER: u32 = 0x00;
217    const AD_DA: u32 = 0x01;
218    const PREAMP: u32 = 0x02;
219    const UNDEFINED: u32 = 0x03;
220
221    const MASK: u32 = 0x03;
222}
223
224fn serialize_standalone_use_case(
225    use_case: &StandaloneUseCase,
226    raw: &mut [u8],
227) -> Result<(), String> {
228    assert!(raw.len() >= 4);
229
230    let mut val = 0u32;
231    deserialize_u32(&mut val, raw);
232
233    let flag = match use_case {
234        StandaloneUseCase::Mixer => StandaloneUseCase::MIXER,
235        StandaloneUseCase::AdDa => StandaloneUseCase::AD_DA,
236        StandaloneUseCase::Preamp => StandaloneUseCase::PREAMP,
237        StandaloneUseCase::Undefined => StandaloneUseCase::UNDEFINED,
238    };
239
240    val &= !StandaloneUseCase::MASK;
241    val |= flag;
242    serialize_u32(&val, raw);
243
244    Ok(())
245}
246
247fn deserialize_standalone_use_case(
248    use_case: &mut StandaloneUseCase,
249    raw: &[u8],
250) -> Result<(), String> {
251    assert!(raw.len() >= 4);
252
253    let mut val = 0u32;
254    deserialize_u32(&mut val, raw);
255
256    val &= StandaloneUseCase::MASK;
257    *use_case = match val {
258        StandaloneUseCase::MIXER => StandaloneUseCase::Mixer,
259        StandaloneUseCase::AD_DA => StandaloneUseCase::AdDa,
260        StandaloneUseCase::PREAMP => StandaloneUseCase::Preamp,
261        _ => StandaloneUseCase::Undefined,
262    };
263
264    Ok(())
265}
266
267const MASTER_KNOB_MASK: u32 = 0x0000003f;
268
269fn serialize_master_knob_assigns(assigns: &[bool; 6], raw: &mut [u8]) -> Result<(), String> {
270    assert!(raw.len() >= 4);
271
272    let mut val = 0u32;
273    deserialize_u32(&mut val, raw);
274    val &= !MASTER_KNOB_MASK;
275
276    assigns
277        .iter()
278        .enumerate()
279        .filter(|(_, &assign)| assign)
280        .for_each(|(i, _)| val |= 1 << i);
281    serialize_u32(&val, raw);
282
283    Ok(())
284}
285
286fn deserialize_master_knob_assigns(assigns: &mut [bool; 6], raw: &[u8]) -> Result<(), String> {
287    assert!(raw.len() >= 4);
288
289    let mut val = 0u32;
290    deserialize_u32(&mut val, raw);
291    assigns
292        .iter_mut()
293        .enumerate()
294        .for_each(|(i, assign)| *assign = val & (1 << i) > 0);
295
296    Ok(())
297}
298
299/// LED state of mute button.
300#[derive(Debug, Copy, Clone, PartialEq, Eq)]
301pub enum MuteLedState {
302    /// Turn Off.
303    Off,
304    /// Blink.
305    Blink,
306    /// Turn on.
307    On,
308}
309
310impl Default for MuteLedState {
311    fn default() -> Self {
312        Self::Off
313    }
314}
315
316impl MuteLedState {
317    const LED_MASK: u32 = 0x00000003;
318    const LED_BLINK_MASK: u32 = 0x00000001;
319}
320
321fn serialize_mute_led_state(state: &MuteLedState, raw: &mut [u8]) -> Result<(), String> {
322    assert!(raw.len() >= 4);
323
324    let mut val = 0u32;
325    deserialize_u32(&mut val, raw);
326    val &= !MuteLedState::LED_MASK;
327
328    match state {
329        MuteLedState::Off => (),
330        MuteLedState::Blink => val |= MuteLedState::LED_BLINK_MASK,
331        MuteLedState::On => val |= MuteLedState::LED_MASK & !MuteLedState::LED_BLINK_MASK,
332    }
333
334    serialize_u32(&val, raw);
335
336    Ok(())
337}
338
339fn deserialize_mute_led_state(state: &mut MuteLedState, raw: &[u8]) -> Result<(), String> {
340    assert!(raw.len() >= 4);
341
342    let mut val = 0u32;
343    deserialize_u32(&mut val, raw);
344
345    *state = if val & MuteLedState::LED_MASK == 0 {
346        MuteLedState::Off
347    } else if val & MuteLedState::LED_BLINK_MASK > 0 {
348        MuteLedState::Blink
349    } else {
350        MuteLedState::On
351    };
352
353    Ok(())
354}
355
356/// LED state of mono button.
357#[derive(Debug, Copy, Clone, PartialEq, Eq)]
358pub enum MonoLedState {
359    /// Turn off.
360    Off,
361    /// Turn on.
362    On,
363}
364
365impl Default for MonoLedState {
366    fn default() -> Self {
367        Self::Off
368    }
369}
370
371impl MonoLedState {
372    const LED_MASK: u32 = 0x0000000c;
373}
374
375fn serialize_mono_led_state(state: &MonoLedState, raw: &mut [u8]) -> Result<(), String> {
376    assert!(raw.len() >= 4);
377
378    let mut val = 0u32;
379    deserialize_u32(&mut val, raw);
380    val &= !MonoLedState::LED_MASK;
381
382    match state {
383        MonoLedState::Off => (),
384        MonoLedState::On => val |= MonoLedState::LED_MASK,
385    }
386
387    serialize_u32(&val, raw);
388
389    Ok(())
390}
391
392fn deserialize_mono_led_state(state: &mut MonoLedState, raw: &[u8]) -> Result<(), String> {
393    assert!(raw.len() >= 4);
394
395    let mut val = 0u32;
396    deserialize_u32(&mut val, raw);
397
398    *state = if val & MonoLedState::LED_MASK > 0 {
399        MonoLedState::On
400    } else {
401        MonoLedState::Off
402    };
403
404    Ok(())
405}
406
407/// LED state of spkr button.
408#[derive(Debug, Copy, Clone, PartialEq, Eq)]
409pub enum SpkrLedState {
410    /// Turn off.
411    Off,
412    /// Green light.
413    Green,
414    /// Blinking green light.
415    GreenBlink,
416    /// Red light.
417    Red,
418    /// Blinking red light.
419    RedBlink,
420    /// Orange light.
421    Orange,
422    /// Blinking orange light.
423    OrangeBlink,
424}
425
426impl Default for SpkrLedState {
427    fn default() -> Self {
428        Self::Off
429    }
430}
431
432impl SpkrLedState {
433    const COLOR_MASK: u32 = 0x00000060;
434    const COLOR_SHIFT: usize = 5;
435    const BLINK_MASK: u32 = 0x00000010;
436    const BLINK_SHIFT: u32 = 4;
437
438    const NONE: u32 = 0;
439    const GREEN: u32 = 1;
440    const RED: u32 = 2;
441    const ORANGE: u32 = 3;
442}
443
444fn serialize_spkr_led_state(state: &SpkrLedState, raw: &mut [u8]) -> Result<(), String> {
445    assert!(raw.len() >= 4);
446
447    let mut val = 0u32;
448    deserialize_u32(&mut val, raw);
449    val &= !(SpkrLedState::COLOR_MASK | SpkrLedState::BLINK_MASK);
450
451    let (color, blink) = match state {
452        SpkrLedState::GreenBlink => (SpkrLedState::GREEN, true),
453        SpkrLedState::Green => (SpkrLedState::GREEN, false),
454        SpkrLedState::RedBlink => (SpkrLedState::RED, true),
455        SpkrLedState::Red => (SpkrLedState::RED, false),
456        SpkrLedState::OrangeBlink => (SpkrLedState::RED, true),
457        SpkrLedState::Orange => (SpkrLedState::ORANGE, false),
458        SpkrLedState::Off => (SpkrLedState::NONE, false),
459    };
460
461    val |= color << SpkrLedState::COLOR_SHIFT;
462    if blink {
463        val |= SpkrLedState::BLINK_MASK;
464    }
465
466    serialize_u32(&val, raw);
467
468    Ok(())
469}
470
471fn deserialize_spkr_led_state(state: &mut SpkrLedState, raw: &[u8]) -> Result<(), String> {
472    assert!(raw.len() >= 4);
473
474    let mut val = 0u32;
475    deserialize_u32(&mut val, raw);
476
477    let color = (val & SpkrLedState::COLOR_MASK) >> SpkrLedState::COLOR_SHIFT;
478    let blink = (val & SpkrLedState::BLINK_MASK) >> SpkrLedState::BLINK_SHIFT > 0;
479
480    *state = match color {
481        SpkrLedState::NONE => SpkrLedState::Off,
482        SpkrLedState::GREEN => {
483            if blink {
484                SpkrLedState::GreenBlink
485            } else {
486                SpkrLedState::Green
487            }
488        }
489        SpkrLedState::RED => {
490            if blink {
491                SpkrLedState::RedBlink
492            } else {
493                SpkrLedState::Red
494            }
495        }
496        SpkrLedState::ORANGE => {
497            if blink {
498                SpkrLedState::OrangeBlink
499            } else {
500                SpkrLedState::Orange
501            }
502        }
503        _ => Err(format!("Speaker LED state not found for value {}", val))?,
504    };
505
506    Ok(())
507}
508
509const PHANTOM_POWERING_MASK: u32 = 0x00000001;
510const INPUT_HPF_ENABLES_MASK: u32 = 0x000000f0;
511const INPUT_HPF_ENABLES_SHIFT: usize = 4;
512
513fn serialize_phantom_powering(enable: &bool, raw: &mut [u8]) -> Result<(), String> {
514    assert!(raw.len() >= 4);
515
516    let mut val = 0u32;
517    deserialize_u32(&mut val, raw);
518    val &= !PHANTOM_POWERING_MASK;
519
520    if *enable {
521        val |= PHANTOM_POWERING_MASK;
522    }
523
524    serialize_u32(&val, raw);
525
526    Ok(())
527}
528
529fn deserialize_phantom_powering(enable: &mut bool, raw: &[u8]) -> Result<(), String> {
530    assert!(raw.len() >= 4);
531
532    let mut val = 0u32;
533    deserialize_u32(&mut val, raw);
534
535    *enable = val & PHANTOM_POWERING_MASK > 0;
536
537    Ok(())
538}
539
540fn serialize_hpf_enables(enables: &[bool; 4], raw: &mut [u8]) -> Result<(), String> {
541    assert!(raw.len() >= 4);
542
543    let mut val = 0u32;
544    deserialize_u32(&mut val, raw);
545    val &= !INPUT_HPF_ENABLES_MASK;
546
547    enables
548        .iter()
549        .enumerate()
550        .filter(|(_, &enabled)| enabled)
551        .for_each(|(i, _)| val |= 1 << (i + INPUT_HPF_ENABLES_SHIFT));
552
553    serialize_u32(&val, raw);
554
555    Ok(())
556}
557
558fn deserialize_hpf_enables(enables: &mut [bool; 4], raw: &[u8]) -> Result<(), String> {
559    assert!(raw.len() >= 4);
560
561    let mut val = 0u32;
562    deserialize_u32(&mut val, raw);
563
564    enables
565        .iter_mut()
566        .enumerate()
567        .for_each(|(i, enabled)| *enabled = val & (1 << (i + INPUT_HPF_ENABLES_SHIFT)) > 0);
568
569    Ok(())
570}
571
572fn serialize_output_trims(trims: &[u8; 6], raw: &mut [u8]) -> Result<(), String> {
573    assert!(raw.len() >= 24);
574
575    trims.iter().enumerate().for_each(|(i, &trim)| {
576        let pos = i * 4;
577        serialize_u8(&(u8::MAX - trim), &mut raw[pos..(pos + 4)]);
578    });
579
580    Ok(())
581}
582
583fn deserialize_output_trims(trims: &mut [u8; 6], raw: &[u8]) -> Result<(), String> {
584    assert!(raw.len() >= 24);
585
586    let mut val = 0u8;
587    trims.iter_mut().enumerate().for_each(|(i, trim)| {
588        let pos = i * 4;
589        deserialize_u8(&mut val, &raw[pos..(pos + 4)]);
590        *trim = u8::MAX - val;
591    });
592
593    Ok(())
594}
595
596/// Type of reverb DSP.
597#[derive(Debug, Copy, Clone, PartialEq, Eq)]
598pub enum ReverbType {
599    /// Room 1.
600    Room1,
601    /// Room 2.
602    Room2,
603    /// Room 3.
604    Room3,
605    /// Hall 1.
606    Hall1,
607    /// Hall 2.
608    Hall2,
609    /// Plate.
610    Plate,
611    /// Delay.
612    Delay,
613    /// Echo.
614    Echo,
615}
616
617impl Default for ReverbType {
618    fn default() -> Self {
619        Self::Room1
620    }
621}
622
623impl ReverbType {
624    const ROOM_1: u32 = 0x01;
625    const ROOM_2: u32 = 0x04;
626    const ROOM_3: u32 = 0x05;
627    const HALL_1: u32 = 0x06;
628    const HALL_2: u32 = 0x08;
629    const PLATE: u32 = 0x0b;
630    const DELAY: u32 = 0x13;
631    const ECHO: u32 = 0x14;
632}
633
634fn serialize_reverb_type(reverb_type: &ReverbType, raw: &mut [u8]) -> Result<(), String> {
635    assert!(raw.len() >= 4);
636
637    let val = match reverb_type {
638        ReverbType::Room1 => ReverbType::ROOM_1,
639        ReverbType::Room2 => ReverbType::ROOM_2,
640        ReverbType::Room3 => ReverbType::ROOM_3,
641        ReverbType::Hall1 => ReverbType::HALL_1,
642        ReverbType::Hall2 => ReverbType::HALL_2,
643        ReverbType::Plate => ReverbType::PLATE,
644        ReverbType::Delay => ReverbType::DELAY,
645        ReverbType::Echo => ReverbType::ECHO,
646    };
647    serialize_u32(&val, raw);
648
649    Ok(())
650}
651
652fn deserialize_reverb_type(reverb_type: &mut ReverbType, raw: &[u8]) -> Result<(), String> {
653    assert!(raw.len() >= 4);
654
655    let mut val = 0u32;
656    deserialize_u32(&mut val, raw);
657
658    *reverb_type = match val {
659        ReverbType::ROOM_1 => ReverbType::Room1,
660        ReverbType::ROOM_2 => ReverbType::Room2,
661        ReverbType::ROOM_3 => ReverbType::Room3,
662        ReverbType::HALL_1 => ReverbType::Hall1,
663        ReverbType::HALL_2 => ReverbType::Hall2,
664        ReverbType::PLATE => ReverbType::Plate,
665        ReverbType::DELAY => ReverbType::Delay,
666        ReverbType::ECHO => ReverbType::Echo,
667        _ => Err(format!("Reverb type not found for value {}", val))?,
668    };
669
670    Ok(())
671}
672
673/// Parameters specific to Mbox 3 pro.
674#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
675pub struct Mbox3SpecificParams {
676    /// Usecase at standalone mode.
677    pub standalone_use_case: StandaloneUseCase,
678    /// State of master knob.
679    pub master_knob_value: u8,
680    /// Assignment map for master knob.
681    pub master_knob_assigns: [bool; 6],
682    /// State of mute LED.
683    pub mute_led: MuteLedState,
684    /// State of mono LED.
685    pub mono_led: MonoLedState,
686    /// State of spkr LED.
687    pub spkr_led: SpkrLedState,
688    /// Whether to use dim LED.
689    pub dim_led: bool,
690    /// Duration till being activate by holding button.
691    pub duration_hold: u8,
692    /// Whether to supply phantom powering.
693    pub phantom_powering: bool,
694    /// Whether to enable High Pass Filter.
695    pub hpf_enables: [bool; 4],
696    /// Volume of analog outputs.
697    pub output_trims: [u8; 6],
698    /// The type of reverb.
699    pub reverb_type: ReverbType,
700    /// Volume of reverb return.
701    pub reverb_volume: u8,
702    /// Duration of reverb.
703    pub reverb_duration: u8,
704    /// Feedback of reverb.
705    pub reverb_feedback: u8,
706}
707
708const MIN_SIZE: usize = 0x50;
709
710fn serialize(params: &Mbox3SpecificParams, raw: &mut [u8]) -> Result<(), String> {
711    assert!(raw.len() >= MIN_SIZE);
712
713    serialize_standalone_use_case(&params.standalone_use_case, &mut raw[..0x04])?;
714    serialize_u8(&params.master_knob_value, &mut raw[0x08..0x0c]);
715    serialize_master_knob_assigns(&params.master_knob_assigns, &mut raw[0x0c..0x10])?;
716    serialize_mute_led_state(&params.mute_led, &mut raw[0x10..0x14])?;
717    serialize_mono_led_state(&params.mono_led, &mut raw[0x14..0x18])?;
718    serialize_spkr_led_state(&params.spkr_led, &mut raw[0x14..0x18])?;
719    serialize_bool(&params.dim_led, &mut raw[0x1c..0x20]);
720    serialize_u8(&params.duration_hold, &mut raw[0x20..0x24]);
721    serialize_phantom_powering(&params.phantom_powering, &mut raw[0x24..0x28])?;
722    serialize_hpf_enables(&params.hpf_enables, &mut raw[0x24..0x28])?;
723    serialize_output_trims(&params.output_trims, &mut raw[0x28..0x40])?;
724    serialize_reverb_type(&params.reverb_type, &mut raw[0x40..0x44])?;
725    serialize_u8(&params.reverb_volume, &mut raw[0x44..0x48]);
726    serialize_u8(&params.reverb_duration, &mut raw[0x48..0x4c]);
727    serialize_u8(&params.reverb_feedback, &mut raw[0x4c..0x50]);
728
729    Ok(())
730}
731
732fn deserialize(params: &mut Mbox3SpecificParams, raw: &[u8]) -> Result<(), String> {
733    assert!(raw.len() >= MIN_SIZE);
734
735    deserialize_standalone_use_case(&mut params.standalone_use_case, &raw[..0x04])?;
736    deserialize_u8(&mut params.master_knob_value, &raw[0x08..0x0c]);
737    deserialize_master_knob_assigns(&mut params.master_knob_assigns, &raw[0x0c..0x10])?;
738    deserialize_mute_led_state(&mut params.mute_led, &raw[0x10..0x14])?;
739    deserialize_mono_led_state(&mut params.mono_led, &raw[0x14..0x18])?;
740    deserialize_spkr_led_state(&mut params.spkr_led, &raw[0x14..0x18])?;
741    deserialize_bool(&mut params.dim_led, &raw[0x1c..0x20]);
742    deserialize_u8(&mut params.duration_hold, &raw[0x20..0x24]);
743    deserialize_phantom_powering(&mut params.phantom_powering, &raw[0x24..0x28])?;
744    deserialize_hpf_enables(&mut params.hpf_enables, &raw[0x24..0x28])?;
745    deserialize_output_trims(&mut params.output_trims, &raw[0x28..0x40])?;
746    deserialize_reverb_type(&mut params.reverb_type, &raw[0x40..0x44])?;
747    deserialize_u8(&mut params.reverb_volume, &raw[0x44..0x48]);
748    deserialize_u8(&mut params.reverb_duration, &raw[0x48..0x4c]);
749    deserialize_u8(&mut params.reverb_feedback, &raw[0x4c..0x50]);
750
751    Ok(())
752}
753
754const PHANTOM_POWERING_CHANGED: u32 = 0x10000000;
755const MASTER_KNOB_CHANGED: u32 = 0x08000000;
756const SPKR_BUTTON_PUSHED: u32 = 0x04000000;
757const SPKR_BUTTON_HELD: u32 = 0x02000000;
758const MONO_BUTTON_PUSHED: u32 = 0x00800000;
759const MUTE_BUTTON_PUSHED: u32 = 0x00400000;
760const MUTE_BUTTON_HELD: u32 = 0x00200000;
761
762impl TcatExtensionSectionParamsOperation<Mbox3SpecificParams> for Mbox3Protocol {
763    fn cache_extension_whole_params(
764        req: &FwReq,
765        node: &FwNode,
766        sections: &ExtensionSections,
767        _: &ExtensionCaps,
768        params: &mut Mbox3SpecificParams,
769        timeout_ms: u32,
770    ) -> Result<(), Error> {
771        let mut raw = vec![0u8; MIN_SIZE];
772        Self::read_extension(req, node, &sections.application, 0, &mut raw, timeout_ms)?;
773        deserialize(params, &raw).map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
774    }
775}
776
777impl TcatExtensionSectionPartialMutableParamsOperation<Mbox3SpecificParams> for Mbox3Protocol {
778    fn update_extension_partial_params(
779        req: &FwReq,
780        node: &FwNode,
781        sections: &ExtensionSections,
782        _: &ExtensionCaps,
783        params: &Mbox3SpecificParams,
784        prev: &mut Mbox3SpecificParams,
785        timeout_ms: u32,
786    ) -> Result<(), Error> {
787        let mut new = vec![0u8; MIN_SIZE];
788        serialize(params, &mut new)
789            .map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
790
791        let mut old = vec![0u8; MIN_SIZE];
792        serialize(prev, &mut old)
793            .map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
794
795        (0..MIN_SIZE).step_by(4).try_for_each(|pos| {
796            if new[pos..(pos + 4)] != old[pos..(pos + 4)] {
797                Self::write_extension(
798                    req,
799                    node,
800                    &sections.application,
801                    pos,
802                    &mut new[pos..(pos + 4)],
803                    timeout_ms,
804                )
805            } else {
806                Ok(())
807            }
808        })?;
809
810        deserialize(prev, &new).map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
811    }
812}
813
814impl TcatExtensionSectionNotifiedParamsOperation<Mbox3SpecificParams> for Mbox3Protocol {
815    fn cache_extension_notified_params(
816        req: &FwReq,
817        node: &FwNode,
818        sections: &ExtensionSections,
819        caps: &ExtensionCaps,
820        params: &mut Mbox3SpecificParams,
821        msg: u32,
822        timeout_ms: u32,
823    ) -> Result<(), Error> {
824        if msg & (PHANTOM_POWERING_CHANGED | MASTER_KNOB_CHANGED) > 0 {
825            Self::cache_extension_whole_params(req, node, sections, caps, params, timeout_ms)?;
826        }
827
828        let mut p = params.clone();
829        if msg & SPKR_BUTTON_PUSHED > 0 {
830            p.spkr_led = match params.spkr_led {
831                SpkrLedState::Off => SpkrLedState::Green,
832                SpkrLedState::GreenBlink => SpkrLedState::Green,
833                SpkrLedState::Green => SpkrLedState::Red,
834                SpkrLedState::RedBlink => SpkrLedState::Red,
835                SpkrLedState::Red => SpkrLedState::Orange,
836                SpkrLedState::OrangeBlink => SpkrLedState::Orange,
837                SpkrLedState::Orange => SpkrLedState::Off,
838            };
839        }
840
841        if msg & SPKR_BUTTON_HELD > 0 {
842            p.spkr_led = match params.spkr_led {
843                SpkrLedState::Off => SpkrLedState::Off,
844                SpkrLedState::GreenBlink => SpkrLedState::Green,
845                SpkrLedState::Green => SpkrLedState::GreenBlink,
846                SpkrLedState::RedBlink => SpkrLedState::Red,
847                SpkrLedState::Red => SpkrLedState::RedBlink,
848                SpkrLedState::OrangeBlink => SpkrLedState::Orange,
849                SpkrLedState::Orange => SpkrLedState::OrangeBlink,
850            };
851        }
852
853        if msg & MONO_BUTTON_PUSHED > 0 {
854            p.mono_led = match params.mono_led {
855                MonoLedState::Off => MonoLedState::On,
856                MonoLedState::On => MonoLedState::Off,
857            };
858        }
859
860        if msg & MUTE_BUTTON_PUSHED > 0 {
861            p.mute_led = match params.mute_led {
862                MuteLedState::Off => MuteLedState::On,
863                MuteLedState::Blink => MuteLedState::On,
864                MuteLedState::On => MuteLedState::Off,
865            };
866        }
867
868        if msg & MUTE_BUTTON_HELD > 0 {
869            p.mute_led = match params.mute_led {
870                MuteLedState::Off => MuteLedState::Off,
871                MuteLedState::Blink => MuteLedState::On,
872                MuteLedState::On => MuteLedState::Blink,
873            };
874        }
875
876        if !p.eq(params) {
877            Self::update_extension_partial_params(
878                req, node, sections, caps, &p, params, timeout_ms,
879            )?;
880        }
881
882        Ok(())
883    }
884}
885
886#[cfg(test)]
887mod test {
888    use super::*;
889
890    #[test]
891    fn mbox3_specific_params_serdes() {
892        let params = Mbox3SpecificParams {
893            standalone_use_case: StandaloneUseCase::AdDa,
894            master_knob_value: 0xf9,
895            master_knob_assigns: [true, false, true, true, false, true],
896            mute_led: MuteLedState::Blink,
897            mono_led: MonoLedState::On,
898            spkr_led: SpkrLedState::RedBlink,
899            dim_led: false,
900            duration_hold: 10,
901            phantom_powering: true,
902            hpf_enables: [false, false, true, false],
903            output_trims: [0, 1, 2, 3, 4, 5],
904            reverb_type: ReverbType::Hall2,
905            reverb_volume: 0xb3,
906            reverb_duration: 0xa5,
907            reverb_feedback: 0x17,
908        };
909
910        let mut raw = [0; MIN_SIZE];
911        serialize(&params, &mut raw).unwrap();
912
913        let mut p = Mbox3SpecificParams::default();
914        deserialize(&mut p, &raw).unwrap();
915
916        assert_eq!(params, p);
917    }
918}