Skip to main content

dvb_si/descriptors/extension/
t2_delivery_system.rs

1//! T2 Delivery System Descriptor — ETSI EN 300 468 §6.4.6.3 (tag_extension 0x04).
2use super::*;
3
4impl<'a> ExtensionBodyDef<'a> for T2DeliverySystem {
5    const TAG_EXTENSION: u8 = 0x04;
6    const NAME: &'static str = "T2_DELIVERY_SYSTEM";
7}
8
9/// One T2 cell (Table 133 inner `for`).
10#[derive(Debug, Clone, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize))]
12pub struct T2Cell {
13    /// cell_id(16).
14    pub cell_id: u16,
15    /// centre_frequency list. When tfs_flag, the length-prefixed loop;
16    /// otherwise exactly one frequency.
17    pub centre_frequencies: Vec<u32>,
18    /// subcell entries.
19    pub subcells: Vec<T2Subcell>,
20}
21
22/// One T2 subcell (Table 133 innermost `for`).
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize))]
25pub struct T2Subcell {
26    /// cell_id_extension(8).
27    pub cell_id_extension: u8,
28    /// transposer_frequency(32).
29    pub transposer_frequency: u32,
30}
31
32/// T2_delivery_system body (Table 133). The cell loop is unfolded.
33#[derive(Debug, Clone, PartialEq, Eq)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize))]
35pub struct T2DeliverySystem {
36    /// PLP identifier.
37    pub plp_id: u8,
38    /// T2 system identifier.
39    pub t2_system_id: u16,
40    /// SISO_MISO(2), present iff `descriptor_length > 4` (flags block present).
41    pub siso_miso: Option<u8>,
42    /// bandwidth(4), present with `siso_miso`.
43    pub bandwidth: Option<u8>,
44    /// guard_interval(3), present with `siso_miso`.
45    pub guard_interval: Option<u8>,
46    /// transmission_mode(3), present with `siso_miso`.
47    pub transmission_mode: Option<u8>,
48    /// other_frequency_flag(1), present with `siso_miso`.
49    pub other_frequency_flag: Option<bool>,
50    /// tfs_flag(1), present with `siso_miso`.
51    pub tfs_flag: Option<bool>,
52    /// Cell loop entries (present only when flags block is present).
53    pub cells: Vec<T2Cell>,
54}
55
56impl<'a> Parse<'a> for T2DeliverySystem {
57    type Error = crate::error::Error;
58    fn parse(sel: &'a [u8]) -> Result<Self> {
59        if sel.len() < T2_FIXED_PREFIX_LEN {
60            return Err(Error::BufferTooShort {
61                need: T2_FIXED_PREFIX_LEN,
62                have: sel.len(),
63                what: "T2_delivery_system body",
64            });
65        }
66        let plp_id = sel[0];
67        let t2_system_id = u16::from_be_bytes([sel[1], sel[2]]);
68        let mut pos = T2_FIXED_PREFIX_LEN;
69        let (
70            siso_miso,
71            bandwidth,
72            guard_interval,
73            transmission_mode,
74            other_frequency_flag,
75            tfs_flag,
76        ) = if sel.len() > T2_FIXED_PREFIX_LEN {
77            if sel.len() < T2_FIXED_PREFIX_LEN + T2_FLAGS_BLOCK_LEN {
78                return Err(Error::BufferTooShort {
79                    need: T2_FIXED_PREFIX_LEN + T2_FLAGS_BLOCK_LEN,
80                    have: sel.len(),
81                    what: "T2_delivery_system body",
82                });
83            }
84            let b0 = sel[pos];
85            let b1 = sel[pos + 1];
86            pos += T2_FLAGS_BLOCK_LEN;
87            (
88                Some(b0 >> 6),
89                Some((b0 >> 2) & 0x0F),
90                Some(b1 >> 5),
91                Some((b1 >> 2) & 0x07),
92                Some((b1 & 0x02) != 0),
93                Some((b1 & 0x01) != 0),
94            )
95        } else {
96            (None, None, None, None, None, None)
97        };
98        let cells = if siso_miso.is_some() {
99            let tfs = tfs_flag.unwrap();
100            let mut cells = Vec::new();
101            while pos < sel.len() {
102                if pos + 2 > sel.len() {
103                    return Err(Error::BufferTooShort {
104                        need: pos + 2,
105                        have: sel.len(),
106                        what: "T2_delivery_system body",
107                    });
108                }
109                let cell_id = u16::from_be_bytes([sel[pos], sel[pos + 1]]);
110                pos += 2;
111                let centre_frequencies = if tfs {
112                    if pos >= sel.len() {
113                        return Err(Error::BufferTooShort {
114                            need: pos + 1,
115                            have: sel.len(),
116                            what: "T2_delivery_system body",
117                        });
118                    }
119                    let freq_loop_len = sel[pos] as usize;
120                    pos += 1;
121                    if freq_loop_len % 4 != 0 {
122                        return Err(invalid(
123                            "T2_delivery_system: frequency_loop_length not a multiple of 4",
124                        ));
125                    }
126                    if pos + freq_loop_len > sel.len() {
127                        return Err(Error::BufferTooShort {
128                            need: pos + freq_loop_len,
129                            have: sel.len(),
130                            what: "T2_delivery_system body",
131                        });
132                    }
133                    let end = pos + freq_loop_len;
134                    let mut freqs = Vec::with_capacity(freq_loop_len / 4);
135                    while pos < end {
136                        freqs.push(u32::from_be_bytes([
137                            sel[pos],
138                            sel[pos + 1],
139                            sel[pos + 2],
140                            sel[pos + 3],
141                        ]));
142                        pos += 4;
143                    }
144                    freqs
145                } else {
146                    if pos + 4 > sel.len() {
147                        return Err(Error::BufferTooShort {
148                            need: pos + 4,
149                            have: sel.len(),
150                            what: "T2_delivery_system body",
151                        });
152                    }
153                    let freq =
154                        u32::from_be_bytes([sel[pos], sel[pos + 1], sel[pos + 2], sel[pos + 3]]);
155                    pos += 4;
156                    vec![freq]
157                };
158                if pos >= sel.len() {
159                    return Err(Error::BufferTooShort {
160                        need: pos + 1,
161                        have: sel.len(),
162                        what: "T2_delivery_system body",
163                    });
164                }
165                let subcell_loop_len = sel[pos] as usize;
166                pos += 1;
167                if subcell_loop_len % 5 != 0 {
168                    return Err(invalid(
169                        "T2_delivery_system: subcell_info_loop_length not a multiple of 5",
170                    ));
171                }
172                if pos + subcell_loop_len > sel.len() {
173                    return Err(Error::BufferTooShort {
174                        need: pos + subcell_loop_len,
175                        have: sel.len(),
176                        what: "T2_delivery_system body",
177                    });
178                }
179                let end = pos + subcell_loop_len;
180                let mut subcells = Vec::with_capacity(subcell_loop_len / 5);
181                while pos < end {
182                    subcells.push(T2Subcell {
183                        cell_id_extension: sel[pos],
184                        transposer_frequency: u32::from_be_bytes([
185                            sel[pos + 1],
186                            sel[pos + 2],
187                            sel[pos + 3],
188                            sel[pos + 4],
189                        ]),
190                    });
191                    pos += 5;
192                }
193                cells.push(T2Cell {
194                    cell_id,
195                    centre_frequencies,
196                    subcells,
197                });
198            }
199            cells
200        } else {
201            Vec::new()
202        };
203        Ok(T2DeliverySystem {
204            plp_id,
205            t2_system_id,
206            siso_miso,
207            bandwidth,
208            guard_interval,
209            transmission_mode,
210            other_frequency_flag,
211            tfs_flag,
212            cells,
213        })
214    }
215}
216
217impl Serialize for T2DeliverySystem {
218    type Error = crate::error::Error;
219    fn serialized_len(&self) -> usize {
220        let mut len = T2_FIXED_PREFIX_LEN;
221        if self.siso_miso.is_some() {
222            len += T2_FLAGS_BLOCK_LEN;
223            let tfs = self.tfs_flag.unwrap_or(false);
224            for cell in &self.cells {
225                len += 2; // cell_id
226                if tfs {
227                    len += 1 + cell.centre_frequencies.len() * 4;
228                } else {
229                    len += 4;
230                }
231                len += 1 + cell.subcells.len() * 5;
232            }
233        }
234        len
235    }
236    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
237        let len = self.serialized_len();
238        if buf.len() < len {
239            return Err(Error::OutputBufferTooSmall {
240                need: len,
241                have: buf.len(),
242            });
243        }
244        buf[0] = self.plp_id;
245        buf[1..3].copy_from_slice(&self.t2_system_id.to_be_bytes());
246        let mut p = T2_FIXED_PREFIX_LEN;
247        if let (Some(sm), Some(bw), Some(gi), Some(tm), Some(off), Some(tfs)) = (
248            self.siso_miso,
249            self.bandwidth,
250            self.guard_interval,
251            self.transmission_mode,
252            self.other_frequency_flag,
253            self.tfs_flag,
254        ) {
255            buf[p] = (sm << 6) | ((bw & 0x0F) << 2) | 0x03;
256            buf[p + 1] = (gi << 5) | ((tm & 0x07) << 2) | (u8::from(off) << 1) | u8::from(tfs);
257            p += T2_FLAGS_BLOCK_LEN;
258            for cell in &self.cells {
259                buf[p..p + 2].copy_from_slice(&cell.cell_id.to_be_bytes());
260                p += 2;
261                if tfs {
262                    let freq_len = (cell.centre_frequencies.len() * 4) as u8;
263                    buf[p] = freq_len;
264                    p += 1;
265                    for &freq in &cell.centre_frequencies {
266                        buf[p..p + 4].copy_from_slice(&freq.to_be_bytes());
267                        p += 4;
268                    }
269                } else {
270                    let freq = cell.centre_frequencies.first().copied().unwrap_or(0);
271                    buf[p..p + 4].copy_from_slice(&freq.to_be_bytes());
272                    p += 4;
273                }
274                let subcell_len = (cell.subcells.len() * 5) as u8;
275                buf[p] = subcell_len;
276                p += 1;
277                for sc in &cell.subcells {
278                    buf[p] = sc.cell_id_extension;
279                    buf[p + 1..p + 5].copy_from_slice(&sc.transposer_frequency.to_be_bytes());
280                    p += 5;
281                }
282            }
283        }
284        Ok(len)
285    }
286}
287
288#[cfg(test)]
289mod tests {
290    use super::*;
291    use crate::descriptors::extension::test_support::*;
292    use crate::descriptors::extension::{ExtensionBody, ExtensionDescriptor};
293
294    #[test]
295    fn parse_t2_minimal() {
296        // body = plp + system_id = 3 bytes => no flags block
297        let sel = [0x07, 0x12, 0x34];
298        let bytes = wrap(0x04, &sel);
299        let d = ExtensionDescriptor::parse(&bytes).unwrap();
300        match &d.body {
301            ExtensionBody::T2DeliverySystem(b) => {
302                assert_eq!(b.plp_id, 0x07);
303                assert_eq!(b.t2_system_id, 0x1234);
304                assert_eq!(b.siso_miso, None);
305                assert!(b.cells.is_empty());
306            }
307            other => panic!("expected T2DeliverySystem, got {other:?}"),
308        }
309        round_trip(&d);
310    }
311
312    #[test]
313    fn parse_t2_structured_flags_and_cells() {
314        // prefix + flags block (siso=0, bw=4, gi=6, tm=3, off=0, tfs=1)
315        // + 2 cells: one empty, one with 3 freqs + 2 subcells
316        let b0: u8 = ((0x04 & 0x0F) << 2) | 0x03; // siso_miso=0, bandwidth=4, reserved=11
317        let b1: u8 = (0x06 << 5) | ((0x03 & 0x07) << 2) | (u8::from(false) << 1) | u8::from(true);
318        // cell 1: cell_id=0x1234, freq_len=0, subcell_len=0
319        let cell1 = [0x12, 0x34, 0x00, 0x00];
320        // cell 2: cell_id=0x5678, freq_len=12 (3 freqs), three freqs, subcell_len=10 (2 subcells), two subcells
321        let f1 = 0x01020304u32;
322        let f2 = 0x05060708u32;
323        let f3 = 0x090A0B0Cu32;
324        let sc1_id = 0x10u8;
325        let sc1_freq = 0x11121314u32;
326        let sc2_id = 0x20u8;
327        let sc2_freq = 0x21222324u32;
328        let mut cell2 = Vec::new();
329        cell2.extend_from_slice(&0x5678u16.to_be_bytes());
330        cell2.push(12);
331        cell2.extend_from_slice(&f1.to_be_bytes());
332        cell2.extend_from_slice(&f2.to_be_bytes());
333        cell2.extend_from_slice(&f3.to_be_bytes());
334        cell2.push(10);
335        cell2.push(sc1_id);
336        cell2.extend_from_slice(&sc1_freq.to_be_bytes());
337        cell2.push(sc2_id);
338        cell2.extend_from_slice(&sc2_freq.to_be_bytes());
339        let mut sel = vec![0x07, 0x12, 0x34, b0, b1];
340        sel.extend_from_slice(&cell1);
341        sel.extend_from_slice(&cell2);
342        let bytes = wrap(0x04, &sel);
343        let d = ExtensionDescriptor::parse(&bytes).unwrap();
344        match &d.body {
345            ExtensionBody::T2DeliverySystem(b) => {
346                assert_eq!(b.plp_id, 0x07);
347                assert_eq!(b.t2_system_id, 0x1234);
348                assert_eq!(b.siso_miso, Some(0x00));
349                assert_eq!(b.bandwidth, Some(0x04));
350                assert_eq!(b.guard_interval, Some(0x06));
351                assert_eq!(b.transmission_mode, Some(0x03));
352                assert_eq!(b.other_frequency_flag, Some(false));
353                assert_eq!(b.tfs_flag, Some(true));
354                assert_eq!(b.cells.len(), 2);
355                // cell 0: empty
356                assert_eq!(b.cells[0].cell_id, 0x1234);
357                assert!(b.cells[0].centre_frequencies.is_empty());
358                assert!(b.cells[0].subcells.is_empty());
359                // cell 1: 3 freqs + 2 subcells
360                assert_eq!(b.cells[1].cell_id, 0x5678);
361                assert_eq!(b.cells[1].centre_frequencies, vec![f1, f2, f3]);
362                assert_eq!(b.cells[1].subcells.len(), 2);
363                assert_eq!(b.cells[1].subcells[0].cell_id_extension, sc1_id);
364                assert_eq!(b.cells[1].subcells[0].transposer_frequency, sc1_freq);
365                assert_eq!(b.cells[1].subcells[1].cell_id_extension, sc2_id);
366                assert_eq!(b.cells[1].subcells[1].transposer_frequency, sc2_freq);
367            }
368            other => panic!("expected T2DeliverySystem, got {other:?}"),
369        }
370        round_trip(&d);
371    }
372
373    #[test]
374    fn tsduck_t2_reference() {
375        let bytes = from_hex(
376            "7f240456789a13cd12340000678a0c075bcd1505e30a780fd22c320a1217ea6406fa0aa9fc59",
377        );
378        let d = ExtensionDescriptor::parse(&bytes).unwrap();
379        match &d.body {
380            ExtensionBody::T2DeliverySystem(b) => {
381                assert_eq!(b.plp_id, 0x56);
382                assert_eq!(b.t2_system_id, 0x789A);
383                assert_eq!(b.siso_miso, Some(0));
384                assert_eq!(b.bandwidth, Some(4));
385                assert_eq!(b.guard_interval, Some(6));
386                assert_eq!(b.transmission_mode, Some(3));
387                assert_eq!(b.other_frequency_flag, Some(false));
388                assert_eq!(b.tfs_flag, Some(true));
389                assert_eq!(b.cells.len(), 2);
390
391                assert_eq!(b.cells[0].cell_id, 0x1234);
392                assert!(b.cells[0].centre_frequencies.is_empty());
393                assert!(b.cells[0].subcells.is_empty());
394
395                assert_eq!(b.cells[1].cell_id, 0x678A);
396                assert_eq!(
397                    b.cells[1].centre_frequencies,
398                    vec![0x075BCD15, 0x05E30A78, 0x0FD22C32]
399                );
400                assert_eq!(b.cells[1].subcells.len(), 2);
401                assert_eq!(b.cells[1].subcells[0].cell_id_extension, 0x12);
402                assert_eq!(b.cells[1].subcells[0].transposer_frequency, 0x17EA6406);
403                assert_eq!(b.cells[1].subcells[1].cell_id_extension, 0xFA);
404                assert_eq!(b.cells[1].subcells[1].transposer_frequency, 0x0AA9FC59);
405            }
406            other => panic!("expected T2DeliverySystem, got {other:?}"),
407        }
408        let mut out = vec![0u8; d.serialized_len()];
409        let n = d.serialize_into(&mut out).unwrap();
410        assert_eq!(
411            out[..n],
412            bytes[..],
413            "byte-exact re-serialize for tsduck T2 reference"
414        );
415    }
416}