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