forked from M-Labs/kirdy
195 lines
6.2 KiB
Rust
195 lines
6.2 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use miniconf::Tree;
|
|
use uom::si::{
|
|
f32::ThermodynamicTemperature, thermodynamic_temperature::degree_celsius
|
|
};
|
|
use num_traits::Float;
|
|
#[derive(PartialEq, Deserialize, Serialize, Copy, Clone, Default, Debug)]
|
|
pub enum TempStatusEnum {
|
|
#[default]
|
|
Off,
|
|
OverTemp,
|
|
Unstable,
|
|
Stable,
|
|
ConstantCurrentMode,
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
|
pub struct TempStatus {
|
|
pub status: TempStatusEnum,
|
|
pub over_temp_alarm: bool,
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
|
pub struct TempMonSettings {
|
|
pub upper_limit: f32,
|
|
pub lower_limit: f32,
|
|
}
|
|
|
|
pub struct TempMon {
|
|
pub upper_limit: ThermodynamicTemperature,
|
|
pub lower_limit: ThermodynamicTemperature,
|
|
pub set_point: ThermodynamicTemperature,
|
|
pub status: TempStatus,
|
|
state: State,
|
|
count: u32,
|
|
is_set_point_changed: bool,
|
|
}
|
|
|
|
impl Default for TempMon {
|
|
fn default() -> Self {
|
|
Self {
|
|
upper_limit: ThermodynamicTemperature::new::<degree_celsius>(45.0),
|
|
lower_limit: ThermodynamicTemperature::new::<degree_celsius>(0.0),
|
|
set_point: ThermodynamicTemperature::new::<degree_celsius>(0.0),
|
|
status: TempStatus {
|
|
status: TempStatusEnum::Off,
|
|
over_temp_alarm: false
|
|
},
|
|
state: State::default(),
|
|
count: 0,
|
|
// stable_temp_count: 0,
|
|
is_set_point_changed: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Default, PartialEq, Debug)]
|
|
enum State {
|
|
#[default]
|
|
PwrOff,
|
|
ConstantCurrentMode,
|
|
PidStartUp,
|
|
PidStable,
|
|
OverTempAlarm,
|
|
}
|
|
|
|
impl TempMon {
|
|
const OVER_TEMP_COUNT_LIMIT: u32 = 25;
|
|
const TEMP_STABLE_COUNT_LIMIT: u32 = 100;
|
|
|
|
pub fn set_upper_limit(&mut self, upper_limit: ThermodynamicTemperature) {
|
|
self.upper_limit = upper_limit;
|
|
}
|
|
|
|
pub fn get_upper_limit(&mut self) -> ThermodynamicTemperature {
|
|
self.upper_limit
|
|
}
|
|
|
|
pub fn set_lower_limit(&mut self, lower_limit: ThermodynamicTemperature) {
|
|
self.lower_limit = lower_limit;
|
|
}
|
|
|
|
pub fn get_lower_limit(&mut self) -> ThermodynamicTemperature {
|
|
self.lower_limit
|
|
}
|
|
|
|
pub fn set_setpoint(&mut self, set_point: ThermodynamicTemperature) {
|
|
if self.set_point != set_point {
|
|
self.is_set_point_changed = true;
|
|
self.count = 0;
|
|
}
|
|
self.set_point = set_point;
|
|
}
|
|
|
|
pub fn clear_alarm(&mut self) {
|
|
self.status.over_temp_alarm = false;
|
|
self.state = State::default();
|
|
}
|
|
|
|
pub fn update_status(&mut self, pid_engaged: bool, pwr_on: bool, temp: ThermodynamicTemperature) {
|
|
match self.state {
|
|
State::PwrOff => {
|
|
self.is_set_point_changed = false;
|
|
self.status.status = TempStatusEnum::Off;
|
|
self.count = 0;
|
|
|
|
// State Transition
|
|
if pwr_on {
|
|
if pid_engaged {
|
|
self.state = State::PidStartUp;
|
|
} else {
|
|
self.state = State::ConstantCurrentMode
|
|
}
|
|
}
|
|
}
|
|
|
|
State::ConstantCurrentMode => {
|
|
let is_over_temp = temp > self.upper_limit || temp < self.lower_limit;
|
|
self.status.status = TempStatusEnum::ConstantCurrentMode;
|
|
|
|
if is_over_temp {
|
|
self.state = State::OverTempAlarm;
|
|
self.status.status = TempStatusEnum::OverTemp;
|
|
}
|
|
else if !pwr_on {
|
|
self.state = State::PwrOff;
|
|
self.status.status = TempStatusEnum::Off;
|
|
} else if pid_engaged {
|
|
self.state = State::PidStartUp;
|
|
self.status.status = TempStatusEnum::Unstable;
|
|
self.is_set_point_changed = false;
|
|
}
|
|
}
|
|
State::PidStartUp | State::PidStable => {
|
|
let is_over_temp: bool;
|
|
if self.state == State::PidStartUp {
|
|
is_over_temp = temp > self.upper_limit || temp < self.lower_limit;
|
|
} else {
|
|
is_over_temp = (temp.value - self.set_point.value).abs() > 0.5;
|
|
}
|
|
|
|
let is_within_spec: bool = (temp.value - self.set_point.value).abs() < 0.001;
|
|
if is_over_temp {
|
|
if self.count > TempMon::OVER_TEMP_COUNT_LIMIT {
|
|
self.status.status = TempStatusEnum::OverTemp;
|
|
} else {
|
|
self.count += 1;
|
|
}
|
|
} else if is_within_spec {
|
|
if self.count > TempMon::TEMP_STABLE_COUNT_LIMIT {
|
|
self.status.status = TempStatusEnum::Stable;
|
|
} else {
|
|
self.count += 1;
|
|
}
|
|
} else {
|
|
self.status.status = TempStatusEnum::Unstable;
|
|
self.count = 0;
|
|
}
|
|
|
|
// State Transition
|
|
if !pwr_on {
|
|
self.state = State::PwrOff;
|
|
}
|
|
else {
|
|
if self.status.status == TempStatusEnum::OverTemp {
|
|
self.state = State::OverTempAlarm;
|
|
} else if self.is_set_point_changed {
|
|
self.is_set_point_changed = false;
|
|
self.state = State::PidStartUp;
|
|
} else if self.status.status == TempStatusEnum::Stable {
|
|
self.state = State::PidStable;
|
|
} else if !pid_engaged {
|
|
self.state = State::ConstantCurrentMode
|
|
}
|
|
}
|
|
}
|
|
State::OverTempAlarm => {
|
|
self.is_set_point_changed = false;
|
|
self.status.over_temp_alarm = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn get_status(&mut self) -> TempStatus {
|
|
self.status
|
|
}
|
|
|
|
pub fn get_settings(&mut self) -> TempMonSettings {
|
|
TempMonSettings {
|
|
upper_limit: self.upper_limit.get::<degree_celsius>(),
|
|
lower_limit: self.lower_limit.get::<degree_celsius>(),
|
|
}
|
|
}
|
|
}
|