1use core::mem::MaybeUninit;
2
3use crate::crc::{CRC_INIT, crc16};
4use crate::sync::Sync;
5use crate::{Cmd, ReadError, Status};
6
7pub const MAX_PAYLOAD: usize = 64;
9
10#[repr(C, packed)]
15#[derive(Clone, Copy)]
16pub struct InfoData {
17 pub capacity: u32,
19 pub erase_size: u16,
21 pub boot_version: u16,
23 pub app_version: u16,
25 pub mode: u16,
27}
28
29#[repr(C)]
31#[derive(Clone, Copy)]
32pub struct EraseData {
33 pub byte_count: u16,
35}
36
37#[repr(C)]
39#[derive(Clone, Copy)]
40pub struct VerifyData {
41 pub crc: u16,
43}
44
45#[repr(C)]
50pub union Data {
51 pub raw: [u8; MAX_PAYLOAD],
53 pub info: InfoData,
55 pub erase: EraseData,
57 pub verify: VerifyData,
59}
60
61#[repr(C)]
68pub struct Frame {
69 sync: Sync,
70 pub cmd: Cmd,
72 pub status: Status,
74 pub addr: u32,
76 pub len: u16,
78 pub data: Data,
80 pub crc: [u8; 2],
82}
83
84impl Default for Frame {
85 fn default() -> Self {
88 let frame: MaybeUninit<Self> = MaybeUninit::uninit();
89 let mut frame = unsafe { frame.assume_init() };
90 frame.sync = Sync::default();
91 frame.cmd = Cmd::Info;
92 frame.status = Status::Request;
93 frame.addr = 0;
94 frame.len = 0;
95 frame.crc = [0; 2];
96 frame
97 }
98}
99
100impl Frame {
101 fn as_bytes(&self, offset: usize, len: usize) -> &[u8] {
102 debug_assert!(offset + len <= core::mem::size_of::<Self>());
103 unsafe {
104 let ptr = (self as *const Self as *const u8).add(offset);
105 core::slice::from_raw_parts(ptr, len)
106 }
107 }
108
109 fn as_bytes_mut(&mut self, offset: usize, len: usize) -> &mut [u8] {
110 debug_assert!(offset + len <= core::mem::size_of::<Self>());
111 unsafe {
112 let ptr = (self as *mut Self as *mut u8).add(offset);
113 core::slice::from_raw_parts_mut(ptr, len)
114 }
115 }
116
117 pub fn send<W: embedded_io::Write>(&mut self, w: &mut W) -> Result<(), W::Error> {
119 self.sync = Sync::valid();
120 let body_len = 10 + self.len as usize;
121 let crc = crc16(CRC_INIT, self.as_bytes(0, body_len)).to_le_bytes();
122 let len = self.len as usize;
126 unsafe {
127 *self.data.raw.get_unchecked_mut(len) = crc[0];
128 *self.data.raw.get_unchecked_mut(len + 1) = crc[1];
129 }
130 w.write_all(self.as_bytes(0, body_len + 2))
131 }
132
133 pub fn read<R: embedded_io::Read>(&mut self, r: &mut R) -> Result<Status, ReadError> {
139 self.sync.read(r)?;
140
141 r.read_exact(self.as_bytes_mut(2, 8))
143 .map_err(|_| ReadError)?;
144
145 if !Cmd::is_valid(self.as_bytes(2, 1)[0]) || !Status::is_valid(self.as_bytes(3, 1)[0]) {
146 return Ok(Status::Unsupported);
151 }
152
153 let data_len = self.len as usize;
154
155 if data_len > MAX_PAYLOAD {
156 return Ok(Status::PayloadOverflow);
159 }
160
161 if data_len > 0 {
163 r.read_exact(unsafe { &mut self.data.raw[..data_len] })
164 .map_err(|_| ReadError)?;
165 }
166
167 r.read_exact(&mut self.crc).map_err(|_| ReadError)?;
169
170 if self.crc != crc16(CRC_INIT, self.as_bytes(0, 10 + data_len)).to_le_bytes() {
172 return Ok(Status::CrcMismatch);
173 }
174
175 Ok(Status::Ok)
176 }
177
178 pub async fn send_async<W: embedded_io_async::Write>(
180 &mut self,
181 w: &mut W,
182 ) -> Result<(), W::Error> {
183 self.sync = Sync::valid();
184 let body_len = 10 + self.len as usize;
185 self.crc = crc16(CRC_INIT, self.as_bytes(0, body_len)).to_le_bytes();
186 w.write_all(self.as_bytes(0, body_len)).await?;
187 w.write_all(&self.crc).await
188 }
189
190 pub async fn read_async<R: embedded_io_async::Read>(
192 &mut self,
193 r: &mut R,
194 ) -> Result<Status, ReadError> {
195 self.sync.read_async(r).await?;
196
197 r.read_exact(self.as_bytes_mut(2, 8))
198 .await
199 .map_err(|_| ReadError)?;
200
201 if !Cmd::is_valid(self.as_bytes(2, 1)[0]) || !Status::is_valid(self.as_bytes(3, 1)[0]) {
202 return Ok(Status::Unsupported);
204 }
205
206 let data_len = self.len as usize;
207
208 if data_len > MAX_PAYLOAD {
209 return Ok(Status::PayloadOverflow);
211 }
212
213 if data_len > 0 {
214 r.read_exact(unsafe { &mut self.data.raw[..data_len] })
215 .await
216 .map_err(|_| ReadError)?;
217 }
218
219 r.read_exact(&mut self.crc).await.map_err(|_| ReadError)?;
220
221 if self.crc != crc16(CRC_INIT, self.as_bytes(0, 10 + data_len)).to_le_bytes() {
222 return Ok(Status::CrcMismatch);
223 }
224
225 Ok(Status::Ok)
226 }
227}
228
229#[cfg(test)]
230mod tests {
231 use super::*;
232
233 struct MockReader<'a> {
234 data: &'a [u8],
235 pos: usize,
236 }
237
238 impl<'a> MockReader<'a> {
239 fn new(data: &'a [u8]) -> Self {
240 Self { data, pos: 0 }
241 }
242 }
243
244 impl embedded_io::ErrorType for MockReader<'_> {
245 type Error = core::convert::Infallible;
246 }
247
248 impl embedded_io::Read for MockReader<'_> {
249 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
250 let n = buf.len().min(self.data.len() - self.pos);
251 buf[..n].copy_from_slice(&self.data[self.pos..self.pos + n]);
252 self.pos += n;
253 Ok(n)
254 }
255 }
256
257 struct Sink {
258 buf: [u8; 512],
259 pos: usize,
260 }
261
262 impl Sink {
263 fn new() -> Self {
264 Self {
265 buf: [0; 512],
266 pos: 0,
267 }
268 }
269 fn written(&self) -> &[u8] {
270 &self.buf[..self.pos]
271 }
272 }
273
274 impl embedded_io::ErrorType for Sink {
275 type Error = core::convert::Infallible;
276 }
277
278 impl embedded_io::Write for Sink {
279 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
280 let n = buf.len().min(self.buf.len() - self.pos);
281 self.buf[self.pos..self.pos + n].copy_from_slice(&buf[..n]);
282 self.pos += n;
283 Ok(n)
284 }
285 fn flush(&mut self) -> Result<(), Self::Error> {
286 Ok(())
287 }
288 }
289
290 fn frame(cmd: Cmd, status: Status, addr: u32, data: &[u8]) -> Frame {
291 let mut f = Frame {
292 cmd,
293 status,
294 addr,
295 len: data.len() as u16,
296 ..Default::default()
297 };
298 unsafe { f.data.raw[..data.len()].copy_from_slice(data) };
299 f
300 }
301
302 #[test]
303 fn request_round_trip() {
304 let mut frame = frame(Cmd::Write, Status::Request, 0x0800, &[0xDE, 0xAD]);
305
306 let mut sink = Sink::new();
307 frame.send(&mut sink).unwrap();
308
309 let mut frame2 = Frame::default();
310 frame2.read(&mut MockReader::new(sink.written())).unwrap();
311 assert_eq!(frame2.cmd, Cmd::Write);
312 assert_eq!(frame2.len, 2);
313 assert_eq!(frame2.addr, 0x0800);
314 assert_eq!(frame2.status, Status::Request);
315 assert_eq!(unsafe { &frame2.data.raw[..2] }, &[0xDE, 0xAD]);
316 }
317
318 #[test]
319 fn response_round_trip() {
320 let mut frame = frame(Cmd::Verify, Status::Ok, 0, &[0x12, 0x34]);
321
322 let mut sink = Sink::new();
323 frame.send(&mut sink).unwrap();
324
325 let mut frame2 = Frame::default();
326 frame2.read(&mut MockReader::new(sink.written())).unwrap();
327 assert_eq!(frame2.cmd, Cmd::Verify);
328 assert_eq!(frame2.status, Status::Ok);
329 assert_eq!(unsafe { &frame2.data.raw[..2] }, &[0x12, 0x34]);
330 }
331
332 #[test]
333 fn request_no_data() {
334 let mut frame = frame(Cmd::Erase, Status::Request, 0, &[]);
335
336 let mut sink = Sink::new();
337 frame.send(&mut sink).unwrap();
338
339 assert_eq!(sink.written().len(), 12);
341
342 let mut frame2 = Frame::default();
343 frame2.read(&mut MockReader::new(sink.written())).unwrap();
344 assert_eq!(frame2.cmd, Cmd::Erase);
345 assert_eq!(frame2.len, 0);
346 }
347
348 #[test]
349 fn large_addr_round_trip() {
350 let mut frame = frame(Cmd::Write, Status::Request, 0x0001_0800, &[0xAB]);
351
352 let mut sink = Sink::new();
353 frame.send(&mut sink).unwrap();
354
355 let mut frame2 = Frame::default();
356 frame2.read(&mut MockReader::new(sink.written())).unwrap();
357 assert_eq!(frame2.addr, 0x0001_0800);
358 }
359
360 #[test]
361 fn cmd_addr_carry_over() {
362 let mut frame = frame(Cmd::Write, Status::Request, 0x0400, &[0xAB, 0xCD]);
363
364 let mut sink = Sink::new();
365 frame.send(&mut sink).unwrap();
366
367 let mut dev = Frame::default();
369 dev.read(&mut MockReader::new(sink.written())).unwrap();
370
371 dev.status = Status::Ok;
373 dev.len = 0;
374 let mut resp_sink = Sink::new();
375 dev.send(&mut resp_sink).unwrap();
376
377 let mut host = Frame::default();
379 host.read(&mut MockReader::new(resp_sink.written()))
380 .unwrap();
381 assert_eq!(host.cmd, Cmd::Write);
382 assert_eq!(host.addr, 0x0400);
383 assert_eq!(host.status, Status::Ok);
384 }
385
386 #[test]
387 fn read_bad_cmd() {
388 let mut frame = frame(Cmd::Info, Status::Request, 0, &[]);
389
390 let mut sink = Sink::new();
391 frame.send(&mut sink).unwrap();
392 sink.buf[2] ^= 0xFF; let mut frame2 = Frame::default();
395 assert_eq!(
396 frame2.read(&mut MockReader::new(sink.written())),
397 Ok(Status::Unsupported)
398 );
399 }
400
401 #[test]
402 fn read_after_garbage() {
403 let mut frame = frame(Cmd::Verify, Status::Request, 0, &[]);
404
405 let mut sink = Sink::new();
406 frame.send(&mut sink).unwrap();
407 let frame_len = sink.pos;
408
409 let mut input = [0u8; 4 + 512];
410 input[..4].copy_from_slice(&[0xFF, 0x00, 0xAA, 0x42]);
411 input[4..4 + frame_len].copy_from_slice(&sink.buf[..frame_len]);
412
413 let mut frame2 = Frame::default();
414 assert_eq!(
415 frame2.read(&mut MockReader::new(&input[..4 + frame_len])),
416 Ok(Status::Ok)
417 );
418 assert_eq!(frame2.cmd, Cmd::Verify);
419 }
420
421 #[test]
422 fn read_overflow() {
423 let mut f = frame(Cmd::Write, Status::Request, 0, &[]);
425
426 let mut sink = Sink::new();
427 f.send(&mut sink).unwrap();
428
429 let overflow_len = (MAX_PAYLOAD as u16 + 1).to_le_bytes();
431 sink.buf[8] = overflow_len[0];
432 sink.buf[9] = overflow_len[1];
433
434 let mut frame2 = Frame::default();
435 assert_eq!(
436 frame2.read(&mut MockReader::new(sink.written())),
437 Ok(Status::PayloadOverflow)
438 );
439 }
440}