mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 08:12:30 +00:00
Merge pull request #3349 from embassy-rs/e-b-introduce-reverted-magic
Add revert state in embassy-boot
This commit is contained in:
commit
cdb44f1272
@ -5,7 +5,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
|||||||
use embassy_sync::blocking_mutex::Mutex;
|
use embassy_sync::blocking_mutex::Mutex;
|
||||||
use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind};
|
use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind};
|
||||||
|
|
||||||
use crate::{State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC};
|
use crate::{State, DFU_DETACH_MAGIC, REVERT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC};
|
||||||
|
|
||||||
/// Errors returned by bootloader
|
/// Errors returned by bootloader
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
@ -276,7 +276,7 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
|
|||||||
self.state.erase(0, self.state.capacity() as u32)?;
|
self.state.erase(0, self.state.capacity() as u32)?;
|
||||||
|
|
||||||
// Set magic
|
// Set magic
|
||||||
state_word.fill(BOOT_MAGIC);
|
state_word.fill(REVERT_MAGIC);
|
||||||
self.state.write(0, state_word)?;
|
self.state.write(0, state_word)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -411,6 +411,8 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
|
|||||||
Ok(State::Swap)
|
Ok(State::Swap)
|
||||||
} else if !state_word.iter().any(|&b| b != DFU_DETACH_MAGIC) {
|
} else if !state_word.iter().any(|&b| b != DFU_DETACH_MAGIC) {
|
||||||
Ok(State::DfuDetach)
|
Ok(State::DfuDetach)
|
||||||
|
} else if !state_word.iter().any(|&b| b != REVERT_MAGIC) {
|
||||||
|
Ok(State::Revert)
|
||||||
} else {
|
} else {
|
||||||
Ok(State::Boot)
|
Ok(State::Boot)
|
||||||
}
|
}
|
||||||
|
@ -289,7 +289,8 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
|
|||||||
|
|
||||||
// Make sure we are running a booted firmware to avoid reverting to a bad state.
|
// Make sure we are running a booted firmware to avoid reverting to a bad state.
|
||||||
async fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
|
async fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
|
||||||
if self.get_state().await? == State::Boot {
|
let state = self.get_state().await?;
|
||||||
|
if state == State::Boot || state == State::DfuDetach || state == State::Revert {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(FirmwareUpdaterError::BadState)
|
Err(FirmwareUpdaterError::BadState)
|
||||||
@ -303,12 +304,7 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
|
|||||||
/// `mark_booted`.
|
/// `mark_booted`.
|
||||||
pub async fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> {
|
pub async fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> {
|
||||||
self.state.read(0, &mut self.aligned).await?;
|
self.state.read(0, &mut self.aligned).await?;
|
||||||
|
Ok(State::from(&self.aligned))
|
||||||
if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) {
|
|
||||||
Ok(State::Swap)
|
|
||||||
} else {
|
|
||||||
Ok(State::Boot)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark to trigger firmware swap on next boot.
|
/// Mark to trigger firmware swap on next boot.
|
||||||
|
@ -324,7 +324,8 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
|
|||||||
|
|
||||||
// Make sure we are running a booted firmware to avoid reverting to a bad state.
|
// Make sure we are running a booted firmware to avoid reverting to a bad state.
|
||||||
fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
|
fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
|
||||||
if self.get_state()? == State::Boot || self.get_state()? == State::DfuDetach {
|
let state = self.get_state()?;
|
||||||
|
if state == State::Boot || state == State::DfuDetach || state == State::Revert {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(FirmwareUpdaterError::BadState)
|
Err(FirmwareUpdaterError::BadState)
|
||||||
@ -338,14 +339,7 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
|
|||||||
/// `mark_booted`.
|
/// `mark_booted`.
|
||||||
pub fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> {
|
pub fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> {
|
||||||
self.state.read(0, &mut self.aligned)?;
|
self.state.read(0, &mut self.aligned)?;
|
||||||
|
Ok(State::from(&self.aligned))
|
||||||
if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) {
|
|
||||||
Ok(State::Swap)
|
|
||||||
} else if !self.aligned.iter().any(|&b| b != DFU_DETACH_MAGIC) {
|
|
||||||
Ok(State::DfuDetach)
|
|
||||||
} else {
|
|
||||||
Ok(State::Boot)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark to trigger firmware swap on next boot.
|
/// Mark to trigger firmware swap on next boot.
|
||||||
|
@ -25,6 +25,7 @@ pub use firmware_updater::{
|
|||||||
FirmwareUpdaterError,
|
FirmwareUpdaterError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub(crate) const REVERT_MAGIC: u8 = 0xC0;
|
||||||
pub(crate) const BOOT_MAGIC: u8 = 0xD0;
|
pub(crate) const BOOT_MAGIC: u8 = 0xD0;
|
||||||
pub(crate) const SWAP_MAGIC: u8 = 0xF0;
|
pub(crate) const SWAP_MAGIC: u8 = 0xF0;
|
||||||
pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0;
|
pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0;
|
||||||
@ -37,10 +38,30 @@ pub enum State {
|
|||||||
Boot,
|
Boot,
|
||||||
/// Bootloader has swapped the active partition with the dfu partition and will attempt boot.
|
/// Bootloader has swapped the active partition with the dfu partition and will attempt boot.
|
||||||
Swap,
|
Swap,
|
||||||
|
/// Bootloader has reverted the active partition with the dfu partition and will attempt boot.
|
||||||
|
Revert,
|
||||||
/// Application has received a request to reboot into DFU mode to apply an update.
|
/// Application has received a request to reboot into DFU mode to apply an update.
|
||||||
DfuDetach,
|
DfuDetach,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for State
|
||||||
|
where
|
||||||
|
T: AsRef<[u8]>,
|
||||||
|
{
|
||||||
|
fn from(magic: T) -> State {
|
||||||
|
let magic = magic.as_ref();
|
||||||
|
if !magic.iter().any(|&b| b != SWAP_MAGIC) {
|
||||||
|
State::Swap
|
||||||
|
} else if !magic.iter().any(|&b| b != REVERT_MAGIC) {
|
||||||
|
State::Revert
|
||||||
|
} else if !magic.iter().any(|&b| b != DFU_DETACH_MAGIC) {
|
||||||
|
State::DfuDetach
|
||||||
|
} else {
|
||||||
|
State::Boot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot.
|
/// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot.
|
||||||
#[repr(align(32))]
|
#[repr(align(32))]
|
||||||
pub struct AlignedBuffer<const N: usize>(pub [u8; N]);
|
pub struct AlignedBuffer<const N: usize>(pub [u8; N]);
|
||||||
@ -157,6 +178,9 @@ mod tests {
|
|||||||
// Running again should cause a revert
|
// Running again should cause a revert
|
||||||
assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap());
|
assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap());
|
||||||
|
|
||||||
|
// Next time we know it was reverted
|
||||||
|
assert_eq!(State::Revert, bootloader.prepare_boot(&mut page).unwrap());
|
||||||
|
|
||||||
let mut read_buf = [0; FIRMWARE_SIZE];
|
let mut read_buf = [0; FIRMWARE_SIZE];
|
||||||
flash.active().read(0, &mut read_buf).unwrap();
|
flash.active().read(0, &mut read_buf).unwrap();
|
||||||
assert_eq!(ORIGINAL, read_buf);
|
assert_eq!(ORIGINAL, read_buf);
|
||||||
|
@ -31,4 +31,7 @@ fn main() {
|
|||||||
|
|
||||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||||
|
if env::var("CARGO_FEATURE_DEFMT").is_ok() {
|
||||||
|
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
use defmt_rtt as _;
|
||||||
|
use embassy_boot::State;
|
||||||
use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig};
|
use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig};
|
||||||
use embassy_embedded_hal::adapter::BlockingAsync;
|
use embassy_embedded_hal::adapter::BlockingAsync;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
@ -22,6 +25,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let mut button = Input::new(p.P0_11, Pull::Up);
|
let mut button = Input::new(p.P0_11, Pull::Up);
|
||||||
let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
|
let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
|
||||||
|
let mut led_reverted = Output::new(p.P0_14, Level::High, OutputDrive::Standard);
|
||||||
|
|
||||||
//let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
|
//let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
|
||||||
//let mut button = Input::new(p.P1_02, Pull::Up);
|
//let mut button = Input::new(p.P1_02, Pull::Up);
|
||||||
@ -53,6 +57,13 @@ async fn main(_spawner: Spawner) {
|
|||||||
let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc);
|
let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc);
|
||||||
let mut magic = [0; 4];
|
let mut magic = [0; 4];
|
||||||
let mut updater = FirmwareUpdater::new(config, &mut magic);
|
let mut updater = FirmwareUpdater::new(config, &mut magic);
|
||||||
|
let state = updater.get_state().await.unwrap();
|
||||||
|
if state == State::Revert {
|
||||||
|
led_reverted.set_low();
|
||||||
|
} else {
|
||||||
|
led_reverted.set_high();
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
led.set_low();
|
led.set_low();
|
||||||
button.wait_for_any_edge().await;
|
button.wait_for_any_edge().await;
|
||||||
|
Loading…
Reference in New Issue
Block a user