Merge branch '8-implement-configuration-persistence' into 'dev'

Resolve "Implement configuration persistence"

See merge request Steins7/fan_monitor!5
This commit is contained in:
Steins7 2022-01-29 14:42:59 +00:00
commit 7941ceeb51
5 changed files with 133 additions and 27 deletions

View File

@ -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"

View File

@ -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<SystemConfig, ConfigError> {
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,

View File

@ -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<RefCell<Option<CountDownTimer<pac::TIM2>>>>
= Mutex::new(RefCell::new(None));
// button interrupt
static BUTTON_PIN: Mutex<RefCell<Option<gpiob::PB8<Input<PullUp>>>>>
static BUTTON_PIN: Mutex<RefCell<Option<gpiob::PB8<Input<Floating>>>>>
= 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 {

View File

@ -6,6 +6,8 @@ use crate::config::{
FanOutput,
};
use crate::utils::ConfigStorage;
pub enum FanState {
On,
Off,
@ -43,6 +45,7 @@ impl<O: OutputPin> Fan<O> {
pub struct SystemState<O: OutputPin> {
config: SystemConfig,
config_storage: ConfigStorage,
ext_temp: Option<f32>,
p1_temp: Option<f32>,
p2_temp: Option<f32>,
@ -51,10 +54,12 @@ pub struct SystemState<O: OutputPin> {
impl<O: OutputPin> SystemState<O> {
pub fn new(config: SystemConfig, fan_control_pin: O) -> SystemState<O> {
pub fn new(config: SystemConfig, config_storage: ConfigStorage, fan_control_pin: O)
-> SystemState<O> {
SystemState {
config,
config_storage,
ext_temp: None,
p1_temp: None,
p2_temp: None,
@ -76,6 +81,7 @@ impl<O: OutputPin> SystemState<O> {
// replace config
self.config = config;
self.config_storage.save_config(&self.config);
// reset fan state before recomputing fan state
self.fan.off();

View File

@ -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<SystemConfig, ()> {
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);
}
}
}