umsh_ulcp/
dfu.rs

1//! Bootloader modes selected by `CMD_DFU`.
2
3use crate::Status;
4
5#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
6#[repr(u8)]
7pub enum DfuMode {
8    /// The platform's fixed default, independent of the current transport.
9    #[default]
10    Default = 0,
11    Serial = 1,
12    Uf2 = 2,
13    Ble = 3,
14}
15
16impl DfuMode {
17    pub fn parse(payload: &[u8]) -> Result<Self, Status> {
18        match payload {
19            [] | [0] => Ok(Self::Default),
20            [1] => Ok(Self::Serial),
21            [2] => Ok(Self::Uf2),
22            [3] => Ok(Self::Ble),
23            [_] => Err(Status::INVALID_ARGUMENT),
24            _ => Err(Status::PARSE_ERROR),
25        }
26    }
27}
28
29#[cfg(test)]
30mod tests {
31    use super::*;
32    use crate::{Frame, frame};
33
34    #[test]
35    fn optional_mode_and_invalid_payloads() {
36        let mut buf = [0; 8];
37        for mode in [
38            None,
39            Some(DfuMode::Default),
40            Some(DfuMode::Serial),
41            Some(DfuMode::Uf2),
42            Some(DfuMode::Ble),
43        ] {
44            let len = frame::dfu(&mut buf, 3, mode).unwrap();
45            let request = Frame::parse(&buf[..len]).unwrap();
46            assert_eq!(request.command(), Some(frame::Cmd::Dfu));
47            assert_eq!(request.header.tid(), 3);
48            assert_eq!(
49                DfuMode::parse(request.payload),
50                Ok(mode.unwrap_or_default())
51            );
52            assert_eq!(request.payload.len(), usize::from(mode.is_some()));
53        }
54        for value in 4..=255 {
55            assert_eq!(DfuMode::parse(&[value]), Err(Status::INVALID_ARGUMENT));
56        }
57        assert_eq!(DfuMode::parse(&[0, 0]), Err(Status::PARSE_ERROR));
58    }
59}