Skip to main content

psdk_fruit_emapi/
frame_codec.rs

1use 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}