Support fan PWM settings #73

Merged
sb10q merged 16 commits from esavkin/thermostat:69-fan_pwm into master 2023-03-22 17:15:49 +08:00
6 changed files with 52 additions and 22 deletions
Showing only changes of commit 583d06a78b - Show all commits

View File

@ -95,7 +95,7 @@ Send commands as simple text string terminated by `\n`. Responses are
formatted as line-delimited JSON. formatted as line-delimited JSON.
| Syntax | Function | | Syntax | Function |
| --- | --- | |----------------------------------|----------------------------------------------------------------------|
| `report` | Show current input | | `report` | Show current input |
| `report mode` | Show current report mode | | `report mode` | Show current report mode |
| `report mode <off/on>` | Set report mode | | `report mode <off/on>` | Set report mode |
@ -124,6 +124,7 @@ formatted as line-delimited JSON.
| `reset` | Reset the device | | `reset` | Reset the device |
| `dfu` | Reset device and enters USB device firmware update (DFU) mode | | `dfu` | Reset device and enters USB device firmware update (DFU) mode |
| `ipv4 <X.X.X.X/L> [Y.Y.Y.Y]` | Configure IPv4 address, netmask length, and optional default gateway | | `ipv4 <X.X.X.X/L> [Y.Y.Y.Y]` | Configure IPv4 address, netmask length, and optional default gateway |
| `fan` | Show current fan settings and sensors' measurements |
| `fan <value>` | Set fan power with values from 0 to 100, where 0 is auto mode (TODO) | | `fan <value>` | Set fan power with values from 0 to 100, where 0 is auto mode (TODO) |

View File

@ -69,7 +69,7 @@
buildInputs = with pkgs; [ buildInputs = with pkgs; [
rustPlatform.rust.rustc rustPlatform.rust.rustc
rustPlatform.rust.cargo rustPlatform.rust.cargo
openocd dfu-util openocd dfu-util gcc-arm-embedded-10
] ++ (with python3Packages; [ ] ++ (with python3Packages; [
numpy matplotlib numpy matplotlib
]); ]);

View File

