Skip to content

Commit

Permalink
flash check
Browse files Browse the repository at this point in the history
  • Loading branch information
surban committed Aug 31, 2023
1 parent 0173083 commit 00e92b2
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 38 deletions.
9 changes: 9 additions & 0 deletions openemc-firmware/memory-big.x
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,13 @@ SECTIONS
}
INSERT BEFORE .data;

SECTIONS
{
.program_end (NOLOAD) : ALIGN(4)
{
__flash_program_end = .;
} > FLASH
}
INSERT AFTER .gnu.sgstubs;

__flash_end = ORIGIN(FLASH) + LENGTH(FLASH);
9 changes: 9 additions & 0 deletions openemc-firmware/memory-normal.x
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,13 @@ SECTIONS
}
INSERT BEFORE .data;

SECTIONS
{
.program_end (NOLOAD) : ALIGN(4)
{
__flash_program_end = .;
} > FLASH
}
INSERT AFTER .gnu.sgstubs;

__flash_end = ORIGIN(FLASH) + LENGTH(FLASH);
9 changes: 9 additions & 0 deletions openemc-firmware/memory-standalone.x
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,13 @@ SECTIONS
}
INSERT BEFORE .data;

SECTIONS
{
.program_end (NOLOAD) : ALIGN(4)
{
__flash_program_end = .;
} > FLASH
}
INSERT AFTER .gnu.sgstubs;

__flash_end = ORIGIN(FLASH) + LENGTH(FLASH);
17 changes: 7 additions & 10 deletions openemc-firmware/src/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use core::{mem::MaybeUninit, ptr::addr_of_mut};
use defmt::Format;

use crate::flash_data::Validate;
use crate::flash_data::FlashData;

/// Behavior when charger is attached while device is powered off.
#[derive(Default, Format, Clone, Copy, PartialEq, Eq)]
Expand All @@ -29,7 +29,7 @@ impl TryFrom<u8> for ChargerAttached {
}

/// Configuration stored in flash.
#[derive(Format, Clone, Copy)]
#[derive(Format, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct Cfg {
/// Behavior when charger is attached while device is powered off.
Expand All @@ -40,14 +40,7 @@ pub struct Cfg {
pub prohibit_power_off: bool,
}

impl Cfg {
/// Log configuration change.
pub fn log(&self) {
defmt::info!("Configuration changed: {:?}", self);
}
}

