thermostat/src/channel_state.rs

80 lines
2.3 KiB
Rust
Raw Normal View History

use smoltcp::time::Instant;
2020-09-14 04:52:20 +08:00
use uom::si::{
2020-09-17 00:40:07 +08:00
f64::{
ElectricPotential,
ElectricalResistance,
ThermodynamicTemperature,
},
2020-09-14 04:52:20 +08:00
electric_potential::volt,
2020-09-17 00:40:07 +08:00
electrical_resistance::ohm,
2020-09-18 06:09:30 +08:00
thermodynamic_temperature::degree_celsius,
2020-09-14 04:52:20 +08:00
};
2020-05-17 07:23:35 +08:00
use crate::{
ad7172,
pid,
steinhart_hart as sh,
};
2020-09-17 02:49:24 +08:00
const R_INNER: f64 = 2.0 * 5100.0;
2020-09-17 05:31:49 +08:00
const VREF_SENS: f64 = 3.3 / 2.0;
pub struct ChannelState {
2020-03-20 06:39:06 +08:00
pub adc_data: Option<u32>,
pub adc_calibration: ad7172::ChannelCalibration,
pub adc_time: Instant,
2020-09-17 05:31:49 +08:00
/// VREF for the TEC (1.5V)
2020-09-17 02:49:24 +08:00
pub vref: ElectricPotential,
2020-09-14 04:52:20 +08:00
pub dac_value: ElectricPotential,
2020-05-13 06:04:55 +08:00
pub pid_engaged: bool,
pub pid: pid::Controller,
pub sh: sh::Parameters,
}
impl ChannelState {
pub fn new(adc_calibration: ad7172::ChannelCalibration) -> Self {
ChannelState {
adc_data: None,
adc_calibration,
adc_time: Instant::from_secs(0),
2020-09-17 02:49:24 +08:00
// can be initialized later with Channels.read_vref()
vref: ElectricPotential::new::<volt>(3.3 / 2.0),
2020-09-14 04:52:20 +08:00
dac_value: ElectricPotential::new::<volt>(0.0),
2020-05-13 06:04:55 +08:00
pid_engaged: false,
pid: pid::Controller::new(pid::Parameters::default()),
sh: sh::Parameters::default(),
}
}
pub fn update(&mut self, now: Instant, adc_data: u32) {
self.adc_data = Some(adc_data);
self.adc_time = now;
}
/// Update PID state on ADC input, calculate new DAC output
2020-09-18 06:09:30 +08:00
pub fn update_pid(&mut self) -> Option<f64> {
let temperature = self.get_temperature()?
.get::<degree_celsius>();
let pid_output = self.pid.update(temperature);
Some(pid_output)
}
pub fn get_adc(&self) -> Option<ElectricPotential> {
2020-09-17 02:49:24 +08:00
Some(self.adc_calibration.convert_data(self.adc_data?))
}
/// Get `SENS[01]` input resistance
pub fn get_sens(&self) -> Option<ElectricalResistance> {
let r_inner = ElectricalResistance::new::<ohm>(R_INNER);
2020-09-17 05:31:49 +08:00
let vref = ElectricPotential::new::<volt>(VREF_SENS);
2020-09-17 02:49:24 +08:00
let adc_input = self.get_adc()?;
2020-09-17 05:31:49 +08:00
let r = r_inner * adc_input / (vref - adc_input);
2020-09-17 02:49:24 +08:00
Some(r)
}
2020-09-17 00:40:07 +08:00
pub fn get_temperature(&self) -> Option<ThermodynamicTemperature> {
2020-09-17 02:49:24 +08:00
let r = self.get_sens()?;
let temperature = self.sh.get_temperature(r);
Some(temperature)
}
}