1use super::descriptor_body;
27use crate::error::{Error, Result};
28use dvb_common::{Parse, Serialize};
29
30pub const TAG: u8 = 0x79;
32const HEADER_LEN: usize = 2;
33const FLAGS_LEN: usize = 1;
34const SCRAMBLING_FIELD_LEN: usize = 3;
35const ISI_FIELD_LEN: usize = 1;
36const TIMESLICE_FIELD_LEN: usize = 1;
37
38const FLAG_SCRAMBLING_SELECTOR: u8 = 0x80;
39const FLAG_MULTIPLE_INPUT_STREAM: u8 = 0x40;
40const FLAG_NOT_TIMESLICE: u8 = 0x10;
41const TS_GS_MODE_MASK: u8 = 0x03;
44const FLAG_RESERVED_BITS: u8 = 0x0C;
48
49const SCRAMBLING_RESERVED_MASK: u8 = 0xFC;
50const SCRAMBLING_INDEX_HI_MASK: u8 = 0x03;
51const SCRAMBLING_INDEX_MAX: u32 = 0x3FFFF;
52
53#[derive(Debug, Clone, PartialEq, Eq)]
55#[cfg_attr(feature = "serde", derive(serde::Serialize))]
56pub struct S2SatelliteDeliverySystemDescriptor {
57 pub scrambling_sequence_selector: bool,
59 pub multiple_input_stream_flag: bool,
61 pub not_timeslice_flag: bool,
63 pub ts_gs_mode: u8,
65 pub scrambling_sequence_index: Option<u32>,
67 pub input_stream_identifier: Option<u8>,
69 pub timeslice_number: Option<u8>,
71}
72
73impl<'a> Parse<'a> for S2SatelliteDeliverySystemDescriptor {
74 type Error = crate::error::Error;
75 fn parse(bytes: &'a [u8]) -> Result<Self> {
76 if bytes.len() < HEADER_LEN + FLAGS_LEN {
77 return Err(Error::BufferTooShort {
78 need: HEADER_LEN + FLAGS_LEN,
79 have: bytes.len(),
80 what: "S2SatelliteDeliverySystemDescriptor header",
81 });
82 }
83 let body = descriptor_body(
84 bytes,
85 TAG,
86 "S2SatelliteDeliverySystemDescriptor",
87 "unexpected tag for s2_satellite_delivery_system_descriptor",
88 )?;
89 if body.len() < FLAGS_LEN {
90 return Err(Error::InvalidDescriptor {
91 tag: TAG,
92 reason: "body must contain at least the flags byte",
93 });
94 }
95
96 let flags = body[0];
98 let scrambling_sequence_selector = (flags & FLAG_SCRAMBLING_SELECTOR) != 0;
99 let multiple_input_stream_flag = (flags & FLAG_MULTIPLE_INPUT_STREAM) != 0;
100 let not_timeslice_flag = (flags & FLAG_NOT_TIMESLICE) != 0;
101 let ts_gs_mode = flags & TS_GS_MODE_MASK;
102
103 let mut pos = FLAGS_LEN;
104
105 let scrambling_sequence_index = if scrambling_sequence_selector {
106 if pos + SCRAMBLING_FIELD_LEN > body.len() {
107 return Err(Error::BufferTooShort {
108 need: pos + SCRAMBLING_FIELD_LEN,
109 have: body.len(),
110 what: "S2SatelliteDeliverySystemDescriptor scrambling_sequence_index",
111 });
112 }
113 let b0 = body[pos];
114 let index = (u32::from(b0 & SCRAMBLING_INDEX_HI_MASK) << 16)
115 | (u32::from(body[pos + 1]) << 8)
116 | u32::from(body[pos + 2]);
117 pos += SCRAMBLING_FIELD_LEN;
118 Some(index)
119 } else {
120 None
121 };
122
123 let input_stream_identifier = if multiple_input_stream_flag {
124 if pos + ISI_FIELD_LEN > body.len() {
125 return Err(Error::BufferTooShort {
126 need: pos + ISI_FIELD_LEN,
127 have: body.len(),
128 what: "S2SatelliteDeliverySystemDescriptor input_stream_identifier",
129 });
130 }
131 let isi = body[pos];
132 pos += ISI_FIELD_LEN;
133 Some(isi)
134 } else {
135 None
136 };
137
138 let timeslice_number = if !not_timeslice_flag {
140 if pos + TIMESLICE_FIELD_LEN > body.len() {
141 return Err(Error::BufferTooShort {
142 need: pos + TIMESLICE_FIELD_LEN,
143 have: body.len(),
144 what: "S2SatelliteDeliverySystemDescriptor timeslice_number",
145 });
146 }
147 Some(body[pos])
148 } else {
149 None
150 };
151
152 Ok(Self {
153 scrambling_sequence_selector,
154 multiple_input_stream_flag,
155 not_timeslice_flag,
156 ts_gs_mode,
157 scrambling_sequence_index,
158 input_stream_identifier,
159 timeslice_number,
160 })
161 }
162}
163
164impl Serialize for S2SatelliteDeliverySystemDescriptor {
165 type Error = crate::error::Error;
166 fn serialized_len(&self) -> usize {
167 HEADER_LEN
168 + FLAGS_LEN
169 + if self.scrambling_sequence_selector {
170 SCRAMBLING_FIELD_LEN
171 } else {
172 0
173 }
174 + if self.multiple_input_stream_flag {
175 ISI_FIELD_LEN
176 } else {
177 0
178 }
179 + if self.not_timeslice_flag {
180 0
181 } else {
182 TIMESLICE_FIELD_LEN
183 }
184 }
185
186 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
187 let len = self.serialized_len();
188 if buf.len() < len {
189 return Err(Error::OutputBufferTooSmall {
190 need: len,
191 have: buf.len(),
192 });
193 }
194 buf[0] = TAG;
195 buf[1] = (len - HEADER_LEN) as u8;
196
197 let mut flags = FLAG_RESERVED_BITS | (self.ts_gs_mode & TS_GS_MODE_MASK);
198 if self.scrambling_sequence_selector {
199 flags |= FLAG_SCRAMBLING_SELECTOR;
200 }
201 if self.multiple_input_stream_flag {
202 flags |= FLAG_MULTIPLE_INPUT_STREAM;
203 }
204 if self.not_timeslice_flag {
205 flags |= FLAG_NOT_TIMESLICE;
206 }
207 buf[HEADER_LEN] = flags;
208
209 let mut pos = HEADER_LEN + FLAGS_LEN;
210 if self.scrambling_sequence_selector {
211 let index = self.scrambling_sequence_index.unwrap_or(0) & SCRAMBLING_INDEX_MAX;
212 buf[pos] = SCRAMBLING_RESERVED_MASK | ((index >> 16) as u8 & SCRAMBLING_INDEX_HI_MASK);
213 buf[pos + 1] = (index >> 8) as u8;
214 buf[pos + 2] = index as u8;
215 pos += SCRAMBLING_FIELD_LEN;
216 }
217 if self.multiple_input_stream_flag {
218 buf[pos] = self.input_stream_identifier.unwrap_or(0);
219 pos += ISI_FIELD_LEN;
220 }
221 if !self.not_timeslice_flag {
222 buf[pos] = self.timeslice_number.unwrap_or(0);
223 }
224 Ok(len)
225 }
226}
227impl<'a> crate::traits::DescriptorDef<'a> for S2SatelliteDeliverySystemDescriptor {
228 const TAG: u8 = TAG;
229 const NAME: &'static str = "S2_SATELLITE_DELIVERY_SYSTEM";
230}
231
232#[cfg(test)]
233mod tests {
234 use super::*;
235
236 #[test]
239 fn parse_minimal_with_timeslice() {
240 let raw = [TAG, 2, 0x2C, 0x07];
241 let d = S2SatelliteDeliverySystemDescriptor::parse(&raw).unwrap();
242 assert!(!d.scrambling_sequence_selector);
243 assert!(!d.multiple_input_stream_flag);
244 assert!(!d.not_timeslice_flag);
245 assert_eq!(d.ts_gs_mode, 0);
246 assert_eq!(d.timeslice_number, Some(0x07));
247 assert_eq!(d.scrambling_sequence_index, None);
248 assert_eq!(d.input_stream_identifier, None);
249 }
250
251 #[test]
252 fn parse_not_timeslice_omits_timeslice_number() {
253 let raw = [TAG, 1, 0x3E];
255 let d = S2SatelliteDeliverySystemDescriptor::parse(&raw).unwrap();
256 assert!(d.not_timeslice_flag);
257 assert_eq!(d.ts_gs_mode, 2);
258 assert_eq!(d.timeslice_number, None);
259 }
260
261 #[test]
262 fn parse_extracts_isi_and_timeslice() {
263 let raw = [TAG, 3, 0x6C, 0x05, 0x09];
265 let d = S2SatelliteDeliverySystemDescriptor::parse(&raw).unwrap();
266 assert!(d.multiple_input_stream_flag);
267 assert_eq!(d.input_stream_identifier, Some(5));
268 assert_eq!(d.timeslice_number, Some(9));
269 }
270
271 #[test]
272 fn parse_extracts_scrambling_index() {
273 let raw = [TAG, 4, 0xBC, 0xFD, 0x23, 0x45];
275 let d = S2SatelliteDeliverySystemDescriptor::parse(&raw).unwrap();
276 assert!(d.scrambling_sequence_selector);
277 assert_eq!(d.scrambling_sequence_index, Some(0x12345));
278 assert!(d.not_timeslice_flag);
279 assert_eq!(d.timeslice_number, None);
280 }
281
282 #[test]
283 fn parse_full_18_bit_index() {
284 let raw = [TAG, 4, 0xBC, 0xFF, 0xFF, 0xFF];
285 let d = S2SatelliteDeliverySystemDescriptor::parse(&raw).unwrap();
286 assert_eq!(d.scrambling_sequence_index, Some(0x3FFFF));
287 }
288
289 #[test]
290 fn parse_rejects_wrong_tag() {
291 let raw = [0x44, 1, 0x3E];
292 assert!(matches!(
293 S2SatelliteDeliverySystemDescriptor::parse(&raw).unwrap_err(),
294 Error::InvalidDescriptor { tag: 0x44, .. }
295 ));
296 }
297
298 #[test]
299 fn parse_rejects_truncated_scrambling() {
300 let raw = [TAG, 1, 0x9C]; assert!(matches!(
302 S2SatelliteDeliverySystemDescriptor::parse(&raw).unwrap_err(),
303 Error::BufferTooShort { .. }
304 ));
305 }
306
307 #[test]
308 fn serialize_round_trip_all_fields() {
309 let d = S2SatelliteDeliverySystemDescriptor {
310 scrambling_sequence_selector: true,
311 multiple_input_stream_flag: true,
312 not_timeslice_flag: false,
313 ts_gs_mode: 2,
314 scrambling_sequence_index: Some(0x2BCDE),
315 input_stream_identifier: Some(0x42),
316 timeslice_number: Some(0x11),
317 };
318 let mut buf = vec![0u8; d.serialized_len()];
319 d.serialize_into(&mut buf).unwrap();
320 assert_eq!(S2SatelliteDeliverySystemDescriptor::parse(&buf).unwrap(), d);
321 }
322
323 #[test]
324 fn serialize_round_trip_not_timeslice() {
325 let d = S2SatelliteDeliverySystemDescriptor {
326 scrambling_sequence_selector: false,
327 multiple_input_stream_flag: false,
328 not_timeslice_flag: true,
329 ts_gs_mode: 1,
330 scrambling_sequence_index: None,
331 input_stream_identifier: None,
332 timeslice_number: None,
333 };
334 let mut buf = vec![0u8; d.serialized_len()];
335 d.serialize_into(&mut buf).unwrap();
336 assert_eq!(S2SatelliteDeliverySystemDescriptor::parse(&buf).unwrap(), d);
337 }
338}