impl Validate for Cfg {
impl FlashData for Cfg {
fn validate(mut this: MaybeUninit<Self>) -> Self {
unsafe {
let ptr = this.as_mut_ptr();
Expand All @@ -65,4 +58,8 @@ impl Validate for Cfg {
this.assume_init()
}
}

fn notify_changed(&self) {
defmt::info!("Configuration changed: {:?}", self);
}
}
61 changes: 42 additions & 19 deletions openemc-firmware/src/flash_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use core::{
mem::{size_of, zeroed, MaybeUninit},
ops::{Deref, DerefMut},
ops::Deref,
slice,
};
use defmt::assert;
Expand All @@ -11,10 +11,12 @@ use stm32f1xx_hal::flash::FlashWriter;

use crate::{flash_page_size, util::FlashUtil};

/// Validate data loaded from flash.
pub trait Validate: Sized {
/// Data storable in flash.
pub trait FlashData: Sized + Copy + Eq + Sized + 'static {
/// Validate and fix data as needed so that it becomes a valid Rust value.
fn validate(this: MaybeUninit<Self>) -> Self;
/// Notify data that it was changed (for logging).
fn notify_changed(&self) {}
}

#[derive(Clone, Copy, PartialEq, Eq)]
Expand All @@ -35,12 +37,14 @@ pub struct FlashBackened<T> {

impl<T> FlashBackened<T>
where
T: Validate + Copy + Sized + 'static,
T: FlashData,
{
const HEADER_SIZE: usize = 8;

/// Create copies at specified offsets in flash.
pub fn new_at(flash: &mut FlashWriter, flash_offset1: u32, flash_offset2: u32, reserved: usize) -> Self {
pub fn new_at(
flash: &mut FlashWriter, flash_offset1: u32, flash_offset2: u32, reserved: usize, erase: bool,
) -> Self {
assert!(size_of::<T>() % 2 == 0, "data must have even size");
assert!(reserved % flash_page_size() == 0, "reserved size must be a multiple of flash page size");
assert!(
Expand All @@ -58,15 +62,21 @@ where
version: 0,
next_save: FlashCopy::Copy1,
};
this.load(flash);

if erase {
this.erase(flash);
} else {
this.load(flash);
}

this
}

/// Create copies with end offset in flash specified.
pub fn new_at_end(flash: &mut FlashWriter, reserved: usize, end_offset: u32) -> Self {
pub fn new_at_end(flash: &mut FlashWriter, reserved: usize, end_offset: u32, erase: bool) -> Self {
let flash_offset2 = end_offset - reserved as u32;
let flash_offset1 = flash_offset2 - reserved as u32;
Self::new_at(flash, flash_offset1, flash_offset2, reserved)
Self::new_at(flash, flash_offset1, flash_offset2, reserved, erase)
}

/// Read copy from flash and verify CRC32.
Expand Down Expand Up @@ -125,11 +135,12 @@ where

self.version = version;
self.data = T::validate(data);
self.data.notify_changed();
self.next_save = next_save;
}

/// Save data to flash.
pub fn save(&mut self, flash: &mut FlashWriter) {
fn save(&mut self, flash: &mut FlashWriter) {
self.version = self.version.wrapping_add(1);
self.next_save = match self.next_save {
FlashCopy::Copy1 => {
Expand All @@ -143,10 +154,28 @@ where
};
}

/// Erase data in flash.
pub fn erase(&self, flash: &mut FlashWriter) {
flash.erase_unwrap(self.flash_offset1, self.reserved + Self::HEADER_SIZE);
flash.erase_unwrap(self.flash_offset2, self.reserved + Self::HEADER_SIZE);
/// Erase data in flash and init with defaults.
pub fn erase(&mut self, flash: &mut FlashWriter) {
flash.erase_unwrap(self.flash_offset1, self.reserved);
flash.erase_unwrap(self.flash_offset2, self.reserved);

self.version = 0;
self.data = T::validate(unsafe { zeroed() });
self.data.notify_changed();
self.next_save = FlashCopy::Copy1;
}

/// Modify data and save to flash if changed.
pub fn modify(&mut self, flash: &mut FlashWriter, modify: impl FnOnce(&mut T)) {
let old_data = self.data;
modify(&mut self.data);

if old_data == self.data {
return;
}

self.data.notify_changed();
self.save(flash);
}
}

Expand All @@ -157,9 +186,3 @@ impl<T> Deref for FlashBackened<T> {
&self.data
}
}

impl<T> DerefMut for FlashBackened<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
30 changes: 21 additions & 9 deletions openemc-firmware/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,21 @@ static mut BOOTLOADER_LOG_REF: Option<
> = None;

extern "C" {
/// End of program in flash (from linker).
pub static __flash_program_end: c_void;

/// End of flash (from linker).
pub static __flash_end: c_void;

/// Flash page size (from linker).
pub static __flash_page_size: c_void;
}

/// End of program in flash.
pub fn flash_program_end() -> usize {
unsafe { &__flash_program_end as *const _ as usize }
}

/// End of user flash.
pub fn flash_end() -> usize {
unsafe { &__flash_end as *const _ as usize }
Expand Down Expand Up @@ -357,8 +365,14 @@ mod app {
let bi = BootInfo::get();

// Load configuration from flash.
let cfg_size = flash_page_size();
defmt::assert!(flash_program_end() <= flash_end() - 2 * cfg_size, "no space for configuration in flash");
let erase_cfg = bi.boot_reason == BootReason::FactoryReset as _;
if erase_cfg {
defmt::info!("Erasing configuration due to factory reset");
}
let mut fw = FlashWriter::new(&mut flash);
let cfg = FlashBackened::new_at_end(&mut fw, flash_page_size(), flash_end() as u32 - FLASH_START);
let cfg = FlashBackened::new_at_end(&mut fw, cfg_size, flash_end() as u32 - FLASH_START, erase_cfg);

// Create board handler.
defmt::info!("board new");
Expand Down Expand Up @@ -1409,20 +1423,18 @@ mod app {
respond_u8(cx.shared.cfg.lock(|cfg| cfg.prohibit_power_off.into()))
}
Event::Write { reg: reg::POWER_OFF_PROHIBITED, value } => {
(cx.shared.flash, cx.shared.cfg).lock(|mut flash, cfg| {
cfg.prohibit_power_off = value.as_u8() != 0;
cfg.save(&mut FlashWriter::new(&mut flash));
cfg.log();
(cx.shared.flash, cx.shared.cfg).lock(|flash, cfg| {
cfg.modify(&mut FlashWriter::new(flash), |cfg| cfg.prohibit_power_off = value.as_u8() != 0);
})
}
Event::Read { reg: reg::POWER_ON_BY_CHARGING } => {
respond_u8(cx.shared.cfg.lock(|cfg| cfg.charger_attached as u8))
}
Event::Write { reg: reg::POWER_ON_BY_CHARGING, value } => {
(cx.shared.flash, cx.shared.cfg).lock(|mut flash, cfg| {
cfg.charger_attached = value.as_u8().try_into().unwrap_or_default();
cfg.save(&mut FlashWriter::new(&mut flash));
cfg.log();
(cx.shared.flash, cx.shared.cfg).lock(|flash, cfg| {
cfg.modify(&mut FlashWriter::new(flash), |cfg| {
cfg.charger_attached = value.as_u8().try_into().unwrap_or_default()
});
})
}
Event::Read { reg: reg::PWM_TIMERS } => respond_u8(cx.local.pwm_timers.len() as u8),
Expand Down
1 change: 1 addition & 0 deletions openemc-firmware/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ pub fn unique_device_id() -> u128 {
/// Flash utility function.
pub trait FlashUtil {
/// Create flash writer.
#[allow(clippy::new_ret_no_self)]
fn new(parts: &mut flash::Parts) -> FlashWriter;

/// Read and panic if failed.
Expand Down

0 comments on commit 00e92b2

Please sign in to comment.