1#![doc = include_str!("../README.md")]
5
6pub mod asynch;
62pub mod isoch;
63
64pub mod config_rom;
65
66use {
67 glib::{Error, FileError},
68 hinawa::{prelude::*, *},
69};
70
71const BASE_OFFSET: u64 = 0xffff00000000;
72const HW_INFO_REGISTER_OFFSET: u64 = 0x00;
73const HW_INFO_FPGA_OFFSET: u64 = 0x04;
74const HW_INFO_ARM_OFFSET: u64 = 0x08;
75const HW_INFO_HW_OFFSET: u64 = 0x0c;
76const LED_OFFSET: u64 = 0x0404;
77
78fn read_quadlet(
79 req: &mut FwReq,
80 node: &mut FwNode,
81 offset: u64,
82 frames: &mut [u8],
83 timeout_ms: u32,
84) -> Result<(), Error> {
85 req.transaction_sync(
86 node,
87 FwTcode::ReadQuadletRequest,
88 BASE_OFFSET + offset,
89 4,
90 frames,
91 timeout_ms,
92 )
93}
94
95fn write_quadlet(
96 req: &mut FwReq,
97 node: &FwNode,
98 offset: u64,
99 frames: &mut [u8],
100 timeout_ms: u32,
101) -> Result<(), Error> {
102 req.transaction_sync(
103 node,
104 FwTcode::WriteQuadletRequest,
105 BASE_OFFSET + offset,
106 4,
107 frames,
108 timeout_ms,
109 )
110}
111
112#[derive(Debug, Default, Copy, Clone)]
114pub struct HardwareInformation {
115 pub register: u32,
116 pub fpga: u32,
117 pub arm: u32,
118 pub hardware: u32,
119}
120
121#[derive(Debug, Default)]
123pub struct HardwareInformationProtocol;
124
125impl HardwareInformationProtocol {
127 pub fn read_hardware_information(
128 req: &mut FwReq,
129 node: &mut FwNode,
130 info: &mut HardwareInformation,
131 timeout_ms: u32,
132 ) -> Result<(), Error> {
133 let mut quads = [0; 4];
134 read_quadlet(req, node, HW_INFO_REGISTER_OFFSET, &mut quads, timeout_ms)
135 .map(|_| info.register = u32::from_be_bytes(quads))?;
136 read_quadlet(req, node, HW_INFO_FPGA_OFFSET, &mut quads, timeout_ms)
137 .map(|_| info.fpga = u32::from_be_bytes(quads))?;
138 read_quadlet(req, node, HW_INFO_ARM_OFFSET, &mut quads, timeout_ms)
139 .map(|_| info.arm = u32::from_be_bytes(quads))?;
140 read_quadlet(req, node, HW_INFO_HW_OFFSET, &mut quads, timeout_ms)
141 .map(|_| info.hardware = u32::from_be_bytes(quads))?;
142 Ok(())
143 }
144}
145
146pub trait TascamHardwareImageSpecification {
148 const IMAGE_QUADLET_COUNT: usize;
149
150 fn create_hardware_image() -> Vec<u32> {
151 vec![0; Self::IMAGE_QUADLET_COUNT]
152 }
153}
154
155#[derive(Debug, Copy, Clone, PartialEq, Eq)]
157pub enum MachineItem {
158 Master,
160 Ol(usize),
161 Rec(usize),
162 Signal(usize),
163 Rotary(usize),
164 Select(usize),
165 Solo(usize),
166 Mute(usize),
167 Input(usize),
168 Func(usize),
169 Pfl,
170
171 Read,
173 Wrt,
174 Tch,
175 Latch,
176 Wheel,
177 Shuttle,
178 Computer,
179 Clock,
180 Up,
181 Left,
182 Down,
183 Right,
184 NudgeLeft,
185 NudgeRight,
186 LocateLeft,
187 LocateRight,
188 Set,
189 In,
190 Out,
191
192 Flip,
194 Pan, Aux(usize),
196 EncoderMode, High,
200 HighMid,
201 LowMid,
202 Low,
203 Recall,
204 Gain,
205 Freq,
206 Q,
207
208 Bank,
210
211 Rew,
213 Fwd,
214 Stop,
215 Play,
216 Record,
217
218 Panel,
220 Save,
221 Revert,
222 AllSafe,
223 ClrSolo,
224 Markers,
225 Loop,
226 Cut,
227 Del,
228 Copy,
229 Paste,
230 Alt,
231 Cmd,
232 Undo,
233 Shift,
234 Ctrl,
235}
236
237impl Default for MachineItem {
238 fn default() -> Self {
239 Self::Master
240 }
241}
242
243impl std::fmt::Display for MachineItem {
244 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
245 match self {
246 Self::Master => write!(f, "master"),
247 Self::Ol(ch) => write!(f, "ol {}", ch),
248 Self::Rec(ch) => write!(f, "rec {}", ch),
249 Self::Signal(ch) => write!(f, "signal {}", ch),
250 Self::Rotary(ch) => write!(f, "rotary {}", ch),
251 Self::Select(ch) => write!(f, "select {}", ch),
252 Self::Solo(ch) => write!(f, "solo {}", ch),
253 Self::Mute(ch) => write!(f, "mute {}", ch),
254 Self::Input(ch) => write!(f, "input {}", ch),
255 Self::Func(ch) => write!(f, "func {}", ch),
256 Self::Pfl => write!(f, "pfl"),
257 Self::Read => write!(f, "read"),
258 Self::Wrt => write!(f, "wrt"),
259 Self::Tch => write!(f, "tch"),
260 Self::Latch => write!(f, "latch"),
261 Self::Wheel => write!(f, "wheel"),
262 Self::Shuttle => write!(f, "Shuttle"),
263 Self::Computer => write!(f, "computer"),
264 Self::Clock => write!(f, "clock"),
265 Self::Up => write!(f, "up"),
266 Self::Left => write!(f, "left"),
267 Self::Down => write!(f, "down"),
268 Self::Right => write!(f, "right"),
269 Self::NudgeLeft => write!(f, "nudge left"),
270 Self::NudgeRight => write!(f, "nudge right"),
271 Self::LocateLeft => write!(f, "locate left"),
272 Self::LocateRight => write!(f, "locate right"),
273 Self::Set => write!(f, "set"),
274 Self::In => write!(f, "in"),
275 Self::Out => write!(f, "out"),
276 Self::Flip => write!(f, "flip"),
277 Self::Pan => write!(f, "pan"),
278 Self::Aux(ch) => write!(f, "aux {}", ch),
279 Self::EncoderMode => write!(f, "encoder model"),
280 Self::High => write!(f, "high"),
281 Self::HighMid => write!(f, "high-mid"),
282 Self::LowMid => write!(f, "low-mid"),
283 Self::Low => write!(f, "low"),
284 Self::Recall => write!(f, "recall"),
285 Self::Gain => write!(f, "gain"),
286 Self::Freq => write!(f, "freq"),
287 Self::Q => write!(f, "q"),
288 Self::Bank => write!(f, "bank"),
289 Self::Rew => write!(f, "rew"),
290 Self::Fwd => write!(f, "fwd"),
291 Self::Stop => write!(f, "stop"),
292 Self::Play => write!(f, "play"),
293 Self::Record => write!(f, "record"),
294 Self::Panel => write!(f, "panel"),
295 Self::Save => write!(f, "save"),
296 Self::Revert => write!(f, "revert"),
297 Self::AllSafe => write!(f, "all safe"),
298 Self::ClrSolo => write!(f, "clr solo"),
299 Self::Markers => write!(f, "markers"),
300 Self::Loop => write!(f, "loop"),
301 Self::Cut => write!(f, "cut"),
302 Self::Del => write!(f, "del"),
303 Self::Copy => write!(f, "copy"),
304 Self::Paste => write!(f, "paste"),
305 Self::Alt => write!(f, "alt"),
306 Self::Cmd => write!(f, "cmd"),
307 Self::Undo => write!(f, "undo"),
308 Self::Shift => write!(f, "shift"),
309 Self::Ctrl => write!(f, "ctrl"),
310 }
311 }
312}
313
314#[derive(Default, Debug, Clone, PartialEq, Eq)]
316pub struct MachineState {
317 bool_items: Vec<bool>,
319 u16_items: Vec<u16>,
321 bank: u16,
323 transport: MachineItem,
325}
326
327#[derive(Debug, Copy, Clone, PartialEq, Eq)]
329pub enum ItemValue {
330 Bool(bool),
331 U16(u16),
332}
333
334const BANK_MIN: u16 = 0;
335const BANK_MAX: u16 = 3;
336
337pub trait MachineStateOperation {
339 const BOOL_ITEMS: &'static [MachineItem];
340 const U16_ITEMS: &'static [MachineItem];
341 const HAS_TRANSPORT: bool;
342 const HAS_BANK: bool;
343
344 const BANK_MIN: u16 = BANK_MIN;
345 const BANK_MAX: u16 = BANK_MAX;
346
347 const U16_ITEM_MIN: u16 = 0;
348 const U16_ITEM_MAX: u16 = 0xffffu16;
349
350 const TRANSPORT_ITEMS: [MachineItem; 5] = [
351 MachineItem::Rew,
352 MachineItem::Fwd,
353 MachineItem::Stop,
354 MachineItem::Play,
355 MachineItem::Record,
356 ];
357
358 const EQ_BAND_ITEMS: [MachineItem; 4] = [
359 MachineItem::High,
360 MachineItem::HighMid,
361 MachineItem::LowMid,
362 MachineItem::Low,
363 ];
364
365 fn create_machine_state() -> MachineState {
366 MachineState {
367 bool_items: vec![false; Self::BOOL_ITEMS.len()],
368 u16_items: vec![0; Self::U16_ITEMS.len()],
369 bank: 0,
370 transport: MachineItem::Stop,
371 }
372 }
373
374 fn get_machine_current_values(state: &MachineState) -> Vec<(MachineItem, ItemValue)> {
375 let mut machine_values = Vec::new();
376
377 Self::BOOL_ITEMS
378 .iter()
379 .zip(&state.bool_items)
380 .for_each(|(&item, &value)| machine_values.push((item, ItemValue::Bool(value))));
381
382 Self::U16_ITEMS
383 .iter()
384 .zip(&state.u16_items)
385 .for_each(|(&item, &value)| machine_values.push((item, ItemValue::U16(value))));
386
387 if Self::HAS_BANK {
388 machine_values.push((MachineItem::Bank, ItemValue::U16(state.bank)));
389 }
390
391 if Self::HAS_TRANSPORT {
392 Self::TRANSPORT_ITEMS.iter().for_each(|&item| {
393 machine_values.push((item, ItemValue::Bool(item.eq(&state.transport))));
394 });
395 }
396
397 machine_values
398 }
399
400 fn change_machine_value(
401 state: &mut MachineState,
402 input: &(MachineItem, ItemValue),
403 ) -> Vec<(MachineItem, ItemValue)> {
404 let mut outputs = Vec::new();
405
406 if let ItemValue::Bool(value) = input.1 {
407 let _ = Self::BOOL_ITEMS
409 .iter()
410 .zip(&mut state.bool_items)
411 .find(|(i, v)| input.0.eq(i) && !value.eq(v))
412 .map(|(_, v)| {
413 *v = value;
414 outputs.push((input.0, ItemValue::Bool(*v)));
415 });
416
417 if Self::HAS_TRANSPORT
419 && Self::TRANSPORT_ITEMS
420 .iter()
421 .find(|i| input.0.eq(i))
422 .is_some()
423 {
424 if input.0 != state.transport {
425 outputs.push((state.transport, ItemValue::Bool(false)));
426 outputs.push((input.0, ItemValue::Bool(true)));
427 state.transport = input.0;
428 }
429 }
430
431 if Self::EQ_BAND_ITEMS.iter().find(|i| input.0.eq(i)).is_some() {
433 if value {
434 Self::BOOL_ITEMS
435 .iter()
436 .zip(&mut state.bool_items)
437 .filter(|(i, v)| {
438 !input.0.eq(i)
439 && **v
440 && Self::EQ_BAND_ITEMS.iter().find(|item| item.eq(i)).is_some()
441 })
442 .for_each(|(i, v)| {
443 *v = false;
444 outputs.push((*i, ItemValue::Bool(*v)));
445 });
446 }
447 }
448 } else if let ItemValue::U16(value) = input.1 {
449 let _ = Self::U16_ITEMS
450 .iter()
451 .zip(&mut state.u16_items)
452 .find(|(i, v)| input.0.eq(i) && !value.eq(v))
453 .map(|(_, v)| {
454 *v = value;
455 outputs.push((input.0, ItemValue::U16(*v)));
456 });
457
458 if Self::HAS_BANK && input.0 == MachineItem::Bank {
459 if state.bank != value && value <= Self::BANK_MAX {
460 state.bank = value;
461 outputs.push((MachineItem::Bank, ItemValue::U16(state.bank)));
462 }
463 }
464 }
465
466 outputs
467 }
468}
469
470pub trait TascamSurfaceLedOperation<T> {
472 fn operate_leds(
473 state: &mut T,
474 machine_value: &(MachineItem, ItemValue),
475 req: &mut FwReq,
476 node: &mut FwNode,
477 timeout_ms: u32,
478 ) -> Result<(), Error>;
479
480 fn clear_leds(
481 state: &mut T,
482 req: &mut FwReq,
483 node: &mut FwNode,
484 timeout_ms: u32,
485 ) -> Result<(), Error>;
486}
487
488pub trait TascamSurfaceStateOperation<T> {
490 fn init(state: &mut T);
492
493 fn peek(
495 state: &T,
496 image: &[u32],
497 index: u32,
498 before: u32,
499 after: u32,
500 ) -> Vec<(MachineItem, ItemValue)>;
501
502 fn ack(state: &mut T, machine_value: &(MachineItem, ItemValue));
504}
505
506#[derive(Default, Debug, Clone, PartialEq, Eq)]
508pub struct TascamSurfaceCommonState {
509 stateful_items: Vec<bool>,
510 enabled_leds: LedState,
511}
512
513pub trait TascamSurfaceLedNormalSpecification {
515 const NORMAL_LEDS: &'static [(&'static [MachineItem], &'static [u16])];
516}
517
518impl<O> TascamSurfaceLedOperation<TascamSurfaceCommonState> for O
519where
520 O: TascamSurfaceLedNormalSpecification,
521{
522 fn operate_leds(
523 state: &mut TascamSurfaceCommonState,
524 machine_value: &(MachineItem, ItemValue),
525 req: &mut FwReq,
526 node: &mut FwNode,
527 timeout_ms: u32,
528 ) -> Result<(), Error> {
529 if let ItemValue::Bool(value) = machine_value.1 {
530 if let Some((_, positions)) = Self::NORMAL_LEDS.iter().find(|(items, _)| {
531 if items.len() == 1 {
532 machine_value.0.eq(&items[0])
533 } else {
534 items.iter().find(|i| machine_value.0.eq(i)).is_some()
535 }
536 }) {
537 operate_led_cached(
538 &mut state.enabled_leds,
539 req,
540 node,
541 positions[0],
542 value,
543 timeout_ms,
544 )?;
545 }
546 }
547
548 Ok(())
549 }
550
551 fn clear_leds(
552 state: &mut TascamSurfaceCommonState,
553 req: &mut FwReq,
554 node: &mut FwNode,
555 timeout_ms: u32,
556 ) -> Result<(), Error> {
557 clear_leds(&mut state.enabled_leds, req, node, timeout_ms)
558 }
559}
560
561pub trait TascamSurfaceStateCommonSpecification {
563 const STATEFUL_ITEMS: &'static [(SurfaceBoolValue, MachineItem)];
565 const STATELESS_ITEMS: &'static [(SurfaceBoolValue, MachineItem)];
567 const ROTARIES: &'static [(SurfaceU16Value, MachineItem)];
569 const FADERS: &'static [(SurfaceBoolValue, SurfaceU16Value, MachineItem)];
571}
572
573impl<O> TascamSurfaceStateOperation<TascamSurfaceCommonState> for O
574where
575 O: TascamSurfaceStateCommonSpecification,
576{
577 fn init(state: &mut TascamSurfaceCommonState) {
578 state.stateful_items = vec![Default::default(); Self::STATEFUL_ITEMS.len()];
579 }
580
581 fn peek(
582 state: &TascamSurfaceCommonState,
583 image: &[u32],
584 index: u32,
585 before: u32,
586 after: u32,
587 ) -> Vec<(MachineItem, ItemValue)> {
588 let mut machine_values = Vec::new();
589
590 Self::STATEFUL_ITEMS
591 .iter()
592 .zip(&state.stateful_items)
593 .filter(|((bool_val, _), _)| {
594 detect_stateful_bool_action(bool_val, index, before, after)
595 })
596 .for_each(|((_, item), &s)| machine_values.push((*item, ItemValue::Bool(!s))));
597
598 Self::STATELESS_ITEMS
599 .iter()
600 .filter(|(bool_val, _)| detect_bool_action(bool_val, index, before, after))
601 .for_each(|(bool_val, item)| {
602 let value = detect_bool_value(bool_val, before);
603 machine_values.push((*item, ItemValue::Bool(value)));
604 });
605
606 Self::ROTARIES
607 .iter()
608 .filter(|(u16_val, _)| detect_u16_action(u16_val, index, before, after))
609 .for_each(|(u16_val, item)| {
610 let value = detect_u16_value(u16_val, after);
611 machine_values.push((*item, ItemValue::U16(value)));
612 });
613
614 Self::FADERS
615 .iter()
616 .filter(|(bool_val, _, _)| detect_bool_action(bool_val, index, before, after))
617 .for_each(|(_, u16_val, item)| {
618 let value = detect_u16_value_in_image(u16_val, image);
619 machine_values.push((*item, ItemValue::U16(value)));
620 });
621
622 machine_values
623 }
624
625 fn ack(state: &mut TascamSurfaceCommonState, machine_value: &(MachineItem, ItemValue)) {
626 if let ItemValue::Bool(val) = machine_value.1 {
627 Self::STATEFUL_ITEMS
628 .iter()
629 .zip(&mut state.stateful_items)
630 .find(|((_, item), _)| machine_value.0.eq(item))
631 .map(|((_, _), s)| *s = val);
632 }
633 }
634}
635
636#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
638pub struct SurfaceBoolValue(usize, u32); #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
642pub struct SurfaceU16Value(usize, u32, usize); fn detect_stateful_bool_action(
645 bool_val: &SurfaceBoolValue,
646 index: u32,
647 before: u32,
648 after: u32,
649) -> bool {
650 bool_val.0 == index as usize && (before ^ after) & bool_val.1 > 0 && before & bool_val.1 > 0
651}
652
653fn detect_bool_action(bool_val: &SurfaceBoolValue, index: u32, before: u32, after: u32) -> bool {
654 bool_val.0 == index as usize && (before ^ after) & bool_val.1 > 0
655}
656
657fn detect_bool_value(bool_val: &SurfaceBoolValue, before: u32) -> bool {
658 before & bool_val.1 > 0
659}
660
661fn detect_u16_action(u16_val: &SurfaceU16Value, index: u32, before: u32, after: u32) -> bool {
662 u16_val.0 == index as usize && (before ^ after) & u16_val.1 > 0
663}
664
665fn detect_u16_value(u16_val: &SurfaceU16Value, after: u32) -> u16 {
666 ((after & u16_val.1) >> u16_val.2) as u16
667}
668
669fn detect_u16_value_in_image(u16_val: &SurfaceU16Value, image: &[u32]) -> u16 {
670 ((image[u16_val.0] & u16_val.1) >> u16_val.2) as u16
671}
672
673#[derive(Default, Debug, Clone, PartialEq, Eq)]
674struct LedState(Vec<u16>);
675
676fn operate_led(
677 req: &mut FwReq,
678 node: &mut FwNode,
679 pos: u16,
680 enable: bool,
681 timeout_ms: u32,
682) -> Result<(), Error> {
683 let mut frame = [0; 4];
684 frame[0..2].copy_from_slice(&(enable as u16).to_be_bytes());
685 frame[2..4].copy_from_slice(&pos.to_be_bytes());
686 write_quadlet(req, node, LED_OFFSET, &mut frame, timeout_ms)
687}
688
689fn operate_led_cached(
690 state: &mut LedState,
691 req: &mut FwReq,
692 node: &mut FwNode,
693 pos: u16,
694 enable: bool,
695 timeout_ms: u32,
696) -> Result<(), Error> {
697 operate_led(req, node, pos, enable, timeout_ms).map(|_| {
698 if !enable {
699 state.0.retain(|&p| p != pos);
700 } else if state.0.iter().find(|&p| *p == pos).is_none() {
701 state.0.push(pos);
702 }
703 })
704}
705
706fn clear_leds(
707 state: &mut LedState,
708 req: &mut FwReq,
709 node: &mut FwNode,
710 timeout_ms: u32,
711) -> Result<(), Error> {
712 let cache = state.0.to_vec();
713 cache
714 .iter()
715 .try_for_each(|&pos| operate_led_cached(state, req, node, pos, false, timeout_ms))
716}
717
718pub trait FireWireLedOperation {
720 const POSITIONS: &'static [u16];
721
722 fn operate_firewire_led(
723 req: &mut FwReq,
724 node: &mut FwNode,
725 enable: bool,
726 timeout_ms: u32,
727 ) -> Result<(), Error> {
728 operate_led(req, node, Self::POSITIONS[0], enable, timeout_ms)
729 }
730}