1use super::*;
3
4impl<'a> ExtensionBodyDef<'a> for ShDeliverySystem {
5 const TAG_EXTENSION: u8 = 0x05;
6 const NAME: &'static str = "SH_DELIVERY_SYSTEM";
7}
8
9#[derive(Debug, Clone, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize))]
15pub struct ShDeliverySystem {
16 pub diversity_mode: u8,
18 pub modulations: Vec<ShModulation>,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize))]
25pub struct ShModulation {
26 pub modulation: ShModulationMode,
28 pub interleaver: Option<ShInterleaver>,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize))]
36pub enum ShModulationMode {
37 Tdm {
39 polarization: u8,
41 roll_off: u8,
43 modulation_mode: u8,
45 code_rate: u8,
47 symbol_rate: u8,
49 },
50 Ofdm {
52 bandwidth: u8,
54 priority: bool,
56 constellation_and_hierarchy: u8,
58 code_rate: u8,
60 guard_interval: u8,
62 transmission_mode: u8,
64 common_frequency: bool,
66 },
67}
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71#[cfg_attr(feature = "serde", derive(serde::Serialize))]
72pub enum ShInterleaver {
73 Type0 {
75 common_multiplier: u8,
77 nof_late_taps: u8,
79 nof_slices: u8,
81 slice_distance: u8,
83 non_late_increments: u8,
85 },
86 Type1 {
88 common_multiplier: u8,
90 },
91}
92
93impl<'a> Parse<'a> for ShDeliverySystem {
94 type Error = crate::error::Error;
95 fn parse(sel: &'a [u8]) -> Result<Self> {
96 if sel.is_empty() {
97 return Err(Error::BufferTooShort {
98 need: 1,
99 have: sel.len(),
100 what: "SH_delivery_system body",
101 });
102 }
103 let diversity_mode = sel[0] >> 4;
104 let mut pos = 1;
105 let mut modulations = Vec::new();
106 while pos < sel.len() {
107 if sel.len() - pos < 3 {
109 return Err(Error::BufferTooShort {
110 need: pos + 3,
111 have: sel.len(),
112 what: "SH_delivery_system body",
113 });
114 }
115 let flags = sel[pos];
116 let modulation_type = (flags >> 7) & 0x01;
117 let interleaver_presence = (flags >> 6) & 0x01;
118 let interleaver_type = (flags >> 5) & 0x01;
119 let mb0 = sel[pos + 1];
120 let mb1 = sel[pos + 2];
121 pos += 3;
122
123 let modulation = if modulation_type == 0 {
124 let polarization = mb0 >> 6;
126 let roll_off = (mb0 >> 4) & 0x03;
127 let modulation_mode = (mb0 >> 2) & 0x03;
128 let code_rate = ((mb0 & 0x03) << 2) | (mb1 >> 6);
129 let symbol_rate = (mb1 >> 1) & 0x1F;
130 ShModulationMode::Tdm {
131 polarization,
132 roll_off,
133 modulation_mode,
134 code_rate,
135 symbol_rate,
136 }
137 } else {
138 let bandwidth = mb0 >> 5;
140 let priority = ((mb0 >> 4) & 0x01) != 0;
141 let constellation_and_hierarchy = (mb0 >> 1) & 0x07;
142 let code_rate = ((mb0 & 0x01) << 3) | (mb1 >> 5);
143 let guard_interval = (mb1 >> 3) & 0x03;
144 let transmission_mode = (mb1 >> 1) & 0x03;
145 let common_frequency = (mb1 & 0x01) != 0;
146 ShModulationMode::Ofdm {
147 bandwidth,
148 priority,
149 constellation_and_hierarchy,
150 code_rate,
151 guard_interval,
152 transmission_mode,
153 common_frequency,
154 }
155 };
156
157 let interleaver = if interleaver_presence == 1 {
158 if interleaver_type == 0 {
159 if sel.len() - pos < 4 {
161 return Err(Error::BufferTooShort {
162 need: pos + 4,
163 have: sel.len(),
164 what: "SH_delivery_system body",
165 });
166 }
167 let b0 = sel[pos];
168 let b1 = sel[pos + 1];
169 let b2 = sel[pos + 2];
170 let b3 = sel[pos + 3];
171 let common_multiplier = b0 >> 2;
172 let nof_late_taps = ((b0 & 0x03) << 4) | (b1 >> 4);
173 let nof_slices = ((b1 & 0x0F) << 2) | (b2 >> 6);
174 let slice_distance = ((b2 & 0x3F) << 2) | (b3 >> 6);
175 let non_late_increments = b3 & 0x3F;
176 pos += 4;
177 Some(ShInterleaver::Type0 {
178 common_multiplier,
179 nof_late_taps,
180 nof_slices,
181 slice_distance,
182 non_late_increments,
183 })
184 } else {
185 if sel.len() - pos < 1 {
187 return Err(Error::BufferTooShort {
188 need: pos + 1,
189 have: sel.len(),
190 what: "SH_delivery_system body",
191 });
192 }
193 let common_multiplier = sel[pos] >> 2;
194 pos += 1;
195 Some(ShInterleaver::Type1 { common_multiplier })
196 }
197 } else {
198 None
199 };
200
201 modulations.push(ShModulation {
202 modulation,
203 interleaver,
204 });
205 }
206 Ok(ShDeliverySystem {
207 diversity_mode,
208 modulations,
209 })
210 }
211}
212
213impl Serialize for ShDeliverySystem {
214 type Error = crate::error::Error;
215 fn serialized_len(&self) -> usize {
216 1 + self
217 .modulations
218 .iter()
219 .map(|m| {
220 3 + match &m.interleaver {
221 None => 0,
222 Some(ShInterleaver::Type0 { .. }) => 4,
223 Some(ShInterleaver::Type1 { .. }) => 1,
224 }
225 })
226 .sum::<usize>()
227 }
228 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
229 let len = self.serialized_len();
230 if buf.len() < len {
231 return Err(Error::OutputBufferTooSmall {
232 need: len,
233 have: buf.len(),
234 });
235 }
236 buf[0] = (self.diversity_mode << 4) | 0x0F;
238 let mut p = 1;
239 for m in &self.modulations {
240 let modulation_type_bit = matches!(m.modulation, ShModulationMode::Ofdm { .. }) as u8;
241 let interleaver_presence_bit = m.interleaver.is_some() as u8;
242 let interleaver_type_bit =
243 matches!(m.interleaver, Some(ShInterleaver::Type1 { .. })) as u8;
244 buf[p] = (modulation_type_bit << 7)
247 | (interleaver_presence_bit << 6)
248 | (interleaver_type_bit << 5)
249 | 0x1F;
250 p += 1;
251
252 match &m.modulation {
253 ShModulationMode::Tdm {
254 polarization,
255 roll_off,
256 modulation_mode,
257 code_rate,
258 symbol_rate,
259 } => {
260 buf[p] = (polarization << 6)
261 | ((roll_off & 0x03) << 4)
262 | ((modulation_mode & 0x03) << 2)
263 | ((code_rate >> 2) & 0x03);
264 buf[p + 1] = ((code_rate & 0x03) << 6) | ((symbol_rate & 0x1F) << 1) | 0x01;
266 }
267 ShModulationMode::Ofdm {
268 bandwidth,
269 priority,
270 constellation_and_hierarchy,
271 code_rate,
272 guard_interval,
273 transmission_mode,
274 common_frequency,
275 } => {
276 buf[p] = (bandwidth << 5)
277 | (u8::from(*priority) << 4)
278 | ((constellation_and_hierarchy & 0x07) << 1)
279 | ((code_rate >> 3) & 0x01);
280 buf[p + 1] = ((code_rate & 0x07) << 5)
281 | ((guard_interval & 0x03) << 3)
282 | ((transmission_mode & 0x03) << 1)
283 | u8::from(*common_frequency);
284 }
285 }
286 p += 2;
287
288 match &m.interleaver {
289 Some(ShInterleaver::Type0 {
290 common_multiplier,
291 nof_late_taps,
292 nof_slices,
293 slice_distance,
294 non_late_increments,
295 }) => {
296 let cm = common_multiplier & 0x3F;
297 let lt = nof_late_taps & 0x3F;
298 let ns = nof_slices & 0x3F;
299 let sd = slice_distance;
300 let nli = non_late_increments & 0x3F;
301 buf[p] = (cm << 2) | (lt >> 4);
302 buf[p + 1] = ((lt & 0x0F) << 4) | (ns >> 2);
303 buf[p + 2] = ((ns & 0x03) << 6) | (sd >> 2);
304 buf[p + 3] = ((sd & 0x03) << 6) | nli;
305 p += 4;
306 }
307 Some(ShInterleaver::Type1 { common_multiplier }) => {
308 buf[p] = ((common_multiplier & 0x3F) << 2) | 0x03;
310 p += 1;
311 }
312 None => {}
313 }
314 }
315 Ok(len)
316 }
317}
318
319#[cfg(test)]
320mod tests {
321 use super::*;
322 use crate::descriptors::extension::test_support::*;
323 use crate::descriptors::extension::{ExtensionBody, ExtensionDescriptor, ExtensionTag};
324
325 #[test]
326 fn parse_sh_tdm_no_interleaver() {
327 let sel = [0xD0, 0x00, 0x9E, 0xAA];
334 let bytes = wrap(0x05, &sel);
335 let d = ExtensionDescriptor::parse(&bytes).unwrap();
336 assert_eq!(d.kind(), Some(ExtensionTag::ShDeliverySystem));
337 match &d.body {
338 ExtensionBody::ShDeliverySystem(b) => {
339 assert_eq!(b.diversity_mode, 0x0D);
340 assert_eq!(b.modulations.len(), 1);
341 let m = &b.modulations[0];
342 assert!(m.interleaver.is_none());
343 match &m.modulation {
344 ShModulationMode::Tdm {
345 polarization,
346 roll_off,
347 modulation_mode,
348 code_rate,
349 symbol_rate,
350 } => {
351 assert_eq!(*polarization, 2);
352 assert_eq!(*roll_off, 1);
353 assert_eq!(*modulation_mode, 3);
354 assert_eq!(*code_rate, 10);
355 assert_eq!(*symbol_rate, 21);
356 }
357 other => panic!("expected Tdm, got {other:?}"),
358 }
359 }
360 other => panic!("expected ShDeliverySystem, got {other:?}"),
361 }
362 round_trip(&d);
363 }
364
365 #[test]
366 fn parse_sh_ofdm_interleaver_type1() {
367 let sel = [0x50, 0xE0, 0x35, 0x7D, 0x54];
375 let bytes = wrap(0x05, &sel);
376 let d = ExtensionDescriptor::parse(&bytes).unwrap();
377 match &d.body {
378 ExtensionBody::ShDeliverySystem(b) => {
379 assert_eq!(b.diversity_mode, 0x05);
380 assert_eq!(b.modulations.len(), 1);
381 let m = &b.modulations[0];
382 match &m.modulation {
383 ShModulationMode::Ofdm {
384 bandwidth,
385 priority,
386 constellation_and_hierarchy,
387 code_rate,
388 guard_interval,
389 transmission_mode,
390 common_frequency,
391 } => {
392 assert_eq!(*bandwidth, 1);
393 assert!(*priority);
394 assert_eq!(*constellation_and_hierarchy, 2);
395 assert_eq!(*code_rate, 11);
396 assert_eq!(*guard_interval, 3);
397 assert_eq!(*transmission_mode, 2);
398 assert!(*common_frequency);
399 }
400 other => panic!("expected Ofdm, got {other:?}"),
401 }
402 match &m.interleaver {
403 Some(ShInterleaver::Type1 { common_multiplier }) => {
404 assert_eq!(*common_multiplier, 21);
405 }
406 other => panic!("expected Type1 interleaver, got {other:?}"),
407 }
408 }
409 other => panic!("expected ShDeliverySystem, got {other:?}"),
410 }
411 round_trip(&d);
412 }
413
414 #[test]
415 fn parse_sh_tdm_interleaver_type0() {
416 let sel = [0x80, 0x40, 0x35, 0x54, 0x29, 0x47, 0x99, 0x28];
427 let bytes = wrap(0x05, &sel);
428 let d = ExtensionDescriptor::parse(&bytes).unwrap();
429 match &d.body {
430 ExtensionBody::ShDeliverySystem(b) => {
431 assert_eq!(b.diversity_mode, 0x08);
432 assert_eq!(b.modulations.len(), 1);
433 let m = &b.modulations[0];
434 match &m.modulation {
435 ShModulationMode::Tdm {
436 polarization,
437 roll_off,
438 modulation_mode,
439 code_rate,
440 symbol_rate,
441 } => {
442 assert_eq!(*polarization, 0);
443 assert_eq!(*roll_off, 3);
444 assert_eq!(*modulation_mode, 1);
445 assert_eq!(*code_rate, 5);
446 assert_eq!(*symbol_rate, 10);
447 }
448 other => panic!("expected Tdm, got {other:?}"),
449 }
450 match &m.interleaver {
451 Some(ShInterleaver::Type0 {
452 common_multiplier,
453 nof_late_taps,
454 nof_slices,
455 slice_distance,
456 non_late_increments,
457 }) => {
458 assert_eq!(*common_multiplier, 10);
459 assert_eq!(*nof_late_taps, 20);
460 assert_eq!(*nof_slices, 30);
461 assert_eq!(*slice_distance, 100);
462 assert_eq!(*non_late_increments, 40);
463 }
464 other => panic!("expected Type0 interleaver, got {other:?}"),
465 }
466 }
467 other => panic!("expected ShDeliverySystem, got {other:?}"),
468 }
469 round_trip(&d);
470 }
471
472 #[test]
473 fn parse_sh_two_entries_mixed() {
474 let sel = [
487 0xD0, 0x00, 0x9E, 0xAA, 0xC0, 0x8B, 0x2A, 0x3D, 0x98, 0xCC, 0xB7,
488 ];
489 let bytes = wrap(0x05, &sel);
490 let d = ExtensionDescriptor::parse(&bytes).unwrap();
491 match &d.body {
492 ExtensionBody::ShDeliverySystem(b) => {
493 assert_eq!(b.diversity_mode, 0x0D);
494 assert_eq!(b.modulations.len(), 2);
495 let m0 = &b.modulations[0];
497 assert!(matches!(m0.modulation, ShModulationMode::Tdm { .. }));
498 assert!(m0.interleaver.is_none());
499 let m1 = &b.modulations[1];
501 assert!(matches!(m1.modulation, ShModulationMode::Ofdm { .. }));
502 match &m1.modulation {
503 ShModulationMode::Ofdm {
504 bandwidth,
505 priority,
506 constellation_and_hierarchy,
507 code_rate,
508 ..
509 } => {
510 assert_eq!(*bandwidth, 4);
511 assert!(!priority);
512 assert_eq!(*constellation_and_hierarchy, 5);
513 assert_eq!(*code_rate, 9);
514 }
515 _ => unreachable!(),
516 }
517 assert!(matches!(m1.interleaver, Some(ShInterleaver::Type0 { .. })));
518 }
519 other => panic!("expected ShDeliverySystem, got {other:?}"),
520 }
521 round_trip(&d);
522 }
523
524 #[test]
525 fn parse_sh_rejects_partial_entry() {
526 let sel = [0xD0, 0x00, 0x9E, 0xAA, 0x00];
528 let bytes = wrap(0x05, &sel);
529 assert!(matches!(
530 ExtensionDescriptor::parse(&bytes).unwrap_err(),
531 crate::error::Error::BufferTooShort { .. }
532 ));
533 }
534
535 #[test]
536 fn parse_sh_single_diversity_byte() {
537 let sel = [0xD0];
539 let bytes = wrap(0x05, &sel);
540 let d = ExtensionDescriptor::parse(&bytes).unwrap();
541 match &d.body {
542 ExtensionBody::ShDeliverySystem(b) => {
543 assert_eq!(b.diversity_mode, 0x0D);
544 assert!(b.modulations.is_empty());
545 }
546 other => panic!("expected ShDeliverySystem, got {other:?}"),
547 }
548 round_trip(&d);
549 }
550
551 #[test]
552 fn parse_sh_rejects_empty_selector() {
553 let bytes = wrap(0x05, &[]);
554 assert!(matches!(
555 ExtensionDescriptor::parse(&bytes).unwrap_err(),
556 crate::error::Error::BufferTooShort { .. }
557 ));
558 }
559
560 #[cfg(feature = "serde")]
561 #[test]
562 fn serde_serialize_sh_delivery_system() {
563 let d = ExtensionDescriptor {
564 tag_extension: 0x05,
565 body: ExtensionBody::ShDeliverySystem(ShDeliverySystem {
566 diversity_mode: 0x0D,
567 modulations: vec![ShModulation {
568 modulation: ShModulationMode::Ofdm {
569 bandwidth: 1,
570 priority: true,
571 constellation_and_hierarchy: 2,
572 code_rate: 11,
573 guard_interval: 3,
574 transmission_mode: 2,
575 common_frequency: true,
576 },
577 interleaver: Some(ShInterleaver::Type1 {
578 common_multiplier: 21,
579 }),
580 }],
581 }),
582 };
583 let json = serde_json::to_string(&d).unwrap();
584 assert!(json.contains("\"tag_extension\":5"));
585 assert!(json.contains("\"shDeliverySystem\""));
586 }
587}