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[1] != SEGMENT_TYPE {
56 return Err(Error::UnknownSegmentType(bytes[1]));
57 }
58 let page_id = u16::from_be_bytes([bytes[2], bytes[3]]);
59 let segment_length = u16::from_be_bytes([bytes[4], bytes[5]]) as usize;
60 let total = HEADER_LEN + segment_length;
61 if bytes.len() < total {
62 return Err(Error::BufferTooShort {
63 need: total,
64 have: bytes.len(),
65 what: "display_definition_segment data",
66 });
67 }
68 let body = &bytes[HEADER_LEN..HEADER_LEN + segment_length];
69 if body.len() < FIXED_BODY_LEN {
70 return Err(Error::BufferTooShort {
71 need: FIXED_BODY_LEN,
72 have: body.len(),
73 what: "display_definition_segment body",
74 });
75 }
76 let b0 = body[0];
77 let dds_version_number = b0 >> 4;
78 let display_window_flag = (b0 & 0x08) != 0;
79 let reserved = b0 & 0x07;
80 let display_width = u16::from_be_bytes([body[1], body[2]]);
81 let display_height = u16::from_be_bytes([body[3], body[4]]);
82
83 if display_window_flag {
84 if body.len() < FIXED_BODY_LEN + WINDOW_LEN {
85 return Err(Error::BufferTooShort {
86 need: FIXED_BODY_LEN + WINDOW_LEN,
87 have: body.len(),
88 what: "display_definition_segment window",
89 });
90 }
91 let dw = &body[FIXED_BODY_LEN..FIXED_BODY_LEN + WINDOW_LEN];
92 Ok(DisplayDefinitionSegment {
93 page_id,
94 dds_version_number,
95 display_window_flag,
96 reserved,
97 display_width,
98 display_height,
99 display_window_horizontal_position_minimum: Some(u16::from_be_bytes([
100 dw[0], dw[1],
101 ])),
102 display_window_horizontal_position_maximum: Some(u16::from_be_bytes([
103 dw[2], dw[3],
104 ])),
105 display_window_vertical_position_minimum: Some(u16::from_be_bytes([dw[4], dw[5]])),
106 display_window_vertical_position_maximum: Some(u16::from_be_bytes([dw[6], dw[7]])),
107 })
108 } else {
109 Ok(DisplayDefinitionSegment {
110 page_id,
111 dds_version_number,
112 display_window_flag,
113 reserved,
114 display_width,
115 display_height,
116 display_window_horizontal_position_minimum: None,
117 display_window_horizontal_position_maximum: None,
118 display_window_vertical_position_minimum: None,
119 display_window_vertical_position_maximum: None,
120 })
121 }
122 }
123}
124
125impl Serialize for DisplayDefinitionSegment {
126 type Error = Error;
127
128 fn serialized_len(&self) -> usize {
129 HEADER_LEN
130 + FIXED_BODY_LEN
131 + if self.display_window_flag {
132 WINDOW_LEN
133 } else {
134 0
135 }
136 }
137
138 fn serialize_into(&self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> {
139 let len = self.serialized_len();
140 if buf.len() < len {
141 return Err(Error::BufferTooShort {
142 need: len,
143 have: buf.len(),
144 what: "display_definition_segment serialize",
145 });
146 }
147 buf[0] = 0x0F; buf[1] = SEGMENT_TYPE;
150 buf[2..4].copy_from_slice(&self.page_id.to_be_bytes());
151 let seg_len = (len - HEADER_LEN) as u16;
152 buf[4..6].copy_from_slice(&seg_len.to_be_bytes());
153
154 buf[6] = (self.dds_version_number << 4)
156 | (u8::from(self.display_window_flag) << 3)
157 | (self.reserved & 0x07);
158 buf[7..9].copy_from_slice(&self.display_width.to_be_bytes());
160 buf[9..11].copy_from_slice(&self.display_height.to_be_bytes());
161
162 if self.display_window_flag {
164 let wmin = self.display_window_horizontal_position_minimum.unwrap_or(0);
165 let wmax = self.display_window_horizontal_position_maximum.unwrap_or(0);
166 let vmin = self.display_window_vertical_position_minimum.unwrap_or(0);
167 let vmax = self.display_window_vertical_position_maximum.unwrap_or(0);
168 buf[11..13].copy_from_slice(&wmin.to_be_bytes());
169 buf[13..15].copy_from_slice(&wmax.to_be_bytes());
170 buf[15..17].copy_from_slice(&vmin.to_be_bytes());
171 buf[17..19].copy_from_slice(&vmax.to_be_bytes());
172 }
173 Ok(len)
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180 use broadcast_common::{Parse, Serialize};
181
182 #[test]
183 fn round_trip_no_window() {
184 let bytes = [
185 0x0F, 0x14, 0x00, 0x01, 0x00, 0x05, 0x30, 0x02, 0xCF, 0x01, 0x1F,
186 ];
187 let seg = DisplayDefinitionSegment::parse(&bytes).unwrap();
188 assert_eq!(seg.dds_version_number, 3);
189 assert!(!seg.display_window_flag);
190 assert_eq!(seg.display_width, 719);
191 assert_eq!(seg.display_height, 287);
192 let out = seg.to_bytes();
193 assert_eq!(out, bytes);
194
195 let mut seg2 = seg.clone();
197 seg2.display_width = 100;
198 let out2 = seg2.to_bytes();
199 assert_ne!(out2, bytes);
200 let reparse = DisplayDefinitionSegment::parse(&out2).unwrap();
201 assert_eq!(reparse.display_width, 100);
202 }
203
204 #[test]
205 fn round_trip_with_window() {
206 let bytes = [
207 0x0F, 0x14, 0x00, 0x01, 0x00, 0x0D, 0x48, 0x02, 0xCF, 0x01, 0x1F, 0x00, 0x32, 0x02,
208 0x9E, 0x00, 0x14, 0x01, 0x0C,
209 ];
210 let seg = DisplayDefinitionSegment::parse(&bytes).unwrap();
211 assert_eq!(seg.dds_version_number, 4);
212 assert!(seg.display_window_flag);
213 assert_eq!(seg.display_window_horizontal_position_minimum, Some(50));
214 assert_eq!(seg.display_window_horizontal_position_maximum, Some(670));
215 let out = seg.to_bytes();
216 assert_eq!(out, bytes);
217
218 let mut seg2 = seg.clone();
220 seg2.display_window_flag = false;
221 let out2 = seg2.to_bytes();
222 assert_ne!(out2.len(), out.len());
223 let reparse = DisplayDefinitionSegment::parse(&out2).unwrap();
224 assert!(!reparse.display_window_flag);
225 }
226}