319 lines
9.2 KiB
Rust
319 lines
9.2 KiB
Rust
use core::fmt;
|
|
|
|
use crate::lcd_gui::LCDScreen;
|
|
|
|
//---Config struct----------------------------------------------------------------------------------
|
|
|
|
#[derive(Copy, Clone)]
|
|
pub enum FanOutput {
|
|
P1,
|
|
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,
|
|
pub raw_value: Option<f32>,
|
|
}
|
|
|
|
impl CalData {
|
|
pub fn new(offset: f32) -> CalData {
|
|
CalData {
|
|
offset,
|
|
raw_value: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone)]
|
|
pub struct SystemConfig {
|
|
pub max_temp_diff: f32,
|
|
pub min_temp_diff: f32,
|
|
pub ext_offset: CalData,
|
|
pub p1_offset: CalData,
|
|
pub p2_offset: CalData,
|
|
pub fan_output: FanOutput,
|
|
}
|
|
|
|
impl SystemConfig {
|
|
|
|
pub fn new() -> SystemConfig {
|
|
SystemConfig {
|
|
max_temp_diff: 8.0,
|
|
min_temp_diff: 4.0,
|
|
ext_offset: CalData::new(0.0),
|
|
p1_offset: CalData::new(0.0),
|
|
p2_offset: CalData::new(0.0),
|
|
fan_output: FanOutput::P1,
|
|
}
|
|
}
|
|
}
|
|
|
|
//---Menu struct------------------------------------------------------------------------------------
|
|
const MENU_ENTRY_NB: usize = 6;
|
|
|
|
pub enum MenuState {
|
|
Scroll,
|
|
Entry,
|
|
}
|
|
|
|
pub struct Menu {
|
|
entries: [Entry; MENU_ENTRY_NB],
|
|
state: MenuState,
|
|
should_refresh: bool,
|
|
entry_index: usize,
|
|
}
|
|
|
|
impl Menu {
|
|
|
|
pub fn new(config: &SystemConfig) -> Menu {
|
|
|
|
Menu {
|
|
entries: [
|
|
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("ex", EntryValue::ExtOffset (CalData::new(0.0)), config),
|
|
Entry::new("s1", EntryValue::P1Offset (CalData::new(0.0)), config),
|
|
Entry::new("s2", EntryValue::P2Offset (CalData::new(0.0)), config),
|
|
],
|
|
state: MenuState::Scroll,
|
|
should_refresh: true,
|
|
entry_index: 0,
|
|
}
|
|
}
|
|
|
|
pub fn button_update(&mut self, config: &mut SystemConfig) -> bool {
|
|
|
|
self.should_refresh = true;
|
|
|
|
// update state machine
|
|
match self.state {
|
|
MenuState::Scroll => {
|
|
if self.entry_index == 0 { return true }
|
|
// read desired value from config
|
|
self.state = MenuState::Entry;
|
|
self.entries[self.entry_index - 1].select(config);
|
|
},
|
|
MenuState::Entry => {
|
|
// write modified value to config
|
|
self.state = MenuState::Scroll;
|
|
self.entries[self.entry_index - 1].deselect(config);
|
|
}
|
|
}
|
|
|
|
false
|
|
}
|
|
|
|
pub fn movement_update(&mut self, movement: i32) {
|
|
|
|
if movement != 0 {
|
|
match self.state {
|
|
MenuState::Scroll => {
|
|
|
|
// convert movement to entry index
|
|
let mut index = self.entry_index as i32 + movement;
|
|
if index > MENU_ENTRY_NB as i32 {
|
|
index = MENU_ENTRY_NB as i32;
|
|
} else if index < 0 {
|
|
index = 0;
|
|
}
|
|
self.entry_index = index as usize;
|
|
},
|
|
MenuState::Entry => {
|
|
|
|
// update entry
|
|
self.entries[self.entry_index - 1].update(-movement);
|
|
//note : "-" sign is just to revert encoder direction, feels better when using
|
|
//the interface
|
|
},
|
|
}
|
|
|
|
self.should_refresh = true;
|
|
}
|
|
}
|
|
|
|
pub fn reset(&mut self) {
|
|
|
|
match self.state {
|
|
MenuState::Entry => {
|
|
// if an entry is selected, disguard all modifications
|
|
self.entries[self.entry_index - 1].disgard();
|
|
self.state = MenuState::Scroll;
|
|
},
|
|
_ => (),
|
|
}
|
|
|
|
self.entry_index = 0;
|
|
}
|
|
|
|
pub fn display<L: LCDScreen>(&mut self, screen: &mut L) {
|
|
|
|
if self.should_refresh {
|
|
|
|
// first line
|
|
screen.clear();
|
|
screen.set_cursor_pos(0);
|
|
let _ = write!(screen, "\u{007e}");
|
|
if self.entry_index == 0 {
|
|
let _ = write!(screen, "retour");
|
|
} else {
|
|
self.entries[self.entry_index - 1].display(screen);
|
|
}
|
|
|
|
// second line (if any)
|
|
if self.entry_index < MENU_ENTRY_NB {
|
|
screen.set_cursor_pos(0x40);
|
|
let _ = write!(screen, " ");
|
|
self.entries[self.entry_index].display(screen);
|
|
}
|
|
|
|
self.should_refresh = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub enum EntryValue {
|
|
MaxTempDiff (f32),
|
|
MinTempDiff (f32),
|
|
ExtOffset (CalData),
|
|
P1Offset (CalData),
|
|
P2Offset (CalData),
|
|
FanOut (FanOutput),
|
|
}
|
|
|
|
impl EntryValue {
|
|
|
|
fn modify(&mut self, n: i32) {
|
|
use libm::{powf, copysignf, fabsf};
|
|
|
|
use crate::utils::TEMP_RANGE;
|
|
|
|
match self {
|
|
Self::MaxTempDiff (val) | Self::MinTempDiff (val) => {
|
|
*val += copysignf(fabsf(n as f32) * 0.85 * powf(10.0, 0.15 * fabsf(n as f32))
|
|
* 0.1, n as f32);
|
|
// avoid display issues by limiting value range
|
|
if *val > 99.9 { *val = 99.9; }
|
|
else if *val < -99.9 { *val = -99.9; }
|
|
},
|
|
Self::ExtOffset (data) | Self::P1Offset (data) | Self::P2Offset (data) => {
|
|
data.offset += copysignf(fabsf(n as f32) * 0.85
|
|
* powf(10.0, 0.15 * fabsf(n as f32)) * 0.1, n as f32);
|
|
// avoid limiting issues like before, taking probe bounds into account
|
|
if data.offset + TEMP_RANGE.end > 99.9 {
|
|
data.offset = 99.9 - TEMP_RANGE.end;
|
|
}
|
|
else if data.offset + TEMP_RANGE.start < -99.9 {
|
|
data.offset = -99.9 - TEMP_RANGE.start;
|
|
}
|
|
},
|
|
Self::FanOut (output) => {
|
|
if n%2 != 0 {
|
|
match output {
|
|
FanOutput::P1 => *output = FanOutput::P2,
|
|
FanOutput::P2 => *output = FanOutput::P1,
|
|
}}}}
|
|
}
|
|
|
|
fn load(&mut self, config: &SystemConfig) {
|
|
match self {
|
|
Self::MaxTempDiff (val) => *val = config.max_temp_diff,
|
|
Self::MinTempDiff (val) => *val = config.min_temp_diff,
|
|
Self::ExtOffset (data) => *data = config.ext_offset,
|
|
Self::P1Offset (data) => *data = config.p1_offset,
|
|
Self::P2Offset (data) => *data = config.p2_offset,
|
|
Self::FanOut (val) => *val = config.fan_output,
|
|
};
|
|
}
|
|
|
|
fn store(&mut self, config: &mut SystemConfig) {
|
|
match self {
|
|
Self::MaxTempDiff (val) => config.max_temp_diff = *val,
|
|
Self::MinTempDiff (val) => config.min_temp_diff = *val,
|
|
Self::ExtOffset (data) => config.ext_offset = *data,
|
|
Self::P1Offset (data) => config.p1_offset = *data,
|
|
Self::P2Offset (data) => config.p2_offset = *data,
|
|
Self::FanOut (val) => config.fan_output = *val,
|
|
};
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for EntryValue {
|
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
use crate::lcd_gui::Temp;
|
|
|
|
match self {
|
|
Self::MaxTempDiff (val) | Self::MinTempDiff (val) =>
|
|
formatter.write_fmt(format_args!("{:.1}", val)),
|
|
Self::ExtOffset (data) | Self::P1Offset (data) | Self::P2Offset (data) => {
|
|
let temp: Temp = data.raw_value.map(|val| val + data.offset).into();
|
|
formatter.write_fmt(format_args!("{:.1}({:.1})", data.offset, temp))
|
|
},
|
|
Self::FanOut (output) => {
|
|
match output {
|
|
FanOutput::P1 => formatter.write_fmt(format_args!("1")),
|
|
FanOutput::P2 => formatter.write_fmt(format_args!("2")),
|
|
}}}
|
|
}
|
|
}
|
|
|
|
|
|
pub struct Entry {
|
|
text: &'static str,
|
|
value: EntryValue,
|
|
is_selected: bool,
|
|
}
|
|
|
|
impl Entry {
|
|
|
|
pub fn new(text: &'static str, mut value: EntryValue, config: &SystemConfig) -> Entry {
|
|
|
|
value.load(config);
|
|
Entry {
|
|
text,
|
|
value,
|
|
is_selected: false,
|
|
}
|
|
}
|
|
|
|
pub fn display<B: core::fmt::Write>(&self, buffer: &mut B) {
|
|
let _ = match self.is_selected {
|
|
true => write!(buffer, "{}:{}", self.text, self.value),
|
|
false => write!(buffer, "{} {}", self.text, self.value),
|
|
};
|
|
}
|
|
|
|
pub fn select(&mut self, config: &SystemConfig) {
|
|
self.is_selected = true;
|
|
self.value.load(config);
|
|
}
|
|
pub fn deselect(&mut self, config: &mut SystemConfig) {
|
|
self.is_selected = false;
|
|
self.value.store(config);
|
|
}
|
|
|
|
pub fn disgard(&mut self) {
|
|
self.is_selected = false;
|
|
}
|
|
|
|
pub fn update(&mut self, n: i32) {
|
|
self.value.modify(n);
|
|
}
|
|
}
|