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] =
159 (broadcast_common::len::fit_mask(self.dds_version_number, 0x0F, "dds_version_number")?
160 << 4)
161 | (u8::from(self.display_window_flag) << 3)
162 | broadcast_common::len::fit_mask(self.reserved, 0x07, "reserved")?;
163 buf[7..9].copy_from_slice(&self.display_width.to_be_bytes());
165 buf[9..11].copy_from_slice(&self.display_height.to_be_bytes());
166
167 if self.display_window_flag {
169 let wmin = self.display_window_horizontal_position_minimum.unwrap_or(0);
170 let wmax = self.display_window_horizontal_position_maximum.unwrap_or(0);
171 let vmin = self.display_window_vertical_position_minimum.unwrap_or(0);
172 let vmax = self.display_window_vertical_position_maximum.unwrap_or(0);
173 buf[11..13].copy_from_slice(&wmin.to_be_bytes());
174 buf[13..15].copy_from_slice(&wmax.to_be_bytes());
175 buf[15..17].copy_from_slice(&vmin.to_be_bytes());
176 buf[17..19].copy_from_slice(&vmax.to_be_bytes());
177 }
178 Ok(len)
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185 use broadcast_common::{Parse, Serialize};
186
187 #[test]
188 fn round_trip_no_window() {
189 let bytes = [
190 0x0F, 0x14, 0x00, 0x01, 0x00, 0x05, 0x30, 0x02, 0xCF, 0x01, 0x1F,
191 ];
192 let seg = DisplayDefinitionSegment::parse(&bytes).unwrap();
193 assert_eq!(seg.dds_version_number, 3);
194 assert!(!seg.display_window_flag);
195 assert_eq!(seg.display_width, 719);
196 assert_eq!(seg.display_height, 287);
197 let out = seg.try_to_bytes().unwrap();
198 assert_eq!(out, bytes);
199
200 let mut seg2 = seg.clone();
202 seg2.display_width = 100;
203 let out2 = seg2.try_to_bytes().unwrap();
204 assert_ne!(out2, bytes);
205 let reparse = DisplayDefinitionSegment::parse(&out2).unwrap();
206 assert_eq!(reparse.display_width, 100);
207 }
208
209 #[test]
211 fn rejects_bad_sync_byte() {
212 let bytes = [
213 0x00, 0x14, 0x00, 0x01, 0x00, 0x05, 0x30, 0x02, 0xCF, 0x01, 0x1F,
214 ];
215 assert!(matches!(
216 DisplayDefinitionSegment::parse(&bytes),
217 Err(Error::BadSyncByte(0x00))
218 ));
219 }
220
221 #[test]
222 fn round_trip_with_window() {
223 let bytes = [
224 0x0F, 0x14, 0x00, 0x01, 0x00, 0x0D, 0x48, 0x02, 0xCF, 0x01, 0x1F, 0x00, 0x32, 0x02,
225 0x9E, 0x00, 0x14, 0x01, 0x0C,
226 ];
227 let seg = DisplayDefinitionSegment::parse(&bytes).unwrap();
228 assert_eq!(seg.dds_version_number, 4);
229 assert!(seg.display_window_flag);
230 assert_eq!(seg.display_window_horizontal_position_minimum, Some(50));
231 assert_eq!(seg.display_window_horizontal_position_maximum, Some(670));
232 let out = seg.try_to_bytes().unwrap();
233 assert_eq!(out, bytes);
234
235 let mut seg2 = seg.clone();
237 seg2.display_window_flag = false;
238 let out2 = seg2.try_to_bytes().unwrap();
239 assert_ne!(out2.len(), out.len());
240 let reparse = DisplayDefinitionSegment::parse(&out2).unwrap();
241 assert!(!reparse.display_window_flag);
242 }
243}