dvb_si/descriptors/extension/
c2_bundle_delivery_system.rs1use super::*;
3
4impl<'a> ExtensionBodyDef<'a> for C2BundleDeliverySystem {
5 const TAG_EXTENSION: u8 = 0x16;
6 const NAME: &'static str = "C2_BUNDLE_DELIVERY_SYSTEM";
7}
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize))]
11pub struct C2BundleEntry {
12 pub plp_id: u8,
14 pub data_slice_id: u8,
16 pub c2_system_tuning_frequency: u32,
18 pub c2_system_tuning_frequency_type: u8,
20 pub active_ofdm_symbol_duration: u8,
22 pub guard_interval: u8,
24 pub primary_channel: bool,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize))]
31pub struct C2BundleDeliverySystem {
32 pub entries: Vec<C2BundleEntry>,
34}
35
36impl<'a> Parse<'a> for C2BundleDeliverySystem {
37 type Error = crate::error::Error;
38 fn parse(sel: &'a [u8]) -> Result<Self> {
39 if sel.len() % C2_BUNDLE_ENTRY_LEN != 0 {
40 return Err(invalid(
41 "C2_bundle_delivery_system: not a whole number of entries",
42 ));
43 }
44 let mut entries = Vec::with_capacity(sel.len() / C2_BUNDLE_ENTRY_LEN);
45 for chunk in sel.chunks_exact(C2_BUNDLE_ENTRY_LEN) {
46 let packed = chunk[6];
47 entries.push(C2BundleEntry {
48 plp_id: chunk[0],
49 data_slice_id: chunk[1],
50 c2_system_tuning_frequency: u32::from_be_bytes([
51 chunk[2], chunk[3], chunk[4], chunk[5],
52 ]),
53 c2_system_tuning_frequency_type: packed >> 6,
54 active_ofdm_symbol_duration: (packed >> 3) & 0x07,
55 guard_interval: packed & 0x07,
56 primary_channel: (chunk[7] & 0x80) != 0,
57 });
58 }
59 Ok(C2BundleDeliverySystem { entries })
60 }
61}
62
63impl Serialize for C2BundleDeliverySystem {
64 type Error = crate::error::Error;
65 fn serialized_len(&self) -> usize {
66 self.entries.len() * C2_BUNDLE_ENTRY_LEN
67 }
68 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
69 let len = self.serialized_len();
70 if buf.len() < len {
71 return Err(Error::OutputBufferTooSmall {
72 need: len,
73 have: buf.len(),
74 });
75 }
76 let mut p = 0;
77 for e in &self.entries {
78 buf[p] = e.plp_id;
79 buf[p + 1] = e.data_slice_id;
80 buf[p + 2..p + 6].copy_from_slice(&e.c2_system_tuning_frequency.to_be_bytes());
81 buf[p + 6] = (e.c2_system_tuning_frequency_type << 6)
82 | ((e.active_ofdm_symbol_duration & 0x07) << 3)
83 | (e.guard_interval & 0x07);
84 buf[p + 7] = u8::from(e.primary_channel) << 7;
85 p += C2_BUNDLE_ENTRY_LEN;
86 }
87 Ok(len)
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 use crate::descriptors::extension::test_support::*;
95 use crate::descriptors::extension::{ExtensionBody, ExtensionDescriptor};
96
97 #[test]
98 fn parse_c2_bundle_two_entries() {
99 let entry = |off: u8| {
100 let packed = (0x01u8 << 6) | 0x01; [off, off + 1, 0x00, 0x00, 0x10, 0x00, packed, 0x80]
103 };
104 let mut sel = Vec::new();
105 sel.extend_from_slice(&entry(0x01));
106 sel.extend_from_slice(&entry(0x05));
107 let bytes = wrap(0x16, &sel);
108 let d = ExtensionDescriptor::parse(&bytes).unwrap();
109 match &d.body {
110 ExtensionBody::C2BundleDeliverySystem(b) => {
111 assert_eq!(b.entries.len(), 2);
112 assert_eq!(b.entries[0].plp_id, 0x01);
113 assert!(b.entries[0].primary_channel);
114 assert_eq!(b.entries[1].plp_id, 0x05);
115 assert_eq!(b.entries[1].guard_interval, 0x01);
116 }
117 other => panic!("expected C2BundleDeliverySystem, got {other:?}"),
118 }
119 round_trip(&d);
120 }
121
122 #[test]
123 fn parse_c2_bundle_rejects_partial_entry() {
124 let sel = [0x01, 0x02, 0x03]; let bytes = wrap(0x16, &sel);
126 assert!(matches!(
127 ExtensionDescriptor::parse(&bytes).unwrap_err(),
128 crate::error::Error::InvalidDescriptor {
129 tag: super::TAG,
130 ..
131 }
132 ));
133 }
134}