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::(45.0), lower_limit: ThermodynamicTemperature::new::(0.0), set_point: ThermodynamicTemperature::new::(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::(), lower_limit: self.lower_limit.get::(), } } }