add auto-mode chlorine flow to desktop

This commit is contained in:
jess 2026-04-03 02:07:51 -07:00
parent c6bbaa5bc4
commit 03d10ab678
1 changed files with 147 additions and 46 deletions

View File

@ -17,6 +17,13 @@ use crate::protocol::{
use crate::storage::{self, Session, Storage};
use crate::udp::UdpEvent;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ClAutoState {
Idle,
LsvRunning,
MeasureRunning,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LsvDensityMode {
PtsPerMv,
@ -109,6 +116,8 @@ pub enum Message {
ClMeasTChanged(String),
ClRtiaSelected(LpRtia),
StartCl,
StartClAuto,
ClToggleManual,
/* pH */
PhStabilizeChanged(String),
StartPh,
@ -238,6 +247,9 @@ pub struct App {
cl_meas_t: String,
cl_rtia: LpRtia,
cl_data: text_editor::Content,
cl_manual_peaks: bool,
cl_auto_state: ClAutoState,
cl_auto_potentials: Option<crate::lsv_analysis::ClPotentials>,
/* pH */
ph_result: Option<PhResult>,
@ -482,6 +494,9 @@ impl App {
cl_meas_t: "5000".into(),
cl_rtia: LpRtia::R10K,
cl_data: text_editor::Content::with_text(&fmt_cl(&[])),
cl_manual_peaks: false,
cl_auto_state: ClAutoState::Idle,
cl_auto_potentials: None,
ph_result: None,
ph_stabilize: "30".into(),
@ -702,6 +717,27 @@ impl App {
}
}
self.status = st;
if self.cl_auto_state == ClAutoState::LsvRunning {
let pots = crate::lsv_analysis::derive_cl_potentials(&self.lsv_points);
self.cl_free_v = format!("{:.0}", pots.v_free);
self.cl_total_v = format!("{:.0}", pots.v_total);
self.cl_auto_potentials = Some(pots);
self.cl_auto_state = ClAutoState::MeasureRunning;
let v_cond = self.cl_cond_v.parse::<f32>().unwrap_or(800.0);
let t_cond = self.cl_cond_t.parse::<f32>().unwrap_or(2000.0);
let t_dep = self.cl_dep_t.parse::<f32>().unwrap_or(5000.0);
let t_meas = self.cl_meas_t.parse::<f32>().unwrap_or(5000.0);
self.send_cmd(&protocol::build_sysex_get_temp());
self.send_cmd(&protocol::build_sysex_start_cl(
v_cond, t_cond, pots.v_free, pots.v_total, t_dep, t_meas, self.cl_rtia,
));
self.status = format!(
"Auto Cl: measuring (free={:.0}, total={:.0})",
pots.v_free, pots.v_total
);
}
}
EisMessage::AmpStart { v_hold } => {
self.amp_points.clear();
@ -744,8 +780,24 @@ impl App {
if let Some(sid) = self.current_session {
self.save_cl(sid);
}
if self.cl_auto_state == ClAutoState::MeasureRunning {
self.cl_auto_state = ClAutoState::Idle;
if let Some(pots) = &self.cl_auto_potentials {
self.status = format!(
"Auto Cl complete: {} pts (free={:.0}{}, total={:.0}{})",
self.cl_points.len(),
pots.v_free,
if pots.v_free_detected { "" } else { " dflt" },
pots.v_total,
if pots.v_total_detected { "" } else { " dflt" },
);
} else {
self.status = format!("Chlorine complete: {} points", self.cl_points.len());
}
} else {
self.status = format!("Chlorine complete: {} points", self.cl_points.len());
}
}
EisMessage::PhResult(r) => {
if self.collecting_refs {
self.ph_ref = Some(r);
@ -932,6 +984,17 @@ impl App {
v_cond, t_cond, v_free, v_total, t_dep, t_meas, self.cl_rtia,
));
}
Message::StartClAuto => {
self.cl_auto_state = ClAutoState::LsvRunning;
self.cl_auto_potentials = None;
let density = self.lsv_density.parse::<f32>().unwrap_or(1.0);
let n = lsv_calc_points(-1100.0, 1100.0, 50.0, density, self.lsv_density_mode);
self.send_cmd(&protocol::build_sysex_start_lsv(-1100.0, 1100.0, 50.0, self.lsv_rtia, n));
self.status = "Auto Cl: running LSV sweep...".into();
}
Message::ClToggleManual => {
self.cl_manual_peaks = !self.cl_manual_peaks;
}
/* pH */
Message::PhStabilizeChanged(s) => self.ph_stabilize = s,
Message::StartPh => {
@ -1650,14 +1713,15 @@ impl App {
.align_y(iced::Alignment::End)
.into(),
Tab::Chlorine => row![
Tab::Chlorine => if self.cl_manual_peaks {
row![
button(text("Start LSV").size(13))
.style(style_action())
.padding([6, 16])
.on_press(Message::StartLsv),
button(text(if self.lsv_manual_peaks { "Manual" } else { "Auto" }).size(13))
button(text("Manual").size(13))
.padding([6, 12])
.on_press(Message::LsvToggleManual),
.on_press(Message::ClToggleManual),
rule::Rule::vertical(1),
column![
text("Cond mV").size(12),
@ -1694,7 +1758,44 @@ impl App {
]
.spacing(8)
.align_y(iced::Alignment::End)
.into(),
.into()
} else {
let auto_btn = {
let b = button(text("Start Auto").size(13))
.style(style_action())
.padding([6, 16]);
if self.cl_auto_state == ClAutoState::Idle {
b.on_press(Message::StartClAuto)
} else {
b
}
};
let pot_text = if let Some(pots) = &self.cl_auto_potentials {
format!(
"free={:.0}{} total={:.0}{}",
pots.v_free,
if pots.v_free_detected { "" } else { "?" },
pots.v_total,
if pots.v_total_detected { "" } else { "?" },
)
} else {
String::new()
};
row![
auto_btn,
button(text("Auto").size(13))
.padding([6, 12])
.on_press(Message::ClToggleManual),
column![
text("RTIA").size(12),
pick_list(LpRtia::ALL, Some(self.cl_rtia), Message::ClRtiaSelected).width(Length::Shrink),
].spacing(2),
text(pot_text).size(12),
]
.spacing(8)
.align_y(iced::Alignment::End)
.into()
},
Tab::Ph => row![
column![