firewire_dice_protocols/tcat/
global_section.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! Global section in general protocol defined by TCAT for ASICs of DICE.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for global section
7//! in general protocol defined by TCAT for ASICs of DICE.
8use super::*;
9
10/// Nominal sampling rate.
11#[derive(Debug, Copy, Clone, PartialEq, Eq)]
12pub enum ClockRate {
13    /// 32.0 kHz.
14    R32000,
15    /// 44.1 kHz.
16    R44100,
17    /// 48.0 kHz.
18    R48000,
19    /// 88.2 kHz.
20    R88200,
21    /// 96.0 kHz.
22    R96000,
23    /// 176.4 kHz.
24    R176400,
25    /// 192.0 kHz.
26    R192000,
27    /// Smaller than 48.0 kHz.
28    AnyLow,
29    /// Between 48.0 and 96.0 kHz.
30    AnyMid,
31    /// Larger than 96.0 kHz.
32    AnyHigh,
33    /// Not available.
34    None,
35    /// Unspecified
36    Reserved(u8),
37}
38
39impl ClockRate {
40    const R32000_VAL: u8 = 0x00;
41    const R44100_VAL: u8 = 0x01;
42    const R48000_VAL: u8 = 0x02;
43    const R88200_VAL: u8 = 0x03;
44    const R96000_VAL: u8 = 0x04;
45    const R176400_VAL: u8 = 0x05;
46    const R192000_VAL: u8 = 0x06;
47    const ANY_LOW_VAL: u8 = 0x07;
48    const ANY_MID_VAL: u8 = 0x08;
49    const ANY_HIGH_VAL: u8 = 0x09;
50    const NONE_VAL: u8 = 0x0a;
51}
52
53impl Default for ClockRate {
54    fn default() -> Self {
55        ClockRate::Reserved(0xff)
56    }
57}
58
59pub(crate) fn serialize_clock_rate(rate: &ClockRate, val: &mut u8) -> Result<(), String> {
60    *val = match *rate {
61        ClockRate::R32000 => ClockRate::R32000_VAL,
62        ClockRate::R44100 => ClockRate::R44100_VAL,
63        ClockRate::R48000 => ClockRate::R48000_VAL,
64        ClockRate::R88200 => ClockRate::R88200_VAL,
65        ClockRate::R96000 => ClockRate::R96000_VAL,
66        ClockRate::R176400 => ClockRate::R176400_VAL,
67        ClockRate::R192000 => ClockRate::R192000_VAL,
68        ClockRate::AnyLow => ClockRate::ANY_LOW_VAL,
69        ClockRate::AnyMid => ClockRate::ANY_MID_VAL,
70        ClockRate::AnyHigh => ClockRate::ANY_HIGH_VAL,
71        ClockRate::None => ClockRate::NONE_VAL,
72        ClockRate::Reserved(val) => val,
73    };
74
75    Ok(())
76}
77
78pub(crate) fn deserialize_clock_rate(rate: &mut ClockRate, val: &u8) -> Result<(), String> {
79    *rate = match *val {
80        ClockRate::R32000_VAL => ClockRate::R32000,
81        ClockRate::R44100_VAL => ClockRate::R44100,
82        ClockRate::R48000_VAL => ClockRate::R48000,
83        ClockRate::R88200_VAL => ClockRate::R88200,
84        ClockRate::R96000_VAL => ClockRate::R96000,
85        ClockRate::R176400_VAL => ClockRate::R176400,
86        ClockRate::R192000_VAL => ClockRate::R192000,
87        ClockRate::ANY_LOW_VAL => ClockRate::AnyLow,
88        ClockRate::ANY_MID_VAL => ClockRate::AnyMid,
89        ClockRate::ANY_HIGH_VAL => ClockRate::AnyHigh,
90        ClockRate::NONE_VAL => ClockRate::None,
91        _ => ClockRate::Reserved(*val),
92    };
93
94    Ok(())
95}
96
97/// Nominal sampling rate.
98#[derive(Debug, Copy, Clone, PartialEq, Eq)]
99pub enum ClockSource {
100    /// IEC 60958 receiver 0.
101    Aes1,
102    /// IEC 60958 receiver 1.
103    Aes2,
104    /// IEC 60958 receiver 2.
105    Aes3,
106    /// IEC 60958 receiver 3.
107    Aes4,
108    /// Any IEC 60958 receiver.
109    AesAny,
110    /// ADAT receiver.
111    Adat,
112    /// TDIF receiver.
113    Tdif,
114    /// Word clock.
115    WordClock,
116    /// Audio Video System Receiver 0.
117    Arx1,
118    /// Audio Video System Receiver 1.
119    Arx2,
120    /// Audio Video System Receiver 2.
121    Arx3,
122    /// Audio Video System Receiver 3.
123    Arx4,
124    /// Internal oscillator.
125    Internal,
126    /// Unspecified.
127    Reserved(u8),
128}
129
130impl Default for ClockSource {
131    fn default() -> Self {
132        ClockSource::Reserved(0xff)
133    }
134}
135
136impl ClockSource {
137    const AES1_VAL: u8 = 0x00;
138    const AES2_VAL: u8 = 0x01;
139    const AES3_VAL: u8 = 0x02;
140    const AES4_VAL: u8 = 0x03;
141    const AES_ANY_VAL: u8 = 0x04;
142    const ADAT_VAL: u8 = 0x05;
143    const TDIF_VAL: u8 = 0x06;
144    const WORD_CLOCK_VAL: u8 = 0x07;
145    const ARX1_VAL: u8 = 0x08;
146    const ARX2_VAL: u8 = 0x09;
147    const ARX3_VAL: u8 = 0x0a;
148    const ARX4_VAL: u8 = 0x0b;
149    const INTERNAL_VAL: u8 = 0x0c;
150}
151
152pub(crate) fn serialize_clock_source(src: &ClockSource, val: &mut u8) -> Result<(), String> {
153    *val = match *src {
154        ClockSource::Aes1 => ClockSource::AES1_VAL,
155        ClockSource::Aes2 => ClockSource::AES2_VAL,
156        ClockSource::Aes3 => ClockSource::AES3_VAL,
157        ClockSource::Aes4 => ClockSource::AES4_VAL,
158        ClockSource::AesAny => ClockSource::AES_ANY_VAL,
159        ClockSource::Adat => ClockSource::ADAT_VAL,
160        ClockSource::Tdif => ClockSource::TDIF_VAL,
161        ClockSource::WordClock => ClockSource::WORD_CLOCK_VAL,
162        ClockSource::Arx1 => ClockSource::ARX1_VAL,
163        ClockSource::Arx2 => ClockSource::ARX2_VAL,
164        ClockSource::Arx3 => ClockSource::ARX3_VAL,
165        ClockSource::Arx4 => ClockSource::ARX4_VAL,
166        ClockSource::Internal => ClockSource::INTERNAL_VAL,
167        ClockSource::Reserved(src_val) => src_val,
168    };
169
170    Ok(())
171}
172
173pub(crate) fn deserialize_clock_source(src: &mut ClockSource, val: &u8) -> Result<(), String> {
174    *src = match *val {
175        ClockSource::AES1_VAL => ClockSource::Aes1,
176        ClockSource::AES2_VAL => ClockSource::Aes2,
177        ClockSource::AES3_VAL => ClockSource::Aes3,
178        ClockSource::AES4_VAL => ClockSource::Aes4,
179        ClockSource::AES_ANY_VAL => ClockSource::AesAny,
180        ClockSource::ADAT_VAL => ClockSource::Adat,
181        ClockSource::TDIF_VAL => ClockSource::Tdif,
182        ClockSource::WORD_CLOCK_VAL => ClockSource::WordClock,
183        ClockSource::ARX1_VAL => ClockSource::Arx1,
184        ClockSource::ARX2_VAL => ClockSource::Arx2,
185        ClockSource::ARX3_VAL => ClockSource::Arx3,
186        ClockSource::ARX4_VAL => ClockSource::Arx4,
187        ClockSource::INTERNAL_VAL => ClockSource::Internal,
188        _ => ClockSource::Reserved(*val),
189    };
190    Ok(())
191}
192
193/// Configuration of clock.
194#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
195pub struct ClockConfig {
196    /// For frequency of media clock.
197    pub rate: ClockRate,
198    /// For signal source of sampling clock.
199    pub src: ClockSource,
200}
201
202impl ClockConfig {
203    const SIZE: usize = 4;
204
205    const SRC_MASK: u32 = 0x000000ff;
206    const SRC_SHIFT: usize = 0;
207    const RATE_MASK: u32 = 0x0000ff00;
208    const RATE_SHIFT: usize = 8;
209}
210
211fn serialize_clock_config(config: &ClockConfig, raw: &mut [u8]) -> Result<(), String> {
212    assert!(raw.len() >= ClockConfig::SIZE);
213
214    let mut src_val = 0u8;
215    serialize_clock_source(&config.src, &mut src_val)?;
216
217    let mut rate_val = 0u8;
218    serialize_clock_rate(&config.rate, &mut rate_val)?;
219
220    let val = (((rate_val as u32) << ClockConfig::RATE_SHIFT) & ClockConfig::RATE_MASK)
221        | (((src_val as u32) << ClockConfig::SRC_SHIFT) & ClockConfig::SRC_MASK);
222
223    serialize_u32(&val, raw);
224
225    Ok(())
226}
227
228fn deserialize_clock_config(config: &mut ClockConfig, raw: &[u8]) -> Result<(), String> {
229    assert!(raw.len() >= ClockConfig::SIZE);
230
231    let mut val = 0u32;
232    deserialize_u32(&mut val, raw);
233
234    let src_val = ((val & ClockConfig::SRC_MASK) >> ClockConfig::SRC_SHIFT) as u8;
235    let rate_val = ((val & ClockConfig::RATE_MASK) >> ClockConfig::RATE_SHIFT) as u8;
236
237    deserialize_clock_source(&mut config.src, &src_val)?;
238    deserialize_clock_rate(&mut config.rate, &rate_val)?;
239
240    Ok(())
241}
242
243/// Status of sampling clock.
244#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
245pub struct ClockStatus {
246    /// Whether the current clock source is locked.
247    pub src_is_locked: bool,
248    /// The detected frequency of media clock.
249    pub rate: ClockRate,
250}
251
252impl ClockStatus {
253    const SIZE: usize = 4;
254
255    const SRC_LOCKED: u32 = 0x00000001;
256    const RATE_MASK: u32 = 0x0000ff00;
257    const RATE_SHIFT: usize = 8;
258}
259
260fn serialize_clock_status(status: &ClockStatus, raw: &mut [u8]) -> Result<(), String> {
261    assert!(raw.len() >= ClockStatus::SIZE);
262
263    let mut val = 0u32;
264    if status.src_is_locked {
265        val |= ClockStatus::SRC_LOCKED;
266    }
267
268    let mut rate_bit = 0u8;
269    serialize_clock_rate(&status.rate, &mut rate_bit)?;
270    val |= ((rate_bit as u32) << ClockStatus::RATE_SHIFT) & ClockStatus::RATE_MASK;
271
272    serialize_u32(&val, raw);
273
274    Ok(())
275}
276
277fn deserialize_clock_status(status: &mut ClockStatus, raw: &[u8]) -> Result<(), String> {
278    assert!(raw.len() >= ClockStatus::SIZE);
279
280    let mut val = 0u32;
281    deserialize_u32(&mut val, raw);
282
283    status.src_is_locked = (val & ClockStatus::SRC_LOCKED) > 0;
284
285    let rate_val = ((val & ClockStatus::RATE_MASK) >> ClockStatus::RATE_SHIFT) as u8;
286    deserialize_clock_rate(&mut status.rate, &rate_val)?;
287
288    Ok(())
289}
290
291/// The states of external signal sources of sampling clock.
292#[derive(Default, Debug, Clone, PartialEq, Eq)]
293pub struct ExternalSourceStates {
294    /// The list of external sources. Internal clock source is always excluded.
295    pub sources: Vec<ClockSource>,
296    /// Whether to lock the corresponding source or not. Any change is notified.
297    pub locked: Vec<bool>,
298    /// Whether to detect slipped for the sorresponding source since the last read operation. Any
299    /// change is not notified.
300    pub slipped: Vec<bool>,
301}
302
303/// Parameters in global section.
304#[derive(Default, Debug, Clone, PartialEq, Eq)]
305pub struct GlobalParameters {
306    /// The address offset of owner node to which Any notification is sent.
307    pub owner: u64,
308    /// The latest notification sent to the owner node.
309    pub latest_notification: u32,
310    /// Nickname of the node. When the same units are in the same bus, it is available to
311    /// distinguish them.
312    pub nickname: String,
313    /// The configuration of media clock and sampling clock.
314    pub clock_config: ClockConfig,
315    /// Whether to enable packet streaming or not.
316    pub enable: bool,
317    /// The status of sampling clock.
318    pub clock_status: ClockStatus,
319    /// The states of external clock sources. Any change is notified by NOTIFY_EXT_STATUS.
320    pub external_source_states: ExternalSourceStates,
321    /// Detected rate of sampling clock in Hz.
322    pub current_rate: u32,
323    /// The version of protocol.
324    pub version: u32,
325    /// The list of available rates for media clock.
326    pub avail_rates: Vec<ClockRate>,
327    /// The list of available sources for sampling clock.
328    pub avail_sources: Vec<ClockSource>,
329    /// The list of external signal names for source of sampling clock.
330    pub clock_source_labels: Vec<(ClockSource, String)>,
331}
332
333/// The specification for parameters in global section.
334pub trait TcatGlobalSectionSpecification {
335    /// Some models report invalid list for signal source of sampling clock.
336    const AVAILABLE_CLOCK_SOURCE_OVERRIDE: Option<&'static [ClockSource]> = None;
337
338    /// Some models report list of labels for signal source of sampling clock with unexpected
339    /// position.
340    const CLOCK_SOURCE_LABEL_TABLE: &'static [ClockSource] = &[
341        ClockSource::Aes1,
342        ClockSource::Aes2,
343        ClockSource::Aes3,
344        ClockSource::Aes4,
345        ClockSource::AesAny,
346        ClockSource::Adat,
347        ClockSource::Tdif,
348        ClockSource::WordClock,
349        ClockSource::Arx1,
350        ClockSource::Arx2,
351        ClockSource::Arx3,
352        ClockSource::Arx4,
353        ClockSource::Internal,
354    ];
355}
356
357const CLOCK_SOURCE_STREAM_LABEL_TABLE: [(ClockSource, &'static str); 4] = [
358    (ClockSource::Arx1, "Stream-1"),
359    (ClockSource::Arx2, "Stream-2"),
360    (ClockSource::Arx3, "Stream-3"),
361    (ClockSource::Arx4, "Stream-4"),
362];
363
364const CLOCK_CAPS_RATE_TABLE: [ClockRate; 11] = [
365    ClockRate::R32000,
366    ClockRate::R44100,
367    ClockRate::R48000,
368    ClockRate::R88200,
369    ClockRate::R96000,
370    ClockRate::R176400,
371    ClockRate::R192000,
372    ClockRate::AnyLow,
373    ClockRate::AnyMid,
374    ClockRate::AnyHigh,
375    ClockRate::None,
376];
377
378const CLOCK_CAPS_SRC_TABLE: [ClockSource; 13] = [
379    ClockSource::Aes1,
380    ClockSource::Aes2,
381    ClockSource::Aes3,
382    ClockSource::Aes4,
383    ClockSource::AesAny,
384    ClockSource::Adat,
385    ClockSource::Tdif,
386    ClockSource::WordClock,
387    ClockSource::Arx1,
388    ClockSource::Arx2,
389    ClockSource::Arx3,
390    ClockSource::Arx4,
391    ClockSource::Internal,
392];
393
394const EXTERNAL_CLOCK_SOURCE_TABLE: [ClockSource; 11] = [
395    ClockSource::Aes1,
396    ClockSource::Aes2,
397    ClockSource::Aes3,
398    ClockSource::Aes4,
399    ClockSource::Adat,
400    ClockSource::Tdif,
401    ClockSource::Arx1,
402    ClockSource::Arx2,
403    ClockSource::Arx3,
404    ClockSource::Arx4,
405    ClockSource::WordClock,
406];
407
408impl<O: TcatOperation + TcatGlobalSectionSpecification> TcatSectionSerdes<GlobalParameters> for O {
409    const MIN_SIZE: usize = 96;
410
411    const ERROR_TYPE: GeneralProtocolError = GeneralProtocolError::Global;
412
413    fn serialize(params: &GlobalParameters, raw: &mut [u8]) -> Result<(), String> {
414        let val = ((params.owner & 0xffffffff00000000) >> 32) as u32;
415        serialize_u32(&val, &mut raw[..4]);
416        let val = (params.owner & 0x00000000ffffffff) as u32;
417        serialize_u32(&val, &mut raw[4..8]);
418
419        serialize_u32(&params.latest_notification, &mut raw[8..12]);
420
421        raw[12..76].fill(0x00);
422        serialize_label(&params.nickname, &mut raw[12..76])?;
423
424        serialize_clock_config(&params.clock_config, &mut raw[76..80])?;
425
426        serialize_bool(&params.enable, &mut raw[80..84]);
427
428        serialize_clock_status(&params.clock_status, &mut raw[84..88])?;
429
430        let mut locked_bits = 0u32;
431        let mut slipped_bits = 0u32;
432        params
433            .external_source_states
434            .sources
435            .iter()
436            .zip(&params.external_source_states.locked)
437            .zip(&params.external_source_states.slipped)
438            .for_each(|((source, &locked), &slipped)| {
439                EXTERNAL_CLOCK_SOURCE_TABLE
440                    .iter()
441                    .enumerate()
442                    .find(|(_, s)| source.eq(s))
443                    .map(|(i, _)| {
444                        if locked {
445                            locked_bits |= 1 << i;
446                        }
447                        if slipped {
448                            slipped_bits |= 1 << i;
449                        }
450                    });
451            });
452        let val = (slipped_bits << 16) | locked_bits;
453        serialize_u32(&val, &mut raw[88..92]);
454
455        serialize_u32(&params.current_rate, &mut raw[92..96]);
456
457        if raw.len() > 96 {
458            serialize_u32(&params.version, &mut raw[96..100]);
459
460            let mut rate_bits = 0u32;
461            params.avail_rates.iter().for_each(|avail_rate| {
462                CLOCK_CAPS_RATE_TABLE
463                    .iter()
464                    .enumerate()
465                    .find(|(_, r)| avail_rate.eq(r))
466                    .map(|(i, _)| rate_bits |= 1 << i);
467            });
468
469            let mut src_bits = 0u32;
470            params.avail_sources.iter().for_each(|avail_source| {
471                CLOCK_CAPS_SRC_TABLE
472                    .iter()
473                    .enumerate()
474                    .find(|(_, s)| avail_source.eq(s))
475                    .map(|(i, _)| src_bits |= 1 << i);
476            });
477            let val = (src_bits << 16) | rate_bits;
478            serialize_u32(&val, &mut raw[100..104]);
479
480            let labels: Vec<&str> = Self::CLOCK_SOURCE_LABEL_TABLE
481                .iter()
482                .map(|source| {
483                    params
484                        .clock_source_labels
485                        .iter()
486                        .find(|(s, _)| source.eq(s))
487                        .map(|(_, l)| l.as_str())
488                        .unwrap_or("unused")
489                })
490                .collect();
491            serialize_labels(&labels, &mut raw[104..360])?;
492        }
493
494        Ok(())
495    }
496
497    fn deserialize(params: &mut GlobalParameters, raw: &[u8]) -> Result<(), String> {
498        let mut val = 0u32;
499
500        // NOTE: the global section was extended in later version of protocol. Evaluate the
501        // extended fields at first.
502        let (version, avail_rates, avail_srcs, src_labels) = if raw.len() > 96 {
503            let mut labels = Vec::new();
504            deserialize_labels(&mut labels, &raw[104..360])?;
505
506            let mut labels: Vec<(ClockSource, String)> = Self::CLOCK_SOURCE_LABEL_TABLE
507                .iter()
508                .cloned()
509                .zip(labels.into_iter())
510                .collect();
511
512            deserialize_u32(&mut val, &raw[100..104]);
513            let rate_bits = (val & 0x0000ffff) as u16;
514            let src_bits = ((val & 0xffff0000) >> 16) as u16;
515
516            let avail_rates = CLOCK_CAPS_RATE_TABLE
517                .iter()
518                .enumerate()
519                .filter(|(i, _)| rate_bits & (1 << i) > 0)
520                .map(|(_, &r)| r)
521                .collect();
522
523            // NOTE: The labels for stream sources are always "unused", while they are available
524            // for external source states. Let us generate corresponding labels here for
525            // applications if available.
526            labels
527                .iter_mut()
528                .filter(|(src, _)| {
529                    CLOCK_CAPS_SRC_TABLE
530                        .iter()
531                        .enumerate()
532                        .find(|(i, s)| src.eq(s) && (src_bits & (1 << i)) > 0)
533                        .is_some()
534                })
535                .for_each(|(src, label)| {
536                    CLOCK_SOURCE_STREAM_LABEL_TABLE
537                        .iter()
538                        .find(|(s, _)| src.eq(&s))
539                        .map(|(_, l)| *label = l.to_string());
540                });
541
542            // NOTE: Some devices report wrong bits for available clock sources. Let us use
543            // hard-coded list alternatively.
544            let avail_srcs = if let Some(table) = Self::AVAILABLE_CLOCK_SOURCE_OVERRIDE {
545                table.to_vec()
546            } else {
547                CLOCK_CAPS_SRC_TABLE
548                    .iter()
549                    .enumerate()
550                    .filter(|(i, _)| src_bits & (1 << i) > 0)
551                    .filter(|(_, src)| {
552                        // NOTE: The stream sources are always detectable, thus no need to be
553                        // selectable.
554                        CLOCK_SOURCE_STREAM_LABEL_TABLE
555                            .iter()
556                            .find(|(s, _)| src.eq(&s))
557                            .is_none()
558                    })
559                    .filter(|(_, src)| {
560                        labels
561                            .iter()
562                            .filter(|(_, label)| label.to_lowercase() != "unused")
563                            .find(|(s, _)| s.eq(&src))
564                            .is_some()
565                    })
566                    .map(|(_, &src)| src)
567                    .collect()
568            };
569
570            labels.retain(|(src, label)| {
571                label.to_lowercase() != "unused"
572                    && (CLOCK_SOURCE_STREAM_LABEL_TABLE
573                        .iter()
574                        .find(|(s, _)| src.eq(&s))
575                        .is_some()
576                        || avail_srcs.iter().find(|s| src.eq(s)).is_some())
577            });
578
579            deserialize_u32(&mut val, &raw[96..100]);
580            let version = val;
581
582            (version, avail_rates, avail_srcs, labels)
583        } else {
584            let src_labels = vec![
585                (ClockSource::Arx1, "Stream-1".to_string()),
586                (ClockSource::Internal, "internal".to_string()),
587            ];
588            let avail_rates = vec![ClockRate::R44100, ClockRate::R48000];
589            let avail_srcs = vec![ClockSource::Internal];
590            let version = 0;
591
592            (version, avail_rates, avail_srcs, src_labels)
593        };
594
595        deserialize_u32(&mut val, &raw[..4]);
596        params.owner = (val as u64) << 32;
597        deserialize_u32(&mut val, &raw[4..8]);
598        params.owner |= val as u64;
599
600        deserialize_u32(&mut params.latest_notification, &raw[8..12]);
601
602        deserialize_label(&mut params.nickname, &raw[12..76])?;
603
604        deserialize_clock_config(&mut params.clock_config, &raw[76..80])?;
605
606        deserialize_bool(&mut params.enable, &raw[80..84]);
607
608        deserialize_clock_status(&mut params.clock_status, &raw[84..88])?;
609
610        deserialize_u32(&mut val, &raw[88..92]);
611        let locked_bits = (val & 0x0000ffff) as u16;
612        let slipped_bits = ((val & 0xffff0000) >> 16) as u16;
613
614        let srcs: Vec<ClockSource> = EXTERNAL_CLOCK_SOURCE_TABLE
615            .iter()
616            .filter(|src| src_labels.iter().find(|(s, _)| src.eq(&s)).is_some())
617            .copied()
618            .collect();
619        let locked: Vec<bool> = EXTERNAL_CLOCK_SOURCE_TABLE
620            .iter()
621            .enumerate()
622            .filter(|(_, src)| srcs.iter().find(|s| src.eq(s)).is_some())
623            .map(|(i, _)| locked_bits & (1 << i) > 0)
624            .collect();
625        let slipped: Vec<bool> = EXTERNAL_CLOCK_SOURCE_TABLE
626            .iter()
627            .enumerate()
628            .filter(|(_, src)| srcs.iter().find(|s| src.eq(s)).is_some())
629            .map(|(i, _)| slipped_bits & (1 << i) > 0)
630            .collect();
631
632        params.external_source_states.sources = srcs;
633        params.external_source_states.locked = locked;
634        params.external_source_states.slipped = slipped;
635
636        deserialize_u32(&mut params.current_rate, &raw[92..96]);
637
638        params.version = version;
639        params.avail_rates = avail_rates;
640        params.avail_sources = avail_srcs;
641        params.clock_source_labels = src_labels;
642
643        Ok(())
644    }
645}
646
647impl<O: TcatOperation + TcatSectionSerdes<GlobalParameters>> TcatSectionOperation<GlobalParameters>
648    for O
649{
650}
651
652impl<O: TcatOperation + TcatSectionSerdes<GlobalParameters>>
653    TcatMutableSectionOperation<GlobalParameters> for O
654{
655}
656
657impl<O: TcatSectionOperation<GlobalParameters>> TcatNotifiedSectionOperation<GlobalParameters>
658    for O
659{
660    const NOTIFY_FLAG: u32 = NOTIFY_LOCK_CHG | NOTIFY_CLOCK_ACCEPTED | NOTIFY_EXT_STATUS;
661}
662
663impl<O: TcatSectionOperation<GlobalParameters>> TcatFluctuatedSectionOperation<GlobalParameters>
664    for O
665{
666    const FLUCTUATED_OFFSETS: &'static [usize] = &[
667        88, // The slipped bits in GLOBAL_EXTENDED_STATUS are fluctuated without any notification.
668    ];
669}
670
671/// The maximum size of nickname in bytes.
672pub const NICKNAME_MAX_SIZE: usize = 64;
673
674#[cfg(test)]
675mod test {
676    use super::*;
677
678    struct Protocol;
679
680    impl TcatOperation for Protocol {}
681
682    impl TcatGlobalSectionSpecification for Protocol {}
683
684    #[test]
685    fn global_params_serdes() {
686        let raw = [
687            0xff, 0xc1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x6b, 0x73,
688            0x65, 0x44, 0x4b, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x6e, 0x6f, 0x00, 0x36, 0x74, 0x6b,
689            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
691            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
692            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x00,
693            0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x80, 0x01, 0x00,
694            0x04, 0x00, 0x13, 0x00, 0x00, 0x7e, 0x73, 0x75, 0x6e, 0x55, 0x55, 0x5c, 0x64, 0x65,
695            0x65, 0x73, 0x75, 0x6e, 0x6e, 0x55, 0x5c, 0x64, 0x64, 0x65, 0x73, 0x75, 0x75, 0x6e,
696            0x55, 0x5c, 0x5c, 0x64, 0x65, 0x73, 0x73, 0x75, 0x6e, 0x55, 0x55, 0x5c, 0x64, 0x65,
697            0x65, 0x73, 0x75, 0x6e, 0x6e, 0x55, 0x5c, 0x64, 0x64, 0x65, 0x73, 0x75, 0x75, 0x6e,
698            0x55, 0x5c, 0x5c, 0x64, 0x65, 0x73, 0x73, 0x75, 0x6e, 0x55, 0x55, 0x5c, 0x64, 0x65,
699            0x65, 0x73, 0x75, 0x6e, 0x6e, 0x55, 0x5c, 0x64, 0x64, 0x65, 0x73, 0x75, 0x75, 0x6e,
700            0x55, 0x5c, 0x5c, 0x64, 0x65, 0x73, 0x45, 0x54, 0x4e, 0x49, 0x4c, 0x41, 0x4e, 0x52,
701            0x00, 0x00, 0x5c, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
702            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
703            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
704            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
705            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
706            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
707            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
708            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
709            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
710            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
711            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
712            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
713        ];
714        let mut params = GlobalParameters::default();
715        Protocol::deserialize(&mut params, &raw).unwrap();
716
717        assert_eq!(params.owner, 0xffc1000100000000);
718        assert_eq!(params.latest_notification, 0x00000010);
719        assert_eq!(params.nickname, "DesktopKonnekt6");
720        assert_eq!(
721            params.clock_config,
722            ClockConfig {
723                rate: ClockRate::R48000,
724                src: ClockSource::Internal
725            }
726        );
727        assert_eq!(params.enable, false);
728        assert_eq!(
729            params.clock_status,
730            ClockStatus {
731                src_is_locked: true,
732                rate: ClockRate::R48000
733            }
734        );
735        assert_eq!(
736            params.external_source_states,
737            ExternalSourceStates {
738                sources: vec![ClockSource::Arx1, ClockSource::Arx2],
739                locked: vec![false, false],
740                slipped: vec![false, false],
741            }
742        );
743        assert_eq!(params.current_rate, 48000);
744        assert_eq!(params.version, 0x01000400);
745        assert_eq!(
746            params.avail_rates,
747            vec![
748                ClockRate::R44100,
749                ClockRate::R48000,
750                ClockRate::R88200,
751                ClockRate::R96000,
752                ClockRate::R176400,
753                ClockRate::R192000
754            ]
755        );
756        assert_eq!(params.avail_sources, vec![ClockSource::Internal]);
757        assert_eq!(
758            params.clock_source_labels,
759            vec![
760                (ClockSource::Arx1, "Stream-1".to_string()),
761                (ClockSource::Arx2, "Stream-2".to_string()),
762                (ClockSource::Internal, "INTERNAL".to_string()),
763            ]
764        );
765
766        let mut r = vec![0u8; raw.len()];
767        Protocol::serialize(&params, &mut r).unwrap();
768
769        // NOTE: The rest of fields are unrecoverable from local parameters.
770        assert_eq!(r[..100], raw[..100]);
771    }
772
773    #[test]
774    fn global_old_params_serdes() {
775        let raw = [
776            0xff, 0xc1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x73, 0x65,
777            0x6c, 0x41, 0x4d, 0x20, 0x73, 0x69, 0x69, 0x74, 0x6c, 0x75, 0x00, 0x78, 0x69, 0x4d,
778            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
779            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
780            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x00,
782            0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x80,
783        ];
784        let mut params = GlobalParameters::default();
785        Protocol::deserialize(&mut params, &raw).unwrap();
786
787        assert_eq!(params.owner, 0xffc1000100000000);
788        assert_eq!(params.latest_notification, 0x00000020);
789        assert_eq!(params.nickname, "Alesis MultiMix");
790        assert_eq!(
791            params.clock_config,
792            ClockConfig {
793                rate: ClockRate::R48000,
794                src: ClockSource::Internal
795            }
796        );
797        assert_eq!(params.enable, false);
798        assert_eq!(
799            params.clock_status,
800            ClockStatus {
801                src_is_locked: true,
802                rate: ClockRate::R48000
803            }
804        );
805        assert_eq!(
806            params.external_source_states,
807            ExternalSourceStates {
808                sources: vec![ClockSource::Arx1],
809                locked: vec![false],
810                slipped: vec![false],
811            }
812        );
813        assert_eq!(params.current_rate, 48000);
814        assert_eq!(params.version, 0);
815        assert_eq!(
816            params.avail_rates,
817            vec![ClockRate::R44100, ClockRate::R48000,]
818        );
819        assert_eq!(params.avail_sources, vec![ClockSource::Internal]);
820        assert_eq!(
821            params.clock_source_labels,
822            vec![
823                (ClockSource::Arx1, "Stream-1".to_string()),
824                (ClockSource::Internal, "internal".to_string()),
825            ]
826        );
827
828        let mut r = vec![0u8; raw.len()];
829        Protocol::serialize(&params, &mut r).unwrap();
830
831        assert_eq!(r, raw);
832    }
833}