1pub mod commands;
2mod error;
3use commands::Command;
4use error::EldritchError;
5use std::fmt::Debug;
6
7#[derive(Clone, Debug, PartialEq)]
8pub struct AddressedCommand {
9 pub device_id: u8,
10 pub command: Command,
11}
12
13#[derive(Clone, PartialEq, PartialOrd)]
14pub struct FixedPointDecimal {
15 raw_val: i16,
16}
17
18impl FixedPointDecimal {
19 pub fn get_real_val(&self) -> f32 {
20 f32::from(self.raw_val) / 2_f32.powi(11)
21 }
22
23 pub fn get_rounded_val(&self) -> f32 {
24 (self.get_real_val() * 100.0).round() / 100.0
25 }
26
27 pub fn from_data(data: &[u8; 2]) -> Self {
28 assert!(data.len() == 2);
29 Self {
30 raw_val: u16::from_le_bytes(*data) as i16,
31 }
32 }
33}
34
35impl Debug for FixedPointDecimal {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 write!(
38 f,
39 "FixedPointDecimal {{ raw_val: {}, real_val: {} }}",
40 self.raw_val,
41 self.get_real_val()
42 )
43 }
44}
45
46impl PartialEq<f32> for FixedPointDecimal {
47 fn eq(&self, other: &f32) -> bool {
48 &self.get_real_val() == other
49 }
50}
51
52impl PartialOrd<f32> for FixedPointDecimal {
53 fn partial_cmp(&self, other: &f32) -> Option<std::cmp::Ordering> {
54 let real_val = self.get_real_val();
55 if &real_val == other {
56 Some(std::cmp::Ordering::Equal)
57 } else if &real_val < other {
58 Some(std::cmp::Ordering::Less)
59 } else {
60 Some(std::cmp::Ordering::Greater)
61 }
62 }
63}
64
65#[derive(Clone, Debug, PartialEq)]
66pub enum Operation {
67 Assign,
68 Increment,
69 Toggle,
70}
71
72#[derive(Clone, Debug, PartialEq)]
73struct CommandHeader {
74 device_id: u8,
75 command_length: u8,
76 command_id: u8,
77}
78
79#[derive(Debug, PartialEq)]
80struct PacketData {
81 data: Vec<u8>,
82 cursor: u8,
83}
84
85impl PacketData {
86 pub fn new(packet_data: Vec<u8>) -> Result<Self, EldritchError> {
87 if packet_data.len() > 255 {
88 Err(EldritchError::PacketToLarge)
89 } else {
90 Ok(Self {
91 data: packet_data,
92 cursor: 0,
93 })
94 }
95 }
96
97 pub fn parse_header(&mut self) -> Result<CommandHeader, EldritchError> {
98 let device_id = self
99 .data
100 .get(self.cursor as usize)
101 .ok_or(EldritchError::InvalidHeader)?;
102 let command_length = self
103 .data
104 .get((self.cursor + 1) as usize)
105 .ok_or(EldritchError::InvalidHeader)?;
106 let command_id = self
107 .data
108 .get((self.cursor + 2) as usize)
109 .ok_or(EldritchError::InvalidHeader)?;
110
111 let header = if let Some(reserved) = self.data.get((self.cursor + 3) as usize) {
112 if *reserved == 0 {
113 Ok(CommandHeader {
114 device_id: *device_id,
115 command_length: *command_length,
116 command_id: *command_id,
117 })
118 } else {
119 Err(EldritchError::InvalidHeader)
120 }
121 } else {
122 Err(EldritchError::InvalidHeader)
123 };
124 self.cursor += 4;
125 header
126 }
127
128 fn has_data(&self) -> bool {
129 usize::from(self.cursor) < self.data.len()
130 }
131
132 fn get_slice(&mut self, slice_len: u8) -> Result<&[u8], EldritchError> {
133 let new_cur = self.cursor + slice_len;
134 if usize::from(new_cur) > self.data.len() {
135 return Err(EldritchError::EndOfPacket);
136 }
137 let slice_data = &self.data[usize::from(self.cursor)..usize::from(new_cur)];
138 self.cursor = new_cur;
139 Ok(slice_data)
140 }
141}
142
143pub fn parse_frame_packet(data: Vec<u8>) -> Result<Vec<AddressedCommand>, EldritchError> {
144 let mut packet = PacketData::new(data)?;
145 let mut commands: Vec<AddressedCommand> = Vec::new();
146
147 while packet.has_data() {
148 let header = packet.parse_header()?;
149 match packet.get_slice(header.command_length) {
151 Ok(command_data) => {
152 commands.push(AddressedCommand {
154 device_id: header.device_id,
155 command: commands::parse_command(command_data)?,
156 });
157 }
158 Err(EldritchError::EndOfPacket) => break,
159 Err(err) => Err(err)?,
160 };
161
162 match packet.get_slice(calculate_padding_length(header.command_length)) {
163 Ok(padding) => verify_padding(padding, header.command_length)?,
164 Err(EldritchError::EndOfPacket) => break,
165 Err(err) => Err(err)?,
166 };
167 }
168
169 Ok(commands)
170}
171
172fn calculate_padding_length(command_length: u8) -> u8 {
173 if command_length.is_multiple_of(4) {
174 0
175 } else {
176 4 - (command_length % 4)
177 }
178}
179
180fn verify_padding(padding: &[u8], command_length: u8) -> Result<(), EldritchError> {
181 if !(padding.len() + usize::from(command_length)).is_multiple_of(4) {
182 return Err(EldritchError::PaddingViolation(String::from(
183 "Padding length is incorrect",
184 )));
185 }
186
187 let mut padding_errors: Vec<Result<(), EldritchError>> = padding
188 .iter()
189 .enumerate()
190 .map(|(idx, byte)| {
191 if *byte != 0x00 {
192 Err(EldritchError::PaddingViolation(format!(
193 "Padding byte at index: {idx} is not 0x00",
194 )))
195 } else {
196 Ok(())
197 }
198 })
199 .filter(|check| check.is_err())
200 .collect();
201
202 if !padding_errors.is_empty() {
203 padding_errors.remove(0)
204 } else {
205 Ok(())
206 }
207}
208
209#[cfg(test)]
210mod fixed_point_test {
211 use super::*;
212
213 #[test]
214 fn fpd_fifteen_percent() {
215 let fifteen_percent = FixedPointDecimal { raw_val: 0x0133 };
216 let float_value = fifteen_percent.get_rounded_val();
217 assert_eq!(float_value, 0.15);
218 }
219
220 #[test]
221 fn fpd_minus_point_three() {
222 let minus_point_three = FixedPointDecimal {
223 raw_val: 0xfd9au16 as i16,
224 };
225 let float_value = minus_point_three.get_rounded_val();
226 assert_eq!(float_value, -0.3_f32);
227 }
228}
229
230#[cfg(test)]
231mod packet_data_test {
232 use crate::commands::{
233 color_correction_commands::{ColorCorrectionCommand, RedGreenBlueLuma},
234 display_commands::DisplayCommand,
235 lens_commands::LensCommand,
236 video_commands::{VideoCommand, VideoModeData},
237 };
238
239 use super::*;
240
241 #[test]
242 fn new() {
243 let packet_data = vec![
244 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x01, 0x9a, 0xfd, 0x00, 0x00, 0x00, ];
248
249 if let Ok(packet) = PacketData::new(packet_data) {
250 assert_eq!(packet.cursor, 0);
251 assert_eq!(packet.data.len(), 12);
252 } else {
253 panic!();
254 }
255 }
256
257 #[test]
258 fn parse_header() {
259 let packet_data = vec![
260 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x01, 0x9a, 0xfd, 0x00, 0x00, 0x00, ];
264
265 let mut packet =
266 PacketData::new(packet_data).expect("Failed to build PacketData with known good data");
267
268 if let Ok(header) = packet.parse_header() {
269 assert_eq!(
270 header,
271 CommandHeader {
272 device_id: 0,
273 command_length: 5,
274 command_id: 0
275 }
276 );
277 } else {
278 panic!();
279 }
280 }
281
282 #[test]
283 fn parse_header_bad_reserved_byte() {
284 let packet_data = vec![
285 0x00, 0x05, 0x00, 0xFF, 0x00, 0x80, 0x01, 0x9a, 0xfd, 0x00, 0x00, 0x00, ];
289
290 let mut packet = PacketData::new(packet_data).expect("Verified packet data");
291
292 if let Err(error) = packet.parse_header() {
293 assert_eq!(error, EldritchError::InvalidHeader);
294 assert_eq!(4, packet.cursor);
295 } else {
296 panic!();
297 }
298 }
299
300 #[test]
301 fn has_data_true() {
302 let packet_data = vec![
303 0x00, 0x05, 0x00, 0xFF, 0x00, 0x80, 0x01, 0x9a, 0xfd, 0x00, 0x00, 0x00, ];
307
308 let mut packet = PacketData::new(packet_data).expect("Verified packet data");
309 packet.cursor = 10;
310 println!("Packet: {:?}", packet);
311 assert!(packet.has_data());
312 }
313
314 #[test]
315 fn has_data_false() {
316 let packet_data = vec![
317 0x00, 0x05, 0x00, 0xFF, 0x00, 0x80, 0x01, 0x9a, 0xfd, 0x00, 0x00, 0x00, ];
321
322 let mut packet = PacketData::new(packet_data).expect("Verified packet data");
323 packet.cursor = 12;
324 println!("Packet: {:?}", packet);
325 assert!(!packet.has_data());
326 }
327
328 #[test]
329 fn get_slice() {
330 let packet_data = vec![
331 0x00, 0x05, 0x00, 0xFF, 0x00, 0x80, 0x01, 0x9a, 0xfd, 0x00, 0x00, 0x00, ];
335 let mut packet = PacketData::new(packet_data).expect("Verified packet data");
336 packet.cursor = 4;
337
338 if let Ok(cmd_data) = packet.get_slice(5) {
339 assert_eq!([0x00, 0x80, 0x01, 0x9a, 0xfd,] as [u8; 5], cmd_data);
340 assert_eq!(9, packet.cursor);
341 } else {
342 panic!();
343 }
344 if let Ok(padding) = packet.get_slice(calculate_padding_length(5)) {
345 assert_eq!([0x00, 0x00, 0x00] as [u8; 3], padding);
346 assert_eq!(12, packet.cursor);
347 } else {
348 panic!();
349 }
350 }
351
352 #[test]
353 fn get_slice_error() {
354 let packet_data = vec![
355 0x00, 0x05, 0x00, 0xFF, 0x00, 0x80, 0x01, 0x9a, 0xfd, 0x00, 0x00, 0x00, ];
359 let mut packet = PacketData::new(packet_data).expect("Verified packet data");
360 packet.cursor = 8;
361
362 if let Err(error) = packet.get_slice(5) {
363 assert_eq!(EldritchError::EndOfPacket, error);
364 } else {
365 panic!();
366 }
367 }
368
369 #[test]
370 fn parse_large_packet() {
371 let frame_packet = vec![
372 0x04, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xff, 0x05, 0x00, 0x00, 0x00, 0x06,
373 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x01, 0x05, 0x03, 0x00,
374 0x10, 0x27, 0x00, 0x00, 0x04, 0x06, 0x00, 0x00, 0x04, 0x02, 0x80, 0x01, 0x33, 0x01,
375 0x00, 0x00, 0xff, 0x09, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x18, 0x01, 0x03, 0x00,
376 0x00, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x00, 0x00, 0x08, 0x01, 0x80, 0x01, 0x00, 0x00,
377 0x9a, 0xfd, 0x9a, 0xfd, 0x00, 0x00,
378 ];
379 let commands = parse_frame_packet(frame_packet).expect("Test Frame should parse");
380 let mut commands = commands.iter();
381
382 assert_eq!(
383 commands.next(),
384 Some(AddressedCommand {
385 device_id: 4,
386 command: Command::Lens(LensCommand::InstantaneousAutoFocus),
387 })
388 .as_ref()
389 );
390
391 assert_eq!(
392 commands.next(),
393 Some(AddressedCommand {
394 device_id: 255,
395 command: Command::Lens(LensCommand::OpticalImageStabalization {
396 operation: Operation::Assign,
397 data: true
398 })
399 })
400 .as_ref()
401 );
402
403 assert_eq!(
404 commands.next(),
405 Some(AddressedCommand {
406 device_id: 4,
407 command: Command::Video(VideoCommand::ExposureUS {
408 operation: Operation::Assign,
409 data: 10000
410 })
411 })
412 .as_ref()
413 );
414
415 assert_eq!(
416 commands.next(),
417 Some(AddressedCommand {
418 device_id: 4,
419 command: Command::Display(DisplayCommand::ZebraLevel {
420 operation: Operation::Increment,
421 data: FixedPointDecimal {
422 raw_val: 0x0133u16 as i16
423 }
424 })
425 })
426 .as_ref()
427 );
428
429 assert_eq!(
430 commands.next(),
431 Some(AddressedCommand {
432 device_id: 255,
433 command: Command::Video(VideoCommand::VideoMode {
434 operation: Operation::Assign,
435 data: VideoModeData {
436 frame_rate: 24,
437 m_rate: 1,
438 dimensions: 3,
439 interlaced: 0,
440 color_space: 0,
441 }
442 })
443 })
444 .as_ref()
445 );
446
447 assert_eq!(
448 commands.next(),
449 Some(AddressedCommand {
450 device_id: 4,
451 command: Command::ColorCorrection(ColorCorrectionCommand::GammaAdjust {
452 operation: Operation::Increment,
453 data: RedGreenBlueLuma {
454 red: FixedPointDecimal { raw_val: 0x00 },
455 green: FixedPointDecimal {
456 raw_val: 0xfd9au16 as i16
457 },
458 blue: FixedPointDecimal {
459 raw_val: 0xfd9au16 as i16
460 },
461 luma: FixedPointDecimal { raw_val: 0x00 },
462 }
463 })
464 })
465 .as_ref()
466 );
467 }
468
469 #[test]
470 fn long_real_packet_one() {
471 let cmd_data: [u8; 243] = [
472 0x01, 0x06, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x8D, 0x1C, 0x00, 0x00, 0x01, 0x06,
473 0x00, 0x00, 0x01, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00,
474 0x01, 0x0D, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x01, 0x01,
475 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00,
476 0x04, 0x10, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x01, 0x05, 0x03, 0x00, 0x1B, 0x41,
477 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
478 0x01, 0x05, 0x00, 0x00, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0C,
479 0x00, 0x00, 0x08, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,
480 0x01, 0x0C, 0x00, 0x00, 0x08, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
481 0x00, 0x00, 0x01, 0x0C, 0x00, 0x00, 0x08, 0x02, 0x80, 0x00, 0x00, 0x08, 0x00, 0x08,
482 0x00, 0x08, 0xCE, 0x07, 0x01, 0x0C, 0x00, 0x00, 0x08, 0x03, 0x80, 0x00, 0x00, 0x00,
483 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x08, 0x04, 0x80, 0x00,
484 0x00, 0x04, 0x00, 0x08, 0x01, 0x06, 0x00, 0x00, 0x08, 0x05, 0x80, 0x00, 0x00, 0x08,
485 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x08, 0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08,
486 0x02, 0x06, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x9B, 0x12, 0x00, 0x00, 0x02, 0x06,
487 0x00, 0x00, 0x01, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00,
488 0x01, 0x0D, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x01, 0x01,
489 0x01, 0x00, 0x08, 0x00, 0x00,
490 ];
491 let result = parse_frame_packet(cmd_data.to_vec());
492 let _commands = result.unwrap();
493 }
494
495 #[test]
496 fn long_real_packet_two() {
497 let cmd_data: [u8; 251] = [
498 0x03, 0x0C, 0x00, 0x00, 0x08, 0x02, 0x80, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08,
499 0x00, 0x08, 0x03, 0x0C, 0x00, 0x00, 0x08, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
500 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0x00, 0x00, 0x08, 0x04, 0x80, 0x00, 0x00, 0x04,
501 0x00, 0x08, 0x03, 0x06, 0x00, 0x00, 0x08, 0x05, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00,
502 0x03, 0x08, 0x00, 0x00, 0x08, 0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x06,
503 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0xF2, 0x15, 0x00, 0x00, 0x04, 0x06, 0x00, 0x00,
504 0x01, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x01, 0x0D,
505 0x01, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00,
506 0x02, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x04, 0x10,
507 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x01, 0x05, 0x03, 0x00, 0x1B, 0x41, 0x00, 0x00,
508 0x04, 0x05, 0x00, 0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x05,
509 0x00, 0x00, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00,
510 0x08, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0C,
511 0x00, 0x00, 0x08, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
512 0x04, 0x0C, 0x00, 0x00, 0x08, 0x02, 0x80, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08,
513 0x00, 0x08, 0x04, 0x0C, 0x00, 0x00, 0x08, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
514 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x08, 0x04, 0x80, 0x00, 0x00, 0x04,
515 0x00, 0x08, 0x04, 0x06, 0x00, 0x00, 0x08, 0x05, 0x80, 0x00, 0x00, 0x08, 0x00,
516 ];
517 let result = parse_frame_packet(cmd_data.to_vec());
518 let _commands = result.unwrap();
519 }
520
521 #[test]
522 fn long_real_packet_three() {
523 let cmd_data: [u8; 247] = [
524 0x10, 0x05, 0x00, 0x00, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0C,
525 0x00, 0x00, 0x08, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
526 0x10, 0x0C, 0x00, 0x00, 0x08, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
527 0x00, 0x00, 0x10, 0x0C, 0x00, 0x00, 0x08, 0x02, 0x80, 0x00, 0x00, 0x08, 0x00, 0x08,
528 0x00, 0x08, 0x00, 0x08, 0x10, 0x0C, 0x00, 0x00, 0x08, 0x03, 0x80, 0x00, 0x00, 0x00,
529 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x08, 0x04, 0x80, 0x00,
530 0x00, 0x04, 0x00, 0x08, 0x10, 0x06, 0x00, 0x00, 0x08, 0x05, 0x80, 0x00, 0x00, 0x08,
531 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x08, 0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08,
532 0x11, 0x06, 0x00, 0x00, 0x01, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x05,
533 0x00, 0x00, 0x01, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x05, 0x00, 0x00,
534 0x01, 0x01, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x11, 0x08, 0x00, 0x00, 0x01, 0x05,
535 0x03, 0x00, 0x20, 0x4E, 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x01, 0x08, 0x01, 0x00,
536 0x01, 0x00, 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00,
537 0x00, 0x00, 0x11, 0x0C, 0x00, 0x00, 0x08, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
538 0x00, 0x00, 0x00, 0x00, 0x11, 0x0C, 0x00, 0x00, 0x08, 0x01, 0x80, 0x00, 0x00, 0x00,
539 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x0C, 0x00, 0x00, 0x08, 0x02, 0x80, 0x00,
540 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x11, 0x0C, 0x00, 0x00, 0x08, 0x03,
541 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
542 ];
543 let result = parse_frame_packet(cmd_data.to_vec());
544 let _commands = result.unwrap();
545 }
546
547 #[test]
548 fn short_real_packet_one() {
549 let cmd_data: [u8; 23] = [
550 0x02, 0x06, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x64, 0x20, 0x00, 0x00, 0x02, 0x06,
551 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x07, 0x21, 0x00,
552 ];
553 let result = parse_frame_packet(cmd_data.to_vec());
554 let _commands = result.unwrap();
555 }
556}
557
558#[cfg(test)]
559mod lib_test {
560 use super::*;
561 use crate::commands::{lens_commands::LensCommand, Command};
562
563 #[test]
564 fn parse_packet_single_command() {
565 let packet_data = vec![
566 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x33, 0x01, 0x00, 0x00, ];
570
571 if let Ok(commands) = parse_frame_packet(packet_data) {
572 println!("parse_packet_single_command() commands: {:?}", commands);
573 assert_eq!(1, commands.len());
574 assert_eq!(
575 AddressedCommand {
576 device_id: 0,
577 command: Command::Lens(LensCommand::Focus {
578 operation: Operation::Increment,
579 data: FixedPointDecimal {
580 raw_val: 0x0133u16 as i16
581 }
582 })
583 },
584 *commands.first().expect("Length asserted to be one")
585 );
586 } else {
587 panic!();
588 }
589 }
590
591 #[test]
592 fn parse_packet_two_commands() {
593 let packet_data = vec![
594 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x33, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x33, 0x01, 0x00, 0x00, ];
601
602 if let Ok(commands) = parse_frame_packet(packet_data) {
603 println!("parse_packet_single_command() commands: {:?}", commands);
604 assert_eq!(2, commands.len());
605 assert_eq!(
606 AddressedCommand {
607 device_id: 0,
608 command: Command::Lens(LensCommand::Focus {
609 operation: Operation::Increment,
610 data: FixedPointDecimal {
611 raw_val: 0x0133u16 as i16
612 }
613 })
614 },
615 *commands
616 .first()
617 .expect("Length asserted to be more then one")
618 );
619 assert_eq!(
620 AddressedCommand {
621 device_id: 0,
622 command: Command::Lens(LensCommand::Focus {
623 operation: Operation::Increment,
624 data: FixedPointDecimal {
625 raw_val: 0x0133u16 as i16
626 }
627 })
628 },
629 *commands.get(1).expect("Length asserted to be two")
630 );
631 } else {
632 panic!();
633 }
634 }
635
636 #[test]
637 fn calculate_padding_length_no_padding() {
638 assert_eq!(0_u8, calculate_padding_length(8));
639 assert_eq!(0_u8, calculate_padding_length(4));
640 }
641
642 #[test]
643 fn calculate_padding_length_one() {
644 assert_eq!(1_u8, calculate_padding_length(3));
645 assert_eq!(1_u8, calculate_padding_length(7));
646 }
647
648 #[test]
649 fn calculate_padding_length_two() {
650 assert_eq!(2_u8, calculate_padding_length(2));
651 assert_eq!(2_u8, calculate_padding_length(6));
652 }
653
654 #[test]
655 fn calculate_padding_length_three() {
656 assert_eq!(3_u8, calculate_padding_length(1));
657 assert_eq!(3_u8, calculate_padding_length(5));
658 }
659
660 #[test]
661 fn verify_padding_success() {
662 let padding: [u8; 3] = [0x00; 3];
663 let command_length = 5;
664
665 assert_eq!(Ok(()), verify_padding(&padding, command_length));
666 }
667
668 #[test]
669 fn verify_padding_too_short() {
670 let padding: [u8; 2] = [0x00; 2];
671 let command_length = 5;
672
673 assert_eq!(
674 Err(EldritchError::PaddingViolation(String::from(
675 "Padding length is incorrect"
676 ))),
677 verify_padding(&padding, command_length)
678 );
679 }
680
681 #[test]
682 fn verify_padding_nonzero_byte_idx_0() {
683 let padding: [u8; 3] = [0xff, 0x00, 0x00];
684 let command_length = 5;
685
686 assert_eq!(
687 Err(EldritchError::PaddingViolation(String::from(
688 "Padding byte at index: 0 is not 0x00"
689 ))),
690 verify_padding(&padding, command_length),
691 )
692 }
693
694 #[test]
695 fn verify_padding_nonzero_byte_idx_2() {
696 let padding: [u8; 3] = [0x00, 0x00, 0xff];
697 let command_length = 5;
698
699 assert_eq!(
700 Err(EldritchError::PaddingViolation(String::from(
701 "Padding byte at index: 2 is not 0x00"
702 ))),
703 verify_padding(&padding, command_length),
704 )
705 }
706}