@ -1,3 +1,4 @@
use core::cmp::max_by;
use heapless::{consts::{U2, U1024}, Vec}; use heapless::{consts::{U2, U1024}, Vec};
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};
use smoltcp::time::Instant; use smoltcp::time::Instant;
@ -82,6 +83,10 @@ impl Channels {
} }
} }
pub fn fan_available(&self) -> bool {
self.hw_rev.major == 2 && self.hw_rev.minor == 2
}
pub fn channel_state<I: Into<usize>>(&mut self, channel: I) -> &mut ChannelState { pub fn channel_state<I: Into<usize>>(&mut self, channel: I) -> &mut ChannelState {
match channel.into() { match channel.into() {
0 => &mut self.channel0.state, 0 => &mut self.channel0.state,
@ -461,7 +466,7 @@ impl Channels {
(self.get_pwm(0, PwmPin::Fan) * 100.0) as u32 (self.get_pwm(0, PwmPin::Fan) * 100.0) as u32
} }
fn report(&mut self, channel: usize, tacho: Option<u32>) -> Report { fn report(&mut self, channel: usize) -> Report {
let vref = self.channel_state(channel).vref; let vref = self.channel_state(channel).vref;
let i_set = self.get_i(channel); let i_set = self.get_i(channel);
let i_tec = self.read_itec(channel); let i_tec = self.read_itec(channel);
@ -486,15 +491,14 @@ impl Channels {
tec_i, tec_i,
tec_u_meas: self.get_tec_v(channel), tec_u_meas: self.get_tec_v(channel),
pid_output, pid_output,
tacho,
hwrev: self.hw_rev hwrev: self.hw_rev
} }
} }
pub fn reports_json(&mut self, tacho: Option<u32>) -> Result<JsonBuffer, serde_json_core::ser::Error> { pub fn reports_json(&mut self) -> Result<JsonBuffer, serde_json_core::ser::Error> {
let mut reports = Vec::<_, U2>::new(); let mut reports = Vec::<_, U2>::new();
for channel in 0..CHANNELS { for channel in 0..CHANNELS {
let _ = reports.push(self.report(channel, tacho)); let _ = reports.push(self.report(channel));
} }
serde_json_core::to_vec(&reports) serde_json_core::to_vec(&reports)
} }
@ -515,7 +519,6 @@ impl Channels {
max_v: (self.get_max_v(channel), ElectricPotential::new::<volt>(5.0)).into(), max_v: (self.get_max_v(channel), ElectricPotential::new::<volt>(5.0)).into(),
max_i_pos: self.get_max_i_pos(channel).into(), max_i_pos: self.get_max_i_pos(channel).into(),
max_i_neg: self.get_max_i_neg(channel).into(), max_i_neg: self.get_max_i_neg(channel).into(),
fan: self.get_fan_pwm(),
} }
} }
@ -553,6 +556,20 @@ impl Channels {
} }
serde_json_core::to_vec(&summaries) serde_json_core::to_vec(&summaries)
} }
pub fn fan_summary(&mut self, tacho: Option<u32>) -> Result<JsonBuffer, serde_json_core::ser::Error> {
if self.fan_available() {
let summary = FanSummary {
fan_pwm: self.get_fan_pwm(),
tacho: tacho.unwrap_or(u32::MAX),
abs_max_tec_i: max_by(self.get_tec_i(0).abs().value, self.get_tec_i(1).abs().value, |a, b| a.partial_cmp(b).unwrap())
};
serde_json_core::to_vec(&summary)
} else {
let summary: Option<()> = None;
serde_json_core::to_vec(&summary)
}
}
} }
type JsonBuffer = Vec<u8, U1024>; type JsonBuffer = Vec<u8, U1024>;
@ -574,7 +591,6 @@ pub struct Report {
tec_i: ElectricCurrent, tec_i: ElectricCurrent,
tec_u_meas: ElectricPotential, tec_u_meas: ElectricPotential,
pid_output: ElectricCurrent, pid_output: ElectricCurrent,
tacho: Option<u32>,
hwrev: HWRev, hwrev: HWRev,
} }
@ -615,7 +631,6 @@ pub struct PwmSummary {
max_v: PwmSummaryField<ElectricPotential>, max_v: PwmSummaryField<ElectricPotential>,
max_i_pos: PwmSummaryField<ElectricCurrent>, max_i_pos: PwmSummaryField<ElectricCurrent>,
max_i_neg: PwmSummaryField<ElectricCurrent>, max_i_neg: PwmSummaryField<ElectricCurrent>,
fan: u32,
} }
#[derive(Serialize)] #[derive(Serialize)]
@ -629,3 +644,10 @@ pub struct SteinhartHartSummary {
channel: usize, channel: usize,
params: steinhart_hart::Parameters, params: steinhart_hart::Parameters,
} }
#[derive(Serialize)]
pub struct FanSummary {
fan_pwm: u32,
tacho: u32,
abs_max_tec_i: f64,
}

View File

