1use crate::with_unknown;
6use anyhow::Result;
7use zerocopy::{FromBytes, Immutable, IntoBytes};
8
9with_unknown! {
10 #[derive(FromBytes, Immutable, IntoBytes)]
11 pub enum DfuState: u8 [default = Self::AppIdle] {
12 AppIdle = 0,
13 AppDetach= 1,
14 Idle = 2,
15 DnLoadSync = 3,
16 DnLoadBusy = 4,
17 DnLoadIdle = 5,
18 ManifestSync = 6,
19 Manifest = 7,
20 ManifestWaitReset = 8,
21 UpLoadIdle = 9,
22 Error = 10,
23 }
24}
25
26with_unknown! {
27 #[derive(FromBytes, Immutable, IntoBytes)]
28 pub enum DfuError: u8 [default = Self::Ok] {
29 Ok = 0,
30 Target = 1,
31 File = 2,
32 Write = 3,
33 Erase = 4,
34 CheckErased = 5,
35 Prog = 6,
36 Verify = 7,
37 Address = 8,
38 NotDone = 9,
39 Firmware = 10,
40 Vendor = 11,
41 UsbReset = 12,
42 PowerOnReset = 13,
43 Unknown = 14,
44 StalledPkt = 15,
45 }
46}
47
48with_unknown! {
49 pub enum DfuRequest: u8 {
50 Detach = 0,
51 DnLoad = 1,
52 UpLoad = 2,
53 GetStatus = 3,
54 ClrStatus = 4,
55 GetState = 5,
56 Abort = 6,
57 BusReset = 7,
58 }
59}
60
61#[derive(Clone, Copy)]
62#[repr(u8)]
63pub enum DfuRequestType {
64 Out = 0x21, In = 0xA1, Vendor = 0x40, }
68
69impl From<DfuRequestType> for u8 {
70 fn from(val: DfuRequestType) -> Self {
71 val as u8
72 }
73}
74
75#[derive(Clone, FromBytes, Immutable, IntoBytes, Default)]
76#[repr(C)]
77pub struct DfuStatus {
78 status: DfuError,
79 poll_timeout: [u8; 3],
80 state: DfuState,
81 string: u8,
82}
83
84impl std::error::Error for DfuError {}
85
86impl DfuStatus {
87 pub fn status(&self) -> std::result::Result<(), DfuError> {
88 match self.status {
89 DfuError::Ok => Ok(()),
90 e => Err(e),
91 }
92 }
93 pub fn poll_timeout(&self) -> u32 {
94 u32::from_le_bytes([
95 self.poll_timeout[0],
96 self.poll_timeout[1],
97 self.poll_timeout[2],
98 0,
99 ])
100 }
101 pub fn state(&self) -> DfuState {
102 self.state
103 }
104 pub fn string(&self) -> u8 {
105 self.string
106 }
107}
108
109pub trait DfuOperations {
110 fn write_control(
111 &self,
112 request_type: u8,
113 request: u8,
114 value: u16,
115 index: u16,
116 data: &[u8],
117 ) -> Result<usize>;
118
119 fn read_control(
120 &self,
121 request_type: u8,
122 request: u8,
123 value: u16,
124 index: u16,
125 data: &mut [u8],
126 ) -> Result<usize>;
127
128 fn get_interface(&self) -> u8;
129
130 fn download(&self, data: &[u8]) -> Result<usize> {
132 self.write_control(
133 DfuRequestType::Out.into(),
134 DfuRequest::DnLoad.into(),
135 0,
136 self.get_interface() as u16,
137 data,
138 )
139 }
140
141 fn upload(&self, data: &mut [u8]) -> Result<usize> {
143 self.read_control(
144 DfuRequestType::In.into(),
145 DfuRequest::UpLoad.into(),
146 0,
147 self.get_interface() as u16,
148 data,
149 )
150 }
151
152 fn get_state(&self) -> Result<DfuState> {
154 let mut buffer = [0u8];
155 self.read_control(
156 DfuRequestType::In.into(),
157 DfuRequest::GetState.into(),
158 0,
159 self.get_interface() as u16,
160 &mut buffer,
161 )?;
162 Ok(DfuState(buffer[0]))
163 }
164
165 fn get_status(&self) -> Result<DfuStatus> {
167 let mut status = DfuStatus::default();
168 self.read_control(
169 DfuRequestType::In.into(),
170 DfuRequest::GetStatus.into(),
171 0,
172 self.get_interface() as u16,
173 status.as_mut_bytes(),
174 )?;
175 Ok(status)
176 }
177
178 fn clear_status(&self) -> Result<()> {
180 self.write_control(
181 DfuRequestType::Out.into(),
182 DfuRequest::ClrStatus.into(),
183 0,
184 self.get_interface() as u16,
185 &[],
186 )?;
187 Ok(())
188 }
189
190 fn abort(&self) -> Result<()> {
192 self.write_control(
193 DfuRequestType::Out.into(),
194 DfuRequest::Abort.into(),
195 0,
196 self.get_interface() as u16,
197 &[],
198 )?;
199 Ok(())
200 }
201}