1use core::mem::MaybeUninit;
2
3use crate::crc::{CRC_INIT, crc16};
4use crate::sync::Sync;
5use crate::{Cmd, ReadError, ResetFlags, Status, WriteFlags};
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)]
50#[derive(Clone, Copy)]
51pub union Flags {
52 pub raw: u8,
54 pub write: WriteFlags,
56 pub reset: ResetFlags,
58}
59
60#[repr(C)]
65pub union Data {
66 pub raw: [u8; MAX_PAYLOAD],
68 pub info: InfoData,
70 pub erase: EraseData,
72 pub verify: VerifyData,
74}
75
76#[repr(C)]
83pub struct Frame {
84 sync: Sync,
85 pub cmd: Cmd,
87 pub status: Status,
89 pub addr_lo: u16,
91 pub addr_hi: u8,
93 pub flags: Flags,
95 pub len: u16,
97 pub data: Data,
99 pub crc: [u8; 2],
101}
102
103impl Default for Frame {
104 fn default() -> Self {
107 let frame: MaybeUninit<Self> = MaybeUninit::uninit();
108 let mut frame = unsafe { frame.assume_init() };
109 frame.sync = Sync::default();
110 frame.cmd = Cmd::Info;
111 frame.status = Status::Request;
112 frame.addr_lo = 0;
113 frame.addr_hi = 0;
114 frame.flags = Flags { raw: 0 };
115 frame.len = 0;
116 frame.crc = [0; 2];
117 frame
118 }
119}
120
121impl Frame {
122 #[inline(always)]
124 pub fn addr(&self) -> u32 {
125 self.addr_lo as u32 | (self.addr_hi as u32) << 16
126 }
127
128 #[inline(always)]
130 pub fn set_addr(&mut self, addr: u32) {
131 self.addr_lo = addr as u16;
132 self.addr_hi = (addr >> 16) as u8;
133 }
134}
135
136impl Frame {
137 fn as_bytes(&self, offset: usize, len: usize) -> &[u8] {
138 debug_assert!(offset + len <= core::mem::size_of::<Self>());
139 unsafe {
140 let ptr = (self as *const Self as *const u8).add(offset);
141 core::slice::from_raw_parts(ptr, len)
142 }
143 }
144
145 fn as_bytes_mut(&mut self, offset: usize, len: usize) -> &mut [u8] {
146 debug_assert!(offset + len <= core::mem::size_of::<Self>());
147 unsafe {
148 let ptr = (self as *mut Self as *mut u8).add(offset);
149 core::slice::from_raw_parts_mut(ptr, len)
150 }
151 }
152
153 pub fn send<W: embedded_io::Write>(&mut self, w: &mut W) -> Result<(), W::Error> {
155 self.sync = Sync::valid();
156 let body_len = 10 + self.len as usize;
157 let crc = crc16(CRC_INIT, self.as_bytes(0, body_len)).to_le_bytes();
158 unsafe {
162 let base = self as *mut Self as *mut u8;
163 *base.add(10 + self.len as usize) = crc[0];
164 *base.add(10 + self.len as usize + 1) = crc[1];
165 }
166 w.write_all(self.as_bytes(0, body_len + 2))
167 }
168
169 pub fn read<R: embedded_io::Read>(&mut self, r: &mut R) -> Result<Status, ReadError> {
175 self.sync.read(r)?;
176
177 r.read_exact(self.as_bytes_mut(2, 8))
179 .map_err(|_| ReadError)?;
180
181 if !Cmd::is_valid(self.as_bytes(2, 1)[0]) || !Status::is_valid(self.as_bytes(3, 1)[0]) {
182 return Ok(Status::Unsupported);
187 }
188
189 let data_len = self.len as usize;
190
191 if data_len > MAX_PAYLOAD {
192 return Ok(Status::PayloadOverflow);
195 }
196
197 if data_len > 0 {
199 r.read_exact(unsafe { &mut self.data.raw[..data_len] })
200 .map_err(|_| ReadError)?;
201 }
202
203 r.read_exact(&mut self.crc).map_err(|_| ReadError)?;
205
206 if self.crc != crc16(CRC_INIT, self.as_bytes(0, 10 + data_len)).to_le_bytes() {
208 return Ok(Status::CrcMismatch);
209 }
210
211 Ok(Status::Ok)
212 }
213
214 pub async fn send_async<W: embedded_io_async::Write>(
216 &mut self,
217 w: &mut W,
218 ) -> Result<(), W::Error> {
219 self.sync = Sync::valid();
220 let body_len = 10 + self.len as usize;
221 self.crc = crc16(CRC_INIT, self.as_bytes(0, body_len)).to_le_bytes();
222 w.write_all(self.as_bytes(0, body_len)).await?;
223 w.write_all(&self.crc).await
224 }
225
226 pub async fn read_async<R: embedded_io_async::Read>(
228 &mut self,
229 r: &mut R,
230 ) -> Result<Status, ReadError> {
231 self.sync.read_async(r).await?;
232
233 r.read_exact(self.as_bytes_mut(2, 8))
234 .await
235 .map_err(|_| ReadError)?;
236
237 if !Cmd::is_valid(self.as_bytes(2, 1)[0]) || !Status::is_valid(self.as_bytes(3, 1)[0]) {
238 return Ok(Status::Unsupported);
240 }
241
242 let data_len = self.len as usize;
243
244 if data_len > MAX_PAYLOAD {
245 return Ok(Status::PayloadOverflow);
247 }
248
249 if data_len > 0 {
250 r.read_exact(unsafe { &mut self.data.raw[..data_len] })
251 .await
252 .map_err(|_| ReadError)?;
253 }
254
255 r.read_exact(&mut self.crc).await.map_err(|_| ReadError)?;
256
257 if self.crc != crc16(CRC_INIT, self.as_bytes(0, 10 + data_len)).to_le_bytes() {
258 return Ok(Status::CrcMismatch);
259 }
260
261 Ok(Status::Ok)
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::*;
268
269 struct MockReader<'a> {
270 data: &'a [u8],
271 pos: usize,
272 }
273
274 impl<'a> MockReader<'a> {
275 fn new(data: &'a [u8]) -> Self {
276 Self { data, pos: 0 }
277 }
278 }
279
280 impl embedded_io::ErrorType for MockReader<'_> {
281 type Error = core::convert::Infallible;
282 }
283
284 impl embedded_io::Read for MockReader<'_> {
285 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
286 let n = buf.len().min(self.data.len() - self.pos);
287 buf[..n].copy_from_slice(&self.data[self.pos..self.pos + n]);
288 self.pos += n;
289 Ok(n)
290 }
291 }
292
293 struct Sink {
294 buf: [u8; 512],
295 pos: usize,
296 }
297
298 impl Sink {
299 fn new() -> Self {
300 Self {
301 buf: [0; 512],
302 pos: 0,
303 }
304 }
305 fn written(&self) -> &[u8] {
306 &self.buf[..self.pos]
307 }
308 }
309
310 impl embedded_io::ErrorType for Sink {
311 type Error = core::convert::Infallible;
312 }
313
314 impl embedded_io::Write for Sink {
315 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
316 let n = buf.len().min(self.buf.len() - self.pos);
317 self.buf[self.pos..self.pos + n].copy_from_slice(&buf[..n]);
318 self.pos += n;
319 Ok(n)
320 }
321 fn flush(&mut self) -> Result<(), Self::Error> {
322 Ok(())
323 }
324 }
325
326 fn frame(cmd: Cmd, status: Status, addr: u32, data: &[u8]) -> Frame {
327 let mut f = Frame {
328 cmd,
329 status,
330 ..Default::default()
331 };
332 f.set_addr(addr);
333 f.len = data.len() as u16;
334 unsafe { f.data.raw[..data.len()].copy_from_slice(data) };
335 f
336 }
337
338 #[test]
339 fn request_round_trip() {
340 let mut frame = frame(Cmd::Write, Status::Request, 0x0800, &[0xDE, 0xAD]);
341
342 let mut sink = Sink::new();
343 frame.send(&mut sink).unwrap();
344
345 let mut frame2 = Frame::default();
346 frame2.read(&mut MockReader::new(sink.written())).unwrap();
347 assert_eq!(frame2.cmd, Cmd::Write);
348 assert_eq!(frame2.len, 2);
349 assert_eq!(frame2.addr(), 0x0800);
350 assert_eq!(frame2.status, Status::Request);
351 assert_eq!(unsafe { &frame2.data.raw[..2] }, &[0xDE, 0xAD]);
352 }
353
354 #[test]
355 fn response_round_trip() {
356 let mut frame = frame(Cmd::Verify, Status::Ok, 0, &[0x12, 0x34]);
357
358 let mut sink = Sink::new();
359 frame.send(&mut sink).unwrap();
360
361 let mut frame2 = Frame::default();
362 frame2.read(&mut MockReader::new(sink.written())).unwrap();
363 assert_eq!(frame2.cmd, Cmd::Verify);
364 assert_eq!(frame2.status, Status::Ok);
365 assert_eq!(unsafe { &frame2.data.raw[..2] }, &[0x12, 0x34]);
366 }
367
368 #[test]
369 fn request_no_data() {
370 let mut frame = frame(Cmd::Erase, Status::Request, 0, &[]);
371
372 let mut sink = Sink::new();
373 frame.send(&mut sink).unwrap();
374
375 assert_eq!(sink.written().len(), 12);
377
378 let mut frame2 = Frame::default();
379 frame2.read(&mut MockReader::new(sink.written())).unwrap();
380 assert_eq!(frame2.cmd, Cmd::Erase);
381 assert_eq!(frame2.len, 0);
382 }
383
384 #[test]
385 fn large_addr_round_trip() {
386 let mut frame = frame(Cmd::Write, Status::Request, 0x0001_0800, &[0xAB]);
387
388 let mut sink = Sink::new();
389 frame.send(&mut sink).unwrap();
390
391 let mut frame2 = Frame::default();
392 frame2.read(&mut MockReader::new(sink.written())).unwrap();
393 assert_eq!(frame2.addr(), 0x0001_0800);
394 }
395
396 #[test]
397 fn cmd_addr_carry_over() {
398 let mut frame = frame(Cmd::Write, Status::Request, 0x0400, &[0xAB, 0xCD]);
399
400 let mut sink = Sink::new();
401 frame.send(&mut sink).unwrap();
402
403 let mut dev = Frame::default();
405 dev.read(&mut MockReader::new(sink.written())).unwrap();
406
407 dev.status = Status::Ok;
409 dev.len = 0;
410 let mut resp_sink = Sink::new();
411 dev.send(&mut resp_sink).unwrap();
412
413 let mut host = Frame::default();
415 host.read(&mut MockReader::new(resp_sink.written()))
416 .unwrap();
417 assert_eq!(host.cmd, Cmd::Write);
418 assert_eq!(host.addr(), 0x0400);
419 assert_eq!(host.status, Status::Ok);
420 }
421
422 #[test]
423 fn read_bad_cmd() {
424 let mut frame = frame(Cmd::Info, Status::Request, 0, &[]);
425
426 let mut sink = Sink::new();
427 frame.send(&mut sink).unwrap();
428 sink.buf[2] ^= 0xFF; let mut frame2 = Frame::default();
431 assert_eq!(
432 frame2.read(&mut MockReader::new(sink.written())),
433 Ok(Status::Unsupported)
434 );
435 }
436
437 #[test]
438 fn read_after_garbage() {
439 let mut frame = frame(Cmd::Verify, Status::Request, 0, &[]);
440
441 let mut sink = Sink::new();
442 frame.send(&mut sink).unwrap();
443 let frame_len = sink.pos;
444
445 let mut input = [0u8; 4 + 512];
446 input[..4].copy_from_slice(&[0xFF, 0x00, 0xAA, 0x42]);
447 input[4..4 + frame_len].copy_from_slice(&sink.buf[..frame_len]);
448
449 let mut frame2 = Frame::default();
450 assert_eq!(
451 frame2.read(&mut MockReader::new(&input[..4 + frame_len])),
452 Ok(Status::Ok)
453 );
454 assert_eq!(frame2.cmd, Cmd::Verify);
455 }
456
457 #[test]
458 fn read_overflow() {
459 let mut f = frame(Cmd::Write, Status::Request, 0, &[]);
461
462 let mut sink = Sink::new();
463 f.send(&mut sink).unwrap();
464
465 let overflow_len = (MAX_PAYLOAD as u16 + 1).to_le_bytes();
467 sink.buf[8] = overflow_len[0];
468 sink.buf[9] = overflow_len[1];
469
470 let mut frame2 = Frame::default();
471 assert_eq!(
472 frame2.read(&mut MockReader::new(sink.written())),
473 Ok(Status::PayloadOverflow)
474 );
475 }
476}