firewire_dice_protocols/tcat/
rx_stream_format_section.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! Rx Stream format section in general protocol for ASICs of DICE.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for Rx stream
7//! format section in general protocol defined by TCAT for ASICs of DICE.
8use super::*;
9
10/// Entry for stream format in stream received by the node.
11#[derive(Default, Debug, Clone, PartialEq, Eq)]
12pub struct RxStreamFormatEntry {
13    /// The channel number for isochronous packet stream.
14    pub iso_channel: i8,
15    /// The start position of data channels from the beginning of payload in quadlet count.
16    pub start: u32,
17    /// The number of PCM channels.
18    pub pcm: u32,
19    /// The number of MIDI ports.
20    pub midi: u32,
21    /// The list of names for data channel.
22    pub labels: Vec<String>,
23    /// The mode for each channel of IEC 60958.
24    pub iec60958: [Iec60958Param; IEC60958_CHANNELS],
25}
26
27const MIN_SIZE: usize = 272;
28
29fn serialize_rx_stream_entry(entry: &RxStreamFormatEntry, raw: &mut [u8]) -> Result<(), String> {
30    assert!(raw.len() >= MIN_SIZE);
31
32    serialize_i32(&(entry.iso_channel as i32), &mut raw[..4]);
33
34    serialize_u32(&entry.start, &mut raw[4..8]);
35    serialize_u32(&entry.pcm, &mut raw[8..12]);
36    serialize_u32(&entry.midi, &mut raw[12..16]);
37
38    serialize_labels(&entry.labels, &mut raw[16..272])?;
39
40    // NOTE: it's not supported by old version of firmware.
41    if raw.len() >= 272 {
42        serialize_iec60958_params(&entry.iec60958, &mut raw[272..280])?;
43    }
44    Ok(())
45}
46
47fn deserialize_rx_stream_entry(entry: &mut RxStreamFormatEntry, raw: &[u8]) -> Result<(), String> {
48    assert!(raw.len() >= MIN_SIZE);
49
50    let mut val = 0i32;
51    deserialize_i32(&mut val, &raw[..4]);
52    entry.iso_channel = val as i8;
53
54    deserialize_u32(&mut entry.start, &raw[4..8]);
55    deserialize_u32(&mut entry.pcm, &raw[8..12]);
56    deserialize_u32(&mut entry.midi, &raw[12..16]);
57
58    deserialize_labels(&mut entry.labels, &raw[16..272])?;
59
60    // NOTE: it's not supported by old version of firmware.
61    if raw.len() >= MIN_SIZE {
62        deserialize_iec60958_params(&mut entry.iec60958, &raw[272..280])?;
63    }
64    Ok(())
65}
66
67/// Parameters for format of receive streams.
68#[derive(Default, Debug, Clone, PartialEq, Eq)]
69pub struct RxStreamFormatParameters(pub Vec<RxStreamFormatEntry>);
70
71impl<O: TcatOperation> TcatSectionSerdes<RxStreamFormatParameters> for O {
72    const MIN_SIZE: usize = 8;
73
74    const ERROR_TYPE: GeneralProtocolError = GeneralProtocolError::RxStreamFormat;
75
76    fn serialize(params: &RxStreamFormatParameters, raw: &mut [u8]) -> Result<(), String> {
77        let mut val = 0u32;
78
79        // The number of streams is read-only.
80        deserialize_u32(&mut val, &raw[..4]);
81        let count = val as usize;
82
83        if count != params.0.len() {
84            let msg = format!(
85                "The count of entries should be {}, actually {}",
86                count,
87                params.0.len()
88            );
89            Err(msg)?;
90        }
91
92        // The size of stream format entry is read-only as well.
93        deserialize_u32(&mut val, &raw[4..8]);
94        let size = 4 * val as usize;
95
96        let expected = 8 + size * count;
97        if raw.len() < expected {
98            let msg = format!(
99                "The size of buffer should be greater than {}, actually {}",
100                expected,
101                raw.len()
102            );
103            Err(msg)?;
104        }
105
106        params.0.iter().enumerate().try_for_each(|(i, entry)| {
107            let pos = 8 + size * i;
108            serialize_rx_stream_entry(entry, &mut raw[pos..(pos + size)])
109        })
110    }
111
112    fn deserialize(params: &mut RxStreamFormatParameters, raw: &[u8]) -> Result<(), String> {
113        let mut val = 0u32;
114        deserialize_u32(&mut val, &raw[..4]);
115        let count = val as usize;
116
117        deserialize_u32(&mut val, &raw[4..8]);
118        let size = 4 * val as usize;
119
120        let expected = 8 + size * count;
121        if raw.len() < expected {
122            let msg = format!(
123                "The size of buffer should be greater than {}, actually {}",
124                expected,
125                raw.len()
126            );
127            Err(msg)?;
128        }
129
130        params.0.resize_with(count, Default::default);
131
132        params.0.iter_mut().enumerate().try_for_each(|(i, entry)| {
133            let pos = 8 + size * i;
134            deserialize_rx_stream_entry(entry, &raw[pos..(pos + size)])
135        })
136    }
137}
138
139impl<O: TcatOperation> TcatSectionOperation<RxStreamFormatParameters> for O {}
140
141impl<O: TcatSectionOperation<RxStreamFormatParameters>>
142    TcatMutableSectionOperation<RxStreamFormatParameters> for O
143{
144}
145
146impl<O: TcatSectionOperation<RxStreamFormatParameters>>
147    TcatNotifiedSectionOperation<RxStreamFormatParameters> for O
148{
149    const NOTIFY_FLAG: u32 = NOTIFY_RX_CFG_CHG;
150}
151
152#[cfg(test)]
153mod test {
154    use super::*;
155
156    #[test]
157    fn rx_stream_format_entry_serdes() {
158        let params = RxStreamFormatEntry {
159            iso_channel: 32,
160            start: 4,
161            pcm: 4,
162            midi: 2,
163            labels: vec![
164                "a".to_string(),
165                "b".to_string(),
166                "c".to_string(),
167                "d".to_string(),
168            ],
169            iec60958: [Iec60958Param {
170                cap: true,
171                enable: false,
172            }; IEC60958_CHANNELS],
173        };
174        let mut raw = [0u8; 2048];
175        serialize_rx_stream_entry(&params, &mut raw).unwrap();
176
177        let mut p = RxStreamFormatEntry::default();
178        deserialize_rx_stream_entry(&mut p, &raw).unwrap();
179
180        assert_eq!(params, p);
181    }
182}