Implemented config persitence
+ added ConfigStorage struct + added CRC computation for data integrity * fixed config error message not showing
This commit is contained in:
parent
07245df732
commit
dedb811aab
@ -14,6 +14,7 @@ cortex-m-semihosting = "0.3.7"
|
|||||||
panic-halt = "0.2.0"
|
panic-halt = "0.2.0"
|
||||||
hd44780-driver = "0.3.0"
|
hd44780-driver = "0.3.0"
|
||||||
libm = "0.2.1"
|
libm = "0.2.1"
|
||||||
|
half = "1.8.2"
|
||||||
|
|
||||||
[dependencies.stm32f1xx-hal]
|
[dependencies.stm32f1xx-hal]
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
|||||||
@ -3,9 +3,6 @@ use core::fmt;
|
|||||||
use crate::lcd_gui::LCDScreen;
|
use crate::lcd_gui::LCDScreen;
|
||||||
|
|
||||||
//---Config struct----------------------------------------------------------------------------------
|
//---Config struct----------------------------------------------------------------------------------
|
||||||
pub enum ConfigError {
|
|
||||||
LoadError,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum FanOutput {
|
pub enum FanOutput {
|
||||||
@ -13,6 +10,21 @@ pub enum FanOutput {
|
|||||||
P2,
|
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)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct CalData {
|
pub struct CalData {
|
||||||
pub offset: f32,
|
pub offset: f32,
|
||||||
@ -20,9 +32,9 @@ pub struct CalData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CalData {
|
impl CalData {
|
||||||
fn new() -> CalData {
|
pub fn new(offset: f32) -> CalData {
|
||||||
CalData {
|
CalData {
|
||||||
offset: 0.0,
|
offset,
|
||||||
raw_value: None,
|
raw_value: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,22 +56,12 @@ impl SystemConfig {
|
|||||||
SystemConfig {
|
SystemConfig {
|
||||||
max_temp_diff: 8.0,
|
max_temp_diff: 8.0,
|
||||||
min_temp_diff: 4.0,
|
min_temp_diff: 4.0,
|
||||||
ext_offset: CalData::new(),
|
ext_offset: CalData::new(0.0),
|
||||||
p1_offset: CalData::new(),
|
p1_offset: CalData::new(0.0),
|
||||||
p2_offset: CalData::new(),
|
p2_offset: CalData::new(0.0),
|
||||||
fan_output: FanOutput::P1,
|
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------------------------------------------------------------------------------------
|
//---Menu struct------------------------------------------------------------------------------------
|
||||||
@ -86,9 +88,9 @@ impl Menu {
|
|||||||
Entry::new("fan out", EntryValue::FanOut (FanOutput::P1), config),
|
Entry::new("fan out", EntryValue::FanOut (FanOutput::P1), config),
|
||||||
Entry::new("max diff", EntryValue::MaxTempDiff (0.0), config),
|
Entry::new("max diff", EntryValue::MaxTempDiff (0.0), config),
|
||||||
Entry::new("min diff", EntryValue::MinTempDiff (0.0), config),
|
Entry::new("min diff", EntryValue::MinTempDiff (0.0), config),
|
||||||
Entry::new("ext cal", EntryValue::ExtOffset (CalData::new()), config),
|
Entry::new("ext cal", EntryValue::ExtOffset (CalData::new(0.0)), config),
|
||||||
Entry::new("p1 cal", EntryValue::P1Offset (CalData::new()), config),
|
Entry::new("p1 cal", EntryValue::P1Offset (CalData::new(0.0)), config),
|
||||||
Entry::new("p2 cal", EntryValue::P2Offset (CalData::new()), config),
|
Entry::new("p2 cal", EntryValue::P2Offset (CalData::new(0.0)), config),
|
||||||
],
|
],
|
||||||
state: MenuState::Scroll,
|
state: MenuState::Scroll,
|
||||||
should_refresh: true,
|
should_refresh: true,
|
||||||
|
|||||||
21
src/main.rs
21
src/main.rs
@ -32,6 +32,7 @@ use lcd_gui::{LCDGui, GUI_TICK_SEC};
|
|||||||
mod utils;
|
mod utils;
|
||||||
use utils::{
|
use utils::{
|
||||||
TemperatureProbe,
|
TemperatureProbe,
|
||||||
|
ConfigStorage,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
@ -58,7 +59,7 @@ static TICK_TIMER: Mutex<RefCell<Option<CountDownTimer<pac::TIM2>>>>
|
|||||||
= Mutex::new(RefCell::new(None));
|
= Mutex::new(RefCell::new(None));
|
||||||
|
|
||||||
// button interrupt
|
// 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));
|
= Mutex::new(RefCell::new(None));
|
||||||
static BUTTON_FLAG: AtomicBool = AtomicBool::new(false);
|
static BUTTON_FLAG: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
@ -185,14 +186,18 @@ fn main() -> ! {
|
|||||||
let mut afio = dp.AFIO.constrain();
|
let mut afio = dp.AFIO.constrain();
|
||||||
|
|
||||||
// initialize system state
|
// initialize system state
|
||||||
|
let mut config_storage = ConfigStorage::new(backup_domain, dp.CRC.new());
|
||||||
let mut error_state = ErrorState::NoError;
|
let mut error_state = ErrorState::NoError;
|
||||||
let config = match SystemConfig::load() {
|
let config = match config_storage.load_config() {
|
||||||
Ok(conf) => conf,
|
Ok(conf) => conf,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
error_state = ErrorState::NewError("config invalide");
|
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
|
// Setup display
|
||||||
let mut gui = {
|
let mut gui = {
|
||||||
@ -234,7 +239,7 @@ fn main() -> ! {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// setup button (interrupt)
|
// 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.make_interrupt_source(&mut afio);
|
||||||
but_pin.trigger_on_edge(&dp.EXTI, Edge::Rising);
|
but_pin.trigger_on_edge(&dp.EXTI, Edge::Rising);
|
||||||
but_pin.enable_interrupt(&dp.EXTI);
|
but_pin.enable_interrupt(&dp.EXTI);
|
||||||
@ -300,6 +305,12 @@ fn main() -> ! {
|
|||||||
/* run */
|
/* run */
|
||||||
let _ = TEMP_FLAG.swap(true, Ordering::Release);
|
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 {
|
loop {
|
||||||
|
|
||||||
match error_state {
|
match error_state {
|
||||||
|
|||||||
@ -6,6 +6,8 @@ use crate::config::{
|
|||||||
FanOutput,
|
FanOutput,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::utils::ConfigStorage;
|
||||||
|
|
||||||
pub enum FanState {
|
pub enum FanState {
|
||||||
On,
|
On,
|
||||||
Off,
|
Off,
|
||||||
@ -43,6 +45,7 @@ impl<O: OutputPin> Fan<O> {
|
|||||||
|
|
||||||
pub struct SystemState<O: OutputPin> {
|
pub struct SystemState<O: OutputPin> {
|
||||||
config: SystemConfig,
|
config: SystemConfig,
|
||||||
|
config_storage: ConfigStorage,
|
||||||
ext_temp: Option<f32>,
|
ext_temp: Option<f32>,
|
||||||
p1_temp: Option<f32>,
|
p1_temp: Option<f32>,
|
||||||
p2_temp: Option<f32>,
|
p2_temp: Option<f32>,
|
||||||
@ -51,10 +54,12 @@ pub struct SystemState<O: OutputPin> {
|
|||||||
|
|
||||||
impl<O: OutputPin> SystemState<O> {
|
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 {
|
SystemState {
|
||||||
config,
|
config,
|
||||||
|
config_storage,
|
||||||
ext_temp: None,
|
ext_temp: None,
|
||||||
p1_temp: None,
|
p1_temp: None,
|
||||||
p2_temp: None,
|
p2_temp: None,
|
||||||
@ -76,6 +81,7 @@ impl<O: OutputPin> SystemState<O> {
|
|||||||
|
|
||||||
// replace config
|
// replace config
|
||||||
self.config = config;
|
self.config = config;
|
||||||
|
self.config_storage.save_config(&self.config);
|
||||||
|
|
||||||
// reset fan state before recomputing fan state
|
// reset fan state before recomputing fan state
|
||||||
self.fan.off();
|
self.fan.off();
|
||||||
|
|||||||
86
src/utils.rs
86
src/utils.rs
@ -6,8 +6,17 @@ use core::{
|
|||||||
|
|
||||||
use embedded_hal::adc::*;
|
use embedded_hal::adc::*;
|
||||||
|
|
||||||
|
use stm32f1xx_hal::{
|
||||||
|
backup_domain::BackupDomain,
|
||||||
|
crc::Crc,
|
||||||
|
};
|
||||||
|
|
||||||
use libm::*;
|
use libm::*;
|
||||||
|
|
||||||
|
use half::f16;
|
||||||
|
|
||||||
|
use crate::config::SystemConfig;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
/* 2nd order linearisation factor for the temperature probe */
|
/* 2nd order linearisation factor for the temperature probe */
|
||||||
const A: f32 = -0.000574;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user