marlin_binary_transfer/
codec.rs1use thiserror::Error;
22
23pub const PACKET_TOKEN: u16 = 0xB5AD;
25
26pub const HEADER_LEN: usize = 8;
29
30pub const MAX_PAYLOAD: usize = u16::MAX as usize;
32
33#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct Packet<'a> {
36 pub sync: u8,
38 pub protocol: u8,
40 pub packet_type: u8,
42 pub payload: &'a [u8],
44}
45
46#[derive(Debug, Error, PartialEq, Eq)]
48pub enum DecodeError {
49 #[error("not enough bytes (need {need}, have {have})")]
51 Incomplete {
52 need: usize,
54 have: usize,
56 },
57 #[error("start token mismatch: expected {expected:#06x}, got {got:#06x}")]
59 BadToken {
60 expected: u16,
62 got: u16,
64 },
65 #[error("header checksum mismatch: stored {stored:#06x}, computed {computed:#06x}")]
67 HeaderChecksum {
68 stored: u16,
70 computed: u16,
72 },
73 #[error("payload checksum mismatch: stored {stored:#06x}, computed {computed:#06x}")]
75 PayloadChecksum {
76 stored: u16,
78 computed: u16,
80 },
81}
82
83#[derive(Debug, Error, PartialEq, Eq)]
86pub enum EncodeError {
87 #[error("payload length {len} exceeds maximum {MAX_PAYLOAD}")]
89 PayloadTooLarge {
90 len: usize,
92 },
93 #[error("protocol id {0} out of range (0..=15)")]
95 BadProtocol(u8),
96 #[error("packet type {0} out of range (0..=15)")]
98 BadPacketType(u8),
99}
100
101impl<'a> Packet<'a> {
102 pub fn new(
105 sync: u8,
106 protocol: u8,
107 packet_type: u8,
108 payload: &'a [u8],
109 ) -> Result<Self, EncodeError> {
110 if protocol > 0xF {
111 return Err(EncodeError::BadProtocol(protocol));
112 }
113 if packet_type > 0xF {
114 return Err(EncodeError::BadPacketType(packet_type));
115 }
116 if payload.len() > MAX_PAYLOAD {
117 return Err(EncodeError::PayloadTooLarge { len: payload.len() });
118 }
119 Ok(Self {
120 sync,
121 protocol,
122 packet_type,
123 payload,
124 })
125 }
126
127 pub fn wire_len(&self) -> usize {
129 if self.payload.is_empty() {
130 HEADER_LEN
131 } else {
132 HEADER_LEN + self.payload.len() + 2
133 }
134 }
135}
136
137pub fn fletcher16(buf: &[u8]) -> u16 {
142 let mut cs: u16 = 0;
143 for &b in buf {
144 let cs_low = ((cs & 0xFF) + b as u16) % 255;
145 cs = ((((cs >> 8) + cs_low) % 255) << 8) | cs_low;
146 }
147 cs
148}
149
150pub fn encode(packet: &Packet<'_>, out: &mut Vec<u8>) -> Result<usize, EncodeError> {
154 if packet.protocol > 0xF {
155 return Err(EncodeError::BadProtocol(packet.protocol));
156 }
157 if packet.packet_type > 0xF {
158 return Err(EncodeError::BadPacketType(packet.packet_type));
159 }
160 if packet.payload.len() > MAX_PAYLOAD {
161 return Err(EncodeError::PayloadTooLarge {
162 len: packet.payload.len(),
163 });
164 }
165
166 let start = out.len();
167
168 out.extend_from_slice(&PACKET_TOKEN.to_le_bytes());
170
171 let header_payload_start = out.len();
175 out.push(packet.sync);
176 out.push(((packet.protocol & 0xF) << 4) | (packet.packet_type & 0xF));
177 out.extend_from_slice(&(packet.payload.len() as u16).to_le_bytes());
178 let header_cs = fletcher16(&out[header_payload_start..]);
179 out.extend_from_slice(&header_cs.to_le_bytes());
180
181 if !packet.payload.is_empty() {
182 out.extend_from_slice(packet.payload);
183 let body_end = out.len();
184 let payload_cs = fletcher16(&out[header_payload_start..body_end]);
187 out.extend_from_slice(&payload_cs.to_le_bytes());
188 }
189
190 Ok(out.len() - start)
191}
192
193pub fn decode(buf: &[u8]) -> Result<(Packet<'_>, usize), DecodeError> {
200 if buf.len() < HEADER_LEN {
201 return Err(DecodeError::Incomplete {
202 need: HEADER_LEN,
203 have: buf.len(),
204 });
205 }
206
207 let token = u16::from_le_bytes([buf[0], buf[1]]);
208 if token != PACKET_TOKEN {
209 return Err(DecodeError::BadToken {
210 expected: PACKET_TOKEN,
211 got: token,
212 });
213 }
214
215 let sync = buf[2];
216 let proto_type = buf[3];
217 let protocol = proto_type >> 4;
218 let packet_type = proto_type & 0x0F;
219 let payload_len = u16::from_le_bytes([buf[4], buf[5]]) as usize;
220 let stored_header_cs = u16::from_le_bytes([buf[6], buf[7]]);
221
222 let computed_header_cs = fletcher16(&buf[2..6]);
223 if stored_header_cs != computed_header_cs {
224 return Err(DecodeError::HeaderChecksum {
225 stored: stored_header_cs,
226 computed: computed_header_cs,
227 });
228 }
229
230 if payload_len == 0 {
231 return Ok((
232 Packet {
233 sync,
234 protocol,
235 packet_type,
236 payload: &[],
237 },
238 HEADER_LEN,
239 ));
240 }
241
242 let total_len = HEADER_LEN + payload_len + 2;
243 if buf.len() < total_len {
244 return Err(DecodeError::Incomplete {
245 need: total_len,
246 have: buf.len(),
247 });
248 }
249
250 let payload = &buf[HEADER_LEN..HEADER_LEN + payload_len];
251 let cs_off = HEADER_LEN + payload_len;
252 let stored_payload_cs = u16::from_le_bytes([buf[cs_off], buf[cs_off + 1]]);
253 let computed_payload_cs = fletcher16(&buf[2..cs_off]);
254 if stored_payload_cs != computed_payload_cs {
255 return Err(DecodeError::PayloadChecksum {
256 stored: stored_payload_cs,
257 computed: computed_payload_cs,
258 });
259 }
260
261 Ok((
262 Packet {
263 sync,
264 protocol,
265 packet_type,
266 payload,
267 },
268 total_len,
269 ))
270}