1use super::*;
10
11#[derive(Debug, Copy, Clone, PartialEq, Eq)]
13pub enum V1ClkSrc {
14 Internal,
16 Spdif,
18 WordClk,
20 AdatOpt,
22 AdatDsub,
24 AesebuXlr,
26}
27
28impl Default for V1ClkSrc {
29 fn default() -> Self {
30 Self::Internal
31 }
32}
33
34#[derive(Debug, Copy, Clone, PartialEq, Eq)]
36pub enum V1OptIfaceMode {
37 Adat,
38 Spdif,
39}
40
41impl Default for V1OptIfaceMode {
42 fn default() -> Self {
43 Self::Adat
44 }
45}
46
47const CONF_828_OFFSET: u32 = 0x00000b00;
85
86const CONF_828_OPT_IN_IFACE_MASK: u32 = 0x00008000;
87const CONF_828_OPT_IN_IFACE_SHIFT: usize = 15;
88
89const CONF_828_OPT_OUT_IFACE_MASK: u32 = 0x00004000;
90const CONF_828_OPT_OUT_IFACE_SHIFT: usize = 14;
91
92const CONF_828_OPT_IFACE_VALS: [u8; 2] = [0x00, 0x01];
93
94const CONF_828_MONITOR_INPUT_CH_MASK: u32 = 0x00003f00;
95const CONF_828_MONITOR_INPUT_CH_SHIFT: usize = 8;
96const CONF_828_MONITOR_INPUT_CH_VALS: &[u8] = &[
97 0x08, 0x1a, 0x2c, 0x3e, 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, ];
110
111const CONF_828_STREAM_INPUT_ENABLE_MASK: u32 = 0x00000080;
112
113const CONF_828_MONITOR_INPUT_DISABLE_MASK: u32 = 0x00000040;
114
115const CONF_828_OUTPUT_ENABLE_MASK: u32 = 0x00000008;
116
117const CONF_828_CLK_RATE_MASK: u32 = 0x00000004;
118const CONF_828_CLK_RATE_SHIFT: usize = 2;
119
120const CONF_828_CLK_SRC_MASK: u32 = 0x00000023;
121const CONF_828_CLK_SRC_SHIFT: usize = 0;
122
123const CONF_896_MONITOR_INPUT_AESEBU_MASK: u32 = 0x00100000;
215const CONF_896_MONITOR_INPUT_AESEBU_SHIFT: usize = 20;
216const CONF_896_MONITOR_INPUT_CH_VALS: &[u8] = &[
217 0x00, 0x48, 0x5a, 0x6c, 0x7e, 0x40, 0x49, 0x52, 0x5b, 0x64, 0x6d, 0x76, 0x7f, ];
231
232const CONF_896_MONITOR_INPUT_CH_MASK: u32 = 0x0000ff00;
233const CONF_896_MONITOR_INPUT_CH_SHIFT: usize = 8;
234const CONF_896_MONITOR_INPUT_VALS: &[(usize, usize)] = &[
235 (0, 0),
236 (1, 0),
237 (2, 0),
238 (3, 0),
239 (4, 0),
240 (1, 1),
241 (5, 0),
242 (6, 0),
243 (7, 0),
244 (8, 0),
245 (9, 0),
246 (10, 0),
247 (11, 0),
248 (12, 0),
249 (5, 1),
250];
251
252const CONF_896_CLK_RATE_MASK: u32 = 0x00000018;
253const CONF_896_CLK_RATE_SHIFT: usize = 3;
254
255const CONF_896_CLK_SRC_MASK: u32 = 0x00000007;
256const CONF_896_CLK_SRC_SHIFT: usize = 0;
257
258const CLK_RATE_LABEL: &str = "clock-rate-v1";
259const CLK_SRC_LABEL: &str = "clock-source-v1";
260
261#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
263pub struct Version1ClockParameters {
264 pub rate: ClkRate,
266 pub source: V1ClkSrc,
268}
269
270pub trait MotuVersion1ClockSpecification {
272 const CLK_OFFSET: u32;
273
274 const CLK_RATE_MASK: u32;
275 const CLK_RATE_SHIFT: usize;
276 const CLK_RATE_VALS: &'static [u8];
277 const CLK_RATES: &'static [ClkRate];
278
279 const CLK_SRC_MASK: u32;
280 const CLK_SRC_SHIFT: usize;
281 const CLK_SRC_VALS: &'static [u8];
282 const CLK_SRCS: &'static [V1ClkSrc];
283}
284
285impl<O> MotuWhollyCacheableParamsOperation<Version1ClockParameters> for O
286where
287 O: MotuVersion1ClockSpecification,
288{
289 fn cache_wholly(
290 req: &mut FwReq,
291 node: &mut FwNode,
292 params: &mut Version1ClockParameters,
293 timeout_ms: u32,
294 ) -> Result<(), Error> {
295 let quad = read_quad(req, node, Self::CLK_OFFSET, timeout_ms)?;
296
297 deserialize_flag(
298 &mut params.rate,
299 &quad,
300 Self::CLK_RATE_MASK,
301 Self::CLK_RATE_SHIFT,
302 Self::CLK_RATES,
303 Self::CLK_RATE_VALS,
304 CLK_RATE_LABEL,
305 )?;
306
307 deserialize_flag(
308 &mut params.source,
309 &quad,
310 Self::CLK_SRC_MASK,
311 Self::CLK_SRC_SHIFT,
312 Self::CLK_SRCS,
313 Self::CLK_SRC_VALS,
314 CLK_SRC_LABEL,
315 )
316 }
317}
318
319impl<O> MotuWhollyUpdatableParamsOperation<Version1ClockParameters> for O
320where
321 O: MotuVersion1ClockSpecification,
322{
323 fn update_wholly(
324 req: &mut FwReq,
325 node: &mut FwNode,
326 params: &Version1ClockParameters,
327 timeout_ms: u32,
328 ) -> Result<(), Error> {
329 let mut quad = read_quad(req, node, Self::CLK_OFFSET, timeout_ms)?;
330
331 serialize_flag(
332 ¶ms.rate,
333 &mut quad,
334 Self::CLK_RATE_MASK,
335 Self::CLK_RATE_SHIFT,
336 Self::CLK_RATES,
337 Self::CLK_RATE_VALS,
338 CLK_RATE_LABEL,
339 )?;
340
341 serialize_flag(
342 ¶ms.source,
343 &mut quad,
344 Self::CLK_SRC_MASK,
345 Self::CLK_SRC_SHIFT,
346 Self::CLK_SRCS,
347 Self::CLK_SRC_VALS,
348 CLK_SRC_LABEL,
349 )?;
350
351 write_quad(req, node, Self::CLK_OFFSET, quad, timeout_ms)
352 }
353}
354
355#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
357pub struct Version1MonitorInputParameters(pub TargetPort);
358
359pub trait MotuVersion1MonitorInputSpecification {
361 const MONITOR_INPUT_MODES: &'static [TargetPort];
362}
363
364const MONITOR_INPUT_CH_LABEL: &str = "monitor-input-ch-v1";
365
366#[derive(Default)]
368pub struct F828Protocol;
369
370impl MotuVersion1ClockSpecification for F828Protocol {
371 const CLK_OFFSET: u32 = CONF_828_OFFSET;
372
373 const CLK_RATE_MASK: u32 = CONF_828_CLK_RATE_MASK;
374 const CLK_RATE_SHIFT: usize = CONF_828_CLK_RATE_SHIFT;
375 const CLK_RATE_VALS: &'static [u8] = &[0x00, 0x01];
376 const CLK_RATES: &'static [ClkRate] = &[ClkRate::R44100, ClkRate::R48000];
377
378 const CLK_SRC_MASK: u32 = CONF_828_CLK_SRC_MASK;
379 const CLK_SRC_SHIFT: usize = CONF_828_CLK_SRC_SHIFT;
380 const CLK_SRC_VALS: &'static [u8] = &[0x00, 0x01, 0x02, 0x21];
381 const CLK_SRCS: &'static [V1ClkSrc] = &[
382 V1ClkSrc::Internal,
383 V1ClkSrc::AdatDsub,
384 V1ClkSrc::Spdif,
385 V1ClkSrc::AdatOpt,
386 ];
387}
388
389impl MotuVersion1MonitorInputSpecification for F828Protocol {
390 const MONITOR_INPUT_MODES: &'static [TargetPort] = &[
391 TargetPort::Disabled,
392 TargetPort::AnalogPair(0),
393 TargetPort::AnalogPair(1),
394 TargetPort::AnalogPair(2),
395 TargetPort::AnalogPair(3),
396 TargetPort::Analog(0),
397 TargetPort::Analog(1),
398 TargetPort::Analog(2),
399 TargetPort::Analog(3),
400 TargetPort::Analog(4),
401 TargetPort::Analog(5),
402 TargetPort::Analog(6),
403 TargetPort::Analog(7),
404 ];
405}
406
407impl MotuWhollyCacheableParamsOperation<Version1MonitorInputParameters> for F828Protocol {
408 fn cache_wholly(
409 req: &mut FwReq,
410 node: &mut FwNode,
411 params: &mut Version1MonitorInputParameters,
412 timeout_ms: u32,
413 ) -> Result<(), Error> {
414 let quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
415
416 if quad & CONF_828_MONITOR_INPUT_DISABLE_MASK > 0 {
417 params.0 = TargetPort::Disabled;
418 Ok(())
419 } else {
420 deserialize_flag(
421 &mut params.0,
422 &quad,
423 CONF_828_MONITOR_INPUT_CH_MASK,
424 CONF_828_MONITOR_INPUT_CH_SHIFT,
425 &Self::MONITOR_INPUT_MODES[1..],
426 CONF_828_MONITOR_INPUT_CH_VALS,
427 MONITOR_INPUT_CH_LABEL,
428 )
429 }
430 }
431}
432
433impl MotuWhollyUpdatableParamsOperation<Version1MonitorInputParameters> for F828Protocol {
434 fn update_wholly(
435 req: &mut FwReq,
436 node: &mut FwNode,
437 params: &Version1MonitorInputParameters,
438 timeout_ms: u32,
439 ) -> Result<(), Error> {
440 if Self::MONITOR_INPUT_MODES
441 .iter()
442 .find(|m| params.0.eq(m))
443 .is_none()
444 {
445 let msg = format!("{:?} is not supported for monitor input", params.0);
446 Err(Error::new(FileError::Inval, &msg))?;
447 }
448
449 let mut quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
450
451 if params.0 == TargetPort::Disabled {
452 quad |= CONF_828_MONITOR_INPUT_DISABLE_MASK;
453 } else {
454 quad &= !CONF_828_MONITOR_INPUT_DISABLE_MASK;
455 serialize_flag(
456 ¶ms.0,
457 &mut quad,
458 CONF_828_MONITOR_INPUT_CH_MASK,
459 CONF_828_MONITOR_INPUT_CH_SHIFT,
460 &<F828Protocol as MotuVersion1MonitorInputSpecification>::MONITOR_INPUT_MODES[1..],
461 CONF_828_MONITOR_INPUT_CH_VALS,
462 MONITOR_INPUT_CH_LABEL,
463 )?;
464 }
465
466 write_quad(req, node, CONF_828_OFFSET, quad, timeout_ms)
467 }
468}
469
470#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
472pub struct F828OpticalIfaceParameters {
473 pub input_mode: V1OptIfaceMode,
475 pub output_mode: V1OptIfaceMode,
477}
478
479const CONF_828_OPT_OUT_IFACE_LABEL: &str = "opt-out-iface-v1";
480const CONF_828_OPT_IN_IFACE_LABEL: &str = "opt-in-iface-v1";
481
482impl F828Protocol {
483 pub const OPT_IFACE_MODES: &[V1OptIfaceMode] = &[V1OptIfaceMode::Adat, V1OptIfaceMode::Spdif];
485}
486
487impl MotuWhollyCacheableParamsOperation<F828OpticalIfaceParameters> for F828Protocol {
488 fn cache_wholly(
489 req: &mut FwReq,
490 node: &mut FwNode,
491 params: &mut F828OpticalIfaceParameters,
492 timeout_ms: u32,
493 ) -> Result<(), Error> {
494 let quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
495
496 deserialize_flag(
497 &mut params.input_mode,
498 &quad,
499 CONF_828_OPT_IN_IFACE_MASK,
500 CONF_828_OPT_IN_IFACE_SHIFT,
501 Self::OPT_IFACE_MODES,
502 &CONF_828_OPT_IFACE_VALS,
503 CONF_828_OPT_IN_IFACE_LABEL,
504 )?;
505
506 deserialize_flag(
507 &mut params.output_mode,
508 &quad,
509 CONF_828_OPT_OUT_IFACE_MASK,
510 CONF_828_OPT_OUT_IFACE_SHIFT,
511 Self::OPT_IFACE_MODES,
512 &CONF_828_OPT_IFACE_VALS,
513 CONF_828_OPT_OUT_IFACE_LABEL,
514 )
515 }
516}
517
518impl MotuWhollyUpdatableParamsOperation<F828OpticalIfaceParameters> for F828Protocol {
519 fn update_wholly(
520 req: &mut FwReq,
521 node: &mut FwNode,
522 params: &F828OpticalIfaceParameters,
523 timeout_ms: u32,
524 ) -> Result<(), Error> {
525 let mut quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
526
527 serialize_flag(
528 ¶ms.input_mode,
529 &mut quad,
530 CONF_828_OPT_IN_IFACE_MASK,
531 CONF_828_OPT_IN_IFACE_SHIFT,
532 Self::OPT_IFACE_MODES,
533 &CONF_828_OPT_IFACE_VALS,
534 CONF_828_OPT_IN_IFACE_LABEL,
535 )?;
536
537 serialize_flag(
538 ¶ms.output_mode,
539 &mut quad,
540 CONF_828_OPT_OUT_IFACE_MASK,
541 CONF_828_OPT_OUT_IFACE_SHIFT,
542 Self::OPT_IFACE_MODES,
543 &CONF_828_OPT_IFACE_VALS,
544 CONF_828_OPT_OUT_IFACE_LABEL,
545 )?;
546
547 write_quad(req, node, CONF_828_OFFSET, quad, timeout_ms)
548 }
549}
550
551#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
553pub struct F828StreamInputParameters(pub bool);
554
555impl MotuWhollyCacheableParamsOperation<F828StreamInputParameters> for F828Protocol {
556 fn cache_wholly(
557 req: &mut FwReq,
558 node: &mut FwNode,
559 params: &mut F828StreamInputParameters,
560 timeout_ms: u32,
561 ) -> Result<(), Error> {
562 let quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
563
564 params.0 = quad & CONF_828_STREAM_INPUT_ENABLE_MASK > 0;
565
566 Ok(())
567 }
568}
569
570impl MotuWhollyUpdatableParamsOperation<F828StreamInputParameters> for F828Protocol {
571 fn update_wholly(
572 req: &mut FwReq,
573 node: &mut FwNode,
574 params: &F828StreamInputParameters,
575 timeout_ms: u32,
576 ) -> Result<(), Error> {
577 let mut quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
578
579 quad &= !CONF_828_STREAM_INPUT_ENABLE_MASK;
580 if params.0 {
581 quad |= CONF_828_STREAM_INPUT_ENABLE_MASK;
582 }
583
584 write_quad(req, node, CONF_828_OFFSET, quad, timeout_ms)
585 }
586}
587
588#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
590pub struct F828OutputParameters(pub bool);
591
592impl MotuWhollyCacheableParamsOperation<F828OutputParameters> for F828Protocol {
593 fn cache_wholly(
594 req: &mut FwReq,
595 node: &mut FwNode,
596 params: &mut F828OutputParameters,
597 timeout_ms: u32,
598 ) -> Result<(), Error> {
599 let quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
600
601 params.0 = quad & CONF_828_OUTPUT_ENABLE_MASK > 0;
602
603 Ok(())
604 }
605}
606
607impl MotuWhollyUpdatableParamsOperation<F828OutputParameters> for F828Protocol {
608 fn update_wholly(
609 req: &mut FwReq,
610 node: &mut FwNode,
611 params: &F828OutputParameters,
612 timeout_ms: u32,
613 ) -> Result<(), Error> {
614 let mut quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
615
616 quad &= !CONF_828_OUTPUT_ENABLE_MASK;
617 if params.0 {
618 quad |= CONF_828_OUTPUT_ENABLE_MASK;
619 }
620
621 write_quad(req, node, CONF_828_OFFSET, quad, timeout_ms)
622 }
623}
624
625#[derive(Default)]
627pub struct F896Protocol;
628
629impl F896Protocol {
630 pub const NOTIFY_FOOTSWITCH_MASK: u32 = 0x01000000;
632}
633
634impl MotuWordClockOutputSpecification for F896Protocol {}
635
636impl MotuVersion1ClockSpecification for F896Protocol {
637 const CLK_OFFSET: u32 = OFFSET_CLK;
638
639 const CLK_RATE_MASK: u32 = CONF_896_CLK_RATE_MASK;
640 const CLK_RATE_SHIFT: usize = CONF_896_CLK_RATE_SHIFT;
641 const CLK_RATE_VALS: &'static [u8] = &[0x00, 0x01, 0x02, 0x03];
642 const CLK_RATES: &'static [ClkRate] = &[
643 ClkRate::R44100,
644 ClkRate::R48000,
645 ClkRate::R88200,
646 ClkRate::R96000,
647 ];
648
649 const CLK_SRC_MASK: u32 = CONF_896_CLK_SRC_MASK;
650 const CLK_SRC_SHIFT: usize = CONF_896_CLK_SRC_SHIFT;
651 const CLK_SRC_VALS: &'static [u8] = &[0x00, 0x01, 0x02, 0x04, 0x05];
652 const CLK_SRCS: &'static [V1ClkSrc] = &[
653 V1ClkSrc::Internal,
654 V1ClkSrc::AdatOpt,
655 V1ClkSrc::AesebuXlr,
656 V1ClkSrc::WordClk,
657 V1ClkSrc::AdatDsub,
658 ];
659}
660
661impl MotuVersion1MonitorInputSpecification for F896Protocol {
662 const MONITOR_INPUT_MODES: &'static [TargetPort] = &[
663 TargetPort::Disabled,
664 TargetPort::AnalogPair(0),
665 TargetPort::AnalogPair(1),
666 TargetPort::AnalogPair(2),
667 TargetPort::AnalogPair(3),
668 TargetPort::AesEbuPair,
669 TargetPort::Analog(0),
670 TargetPort::Analog(1),
671 TargetPort::Analog(2),
672 TargetPort::Analog(3),
673 TargetPort::Analog(4),
674 TargetPort::Analog(5),
675 TargetPort::Analog(6),
676 TargetPort::Analog(7),
677 TargetPort::AesEbu(0),
678 TargetPort::AesEbu(1),
679 ];
680}
681
682impl MotuWhollyCacheableParamsOperation<Version1MonitorInputParameters> for F896Protocol {
683 fn cache_wholly(
684 req: &mut FwReq,
685 node: &mut FwNode,
686 params: &mut Version1MonitorInputParameters,
687 timeout_ms: u32,
688 ) -> Result<(), Error> {
689 let quad = read_quad(req, node, OFFSET_CLK, timeout_ms)?;
690
691 let aesebu_idx = ((quad & CONF_896_MONITOR_INPUT_AESEBU_MASK)
692 >> CONF_896_MONITOR_INPUT_AESEBU_SHIFT) as usize;
693 let ch_idx =
694 ((quad & CONF_896_MONITOR_INPUT_CH_MASK) >> CONF_896_MONITOR_INPUT_CH_SHIFT) as usize;
695
696 Self::MONITOR_INPUT_MODES
697 .iter()
698 .zip(CONF_896_MONITOR_INPUT_VALS)
699 .find(|(_, entry)| (ch_idx, aesebu_idx).eq(entry))
700 .ok_or_else(|| {
701 let label = "Detect invalid value for monitor input";
702 Error::new(FileError::Io, &label)
703 })
704 .map(|(&mode, _)| params.0 = mode)
705 }
706}
707
708impl MotuWhollyUpdatableParamsOperation<Version1MonitorInputParameters> for F896Protocol {
709 fn update_wholly(
710 req: &mut FwReq,
711 node: &mut FwNode,
712 params: &Version1MonitorInputParameters,
713 timeout_ms: u32,
714 ) -> Result<(), Error> {
715 let (ch_idx, aesebu_idx) = Self::MONITOR_INPUT_MODES
716 .iter()
717 .zip(CONF_896_MONITOR_INPUT_VALS)
718 .find(|(m, _)| params.0.eq(m))
719 .ok_or_else(|| {
720 let msg = format!("{:?} is not supported for monitor input", params.0);
721 Error::new(FileError::Io, &msg)
722 })
723 .map(|(_, &entry)| entry)?;
724
725 let mut quad = read_quad(req, node, OFFSET_CLK, timeout_ms)?;
726
727 quad &= !CONF_896_MONITOR_INPUT_AESEBU_MASK;
728 if aesebu_idx > 0 {
729 quad |= (aesebu_idx as u32) << CONF_896_MONITOR_INPUT_AESEBU_SHIFT;
730 }
731
732 quad &= !CONF_896_MONITOR_INPUT_CH_MASK;
733 quad |= (CONF_896_MONITOR_INPUT_CH_VALS[ch_idx] as u32) << CONF_896_MONITOR_INPUT_CH_SHIFT;
734
735 write_quad(req, node, OFFSET_CLK, quad, timeout_ms)
736 }
737}
738
739impl MotuAesebuRateConvertSpecification for F896Protocol {
740 const AESEBU_RATE_CONVERT_MASK: u32 = 0x00000060;
741 const AESEBU_RATE_CONVERT_SHIFT: usize = 5;
742}
743
744impl MotuLevelMetersSpecification for F896Protocol {
745 const LEVEL_METERS_PROGRAMMABLE_MODES: &'static [LevelMetersProgrammableMode] = &[
746 LevelMetersProgrammableMode::AnalogOutput,
747 LevelMetersProgrammableMode::AdatAInput,
748 LevelMetersProgrammableMode::AdatAOutput,
749 ];
750}
751
752#[cfg(test)]
753mod test {
754 use super::*;
755
756 #[test]
757 fn v1_clock_specification() {
758 assert_eq!(
759 F828Protocol::CLK_RATE_VALS.len(),
760 F828Protocol::CLK_RATES.len()
761 );
762 assert_eq!(
763 F828Protocol::CLK_SRC_VALS.len(),
764 F828Protocol::CLK_SRCS.len()
765 );
766
767 assert_eq!(
768 F896Protocol::CLK_RATE_VALS.len(),
769 F896Protocol::CLK_RATES.len()
770 );
771 assert_eq!(
772 F896Protocol::CLK_SRC_VALS.len(),
773 F896Protocol::CLK_SRCS.len()
774 );
775 }
776}