dvb_si/descriptors/extension/
c2_delivery_system.rs1use super::*;
3
4impl<'a> ExtensionBodyDef<'a> for C2DeliverySystem {
5 const TAG_EXTENSION: u8 = 0x0D;
6 const NAME: &'static str = "C2_DELIVERY_SYSTEM";
7}
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize))]
12#[non_exhaustive]
13pub enum C2TuningFrequencyType {
14 DataSliceTuningFrequency,
16 C2SystemCentreFrequency,
18 InitialTuningPositionStaticDataSlice,
20 Reserved(u8),
22}
23
24impl C2TuningFrequencyType {
25 #[must_use]
26 pub fn from_u8(v: u8) -> Self {
28 match v {
29 0 => C2TuningFrequencyType::DataSliceTuningFrequency,
30 1 => C2TuningFrequencyType::C2SystemCentreFrequency,
31 2 => C2TuningFrequencyType::InitialTuningPositionStaticDataSlice,
32 other => C2TuningFrequencyType::Reserved(other),
33 }
34 }
35
36 #[must_use]
37 pub fn to_u8(self) -> u8 {
39 match self {
40 C2TuningFrequencyType::DataSliceTuningFrequency => 0,
41 C2TuningFrequencyType::C2SystemCentreFrequency => 1,
42 C2TuningFrequencyType::InitialTuningPositionStaticDataSlice => 2,
43 C2TuningFrequencyType::Reserved(v) => v,
44 }
45 }
46
47 #[must_use]
48 pub fn name(self) -> &'static str {
50 match self {
51 C2TuningFrequencyType::DataSliceTuningFrequency => "Data Slice tuning frequency",
52 C2TuningFrequencyType::C2SystemCentreFrequency => "C2 system centre frequency",
53 C2TuningFrequencyType::InitialTuningPositionStaticDataSlice => {
54 "initial tuning position for a Static Data Slice"
55 }
56 C2TuningFrequencyType::Reserved(_) => "reserved",
57 }
58 }
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63#[cfg_attr(feature = "serde", derive(serde::Serialize))]
64#[non_exhaustive]
65pub enum ActiveOfdmSymbolDuration {
66 Us448,
68 Us597_33,
70 Reserved(u8),
72}
73
74impl ActiveOfdmSymbolDuration {
75 #[must_use]
76 pub fn from_u8(v: u8) -> Self {
78 match v {
79 0 => ActiveOfdmSymbolDuration::Us448,
80 1 => ActiveOfdmSymbolDuration::Us597_33,
81 other => ActiveOfdmSymbolDuration::Reserved(other),
82 }
83 }
84
85 #[must_use]
86 pub fn to_u8(self) -> u8 {
88 match self {
89 ActiveOfdmSymbolDuration::Us448 => 0,
90 ActiveOfdmSymbolDuration::Us597_33 => 1,
91 ActiveOfdmSymbolDuration::Reserved(v) => v,
92 }
93 }
94
95 #[must_use]
96 pub fn name(self) -> &'static str {
98 match self {
99 ActiveOfdmSymbolDuration::Us448 => "448 µs (4k FFT, 8 MHz)",
100 ActiveOfdmSymbolDuration::Us597_33 => "597.33 µs (4k FFT, 6 MHz)",
101 ActiveOfdmSymbolDuration::Reserved(_) => "reserved",
102 }
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108#[cfg_attr(feature = "serde", derive(serde::Serialize))]
109#[non_exhaustive]
110pub enum C2GuardInterval {
111 G1_128,
113 G1_64,
115 Reserved(u8),
117}
118
119impl C2GuardInterval {
120 #[must_use]
121 pub fn from_u8(v: u8) -> Self {
123 match v {
124 0 => C2GuardInterval::G1_128,
125 1 => C2GuardInterval::G1_64,
126 other => C2GuardInterval::Reserved(other),
127 }
128 }
129
130 #[must_use]
131 pub fn to_u8(self) -> u8 {
133 match self {
134 C2GuardInterval::G1_128 => 0,
135 C2GuardInterval::G1_64 => 1,
136 C2GuardInterval::Reserved(v) => v,
137 }
138 }
139
140 #[must_use]
141 pub fn name(self) -> &'static str {
143 match self {
144 C2GuardInterval::G1_128 => "1/128",
145 C2GuardInterval::G1_64 => "1/64",
146 C2GuardInterval::Reserved(_) => "reserved",
147 }
148 }
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq)]
153#[cfg_attr(feature = "serde", derive(serde::Serialize))]
154pub struct C2DeliverySystem {
155 pub plp_id: u8,
157 pub data_slice_id: u8,
159 pub c2_system_tuning_frequency: u32,
161 pub c2_system_tuning_frequency_type: C2TuningFrequencyType,
163 pub active_ofdm_symbol_duration: ActiveOfdmSymbolDuration,
165 pub guard_interval: C2GuardInterval,
167}
168
169impl<'a> Parse<'a> for C2DeliverySystem {
170 type Error = crate::error::Error;
171 fn parse(sel: &'a [u8]) -> Result<Self> {
172 if sel.len() < C2_LEN {
173 return Err(Error::BufferTooShort {
174 need: C2_LEN,
175 have: sel.len(),
176 what: "C2_delivery_system body",
177 });
178 }
179 let packed = sel[6];
180 Ok(C2DeliverySystem {
181 plp_id: sel[0],
182 data_slice_id: sel[1],
183 c2_system_tuning_frequency: u32::from_be_bytes([sel[2], sel[3], sel[4], sel[5]]),
184 c2_system_tuning_frequency_type: C2TuningFrequencyType::from_u8(packed >> 6),
185 active_ofdm_symbol_duration: ActiveOfdmSymbolDuration::from_u8((packed >> 3) & 0x07),
186 guard_interval: C2GuardInterval::from_u8(packed & 0x07),
187 })
188 }
189}
190
191impl Serialize for C2DeliverySystem {
192 type Error = crate::error::Error;
193 fn serialized_len(&self) -> usize {
194 C2_LEN
195 }
196 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
197 let len = self.serialized_len();
198 if buf.len() < len {
199 return Err(Error::OutputBufferTooSmall {
200 need: len,
201 have: buf.len(),
202 });
203 }
204 buf[0] = self.plp_id;
205 buf[1] = self.data_slice_id;
206 buf[2..6].copy_from_slice(&self.c2_system_tuning_frequency.to_be_bytes());
207 buf[6] = (self.c2_system_tuning_frequency_type.to_u8() << 6)
208 | ((self.active_ofdm_symbol_duration.to_u8() & 0x07) << 3)
209 | (self.guard_interval.to_u8() & 0x07);
210 Ok(len)
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217 use crate::descriptors::extension::test_support::*;
218 use crate::descriptors::extension::{ExtensionBody, ExtensionDescriptor};
219
220 #[test]
221 fn c2_tuning_frequency_type_roundtrip() {
222 for b in 0..=0xFFu8 {
223 assert_eq!(C2TuningFrequencyType::from_u8(b).to_u8(), b);
224 }
225 }
226
227 #[test]
228 fn c2_tuning_frequency_type_name() {
229 assert_eq!(
230 C2TuningFrequencyType::DataSliceTuningFrequency.name(),
231 "Data Slice tuning frequency"
232 );
233 assert_eq!(
234 C2TuningFrequencyType::C2SystemCentreFrequency.name(),
235 "C2 system centre frequency"
236 );
237 assert_eq!(
238 C2TuningFrequencyType::InitialTuningPositionStaticDataSlice.name(),
239 "initial tuning position for a Static Data Slice"
240 );
241 assert_eq!(C2TuningFrequencyType::Reserved(3).name(), "reserved");
242 }
243
244 #[test]
245 fn active_ofdm_symbol_duration_roundtrip() {
246 for b in 0..=0xFFu8 {
247 assert_eq!(ActiveOfdmSymbolDuration::from_u8(b).to_u8(), b);
248 }
249 }
250
251 #[test]
252 fn c2_guard_interval_roundtrip() {
253 for b in 0..=0xFFu8 {
254 assert_eq!(C2GuardInterval::from_u8(b).to_u8(), b);
255 }
256 }
257
258 #[test]
259 fn parse_c2_delivery_system() {
260 let packed = (0x01u8 << 3) | 0x01;
261 let sel = [0x05, 0x09, 0x12, 0x34, 0x56, 0x78, packed];
262 let bytes = wrap(0x0D, &sel);
263 let d = ExtensionDescriptor::parse(&bytes).unwrap();
264 match &d.body {
265 ExtensionBody::C2DeliverySystem(b) => {
266 assert_eq!(b.plp_id, 0x05);
267 assert_eq!(b.data_slice_id, 0x09);
268 assert_eq!(b.c2_system_tuning_frequency, 0x1234_5678);
269 assert_eq!(
270 b.c2_system_tuning_frequency_type,
271 C2TuningFrequencyType::DataSliceTuningFrequency
272 );
273 assert_eq!(
274 b.active_ofdm_symbol_duration,
275 ActiveOfdmSymbolDuration::Us597_33
276 );
277 assert_eq!(b.guard_interval, C2GuardInterval::G1_64);
278 }
279 other => panic!("expected C2DeliverySystem, got {other:?}"),
280 }
281 round_trip(&d);
282 }
283
284 #[test]
285 fn parse_c2_delivery_system_centre_frequency() {
286 let packed = 0x01u8 << 6;
287 let sel = [0x05, 0x09, 0x12, 0x34, 0x56, 0x78, packed];
288 let bytes = wrap(0x0D, &sel);
289 let d = ExtensionDescriptor::parse(&bytes).unwrap();
290 match &d.body {
291 ExtensionBody::C2DeliverySystem(b) => {
292 assert_eq!(
293 b.c2_system_tuning_frequency_type,
294 C2TuningFrequencyType::C2SystemCentreFrequency
295 );
296 }
297 other => panic!("expected C2DeliverySystem, got {other:?}"),
298 }
299 round_trip(&d);
300 }
301
302 #[test]
303 fn parse_c2_delivery_system_initial_tuning() {
304 let packed = 0x02u8 << 6;
305 let sel = [0x05, 0x09, 0x12, 0x34, 0x56, 0x78, packed];
306 let bytes = wrap(0x0D, &sel);
307 let d = ExtensionDescriptor::parse(&bytes).unwrap();
308 match &d.body {
309 ExtensionBody::C2DeliverySystem(b) => {
310 assert_eq!(
311 b.c2_system_tuning_frequency_type,
312 C2TuningFrequencyType::InitialTuningPositionStaticDataSlice
313 );
314 }
315 other => panic!("expected C2DeliverySystem, got {other:?}"),
316 }
317 round_trip(&d);
318 }
319
320 #[test]
321 fn parse_c2_delivery_system_reserved_values() {
322 let packed = (0x03u8 << 6) | (0x07u8 << 3) | 0x07;
323 let sel = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, packed];
324 let bytes = wrap(0x0D, &sel);
325 let d = ExtensionDescriptor::parse(&bytes).unwrap();
326 match &d.body {
327 ExtensionBody::C2DeliverySystem(b) => {
328 assert_eq!(
329 b.c2_system_tuning_frequency_type,
330 C2TuningFrequencyType::Reserved(3)
331 );
332 assert_eq!(
333 b.active_ofdm_symbol_duration,
334 ActiveOfdmSymbolDuration::Reserved(7)
335 );
336 assert_eq!(b.guard_interval, C2GuardInterval::Reserved(7));
337 }
338 other => panic!("expected C2DeliverySystem, got {other:?}"),
339 }
340 round_trip(&d);
341 }
342}