aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb-dfu/src
diff options
context:
space:
mode:
authorKaitlyn Kenwell <[email protected]>2023-12-14 09:36:22 -0500
committerKaitlyn Kenwell <[email protected]>2023-12-14 09:36:22 -0500
commite27e00f6280683293f427d0731aa69ca32dbbe60 (patch)
treee238a3ed8fda1b7c89c27864b62d387786e75925 /embassy-usb-dfu/src
parentb60b3f4eb8f22ecda1c30d63213010f1b6b47686 (diff)
Address reviews
Diffstat (limited to 'embassy-usb-dfu/src')
-rw-r--r--embassy-usb-dfu/src/application.rs36
-rw-r--r--embassy-usb-dfu/src/bootloader.rs8
-rw-r--r--embassy-usb-dfu/src/fmt.rs258
-rw-r--r--embassy-usb-dfu/src/lib.rs1
4 files changed, 279 insertions, 24 deletions
diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs
index 2e7bda121..0b7b53af8 100644
--- a/embassy-usb-dfu/src/application.rs
+++ b/embassy-usb-dfu/src/application.rs
@@ -1,4 +1,4 @@
1use embassy_boot::BlockingFirmwareUpdater; 1use embassy_boot::BlockingFirmwareState;
2use embassy_time::{Duration, Instant}; 2use embassy_time::{Duration, Instant};
3use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; 3use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
4use embassy_usb::driver::Driver; 4use embassy_usb::driver::Driver;
@@ -11,18 +11,18 @@ use crate::consts::{
11}; 11};
12 12
13/// Internal state for the DFU class 13/// Internal state for the DFU class
14pub struct Control<'d, DFU: NorFlash, STATE: NorFlash> { 14pub struct Control<'d, STATE: NorFlash> {
15 updater: BlockingFirmwareUpdater<'d, DFU, STATE>, 15 firmware_state: BlockingFirmwareState<'d, STATE>,
16 attrs: DfuAttributes, 16 attrs: DfuAttributes,
17 state: State, 17 state: State,
18 timeout: Option<Duration>, 18 timeout: Option<Duration>,
19 detach_start: Option<Instant>, 19 detach_start: Option<Instant>,
20} 20}
21 21
22impl<'d, DFU: NorFlash, STATE: NorFlash> Control<'d, DFU, STATE> { 22impl<'d, STATE: NorFlash> Control<'d, STATE> {
23 pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self { 23 pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self {
24 Control { 24 Control {
25 updater, 25 firmware_state,
26 attrs, 26 attrs,
27 state: State::AppIdle, 27 state: State::AppIdle,
28 detach_start: None, 28 detach_start: None,
@@ -31,19 +31,20 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Control<'d, DFU, STATE> {
31 } 31 }
32} 32}
33 33
34impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> { 34impl<'d, STATE: NorFlash> Handler for Control<'d, STATE> {
35 fn reset(&mut self) { 35 fn reset(&mut self) {
36 if let Some(start) = self.detach_start { 36 if let Some(start) = self.detach_start {
37 let delta = Instant::now() - start; 37 let delta = Instant::now() - start;
38 let timeout = self.timeout.unwrap(); 38 let timeout = self.timeout.unwrap();
39 #[cfg(feature = "defmt")] 39 trace!(
40 defmt::info!(
41 "Received RESET with delta = {}, timeout = {}", 40 "Received RESET with delta = {}, timeout = {}",
42 delta.as_millis(), 41 delta.as_millis(),
43 timeout.as_millis() 42 timeout.as_millis()
44 ); 43 );
45 if delta < timeout { 44 if delta < timeout {
46 self.updater.mark_dfu().expect("Failed to mark DFU mode in bootloader"); 45 self.firmware_state
46 .mark_dfu()
47 .expect("Failed to mark DFU mode in bootloader");
47 cortex_m::asm::dsb(); 48 cortex_m::asm::dsb();
48 cortex_m::peripheral::SCB::sys_reset(); 49 cortex_m::peripheral::SCB::sys_reset();
49 } 50 }
@@ -59,13 +60,11 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> {
59 return None; 60 return None;
60 } 61 }
61 62
62 #[cfg(feature = "defmt")] 63 trace!("Received request {}", req);
63 defmt::info!("Received request {}", req);
64 64
65 match Request::try_from(req.request) { 65 match Request::try_from(req.request) {
66 Ok(Request::Detach) => { 66 Ok(Request::Detach) => {
67 #[cfg(feature = "defmt")] 67 trace!("Received DETACH, awaiting USB reset");
68 defmt::info!("Received DETACH, awaiting USB reset");
69 self.detach_start = Some(Instant::now()); 68 self.detach_start = Some(Instant::now());
70 self.timeout = Some(Duration::from_millis(req.value as u64)); 69 self.timeout = Some(Duration::from_millis(req.value as u64));
71 self.state = State::AppDetach; 70 self.state = State::AppDetach;
@@ -84,8 +83,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> {
84 return None; 83 return None;
85 } 84 }
86 85
87 #[cfg(feature = "defmt")] 86 trace!("Received request {}", req);
88 defmt::info!("Received request {}", req);
89 87
90 match Request::try_from(req.request) { 88 match Request::try_from(req.request) {
91 Ok(Request::GetStatus) => { 89 Ok(Request::GetStatus) => {
@@ -106,13 +104,11 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> {
106/// it should expose a DFU device, and a software reset will be issued. 104/// it should expose a DFU device, and a software reset will be issued.
107/// 105///
108/// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host. 106/// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host.
109pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash>( 107pub fn usb_dfu<'d, D: Driver<'d>, STATE: NorFlash>(
110 builder: &mut Builder<'d, D>, 108 builder: &mut Builder<'d, D>,
111 handler: &'d mut Control<'d, DFU, STATE>, 109 handler: &'d mut Control<'d, STATE>,
112 timeout: Duration, 110 timeout: Duration,
113) { 111) {
114 #[cfg(feature = "defmt")]
115 defmt::info!("Application USB DFU initializing");
116 let mut func = builder.function(0x00, 0x00, 0x00); 112 let mut func = builder.function(0x00, 0x00, 0x00);
117 let mut iface = func.interface(); 113 let mut iface = func.interface();
118 let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_RT, None); 114 let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_RT, None);
diff --git a/embassy-usb-dfu/src/bootloader.rs b/embassy-usb-dfu/src/bootloader.rs
index 215058932..99384d961 100644
--- a/embassy-usb-dfu/src/bootloader.rs
+++ b/embassy-usb-dfu/src/bootloader.rs
@@ -1,4 +1,4 @@
1use embassy_boot::BlockingFirmwareUpdater; 1use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater};
2use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; 2use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
3use embassy_usb::driver::Driver; 3use embassy_usb::driver::Driver;
4use embassy_usb::{Builder, Handler}; 4use embassy_usb::{Builder, Handler};
@@ -56,8 +56,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Co
56 self.offset = 0; 56 self.offset = 0;
57 } 57 }
58 58
59 let mut buf = [0; BLOCK_SIZE]; 59 let mut buf = AlignedBuffer([0; BLOCK_SIZE]);
60 buf[..data.len()].copy_from_slice(data); 60 buf.as_mut()[..data.len()].copy_from_slice(data);
61 61
62 if req.length == 0 { 62 if req.length == 0 {
63 match self.updater.mark_updated() { 63 match self.updater.mark_updated() {
@@ -85,7 +85,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Co
85 self.state = State::Error; 85 self.state = State::Error;
86 return Some(OutResponse::Rejected); 86 return Some(OutResponse::Rejected);
87 } 87 }
88 match self.updater.write_firmware(self.offset, &buf[..]) { 88 match self.updater.write_firmware(self.offset, buf.as_ref()) {
89 Ok(_) => { 89 Ok(_) => {
90 self.status = Status::Ok; 90 self.status = Status::Ok;
91 self.state = State::DlSync; 91 self.state = State::DlSync;
diff --git a/embassy-usb-dfu/src/fmt.rs b/embassy-usb-dfu/src/fmt.rs
new file mode 100644
index 000000000..78e583c1c
--- /dev/null
+++ b/embassy-usb-dfu/src/fmt.rs
@@ -0,0 +1,258 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4use core::fmt::{Debug, Display, LowerHex};
5
6#[cfg(all(feature = "defmt", feature = "log"))]
7compile_error!("You may not enable both `defmt` and `log` features.");
8
9macro_rules! assert {
10 ($($x:tt)*) => {
11 {
12 #[cfg(not(feature = "defmt"))]
13 ::core::assert!($($x)*);
14 #[cfg(feature = "defmt")]
15 ::defmt::assert!($($x)*);
16 }
17 };
18}
19
20macro_rules! assert_eq {
21 ($($x:tt)*) => {
22 {
23 #[cfg(not(feature = "defmt"))]
24 ::core::assert_eq!($($x)*);
25 #[cfg(feature = "defmt")]
26 ::defmt::assert_eq!($($x)*);
27 }
28 };
29}
30
31macro_rules! assert_ne {
32 ($($x:tt)*) => {
33 {
34 #[cfg(not(feature = "defmt"))]
35 ::core::assert_ne!($($x)*);
36 #[cfg(feature = "defmt")]
37 ::defmt::assert_ne!($($x)*);
38 }
39 };
40}
41
42macro_rules! debug_assert {
43 ($($x:tt)*) => {
44 {
45 #[cfg(not(feature = "defmt"))]
46 ::core::debug_assert!($($x)*);
47 #[cfg(feature = "defmt")]
48 ::defmt::debug_assert!($($x)*);
49 }
50 };
51}
52
53macro_rules! debug_assert_eq {
54 ($($x:tt)*) => {
55 {
56 #[cfg(not(feature = "defmt"))]
57 ::core::debug_assert_eq!($($x)*);
58 #[cfg(feature = "defmt")]
59 ::defmt::debug_assert_eq!($($x)*);
60 }
61 };
62}
63
64macro_rules! debug_assert_ne {
65 ($($x:tt)*) => {
66 {
67 #[cfg(not(feature = "defmt"))]
68 ::core::debug_assert_ne!($($x)*);
69 #[cfg(feature = "defmt")]
70 ::defmt::debug_assert_ne!($($x)*);
71 }
72 };
73}
74
75macro_rules! todo {
76 ($($x:tt)*) => {
77 {
78 #[cfg(not(feature = "defmt"))]
79 ::core::todo!($($x)*);
80 #[cfg(feature = "defmt")]
81 ::defmt::todo!($($x)*);
82 }
83 };
84}
85
86#[cfg(not(feature = "defmt"))]
87macro_rules! unreachable {
88 ($($x:tt)*) => {
89 ::core::unreachable!($($x)*)
90 };
91}
92
93#[cfg(feature = "defmt")]
94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*)
97 };
98}
99
100macro_rules! panic {
101 ($($x:tt)*) => {
102 {
103 #[cfg(not(feature = "defmt"))]
104 ::core::panic!($($x)*);
105 #[cfg(feature = "defmt")]
106 ::defmt::panic!($($x)*);
107 }
108 };
109}
110
111macro_rules! trace {
112 ($s:literal $(, $x:expr)* $(,)?) => {
113 {
114 #[cfg(feature = "log")]
115 ::log::trace!($s $(, $x)*);
116 #[cfg(feature = "defmt")]
117 ::defmt::trace!($s $(, $x)*);
118 #[cfg(not(any(feature = "log", feature="defmt")))]
119 let _ = ($( & $x ),*);
120 }
121 };
122}
123
124macro_rules! debug {
125 ($s:literal $(, $x:expr)* $(,)?) => {
126 {
127 #[cfg(feature = "log")]
128 ::log::debug!($s $(, $x)*);
129 #[cfg(feature = "defmt")]
130 ::defmt::debug!($s $(, $x)*);
131 #[cfg(not(any(feature = "log", feature="defmt")))]
132 let _ = ($( & $x ),*);
133 }
134 };
135}
136
137macro_rules! info {
138 ($s:literal $(, $x:expr)* $(,)?) => {
139 {
140 #[cfg(feature = "log")]
141 ::log::info!($s $(, $x)*);
142 #[cfg(feature = "defmt")]
143 ::defmt::info!($s $(, $x)*);
144 #[cfg(not(any(feature = "log", feature="defmt")))]
145 let _ = ($( & $x ),*);
146 }
147 };
148}
149
150macro_rules! warn {
151 ($s:literal $(, $x:expr)* $(,)?) => {
152 {
153 #[cfg(feature = "log")]
154 ::log::warn!($s $(, $x)*);
155 #[cfg(feature = "defmt")]
156 ::defmt::warn!($s $(, $x)*);
157 #[cfg(not(any(feature = "log", feature="defmt")))]
158 let _ = ($( & $x ),*);
159 }
160 };
161}
162
163macro_rules! error {
164 ($s:literal $(, $x:expr)* $(,)?) => {
165 {
166 #[cfg(feature = "log")]
167 ::log::error!($s $(, $x)*);
168 #[cfg(feature = "defmt")]
169 ::defmt::error!($s $(, $x)*);
170 #[cfg(not(any(feature = "log", feature="defmt")))]
171 let _ = ($( & $x ),*);
172 }
173 };
174}
175
176#[cfg(feature = "defmt")]
177macro_rules! unwrap {
178 ($($x:tt)*) => {
179 ::defmt::unwrap!($($x)*)
180 };
181}
182
183#[cfg(not(feature = "defmt"))]
184macro_rules! unwrap {
185 ($arg:expr) => {
186 match $crate::fmt::Try::into_result($arg) {
187 ::core::result::Result::Ok(t) => t,
188 ::core::result::Result::Err(e) => {
189 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
190 }
191 }
192 };
193 ($arg:expr, $($msg:expr),+ $(,)? ) => {
194 match $crate::fmt::Try::into_result($arg) {
195 ::core::result::Result::Ok(t) => t,
196 ::core::result::Result::Err(e) => {
197 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
198 }
199 }
200 }
201}
202
203#[derive(Debug, Copy, Clone, Eq, PartialEq)]
204pub struct NoneError;
205
206pub trait Try {
207 type Ok;
208 type Error;
209 fn into_result(self) -> Result<Self::Ok, Self::Error>;
210}
211
212impl<T> Try for Option<T> {
213 type Ok = T;
214 type Error = NoneError;
215
216 #[inline]
217 fn into_result(self) -> Result<T, NoneError> {
218 self.ok_or(NoneError)
219 }
220}
221
222impl<T, E> Try for Result<T, E> {
223 type Ok = T;
224 type Error = E;
225
226 #[inline]
227 fn into_result(self) -> Self {
228 self
229 }
230}
231
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-usb-dfu/src/lib.rs b/embassy-usb-dfu/src/lib.rs
index 81ef041f8..ae0fbbd4c 100644
--- a/embassy-usb-dfu/src/lib.rs
+++ b/embassy-usb-dfu/src/lib.rs
@@ -1,4 +1,5 @@
1#![no_std] 1#![no_std]
2mod fmt;
2 3
3pub mod consts; 4pub mod consts;
4 5