@ -93,8 +93,8 @@ impl Handler {
Ok(Handler::Handled) Ok(Handler::Handled)
} }
fn show_report(socket: &mut TcpSocket, channels: &mut Channels, tacho: Option<u32>) -> Result<Handler, Error> { fn show_report(socket: &mut TcpSocket, channels: &mut Channels) -> Result<Handler, Error> {
match channels.reports_json(tacho) { match channels.reports_json() {
Ok(buf) => { Ok(buf) => {
send_line(socket, &buf[..]); send_line(socket, &buf[..]);
} }
@ -344,14 +344,24 @@ impl Handler {
Ok(Handler::Reset) Ok(Handler::Reset)
} }
fn fan (channels: &mut Channels, fan_pwm: Option<u32>) -> Result<Handler, Error> { fn fan (socket: &mut TcpSocket, channels: &mut Channels, fan_pwm: Option<u32>, tacho_value: Option<u32>) -> Result<Handler, Error> {
match fan_pwm { match fan_pwm {
Some(val) => { Some(val) => {
channels.set_fan_pwm(val); channels.set_fan_pwm(val);
Ok(Handler::Handled) Ok(Handler::Handled)
}, },
None => { None => {
Err(Error::ReportError) match channels.fan_summary(tacho_value) {
Ok(buf) => {
send_line(socket, &buf);
}
Err(e) => {
error!("unable to serialize fan summary: {:?}", e);
let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e);
return Err(Error::ReportError);
}
};
Ok(Handler::Handled)
} }
} }
} }
@ -361,7 +371,7 @@ impl Handler {
Command::Quit => Ok(Handler::CloseSocket), Command::Quit => Ok(Handler::CloseSocket),
Command::Reporting(_reporting) => Handler::reporting(socket), Command::Reporting(_reporting) => Handler::reporting(socket),
Command::Show(ShowCommand::Reporting) => Handler::show_report_mode(socket, session), Command::Show(ShowCommand::Reporting) => Handler::show_report_mode(socket, session),
Command::Show(ShowCommand::Input) => Handler::show_report(socket, channels, tacho_value), Command::Show(ShowCommand::Input) => Handler::show_report(socket, channels),
Command::Show(ShowCommand::Pid) => Handler::show_pid(socket, channels), Command::Show(ShowCommand::Pid) => Handler::show_pid(socket, channels),
Command::Show(ShowCommand::Pwm) => Handler::show_pwm(socket, channels), Command::Show(ShowCommand::Pwm) => Handler::show_pwm(socket, channels),
Command::Show(ShowCommand::SteinhartHart) => Handler::show_steinhart_hart(socket, channels), Command::Show(ShowCommand::SteinhartHart) => Handler::show_steinhart_hart(socket, channels),
@ -379,7 +389,7 @@ impl Handler {
Command::Ipv4(config) => Handler::set_ipv4(socket, store, config), Command::Ipv4(config) => Handler::set_ipv4(socket, store, config),
Command::Reset => Handler::reset(channels), Command::Reset => Handler::reset(channels),
Command::Dfu => Handler::dfu(channels), Command::Dfu => Handler::dfu(channels),
Command::Fan {fan_pwm} => Handler::fan(channels, fan_pwm) Command::Fan {fan_pwm} => Handler::fan(socket, channels, fan_pwm, tacho_value)
} }
} }
} }

View File

View File

@ -152,7 +152,7 @@ fn main() -> ! {
} }
} }
let fan_available = channels.hw_rev.major == 2 && channels.hw_rev.minor == 2; let fan_available = channels.fan_available();
// default net config: // default net config:
let mut ipv4_config = Ipv4Config { let mut ipv4_config = Ipv4Config {
@ -206,12 +206,9 @@ fn main() -> ! {
let instant = Instant::from_millis(i64::from(timer::now())); let instant = Instant::from_millis(i64::from(timer::now()));
if fan_available { if fan_available {
let mut tacho_input = false; let tacho_input = tacho.check_interrupt();
cortex_m::interrupt::free(|_cs| {
tacho_input = tacho.check_interrupt();
tacho.clear_interrupt_pending_bit();
});
if tacho_input { if tacho_input {
tacho.clear_interrupt_pending_bit();
tacho_cnt += 1; tacho_cnt += 1;
} }
@ -262,7 +259,7 @@ fn main() -> ! {
} }
} else if socket.can_send() { } else if socket.can_send() {
if let Some(channel) = session.is_report_pending() { if let Some(channel) = session.is_report_pending() {
match channels.reports_json(tacho_value) { match channels.reports_json() {
Ok(buf) => { Ok(buf) => {
send_line(&mut socket, &buf[..]); send_line(&mut socket, &buf[..]);
session.mark_report_sent(channel); session.mark_report_sent(channel);