aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb-dfu/src/consts.rs
blob: 8701dabc4fe949e4de22de1bfe16863ae72e22db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! USB DFU constants, taken from
//! https://www.usb.org/sites/default/files/DFU_1.1.pdf
/// Device Firmware Upgrade class, App specific
pub(crate) const USB_CLASS_APPN_SPEC: u8 = 0xFE;
/// Device Firmware Upgrade subclass, App specific
pub(crate) const APPN_SPEC_SUBCLASS_DFU: u8 = 0x01;
#[allow(unused)]
/// USB interface alternative setting
pub(crate) const DFU_PROTOCOL_DFU: u8 = 0x02;
#[allow(unused)]
/// DFU runtime class
pub(crate) const DFU_PROTOCOL_RT: u8 = 0x01;
/// DFU functional descriptor
pub(crate) const DESC_DFU_FUNCTIONAL: u8 = 0x21;

macro_rules! define_dfu_attributes {
    ($macro:path) => {
        $macro! {
            /// Attributes supported by the DFU controller.
            pub struct DfuAttributes: u8 {
                /// Generate WillDetache sequence on bus.
                const WILL_DETACH = 0b0000_1000;
                /// Device can communicate during manifestation phase.
                const MANIFESTATION_TOLERANT = 0b0000_0100;
                /// Capable of upload.
                const CAN_UPLOAD = 0b0000_0010;
                /// Capable of download.
                const CAN_DOWNLOAD = 0b0000_0001;
            }
        }
    };
}

#[cfg(feature = "defmt")]
define_dfu_attributes!(defmt::bitflags);

#[cfg(not(feature = "defmt"))]
define_dfu_attributes!(bitflags::bitflags);

#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
#[allow(unused)]
/// An indication of the state that the device is going to enter immediately following transmission of this response.
pub(crate) enum State {
    /// Device is running its normal application.
    AppIdle = 0,
    /// Device is running its normal application, has received the DFU_DETACH request, and is waiting for a USB reset.
    AppDetach = 1,
    /// Device is operating in the DFU mode and is waiting for requests.
    DfuIdle = 2,
    /// Device has received a block and is waiting for the host to solicit the status via DFU_GETSTATUS.
    DlSync = 3,
    /// Device is programming a control-write block into its nonvolatile memories.
    DlBusy = 4,
    /// Device is processing a download operation. Expecting DFU_DNLOAD requests.
    Download = 5,
    /// Device has received the final block of firmware from the host, waits for DFU_GETSTATUS to start Manifestation phase or completed this phase
    ManifestSync = 6,
    /// Device is in the Manifestation phase. Not all devices will be able to respond to DFU_GETSTATUS when in this state.
    Manifest = 7,
    /// Device has programmed its memories and is waiting for a USB reset or a power on reset.
    ManifestWaitReset = 8,
    /// The device is processing an upload operation. Expecting DFU_UPLOAD requests.
    UploadIdle = 9,
    /// An error has occurred. Awaiting the DFU_CLRSTATUS request.
    Error = 10,
}

#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
#[allow(unused)]
/// An indication of the status resulting from the execution of the most recent request.
pub(crate) enum Status {
    /// No error
    Ok = 0x00,
    /// File is not targeted for use by this device
    ErrTarget = 0x01,
    /// File is for this device but fails some vendor-specific verification test
    ErrFile = 0x02,
    /// Device is unable to write memory
    ErrWrite = 0x03,
    /// Memory erase function failed
    ErrErase = 0x04,
    /// Memory erase check failed
    ErrCheckErased = 0x05,
    /// Program memory function failed
    ErrProg = 0x06,
    /// Programmed memory failed verification
    ErrVerify = 0x07,
    /// Cannot program memory due to received address that is out of range
    ErrAddress = 0x08,
    /// Received DFU_DNLOAD with wLength = 0, but device does not think it has all of the data yet
    ErrNotDone = 0x09,
    /// Device’s firmware is corrupt. It cannot return to run-time (non-DFU) operations
    ErrFirmware = 0x0A,
    /// iString indicates a vendor-specific error
    ErrVendor = 0x0B,
    /// Device detected unexpected USB reset signaling
    ErrUsbr = 0x0C,
    /// Device detected unexpected power on reset
    ErrPor = 0x0D,
    /// Something went wrong, but the device does not know what
    ErrUnknown = 0x0E,
    /// Device stalled an unexpected request
    ErrStalledPkt = 0x0F,
}

#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
/// DFU requests
pub(crate) enum Request {
    /// Host instructs the device to generate a detach-attach sequence
    Detach = 0,
    /// Host initiates control-write transfers with this request, and sends a DFU_DNLOAD request
    /// with  wLength = 0 to indicate that it has completed transferring the firmware image file
    Dnload = 1,
    /// The DFU_UPLOAD request is employed by the host to solicit firmware from the device.
    Upload = 2,
    /// The host employs the DFU_GETSTATUS request to facilitate synchronization with the device.
    GetStatus = 3,
    ///  Any time the device detects an error, it waits with transition until ClrStatus
    ClrStatus = 4,
    /// Requests a report about a state of the device
    GetState = 5,
    /// Enables the host to exit from certain states and return to the DFU_IDLE state
    Abort = 6,
}

impl TryFrom<u8> for Request {
    type Error = ();

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(Request::Detach),
            1 => Ok(Request::Dnload),
            2 => Ok(Request::Upload),
            3 => Ok(Request::GetStatus),
            4 => Ok(Request::ClrStatus),
            5 => Ok(Request::GetState),
            6 => Ok(Request::Abort),
            _ => Err(()),
        }
    }
}