diff options
| author | Kaitlyn Kenwell <[email protected]> | 2023-12-13 14:40:49 -0500 |
|---|---|---|
| committer | Kaitlyn Kenwell <[email protected]> | 2023-12-13 14:40:49 -0500 |
| commit | 976a7ae22aa222213861c12d515115aac87bd2e0 (patch) | |
| tree | 88f802c7d57df011c02142ef309ff5cffe8bd3b0 /embassy-boot | |
| parent | 14f41a71b6ea9dedb4ee5b9c741fe10575772c7d (diff) | |
Add embassy-usb-dfu
Diffstat (limited to 'embassy-boot')
| -rw-r--r-- | embassy-boot/boot/src/boot_loader.rs | 4 | ||||
| -rw-r--r-- | embassy-boot/boot/src/firmware_updater/asynch.rs | 13 | ||||
| -rw-r--r-- | embassy-boot/boot/src/firmware_updater/blocking.rs | 17 | ||||
| -rw-r--r-- | embassy-boot/boot/src/lib.rs | 3 | ||||
| -rw-r--r-- | embassy-boot/stm32/src/lib.rs | 9 |
5 files changed, 39 insertions, 7 deletions
diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs index a8c19197b..c0deca22b 100644 --- a/embassy-boot/boot/src/boot_loader.rs +++ b/embassy-boot/boot/src/boot_loader.rs | |||
| @@ -5,7 +5,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; | |||
| 5 | use embassy_sync::blocking_mutex::Mutex; | 5 | use embassy_sync::blocking_mutex::Mutex; |
| 6 | use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; | 6 | use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; |
| 7 | 7 | ||
| 8 | use crate::{State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; | 8 | use crate::{State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC, DFU_DETACH_MAGIC}; |
| 9 | 9 | ||
| 10 | /// Errors returned by bootloader | 10 | /// Errors returned by bootloader |
| 11 | #[derive(PartialEq, Eq, Debug)] | 11 | #[derive(PartialEq, Eq, Debug)] |
| @@ -384,6 +384,8 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S | |||
| 384 | 384 | ||
| 385 | if !state_word.iter().any(|&b| b != SWAP_MAGIC) { | 385 | if !state_word.iter().any(|&b| b != SWAP_MAGIC) { |
| 386 | Ok(State::Swap) | 386 | Ok(State::Swap) |
| 387 | } else if !state_word.iter().any(|&b| b != DFU_DETACH_MAGIC) { | ||
| 388 | Ok(State::DfuDetach) | ||
| 387 | } else { | 389 | } else { |
| 388 | Ok(State::Boot) | 390 | Ok(State::Boot) |
| 389 | } | 391 | } |
diff --git a/embassy-boot/boot/src/firmware_updater/asynch.rs b/embassy-boot/boot/src/firmware_updater/asynch.rs index ae713bb6f..0a3cbc136 100644 --- a/embassy-boot/boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/boot/src/firmware_updater/asynch.rs | |||
| @@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; | |||
| 6 | use embedded_storage_async::nor_flash::NorFlash; | 6 | use embedded_storage_async::nor_flash::NorFlash; |
| 7 | 7 | ||
| 8 | use super::FirmwareUpdaterConfig; | 8 | use super::FirmwareUpdaterConfig; |
| 9 | use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; | 9 | use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC, DFU_DETACH_MAGIC}; |
| 10 | 10 | ||
| 11 | /// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to | 11 | /// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to |
| 12 | /// 'mess up' the internal bootloader state | 12 | /// 'mess up' the internal bootloader state |
| @@ -161,6 +161,12 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { | |||
| 161 | self.state.mark_updated().await | 161 | self.state.mark_updated().await |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | /// Mark to trigger USB DFU on next boot. | ||
| 165 | pub async fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> { | ||
| 166 | self.state.verify_booted().await?; | ||
| 167 | self.state.mark_dfu().await | ||
| 168 | } | ||
| 169 | |||
| 164 | /// Mark firmware boot successful and stop rollback on reset. | 170 | /// Mark firmware boot successful and stop rollback on reset. |
| 165 | pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { | 171 | pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { |
| 166 | self.state.mark_booted().await | 172 | self.state.mark_booted().await |
| @@ -247,6 +253,11 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { | |||
| 247 | self.set_magic(SWAP_MAGIC).await | 253 | self.set_magic(SWAP_MAGIC).await |
| 248 | } | 254 | } |
| 249 | 255 | ||
| 256 | /// Mark to trigger USB DFU on next boot. | ||
| 257 | pub async fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> { | ||
| 258 | self.set_magic(DFU_DETACH_MAGIC).await | ||
| 259 | } | ||
| 260 | |||
| 250 | /// Mark firmware boot successful and stop rollback on reset. | 261 | /// Mark firmware boot successful and stop rollback on reset. |
| 251 | pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { | 262 | pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { |
| 252 | self.set_magic(BOOT_MAGIC).await | 263 | self.set_magic(BOOT_MAGIC).await |
diff --git a/embassy-boot/boot/src/firmware_updater/blocking.rs b/embassy-boot/boot/src/firmware_updater/blocking.rs index 76e4264a0..b2a633d1e 100644 --- a/embassy-boot/boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/boot/src/firmware_updater/blocking.rs | |||
| @@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; | |||
| 6 | use embedded_storage::nor_flash::NorFlash; | 6 | use embedded_storage::nor_flash::NorFlash; |
| 7 | 7 | ||
| 8 | use super::FirmwareUpdaterConfig; | 8 | use super::FirmwareUpdaterConfig; |
| 9 | use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; | 9 | use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC, DFU_DETACH_MAGIC}; |
| 10 | 10 | ||
| 11 | /// Blocking FirmwareUpdater is an application API for interacting with the BootLoader without the ability to | 11 | /// Blocking FirmwareUpdater is an application API for interacting with the BootLoader without the ability to |
| 12 | /// 'mess up' the internal bootloader state | 12 | /// 'mess up' the internal bootloader state |
| @@ -168,6 +168,12 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> | |||
| 168 | self.state.mark_updated() | 168 | self.state.mark_updated() |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | /// Mark to trigger USB DFU device on next boot. | ||
| 172 | pub fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> { | ||
| 173 | self.state.verify_booted()?; | ||
| 174 | self.state.mark_dfu() | ||
| 175 | } | ||
| 176 | |||
| 171 | /// Mark firmware boot successful and stop rollback on reset. | 177 | /// Mark firmware boot successful and stop rollback on reset. |
| 172 | pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { | 178 | pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { |
| 173 | self.state.mark_booted() | 179 | self.state.mark_booted() |
| @@ -226,7 +232,7 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { | |||
| 226 | 232 | ||
| 227 | // Make sure we are running a booted firmware to avoid reverting to a bad state. | 233 | // Make sure we are running a booted firmware to avoid reverting to a bad state. |
| 228 | fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { | 234 | fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { |
| 229 | if self.get_state()? == State::Boot { | 235 | if self.get_state()? == State::Boot || self.get_state()? == State::DfuDetach { |
| 230 | Ok(()) | 236 | Ok(()) |
| 231 | } else { | 237 | } else { |
| 232 | Err(FirmwareUpdaterError::BadState) | 238 | Err(FirmwareUpdaterError::BadState) |
| @@ -243,6 +249,8 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { | |||
| 243 | 249 | ||
| 244 | if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) { | 250 | if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) { |
| 245 | Ok(State::Swap) | 251 | Ok(State::Swap) |
| 252 | } else if !self.aligned.iter().any(|&b| b != DFU_DETACH_MAGIC) { | ||
| 253 | Ok(State::DfuDetach) | ||
| 246 | } else { | 254 | } else { |
| 247 | Ok(State::Boot) | 255 | Ok(State::Boot) |
| 248 | } | 256 | } |
| @@ -253,6 +261,11 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { | |||
| 253 | self.set_magic(SWAP_MAGIC) | 261 | self.set_magic(SWAP_MAGIC) |
| 254 | } | 262 | } |
| 255 | 263 | ||
| 264 | /// Mark to trigger USB DFU on next boot. | ||
| 265 | pub fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> { | ||
| 266 | self.set_magic(DFU_DETACH_MAGIC) | ||
| 267 | } | ||
| 268 | |||
| 256 | /// Mark firmware boot successful and stop rollback on reset. | 269 | /// Mark firmware boot successful and stop rollback on reset. |
| 257 | pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { | 270 | pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { |
| 258 | self.set_magic(BOOT_MAGIC) | 271 | self.set_magic(BOOT_MAGIC) |
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index 9e70a4dca..451992945 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs | |||
| @@ -23,6 +23,7 @@ pub use firmware_updater::{ | |||
| 23 | 23 | ||
| 24 | pub(crate) const BOOT_MAGIC: u8 = 0xD0; | 24 | pub(crate) const BOOT_MAGIC: u8 = 0xD0; |
| 25 | pub(crate) const SWAP_MAGIC: u8 = 0xF0; | 25 | pub(crate) const SWAP_MAGIC: u8 = 0xF0; |
| 26 | pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0; | ||
| 26 | 27 | ||
| 27 | /// The state of the bootloader after running prepare. | 28 | /// The state of the bootloader after running prepare. |
| 28 | #[derive(PartialEq, Eq, Debug)] | 29 | #[derive(PartialEq, Eq, Debug)] |
| @@ -32,6 +33,8 @@ pub enum State { | |||
| 32 | Boot, | 33 | Boot, |
| 33 | /// Bootloader has swapped the active partition with the dfu partition and will attempt boot. | 34 | /// Bootloader has swapped the active partition with the dfu partition and will attempt boot. |
| 34 | Swap, | 35 | Swap, |
| 36 | /// Application has received a DFU_DETACH request over USB, and is rebooting into the bootloader to apply a DFU. | ||
| 37 | DfuDetach, | ||
| 35 | } | 38 | } |
| 36 | 39 | ||
| 37 | /// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot. | 40 | /// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot. |
diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot/stm32/src/lib.rs index c418cb262..4b4091ac9 100644 --- a/embassy-boot/stm32/src/lib.rs +++ b/embassy-boot/stm32/src/lib.rs | |||
| @@ -10,7 +10,10 @@ pub use embassy_boot::{ | |||
| 10 | use embedded_storage::nor_flash::NorFlash; | 10 | use embedded_storage::nor_flash::NorFlash; |
| 11 | 11 | ||
| 12 | /// A bootloader for STM32 devices. | 12 | /// A bootloader for STM32 devices. |
| 13 | pub struct BootLoader; | 13 | pub struct BootLoader { |
| 14 | /// The reported state of the bootloader after preparing for boot | ||
| 15 | pub state: State, | ||
| 16 | } | ||
| 14 | 17 | ||
| 15 | impl BootLoader { | 18 | impl BootLoader { |
| 16 | /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware | 19 | /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware |
| @@ -19,8 +22,8 @@ impl BootLoader { | |||
| 19 | ) -> Self { | 22 | ) -> Self { |
| 20 | let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); | 23 | let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); |
| 21 | let mut boot = embassy_boot::BootLoader::new(config); | 24 | let mut boot = embassy_boot::BootLoader::new(config); |
| 22 | boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error"); | 25 | let state = boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error"); |
| 23 | Self | 26 | Self { state } |
| 24 | } | 27 | } |
| 25 | 28 | ||
| 26 | /// Boots the application. | 29 | /// Boots the application. |
