1use super::*;
84
85#[derive(Default, Debug)]
87pub struct EnsembleClkProtocol;
88
89impl MediaClockFrequencyOperation for EnsembleClkProtocol {
90 const FREQ_LIST: &'static [u32] = &[44100, 48000, 88200, 96000, 176400, 192000];
91}
92
93impl SamplingClockSourceOperation for EnsembleClkProtocol {
94 const DST: SignalAddr = SignalAddr::Subunit(SignalSubunitAddr {
95 subunit: MUSIC_SUBUNIT_0,
96 plug_id: 7,
97 });
98
99 const SRC_LIST: &'static [SignalAddr] = &[
100 SignalAddr::Subunit(SignalSubunitAddr {
102 subunit: MUSIC_SUBUNIT_0,
103 plug_id: 7,
104 }),
105 SignalAddr::Unit(SignalUnitAddr::Ext(4)),
107 SignalAddr::Unit(SignalUnitAddr::Ext(5)),
109 SignalAddr::Unit(SignalUnitAddr::Ext(6)),
111 ];
112}
113
114#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
116pub struct EnsembleConverterParameters {
117 pub format_target: FormatConvertTarget,
119 pub rate_target: RateConvertTarget,
121 pub converted_rate: RateConvertRate,
123 pub cd_mode: bool,
125}
126
127#[derive(Default, Debug)]
129pub struct EnsembleConverterProtocol;
130
131impl EnsembleParametersConverter<EnsembleConverterParameters> for EnsembleConverterProtocol {
132 fn parse_cmds(params: &mut EnsembleConverterParameters, cmds: &[EnsembleCmd]) {
133 cmds.iter().for_each(|cmd| match cmd {
134 &EnsembleCmd::FormatConvert(format_target) => {
135 params.format_target = format_target;
136 }
137 &EnsembleCmd::RateConvert(rate_target, converted_rate) => {
138 params.rate_target = rate_target;
139 params.converted_rate = converted_rate;
140 }
141 &EnsembleCmd::Hw(HwCmd::CdMode(cd_mode)) => {
142 params.cd_mode = cd_mode;
143 }
144 _ => (),
145 });
146 }
147
148 fn build_cmds(params: &EnsembleConverterParameters) -> Vec<EnsembleCmd> {
149 vec![
150 EnsembleCmd::FormatConvert(params.format_target),
151 EnsembleCmd::RateConvert(params.rate_target, params.converted_rate),
152 EnsembleCmd::Hw(HwCmd::CdMode(params.cd_mode)),
153 ]
154 }
155}
156
157impl From<&EnsembleConverterParameters> for Vec<EnsembleCmd> {
158 fn from(params: &EnsembleConverterParameters) -> Self {
159 EnsembleConverterProtocol::build_cmds(params)
160 }
161}
162
163impl EnsembleParameterProtocol<EnsembleConverterParameters> for EnsembleConverterProtocol {}
164
165#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
167pub struct EnsembleDisplayParameters {
168 pub enabled: bool,
170 pub illuminate: bool,
172 pub target: DisplayMeterTarget,
174 pub overhold: bool,
176}
177
178#[derive(Default, Debug)]
180pub struct EnsembleDisplayProtocol;
181
182impl EnsembleParametersConverter<EnsembleDisplayParameters> for EnsembleDisplayProtocol {
183 fn parse_cmds(params: &mut EnsembleDisplayParameters, cmds: &[EnsembleCmd]) {
184 cmds.iter().for_each(|cmd| match cmd {
185 &EnsembleCmd::Hw(HwCmd::DisplayMode(enabled)) => {
186 params.enabled = enabled;
187 }
188 &EnsembleCmd::Hw(HwCmd::DisplayIlluminate(illuminate)) => {
189 params.illuminate = illuminate;
190 }
191 &EnsembleCmd::Hw(HwCmd::DisplayTarget(target)) => {
192 params.target = target;
193 }
194 &EnsembleCmd::Hw(HwCmd::DisplayOverhold(overhold)) => {
195 params.overhold = overhold;
196 }
197 _ => (),
198 })
199 }
200
201 fn build_cmds(params: &EnsembleDisplayParameters) -> Vec<EnsembleCmd> {
202 vec![
203 EnsembleCmd::Hw(HwCmd::DisplayMode(params.enabled)),
204 EnsembleCmd::Hw(HwCmd::DisplayIlluminate(params.illuminate)),
205 EnsembleCmd::Hw(HwCmd::DisplayTarget(params.target)),
206 EnsembleCmd::Hw(HwCmd::DisplayOverhold(params.overhold)),
207 ]
208 }
209}
210
211impl From<&EnsembleDisplayParameters> for Vec<EnsembleCmd> {
212 fn from(params: &EnsembleDisplayParameters) -> Self {
213 EnsembleDisplayProtocol::build_cmds(params)
214 }
215}
216
217impl EnsembleParameterProtocol<EnsembleDisplayParameters> for EnsembleDisplayProtocol {}
218
219#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
222pub struct EnsembleInputParameters {
223 pub limits: [bool; 8],
225 pub levels: [InputNominalLevel; 8],
227 pub gains: [u8; 4],
229 pub phantoms: [bool; 4],
231 pub polarities: [bool; 4],
233 pub opt_iface_mode: OptIfaceMode,
235}
236
237#[derive(Default, Debug)]
239pub struct EnsembleInputProtocol;
240
241impl EnsembleInputProtocol {
242 pub const GAIN_MIN: u8 = 0;
244
245 pub const GAIN_MAX: u8 = 75;
247
248 pub const GAIN_STEP: u8 = 1;
250}
251
252impl EnsembleParametersConverter<EnsembleInputParameters> for EnsembleInputProtocol {
253 fn parse_cmds(params: &mut EnsembleInputParameters, cmds: &[EnsembleCmd]) {
254 cmds.iter().for_each(|cmd| match cmd {
255 &EnsembleCmd::InputLimit(i, limit) => {
256 if i < params.limits.len() {
257 params.limits[i] = limit;
258 }
259 }
260 &EnsembleCmd::InputNominalLevel(i, level) => {
261 if i < params.levels.len() {
262 params.levels[i] = level;
263 }
264 }
265 &EnsembleCmd::MicGain(i, gain) => {
266 if i < params.gains.len() {
267 params.gains[i] = gain;
268 }
269 }
270 &EnsembleCmd::MicPower(i, phantom) => {
271 if i < params.phantoms.len() {
272 params.phantoms[i] = phantom;
273 }
274 }
275 &EnsembleCmd::MicPolarity(i, polarity) => {
276 if i < params.polarities.len() {
277 params.polarities[i] = polarity;
278 }
279 }
280 &EnsembleCmd::InputOptIface(opt_iface_mode) => {
281 params.opt_iface_mode = opt_iface_mode;
282 }
283 _ => (),
284 })
285 }
286
287 fn build_cmds(params: &EnsembleInputParameters) -> Vec<EnsembleCmd> {
288 let mut cmds = Vec::new();
289
290 params
291 .limits
292 .iter()
293 .enumerate()
294 .for_each(|(i, &limit)| cmds.push(EnsembleCmd::InputLimit(i, limit)));
295
296 params
297 .levels
298 .iter()
299 .enumerate()
300 .for_each(|(i, &level)| cmds.push(EnsembleCmd::InputNominalLevel(i, level)));
301
302 params
303 .gains
304 .iter()
305 .enumerate()
306 .for_each(|(i, &gain)| cmds.push(EnsembleCmd::MicGain(i, gain)));
307
308 params
309 .phantoms
310 .iter()
311 .enumerate()
312 .for_each(|(i, &phantom)| cmds.push(EnsembleCmd::MicPower(i, phantom)));
313
314 params
315 .polarities
316 .iter()
317 .enumerate()
318 .for_each(|(i, &polarity)| cmds.push(EnsembleCmd::MicPolarity(i, polarity)));
319
320 cmds.push(EnsembleCmd::InputOptIface(params.opt_iface_mode));
321
322 cmds
323 }
324}
325
326impl From<&EnsembleInputParameters> for Vec<EnsembleCmd> {
327 fn from(params: &EnsembleInputParameters) -> Self {
328 EnsembleInputProtocol::build_cmds(params)
329 }
330}
331
332impl EnsembleParameterProtocol<EnsembleInputParameters> for EnsembleInputProtocol {}
333
334#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
336pub struct EnsembleOutputParameters {
337 pub vol: u8,
339 pub headphone_vols: [u8; 2],
341 pub levels: [OutputNominalLevel; 8],
343 pub opt_iface_mode: OptIfaceMode,
345}
346
347#[derive(Default, Debug)]
349pub struct EnsembleOutputProtocol;
350
351impl EnsembleOutputProtocol {
352 pub const VOL_MIN: u8 = 0;
354
355 pub const VOL_MAX: u8 = 0x7f;
357
358 pub const VOL_STEP: u8 = 1;
360
361 fn coef_from_vol(vol: u8) -> u8 {
362 Self::VOL_MAX - vol
363 }
364
365 fn coef_to_vol(coef: u8) -> u8 {
366 Self::VOL_MAX - coef
367 }
368}
369
370impl EnsembleParametersConverter<EnsembleOutputParameters> for EnsembleOutputProtocol {
371 fn parse_cmds(params: &mut EnsembleOutputParameters, cmds: &[EnsembleCmd]) {
372 cmds.iter().for_each(|cmd| match cmd {
373 &EnsembleCmd::OutVol(i, coef) => {
374 let vol = Self::coef_to_vol(coef);
375 match i {
376 0 => params.vol = vol,
377 1..=2 => {
378 params.headphone_vols[i - 1] = vol;
379 }
380 _ => (),
381 }
382 }
383 &EnsembleCmd::OutputNominalLevel(i, level) => {
384 if i < params.levels.len() {
385 params.levels[i] = level;
386 }
387 }
388 &EnsembleCmd::OutputOptIface(opt_iface_mode) => {
389 params.opt_iface_mode = opt_iface_mode;
390 }
391 _ => (),
392 })
393 }
394
395 fn build_cmds(params: &EnsembleOutputParameters) -> Vec<EnsembleCmd> {
396 let mut cmds = Vec::new();
397
398 [params.vol]
399 .iter()
400 .chain(¶ms.headphone_vols)
401 .enumerate()
402 .for_each(|(i, &vol)| cmds.push(EnsembleCmd::OutVol(i, Self::coef_from_vol(vol))));
403
404 params
405 .levels
406 .iter()
407 .enumerate()
408 .for_each(|(i, &level)| cmds.push(EnsembleCmd::OutputNominalLevel(i, level)));
409
410 cmds.push(EnsembleCmd::OutputOptIface(params.opt_iface_mode));
411
412 cmds
413 }
414}
415
416impl From<&EnsembleOutputParameters> for Vec<EnsembleCmd> {
417 fn from(params: &EnsembleOutputParameters) -> Self {
418 EnsembleOutputProtocol::build_cmds(params)
419 }
420}
421
422impl EnsembleParameterProtocol<EnsembleOutputParameters> for EnsembleOutputProtocol {}
423
424#[derive(Debug, Copy, Clone, PartialEq, Eq)]
426pub struct EnsembleSourceParameters {
427 pub output_sources: [usize; 18],
446 pub capture_sources: [usize; 18],
459 pub headphone_sources: [usize; 2],
463}
464
465impl Default for EnsembleSourceParameters {
466 fn default() -> Self {
467 let mut output_sources = [0; 18];
468 output_sources
469 .iter_mut()
470 .enumerate()
471 .for_each(|(i, v)| *v = i + 8);
472
473 let mut capture_sources = [0; 18];
474 capture_sources
475 .iter_mut()
476 .enumerate()
477 .for_each(|(i, v)| *v = i);
478
479 let mut headphone_sources = [0; 2];
480 headphone_sources
481 .iter_mut()
482 .enumerate()
483 .for_each(|(i, v)| *v = i);
484
485 EnsembleSourceParameters {
486 output_sources,
487 capture_sources,
488 headphone_sources,
489 }
490 }
491}
492
493#[derive(Default, Debug)]
495pub struct EnsembleSourceProtocol;
496
497impl EnsembleSourceProtocol {
498 fn dst_id_from_out_idx(idx: usize) -> Option<usize> {
499 match idx {
500 0..=7 => Some(idx),
501 8..=17 => Some(idx + 18),
502 _ => None,
503 }
504 }
505
506 fn dst_id_to_out_idx(dst_id: usize) -> Option<usize> {
507 match dst_id {
508 0..=7 => Some(dst_id),
509 8..=25 => None,
510 26..=35 => Some(dst_id - 18),
511 _ => None,
512 }
513 }
514
515 fn dst_id_from_cap_idx(idx: usize) -> Option<usize> {
516 if idx < 18 {
517 Some(idx + 8)
518 } else {
519 None
520 }
521 }
522
523 fn dst_id_to_cap_idx(dst_id: usize) -> Option<usize> {
524 match dst_id {
525 0..=7 => None,
526 8..=25 => Some(dst_id - 8),
527 _ => None,
528 }
529 }
530
531 fn src_id_from_stream_idx(src_id: usize) -> Option<usize> {
532 match src_id {
533 0..=7 => Some(src_id),
534 8..=17 => Some(src_id + 18),
535 _ => None,
536 }
537 }
538
539 fn src_id_to_stream_idx(idx: usize) -> Option<usize> {
540 match idx {
541 0..=7 => Some(idx),
542 8..=25 => None,
543 26..=35 => Some(idx - 18),
544 _ => None,
545 }
546 }
547}
548
549impl EnsembleParametersConverter<EnsembleSourceParameters> for EnsembleSourceProtocol {
550 fn build_cmds(params: &EnsembleSourceParameters) -> Vec<EnsembleCmd> {
551 let mut cmds = Vec::new();
552
553 params
554 .output_sources
555 .iter()
556 .enumerate()
557 .for_each(|(out_idx, &src_id)| {
558 Self::dst_id_from_out_idx(out_idx).map(|dst_id| {
559 cmds.push(EnsembleCmd::IoRouting(dst_id, src_id));
560 });
561 });
562
563 params
564 .capture_sources
565 .iter()
566 .enumerate()
567 .for_each(|(cap_idx, &stream_idx)| {
568 Self::dst_id_from_cap_idx(cap_idx).map(|dst_id| {
569 Self::src_id_from_stream_idx(stream_idx).map(|src_id| {
570 cmds.push(EnsembleCmd::IoRouting(dst_id, src_id));
571 });
572 });
573 });
574
575 params
576 .headphone_sources
577 .iter()
578 .enumerate()
579 .for_each(|(dst_id, &src_id)| {
580 cmds.push(EnsembleCmd::HpSrc(dst_id, src_id));
581 });
582
583 cmds
584 }
585
586 fn parse_cmds(params: &mut EnsembleSourceParameters, cmds: &[EnsembleCmd]) {
587 cmds.iter().for_each(|cmd| match cmd {
588 &EnsembleCmd::IoRouting(dst_id, src_id) => {
589 if let Some(cap_idx) = Self::dst_id_to_cap_idx(dst_id) {
590 Self::src_id_to_stream_idx(src_id).map(|stream_idx| {
591 params.capture_sources[cap_idx] = stream_idx;
592 });
593 } else if let Some(out_idx) = Self::dst_id_to_out_idx(dst_id) {
594 params.output_sources[out_idx] = src_id;
595 }
596 }
597 &EnsembleCmd::HpSrc(dst_id, src_id) => {
598 if dst_id < params.headphone_sources.len() {
599 params.headphone_sources[dst_id] = src_id;
600 }
601 }
602 _ => (),
603 })
604 }
605}
606impl From<&EnsembleSourceParameters> for Vec<EnsembleCmd> {
607 fn from(params: &EnsembleSourceParameters) -> Self {
608 EnsembleSourceProtocol::build_cmds(params)
609 }
610}
611
612impl EnsembleParameterProtocol<EnsembleSourceParameters> for EnsembleSourceProtocol {}
613
614#[derive(Debug, Copy, Clone, PartialEq, Eq)]
616pub struct EnsembleMixerParameters {
617 pub src_gains: [[i16; 36]; 4],
632}
633
634impl Default for EnsembleMixerParameters {
635 fn default() -> Self {
636 let mut src_gains = [[0; 36]; 4];
637
638 src_gains.iter_mut().enumerate().for_each(|(i, gains)| {
639 gains
640 .iter_mut()
641 .enumerate()
642 .filter(|(j, _)| i % 2 == j % 2)
643 .for_each(|(_, gain)| *gain = EnsembleMixerProtocol::GAIN_MAX);
644 });
645 Self { src_gains }
646 }
647}
648
649#[derive(Default, Debug)]
651pub struct EnsembleMixerProtocol;
652
653impl EnsembleMixerProtocol {
654 pub const GAIN_MIN: i16 = 0;
656
657 pub const GAIN_MAX: i16 = 0xff;
659
660 pub const GAIN_STEP: i16 = 0x01;
662
663 fn array_indices_to_cmd_indices(dst_idx: usize, src_idx: usize) -> (usize, usize, usize) {
664 let pair_idx = dst_idx / 2;
665 let target_idx = src_idx / 9;
666 let coef_idx = (dst_idx % 2) + (src_idx % 9) * 2;
667
668 (pair_idx, target_idx, coef_idx)
669 }
670
671 fn array_indices_from_cmd_indices(
672 pair_idx: usize,
673 target_idx: usize,
674 coef_idx: usize,
675 ) -> (usize, usize) {
676 let dst_idx = pair_idx * 2 + coef_idx % 2;
677 let src_idx = target_idx * 9 + coef_idx / 2;
678
679 (dst_idx, src_idx)
680 }
681
682 fn partial_update_by_cmd_content(
683 params: &mut EnsembleMixerParameters,
684 pair_idx: usize,
685 target_idx: usize,
686 gains: &[i16],
687 ) {
688 assert!(pair_idx < 2);
689 assert!(target_idx < 4);
690 assert_eq!(gains.len(), MIXER_COEFFICIENT_COUNT);
691
692 gains.iter().enumerate().for_each(|(coef_idx, &gain)| {
693 let (dst_idx, src_idx) =
694 Self::array_indices_from_cmd_indices(pair_idx, target_idx, coef_idx);
695 params.src_gains[dst_idx][src_idx] = gain;
696 });
697 }
698}
699
700impl EnsembleParametersConverter<EnsembleMixerParameters> for EnsembleMixerProtocol {
730 fn build_cmds(params: &EnsembleMixerParameters) -> Vec<EnsembleCmd> {
731 let mut cmds = Vec::new();
732
733 (0..2).for_each(|pair_idx| {
734 let mut src0_gains = [0; MIXER_COEFFICIENT_COUNT];
735 let mut src1_gains = [0; MIXER_COEFFICIENT_COUNT];
736 let mut src2_gains = [0; MIXER_COEFFICIENT_COUNT];
737 let mut src3_gains = [0; MIXER_COEFFICIENT_COUNT];
738
739 params
740 .src_gains
741 .iter()
742 .skip(pair_idx * 2)
743 .take(2)
744 .enumerate()
745 .for_each(|(idx, gains)| {
746 let dst_idx = pair_idx * 2 + idx;
747 gains.iter().enumerate().for_each(|(src_idx, &gain)| {
748 let (_, target_idx, coef_idx) =
749 Self::array_indices_to_cmd_indices(dst_idx, src_idx);
750 let src_gains = match target_idx {
751 0 => &mut src0_gains,
752 1 => &mut src1_gains,
753 2 => &mut src2_gains,
754 3 => &mut src3_gains,
755 _ => unreachable!(),
756 };
757 src_gains[coef_idx] = gain;
758 });
759 });
760
761 cmds.push(EnsembleCmd::MixerSrc0(pair_idx, src0_gains));
762 cmds.push(EnsembleCmd::MixerSrc1(pair_idx, src1_gains));
763 cmds.push(EnsembleCmd::MixerSrc2(pair_idx, src2_gains));
764 cmds.push(EnsembleCmd::MixerSrc3(pair_idx, src3_gains));
765 });
766
767 cmds
768 }
769
770 fn parse_cmds(params: &mut EnsembleMixerParameters, cmds: &[EnsembleCmd]) {
771 cmds.iter().for_each(|cmd| match cmd {
772 EnsembleCmd::MixerSrc0(pair_idx, gains) => {
773 Self::partial_update_by_cmd_content(params, *pair_idx, 0, gains);
774 }
775 EnsembleCmd::MixerSrc1(pair_idx, gains) => {
776 Self::partial_update_by_cmd_content(params, *pair_idx, 1, gains);
777 }
778 EnsembleCmd::MixerSrc2(pair_idx, gains) => {
779 Self::partial_update_by_cmd_content(params, *pair_idx, 2, gains);
780 }
781 EnsembleCmd::MixerSrc3(pair_idx, gains) => {
782 Self::partial_update_by_cmd_content(params, *pair_idx, 3, gains);
783 }
784 _ => (),
785 });
786 }
787}
788impl From<&EnsembleMixerParameters> for Vec<EnsembleCmd> {
789 fn from(params: &EnsembleMixerParameters) -> Self {
790 EnsembleMixerProtocol::build_cmds(params)
791 }
792}
793
794impl EnsembleParameterProtocol<EnsembleMixerParameters> for EnsembleMixerProtocol {}
795
796#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
798pub struct EnsembleStreamParameters {
799 pub mode: StreamMode,
801}
802
803#[derive(Default, Debug)]
805pub struct EnsembleStreamProtocol;
806
807impl EnsembleParametersConverter<EnsembleStreamParameters> for EnsembleStreamProtocol {
808 fn build_cmds(params: &EnsembleStreamParameters) -> Vec<EnsembleCmd> {
809 vec![EnsembleCmd::Hw(HwCmd::StreamMode(params.mode))]
810 }
811
812 fn parse_cmds(params: &mut EnsembleStreamParameters, cmds: &[EnsembleCmd]) {
813 cmds.iter().for_each(|cmd| match cmd {
814 &EnsembleCmd::Hw(HwCmd::StreamMode(mode)) => {
815 params.mode = mode;
816 }
817 _ => (),
818 });
819 }
820}
821
822impl From<&EnsembleStreamParameters> for Vec<EnsembleCmd> {
823 fn from(params: &EnsembleStreamParameters) -> Self {
824 EnsembleStreamProtocol::build_cmds(params)
825 }
826}
827
828impl EnsembleParameterProtocol<EnsembleStreamParameters> for EnsembleStreamProtocol {
829 fn whole_update(
830 avc: &BebobAvc,
831 params: &mut EnsembleStreamParameters,
832 timeout_ms: u32,
833 ) -> Result<(), Error> {
834 let plug_addr =
835 BcoPlugAddr::new_for_unit(BcoPlugDirection::Output, BcoPlugAddrUnitType::Isoc, 0);
836 let mut op = ExtendedStreamFormatSingle::new(&plug_addr);
837 avc.status(&AvcAddr::Unit, &mut op, timeout_ms)?;
838
839 let info = op
840 .stream_format
841 .as_bco_compound_am824_stream()
842 .ok_or_else(|| {
843 let label = "Bco Compound AM824 stream is not available for the unit";
844 Error::new(FileError::Nxio, &label)
845 })?;
846 let count = info
847 .entries
848 .iter()
849 .filter(|entry| entry.format == BcoCompoundAm824StreamFormat::MultiBitLinearAudioRaw)
850 .fold(0, |count, entry| count + entry.count as usize);
851 params.mode = match count {
852 18 => StreamMode::Format18x18,
853 10 => StreamMode::Format10x10,
854 _ => StreamMode::Format8x8,
855 };
856
857 Ok(())
858 }
859}
860
861pub trait EnsembleParametersConverter<T: Copy> {
863 fn parse_cmds(params: &mut T, cmds: &[EnsembleCmd]);
865 fn build_cmds(params: &T) -> Vec<EnsembleCmd>;
867}
868
869pub trait EnsembleParameterProtocol<T: Copy>: EnsembleParametersConverter<T> {
871 fn whole_update(avc: &BebobAvc, params: &mut T, timeout_ms: u32) -> Result<(), Error> {
873 Self::build_cmds(params).into_iter().try_for_each(|cmd| {
874 let mut op = EnsembleOperation::new(cmd);
875 avc.control(&AvcAddr::Unit, &mut op, timeout_ms)
876 })
877 }
878
879 fn partial_update(avc: &BebobAvc, new: &T, old: &mut T, timeout_ms: u32) -> Result<(), Error> {
881 Self::build_cmds(new)
882 .into_iter()
883 .zip(Self::build_cmds(old))
884 .filter(|(n, o)| !n.eq(o))
885 .try_for_each(|(n, _)| {
886 let mut op = EnsembleOperation::new(n);
887 avc.control(&AvcAddr::Unit, &mut op, timeout_ms)
888 })
889 .map(|_| *old = *new)
890 }
891}
892
893#[derive(Debug, Copy, Clone, PartialEq, Eq)]
895pub enum KnobInputTarget {
896 Mic0,
898 Mic1,
900 Mic2,
902 Mic3,
904}
905
906impl Default for KnobInputTarget {
907 fn default() -> Self {
908 Self::Mic1
909 }
910}
911
912#[derive(Debug, Copy, Clone, PartialEq, Eq)]
914pub enum KnobOutputTarget {
915 AnalogOutputPair0,
917 HeadphonePair0,
919 HeadphonePair1,
921}
922
923impl Default for KnobOutputTarget {
924 fn default() -> Self {
925 Self::AnalogOutputPair0
926 }
927}
928
929#[derive(Debug, Copy, Clone, PartialEq, Eq)]
931pub struct EnsembleMeter {
932 pub knob_input_target: KnobInputTarget,
934 pub knob_output_target: KnobOutputTarget,
936 pub knob_input_vals: [u8; 4],
938 pub knob_output_vals: [u8; 3],
940 pub phys_inputs: [u8; 18],
942 pub phys_outputs: [u8; 16],
944}
945
946impl Default for EnsembleMeter {
947 fn default() -> Self {
948 Self {
949 knob_input_target: Default::default(),
950 knob_output_target: Default::default(),
951 knob_input_vals: Default::default(),
952 knob_output_vals: Default::default(),
953 phys_inputs: [0; 18],
954 phys_outputs: [0; 16],
955 }
956 }
957}
958
959#[derive(Default, Debug)]
961pub struct EnsembleMeterProtocol;
962
963const KNOB_IN_TARGET_MASK: u8 = 0x03;
964const KNOB_IN_TARGET_SHIFT: usize = 3;
965
966const KNOB_OUT_TARGET_MASK: u8 = 0x07;
967const KNOB_OUT_TARGET_SHIFT: usize = 0;
968
969const SELECT_POS: usize = 4;
973const IN_GAIN_POS: [usize; 4] = [0, 1, 2, 3];
974const OUT_VOL_POS: [usize; 3] = [7, 6, 5];
975const IN_METER_POS: [usize; 18] = [
976 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
977];
978const OUT_METER_POS: [usize; 16] = [
979 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
980];
981
982impl EnsembleMeterProtocol {
984 pub const OUT_KNOB_VAL_MIN: u8 = EnsembleOutputProtocol::VOL_MIN;
986 pub const OUT_KNOB_VAL_MAX: u8 = EnsembleOutputProtocol::VOL_MAX;
988 pub const OUT_KNOB_VAL_STEP: u8 = EnsembleOutputProtocol::VOL_STEP;
990
991 pub const IN_KNOB_VAL_MIN: u8 = EnsembleInputProtocol::GAIN_MIN;
993 pub const IN_KNOB_VAL_MAX: u8 = EnsembleInputProtocol::GAIN_MAX;
995 pub const IN_KNOB_VAL_STEP: u8 = EnsembleInputProtocol::GAIN_STEP;
997
998 pub const LEVEL_MIN: u8 = u8::MIN;
1000 pub const LEVEL_MAX: u8 = u8::MAX;
1002 pub const LEVEL_STEP: u8 = 1;
1004
1005 pub fn whole_update(
1007 avc: &BebobAvc,
1008 meter: &mut EnsembleMeter,
1009 timeout_ms: u32,
1010 ) -> Result<(), Error> {
1011 let cmd = EnsembleCmd::HwStatusLong([0; METER_LONG_FRAME_SIZE]);
1012 let mut op = EnsembleOperation::new(cmd);
1013 avc.control(&AvcAddr::Unit, &mut op, timeout_ms).map(|_| {
1014 if let EnsembleCmd::HwStatusLong(frame) = &op.cmd {
1015 let val = (frame[SELECT_POS] >> KNOB_IN_TARGET_SHIFT) & KNOB_IN_TARGET_MASK;
1016 meter.knob_input_target = match val & 0x03 {
1017 3 => KnobInputTarget::Mic3,
1018 2 => KnobInputTarget::Mic2,
1019 1 => KnobInputTarget::Mic1,
1020 _ => KnobInputTarget::Mic0,
1021 };
1022
1023 let val = (frame[SELECT_POS] >> KNOB_OUT_TARGET_SHIFT) & KNOB_OUT_TARGET_MASK;
1024 meter.knob_output_target = match val {
1025 4 => KnobOutputTarget::HeadphonePair1,
1026 2 => KnobOutputTarget::HeadphonePair0,
1027 _ => KnobOutputTarget::AnalogOutputPair0,
1028 };
1029
1030 IN_GAIN_POS
1031 .iter()
1032 .zip(&mut meter.knob_input_vals)
1033 .for_each(|(&i, m)| *m = frame[i]);
1034
1035 OUT_VOL_POS
1036 .iter()
1037 .zip(&mut meter.knob_output_vals)
1038 .for_each(|(&i, m)| {
1039 *m = Self::OUT_KNOB_VAL_MAX - (frame[i] & Self::OUT_KNOB_VAL_MAX);
1040 });
1041
1042 IN_METER_POS
1043 .iter()
1044 .zip(&mut meter.phys_inputs)
1045 .for_each(|(&i, m)| *m = frame[i]);
1046
1047 OUT_METER_POS
1048 .iter()
1049 .zip(&mut meter.phys_outputs)
1050 .for_each(|(&i, m)| *m = frame[i]);
1051 }
1052 })
1053 }
1054}
1055
1056#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1058pub enum InputNominalLevel {
1059 Professional,
1061 Consumer,
1063 Microphone,
1065}
1066
1067impl Default for InputNominalLevel {
1068 fn default() -> Self {
1069 Self::Professional
1070 }
1071}
1072
1073#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1075pub enum OutputNominalLevel {
1076 Professional,
1078 Consumer,
1080}
1081
1082impl Default for OutputNominalLevel {
1083 fn default() -> Self {
1084 Self::Professional
1085 }
1086}
1087
1088#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1090pub enum OptIfaceMode {
1091 Spdif,
1092 Adat,
1093}
1094
1095impl Default for OptIfaceMode {
1096 fn default() -> Self {
1097 Self::Spdif
1098 }
1099}
1100
1101fn opt_iface_mode_to_val(mode: &OptIfaceMode) -> u8 {
1102 if mode.eq(&OptIfaceMode::Adat) {
1103 1
1104 } else {
1105 0
1106 }
1107}
1108
1109fn opt_iface_mode_from_val(val: u8) -> OptIfaceMode {
1110 if val > 0 {
1111 OptIfaceMode::Adat
1112 } else {
1113 OptIfaceMode::Spdif
1114 }
1115}
1116
1117#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1119pub enum FormatConvertTarget {
1120 Disabled,
1122 AnalogInputPair0,
1124 AnalogInputPair1,
1126 AnalogInputPair2,
1128 AnalogInputPair3,
1130 SpdifOpticalInputPair0,
1132 SpdifCoaxialInputPair0,
1134 SpdifCoaxialOutputPair0,
1136 SpdifOpticalOutputPair0,
1138}
1139
1140impl Default for FormatConvertTarget {
1141 fn default() -> Self {
1142 Self::Disabled
1143 }
1144}
1145
1146#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1148pub enum RateConvertTarget {
1149 Disabled,
1151 SpdifOpticalOutputPair0,
1153 SpdifCoaxialOutputPair0,
1155 SpdifOpticalInputPair0,
1157 SpdifCoaxialInputPair0,
1159}
1160
1161impl Default for RateConvertTarget {
1162 fn default() -> Self {
1163 Self::Disabled
1164 }
1165}
1166
1167#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1169pub enum RateConvertRate {
1170 R44100,
1172 R48000,
1174 R88200,
1176 R96000,
1178 R176400,
1180 R192000,
1182}
1183
1184impl Default for RateConvertRate {
1185 fn default() -> Self {
1186 Self::R44100
1187 }
1188}
1189
1190const METER_SHORT_FRAME_SIZE: usize = 17;
1191const METER_LONG_FRAME_SIZE: usize = 56;
1192const MIXER_COEFFICIENT_COUNT: usize = 18;
1193
1194#[derive(Debug, Clone, Eq, PartialEq)]
1196pub enum EnsembleCmd {
1197 InputLimit(usize, bool), MicPower(usize, bool), InputNominalLevel(usize, InputNominalLevel),
1203 OutputNominalLevel(usize, OutputNominalLevel),
1205 IoRouting(usize, usize), Hw(HwCmd),
1209 HpSrc(usize, usize), MixerSrc0(usize, [i16; MIXER_COEFFICIENT_COUNT]),
1213 MixerSrc1(usize, [i16; MIXER_COEFFICIENT_COUNT]),
1215 MixerSrc2(usize, [i16; MIXER_COEFFICIENT_COUNT]),
1217 MixerSrc3(usize, [i16; MIXER_COEFFICIENT_COUNT]),
1219 MicGain(usize, u8), OutputOptIface(OptIfaceMode),
1223 InputOptIface(OptIfaceMode),
1225 FormatConvert(FormatConvertTarget),
1227 RateConvert(RateConvertTarget, RateConvertRate),
1229 MicPolarity(usize, bool), OutVol(usize, u8), HwStatusShort([u8; METER_SHORT_FRAME_SIZE]),
1235 HwStatusLong([u8; METER_LONG_FRAME_SIZE]),
1237 Reserved(Vec<u8>),
1238}
1239
1240impl Default for EnsembleCmd {
1241 fn default() -> Self {
1242 Self::Reserved(Vec::new())
1243 }
1244}
1245
1246impl EnsembleCmd {
1247 const INPUT_LIMIT: u8 = 0xe4;
1248 const MIC_POWER: u8 = 0xe5;
1249 const IO_NOMINAL_LEVEL: u8 = 0xe8;
1250 const IO_ROUTING: u8 = 0xef;
1251 const HW: u8 = 0xeb;
1252 const HP_SRC: u8 = 0xab;
1253 const MIXER_SRC0: u8 = 0xb0;
1254 const MIXER_SRC1: u8 = 0xb1;
1255 const MIXER_SRC2: u8 = 0xb2;
1256 const MIXER_SRC3: u8 = 0xb3;
1257 const MIC_GAIN: u8 = 0xe6;
1258 const OPT_IFACE_MODE: u8 = 0xf1;
1259 const FORMAT_CONVERT: u8 = 0xf2;
1260 const RATE_CONVERT: u8 = 0xf3;
1261 const MIC_POLARITY: u8 = 0xf5;
1262 const OUT_VOL: u8 = 0xf6;
1263 const HW_STATUS: u8 = 0xff;
1264}
1265
1266impl From<&EnsembleCmd> for Vec<u8> {
1267 fn from(cmd: &EnsembleCmd) -> Self {
1268 match cmd {
1269 EnsembleCmd::InputLimit(ch, state) => {
1270 vec![EnsembleCmd::INPUT_LIMIT, *ch as u8, *state as u8]
1271 }
1272 EnsembleCmd::MicPower(ch, state) => {
1273 vec![EnsembleCmd::MIC_POWER, *ch as u8, *state as u8]
1274 }
1275 EnsembleCmd::InputNominalLevel(ch, state) => {
1276 let val = match state {
1277 InputNominalLevel::Professional => 0,
1278 InputNominalLevel::Consumer => 1,
1279 InputNominalLevel::Microphone => 2,
1280 };
1281 vec![EnsembleCmd::IO_NOMINAL_LEVEL, *ch as u8, 0x01, val]
1282 }
1283 EnsembleCmd::OutputNominalLevel(ch, state) => {
1284 let val = match state {
1285 OutputNominalLevel::Professional => 0,
1286 OutputNominalLevel::Consumer => 1,
1287 };
1288 vec![EnsembleCmd::IO_NOMINAL_LEVEL, *ch as u8, 0x00, val]
1289 }
1290 EnsembleCmd::IoRouting(dst, src) => {
1291 vec![EnsembleCmd::IO_ROUTING, *dst as u8, *src as u8]
1292 }
1293 EnsembleCmd::Hw(op) => {
1294 let mut params = Into::<Vec<u8>>::into(op);
1295 params.insert(0, EnsembleCmd::HW);
1296 params
1297 }
1298 EnsembleCmd::HpSrc(dst, src) => {
1299 vec![
1300 EnsembleCmd::HP_SRC,
1301 (1 + *dst as u8) % 2,
1302 (1 + 2 * *src as u8),
1303 ]
1304 }
1305 EnsembleCmd::MixerSrc0(pair, coefs) => {
1306 let mut data = Vec::with_capacity(2 + 2 * MIXER_COEFFICIENT_COUNT);
1307 data.push(EnsembleCmd::MIXER_SRC0);
1308 data.push(*pair as u8);
1309 coefs
1310 .iter()
1311 .for_each(|coef| data.extend_from_slice(&coef.to_be_bytes()));
1312 data
1313 }
1314 EnsembleCmd::MixerSrc1(pair, coefs) => {
1315 let mut data = Vec::with_capacity(2 + 2 * MIXER_COEFFICIENT_COUNT);
1316 data.push(EnsembleCmd::MIXER_SRC1);
1317 data.push(*pair as u8);
1318 coefs
1319 .iter()
1320 .for_each(|coef| data.extend_from_slice(&coef.to_be_bytes()));
1321 data
1322 }
1323 EnsembleCmd::MixerSrc2(pair, coefs) => {
1324 let mut data = Vec::with_capacity(2 + 2 * MIXER_COEFFICIENT_COUNT);
1325 data.push(EnsembleCmd::MIXER_SRC2);
1326 data.push(*pair as u8);
1327 coefs
1328 .iter()
1329 .for_each(|coef| data.extend_from_slice(&coef.to_be_bytes()));
1330 data
1331 }
1332 EnsembleCmd::MixerSrc3(pair, coefs) => {
1333 let mut data = Vec::with_capacity(2 + 2 * MIXER_COEFFICIENT_COUNT);
1334 data.push(EnsembleCmd::MIXER_SRC3);
1335 data.push(*pair as u8);
1336 coefs
1337 .iter()
1338 .for_each(|coef| data.extend_from_slice(&coef.to_be_bytes()));
1339 data
1340 }
1341 EnsembleCmd::MicGain(target, val) => {
1342 vec![EnsembleCmd::MIC_GAIN, *target as u8, *val]
1343 }
1344 EnsembleCmd::OutputOptIface(mode) => {
1345 vec![EnsembleCmd::OPT_IFACE_MODE, 0, opt_iface_mode_to_val(mode)]
1346 }
1347 EnsembleCmd::InputOptIface(mode) => {
1348 vec![EnsembleCmd::OPT_IFACE_MODE, 1, opt_iface_mode_to_val(mode)]
1349 }
1350 EnsembleCmd::FormatConvert(state) => {
1351 let val = match state {
1352 FormatConvertTarget::Disabled => 0,
1353 FormatConvertTarget::AnalogInputPair0 => 1,
1354 FormatConvertTarget::AnalogInputPair1 => 2,
1355 FormatConvertTarget::AnalogInputPair2 => 3,
1356 FormatConvertTarget::AnalogInputPair3 => 4,
1357 FormatConvertTarget::SpdifOpticalInputPair0 => 5,
1358 FormatConvertTarget::SpdifCoaxialInputPair0 => 6,
1359 FormatConvertTarget::SpdifCoaxialOutputPair0 => 7,
1360 FormatConvertTarget::SpdifOpticalOutputPair0 => 8,
1361 };
1362 vec![EnsembleCmd::FORMAT_CONVERT, val]
1363 }
1364 EnsembleCmd::RateConvert(target, rate) => {
1365 let triplet = match target {
1366 RateConvertTarget::Disabled => [0, 0, 0],
1367 RateConvertTarget::SpdifOpticalOutputPair0 => [1, 0, 0],
1368 RateConvertTarget::SpdifCoaxialOutputPair0 => [1, 1, 0],
1369 RateConvertTarget::SpdifOpticalInputPair0 => [1, 0, 1],
1370 RateConvertTarget::SpdifCoaxialInputPair0 => [1, 1, 1],
1371 };
1372 let val = match rate {
1373 RateConvertRate::R44100 => 0,
1374 RateConvertRate::R48000 => 1,
1375 RateConvertRate::R88200 => 2,
1376 RateConvertRate::R96000 => 3,
1377 RateConvertRate::R176400 => 4,
1378 RateConvertRate::R192000 => 5,
1379 };
1380 vec![
1381 EnsembleCmd::RATE_CONVERT,
1382 triplet[0],
1383 triplet[1],
1384 triplet[2],
1385 val,
1386 ]
1387 }
1388 EnsembleCmd::MicPolarity(ch, state) => {
1389 vec![EnsembleCmd::MIC_POLARITY, *ch as u8, *state as u8]
1390 }
1391 EnsembleCmd::OutVol(target, vol) => {
1392 vec![EnsembleCmd::OUT_VOL, *target as u8, *vol]
1393 }
1394 EnsembleCmd::HwStatusShort(_) => vec![EnsembleCmd::HW_STATUS, 0],
1395 EnsembleCmd::HwStatusLong(_) => vec![EnsembleCmd::HW_STATUS, 1],
1396 EnsembleCmd::Reserved(r) => r.to_vec(),
1397 }
1398 }
1399}
1400
1401impl From<&[u8]> for EnsembleCmd {
1402 fn from(raw: &[u8]) -> Self {
1403 match raw[0] {
1404 Self::INPUT_LIMIT => Self::InputLimit(raw[1] as usize, raw[2] > 0),
1405 Self::MIC_POWER => Self::MicPower(raw[1] as usize, raw[2] > 0),
1406 Self::IO_NOMINAL_LEVEL => {
1407 if raw[2] > 0 {
1408 let state = match raw[3] {
1409 2 => InputNominalLevel::Microphone,
1410 1 => InputNominalLevel::Consumer,
1411 _ => InputNominalLevel::Professional,
1412 };
1413 Self::InputNominalLevel(raw[1] as usize, state)
1414 } else {
1415 let state = match raw[3] {
1416 1 => OutputNominalLevel::Consumer,
1417 _ => OutputNominalLevel::Professional,
1418 };
1419 Self::OutputNominalLevel(raw[1] as usize, state)
1420 }
1421 }
1422 Self::IO_ROUTING => Self::IoRouting(raw[1] as usize, raw[2] as usize),
1423 Self::HW => Self::Hw(HwCmd::from(&raw[1..])),
1424 Self::HP_SRC => Self::HpSrc((1 + raw[1] as usize) % 2, (raw[2] as usize) / 2),
1425 Self::MIXER_SRC0 => {
1426 let mut doublet = [0; 2];
1427 let mut coefs = [0; MIXER_COEFFICIENT_COUNT];
1428 coefs.iter_mut().enumerate().for_each(|(i, coef)| {
1429 let pos = 2 + i * 2;
1430 doublet.copy_from_slice(&raw[pos..(pos + 2)]);
1431 *coef = i16::from_be_bytes(doublet);
1432 });
1433 Self::MixerSrc0(raw[1] as usize, coefs)
1434 }
1435 Self::MIXER_SRC1 => {
1436 let mut doublet = [0; 2];
1437 let mut coefs = [0; MIXER_COEFFICIENT_COUNT];
1438 coefs.iter_mut().enumerate().for_each(|(i, coef)| {
1439 let pos = 2 + i * 2;
1440 doublet.copy_from_slice(&raw[pos..(pos + 2)]);
1441 *coef = i16::from_be_bytes(doublet);
1442 });
1443 Self::MixerSrc1(raw[1] as usize, coefs)
1444 }
1445 Self::MIXER_SRC2 => {
1446 let mut doublet = [0; 2];
1447 let mut coefs = [0; MIXER_COEFFICIENT_COUNT];
1448 coefs.iter_mut().enumerate().for_each(|(i, coef)| {
1449 let pos = 2 + i * 2;
1450 doublet.copy_from_slice(&raw[pos..(pos + 2)]);
1451 *coef = i16::from_be_bytes(doublet);
1452 });
1453 Self::MixerSrc2(raw[1] as usize, coefs)
1454 }
1455 Self::MIXER_SRC3 => {
1456 let mut doublet = [0; 2];
1457 let mut coefs = [0; MIXER_COEFFICIENT_COUNT];
1458 coefs.iter_mut().enumerate().for_each(|(i, coef)| {
1459 let pos = 2 + i * 2;
1460 doublet.copy_from_slice(&raw[pos..(pos + 2)]);
1461 *coef = i16::from_be_bytes(doublet);
1462 });
1463 Self::MixerSrc3(raw[1] as usize, coefs)
1464 }
1465 Self::MIC_GAIN => Self::MicGain(raw[1] as usize, raw[2]),
1466 Self::OPT_IFACE_MODE => {
1467 let mode = opt_iface_mode_from_val(raw[2]);
1468 if raw[1] > 0 {
1469 Self::InputOptIface(mode)
1470 } else {
1471 Self::OutputOptIface(mode)
1472 }
1473 }
1474 Self::FORMAT_CONVERT => {
1475 let target = match raw[1] {
1476 8 => FormatConvertTarget::SpdifOpticalOutputPair0,
1477 7 => FormatConvertTarget::SpdifCoaxialOutputPair0,
1478 6 => FormatConvertTarget::SpdifCoaxialInputPair0,
1479 5 => FormatConvertTarget::SpdifOpticalInputPair0,
1480 4 => FormatConvertTarget::AnalogInputPair3,
1481 3 => FormatConvertTarget::AnalogInputPair2,
1482 2 => FormatConvertTarget::AnalogInputPair1,
1483 1 => FormatConvertTarget::AnalogInputPair0,
1484 _ => FormatConvertTarget::Disabled,
1485 };
1486 Self::FormatConvert(target)
1487 }
1488 Self::RATE_CONVERT => {
1489 let target = if raw[1] == 0 {
1490 RateConvertTarget::Disabled
1491 } else {
1492 match (raw[2], raw[3]) {
1493 (0, 0) => RateConvertTarget::SpdifOpticalOutputPair0,
1494 (1, 0) => RateConvertTarget::SpdifCoaxialOutputPair0,
1495 (0, 1) => RateConvertTarget::SpdifOpticalInputPair0,
1496 (1, 1) => RateConvertTarget::SpdifCoaxialInputPair0,
1497 _ => RateConvertTarget::Disabled,
1498 }
1499 };
1500 let rate = match raw[4] {
1501 5 => RateConvertRate::R192000,
1502 4 => RateConvertRate::R176400,
1503 3 => RateConvertRate::R96000,
1504 2 => RateConvertRate::R88200,
1505 1 => RateConvertRate::R48000,
1506 _ => RateConvertRate::R44100,
1507 };
1508 Self::RateConvert(target, rate)
1509 }
1510 Self::MIC_POLARITY => Self::MicPolarity(raw[1] as usize, raw[2] > 0),
1511 Self::OUT_VOL => Self::OutVol(raw[1] as usize, raw[2]),
1512 Self::HW_STATUS => {
1513 if raw[1] > 0 {
1514 let mut params = [0; METER_LONG_FRAME_SIZE];
1515 params.copy_from_slice(&raw[1..]);
1516 Self::HwStatusLong(params)
1517 } else {
1518 let mut params = [0; METER_SHORT_FRAME_SIZE];
1519 params.copy_from_slice(&raw[1..]);
1520 Self::HwStatusShort(params)
1521 }
1522 }
1523 _ => Self::Reserved(raw.to_vec()),
1524 }
1525 }
1526}
1527
1528#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1530pub enum StreamMode {
1531 Format18x18,
1533 Format10x10,
1535 Format8x8,
1537}
1538
1539impl Default for StreamMode {
1540 fn default() -> Self {
1541 StreamMode::Format8x8
1542 }
1543}
1544
1545#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1547pub enum DisplayMeterTarget {
1548 Output,
1550 Input,
1552}
1553
1554impl Default for DisplayMeterTarget {
1555 fn default() -> Self {
1556 Self::Output
1557 }
1558}
1559
1560#[derive(Debug, Clone, PartialEq, Eq)]
1562pub enum HwCmd {
1563 StreamMode(StreamMode),
1565 DisplayIlluminate(bool),
1567 DisplayMode(bool),
1569 DisplayTarget(DisplayMeterTarget),
1571 DisplayOverhold(bool),
1573 MeterReset,
1575 CdMode(bool),
1577 Reserved(Vec<u8>),
1578}
1579
1580impl HwCmd {
1581 const STREAM_MODE: u8 = 0x06;
1582 const DISPLAY_ILLUMINATE: u8 = 0x08;
1583 const DISPLAY_MODE: u8 = 0x09;
1584 const DISPLAY_TARGET: u8 = 0x0a;
1585 const DISPLAY_OVERHOLD: u8 = 0x0e;
1586 const METER_RESET: u8 = 0x0f;
1587 const CD_MODE: u8 = 0xf5;
1588}
1589
1590impl From<&HwCmd> for Vec<u8> {
1591 fn from(op: &HwCmd) -> Self {
1592 match op {
1593 HwCmd::StreamMode(mode) => {
1594 let val = match mode {
1595 StreamMode::Format18x18 => 0,
1596 StreamMode::Format10x10 => 1,
1597 StreamMode::Format8x8 => 2,
1598 };
1599 vec![HwCmd::STREAM_MODE, val]
1600 }
1601 HwCmd::DisplayIlluminate(state) => vec![HwCmd::DISPLAY_ILLUMINATE, *state as u8],
1602 HwCmd::DisplayMode(state) => vec![HwCmd::DISPLAY_MODE, *state as u8],
1603 HwCmd::DisplayTarget(target) => {
1604 let val = match target {
1605 DisplayMeterTarget::Output => 0,
1606 DisplayMeterTarget::Input => 1,
1607 };
1608 vec![HwCmd::DISPLAY_TARGET, val]
1609 }
1610 HwCmd::DisplayOverhold(state) => vec![HwCmd::DISPLAY_OVERHOLD, *state as u8],
1611 HwCmd::MeterReset => vec![HwCmd::METER_RESET],
1612 HwCmd::CdMode(state) => vec![HwCmd::CD_MODE, *state as u8],
1613 HwCmd::Reserved(val) => val.to_vec(),
1614 }
1615 }
1616}
1617
1618impl From<&[u8]> for HwCmd {
1619 fn from(vals: &[u8]) -> HwCmd {
1620 match vals[0] {
1621 HwCmd::STREAM_MODE => {
1622 let mode = match vals[1] {
1623 2 => StreamMode::Format8x8,
1624 1 => StreamMode::Format10x10,
1625 _ => StreamMode::Format18x18,
1626 };
1627 HwCmd::StreamMode(mode)
1628 }
1629 HwCmd::DISPLAY_ILLUMINATE => HwCmd::DisplayIlluminate(vals[1] > 0),
1630 HwCmd::DISPLAY_MODE => HwCmd::DisplayMode(vals[1] > 0),
1631 HwCmd::DISPLAY_TARGET => {
1632 let target = if vals[1] > 0 {
1633 DisplayMeterTarget::Input
1634 } else {
1635 DisplayMeterTarget::Output
1636 };
1637 HwCmd::DisplayTarget(target)
1638 }
1639 HwCmd::DISPLAY_OVERHOLD => HwCmd::DisplayOverhold(vals[1] > 0),
1640 HwCmd::METER_RESET => HwCmd::MeterReset,
1641 HwCmd::CD_MODE => HwCmd::CdMode(vals[1] > 0),
1642 _ => HwCmd::Reserved(vals.to_vec()),
1643 }
1644 }
1645}
1646
1647#[derive(Debug)]
1649pub struct EnsembleOperation {
1650 pub cmd: EnsembleCmd,
1651 op: VendorDependent,
1652}
1653
1654impl Default for EnsembleOperation {
1655 fn default() -> Self {
1656 Self {
1657 cmd: Default::default(),
1658 op: VendorDependent {
1659 company_id: APOGEE_OUI,
1660 data: Default::default(),
1661 },
1662 }
1663 }
1664}
1665
1666impl EnsembleOperation {
1667 pub fn new(cmd: EnsembleCmd) -> Self {
1668 Self {
1669 cmd,
1670 ..Default::default()
1671 }
1672 }
1673}
1674
1675impl AvcOp for EnsembleOperation {
1676 const OPCODE: u8 = VendorDependent::OPCODE;
1677}
1678
1679impl AvcControl for EnsembleOperation {
1680 fn build_operands(&mut self, addr: &AvcAddr) -> Result<Vec<u8>, AvcCmdBuildError> {
1681 self.op.data = Into::<Vec<u8>>::into(&self.cmd);
1682
1683 while self.op.data.len() < 6 {
1685 self.op.data.push(0xff);
1686 }
1687
1688 AvcControl::build_operands(&mut self.op, addr)
1689 }
1690
1691 fn parse_operands(&mut self, addr: &AvcAddr, operands: &[u8]) -> Result<(), AvcRespParseError> {
1692 AvcControl::parse_operands(&mut self.op, addr, operands).map(|_| {
1693 match &mut self.cmd {
1695 EnsembleCmd::HwStatusShort(buf) => buf.copy_from_slice(&self.op.data[2..]),
1696 EnsembleCmd::HwStatusLong(buf) => buf.copy_from_slice(&self.op.data[2..]),
1697 _ => (),
1698 }
1699 })
1700 }
1701}
1702
1703#[cfg(test)]
1704mod test {
1705 use super::*;
1706
1707 #[test]
1708 fn converter_params_and_cmds() {
1709 let params = EnsembleConverterParameters {
1710 format_target: FormatConvertTarget::SpdifCoaxialInputPair0,
1711 rate_target: RateConvertTarget::SpdifOpticalOutputPair0,
1712 converted_rate: RateConvertRate::R88200,
1713 cd_mode: true,
1714 };
1715 let cmds = EnsembleConverterProtocol::build_cmds(¶ms);
1716 let mut p = EnsembleConverterParameters::default();
1717 EnsembleConverterProtocol::parse_cmds(&mut p, &cmds);
1718
1719 assert_eq!(params, p);
1720 }
1721
1722 #[test]
1723 fn display_params_and_cmds() {
1724 let params = EnsembleDisplayParameters {
1725 enabled: false,
1726 illuminate: true,
1727 target: DisplayMeterTarget::Output,
1728 overhold: true,
1729 };
1730 let cmds = EnsembleDisplayProtocol::build_cmds(¶ms);
1731 let mut p = EnsembleDisplayParameters::default();
1732 EnsembleDisplayProtocol::parse_cmds(&mut p, &cmds);
1733
1734 assert_eq!(params, p);
1735 }
1736
1737 #[test]
1738 fn input_params_and_cmds() {
1739 let params = EnsembleInputParameters {
1740 limits: [false, true, false, true, true, false, true, false],
1741 levels: [
1742 InputNominalLevel::Professional,
1743 InputNominalLevel::Consumer,
1744 InputNominalLevel::Microphone,
1745 InputNominalLevel::Professional,
1746 InputNominalLevel::Consumer,
1747 InputNominalLevel::Microphone,
1748 InputNominalLevel::Professional,
1749 InputNominalLevel::Consumer,
1750 ],
1751 gains: [10, 20, 30, 40],
1752 phantoms: [true, false, false, true],
1753 polarities: [false, true, true, false],
1754 opt_iface_mode: OptIfaceMode::Adat,
1755 };
1756 let cmds = EnsembleInputProtocol::build_cmds(¶ms);
1757 let mut p = EnsembleInputParameters::default();
1758 EnsembleInputProtocol::parse_cmds(&mut p, &cmds);
1759
1760 assert_eq!(params, p);
1761 }
1762
1763 #[test]
1764 fn output_params_and_cmds() {
1765 let params = EnsembleOutputParameters {
1766 vol: 0x72,
1767 headphone_vols: [0x4f, 0x5a],
1768 levels: [
1769 OutputNominalLevel::Professional,
1770 OutputNominalLevel::Consumer,
1771 OutputNominalLevel::Professional,
1772 OutputNominalLevel::Consumer,
1773 OutputNominalLevel::Professional,
1774 OutputNominalLevel::Consumer,
1775 OutputNominalLevel::Professional,
1776 OutputNominalLevel::Consumer,
1777 ],
1778 opt_iface_mode: OptIfaceMode::Adat,
1779 };
1780 let cmds = EnsembleOutputProtocol::build_cmds(¶ms);
1781 let mut p = EnsembleOutputParameters::default();
1782 EnsembleOutputProtocol::parse_cmds(&mut p, &cmds);
1783
1784 assert_eq!(params, p);
1785 }
1786
1787 #[test]
1788 fn source_params_and_cmds() {
1789 let params = EnsembleSourceParameters {
1790 output_sources: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 17, 16, 15, 14, 13, 12, 11, 10],
1791 capture_sources: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 17, 16, 15, 14, 13, 12, 11, 10],
1792 headphone_sources: [7, 2],
1793 };
1794 let cmds = EnsembleSourceProtocol::build_cmds(¶ms);
1795 let mut p = EnsembleSourceParameters::default();
1796 EnsembleSourceProtocol::parse_cmds(&mut p, &cmds);
1797
1798 assert_eq!(params, p);
1799 }
1800
1801 #[test]
1802 fn mixer_params_and_cmds() {
1803 let params = EnsembleMixerParameters {
1804 src_gains: [
1805 [
1806 39, -84, 33, 93, -55, 26, -14, -16, 36, 25, -76, 27, -90, -22, -92, 15, -98,
1807 90, 55, 58, 0, -33, -3, -86, 62, -57, 45, 2, 51, -39, 53, 41, -58, -18, -88,
1808 -38,
1809 ],
1810 [
1811 -12, -78, -72, -43, -50, -73, 19, -9, 21, 28, -15, 36, 55, -58, 22, 56, 39, 43,
1812 10, -1, 60, -6, -29, 15, -98, 46, 90, -67, 32, 83, -55, 66, 54, 48, 62, -49,
1813 ],
1814 [
1815 10, -100, 90, 18, -3, -61, -2, -37, -29, -60, 99, -16, 54, 28, -17, 17, -69,
1816 33, -81, -56, -39, 3, 22, 85, -35, -52, -21, 40, 21, -67, 45, 80, 0, 42, -88,
1817 63,
1818 ],
1819 [
1820 4, -72, 18, -56, 10, 68, -82, 82, 94, -8, -9, 6, -79, 64, 30, -50, -88, -23,
1821 -34, 23, -33, 77, -28, -7, 21, -32, -42, -58, -1, 71, 84, 37, -80, -19, 88, 0,
1822 ],
1823 ],
1824 };
1825 let cmds = EnsembleMixerProtocol::build_cmds(¶ms);
1826 let mut p = EnsembleMixerParameters::default();
1827 EnsembleMixerProtocol::parse_cmds(&mut p, &cmds);
1828
1829 assert_eq!(params, p);
1830 }
1831
1832 #[test]
1833 fn stream_params() {
1834 let params = EnsembleStreamParameters {
1835 mode: StreamMode::Format10x10,
1836 };
1837 let cmds = EnsembleStreamProtocol::build_cmds(¶ms);
1838 let mut p = EnsembleStreamParameters::default();
1839 EnsembleStreamProtocol::parse_cmds(&mut p, &cmds);
1840
1841 assert_eq!(params, p);
1842 }
1843
1844 #[test]
1845 fn vendorcmd_from() {
1846 let cmd = EnsembleCmd::InputLimit(1, true);
1847 assert_eq!(
1848 cmd,
1849 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1850 );
1851
1852 let cmd = EnsembleCmd::MicPower(1, true);
1853 assert_eq!(
1854 cmd,
1855 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1856 );
1857
1858 let cmd = EnsembleCmd::InputNominalLevel(1, InputNominalLevel::Microphone);
1859 assert_eq!(
1860 cmd,
1861 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1862 );
1863
1864 let cmd = EnsembleCmd::OutputNominalLevel(1, OutputNominalLevel::Consumer);
1865 assert_eq!(
1866 cmd,
1867 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1868 );
1869
1870 let cmd = EnsembleCmd::IoRouting(1, 11);
1871 assert_eq!(
1872 cmd,
1873 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1874 );
1875
1876 let cmd = EnsembleCmd::Hw(HwCmd::StreamMode(StreamMode::Format10x10));
1877 assert_eq!(
1878 cmd,
1879 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1880 );
1881
1882 let cmd = EnsembleCmd::HpSrc(1, 31);
1883 assert_eq!(
1884 cmd,
1885 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1886 );
1887
1888 let cmd = EnsembleCmd::MixerSrc0(3, [3; MIXER_COEFFICIENT_COUNT]);
1889 assert_eq!(
1890 cmd,
1891 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1892 );
1893
1894 let cmd = EnsembleCmd::MixerSrc1(2, [11; MIXER_COEFFICIENT_COUNT]);
1895 assert_eq!(
1896 cmd,
1897 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1898 );
1899
1900 let cmd = EnsembleCmd::MixerSrc2(1, [17; MIXER_COEFFICIENT_COUNT]);
1901 assert_eq!(
1902 cmd,
1903 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1904 );
1905
1906 let cmd = EnsembleCmd::MixerSrc3(0, [21; MIXER_COEFFICIENT_COUNT]);
1907 assert_eq!(
1908 cmd,
1909 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1910 );
1911
1912 let cmd = EnsembleCmd::MicGain(195, 233);
1913 assert_eq!(
1914 cmd,
1915 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1916 );
1917
1918 let cmd = EnsembleCmd::OutputOptIface(OptIfaceMode::Adat);
1919 assert_eq!(
1920 cmd,
1921 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1922 );
1923
1924 let cmd = EnsembleCmd::InputOptIface(OptIfaceMode::Spdif);
1925 assert_eq!(
1926 cmd,
1927 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1928 );
1929
1930 let cmd = EnsembleCmd::FormatConvert(FormatConvertTarget::AnalogInputPair0);
1931 assert_eq!(
1932 cmd,
1933 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1934 );
1935
1936 let cmd = EnsembleCmd::RateConvert(
1937 RateConvertTarget::SpdifOpticalInputPair0,
1938 RateConvertRate::R88200,
1939 );
1940 assert_eq!(
1941 cmd,
1942 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1943 );
1944
1945 let cmd = EnsembleCmd::MicPolarity(0, true);
1946 assert_eq!(
1947 cmd,
1948 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1949 );
1950
1951 let cmd = EnsembleCmd::OutVol(0, 113);
1952 assert_eq!(
1953 cmd,
1954 EnsembleCmd::from(Into::<Vec<u8>>::into(&cmd).as_slice())
1955 );
1956 }
1957}