1use super::command::OpCode;
2use super::error::{Error, ErrorKind, Status};
3use crate::datalink::Transaction;
4use core::convert::{TryFrom, TryInto};
5use core::mem::size_of;
6use core::ops::RangeTo;
7use crc::{Algorithm, Crc};
8
9const PACKET_OFFSET: usize = 1;
11const PDU_OFFSET: usize = 6;
13const CMD_SIZE_MIN: usize = 7;
15
16const CUSTOM_ALG: Algorithm<u16> = Algorithm {
18 poly: 0x8005,
19 init: 0x0000,
20 refin: true,
21 refout: false,
22 xorout: 0x0000,
23 check: 0xbcdd,
24 residue: 0x0000,
25};
26
27pub const CRC16: Crc<u16> = Crc::<u16>::new(&CUSTOM_ALG);
29
30#[derive(Debug)]
31pub(crate) struct PacketBuilder<'a> {
32 buffer: &'a mut [u8],
33 pdu_length: Option<usize>,
34 opcode: Option<OpCode>,
35 mode: Option<u8>,
36 param2: Option<u16>,
37}
38
39impl<'a> PacketBuilder<'a> {
40 pub(crate) fn new(buffer: &'a mut [u8]) -> Self {
41 Self {
42 buffer,
43 pdu_length: None,
44 opcode: None,
45 mode: None,
46 param2: None,
47 }
48 }
49
50 pub(crate) fn opcode(&mut self, opcode: OpCode) -> &mut Self {
51 self.opcode.replace(opcode);
52 self
53 }
54
55 pub(crate) fn mode(&mut self, mode: u8) -> &mut Self {
57 self.mode.replace(mode);
58 self
59 }
60
61 pub(crate) fn param2(&mut self, param2: u16) -> &mut Self {
63 self.param2.replace(param2);
64 self
65 }
66
67 pub(crate) fn pdu_data(&mut self, data: impl AsRef<[u8]>) -> &mut Self {
68 let data_length = data.as_ref().len();
69 self.buffer[PDU_OFFSET..PDU_OFFSET + data_length]
70 .as_mut()
71 .copy_from_slice(data.as_ref());
72 self.pdu_length.replace(data_length);
73 self
74 }
75
76 pub(crate) fn pdu_length(&mut self, length: usize) -> &mut Self {
79 self.pdu_length.replace(length);
80 self
81 }
82
83 pub(crate) fn packet_buffer(&mut self) -> &mut [u8] {
84 self.buffer[PACKET_OFFSET..].as_mut()
85 }
86
87 pub(crate) fn pdu_buffer(&mut self) -> &mut [u8] {
88 self.buffer[PDU_OFFSET..].as_mut()
89 }
90
91 pub(crate) fn build(&mut self) -> Result<Packet, Error> {
92 let packet_length = self
93 .pdu_length
94 .iter()
95 .fold(CMD_SIZE_MIN, |min, pdu_len| min + pdu_len);
96 let opcode = self.opcode.ok_or(Error::from(ErrorKind::BadOpcode))?;
97 let mode = self.mode.unwrap_or_default();
98 let param2 = self.param2.unwrap_or_default();
99
100 self.buffer[0] = Transaction::Command as u8;
102 let packet = self.packet_buffer();
103 packet[0] = packet_length as u8;
104 packet[1] = opcode as u8;
105 packet[2] = mode;
106 packet[3..5]
107 .as_mut()
108 .copy_from_slice(param2.to_le_bytes().as_ref());
109
110 let crc_offset = packet_length - size_of::<u16>();
111 let crc = CRC16.checksum(&packet[..crc_offset]);
112 packet[crc_offset..packet_length]
113 .as_mut()
114 .copy_from_slice(crc.to_le_bytes().as_ref());
115 Ok(Packet {
116 opcode,
117 range: (..packet_length + PACKET_OFFSET),
118 })
119 }
120}
121
122impl<'a> From<&'a mut [u8]> for PacketBuilder<'a> {
123 fn from(buffer: &'a mut [u8]) -> Self {
124 Self::new(buffer)
125 }
126}
127
128#[derive(Clone, Copy, Debug)]
130pub(crate) struct Packet {
131 opcode: OpCode,
132 range: RangeTo<usize>,
133}
134
135impl Packet {
136 pub(crate) fn opcode(&self) -> &OpCode {
137 &self.opcode
138 }
139
140 pub(crate) fn buffer(self, buffer: &[u8]) -> &[u8] {
141 buffer[self.range].as_ref()
142 }
143}
144
145#[derive(Clone, Copy, Debug)]
148pub struct Response<'a> {
149 pdu: &'a [u8],
150}
151
152impl<'a> Response<'a> {
153 pub(crate) fn new(buffer: &'a [u8]) -> Result<Self, Error> {
157 if buffer.len() < 0x04 {
159 return Err(ErrorKind::RxFail.into());
161 }
162
163 let (payload, crc_bytes) = buffer.split_at(buffer.len() - size_of::<u16>());
165 let crc = crc_bytes
166 .try_into()
167 .map(u16::from_le_bytes)
168 .unwrap_or_else(|_| unreachable!());
169 if crc != CRC16.checksum(&payload) {
170 return Err(ErrorKind::RxCrcError.into());
171 }
172
173 let (header, pdu) = payload.split_at(1);
175 if header[0] == 0x04 {
176 if let Ok(status) = Status::try_from(pdu[0]) {
177 return Err(status.into());
178 }
179 }
180
181 Ok(Self { pdu })
182 }
183}
184
185impl<'a> AsRef<[u8]> for Response<'a> {
186 fn as_ref(&self) -> &[u8] {
187 self.pdu
188 }
189}