From dedb811aabf8a0e0290bdf5422302e8c6b015c5e Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 29 Jan 2022 15:41:05 +0100 Subject: [PATCH] Implemented config persitence + added ConfigStorage struct + added CRC computation for data integrity * fixed config error message not showing --- Cargo.toml | 1 + src/config.rs | 44 +++++++++++++------------- src/main.rs | 21 ++++++++++--- src/state.rs | 8 ++++- src/utils.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 00450cf..629f8db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ cortex-m-semihosting = "0.3.7" panic-halt = "0.2.0" hd44780-driver = "0.3.0" libm = "0.2.1" +half = "1.8.2" [dependencies.stm32f1xx-hal] version = "0.8.0" diff --git a/src/config.rs b/src/config.rs index b7d0d72..0462d22 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,9 +3,6 @@ use core::fmt; use crate::lcd_gui::LCDScreen; //---Config struct---------------------------------------------------------------------------------- -pub enum ConfigError { - LoadError, -} #[derive(Copy, Clone)] pub enum FanOutput { @@ -13,6 +10,21 @@ pub enum FanOutput { P2, } +impl FanOutput { + + pub fn from_bits(bits: u16) -> FanOutput { + if bits == 0 { return Self::P1 } + return Self::P2; + } + + pub fn to_bits(&self) -> u16 { + match self { + Self::P1 => 0, + Self::P2 => 1, + } + } +} + #[derive(Copy, Clone)] pub struct CalData { pub offset: f32, @@ -20,9 +32,9 @@ pub struct CalData { } impl CalData { - fn new() -> CalData { + pub fn new(offset: f32) -> CalData { CalData { - offset: 0.0, + offset, raw_value: None, } } @@ -44,22 +56,12 @@ impl SystemConfig { SystemConfig { max_temp_diff: 8.0, min_temp_diff: 4.0, - ext_offset: CalData::new(), - p1_offset: CalData::new(), - p2_offset: CalData::new(), + ext_offset: CalData::new(0.0), + p1_offset: CalData::new(0.0), + p2_offset: CalData::new(0.0), fan_output: FanOutput::P1, } } - - #[allow(dead_code)] - pub fn load() -> Result { - Err(ConfigError::LoadError) - } - - #[allow(dead_code)] - pub fn store() -> SystemConfig { - unimplemented!(); - } } //---Menu struct------------------------------------------------------------------------------------ @@ -86,9 +88,9 @@ impl Menu { Entry::new("fan out", EntryValue::FanOut (FanOutput::P1), config), Entry::new("max diff", EntryValue::MaxTempDiff (0.0), config), Entry::new("min diff", EntryValue::MinTempDiff (0.0), config), - Entry::new("ext cal", EntryValue::ExtOffset (CalData::new()), config), - Entry::new("p1 cal", EntryValue::P1Offset (CalData::new()), config), - Entry::new("p2 cal", EntryValue::P2Offset (CalData::new()), config), + Entry::new("ext cal", EntryValue::ExtOffset (CalData::new(0.0)), config), + Entry::new("p1 cal", EntryValue::P1Offset (CalData::new(0.0)), config), + Entry::new("p2 cal", EntryValue::P2Offset (CalData::new(0.0)), config), ], state: MenuState::Scroll, should_refresh: true, diff --git a/src/main.rs b/src/main.rs index 1c9674f..1931b84 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,6 +32,7 @@ use lcd_gui::{LCDGui, GUI_TICK_SEC}; mod utils; use utils::{ TemperatureProbe, + ConfigStorage, }; mod config; @@ -58,7 +59,7 @@ static TICK_TIMER: Mutex>>> = Mutex::new(RefCell::new(None)); // button interrupt -static BUTTON_PIN: Mutex>>>> +static BUTTON_PIN: Mutex>>>> = Mutex::new(RefCell::new(None)); static BUTTON_FLAG: AtomicBool = AtomicBool::new(false); @@ -185,14 +186,18 @@ fn main() -> ! { let mut afio = dp.AFIO.constrain(); // initialize system state + let mut config_storage = ConfigStorage::new(backup_domain, dp.CRC.new()); let mut error_state = ErrorState::NoError; - let config = match SystemConfig::load() { + let config = match config_storage.load_config() { Ok(conf) => conf, Err(_) => { error_state = ErrorState::NewError("config invalide"); - SystemConfig::new() + let conf = SystemConfig::new(); + config_storage.save_config(&conf); + conf }}; - let mut state = SystemState::new(config, gpiob.pb12.into_push_pull_output(&mut gpiob.crh)); + let mut state = SystemState::new(config, config_storage, + gpiob.pb12.into_push_pull_output(&mut gpiob.crh)); // Setup display let mut gui = { @@ -234,7 +239,7 @@ fn main() -> ! { ); // setup button (interrupt) - let mut but_pin = gpiob.pb8.into_pull_up_input(&mut gpiob.crh); + let mut but_pin = gpiob.pb8.into_floating_input(&mut gpiob.crh); but_pin.make_interrupt_source(&mut afio); but_pin.trigger_on_edge(&dp.EXTI, Edge::Rising); but_pin.enable_interrupt(&dp.EXTI); @@ -300,6 +305,12 @@ fn main() -> ! { /* run */ let _ = TEMP_FLAG.swap(true, Ordering::Release); + // fix some weird bug caused by the debouncing capacitor of the button + for i in 0..10 { + cortex_m::asm::wfi(); + } + BUTTON_FLAG.store(false, Ordering::Release); + loop { match error_state { diff --git a/src/state.rs b/src/state.rs index 3c2fd95..b89ce4d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -6,6 +6,8 @@ use crate::config::{ FanOutput, }; +use crate::utils::ConfigStorage; + pub enum FanState { On, Off, @@ -43,6 +45,7 @@ impl Fan { pub struct SystemState { config: SystemConfig, + config_storage: ConfigStorage, ext_temp: Option, p1_temp: Option, p2_temp: Option, @@ -51,10 +54,12 @@ pub struct SystemState { impl SystemState { - pub fn new(config: SystemConfig, fan_control_pin: O) -> SystemState { + pub fn new(config: SystemConfig, config_storage: ConfigStorage, fan_control_pin: O) + -> SystemState { SystemState { config, + config_storage, ext_temp: None, p1_temp: None, p2_temp: None, @@ -76,6 +81,7 @@ impl SystemState { // replace config self.config = config; + self.config_storage.save_config(&self.config); // reset fan state before recomputing fan state self.fan.off(); diff --git a/src/utils.rs b/src/utils.rs index 2550770..822b9ac 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -6,8 +6,17 @@ use core::{ use embedded_hal::adc::*; +use stm32f1xx_hal::{ + backup_domain::BackupDomain, + crc::Crc, +}; + use libm::*; +use half::f16; + +use crate::config::SystemConfig; + //-------------------------------------------------------------------------------------------------- /* 2nd order linearisation factor for the temperature probe */ const A: f32 = -0.000574; @@ -138,3 +147,80 @@ where } } +//-------------------------------------------------------------------------------------------------- +/* ConfigStorage */ + +pub struct ConfigStorage { + backup_domain: BackupDomain, + crc: Crc, +} + +impl ConfigStorage { + + pub fn new(backup_domain: BackupDomain, crc: Crc) -> ConfigStorage { + + ConfigStorage { + backup_domain, + crc, + } + } + + pub fn load_config(&mut self) -> Result { + use crate::config::{CalData, FanOutput}; + + // read from persistent memory + let mut values: [u16; 10] = [0; 10]; + for (i, val) in values.iter_mut().enumerate() { + *val = self.backup_domain.read_data_register_low(i); + } + + // compute CRC + self.crc.reset(); + for i in (2..8).step_by(2) { + self.crc.write((values[i] as u32) << 16 | values[i+1] as u32); + } + let crc = (values[0] as u32) << 16 | values[1] as u32; + + // parse config if CRC is valid + match crc != 0 && crc == self.crc.read() { + true => { + Ok(SystemConfig { + max_temp_diff: f16::from_bits(values[2]).to_f32(), + min_temp_diff: f16::from_bits(values[3]).to_f32(), + ext_offset: CalData::new(f16::from_bits(values[4]).to_f32()), + p1_offset: CalData::new(f16::from_bits(values[5]).to_f32()), + p2_offset: CalData::new(f16::from_bits(values[6]).to_f32()), + fan_output: FanOutput::from_bits(values[7]), + }) + }, + false => Err(()), + } + } + + pub fn save_config(&mut self, config: &SystemConfig) { + + // prepare buffer for later storage + let mut values: [u16; 10] = [0; 10]; + values[2] = f16::from_f32(config.max_temp_diff).to_bits(); + values[3] = f16::from_f32(config.min_temp_diff).to_bits(); + values[4] = f16::from_f32(config.ext_offset.offset).to_bits(); + values[5] = f16::from_f32(config.p1_offset.offset).to_bits(); + values[6] = f16::from_f32(config.p2_offset.offset).to_bits(); + values[7] = config.fan_output.to_bits(); + + // compute CRC + self.crc.reset(); + for i in (2..8).step_by(2) { + self.crc.write((values[i] as u32) << 16 | values[i+1] as u32); + } + let crc = self.crc.read(); + values[0] = ((crc >> 16) & 0xFFFF) as u16; + values[1] = (crc & 0xFFFF) as u16; + + // write to persistent memory + for (i, val) in values.iter().enumerate() { + self.backup_domain.write_data_register_low(i, *val); + } + } +} +