1pub mod packet_type;
24pub use packet_type::*;
25
26pub mod pixel_config;
27pub use pixel_config::{DataType, PixelConfig, PixelFormat};
28
29pub mod id;
30pub use id::ID;
31
32#[cfg(feature = "std")]
33pub mod message;
34
35pub mod timecode;
36use timecode::TimeCode;
37
38mod frame;
39pub use frame::{FrameBuilder, MAX_DATA_LENGTH};
40
41#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Default)]
65pub struct Header {
66 pub packet_type: PacketType,
68
69 pub sequence_number: u8,
71
72 pub pixel_config: PixelConfig,
74
75 pub id: ID,
77
78 pub offset: u32,
80
81 pub length: u16,
83
84 pub time_code: TimeCode,
86}
87
88impl From<Header> for [u8; 10] {
89 fn from(header: Header) -> Self {
90 let mut buffer: [u8; 10] = [0u8; 10];
92
93 let packet_type_byte: u8 = header.packet_type.into();
96 buffer[0] = packet_type_byte;
97
98 buffer[1] = header.sequence_number;
100
101 buffer[2] = header.pixel_config.into();
103
104 buffer[3] = header.id.into();
106
107 let offset_bytes = header.offset.to_be_bytes();
109 buffer[4..8].copy_from_slice(&offset_bytes);
110
111 let length_bytes = header.length.to_be_bytes();
113 buffer[8..10].copy_from_slice(&length_bytes);
114
115 buffer
117 }
118}
119impl From<Header> for [u8; 14] {
120 fn from(header: Header) -> Self {
121 let mut buffer = [0u8; 14];
123
124 let packet_type_byte: u8 = header.packet_type.into();
127 buffer[0] = packet_type_byte;
128
129 buffer[1] = header.sequence_number;
131
132 buffer[2] = header.pixel_config.into();
134
135 buffer[3] = header.id.into();
137
138 let offset_bytes: [u8; 4] = header.offset.to_be_bytes();
140 buffer[4..8].copy_from_slice(&offset_bytes);
141
142 let length_bytes: [u8; 2] = header.length.to_be_bytes();
144 buffer[8..10].copy_from_slice(&length_bytes);
145
146 let time_code: [u8; 4] = header.time_code.to_bytes();
147 buffer[10..14].copy_from_slice(&time_code);
148
149 buffer
151 }
152}
153
154impl<'a> From<&'a [u8]> for Header {
155 fn from(bytes: &'a [u8]) -> Self {
156 let packet_type = PacketType::from(bytes[0]);
158
159 let sequence_number = bytes[1];
161
162 let pixel_config = PixelConfig::from(bytes[2]);
164
165 let id = ID::from(bytes[3]);
167
168 let offset = u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
170
171 let length = u16::from_be_bytes([bytes[8], bytes[9]]);
173
174 if packet_type.timecode && bytes.len() >= 14 {
175 let time_code = TimeCode::from_4_bytes([bytes[10], bytes[11], bytes[12], bytes[13]]);
176
177 Header {
178 packet_type,
179 sequence_number,
180 pixel_config,
181 id,
182 offset,
183 length,
184 time_code,
185 }
186 } else {
187 Header {
188 packet_type,
189 sequence_number,
190 pixel_config,
191 id,
192 offset,
193 length,
194 time_code: TimeCode(None),
195 }
196 }
197 }
198}
199
200impl Header {
201 pub fn write_into(&self, buf: &mut [u8]) -> usize {
223 if self.packet_type.timecode {
224 let bytes: [u8; 14] = (*self).into();
225 buf[..14].copy_from_slice(&bytes);
226 14
227 } else {
228 let bytes: [u8; 10] = (*self).into();
229 buf[..10].copy_from_slice(&bytes);
230 10
231 }
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238
239 #[test]
240 fn test_parsing() {
241 {
243 let data: [u8; 10] = [65, 6, 10, 1, 0, 0, 0, 0, 0, 3];
244 let header = Header::from(&data[..]);
245
246 assert_eq!(
247 header.packet_type,
248 PacketType {
249 version: 1,
250 timecode: false,
251 storage: false,
252 reply: false,
253 query: false,
254 push: true
255 }
256 );
257 assert_eq!(header.sequence_number, 6);
258 assert_eq!(header.length, 3);
259 assert_eq!(header.offset, 0);
260 }
261
262 {
264 let data: [u8; 10] = [255, 12, 13, 1, 0, 0, 0x99, 0xd5, 0x01, 0x19];
265 let header = Header::from(&data[..]);
266
267 assert_eq!(
268 header.packet_type,
269 PacketType {
270 version: 3,
271 timecode: true,
272 storage: true,
273 reply: true,
274 query: true,
275 push: true
276 }
277 );
278
279 assert_eq!(header.sequence_number, 12);
280 assert_eq!(
281 header.pixel_config,
282 PixelConfig {
283 data_type: pixel_config::DataType::RGB,
284 data_size: PixelFormat::Pixel24Bits,
285 customer_defined: false
286 }
287 );
288 assert_eq!(header.length, 281);
289 assert_eq!(header.offset, 39381);
290 }
291 }
292
293 use proptest::prelude::*;
295
296 proptest! {
297 #[test]
298 fn test_header_10_byte_roundtrip(
299 packet_type_byte in any::<u8>(),
300 seq_num in any::<u8>(),
301 pixel_config in any::<u8>(),
302 id in any::<u8>(),
303 offset in any::<u32>(),
304 length in any::<u16>(),
305 ) {
306 let mut bytes = vec![packet_type_byte, seq_num, pixel_config, id];
308 bytes.extend_from_slice(&offset.to_be_bytes());
309 bytes.extend_from_slice(&length.to_be_bytes());
310
311 let header = Header::from(&bytes[..]);
313
314 let roundtrip_bytes: [u8; 10] = header.into();
316
317 prop_assert_eq!(header.sequence_number, seq_num);
319 prop_assert_eq!(header.offset, offset);
320 prop_assert_eq!(header.length, length);
321
322 let roundtrip_header = Header::from(&roundtrip_bytes[..]);
324 prop_assert_eq!(header.sequence_number, roundtrip_header.sequence_number);
325 prop_assert_eq!(header.offset, roundtrip_header.offset);
326 prop_assert_eq!(header.length, roundtrip_header.length);
327 }
328
329 #[test]
330 fn test_header_14_byte_with_timecode_roundtrip(
331 seq_num in any::<u8>(),
332 pixel_config in any::<u8>(),
333 id in any::<u8>(),
334 offset in any::<u32>(),
335 length in any::<u16>(),
336 timecode in any::<u32>(),
337 ) {
338 let packet_type_byte = 0b01010000u8; let mut bytes = vec![packet_type_byte, seq_num, pixel_config, id];
341 bytes.extend_from_slice(&offset.to_be_bytes());
342 bytes.extend_from_slice(&length.to_be_bytes());
343 bytes.extend_from_slice(&timecode.to_be_bytes());
344
345 let header = Header::from(&bytes[..]);
347
348 prop_assert_eq!(header.time_code.0, Some(timecode));
350 prop_assert_eq!(header.sequence_number, seq_num);
351 prop_assert_eq!(header.offset, offset);
352 prop_assert_eq!(header.length, length);
353 prop_assert!(header.packet_type.timecode);
354
355 let roundtrip_bytes: [u8; 14] = header.into();
357
358 let roundtrip_header = Header::from(&roundtrip_bytes[..]);
360 prop_assert_eq!(header.time_code, roundtrip_header.time_code);
361 prop_assert_eq!(header.sequence_number, roundtrip_header.sequence_number);
362 }
363
364 #[test]
365 fn test_header_parsing_never_panics(
366 bytes in prop::collection::vec(any::<u8>(), 10..20)
367 ) {
368 let _ = Header::from(&bytes[..]);
370 }
371
372 #[test]
373 fn test_header_offset_range(
374 offset in 0u32..=0xFFFFFFFF,
375 ) {
376 let header = Header {
377 offset,
378 ..Default::default()
379 };
380
381 let bytes: [u8; 10] = header.into();
382 let parsed = Header::from(&bytes[..]);
383
384 prop_assert_eq!(parsed.offset, offset);
385 }
386
387 #[test]
388 fn test_header_length_range(
389 length in 0u16..=1500,
390 ) {
391 let header = Header {
392 length,
393 ..Default::default()
394 };
395
396 let bytes: [u8; 10] = header.into();
397 let parsed = Header::from(&bytes[..]);
398
399 prop_assert_eq!(parsed.length, length);
400 }
401 }
402}