1use super::*;
7
8#[derive(Default, Debug)]
10pub struct Ff802Protocol;
11
12const CFG_CLK_SRC_MASK: u32 = 0x00001c00;
14const CFG_CLK_SRC_ADAT_B_FLAG: u32 = 0x00001000;
15const CFG_CLK_SRC_ADAT_A_FLAG: u32 = 0x00000c00;
16const CFG_CLK_SRC_AESEBU_FLAG: u32 = 0x00000800;
17const CFG_CLK_SRC_WORD_CLK_FLAG: u32 = 0x00000400;
18const CFG_CLK_SRC_INTERNAL_FLAG: u32 = 0x00000000;
19const CFG_AESEBU_INPUT_FROM_OPT_IFACE_MASK: u32 = 0x00000200;
20const CFG_AESEBU_OUTPUT_TO_OPT_IFACE_MASK: u32 = 0x00000100;
21const CFG_DSP_EFFECT_ON_INPUT_MASK: u32 = 0x00000040;
22const CFG_AESEBU_OUT_PRO_MASK: u32 = 0x00000020;
23const CFG_WORD_OUT_SINGLE_MASK: u32 = 0x00000010;
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum Ff802ClkSrc {
28 Internal,
29 AdatA,
30 AdatB,
31 AesEbu,
32 WordClk,
33}
34
35impl Default for Ff802ClkSrc {
36 fn default() -> Self {
37 Self::Internal
38 }
39}
40
41fn serialize_clock_source(src: &Ff802ClkSrc, quad: &mut u32) {
42 *quad &= !CFG_CLK_SRC_MASK;
43 *quad |= match src {
44 Ff802ClkSrc::AdatB => CFG_CLK_SRC_ADAT_B_FLAG,
45 Ff802ClkSrc::AdatA => CFG_CLK_SRC_ADAT_A_FLAG,
46 Ff802ClkSrc::AesEbu => CFG_CLK_SRC_AESEBU_FLAG,
47 Ff802ClkSrc::WordClk => CFG_CLK_SRC_WORD_CLK_FLAG,
48 Ff802ClkSrc::Internal => CFG_CLK_SRC_INTERNAL_FLAG,
49 };
50}
51
52fn deserialize_clock_source(src: &mut Ff802ClkSrc, quad: &u32) {
53 *src = match *quad & CFG_CLK_SRC_MASK {
54 CFG_CLK_SRC_ADAT_B_FLAG => Ff802ClkSrc::AdatB,
55 CFG_CLK_SRC_ADAT_A_FLAG => Ff802ClkSrc::AdatA,
56 CFG_CLK_SRC_AESEBU_FLAG => Ff802ClkSrc::AesEbu,
57 CFG_CLK_SRC_WORD_CLK_FLAG => Ff802ClkSrc::WordClk,
58 CFG_CLK_SRC_INTERNAL_FLAG => Ff802ClkSrc::Internal,
59 _ => unreachable!(),
60 };
61}
62
63#[derive(Debug, Copy, Clone, PartialEq, Eq)]
65pub enum Ff802SpdifIface {
66 Xlr,
67 Optical,
68}
69
70impl Default for Ff802SpdifIface {
71 fn default() -> Self {
72 Self::Xlr
73 }
74}
75
76#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
78pub struct Ff802Config {
79 midi_tx_low_offset: FfLatterMidiTxLowOffset,
81 pub clk_src: Ff802ClkSrc,
83 pub spdif_in_iface: Ff802SpdifIface,
85 pub opt_out_signal: OpticalOutputSignal,
87 pub effect_on_inputs: bool,
89 pub spdif_out_format: SpdifFormat,
91 pub word_out_single: bool,
93}
94
95impl RmeFfOffsetParamsSerialize<Ff802Config> for Ff802Protocol {
96 fn serialize_offsets(state: &Ff802Config) -> Vec<u8> {
97 let mut quad = 0;
98
99 serialize_midi_tx_low_offset(&state.midi_tx_low_offset, &mut quad);
100 serialize_clock_source(&state.clk_src, &mut quad);
101
102 quad &= !CFG_AESEBU_INPUT_FROM_OPT_IFACE_MASK;
103 if state.spdif_in_iface == Ff802SpdifIface::Optical {
104 quad |= CFG_AESEBU_INPUT_FROM_OPT_IFACE_MASK;
105 }
106
107 quad &= !CFG_AESEBU_OUTPUT_TO_OPT_IFACE_MASK;
108 if state.opt_out_signal == OpticalOutputSignal::Spdif {
109 quad |= CFG_AESEBU_OUTPUT_TO_OPT_IFACE_MASK;
110 }
111
112 quad &= !CFG_DSP_EFFECT_ON_INPUT_MASK;
113 if state.effect_on_inputs {
114 quad |= CFG_DSP_EFFECT_ON_INPUT_MASK;
115 }
116
117 quad &= !CFG_AESEBU_OUT_PRO_MASK;
118 if state.spdif_out_format == SpdifFormat::Professional {
119 quad |= CFG_AESEBU_OUT_PRO_MASK;
120 }
121
122 quad &= !CFG_WORD_OUT_SINGLE_MASK;
123 if state.word_out_single {
124 quad |= CFG_WORD_OUT_SINGLE_MASK;
125 }
126
127 quad.to_le_bytes().to_vec()
128 }
129}
130
131impl RmeFfOffsetParamsDeserialize<Ff802Config> for Ff802Protocol {
132 fn deserialize_offsets(state: &mut Ff802Config, raw: &[u8]) {
133 assert!(raw.len() >= LATTER_CONFIG_SIZE);
134
135 let mut r = [0; 4];
136 r.copy_from_slice(&raw[..4]);
137 let quad = u32::from_le_bytes(r);
138
139 deserialize_midi_tx_low_offset(&mut state.midi_tx_low_offset, &quad);
140 deserialize_clock_source(&mut state.clk_src, &quad);
141
142 state.spdif_in_iface = if quad & CFG_AESEBU_INPUT_FROM_OPT_IFACE_MASK > 0 {
143 Ff802SpdifIface::Optical
144 } else {
145 Ff802SpdifIface::Xlr
146 };
147
148 state.opt_out_signal = if quad & CFG_AESEBU_OUTPUT_TO_OPT_IFACE_MASK > 0 {
149 OpticalOutputSignal::Spdif
150 } else {
151 OpticalOutputSignal::Adat
152 };
153
154 state.effect_on_inputs = quad & CFG_DSP_EFFECT_ON_INPUT_MASK > 0;
155 state.spdif_out_format = if quad & CFG_AESEBU_OUT_PRO_MASK > 0 {
156 SpdifFormat::Professional
157 } else {
158 SpdifFormat::Consumer
159 };
160 state.word_out_single = quad & CFG_WORD_OUT_SINGLE_MASK > 0;
161 }
162}
163
164impl RmeFfWhollyUpdatableParamsOperation<Ff802Config> for Ff802Protocol {
165 fn update_wholly(
166 req: &mut FwReq,
167 node: &mut FwNode,
168 params: &Ff802Config,
169 timeout_ms: u32,
170 ) -> Result<(), Error> {
171 write_config::<Ff802Protocol, Ff802Config>(req, node, params, timeout_ms)
172 }
173}
174const STATUS_ACTIVE_CLK_RATE_MASK: u32 = 0xf0000000;
176const STATUS_ADAT_B_RATE_MASK: u32 = 0x0f000000;
177const STATUS_ADAT_A_RATE_MASK: u32 = 0x00f00000;
178const STATUS_SPDIF_RATE_MASK: u32 = 0x000f0000;
179const STATUS_WORD_CLK_RATE_MASK: u32 = 0x0000f000;
180const STATUS_ACTIVE_CLK_SRC_MASK: u32 = 0x00000e00;
181const STATUS_ACTIVE_CLK_SRC_INTERNAL_FLAG: u32 = 0x00000e00;
182const STATUS_ACTIVE_CLK_SRC_ADAT_A_FLAG: u32 = 0x00000800;
183const STATUS_ACTIVE_CLK_SRC_ADAT_B_FLAG: u32 = 0x00000600;
184const STATUS_ACTIVE_CLK_SRC_AESEBU_FLAG: u32 = 0x00000400;
185const STATUS_ACTIVE_CLK_SRC_WORD_CLK_FLAG: u32 = 0x00000200;
186const STATUS_SYNC_MASK: u32 = 0x000000f0;
187const STATUS_SYNC_ADAT_B_MASK: u32 = 0x00000080;
188const STATUS_SYNC_ADAT_A_MASK: u32 = 0x00000040;
189const STATUS_SYNC_SPDIF_MASK: u32 = 0x00000020;
190const STATUS_SYNC_WORD_CLK_MASK: u32 = 0x00000010;
191const STATUS_LOCK_MASK: u32 = 0x0000000f;
192const STATUS_LOCK_ADAT_B_MASK: u32 = 0x00000008;
193const STATUS_LOCK_ADAT_A_MASK: u32 = 0x00000004;
194const STATUS_LOCK_SPDIF_MASK: u32 = 0x00000002;
195const STATUS_LOCK_WORD_CLK_MASK: u32 = 0x00000001;
196
197#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
199pub struct Ff802ExtLockStatus {
200 pub word_clk: bool,
201 pub spdif: bool,
202 pub adat_b: bool,
203 pub adat_a: bool,
204}
205
206fn serialize_external_lock_status(status: &Ff802ExtLockStatus, quad: &mut u32) {
207 *quad &= !STATUS_LOCK_MASK;
208
209 if status.word_clk {
210 *quad |= STATUS_LOCK_WORD_CLK_MASK;
211 }
212 if status.spdif {
213 *quad |= STATUS_LOCK_SPDIF_MASK;
214 }
215 if status.adat_b {
216 *quad |= STATUS_LOCK_ADAT_B_MASK;
217 }
218 if status.adat_a {
219 *quad |= STATUS_LOCK_ADAT_A_MASK;
220 }
221}
222
223fn deserialize_external_lock_status(status: &mut Ff802ExtLockStatus, quad: &u32) {
224 status.word_clk = *quad & STATUS_LOCK_WORD_CLK_MASK > 0;
225 status.spdif = *quad & STATUS_LOCK_SPDIF_MASK > 0;
226 status.adat_b = *quad & STATUS_LOCK_ADAT_B_MASK > 0;
227 status.adat_a = *quad & STATUS_LOCK_ADAT_A_MASK > 0;
228}
229
230#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
232pub struct Ff802ExtSyncStatus {
233 pub word_clk: bool,
234 pub spdif: bool,
235 pub adat_b: bool,
236 pub adat_a: bool,
237}
238
239fn serialize_external_sync_status(status: &Ff802ExtSyncStatus, quad: &mut u32) {
240 *quad &= !STATUS_SYNC_MASK;
241
242 if status.word_clk {
243 *quad |= STATUS_SYNC_WORD_CLK_MASK;
244 }
245 if status.spdif {
246 *quad |= STATUS_SYNC_SPDIF_MASK;
247 }
248 if status.adat_b {
249 *quad |= STATUS_SYNC_ADAT_B_MASK;
250 }
251 if status.adat_a {
252 *quad |= STATUS_SYNC_ADAT_A_MASK;
253 }
254}
255
256fn deserialize_external_sync_status(status: &mut Ff802ExtSyncStatus, quad: &u32) {
257 status.word_clk = *quad & STATUS_SYNC_WORD_CLK_MASK > 0;
258 status.spdif = *quad & STATUS_SYNC_SPDIF_MASK > 0;
259 status.adat_b = *quad & STATUS_SYNC_ADAT_B_MASK > 0;
260 status.adat_a = *quad & STATUS_SYNC_ADAT_A_MASK > 0;
261}
262
263#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
265pub struct Ff802ExtRateStatus {
266 pub word_clk: Option<ClkNominalRate>,
267 pub spdif: Option<ClkNominalRate>,
268 pub adat_b: Option<ClkNominalRate>,
269 pub adat_a: Option<ClkNominalRate>,
270}
271
272fn serialize_external_rate(
273 rate: &Option<ClkNominalRate>,
274 quad: &mut u32,
275 shift: usize,
276 lock_flag: u32,
277) {
278 serialize_clock_rate_optional(rate, quad, shift);
279
280 if rate.is_some() {
282 *quad |= lock_flag;
283 }
284}
285
286fn serialize_external_rate_status(status: &Ff802ExtRateStatus, quad: &mut u32) {
288 *quad &= !(STATUS_WORD_CLK_RATE_MASK
289 | STATUS_SPDIF_RATE_MASK
290 | STATUS_ADAT_A_RATE_MASK
291 | STATUS_ADAT_B_RATE_MASK);
292 serialize_external_rate(&status.word_clk, quad, 12, STATUS_LOCK_WORD_CLK_MASK);
293 serialize_external_rate(&status.spdif, quad, 16, STATUS_LOCK_SPDIF_MASK);
294 serialize_external_rate(&status.adat_a, quad, 20, STATUS_LOCK_ADAT_A_MASK);
295 serialize_external_rate(&status.adat_b, quad, 24, STATUS_LOCK_ADAT_B_MASK);
296}
297
298fn deserialize_external_rate_status(status: &mut Ff802ExtRateStatus, quad: &u32) {
299 if *quad & (STATUS_SYNC_WORD_CLK_MASK | STATUS_LOCK_WORD_CLK_MASK) > 0 {
300 if *quad & (STATUS_SYNC_WORD_CLK_MASK | STATUS_LOCK_WORD_CLK_MASK) > 0 {
301 deserialize_clock_rate_optional(&mut status.word_clk, quad, 12);
302 } else {
303 status.word_clk = None;
304 }
305 if *quad & (STATUS_SYNC_SPDIF_MASK | STATUS_LOCK_SPDIF_MASK) > 0 {
306 deserialize_clock_rate_optional(&mut status.spdif, quad, 16);
307 } else {
308 status.spdif = None;
309 }
310 if *quad & (STATUS_SYNC_ADAT_B_MASK | STATUS_LOCK_ADAT_B_MASK) > 0 {
311 deserialize_clock_rate_optional(&mut status.adat_b, quad, 24);
312 } else {
313 status.adat_b = None;
314 }
315 if *quad & (STATUS_SYNC_ADAT_A_MASK | STATUS_LOCK_ADAT_A_MASK) > 0 {
316 deserialize_clock_rate_optional(&mut status.adat_a, quad, 20);
317 } else {
318 status.adat_a = None;
319 }
320 }
321}
322
323#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
325pub struct Ff802Status {
326 pub ext_lock: Ff802ExtLockStatus,
327 pub ext_sync: Ff802ExtSyncStatus,
328 pub ext_rate: Ff802ExtRateStatus,
329 pub active_clk_src: Ff802ClkSrc,
330 pub active_clk_rate: ClkNominalRate,
331}
332
333impl RmeFfOffsetParamsSerialize<Ff802Status> for Ff802Protocol {
334 fn serialize_offsets(status: &Ff802Status) -> Vec<u8> {
335 let mut quad = 0;
336
337 serialize_external_lock_status(&status.ext_lock, &mut quad);
338 serialize_external_sync_status(&status.ext_sync, &mut quad);
339 serialize_external_rate_status(&status.ext_rate, &mut quad);
340
341 quad &= !STATUS_ACTIVE_CLK_RATE_MASK;
342 serialize_clock_rate(&status.active_clk_rate, &mut quad, 28);
343
344 quad &= !STATUS_ACTIVE_CLK_SRC_MASK;
345 let val = match status.active_clk_src {
346 Ff802ClkSrc::Internal => STATUS_ACTIVE_CLK_SRC_INTERNAL_FLAG,
347 Ff802ClkSrc::AdatA => STATUS_ACTIVE_CLK_SRC_ADAT_A_FLAG,
348 Ff802ClkSrc::AdatB => STATUS_ACTIVE_CLK_SRC_ADAT_B_FLAG,
349 Ff802ClkSrc::AesEbu => STATUS_ACTIVE_CLK_SRC_AESEBU_FLAG,
350 Ff802ClkSrc::WordClk => STATUS_ACTIVE_CLK_SRC_WORD_CLK_FLAG,
351 };
352 quad |= val;
353
354 quad.to_le_bytes().to_vec()
355 }
356}
357
358impl RmeFfOffsetParamsDeserialize<Ff802Status> for Ff802Protocol {
359 fn deserialize_offsets(status: &mut Ff802Status, raw: &[u8]) {
360 assert!(raw.len() >= LATTER_STATUS_SIZE);
361
362 let mut r = [0; 4];
363 r.copy_from_slice(&raw[..4]);
364 let quad = u32::from_le_bytes(r);
365
366 deserialize_external_lock_status(&mut status.ext_lock, &quad);
367 deserialize_external_sync_status(&mut status.ext_sync, &quad);
368 deserialize_external_rate_status(&mut status.ext_rate, &quad);
369
370 deserialize_clock_rate(&mut status.active_clk_rate, &quad, 28);
371
372 status.active_clk_src = match quad & STATUS_ACTIVE_CLK_SRC_MASK {
373 STATUS_ACTIVE_CLK_SRC_INTERNAL_FLAG => Ff802ClkSrc::Internal,
374 STATUS_ACTIVE_CLK_SRC_ADAT_A_FLAG => Ff802ClkSrc::AdatA,
375 STATUS_ACTIVE_CLK_SRC_ADAT_B_FLAG => Ff802ClkSrc::AdatB,
376 STATUS_ACTIVE_CLK_SRC_AESEBU_FLAG => Ff802ClkSrc::AesEbu,
377 STATUS_ACTIVE_CLK_SRC_WORD_CLK_FLAG => Ff802ClkSrc::WordClk,
378 _ => unreachable!(),
379 };
380 }
381}
382
383impl RmeFfCacheableParamsOperation<Ff802Status> for Ff802Protocol {
384 fn cache_wholly(
385 req: &mut FwReq,
386 node: &mut FwNode,
387 status: &mut Ff802Status,
388 timeout_ms: u32,
389 ) -> Result<(), Error> {
390 read_status::<Ff802Protocol, Ff802Status>(req, node, status, timeout_ms)
391 }
392}
393
394impl RmeFfLatterSpecification for Ff802Protocol {
395 const LINE_INPUT_COUNT: usize = 8;
396 const MIC_INPUT_COUNT: usize = 4;
397 const SPDIF_INPUT_COUNT: usize = 2;
398 const ADAT_INPUT_COUNT: usize = 16;
399 const STREAM_INPUT_COUNT: usize = 30;
400
401 const LINE_OUTPUT_COUNT: usize = 8;
402 const HP_OUTPUT_COUNT: usize = 4;
403 const SPDIF_OUTPUT_COUNT: usize = 2;
404 const ADAT_OUTPUT_COUNT: usize = 16;
405}
406
407#[cfg(test)]
408mod test {
409 use super::*;
410
411 #[test]
412 fn clock_source_serdes() {
413 [
414 Ff802ClkSrc::AdatB,
415 Ff802ClkSrc::AdatA,
416 Ff802ClkSrc::AesEbu,
417 Ff802ClkSrc::WordClk,
418 Ff802ClkSrc::Internal,
419 ]
420 .iter()
421 .for_each(|orig| {
422 let mut quad = 0;
423 serialize_clock_source(&orig, &mut quad);
424 let mut target = Ff802ClkSrc::default();
425 deserialize_clock_source(&mut target, &quad);
426
427 assert_eq!(&target, orig);
428 });
429 }
430
431 #[test]
432 fn config_serdes() {
433 let orig = Ff802Config {
434 midi_tx_low_offset: FfLatterMidiTxLowOffset::A0180,
435 clk_src: Ff802ClkSrc::AesEbu,
436 spdif_in_iface: Ff802SpdifIface::Optical,
437 opt_out_signal: OpticalOutputSignal::Spdif,
438 effect_on_inputs: true,
439 spdif_out_format: SpdifFormat::Professional,
440 word_out_single: true,
441 };
442 let quads = Ff802Protocol::serialize_offsets(&orig);
443 let mut target = Ff802Config::default();
444 Ff802Protocol::deserialize_offsets(&mut target, &quads);
445
446 assert_eq!(target, orig);
447 }
448
449 #[test]
450 fn external_lock_status_serdes() {
451 let orig = Ff802ExtLockStatus {
452 word_clk: true,
453 spdif: true,
454 adat_b: true,
455 adat_a: true,
456 };
457 let mut quad = 0;
458 serialize_external_lock_status(&orig, &mut quad);
459 let mut target = Ff802ExtLockStatus::default();
460 deserialize_external_lock_status(&mut target, &quad);
461
462 assert_eq!(target, orig);
463 }
464
465 #[test]
466 fn external_sync_status_serdes() {
467 let orig = Ff802ExtSyncStatus {
468 word_clk: true,
469 spdif: true,
470 adat_b: true,
471 adat_a: true,
472 };
473 let mut quad = 0;
474 serialize_external_sync_status(&orig, &mut quad);
475 let mut target = Ff802ExtSyncStatus::default();
476 deserialize_external_sync_status(&mut target, &quad);
477
478 assert_eq!(target, orig);
479 }
480
481 #[test]
482 fn external_rate_status_serdes() {
483 let orig = Ff802ExtRateStatus {
484 word_clk: Some(ClkNominalRate::R88200),
485 spdif: Some(ClkNominalRate::R192000),
486 adat_b: Some(ClkNominalRate::R44100),
487 adat_a: None,
488 };
489 let mut quad = 0;
490 serialize_external_rate_status(&orig, &mut quad);
491 let mut target = Ff802ExtRateStatus::default();
492 deserialize_external_rate_status(&mut target, &quad);
493
494 assert_eq!(target, orig);
495 }
496
497 #[test]
498 fn status_serdes() {
499 let orig = Ff802Status {
500 ext_lock: Ff802ExtLockStatus {
501 word_clk: true,
502 spdif: false,
503 adat_b: true,
504 adat_a: false,
505 },
506 ext_sync: Ff802ExtSyncStatus {
507 word_clk: true,
508 spdif: false,
509 adat_b: false,
510 adat_a: false,
511 },
512 ext_rate: Ff802ExtRateStatus {
513 word_clk: Some(ClkNominalRate::R88200),
514 spdif: None,
515 adat_b: Some(ClkNominalRate::R44100),
516 adat_a: None,
517 },
518 active_clk_src: Ff802ClkSrc::AdatA,
519 active_clk_rate: ClkNominalRate::R96000,
520 };
521 let raw = Ff802Protocol::serialize_offsets(&orig);
522 let mut target = Ff802Status::default();
523 Ff802Protocol::deserialize_offsets(&mut target, &raw);
524
525 assert_eq!(target, orig);
526 }
527}