1use {
39 super::{
40 tcat::{
41 extension::{router_entry::*, *},
42 *,
43 },
44 *,
45 },
46 std::ops::Range,
47};
48
49const BASE_OFFSET: usize = 0x00200000;
50
51const MIXER_BUS_SRC_OFFSET: usize = 0x0000;
52const MIXER_MAIN_SRC_OFFSET: usize = 0x02d0;
53const MIXER_REVERB_SRC_OFFSET: usize = 0x0360;
54const METER_OFFSET: usize = 0x0500;
55const EFFECT_OFFSET: usize = 0x4000;
56
57const MIXER_BUS_SRC_SIZE: usize = 0x02d0;
58const MIXER_MAIN_SRC_SIZE: usize = 0x0090;
59const MIXER_REVERB_SRC_SIZE: usize = 0x090;
60const METER_SIZE: usize = 0x200;
61
62#[derive(Default, Debug)]
64pub struct IonixProtocol;
65
66impl TcatOperation for IonixProtocol {}
67
68impl TcatGlobalSectionSpecification for IonixProtocol {}
69
70impl LexiconOperation for IonixProtocol {}
71
72pub trait LexiconParametersSerdes<T> {
74 const NAME: &'static str;
76
77 const OFFSET_RANGES: &'static [Range<usize>];
79
80 fn serialize_params(params: &T, raw: &mut [u8]) -> Result<(), String>;
82
83 fn deserialize_params(params: &mut T, raw: &[u8]) -> Result<(), String>;
85}
86
87pub trait LexiconOperation: TcatOperation {
89 fn read_parameters(
91 req: &FwReq,
92 node: &FwNode,
93 offset: usize,
94 raw: &mut [u8],
95 timeout_ms: u32,
96 ) -> Result<(), Error> {
97 Self::read(req, node, BASE_OFFSET + offset, raw, timeout_ms)
98 }
99
100 fn write_parameters(
102 req: &FwReq,
103 node: &FwNode,
104 offset: usize,
105 raw: &mut [u8],
106 timeout_ms: u32,
107 ) -> Result<(), Error> {
108 Self::write(req, node, BASE_OFFSET + offset, raw, timeout_ms)
109 }
110}
111
112fn compute_params_size(ranges: &[Range<usize>]) -> usize {
113 ranges
114 .iter()
115 .fold(0usize, |size, range| size + range.end - range.start)
116}
117
118fn generate_err(name: &str, cause: &str, raw: &[u8]) -> Error {
119 let msg = format!("params: {}, cause: {}, raw: {:02x?}", name, cause, raw);
120 Error::new(GeneralProtocolError::VendorDependent, &msg)
121}
122
123pub trait LexiconParametersOperation<T>: LexiconOperation + LexiconParametersSerdes<T> {
125 fn cache_whole_params(
127 req: &FwReq,
128 node: &FwNode,
129 params: &mut T,
130 timeout_ms: u32,
131 ) -> Result<(), Error> {
132 let size = compute_params_size(Self::OFFSET_RANGES);
133 let mut raw = vec![0u8; size];
134
135 let mut pos = 0;
136
137 Self::OFFSET_RANGES.iter().try_for_each(|range| {
138 let size = range.end - range.start;
139 Self::read_parameters(
140 req,
141 node,
142 range.start,
143 &mut raw[pos..(pos + size)],
144 timeout_ms,
145 )
146 .map(|_| pos += size)
147 })?;
148
149 Self::deserialize_params(params, &raw)
150 .map_err(|cause| generate_err(Self::NAME, &cause, &raw))
151 }
152}
153
154impl<O: LexiconOperation + LexiconParametersSerdes<T>, T> LexiconParametersOperation<T> for O {}
155
156pub trait LexiconMutableParametersOperation<T>:
158 LexiconOperation + LexiconParametersSerdes<T>
159{
160 fn update_partial_parameters(
162 req: &FwReq,
163 node: &FwNode,
164 params: &T,
165 prev: &mut T,
166 timeout_ms: u32,
167 ) -> Result<(), Error> {
168 let size = compute_params_size(Self::OFFSET_RANGES);
169
170 let mut new = vec![0u8; size];
171 let mut old = vec![0u8; size];
172 Self::serialize_params(params, &mut new)
173 .map_err(|cause| generate_err(Self::NAME, &cause, &new))?;
174 Self::serialize_params(prev, &mut old)
175 .map_err(|cause| generate_err(Self::NAME, &cause, &old))?;
176
177 let mut pos = 0;
178
179 Self::OFFSET_RANGES.iter().try_for_each(|range| {
180 let size = range.end - range.start;
181
182 if new[pos..(pos + size)] != old[pos..(pos + size)] {
183 (0..size).step_by(4).try_for_each(|offset| {
184 let p = pos + offset;
185 if new[p..(p + 4)] != old[p..(p + 4)] {
186 Self::write_parameters(
187 req,
188 node,
189 range.start + offset,
190 &mut new[p..(p + 4)],
191 timeout_ms,
192 )
193 } else {
194 Ok(())
195 }
196 })
197 } else {
198 Ok(())
199 }
200 .map(|_| pos += size)
201 })?;
202
203 Self::deserialize_params(prev, &new).map_err(|cause| generate_err(Self::NAME, &cause, &new))
204 }
205}
206
207impl IonixProtocol {
208 pub const ANALOG_INPUT_COUNT: usize = 8;
210
211 pub const SPDIF_INPUT_COUNT: usize = 2;
213
214 pub const STREAM_INPUT_COUNT: usize = 10;
216
217 pub const MIXER_ANALOG_INPUT_COUNT: usize = 8;
219
220 pub const MIXER_SPDIF_INPUT_COUNT: usize = 2;
222
223 pub const MIXER_STREAM_INPUT_COUNT: usize = 8;
225
226 pub const MIXER_BUS_COUNT: usize = 8;
228
229 pub const MIXER_MAIN_COUNT: usize = 2;
231
232 pub const MIXER_REVERB_COUNT: usize = 2;
234}
235
236#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
238pub struct IonixMeter {
239 pub analog_inputs: [u16; IonixProtocol::ANALOG_INPUT_COUNT],
241 pub spdif_inputs: [u16; IonixProtocol::SPDIF_INPUT_COUNT],
243 pub stream_inputs: [u16; IonixProtocol::STREAM_INPUT_COUNT],
245 pub bus_outputs: [u16; IonixProtocol::MIXER_BUS_COUNT],
247 pub main_outputs: [u16; IonixProtocol::MIXER_MAIN_COUNT],
249}
250
251impl<O: LexiconOperation> LexiconParametersSerdes<IonixMeter> for O {
291 const NAME: &'static str = "meter";
292
293 const OFFSET_RANGES: &'static [Range<usize>] = &[Range {
294 start: METER_OFFSET,
295 end: METER_OFFSET + METER_SIZE,
296 }];
297
298 fn serialize_params(params: &IonixMeter, raw: &mut [u8]) -> Result<(), String> {
299 raw.fill_with(Default::default);
300
301 let mut entry = RouterEntry::default();
302 let mut pos = 0;
303
304 [
305 (
306 ¶ms.stream_inputs[..8],
307 DstBlkId::MixerTx0,
308 0,
309 SrcBlkId::Avs0,
310 0,
311 ),
312 (
313 ¶ms.stream_inputs[8..10],
314 DstBlkId::Aes,
315 2,
316 SrcBlkId::Avs0,
317 8,
318 ),
319 (
320 ¶ms.spdif_inputs[..],
321 DstBlkId::MixerTx0,
322 8,
323 SrcBlkId::Aes,
324 2,
325 ),
326 (
327 ¶ms.analog_inputs[..4],
328 DstBlkId::MixerTx0,
329 10,
330 SrcBlkId::Ins0,
331 0,
332 ),
333 (
334 ¶ms.analog_inputs[4..6],
335 DstBlkId::MixerTx0,
336 14,
337 SrcBlkId::Ins0,
338 8,
339 ),
340 (
341 ¶ms.analog_inputs[6..8],
342 DstBlkId::MixerTx1,
343 0,
344 SrcBlkId::Ins0,
345 10,
346 ),
347 (
348 ¶ms.bus_outputs[..4],
349 DstBlkId::Ins0,
350 4,
351 SrcBlkId::Mixer,
352 0,
353 ),
354 (
355 ¶ms.bus_outputs[4..],
356 DstBlkId::Ins0,
357 12,
358 SrcBlkId::Mixer,
359 4,
360 ),
361 (
362 ¶ms.main_outputs[..],
363 DstBlkId::Ins1,
364 0,
365 SrcBlkId::Mixer,
366 10,
367 ),
368 ]
369 .iter()
370 .try_for_each(
371 |(levels, dst_blk_id, dst_blk_ch_offset, src_blk_id, src_blk_ch_offset)| {
372 levels.iter().enumerate().try_for_each(|(i, &level)| {
373 entry.peak = level;
374 entry.dst.id = *dst_blk_id;
375 entry.dst.ch = (i + dst_blk_ch_offset) as u8;
376 entry.src.id = *src_blk_id;
377 entry.src.ch = (i + src_blk_ch_offset) as u8;
378 serialize_router_entry(&entry, &mut raw[pos..(pos + 4)]).map(|_| pos += 4)
379 })
380 },
381 )
382 }
383
384 fn deserialize_params(params: &mut IonixMeter, raw: &[u8]) -> Result<(), String> {
385 let mut entry = RouterEntry::default();
386
387 (0..raw.len()).step_by(4).try_for_each(|pos| {
388 deserialize_router_entry(&mut entry, &raw[pos..(pos + 4)]).map(|_| {
389 match (entry.dst.id, entry.dst.ch, entry.src.id, entry.src.ch) {
390 (DstBlkId::MixerTx0, 0..=7, SrcBlkId::Avs0, 0..=7) => {
391 let pos = entry.src.ch as usize;
392 params.stream_inputs[pos] = entry.peak;
393 }
394 (DstBlkId::Aes, 2..=3, SrcBlkId::Avs0, 8..=9) => {
395 let pos = entry.src.ch as usize;
396 params.stream_inputs[pos] = entry.peak;
397 }
398 (DstBlkId::MixerTx0, 8..=9, SrcBlkId::Aes, 2..=3) => {
399 let pos = (entry.src.ch - 2) as usize;
400 params.spdif_inputs[pos] = entry.peak;
401 }
402 (DstBlkId::MixerTx0, 10..=13, SrcBlkId::Ins0, 0..=3) => {
403 let pos = entry.src.ch as usize;
404 params.analog_inputs[pos] = entry.peak;
405 }
406 (DstBlkId::MixerTx0, 14..=15, SrcBlkId::Ins0, 8..=9) => {
407 let pos = 4 + (entry.src.ch - 8) as usize;
408 params.analog_inputs[pos] = entry.peak;
409 }
410 (DstBlkId::MixerTx1, 0..=2, SrcBlkId::Ins0, 10..=11) => {
411 let pos = 6 + (entry.src.ch - 10) as usize;
412 params.analog_inputs[pos] = entry.peak;
413 }
414 (DstBlkId::Ins0, 4..=7, SrcBlkId::Mixer, 0..=3) => {
415 let pos = entry.src.ch as usize;
416 params.bus_outputs[pos] = entry.peak;
417 }
418 (DstBlkId::Ins0, 12..=15, SrcBlkId::Mixer, 4..=7) => {
419 let pos = 4 + (entry.src.ch - 4) as usize;
420 params.bus_outputs[pos] = entry.peak;
421 }
422 (DstBlkId::Ins1, 0..=2, SrcBlkId::Mixer, 10..=11) => {
423 let pos = (entry.src.ch - 10) as usize;
424 params.main_outputs[pos] = entry.peak;
425 }
426 _ => (),
427 }
428 })
429 })
430 }
431}
432
433#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
435pub struct IonixMixerSources {
436 pub stream_inputs: [i16; IonixProtocol::MIXER_STREAM_INPUT_COUNT],
438 pub spdif_inputs: [i16; IonixProtocol::MIXER_SPDIF_INPUT_COUNT],
440 pub analog_inputs: [i16; IonixProtocol::MIXER_ANALOG_INPUT_COUNT],
442}
443
444#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
446pub struct IonixMixerParameters {
447 pub bus_sources: [IonixMixerSources; IonixProtocol::MIXER_BUS_COUNT],
449 pub main_sources: [IonixMixerSources; IonixProtocol::MIXER_MAIN_COUNT],
451 pub reverb_sources: [IonixMixerSources; IonixProtocol::MIXER_REVERB_COUNT],
453}
454
455impl<O: LexiconOperation> LexiconParametersSerdes<IonixMixerParameters> for O {
456 const NAME: &'static str = "meter";
457
458 const OFFSET_RANGES: &'static [Range<usize>] = &[
459 Range {
460 start: MIXER_BUS_SRC_OFFSET,
461 end: MIXER_BUS_SRC_OFFSET + MIXER_BUS_SRC_SIZE,
462 },
463 Range {
464 start: MIXER_MAIN_SRC_OFFSET,
465 end: MIXER_MAIN_SRC_OFFSET + MIXER_MAIN_SRC_SIZE,
466 },
467 Range {
468 start: MIXER_REVERB_SRC_OFFSET,
469 end: MIXER_REVERB_SRC_OFFSET + MIXER_REVERB_SRC_SIZE,
470 },
471 ];
472
473 fn serialize_params(params: &IonixMixerParameters, raw: &mut [u8]) -> Result<(), String> {
474 [
475 (¶ms.bus_sources[..], 0x0000),
476 (¶ms.main_sources[..], 0x02d0),
477 (¶ms.reverb_sources[..], 0x0360),
478 ]
479 .iter()
480 .for_each(|(srcs, offset)| {
481 srcs.iter().enumerate().for_each(|(i, src)| {
482 src.stream_inputs
483 .iter()
484 .chain(src.spdif_inputs.iter())
485 .chain(src.analog_inputs.iter())
486 .enumerate()
487 .for_each(|(j, gain)| {
488 let pos = *offset + i * 0x48 + j * 4;
489 serialize_i16(gain, &mut raw[pos..(pos + 4)]);
490 });
491 });
492 });
493
494 Ok(())
495 }
496
497 fn deserialize_params(params: &mut IonixMixerParameters, raw: &[u8]) -> Result<(), String> {
498 [
499 (&mut params.bus_sources[..], 0x0000),
500 (&mut params.main_sources[..], 0x02d0),
501 (&mut params.reverb_sources[..], 0x0360),
502 ]
503 .iter_mut()
504 .for_each(|(srcs, offset)| {
505 srcs.iter_mut().enumerate().for_each(|(i, src)| {
506 src.stream_inputs
507 .iter_mut()
508 .chain(src.spdif_inputs.iter_mut())
509 .chain(src.analog_inputs.iter_mut())
510 .enumerate()
511 .for_each(|(j, gain)| {
512 let pos = *offset + i * 0x48 + j * 4;
513 deserialize_i16(gain, &raw[pos..(pos + 4)]);
514 });
515 });
516 });
517
518 Ok(())
519 }
520}
521
522impl<O: LexiconOperation + LexiconParametersSerdes<IonixMixerParameters>>
523 LexiconMutableParametersOperation<IonixMixerParameters> for O
524{
525}
526
527pub trait IonixSysExDataSerdes<T> {
529 const NAME: &'static str;
531
532 fn serialize_sysex_data(params: &T) -> Result<Vec<Vec<u8>>, String>;
534
535 fn deserialize_sysex_data<U: AsRef<[u8]>>(params: &mut T, raw: &[U]) -> Result<(), String>;
537}
538
539fn serialize_effect_frame(data: &[u8]) -> Vec<u8> {
540 const DATA_PREFIX: [u8; 5] = [0x06, 0x00, 0x1b, 0x01, 0x41];
542
543 const SYSEX_MSG_PREFIX: u8 = 0xf0;
545
546 const SYSEX_MSG_SUFFIX: u8 = 0xf7;
548
549 let mut sysex_data = DATA_PREFIX.to_vec();
551 sysex_data.extend_from_slice(data);
552
553 let checksum = sysex_data.iter().fold(0u8, |val, &msg| val | msg);
555 sysex_data.push(checksum);
556
557 let mut sysex = vec![SYSEX_MSG_PREFIX];
559 sysex.append(&mut sysex_data);
560 sysex.push(SYSEX_MSG_SUFFIX);
561
562 let mut raw = Vec::new();
564 sysex
565 .iter()
566 .for_each(|&msg| raw.extend_from_slice(&(msg as u32).to_be_bytes()));
567
568 raw
569}
570
571fn generate_effect_err(name: &str, cause: &str) -> Error {
572 let msg = format!("params: {}, cause: {}", name, cause);
573 Error::new(GeneralProtocolError::VendorDependent, &msg)
574}
575
576pub trait LexiconEffectOperation<T>: LexiconOperation + IonixSysExDataSerdes<T> {
578 fn update_effect_params(
580 req: &FwReq,
581 node: &FwNode,
582 params: &T,
583 prev: &mut T,
584 timeout_ms: u32,
585 ) -> Result<(), Error> {
586 let new = Self::serialize_sysex_data(params)
587 .map_err(|cause| generate_effect_err(Self::NAME, &cause))?;
588 let old = Self::serialize_sysex_data(prev)
589 .map_err(|cause| generate_effect_err(Self::NAME, &cause))?;
590
591 new.iter()
592 .zip(old.iter())
593 .filter(|(n, o)| !n.eq(o))
594 .try_for_each(|(data, _)| {
595 let mut raw = serialize_effect_frame(data);
596 Self::write(req, node, EFFECT_OFFSET, &mut raw, timeout_ms)
597 })?;
598
599 Self::deserialize_sysex_data(prev, &new)
600 .map_err(|cause| generate_effect_err(Self::NAME, &cause))
601 }
602}
603
604impl<O: LexiconOperation + IonixSysExDataSerdes<T>, T> LexiconEffectOperation<T> for O {}
605
606#[cfg(test)]
607mod test {
608 use super::*;
609
610 #[test]
611 fn mixer_params_serdes() {
612 let mut params = IonixMixerParameters::default();
613 params
614 .bus_sources
615 .iter_mut()
616 .chain(params.main_sources.iter_mut())
617 .chain(params.reverb_sources.iter_mut())
618 .flat_map(|srcs| {
619 srcs.stream_inputs
620 .iter_mut()
621 .chain(srcs.spdif_inputs.iter_mut())
622 .chain(srcs.analog_inputs.iter_mut())
623 })
624 .enumerate()
625 .for_each(|(i, gain)| *gain = i as i16);
626
627 let size = compute_params_size(
628 <IonixProtocol as LexiconParametersSerdes<IonixMixerParameters>>::OFFSET_RANGES,
629 );
630 let mut raw = vec![0u8; size];
631 IonixProtocol::serialize_params(¶ms, &mut raw).unwrap();
632
633 let mut p = IonixMixerParameters::default();
634 IonixProtocol::deserialize_params(&mut p, &raw).unwrap();
635
636 assert_eq!(params.bus_sources, p.bus_sources, "{:02x?}", raw);
637 assert_eq!(params.main_sources, p.main_sources);
638 assert_eq!(params.reverb_sources, p.reverb_sources);
639 }
640}