aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaitlyn Kenwell <[email protected]>2023-12-14 13:29:26 -0500
committerKaitlyn Kenwell <[email protected]>2023-12-14 13:29:26 -0500
commit9f9f6e75bb3ef6d285ebed88a20ab57fb55f3d07 (patch)
tree2a40c219cee9f20cd3b4e3d2b0067b0ba89c4a63
parentcbc8ccc51e8e747fab51ac377225495cd24eb447 (diff)
Abstract chip reset logic, add Reset impls for cortex-m and esp32c3
-rw-r--r--embassy-usb-dfu/Cargo.toml5
-rw-r--r--embassy-usb-dfu/src/application.rs17
-rw-r--r--embassy-usb-dfu/src/bootloader.rs19
-rw-r--r--embassy-usb-dfu/src/lib.rs31
-rw-r--r--examples/boot/application/stm32wb-dfu/Cargo.toml2
-rw-r--r--examples/boot/application/stm32wb-dfu/src/main.rs4
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/Cargo.toml2
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/src/main.rs4
8 files changed, 64 insertions, 20 deletions
diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml
index 62398afbc..02146c646 100644
--- a/embassy-usb-dfu/Cargo.toml
+++ b/embassy-usb-dfu/Cargo.toml
@@ -15,15 +15,16 @@ categories = [
15 15
16[dependencies] 16[dependencies]
17bitflags = "2.4.1" 17bitflags = "2.4.1"
18cortex-m = { version = "0.7.7", features = ["inline-asm"] } 18cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true }
19defmt = { version = "0.3.5", optional = true } 19defmt = { version = "0.3.5", optional = true }
20embassy-boot = { version = "0.1.1", path = "../embassy-boot/boot" } 20embassy-boot = { version = "0.1.1", path = "../embassy-boot/boot" }
21embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } 21# embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
22embassy-futures = { version = "0.1.1", path = "../embassy-futures" } 22embassy-futures = { version = "0.1.1", path = "../embassy-futures" }
23embassy-sync = { version = "0.5.0", path = "../embassy-sync" } 23embassy-sync = { version = "0.5.0", path = "../embassy-sync" }
24embassy-time = { version = "0.2.0", path = "../embassy-time" } 24embassy-time = { version = "0.2.0", path = "../embassy-time" }
25embassy-usb = { version = "0.1.0", path = "../embassy-usb", default-features = false } 25embassy-usb = { version = "0.1.0", path = "../embassy-usb", default-features = false }
26embedded-storage = { version = "0.3.1" } 26embedded-storage = { version = "0.3.1" }
27esp32c3-hal = { version = "0.13.0", optional = true, default-features = false }
27 28
28[features] 29[features]
29bootloader = [] 30bootloader = []
diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs
index 5ff8f90f8..75689db26 100644
--- a/embassy-usb-dfu/src/application.rs
+++ b/embassy-usb-dfu/src/application.rs
@@ -1,3 +1,5 @@
1use core::marker::PhantomData;
2
1use embassy_boot::BlockingFirmwareState; 3use embassy_boot::BlockingFirmwareState;
2use embassy_time::{Duration, Instant}; 4use embassy_time::{Duration, Instant};
3use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; 5use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
@@ -9,17 +11,19 @@ use crate::consts::{
9 DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_RT, 11 DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_RT,
10 USB_CLASS_APPN_SPEC, 12 USB_CLASS_APPN_SPEC,
11}; 13};
14use crate::Reset;
12 15
13/// Internal state for the DFU class 16/// Internal state for the DFU class
14pub struct Control<'d, STATE: NorFlash> { 17pub struct Control<'d, STATE: NorFlash, RST: Reset> {
15 firmware_state: BlockingFirmwareState<'d, STATE>, 18 firmware_state: BlockingFirmwareState<'d, STATE>,
16 attrs: DfuAttributes, 19 attrs: DfuAttributes,
17 state: State, 20 state: State,
18 timeout: Option<Duration>, 21 timeout: Option<Duration>,
19 detach_start: Option<Instant>, 22 detach_start: Option<Instant>,
23 _rst: PhantomData<RST>,
20} 24}
21 25
22impl<'d, STATE: NorFlash> Control<'d, STATE> { 26impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> {
23 pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self { 27 pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self {
24 Control { 28 Control {
25 firmware_state, 29 firmware_state,
@@ -27,11 +31,12 @@ impl<'d, STATE: NorFlash> Control<'d, STATE> {
27 state: State::AppIdle, 31 state: State::AppIdle,
28 detach_start: None, 32 detach_start: None,
29 timeout: None, 33 timeout: None,
34 _rst: PhantomData,
30 } 35 }
31 } 36 }
32} 37}
33 38
34impl<'d, STATE: NorFlash> Handler for Control<'d, STATE> { 39impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> {
35 fn reset(&mut self) { 40 fn reset(&mut self) {
36 if let Some(start) = self.detach_start { 41 if let Some(start) = self.detach_start {
37 let delta = Instant::now() - start; 42 let delta = Instant::now() - start;
@@ -45,7 +50,7 @@ impl<'d, STATE: NorFlash> Handler for Control<'d, STATE> {
45 self.firmware_state 50 self.firmware_state
46 .mark_dfu() 51 .mark_dfu()
47 .expect("Failed to mark DFU mode in bootloader"); 52 .expect("Failed to mark DFU mode in bootloader");
48 cortex_m::peripheral::SCB::sys_reset(); 53 RST::sys_reset()
49 } 54 }
50 } 55 }
51 } 56 }
@@ -103,9 +108,9 @@ impl<'d, STATE: NorFlash> Handler for Control<'d, STATE> {
103/// it should expose a DFU device, and a software reset will be issued. 108/// it should expose a DFU device, and a software reset will be issued.
104/// 109///
105/// 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. 110/// 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.
106pub fn usb_dfu<'d, D: Driver<'d>, STATE: NorFlash>( 111pub fn usb_dfu<'d, D: Driver<'d>, STATE: NorFlash, RST: Reset>(
107 builder: &mut Builder<'d, D>, 112 builder: &mut Builder<'d, D>,
108 handler: &'d mut Control<'d, STATE>, 113 handler: &'d mut Control<'d, STATE, RST>,
109 timeout: Duration, 114 timeout: Duration,
110) { 115) {
111 let mut func = builder.function(0x00, 0x00, 0x00); 116 let mut func = builder.function(0x00, 0x00, 0x00);
diff --git a/embassy-usb-dfu/src/bootloader.rs b/embassy-usb-dfu/src/bootloader.rs
index 99384d961..d41e6280d 100644
--- a/embassy-usb-dfu/src/bootloader.rs
+++ b/embassy-usb-dfu/src/bootloader.rs
@@ -1,3 +1,5 @@
1use core::marker::PhantomData;
2
1use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater}; 3use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater};
2use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; 4use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
3use embassy_usb::driver::Driver; 5use embassy_usb::driver::Driver;
@@ -8,17 +10,19 @@ use crate::consts::{
8 DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_DFU, 10 DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_DFU,
9 USB_CLASS_APPN_SPEC, 11 USB_CLASS_APPN_SPEC,
10}; 12};
13use crate::Reset;
11 14
12/// Internal state for USB DFU 15/// Internal state for USB DFU
13pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> { 16pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> {
14 updater: BlockingFirmwareUpdater<'d, DFU, STATE>, 17 updater: BlockingFirmwareUpdater<'d, DFU, STATE>,
15 attrs: DfuAttributes, 18 attrs: DfuAttributes,
16 state: State, 19 state: State,
17 status: Status, 20 status: Status,
18 offset: usize, 21 offset: usize,
22 _rst: PhantomData<RST>,
19} 23}
20 24
21impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, BLOCK_SIZE> { 25impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> {
22 pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self { 26 pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self {
23 Self { 27 Self {
24 updater, 28 updater,
@@ -26,6 +30,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Control<'d, DF
26 state: State::DfuIdle, 30 state: State::DfuIdle,
27 status: Status::Ok, 31 status: Status::Ok,
28 offset: 0, 32 offset: 0,
33 _rst: PhantomData,
29 } 34 }
30 } 35 }
31 36
@@ -36,7 +41,9 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Control<'d, DF
36 } 41 }
37} 42}
38 43
39impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Control<'d, DFU, STATE, BLOCK_SIZE> { 44impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Handler
45 for Control<'d, DFU, STATE, RST, BLOCK_SIZE>
46{
40 fn control_out( 47 fn control_out(
41 &mut self, 48 &mut self,
42 req: embassy_usb::control::Request, 49 req: embassy_usb::control::Request,
@@ -131,7 +138,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Co
131 buf[0..6].copy_from_slice(&[self.status as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]); 138 buf[0..6].copy_from_slice(&[self.status as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]);
132 match self.state { 139 match self.state {
133 State::DlSync => self.state = State::Download, 140 State::DlSync => self.state = State::Download,
134 State::ManifestSync => cortex_m::peripheral::SCB::sys_reset(), 141 State::ManifestSync => RST::sys_reset(),
135 _ => {} 142 _ => {}
136 } 143 }
137 144
@@ -157,9 +164,9 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Co
157/// 164///
158/// Once the host has initiated a DFU download operation, the chunks sent by the host will be written to the DFU partition. 165/// Once the host has initiated a DFU download operation, the chunks sent by the host will be written to the DFU partition.
159/// Once the final sync in the manifestation phase has been received, the handler will trigger a system reset to swap the new firmware. 166/// Once the final sync in the manifestation phase has been received, the handler will trigger a system reset to swap the new firmware.
160pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize>( 167pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize>(
161 builder: &mut Builder<'d, D>, 168 builder: &mut Builder<'d, D>,
162 handler: &'d mut Control<'d, DFU, STATE, BLOCK_SIZE>, 169 handler: &'d mut Control<'d, DFU, STATE, RST, BLOCK_SIZE>,
163) { 170) {
164 let mut func = builder.function(0x00, 0x00, 0x00); 171 let mut func = builder.function(0x00, 0x00, 0x00);
165 let mut iface = func.interface(); 172 let mut iface = func.interface();
diff --git a/embassy-usb-dfu/src/lib.rs b/embassy-usb-dfu/src/lib.rs
index ae0fbbd4c..283905de9 100644
--- a/embassy-usb-dfu/src/lib.rs
+++ b/embassy-usb-dfu/src/lib.rs
@@ -18,3 +18,34 @@ pub use self::application::*;
18 not(any(feature = "bootloader", feature = "application")) 18 not(any(feature = "bootloader", feature = "application"))
19))] 19))]
20compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `application` features"); 20compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `application` features");
21
22/// Provides a platform-agnostic interface for initiating a system reset.
23///
24/// This crate exposes `ResetImmediate` when compiled with cortex-m or esp32c3 support, which immediately issues a
25/// reset request without interfacing with any other peripherals.
26///
27/// If alternate behaviour is desired, a custom implementation of Reset can be provided as a type argument to the usb_dfu function.
28pub trait Reset {
29 fn sys_reset() -> !;
30}
31
32#[cfg(feature = "esp32c3-hal")]
33pub struct ResetImmediate;
34
35#[cfg(feature = "esp32c3-hal")]
36impl Reset for ResetImmediate {
37 fn sys_reset() -> ! {
38 esp32c3_hal::reset::software_reset();
39 loop {}
40 }
41}
42
43#[cfg(feature = "cortex-m")]
44pub struct ResetImmediate;
45
46#[cfg(feature = "cortex-m")]
47impl Reset for ResetImmediate {
48 fn sys_reset() -> ! {
49 cortex_m::peripheral::SCB::sys_reset()
50 }
51}
diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml
index 0ed0b75e0..f6beea498 100644
--- a/examples/boot/application/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/application/stm32wb-dfu/Cargo.toml
@@ -12,7 +12,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", feature
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb" } 14embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb" }
15embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application"] } 15embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] }
16 16
17defmt = { version = "0.3", optional = true } 17defmt = { version = "0.3", optional = true }
18defmt-rtt = { version = "0.4", optional = true } 18defmt-rtt = { version = "0.4", optional = true }
diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs
index cdac903b5..fbecbf23b 100644
--- a/examples/boot/application/stm32wb-dfu/src/main.rs
+++ b/examples/boot/application/stm32wb-dfu/src/main.rs
@@ -16,7 +16,7 @@ use embassy_sync::blocking_mutex::Mutex;
16use embassy_time::Duration; 16use embassy_time::Duration;
17use embassy_usb::Builder; 17use embassy_usb::Builder;
18use embassy_usb_dfu::consts::DfuAttributes; 18use embassy_usb_dfu::consts::DfuAttributes;
19use embassy_usb_dfu::{usb_dfu, Control}; 19use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate};
20use panic_reset as _; 20use panic_reset as _;
21 21
22bind_interrupts!(struct Irqs { 22bind_interrupts!(struct Irqs {
@@ -57,7 +57,7 @@ async fn main(_spawner: Spawner) {
57 &mut control_buf, 57 &mut control_buf,
58 ); 58 );
59 59
60 usb_dfu::<_, _>(&mut builder, &mut state, Duration::from_millis(2500)); 60 usb_dfu::<_, _, ResetImmediate>(&mut builder, &mut state, Duration::from_millis(2500));
61 61
62 let mut dev = builder.build(); 62 let mut dev = builder.build();
63 dev.run().await 63 dev.run().await
diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
index fde9eb57d..e849eb539 100644
--- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
@@ -17,7 +17,7 @@ cortex-m-rt = { version = "0.7" }
17embedded-storage = "0.3.1" 17embedded-storage = "0.3.1"
18embedded-storage-async = "0.4.0" 18embedded-storage-async = "0.4.0"
19cfg-if = "1.0.0" 19cfg-if = "1.0.0"
20embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["bootloader"] } 20embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["bootloader", "cortex-m"] }
21embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb", default-features = false } 21embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb", default-features = false }
22embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" } 22embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" }
23 23
diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
index db7039e8c..a7ab813b6 100644
--- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs
+++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
@@ -14,7 +14,7 @@ use embassy_stm32::{bind_interrupts, peripherals, usb};
14use embassy_sync::blocking_mutex::Mutex; 14use embassy_sync::blocking_mutex::Mutex;
15use embassy_usb::Builder; 15use embassy_usb::Builder;
16use embassy_usb_dfu::consts::DfuAttributes; 16use embassy_usb_dfu::consts::DfuAttributes;
17use embassy_usb_dfu::{usb_dfu, Control}; 17use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate};
18 18
19bind_interrupts!(struct Irqs { 19bind_interrupts!(struct Irqs {
20 USB_LP => usb::InterruptHandler<peripherals::USB>; 20 USB_LP => usb::InterruptHandler<peripherals::USB>;
@@ -64,7 +64,7 @@ fn main() -> ! {
64 &mut control_buf, 64 &mut control_buf,
65 ); 65 );
66 66
67 usb_dfu::<_, _, _, 4096>(&mut builder, &mut state); 67 usb_dfu::<_, _, _, ResetImmediate, 4096>(&mut builder, &mut state);
68 68
69 let mut dev = builder.build(); 69 let mut dev = builder.build();
70 embassy_futures::block_on(dev.run()); 70 embassy_futures::block_on(dev.run());