psdk_fruit_emapi/
frame_codec.rs1use crate::{
2 command::EmapiCommand,
3 constants::{COMMAND_HEADER_LENGTH, FRAME_HEAD, FRAME_OVERHEAD_LENGTH, FRAME_TAIL, RESERVED},
4 crc32,
5 endian::{read_uint16, read_uint32, uint16, uint32},
6 error::{EmapiError, Result},
7};
8
9pub struct FrameCodec;
10
11impl FrameCodec {
12 pub fn encode(command: &EmapiCommand) -> Result<Vec<u8>> {
13 let data_length = COMMAND_HEADER_LENGTH + command.payload.len();
14 if data_length > usize::from(u16::MAX) {
15 return Err(EmapiError::Range {
16 name: "dataLength",
17 min: 0,
18 max: u64::from(u16::MAX),
19 value: data_length as u64,
20 });
21 }
22
23 let mut data = Vec::with_capacity(data_length);
24 data.push(command.command_type);
25 data.push(command.parent);
26 data.push(command.child);
27 data.extend_from_slice(&uint16(command.payload.len() as u16));
28 data.extend_from_slice(&command.payload);
29
30 let mut frame = Vec::with_capacity(data_length + FRAME_OVERHEAD_LENGTH);
31 frame.push(FRAME_HEAD);
32 frame.push(RESERVED);
33 frame.extend_from_slice(&uint16(data.len() as u16));
34 frame.extend_from_slice(&data);
35 frame.extend_from_slice(&uint32(crc32::compute(&data)));
36 frame.push(FRAME_TAIL);
37 Ok(frame)
38 }
39
40 pub fn decode(frame: &[u8]) -> Result<EmapiCommand> {
41 if frame.len() < FRAME_OVERHEAD_LENGTH {
42 return Err(EmapiError::FrameTooShort);
43 }
44 if frame[0] != FRAME_HEAD {
45 return Err(EmapiError::MissingFrameHead);
46 }
47 if frame[frame.len() - 1] != FRAME_TAIL {
48 return Err(EmapiError::MissingFrameTail);
49 }
50
51 let data_length = usize::from(read_uint16(frame, 2)?);
52 let expected_frame_length = data_length + FRAME_OVERHEAD_LENGTH;
53 if frame.len() != expected_frame_length {
54 return Err(EmapiError::FrameLengthMismatch {
55 expected: expected_frame_length,
56 actual: frame.len(),
57 });
58 }
59 if data_length < COMMAND_HEADER_LENGTH {
60 return Err(EmapiError::CommandDataTooShort);
61 }
62
63 let data_start = 4;
64 let data_end = data_start + data_length;
65 let data = &frame[data_start..data_end];
66 let expected_crc = read_uint32(frame, data_end)?;
67 let actual_crc = crc32::compute(data);
68 if expected_crc != actual_crc {
69 return Err(EmapiError::BadFrameCrc {
70 expected: expected_crc,
71 actual: actual_crc,
72 });
73 }
74
75 let payload_length = usize::from(read_uint16(data, 3)?);
76 let expected_data_length = COMMAND_HEADER_LENGTH + payload_length;
77 if data.len() != expected_data_length {
78 return Err(EmapiError::PayloadLengthMismatch {
79 expected: payload_length,
80 actual: data.len() - COMMAND_HEADER_LENGTH,
81 });
82 }
83
84 Ok(EmapiCommand::new(
85 data[0],
86 data[1],
87 data[2],
88 data[COMMAND_HEADER_LENGTH..].to_vec(),
89 ))
90 }
91}