cameleon_device/u3v/protocol/
ack.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::{io::Cursor, time};
6
7use cameleon_impl::bytes_io::ReadBytes;
8
9use crate::u3v::{Error, Result};
10
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct AckPacket<'a> {
13    ccd: AckCcd,
14    raw_scd: &'a [u8],
15}
16
17impl<'a> AckPacket<'a> {
18    const PREFIX_MAGIC: u32 = 0x4356_3355;
19
20    pub fn parse(buf: &'a (impl AsRef<[u8]> + ?Sized)) -> Result<Self> {
21        let mut cursor = Cursor::new(buf.as_ref());
22
23        Self::parse_prefix(&mut cursor)?;
24
25        let ccd = AckCcd::parse(&mut cursor)?;
26
27        let raw_scd = &cursor.get_ref()[cursor.position() as usize..];
28        Ok(Self { ccd, raw_scd })
29    }
30
31    #[must_use]
32    pub fn scd_kind(&self) -> ScdKind {
33        self.ccd.scd_kind
34    }
35
36    #[must_use]
37    pub fn ccd(&self) -> &AckCcd {
38        &self.ccd
39    }
40
41    #[must_use]
42    pub fn raw_scd(&self) -> &'a [u8] {
43        self.raw_scd
44    }
45
46    pub fn scd_as<T: ParseScd<'a>>(&self) -> Result<T> {
47        T::parse(self.raw_scd, &self.ccd)
48    }
49
50    #[must_use]
51    pub fn status(&self) -> &Status {
52        &self.ccd.status
53    }
54
55    #[must_use]
56    pub fn request_id(&self) -> u16 {
57        self.ccd.request_id
58    }
59
60    fn parse_prefix(cursor: &mut Cursor<&[u8]>) -> Result<()> {
61        let magic: u32 = cursor.read_bytes_le()?;
62        if magic == Self::PREFIX_MAGIC {
63            Ok(())
64        } else {
65            Err(Error::InvalidPacket("invalid prefix magic".into()))
66        }
67    }
68}
69
70#[derive(Clone, Debug, PartialEq, Eq)]
71pub struct AckCcd {
72    pub(crate) status: Status,
73    pub(crate) scd_kind: ScdKind,
74    pub(crate) request_id: u16,
75    pub(crate) scd_len: u16,
76}
77
78impl AckCcd {
79    #[must_use]
80    pub fn status(&self) -> Status {
81        self.status
82    }
83
84    #[must_use]
85    pub fn scd_kind(&self) -> ScdKind {
86        self.scd_kind
87    }
88
89    #[must_use]
90    pub fn request_id(&self) -> u16 {
91        self.request_id
92    }
93
94    #[must_use]
95    pub fn scd_len(&self) -> u16 {
96        self.scd_len
97    }
98
99    fn parse(cursor: &mut Cursor<&[u8]>) -> Result<Self> {
100        let status = Status::parse(cursor)?;
101        let scd_kind = ScdKind::parse(cursor)?;
102        let scd_len = cursor.read_bytes_le()?;
103        let request_id = cursor.read_bytes_le()?;
104
105        Ok(Self {
106            status,
107            scd_kind,
108            request_id,
109            scd_len,
110        })
111    }
112}
113
114#[derive(Clone, Copy, Debug, PartialEq, Eq)]
115pub struct Status {
116    pub(crate) code: u16,
117    pub(crate) kind: StatusKind,
118}
119
120#[derive(Clone, Copy, Debug, PartialEq, Eq)]
121pub enum StatusKind {
122    GenCp(GenCpStatus),
123    UsbSpecific(UsbSpecificStatus),
124    DeviceSpecific,
125}
126
127#[derive(Clone, Copy, Debug, PartialEq, Eq)]
128pub enum GenCpStatus {
129    /// Success.
130    Success,
131
132    /// Command not implemented in the device.
133    NotImplemented,
134
135    /// Command parameter of CCD or SCD is invalid.
136    InvalidParameter,
137
138    /// Attempt to access an address that doesn't exist.
139    InvalidAddress,
140
141    /// Attempt to write to a read only address.
142    WriteProtect,
143
144    /// Attempt to access an address with bad alignment.
145    BadAlignment,
146
147    /// Attempt to read unreadable address or write to unwritable address.
148    AccessDenied,
149
150    /// The command receiver is busy.
151    Busy,
152
153    /// Timeout waiting for an acknowledge.
154    Timeout,
155
156    /// Header is inconsistent with data.
157    InvalidHeader,
158
159    /// The receiver configuration does not allow the execution of the sent command.
160    WrongConfig,
161
162    /// Generic error.
163    GenericError,
164}
165
166#[derive(Clone, Copy, Debug, PartialEq, Eq)]
167pub enum UsbSpecificStatus {
168    /// Resend command is not supported by USB device.
169    ResendNotSupported,
170
171    /// Stream endpoint is halted when stream flag is set.
172    StreamEndpointHalted,
173
174    /// Command that attempts to set payload size is invalid because of bad alignment.
175    PayloadSizeNotAligned,
176
177    /// Event endpoint is halted when event enable flag is set.
178    EventEndpointHalted,
179
180    /// Command that attempts to enable stream is failed because streaming interface is invalid
181    /// state.
182    InvalidSiState,
183}
184
185impl Status {
186    #[must_use]
187    pub fn is_success(self) -> bool {
188        matches!(self.kind, StatusKind::GenCp(GenCpStatus::Success))
189    }
190
191    #[must_use]
192    pub fn is_fatal(self) -> bool {
193        self.code >> 15_i32 == 1
194    }
195
196    #[must_use]
197    pub fn code(self) -> u16 {
198        self.code
199    }
200
201    #[must_use]
202    pub fn kind(self) -> StatusKind {
203        self.kind
204    }
205
206    fn parse(cursor: &mut Cursor<&[u8]>) -> Result<Self> {
207        let code: u16 = cursor.read_bytes_le()?;
208
209        let namespace = (code >> 13_i32) & 0x11;
210        match namespace {
211            0b00 => Self::parse_gencp_status(code),
212            0b01 => Self::parse_usb_status(code),
213            0b10 => Ok(Self {
214                code,
215                kind: StatusKind::DeviceSpecific,
216            }),
217            _ => Err(Error::InvalidPacket(
218                "invalid ack status code, namespace is set to 0b11".into(),
219            )),
220        }
221    }
222
223    fn parse_gencp_status(code: u16) -> Result<Self> {
224        use GenCpStatus::{
225            AccessDenied, BadAlignment, Busy, GenericError, InvalidAddress, InvalidHeader,
226            InvalidParameter, NotImplemented, Success, Timeout, WriteProtect, WrongConfig,
227        };
228
229        debug_assert!((code >> 13).trailing_zeros() >= 2);
230
231        let status = match code {
232            0x0000 => Success,
233            0x8001 => NotImplemented,
234            0x8002 => InvalidParameter,
235            0x8003 => InvalidAddress,
236            0x8004 => WriteProtect,
237            0x8005 => BadAlignment,
238            0x8006 => AccessDenied,
239            0x8007 => Busy,
240            0x800B => Timeout,
241            0x800E => InvalidHeader,
242            0x800F => WrongConfig,
243            0x8FFF => GenericError,
244            _ => {
245                return Err(Error::InvalidPacket(
246                    format! {"invalid gencp status code {:#X}", code}.into(),
247                ))
248            }
249        };
250
251        Ok(Self {
252            code,
253            kind: StatusKind::GenCp(status),
254        })
255    }
256
257    fn parse_usb_status(code: u16) -> Result<Self> {
258        use UsbSpecificStatus::{
259            EventEndpointHalted, InvalidSiState, PayloadSizeNotAligned, ResendNotSupported,
260            StreamEndpointHalted,
261        };
262
263        debug_assert!(code >> 13_i32 & 0b11 == 0b01);
264
265        let status = match code {
266            0xA001 => ResendNotSupported,
267            0xA002 => StreamEndpointHalted,
268            0xA003 => PayloadSizeNotAligned,
269            0xA004 => InvalidSiState,
270            0xA005 => EventEndpointHalted,
271            _ => {
272                return Err(Error::InvalidPacket(
273                    format! {"invalid usb status code {:#X}", code}.into(),
274                ))
275            }
276        };
277
278        Ok(Self {
279            code,
280            kind: StatusKind::UsbSpecific(status),
281        })
282    }
283}
284
285#[derive(Clone, Copy, Debug, PartialEq, Eq)]
286pub enum ScdKind {
287    ReadMem,
288    WriteMem,
289    ReadMemStacked,
290    WriteMemStacked,
291    Pending,
292}
293
294impl ScdKind {
295    fn parse(cursor: &mut Cursor<&[u8]>) -> Result<Self> {
296        let id: u16 = cursor.read_bytes_le()?;
297        match id {
298            0x0801 => Ok(ScdKind::ReadMem),
299            0x0803 => Ok(ScdKind::WriteMem),
300            0x0805 => Ok(ScdKind::Pending),
301            0x0807 => Ok(ScdKind::ReadMemStacked),
302            0x0809 => Ok(ScdKind::WriteMemStacked),
303            _ => Err(Error::InvalidPacket(
304                format!("unknown ack command id {:#X}", id).into(),
305            )),
306        }
307    }
308}
309
310pub trait ParseScd<'a>: Sized {
311    fn parse(buf: &'a [u8], ccd: &AckCcd) -> Result<Self>;
312}
313
314pub struct ReadMem<'a> {
315    pub data: &'a [u8],
316}
317
318pub struct WriteMem {
319    pub length: u16,
320}
321
322pub struct Pending {
323    pub timeout: time::Duration,
324}
325
326pub struct ReadMemStacked<'a> {
327    pub data: &'a [u8],
328}
329
330pub struct WriteMemStacked {
331    pub lengths: Vec<u16>,
332}
333
334pub struct CustomAck<'a> {
335    pub data: &'a [u8],
336}
337
338impl<'a> ParseScd<'a> for ReadMem<'a> {
339    fn parse(buf: &'a [u8], ccd: &AckCcd) -> Result<Self> {
340        let scd_len = ccd.scd_len() as usize;
341        if buf.len() < scd_len {
342            return Err(Error::InvalidPacket(
343                "SCD length is smaller than specified length in CCD".into(),
344            ));
345        }
346        let data = &buf[..scd_len];
347        Ok(Self { data })
348    }
349}
350
351impl<'a> ParseScd<'a> for WriteMem {
352    fn parse(buf: &'a [u8], _ccd: &AckCcd) -> Result<Self> {
353        let mut cursor = Cursor::new(buf);
354        let reserved: u16 = cursor.read_bytes_le()?;
355        if reserved != 0 {
356            return Err(Error::InvalidPacket(
357                "the first two bytes of WriteMemAck scd must be set to zero".into(),
358            ));
359        }
360
361        let length = cursor.read_bytes_le()?;
362        Ok(Self { length })
363    }
364}
365
366impl<'a> ParseScd<'a> for Pending {
367    fn parse(buf: &'a [u8], _ccd: &AckCcd) -> Result<Self> {
368        let mut cursor = Cursor::new(buf);
369        let reserved: u16 = cursor.read_bytes_le()?;
370        if reserved != 0 {
371            return Err(Error::InvalidPacket(
372                "the first two bytes of PendingAck scd must be set to zero".into(),
373            ));
374        }
375
376        let timeout_ms: u16 = cursor.read_bytes_le()?;
377        let timeout = time::Duration::from_millis(timeout_ms.into());
378        Ok(Self { timeout })
379    }
380}
381
382impl<'a> ParseScd<'a> for ReadMemStacked<'a> {
383    fn parse(buf: &'a [u8], ccd: &AckCcd) -> Result<Self> {
384        let scd_len = ccd.scd_len() as usize;
385        if buf.len() < scd_len {
386            return Err(Error::InvalidPacket(
387                "SCD length is smaller than specified length in CCD".into(),
388            ));
389        }
390        let data = &buf[..scd_len];
391        Ok(Self { data })
392    }
393}
394
395impl<'a> ParseScd<'a> for WriteMemStacked {
396    fn parse(buf: &'a [u8], ccd: &AckCcd) -> Result<Self> {
397        let mut cursor = Cursor::new(buf);
398        let mut to_read = ccd.scd_len as usize;
399        let mut lengths = Vec::with_capacity(to_read / 4);
400
401        while to_read > 0 {
402            let reserved: u16 = cursor.read_bytes_le()?;
403            if reserved != 0 {
404                return Err(Error::InvalidPacket(
405                    "the first two bytes of each WriteMemStackedAck SCD must be set to zero".into(),
406                ));
407            }
408            let length = cursor.read_bytes_le()?;
409            lengths.push(length);
410            to_read -= 4;
411        }
412
413        Ok(Self { lengths })
414    }
415}
416
417#[cfg(test)]
418mod tests {
419    use super::*;
420    use cameleon_impl::bytes_io::WriteBytes;
421
422    fn serialize_header(
423        status_code: u16,
424        command_id: u16,
425        scd_len: u16,
426        request_id: u16,
427    ) -> Vec<u8> {
428        let mut ccd = vec![];
429        ccd.write_bytes_le(0x4356_3355_u32).unwrap();
430        ccd.write_bytes_le(status_code).unwrap();
431        ccd.write_bytes_le(command_id).unwrap();
432        ccd.write_bytes_le(scd_len).unwrap();
433        ccd.write_bytes_le(request_id).unwrap();
434        ccd
435    }
436
437    #[test]
438    fn test_read_mem_ack() {
439        let scd = &[0x01, 0x02, 0x03, 0x04];
440        let mut raw_packet = serialize_header(0x0000, 0x0801, scd.len() as u16, 1);
441        raw_packet.extend(scd);
442
443        let ack = AckPacket::parse(&raw_packet).unwrap();
444        assert!(ack.status().is_success());
445        assert!(!ack.status().is_fatal());
446        assert_eq!(ack.request_id(), 1);
447
448        let parsed_scd = ack.scd_as::<ReadMem>().unwrap();
449        assert_eq!(parsed_scd.data, scd);
450    }
451
452    #[test]
453    fn test_write_mem_ack() {
454        let scd = &[0x00, 0x00, 0x0a, 0x00]; // Written length is 10.
455        let mut raw_packet = serialize_header(0x0000, 0x0803, scd.len() as u16, 1);
456        raw_packet.extend(scd);
457
458        let ack = AckPacket::parse(&raw_packet).unwrap();
459        assert_eq!(ack.status().code(), 0x0000);
460        assert!(ack.status().is_success());
461        assert!(!ack.status().is_fatal());
462        assert_eq!(ack.request_id(), 1);
463
464        let parsed_scd = ack.scd_as::<WriteMem>().unwrap();
465        assert_eq!(parsed_scd.length, 0x0a);
466    }
467
468    #[test]
469    fn test_read_mem_stacked_ack() {
470        let scd = &[0x01, 0x02, 0x03, 0x04];
471        let mut raw_packet = serialize_header(0x0000, 0x0807, scd.len() as u16, 1);
472        raw_packet.extend(scd);
473
474        let ack = AckPacket::parse(&raw_packet).unwrap();
475        assert_eq!(ack.status().code(), 0x0000);
476        assert!(ack.status().is_success());
477        assert!(!ack.status().is_fatal());
478        assert_eq!(ack.request_id(), 1);
479
480        let parsed_scd = ack.scd_as::<ReadMemStacked>().unwrap();
481        assert_eq!(parsed_scd.data, scd);
482    }
483
484    #[test]
485    fn test_write_mem_stacked_ack() {
486        let mut scd = vec![0x00, 0x00, 0x03, 0x00]; // Written length 0: 3 bytes written.
487        scd.extend([0x00, 0x00, 0x0a, 0x00]); // Written length 1: 10 bytes written.
488        let mut raw_packet = serialize_header(0x0000, 0x0809, scd.len() as u16, 1);
489        raw_packet.extend(&scd);
490
491        let ack = AckPacket::parse(&raw_packet).unwrap();
492        assert_eq!(ack.status().code(), 0x0000);
493        assert!(ack.status().is_success());
494        assert!(!ack.status().is_fatal());
495        assert_eq!(ack.request_id(), 1);
496
497        let parsed_scd = ack.scd_as::<WriteMemStacked>().unwrap();
498        assert_eq!(&parsed_scd.lengths, &[3, 10]);
499    }
500
501    #[test]
502    fn test_pending_ack() {
503        use std::time::Duration;
504
505        let scd = &[0x00, 0x00, 0xbc, 0x02]; // Timeout is 700 ms.
506        let mut raw_packet = serialize_header(0x0000, 0x0805, scd.len() as u16, 1);
507        raw_packet.extend(scd);
508
509        let ack = AckPacket::parse(&raw_packet).unwrap();
510        assert_eq!(ack.status().code(), 0x0000);
511        assert!(ack.status().is_success());
512        assert!(!ack.status().is_fatal());
513        assert_eq!(ack.request_id(), 1);
514
515        let parsed_scd = ack.scd_as::<Pending>().unwrap();
516        assert_eq!(parsed_scd.timeout, Duration::from_millis(700));
517    }
518
519    #[test]
520    fn test_gencp_error_status() {
521        let mut code_buf = vec![0; 2];
522
523        code_buf.as_mut_slice().write_bytes_le(0x800F_u16).unwrap();
524        let mut code = Cursor::new(code_buf.as_slice());
525        let status = Status::parse(&mut code).unwrap();
526        assert!(!status.is_success());
527        assert!(status.is_fatal());
528    }
529
530    #[test]
531    fn test_usb_error_status() {
532        let mut code_buf = vec![0; 2];
533
534        code_buf.as_mut_slice().write_bytes_le(0xA001_u16).unwrap();
535        let mut code = Cursor::new(code_buf.as_slice());
536        let status = Status::parse(&mut code).unwrap();
537        assert!(!status.is_success());
538        assert!(status.is_fatal());
539        match status.kind {
540            StatusKind::UsbSpecific(..) => {}
541            _ => panic!("must be USB specific error status"),
542        }
543    }
544}