1use super::descriptor_body;
22use crate::error::{Error, Result};
23use dvb_common::{Parse, Serialize};
24
25pub const TAG: u8 = 0x6D;
27pub const HEADER_LEN: usize = 2;
29pub const OUTER_FIXED_LEN: usize = 7;
31pub const SUBCELL_LEN: usize = 5;
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize))]
37pub struct CellFrequencyLinkSubcell {
38 pub cell_id_extension: u8,
40 pub transposer_frequency: u32,
42}
43
44#[derive(Debug, Clone, PartialEq, Eq)]
46#[cfg_attr(feature = "serde", derive(serde::Serialize))]
47pub struct CellFrequencyLinkEntry {
48 pub cell_id: u16,
50 pub frequency: u32,
52 pub subcells: Vec<CellFrequencyLinkSubcell>,
54}
55
56#[derive(Debug, Clone, PartialEq, Eq)]
58#[cfg_attr(feature = "serde", derive(serde::Serialize))]
59pub struct CellFrequencyLinkDescriptor {
60 pub entries: Vec<CellFrequencyLinkEntry>,
62}
63
64impl<'a> Parse<'a> for CellFrequencyLinkDescriptor {
65 type Error = crate::error::Error;
66 fn parse(bytes: &'a [u8]) -> Result<Self> {
67 let body = descriptor_body(
68 bytes,
69 TAG,
70 "CellFrequencyLinkDescriptor",
71 "unexpected tag for cell_frequency_link_descriptor",
72 )?;
73 let mut entries = Vec::new();
74 let mut pos = 0;
75 while pos < body.len() {
76 if pos + OUTER_FIXED_LEN > body.len() {
77 return Err(Error::InvalidDescriptor {
78 tag: TAG,
79 reason: "cell_frequency_link outer entry truncated",
80 });
81 }
82 let cell_id = u16::from_be_bytes([body[pos], body[pos + 1]]);
83 let frequency =
84 u32::from_be_bytes([body[pos + 2], body[pos + 3], body[pos + 4], body[pos + 5]]);
85 let subcell_info_loop_length = body[pos + 6] as usize;
86 pos += OUTER_FIXED_LEN;
87 if subcell_info_loop_length % SUBCELL_LEN != 0 {
88 return Err(Error::InvalidDescriptor {
89 tag: TAG,
90 reason: "subcell_info_loop_length must be a multiple of 5",
91 });
92 }
93 if pos + subcell_info_loop_length > body.len() {
94 return Err(Error::InvalidDescriptor {
95 tag: TAG,
96 reason: "subcell_info_loop_length exceeds descriptor body",
97 });
98 }
99 let subcell_count = subcell_info_loop_length / SUBCELL_LEN;
100 let mut subcells = Vec::with_capacity(subcell_count);
101 for _ in 0..subcell_count {
102 let cell_id_extension = body[pos];
103 let transposer_frequency = u32::from_be_bytes([
104 body[pos + 1],
105 body[pos + 2],
106 body[pos + 3],
107 body[pos + 4],
108 ]);
109 subcells.push(CellFrequencyLinkSubcell {
110 cell_id_extension,
111 transposer_frequency,
112 });
113 pos += SUBCELL_LEN;
114 }
115 entries.push(CellFrequencyLinkEntry {
116 cell_id,
117 frequency,
118 subcells,
119 });
120 }
121 Ok(Self { entries })
122 }
123}
124
125impl CellFrequencyLinkDescriptor {
126 fn body_len(&self) -> usize {
127 self.entries
128 .iter()
129 .map(|e| OUTER_FIXED_LEN + e.subcells.len() * SUBCELL_LEN)
130 .sum()
131 }
132}
133
134impl Serialize for CellFrequencyLinkDescriptor {
135 type Error = crate::error::Error;
136 fn serialized_len(&self) -> usize {
137 HEADER_LEN + self.body_len()
138 }
139
140 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
141 let body_len = self.body_len();
142 if body_len > u8::MAX as usize {
143 return Err(Error::InvalidDescriptor {
144 tag: TAG,
145 reason: "cell_frequency_link_descriptor body exceeds 255 bytes",
146 });
147 }
148 for e in &self.entries {
149 if e.subcells.len() * SUBCELL_LEN > u8::MAX as usize {
150 return Err(Error::InvalidDescriptor {
151 tag: TAG,
152 reason: "subcell_info_loop_length exceeds 255 bytes",
153 });
154 }
155 }
156 let len = self.serialized_len();
157 if buf.len() < len {
158 return Err(Error::OutputBufferTooSmall {
159 need: len,
160 have: buf.len(),
161 });
162 }
163 buf[0] = TAG;
164 buf[1] = body_len as u8;
165 let mut pos = HEADER_LEN;
166 for e in &self.entries {
167 buf[pos..pos + 2].copy_from_slice(&e.cell_id.to_be_bytes());
168 buf[pos + 2..pos + 6].copy_from_slice(&e.frequency.to_be_bytes());
169 buf[pos + 6] = (e.subcells.len() * SUBCELL_LEN) as u8;
170 pos += OUTER_FIXED_LEN;
171 for sc in &e.subcells {
172 buf[pos] = sc.cell_id_extension;
173 buf[pos + 1..pos + 5].copy_from_slice(&sc.transposer_frequency.to_be_bytes());
174 pos += SUBCELL_LEN;
175 }
176 }
177 Ok(len)
178 }
179}
180impl<'a> crate::traits::DescriptorDef<'a> for CellFrequencyLinkDescriptor {
181 const TAG: u8 = TAG;
182 const NAME: &'static str = "CELL_FREQUENCY_LINK";
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn parse_entry_with_subcells() {
191 let bytes = [
192 TAG, 17, 0x12, 0x34, 0x00, 0x11, 0x22, 0x33, 10, 0x01, 0x0A, 0xAB, 0xBC, 0xCD, 0x02, 0x0D, 0xDE, 0xEF, 0xF0,
197 ];
198 let d = CellFrequencyLinkDescriptor::parse(&bytes).unwrap();
199 assert_eq!(d.entries.len(), 1);
200 assert_eq!(d.entries[0].cell_id, 0x1234);
201 assert_eq!(d.entries[0].frequency, 0x0011_2233);
202 assert_eq!(d.entries[0].subcells.len(), 2);
203 assert_eq!(d.entries[0].subcells[0].cell_id_extension, 0x01);
204 assert_eq!(d.entries[0].subcells[0].transposer_frequency, 0x0AAB_BCCD);
205 assert_eq!(d.entries[0].subcells[1].cell_id_extension, 0x02);
206 }
207
208 #[test]
209 fn parse_entry_no_subcells() {
210 let bytes = [TAG, 7, 0x00, 0x05, 0x00, 0x00, 0x10, 0x00, 0x00];
211 let d = CellFrequencyLinkDescriptor::parse(&bytes).unwrap();
212 assert_eq!(d.entries.len(), 1);
213 assert_eq!(d.entries[0].cell_id, 0x0005);
214 assert!(d.entries[0].subcells.is_empty());
215 }
216
217 #[test]
218 fn empty_body_is_valid() {
219 let d = CellFrequencyLinkDescriptor::parse(&[TAG, 0]).unwrap();
220 assert!(d.entries.is_empty());
221 }
222
223 #[test]
224 fn parse_rejects_wrong_tag() {
225 assert!(matches!(
226 CellFrequencyLinkDescriptor::parse(&[0x6E, 0]).unwrap_err(),
227 Error::InvalidDescriptor { tag: 0x6E, .. }
228 ));
229 }
230
231 #[test]
232 fn parse_rejects_truncated_outer() {
233 let bytes = [TAG, 5, 0x00, 0x01, 0x00, 0x00, 0x10];
235 assert!(matches!(
236 CellFrequencyLinkDescriptor::parse(&bytes).unwrap_err(),
237 Error::InvalidDescriptor { tag: TAG, .. }
238 ));
239 }
240
241 #[test]
242 fn parse_rejects_subcell_loop_overrun() {
243 let bytes = [TAG, 7, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 10];
245 assert!(matches!(
246 CellFrequencyLinkDescriptor::parse(&bytes).unwrap_err(),
247 Error::InvalidDescriptor { tag: TAG, .. }
248 ));
249 }
250
251 #[test]
252 fn parse_rejects_buffer_shorter_than_length() {
253 let bytes = [TAG, 7, 0x00, 0x01, 0x00];
254 assert!(matches!(
255 CellFrequencyLinkDescriptor::parse(&bytes).unwrap_err(),
256 Error::BufferTooShort { .. }
257 ));
258 }
259
260 #[test]
261 fn serialize_round_trip() {
262 let d = CellFrequencyLinkDescriptor {
263 entries: vec![
264 CellFrequencyLinkEntry {
265 cell_id: 0x1234,
266 frequency: 0x0011_2233,
267 subcells: vec![
268 CellFrequencyLinkSubcell {
269 cell_id_extension: 0x01,
270 transposer_frequency: 0x0AAB_BCCD,
271 },
272 CellFrequencyLinkSubcell {
273 cell_id_extension: 0x02,
274 transposer_frequency: 0x0DDE_EFF0,
275 },
276 ],
277 },
278 CellFrequencyLinkEntry {
279 cell_id: 0x9999,
280 frequency: 0x4455_6677,
281 subcells: vec![],
282 },
283 ],
284 };
285 let mut buf = vec![0u8; d.serialized_len()];
286 d.serialize_into(&mut buf).unwrap();
287 assert_eq!(CellFrequencyLinkDescriptor::parse(&buf).unwrap(), d);
288 }
289
290 #[test]
291 fn serialize_rejects_too_small_buffer() {
292 let d = CellFrequencyLinkDescriptor {
293 entries: vec![CellFrequencyLinkEntry {
294 cell_id: 0,
295 frequency: 0,
296 subcells: vec![],
297 }],
298 };
299 let mut buf = vec![0u8; 3];
300 assert!(matches!(
301 d.serialize_into(&mut buf).unwrap_err(),
302 Error::OutputBufferTooSmall { .. }
303 ));
304 }
305
306 #[test]
307 fn serialize_rejects_over_range_body() {
308 let d = CellFrequencyLinkDescriptor {
310 entries: (0..37)
311 .map(|_| CellFrequencyLinkEntry {
312 cell_id: 0,
313 frequency: 0,
314 subcells: vec![],
315 })
316 .collect(),
317 };
318 let mut buf = vec![0u8; d.serialized_len()];
319 assert!(matches!(
320 d.serialize_into(&mut buf).unwrap_err(),
321 Error::InvalidDescriptor { tag: TAG, .. }
322 ));
323 }
324
325 #[cfg(feature = "serde")]
326 #[test]
327 fn serde_round_trip() {
328 let d = CellFrequencyLinkDescriptor {
329 entries: vec![CellFrequencyLinkEntry {
330 cell_id: 0x1234,
331 frequency: 0x0011_2233,
332 subcells: vec![CellFrequencyLinkSubcell {
333 cell_id_extension: 0x01,
334 transposer_frequency: 0x0AAB_BCCD,
335 }],
336 }],
337 };
338 let json = serde_json::to_string(&d).unwrap();
339 let _v: serde_json::Value = serde_json::from_str(&json).unwrap();
341 }
342}