1use super::{tcat::tcd22xx_spec::*, *};
111
112#[derive(Default, Debug)]
121pub struct LiquidS56Protocol;
122
123impl TcatOperation for LiquidS56Protocol {}
124
125impl TcatGlobalSectionSpecification for LiquidS56Protocol {}
126
127impl TcatExtensionOperation for LiquidS56Protocol {}
128
129impl Tcd22xxSpecification for LiquidS56Protocol {
130 const INPUTS: &'static [Input] = &[
131 Input {
132 id: SrcBlkId::Ins0,
133 offset: 0,
134 count: 2,
135 label: None,
136 },
137 Input {
138 id: SrcBlkId::Ins1,
139 offset: 2,
140 count: 6,
141 label: None,
142 },
143 Input {
144 id: SrcBlkId::Adat,
145 offset: 0,
146 count: 8,
147 label: None,
148 },
149 Input {
150 id: SrcBlkId::Aes,
151 offset: 0,
152 count: 2,
153 label: Some("S/PDIF-coax"),
154 },
155 Input {
157 id: SrcBlkId::Adat,
158 offset: 8,
159 count: 8,
160 label: None,
161 },
162 Input {
163 id: SrcBlkId::Aes,
164 offset: 6,
165 count: 2,
166 label: Some("S/PDIF-opt"),
167 },
168 ];
169 const OUTPUTS: &'static [Output] = &[
170 Output {
171 id: DstBlkId::Ins0,
172 offset: 0,
173 count: 2,
174 label: None,
175 },
176 Output {
177 id: DstBlkId::Ins1,
178 offset: 0,
179 count: 8,
180 label: None,
181 },
182 Output {
183 id: DstBlkId::Adat,
184 offset: 0,
185 count: 8,
186 label: None,
187 },
188 Output {
189 id: DstBlkId::Aes,
190 offset: 0,
191 count: 2,
192 label: Some("S/PDIF-coax"),
193 },
194 Output {
196 id: DstBlkId::Adat,
197 offset: 8,
198 count: 8,
199 label: None,
200 },
201 Output {
202 id: DstBlkId::Aes,
203 offset: 6,
204 count: 2,
205 label: Some("S/PDIF-opt"),
206 },
207 ];
208 const FIXED: &'static [SrcBlk] = &[
211 SrcBlk {
212 id: SrcBlkId::Ins1,
213 ch: 0,
214 },
215 SrcBlk {
216 id: SrcBlkId::Ins1,
217 ch: 1,
218 },
219 SrcBlk {
220 id: SrcBlkId::Ins1,
221 ch: 2,
222 },
223 SrcBlk {
224 id: SrcBlkId::Ins1,
225 ch: 3,
226 },
227 SrcBlk {
228 id: SrcBlkId::Ins1,
229 ch: 4,
230 },
231 SrcBlk {
232 id: SrcBlkId::Ins1,
233 ch: 5,
234 },
235 SrcBlk {
236 id: SrcBlkId::Ins1,
237 ch: 6,
238 },
239 SrcBlk {
240 id: SrcBlkId::Ins1,
241 ch: 7,
242 },
243 SrcBlk {
244 id: SrcBlkId::Aes,
245 ch: 0,
246 },
247 SrcBlk {
248 id: SrcBlkId::Aes,
249 ch: 1,
250 },
251 SrcBlk {
252 id: SrcBlkId::Adat,
253 ch: 0,
254 },
255 SrcBlk {
256 id: SrcBlkId::Adat,
257 ch: 1,
258 },
259 SrcBlk {
260 id: SrcBlkId::Adat,
261 ch: 2,
262 },
263 SrcBlk {
264 id: SrcBlkId::Adat,
265 ch: 3,
266 },
267 SrcBlk {
268 id: SrcBlkId::Adat,
269 ch: 4,
270 },
271 SrcBlk {
272 id: SrcBlkId::Adat,
273 ch: 5,
274 },
275 SrcBlk {
276 id: SrcBlkId::Adat,
277 ch: 6,
278 },
279 SrcBlk {
280 id: SrcBlkId::Adat,
281 ch: 7,
282 },
283 SrcBlk {
284 id: SrcBlkId::Adat,
285 ch: 8,
286 },
287 SrcBlk {
288 id: SrcBlkId::Adat,
289 ch: 9,
290 },
291 SrcBlk {
292 id: SrcBlkId::Adat,
293 ch: 10,
294 },
295 SrcBlk {
296 id: SrcBlkId::Adat,
297 ch: 11,
298 },
299 SrcBlk {
300 id: SrcBlkId::Adat,
301 ch: 12,
302 },
303 SrcBlk {
304 id: SrcBlkId::Adat,
305 ch: 13,
306 },
307 SrcBlk {
308 id: SrcBlkId::Adat,
309 ch: 14,
310 },
311 SrcBlk {
312 id: SrcBlkId::Adat,
313 ch: 15,
314 },
315 ];
316}
317
318impl SaffireproSwNoticeOperation for LiquidS56Protocol {
319 const SW_NOTICE_OFFSET: usize = 0x02c8;
320}
321
322const SRC_SW_NOTICE: u32 = 0x00000001;
323const DIM_MUTE_SW_NOTICE: u32 = 0x00000003;
324const MIC_AMP_1_HARMONICS_SW_NOTICE: u32 = 0x00000006;
325const MIC_AMP_2_HARMONICS_SW_NOTICE: u32 = 0x00000007;
326const MIC_AMP_1_EMULATION_SW_NOTICE: u32 = 0x00000008;
327const MIC_AMP_2_EMULATION_SW_NOTICE: u32 = 0x00000009;
328const MIC_AMP_POLARITY_SW_NOTICE: u32 = 0x0000000a;
329const INPUT_LEVEL_SW_NOTICE: u32 = 0x0000000b;
330
331impl SaffireproOutGroupSpecification for LiquidS56Protocol {
332 const OUT_GROUP_STATE_OFFSET: usize = 0x000c;
333
334 const ENTRY_COUNT: usize = 10;
335 const HAS_VOL_HWCTL: bool = true;
336
337 const SRC_NOTICE: u32 = SRC_SW_NOTICE;
338 const DIM_MUTE_NOTICE: u32 = DIM_MUTE_SW_NOTICE;
339}
340
341impl SaffireproIoParamsSpecification for LiquidS56Protocol {
342 const AESEBU_IS_SUPPORTED: bool = true;
343 const MIC_PREAMP_TRANSFORMER_IS_SUPPORTED: bool = true;
344}
345
346#[derive(Debug, Copy, Clone, PartialEq, Eq)]
348pub enum MicAmpEmulationType {
349 Flat,
350 Trany1h,
351 Silver2,
352 FfRed1h,
353 Savillerow,
354 Dunk,
355 ClassA2a,
356 OldTube,
357 Deutsch72,
358 Stellar1b,
359 NewAge,
360}
361
362impl Default for MicAmpEmulationType {
363 fn default() -> Self {
364 Self::Flat
365 }
366}
367
368impl MicAmpEmulationType {
369 const FLAT_VALUE: u32 = 0;
370 const TRANY1H_VALUE: u32 = 1;
371 const SILVER2_VALUE: u32 = 2;
372 const FFRED1H_VALUE: u32 = 3;
373 const SAVILLEROW_VALUE: u32 = 4;
374 const DUNK_VALUE: u32 = 5;
375 const CLASSA2A_VALUE: u32 = 6;
376 const OLDTUBE_VALUE: u32 = 7;
377 const DEUTSCH72_VALUE: u32 = 8;
378 const STELLAR1B_VALUE: u32 = 9;
379 const NEWAGE_VALUE: u32 = 10;
380}
381
382fn serialize_mic_amp_emulation_types(
383 emulation_types: &[MicAmpEmulationType; 2],
384 raw: &mut [u8],
385) -> Result<(), String> {
386 assert!(raw.len() >= 8);
387
388 emulation_types
389 .iter()
390 .enumerate()
391 .for_each(|(i, emulation_type)| {
392 let pos = i * 4;
393 let val = match emulation_type {
394 MicAmpEmulationType::Flat => MicAmpEmulationType::FLAT_VALUE,
395 MicAmpEmulationType::Trany1h => MicAmpEmulationType::TRANY1H_VALUE,
396 MicAmpEmulationType::Silver2 => MicAmpEmulationType::SILVER2_VALUE,
397 MicAmpEmulationType::FfRed1h => MicAmpEmulationType::FFRED1H_VALUE,
398 MicAmpEmulationType::Savillerow => MicAmpEmulationType::SAVILLEROW_VALUE,
399 MicAmpEmulationType::Dunk => MicAmpEmulationType::DUNK_VALUE,
400 MicAmpEmulationType::ClassA2a => MicAmpEmulationType::CLASSA2A_VALUE,
401 MicAmpEmulationType::OldTube => MicAmpEmulationType::OLDTUBE_VALUE,
402 MicAmpEmulationType::Deutsch72 => MicAmpEmulationType::DEUTSCH72_VALUE,
403 MicAmpEmulationType::Stellar1b => MicAmpEmulationType::STELLAR1B_VALUE,
404 MicAmpEmulationType::NewAge => MicAmpEmulationType::NEWAGE_VALUE,
405 };
406 serialize_u32(&val, &mut raw[pos..(pos + 4)]);
407 });
408
409 Ok(())
410}
411
412fn deserialize_mic_amp_emulation_types(
413 emulation_types: &mut [MicAmpEmulationType; 2],
414 raw: &[u8],
415) -> Result<(), String> {
416 assert!(raw.len() >= 8);
417
418 let mut val = 0u32;
419
420 emulation_types
421 .iter_mut()
422 .enumerate()
423 .try_for_each(|(i, emulation_type)| {
424 let pos = i * 4;
425 deserialize_u32(&mut val, &raw[pos..(pos + 4)]);
426
427 *emulation_type = match val {
428 MicAmpEmulationType::FLAT_VALUE => MicAmpEmulationType::Flat,
429 MicAmpEmulationType::TRANY1H_VALUE => MicAmpEmulationType::Trany1h,
430 MicAmpEmulationType::SILVER2_VALUE => MicAmpEmulationType::Silver2,
431 MicAmpEmulationType::FFRED1H_VALUE => MicAmpEmulationType::FfRed1h,
432 MicAmpEmulationType::SAVILLEROW_VALUE => MicAmpEmulationType::Savillerow,
433 MicAmpEmulationType::DUNK_VALUE => MicAmpEmulationType::Dunk,
434 MicAmpEmulationType::CLASSA2A_VALUE => MicAmpEmulationType::ClassA2a,
435 MicAmpEmulationType::OLDTUBE_VALUE => MicAmpEmulationType::OldTube,
436 MicAmpEmulationType::DEUTSCH72_VALUE => MicAmpEmulationType::Deutsch72,
437 MicAmpEmulationType::STELLAR1B_VALUE => MicAmpEmulationType::Stellar1b,
438 MicAmpEmulationType::NEWAGE_VALUE => MicAmpEmulationType::NewAge,
439 _ => Err(format!(
440 "Mic amplifier emulation type not found for value: {}",
441 val
442 ))?,
443 };
444
445 Ok(())
446 })
447}
448
449fn serialize_mic_amp_harmonics(harmonics: &[u8; 2], raw: &mut [u8]) -> Result<(), String> {
450 assert!(raw.len() >= 8);
451
452 harmonics.iter().enumerate().for_each(|(i, h)| {
453 let pos = i * 4;
454 serialize_u8(h, &mut raw[pos..(pos + 4)]);
455 });
456
457 Ok(())
458}
459
460fn deserialize_mic_amp_harmonics(harmonics: &mut [u8; 2], raw: &[u8]) -> Result<(), String> {
461 assert!(raw.len() >= 8);
462
463 harmonics.iter_mut().enumerate().for_each(|(i, h)| {
464 let pos = i * 4;
465 deserialize_u8(h, &raw[pos..(pos + 4)]);
466 });
467
468 Ok(())
469}
470
471fn serialize_mic_amp_polarities(polarities: &[bool; 2], raw: &mut [u8]) -> Result<(), String> {
472 assert!(raw.len() >= 8);
473
474 polarities.iter().enumerate().for_each(|(i, polarity)| {
475 let pos = i * 4;
476 serialize_bool(polarity, &mut raw[pos..(pos + 4)]);
477 });
478
479 Ok(())
480}
481
482fn deserialize_mic_amp_polarities(polarities: &mut [bool; 2], raw: &[u8]) -> Result<(), String> {
483 assert!(raw.len() >= 8);
484
485 polarities.iter_mut().enumerate().for_each(|(i, polarity)| {
486 let pos = i * 4;
487 deserialize_bool(polarity, &raw[pos..(pos + 4)]);
488 });
489
490 Ok(())
491}
492
493#[derive(Debug, Copy, Clone, PartialEq, Eq)]
495pub enum AnalogInputLevel {
496 Line,
497 Mic,
498 Inst,
500}
501
502impl Default for AnalogInputLevel {
503 fn default() -> Self {
504 Self::Line
505 }
506}
507
508impl AnalogInputLevel {
509 const LINE_VALUE: u8 = 0;
510 const MIC_VALUE: u8 = 1;
511 const INST_VALUE: u8 = 2;
512}
513
514fn serialize_analog_input_levels(
515 levels: &[AnalogInputLevel; 8],
516 raw: &mut [u8],
517) -> Result<(), String> {
518 assert!(raw.len() >= 8);
519
520 (0..levels.len()).step_by(4).for_each(|pos| {
521 let mut val = 0u32;
522 levels[pos..(pos + 4)]
523 .iter()
524 .enumerate()
525 .for_each(|(j, level)| {
526 let v = match level {
527 AnalogInputLevel::Line => AnalogInputLevel::LINE_VALUE,
528 AnalogInputLevel::Mic => AnalogInputLevel::MIC_VALUE,
529 AnalogInputLevel::Inst => AnalogInputLevel::INST_VALUE,
530 };
531 val |= (v as u32) << (j * 8);
532 });
533 serialize_u32(&val, &mut raw[pos..(pos + 4)]);
534 });
535
536 Ok(())
537}
538
539fn deserialize_analog_input_levels(
540 levels: &mut [AnalogInputLevel; 8],
541 raw: &[u8],
542) -> Result<(), String> {
543 assert!(raw.len() >= 8);
544
545 let mut val = 0u32;
546
547 (0..levels.len()).step_by(4).try_for_each(|pos| {
548 deserialize_u32(&mut val, &raw[pos..(pos + 4)]);
549
550 levels[pos..(pos + 4)]
551 .iter_mut()
552 .enumerate()
553 .try_for_each(|(j, level)| {
554 let v = ((val >> (j * 8)) & 0x000000ff) as u8;
555 *level = match v {
556 AnalogInputLevel::LINE_VALUE => AnalogInputLevel::Line,
557 AnalogInputLevel::MIC_VALUE => AnalogInputLevel::Mic,
558 AnalogInputLevel::INST_VALUE => AnalogInputLevel::Inst,
559 _ => Err(format!("Analog input level not found for value: {}", val))?,
560 };
561 Ok(())
562 })
563 })
564}
565
566#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
568pub struct LedState {
569 pub adat1: bool,
571 pub adat2: bool,
573 pub spdif: bool,
575 pub midi_in: bool,
577}
578
579impl LedState {
580 const ADAT1_FLAG: u32 = 0x00000001;
581 const ADAT2_FLAG: u32 = 0x00000002;
582 const SPDIF_FLAG: u32 = 0x00000004;
583 const MIDI_IN_FLAG: u32 = 0x00000008;
584}
585
586fn serialize_led_state(state: &LedState, raw: &mut [u8]) -> Result<(), String> {
587 assert!(raw.len() >= 4);
588
589 let mut val = 0u32;
590
591 [
592 (&state.adat1, LedState::ADAT1_FLAG),
593 (&state.adat2, LedState::ADAT2_FLAG),
594 (&state.spdif, LedState::SPDIF_FLAG),
595 (&state.midi_in, LedState::MIDI_IN_FLAG),
596 ]
597 .iter_mut()
598 .filter(|(&on, _)| on)
599 .for_each(|(_, flag)| val |= *flag);
600
601 serialize_u32(&val, raw);
602
603 Ok(())
604}
605
606fn deserialize_led_state(state: &mut LedState, raw: &[u8]) -> Result<(), String> {
607 assert!(raw.len() >= 4);
608
609 let mut val = 0u32;
610 deserialize_u32(&mut val, raw);
611
612 [
613 (&mut state.adat1, LedState::ADAT1_FLAG),
614 (&mut state.adat2, LedState::ADAT2_FLAG),
615 (&mut state.spdif, LedState::SPDIF_FLAG),
616 (&mut state.midi_in, LedState::MIDI_IN_FLAG),
617 ]
618 .iter_mut()
619 .for_each(|(on, flag)| **on = val & *flag > 0);
620
621 Ok(())
622}
623
624#[derive(Debug, Copy, Clone, PartialEq, Eq)]
626pub enum MeterDisplayTarget {
627 AnalogInput0,
628 AnalogInput1,
629 AnalogInput2,
630 AnalogInput3,
631 AnalogInput4,
632 AnalogInput5,
633 AnalogInput6,
634 AnalogInput7,
635 SpdifInput0,
636 SpdifInput1,
637 AdatInput0,
638 AdatInput1,
639 AdatInput2,
640 AdatInput3,
641 AdatInput4,
642 AdatInput5,
643 AdatInput6,
644 AdatInput7,
645 AdatInput8,
646 AdatInput9,
647 AdatInput10,
648 AdatInput11,
649 AdatInput12,
650 AdatInput13,
651 AdatInput14,
652 AdatInput15,
653}
654
655impl Default for MeterDisplayTarget {
656 fn default() -> Self {
657 MeterDisplayTarget::AnalogInput0
658 }
659}
660
661const METER_DISPLAY_TARGETS: &[MeterDisplayTarget] = &[
662 MeterDisplayTarget::AnalogInput0,
663 MeterDisplayTarget::AnalogInput1,
664 MeterDisplayTarget::AnalogInput2,
665 MeterDisplayTarget::AnalogInput3,
666 MeterDisplayTarget::AnalogInput4,
667 MeterDisplayTarget::AnalogInput5,
668 MeterDisplayTarget::AnalogInput6,
669 MeterDisplayTarget::AnalogInput7,
670 MeterDisplayTarget::SpdifInput0,
671 MeterDisplayTarget::SpdifInput1,
672 MeterDisplayTarget::AdatInput0,
673 MeterDisplayTarget::AdatInput1,
674 MeterDisplayTarget::AdatInput2,
675 MeterDisplayTarget::AdatInput3,
676 MeterDisplayTarget::AdatInput4,
677 MeterDisplayTarget::AdatInput5,
678 MeterDisplayTarget::AdatInput6,
679 MeterDisplayTarget::AdatInput7,
680 MeterDisplayTarget::AdatInput8,
681 MeterDisplayTarget::AdatInput9,
682 MeterDisplayTarget::AdatInput10,
683 MeterDisplayTarget::AdatInput11,
684 MeterDisplayTarget::AdatInput12,
685 MeterDisplayTarget::AdatInput13,
686 MeterDisplayTarget::AdatInput14,
687 MeterDisplayTarget::AdatInput15,
688];
689
690fn serialize_meter_display_targets(
691 targets: &[MeterDisplayTarget; 8],
692 raw: &mut [u8],
693) -> Result<(), String> {
694 assert!(raw.len() >= 8);
695
696 (0..targets.len()).step_by(4).for_each(|pos| {
697 let mut val = 0u32;
698
699 targets[pos..(pos + 4)]
700 .iter()
701 .enumerate()
702 .for_each(|(j, target)| {
703 let pos = METER_DISPLAY_TARGETS
704 .iter()
705 .position(|t| target.eq(t))
706 .unwrap();
707 val |= (pos as u32) << (j * 8);
708 });
709
710 serialize_u32(&val, &mut raw[pos..(pos + 4)]);
711 });
712
713 Ok(())
714}
715
716fn deserialize_meter_display_targets(
717 targets: &mut [MeterDisplayTarget; 8],
718 raw: &[u8],
719) -> Result<(), String> {
720 assert!(raw.len() >= 8);
721
722 let mut val = 0u32;
723
724 (0..targets.len()).step_by(4).try_for_each(|pos| {
725 deserialize_u32(&mut val, &raw[pos..(pos + 4)]);
726
727 targets[pos..(pos + 4)]
728 .iter_mut()
729 .enumerate()
730 .try_for_each(|(j, target)| {
731 let pos = ((val >> (j * 8)) & 0x000000ff) as usize;
732 METER_DISPLAY_TARGETS
733 .iter()
734 .nth(pos)
735 .ok_or_else(|| format!("Meter display target not found for position {}", pos))
736 .map(|&t| *target = t)
737 })
738 })
739}
740
741#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
743pub struct LiquidS56SpecificParams {
744 pub mic_amp_emulation_types: [MicAmpEmulationType; 2],
746 pub mic_amp_harmonics: [u8; 2],
748 pub mic_amp_polarities: [bool; 2],
750 pub analog_input_levels: [AnalogInputLevel; 8],
752 pub led_states: LedState,
754 pub meter_display_targets: [MeterDisplayTarget; 8],
756}
757
758const SPECIFIC_PARAMS_OFFSET: usize = 0x0278;
759const SPECIFIC_PARAMS_SIZE: usize = 0x48;
760
761fn serialize_specific_params(
762 params: &LiquidS56SpecificParams,
763 raw: &mut [u8],
764) -> Result<(), String> {
765 assert!(raw.len() >= SPECIFIC_PARAMS_SIZE);
766
767 serialize_mic_amp_emulation_types(¶ms.mic_amp_emulation_types, &mut raw[..0x08])?;
768 serialize_mic_amp_harmonics(¶ms.mic_amp_harmonics, &mut raw[0x08..0x10])?;
769 serialize_mic_amp_polarities(¶ms.mic_amp_polarities, &mut raw[0x10..0x18])?;
770 serialize_meter_display_targets(¶ms.meter_display_targets, &mut raw[0x24..0x3c])?;
771 serialize_analog_input_levels(¶ms.analog_input_levels, &mut raw[0x3c..0x44])?;
772 serialize_led_state(¶ms.led_states, &mut raw[0x44..0x48])?;
773
774 Ok(())
775}
776
777fn deserialize_specific_params(
778 params: &mut LiquidS56SpecificParams,
779 raw: &[u8],
780) -> Result<(), String> {
781 assert!(raw.len() >= SPECIFIC_PARAMS_SIZE);
782
783 deserialize_mic_amp_emulation_types(&mut params.mic_amp_emulation_types, &raw[..0x08])?;
784 deserialize_mic_amp_harmonics(&mut params.mic_amp_harmonics, &raw[0x08..0x10])?;
785 deserialize_mic_amp_polarities(&mut params.mic_amp_polarities, &raw[0x10..0x18])?;
786 deserialize_meter_display_targets(&mut params.meter_display_targets, &raw[0x24..0x3c])?;
787 deserialize_analog_input_levels(&mut params.analog_input_levels, &raw[0x3c..0x44])?;
788 deserialize_led_state(&mut params.led_states, &raw[0x44..0x48])?;
789
790 Ok(())
791}
792
793impl LiquidS56Protocol {
795 pub const MIC_AMP_HARMONICS_MIN: u8 = 0;
796 pub const MIC_AMP_HARMONICS_MAX: u8 = 21;
797}
798
799impl TcatExtensionSectionParamsOperation<LiquidS56SpecificParams> for LiquidS56Protocol {
800 fn cache_extension_whole_params(
801 req: &FwReq,
802 node: &FwNode,
803 sections: &ExtensionSections,
804 _: &ExtensionCaps,
805 params: &mut LiquidS56SpecificParams,
806 timeout_ms: u32,
807 ) -> Result<(), Error> {
808 let mut raw = vec![0u8; SPECIFIC_PARAMS_SIZE];
809 Self::read_extension(
810 req,
811 node,
812 §ions.application,
813 SPECIFIC_PARAMS_OFFSET,
814 &mut raw,
815 timeout_ms,
816 )?;
817 deserialize_specific_params(params, &raw)
818 .map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
819 }
820}
821
822impl TcatExtensionSectionPartialMutableParamsOperation<LiquidS56SpecificParams>
823 for LiquidS56Protocol
824{
825 fn update_extension_partial_params(
826 req: &FwReq,
827 node: &FwNode,
828 sections: &ExtensionSections,
829 _: &ExtensionCaps,
830 params: &LiquidS56SpecificParams,
831 prev: &mut LiquidS56SpecificParams,
832 timeout_ms: u32,
833 ) -> Result<(), Error> {
834 let mut new = vec![0u8; SPECIFIC_PARAMS_SIZE];
835 serialize_specific_params(params, &mut new)
836 .map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
837
838 let mut old = vec![0u8; SPECIFIC_PARAMS_SIZE];
839 serialize_specific_params(prev, &mut old)
840 .map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
841
842 (0..SPECIFIC_PARAMS_SIZE).step_by(4).try_for_each(|pos| {
843 if new[pos..(pos + 4)] != old[pos..(pos + 4)] {
844 Self::write_extension(
845 req,
846 node,
847 §ions.application,
848 SPECIFIC_PARAMS_OFFSET + pos,
849 &mut new[pos..(pos + 4)],
850 timeout_ms,
851 )
852 } else {
853 Ok(())
854 }
855 })?;
856
857 [
858 (0x00, MIC_AMP_1_EMULATION_SW_NOTICE),
859 (0x04, MIC_AMP_2_EMULATION_SW_NOTICE),
860 (0x08, MIC_AMP_1_HARMONICS_SW_NOTICE),
861 (0x0c, MIC_AMP_2_HARMONICS_SW_NOTICE),
862 (0x10, MIC_AMP_POLARITY_SW_NOTICE),
863 (0x14, MIC_AMP_POLARITY_SW_NOTICE),
864 (0x38, INPUT_LEVEL_SW_NOTICE),
865 (0x3c, INPUT_LEVEL_SW_NOTICE),
866 ]
867 .iter()
868 .filter(|(pos, _)| &new[*pos..(*pos + 4)] != &old[*pos..(*pos + 4)])
869 .try_for_each(|(_, msg)| Self::write_sw_notice(req, node, sections, *msg, timeout_ms))?;
870
871 deserialize_specific_params(prev, &new)
872 .map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
873 }
874}
875
876#[cfg(test)]
877mod test {
878 use super::*;
879
880 #[test]
881 fn serdes_specific_params() {
882 let params = LiquidS56SpecificParams {
883 mic_amp_emulation_types: [MicAmpEmulationType::Savillerow, MicAmpEmulationType::Dunk],
884 mic_amp_harmonics: [0x59, 0xb2],
885 mic_amp_polarities: [false, true],
886 analog_input_levels: [
887 AnalogInputLevel::Line,
888 AnalogInputLevel::Mic,
889 AnalogInputLevel::Inst,
890 AnalogInputLevel::Line,
891 AnalogInputLevel::Mic,
892 AnalogInputLevel::Inst,
893 AnalogInputLevel::Line,
894 AnalogInputLevel::Mic,
895 ],
896 led_states: LedState {
897 adat1: false,
898 adat2: true,
899 spdif: false,
900 midi_in: true,
901 },
902 meter_display_targets: [
903 MeterDisplayTarget::AdatInput8,
904 MeterDisplayTarget::AdatInput11,
905 MeterDisplayTarget::AdatInput2,
906 MeterDisplayTarget::AdatInput5,
907 MeterDisplayTarget::AnalogInput5,
908 MeterDisplayTarget::SpdifInput1,
909 MeterDisplayTarget::AnalogInput0,
910 MeterDisplayTarget::AnalogInput3,
911 ],
912 };
913 let mut raw = vec![0u8; SPECIFIC_PARAMS_SIZE];
914 serialize_specific_params(¶ms, &mut raw).unwrap();
915
916 let mut p = LiquidS56SpecificParams::default();
917 deserialize_specific_params(&mut p, &raw).unwrap();
918
919 assert_eq!(params, p);
920 }
921}