1use crate::error::{Error, Result};
6use broadcast_common::len::{need_in, need_out};
7use broadcast_common::{Parse, Serialize};
8
9pub const SEGMENT_TYPE: u8 = 0x14;
11pub const HEADER_LEN: usize = 6;
13pub const FIXED_BODY_LEN: usize = 5;
15pub const WINDOW_LEN: usize = 8;
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize))]
21pub struct DisplayDefinitionSegment {
22 pub page_id: u16,
24 pub dds_version_number: u8,
26 pub display_window_flag: bool,
28 pub reserved: u8,
30 pub display_width: u16,
32 pub display_height: u16,
34 pub display_window_horizontal_position_minimum: Option<u16>,
36 pub display_window_horizontal_position_maximum: Option<u16>,
38 pub display_window_vertical_position_minimum: Option<u16>,
40 pub display_window_vertical_position_maximum: Option<u16>,
42}
43
44impl<'a> Parse<'a> for DisplayDefinitionSegment {
45 type Error = Error;
46
47 fn parse(bytes: &'a [u8]) -> Result<Self> {
48 let min = HEADER_LEN + FIXED_BODY_LEN;
49 need_in(bytes, min, "display_definition_segment")?;
50 if bytes[0] != crate::pes_data_field::SYNC_BYTE {
51 return Err(Error::InvalidSync(broadcast_common::error::InvalidSync {
52 what: "sync_byte",
53 expected: u32::from(crate::pes_data_field::SYNC_BYTE),
54 found: u32::from(bytes[0]),
55 }));
56 }
57 if bytes[1] != SEGMENT_TYPE {
58 return Err(Error::UnknownSegmentType(bytes[1]));
59 }
60 let page_id = u16::from_be_bytes([bytes[2], bytes[3]]);
61 let segment_length = u16::from_be_bytes([bytes[4], bytes[5]]) as usize;
62 let total = HEADER_LEN + segment_length;
63 need_in(bytes, total, "display_definition_segment data")?;
64 let body = &bytes[HEADER_LEN..HEADER_LEN + segment_length];
65 need_in(body, FIXED_BODY_LEN, "display_definition_segment body")?;
66 let b0 = body[0];
67 let dds_version_number = b0 >> 4;
68 let display_window_flag = (b0 & 0x08) != 0;
69 let reserved = b0 & 0x07;
70 let display_width = u16::from_be_bytes([body[1], body[2]]);
71 let display_height = u16::from_be_bytes([body[3], body[4]]);
72
73 if display_window_flag {
74 need_in(
75 body,
76 FIXED_BODY_LEN + WINDOW_LEN,
77 "display_definition_segment window",
78 )?;
79 let dw = &body[FIXED_BODY_LEN..FIXED_BODY_LEN + WINDOW_LEN];
80 Ok(DisplayDefinitionSegment {
81 page_id,
82 dds_version_number,
83 display_window_flag,
84 reserved,
85 display_width,
86 display_height,
87 display_window_horizontal_position_minimum: Some(u16::from_be_bytes([
88 dw[0], dw[1],
89 ])),
90 display_window_horizontal_position_maximum: Some(u16::from_be_bytes([
91 dw[2], dw[3],
92 ])),
93 display_window_vertical_position_minimum: Some(u16::from_be_bytes([dw[4], dw[5]])),
94 display_window_vertical_position_maximum: Some(u16::from_be_bytes([dw[6], dw[7]])),
95 })
96 } else {
97 Ok(DisplayDefinitionSegment {
98 page_id,
99 dds_version_number,
100 display_window_flag,
101 reserved,
102 display_width,
103 display_height,
104 display_window_horizontal_position_minimum: None,
105 display_window_horizontal_position_maximum: None,
106 display_window_vertical_position_minimum: None,
107 display_window_vertical_position_maximum: None,
108 })
109 }
110 }
111}
112
113impl Serialize for DisplayDefinitionSegment {
114 type Error = Error;
115
116 fn serialized_len(&self) -> usize {
117 HEADER_LEN
118 + FIXED_BODY_LEN
119 + if self.display_window_flag {
120 WINDOW_LEN
121 } else {
122 0
123 }
124 }
125
126 fn serialize_into(&self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> {
127 let len = self.serialized_len();
128 need_out(buf, len)?;
129 buf[0] = 0x0F; buf[1] = SEGMENT_TYPE;
132 buf[2..4].copy_from_slice(&self.page_id.to_be_bytes());
133 let seg_len = crate::segments::check_segment_length(len - HEADER_LEN)?;
134 buf[4..6].copy_from_slice(&seg_len.to_be_bytes());
135
136 buf[6] =
138 (broadcast_common::len::fit_mask(self.dds_version_number, 0x0F, "dds_version_number")?
139 << 4)
140 | (u8::from(self.display_window_flag) << 3)
141 | broadcast_common::len::fit_mask(self.reserved, 0x07, "reserved")?;
142 buf[7..9].copy_from_slice(&self.display_width.to_be_bytes());
144 buf[9..11].copy_from_slice(&self.display_height.to_be_bytes());
145
146 if self.display_window_flag {
148 let wmin = self.display_window_horizontal_position_minimum.unwrap_or(0);
149 let wmax = self.display_window_horizontal_position_maximum.unwrap_or(0);
150 let vmin = self.display_window_vertical_position_minimum.unwrap_or(0);
151 let vmax = self.display_window_vertical_position_maximum.unwrap_or(0);
152 buf[11..13].copy_from_slice(&wmin.to_be_bytes());
153 buf[13..15].copy_from_slice(&wmax.to_be_bytes());
154 buf[15..17].copy_from_slice(&vmin.to_be_bytes());
155 buf[17..19].copy_from_slice(&vmax.to_be_bytes());
156 }
157 Ok(len)
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164 use broadcast_common::{Parse, Serialize};
165
166 #[test]
167 fn round_trip_no_window() {
168 let bytes = [
169 0x0F, 0x14, 0x00, 0x01, 0x00, 0x05, 0x30, 0x02, 0xCF, 0x01, 0x1F,
170 ];
171 let seg = DisplayDefinitionSegment::parse(&bytes).unwrap();
172 assert_eq!(seg.dds_version_number, 3);
173 assert!(!seg.display_window_flag);
174 assert_eq!(seg.display_width, 719);
175 assert_eq!(seg.display_height, 287);
176 let out = seg.try_to_bytes().unwrap();
177 assert_eq!(out, bytes);
178
179 let mut seg2 = seg.clone();
181 seg2.display_width = 100;
182 let out2 = seg2.try_to_bytes().unwrap();
183 assert_ne!(out2, bytes);
184 let reparse = DisplayDefinitionSegment::parse(&out2).unwrap();
185 assert_eq!(reparse.display_width, 100);
186 }
187
188 #[test]
190 fn rejects_bad_sync_byte() {
191 let bytes = [
192 0x00, 0x14, 0x00, 0x01, 0x00, 0x05, 0x30, 0x02, 0xCF, 0x01, 0x1F,
193 ];
194 assert!(matches!(
195 DisplayDefinitionSegment::parse(&bytes),
196 Err(Error::InvalidSync(broadcast_common::error::InvalidSync {
197 found: 0x00,
198 ..
199 }))
200 ));
201 }
202
203 #[test]
204 fn round_trip_with_window() {
205 let bytes = [
206 0x0F, 0x14, 0x00, 0x01, 0x00, 0x0D, 0x48, 0x02, 0xCF, 0x01, 0x1F, 0x00, 0x32, 0x02,
207 0x9E, 0x00, 0x14, 0x01, 0x0C,
208 ];
209 let seg = DisplayDefinitionSegment::parse(&bytes).unwrap();
210 assert_eq!(seg.dds_version_number, 4);
211 assert!(seg.display_window_flag);
212 assert_eq!(seg.display_window_horizontal_position_minimum, Some(50));
213 assert_eq!(seg.display_window_horizontal_position_maximum, Some(670));
214 let out = seg.try_to_bytes().unwrap();
215 assert_eq!(out, bytes);
216
217 let mut seg2 = seg.clone();
219 seg2.display_window_flag = false;
220 let out2 = seg2.try_to_bytes().unwrap();
221 assert_ne!(out2.len(), out.len());
222 let reparse = DisplayDefinitionSegment::parse(&out2).unwrap();
223 assert!(!reparse.display_window_flag);
224 }
225}