Route start/stop via middle layer.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-04-26 21:04:38 +02:00
parent 97bd27c945
commit f34e4a4a16
5 changed files with 131 additions and 101 deletions

View File

@@ -19,7 +19,7 @@ use egui_plot::{Corner, GridInput, GridMark, Legend, Line, Plot, PlotPoint, Poin
use egui_dock::{DockArea, DockState, Style};
use egui_extras::{TableBuilder, Column};
use crate::state::{AppState, ControlCommand, HardwareConnected, HardwareState, MeasurementDataState};
use crate::state::{AppState, ControlCommand, HardwareConnected, HardwareState, MeasurementDataState, Mode};
use crate::logging::LoggingStates;
use crate::plot::{TimeSeriesPlot, BodePlot};
@@ -56,9 +56,7 @@ pub struct App {
tree: DockState<String>,
tab_viewer: TabViewer,
tab_active: TabActive,
run_impedancemeter_tx: mpsc::Sender<StartStopSignal>,
log_tx: mpsc::Sender<LoggingSignal>,
pub on: Arc<Mutex<bool>>,
pub gui_logging_state: Arc<Mutex<LoggingStates>>,
log_filename: String,
log_marker_modal: bool,
@@ -70,7 +68,6 @@ pub struct App {
}
struct TabViewer {
on: Arc<Mutex<bool>>,
show_settings: bool,
show_settings_toggle: Option<bool>,
measurement_data: Arc<MeasurementDataState>,
@@ -148,8 +145,8 @@ impl TabViewer {
let settings = CollapsingHeader::new("Settings")
.open(self.show_settings_toggle)
.show(ui, |ui| {
if let Ok(on) = self.on.lock() {
ui.add_enabled_ui(!*on, |ui| {
if let running = self.hardware_state_rx.borrow().running {
ui.add_enabled_ui(!running, |ui| {
ui.horizontal(|ui| {
ui.label("Lead Mode:");
@@ -180,7 +177,7 @@ impl TabViewer {
ui.horizontal(|ui| {
// Show lead configuration
ui.label("Lead Configuration:");
let hardware_connected = self.hardware_state_rx.borrow().connected;
let hardware_connected = self.hardware_state_rx.borrow().hardware_connected;
let lead_mode = self.app_state_rx.borrow().lead_mode;
let mut settings = self.app_state_rx.borrow().electrode_settings;
@@ -206,7 +203,7 @@ impl TabViewer {
}
});
});
ui.add_enabled_ui(!*on, |ui| {
ui.add_enabled_ui(!running, |ui| {
ui.horizontal(|ui| {
ui.label("Single Frequency:");
let mut freq = self.app_state_rx.borrow().single_frequency;
@@ -232,10 +229,10 @@ impl TabViewer {
};
});
});
ui.add_enabled_ui(*on, |ui| {
ui.add_enabled_ui(running, |ui| {
ui.horizontal(|ui| {
ui.label("Periods per DFT:");
match (*on, self.hardware_state_rx.borrow().periods_per_dft) {
match (running, self.hardware_state_rx.borrow().periods_per_dft) {
(true, Some(periods)) => {
ui.add(Label::new(format!("{:.2}", periods)));
},
@@ -306,8 +303,8 @@ impl TabViewer {
let settings = CollapsingHeader::new("Settings")
.open(self.show_settings_toggle)
.show(ui, |ui| {
if let Ok(on) = self.on.lock() {
ui.add_enabled_ui(!*on, |ui| {
if let running = self.hardware_state_rx.borrow().running {
ui.add_enabled_ui(!running, |ui| {
ui.horizontal(|ui| {
ui.label("Lead Mode:");
@@ -338,7 +335,7 @@ impl TabViewer {
ui.horizontal(|ui| {
// Show lead configuration
ui.label("Lead Configuration:");
let hardware_connected = self.hardware_state_rx.borrow().connected;
let hardware_connected = self.hardware_state_rx.borrow().hardware_connected;
let lead_mode = self.app_state_rx.borrow().lead_mode;
let mut settings = self.app_state_rx.borrow().electrode_settings;
@@ -363,7 +360,7 @@ impl TabViewer {
}
});
});
ui.add_enabled_ui(!*on, |ui| {
ui.add_enabled_ui(!running, |ui| {
ui.horizontal(|ui| {
ui.label("Measurement Points:");
let mut measurement_points = self.app_state_rx.borrow().sweep_points;
@@ -381,7 +378,7 @@ impl TabViewer {
}
});
});
ui.add_enabled_ui(*on, |ui| {
ui.add_enabled_ui(running, |ui| {
let (freq, periods_per_dft_vec) = self.hardware_state_rx.borrow().periods_per_dft_sweep.clone();
fn format_frequency(freq: u32) -> String {
@@ -598,14 +595,12 @@ impl egui_dock::TabViewer for TabViewer {
}
impl App {
pub fn new(run_impedancemeter_tx: mpsc::Sender<StartStopSignal>,
log_tx: mpsc::Sender<LoggingSignal>,
pub fn new(log_tx: mpsc::Sender<LoggingSignal>,
measurement_data: Arc<MeasurementDataState>,
control_tx: mpsc::Sender<ControlCommand>,
app_state_rx: watch::Receiver<AppState>,
hardware_state_rx: watch::Receiver<HardwareState>) -> Self {
// Step 1: Initialize shared fields first
let on = Arc::new(Mutex::new(true));
let tab_active = TabActive::Single;
// Step 2: Now we can initialize tab_viewer
@@ -613,7 +608,6 @@ impl App {
let app_state_clone = app_state_rx.clone();
let hardware_state_clone = hardware_state_rx.clone();
let tab_viewer = TabViewer { measurement_data: measurement_data.clone(),
on: on.clone(),
show_settings: false,
show_settings_toggle: None,
control_tx: control_tx_clone,
@@ -626,9 +620,7 @@ impl App {
tree: DockState::new(vec!["Single".to_string(), "Sweep".to_string(), "Shortcuts".to_string()]),
tab_viewer,
tab_active,
run_impedancemeter_tx,
log_tx,
on,
gui_logging_state: Arc::new(Mutex::new(LoggingStates::Idle)),
log_filename: format!("log_{}_single.csv", Local::now().format("%Y%m%d")),
log_marker_modal: false,
@@ -657,31 +649,20 @@ impl App {
// app.bode_plot.lock().unwrap().update_magnitudes(MeasurementPointSet::Eighteen, magnitudes);
// app.bode_plot.lock().unwrap().update_phases(MeasurementPointSet::Eighteen, phases);
app.update_start_stop();
app.toggle_start_stop();
app
}
pub fn update_start_stop(&self) {
match (self.tab_active, *self.on.lock().unwrap()) {
(TabActive::Single, true) => {
let lead_mode = self.app_state_rx.borrow().lead_mode;
let electrode_config = self.app_state_rx.borrow().electrode_settings.to_electrode_config(self.hardware_state_rx.borrow().connected, lead_mode);
if let Err(e) = self.run_impedancemeter_tx.try_send(
StartStopSignal::StartSingle(self.app_state_rx.borrow().single_frequency, lead_mode, electrode_config, self.app_state_rx.borrow().dft_num)) {
error!("Failed to send start command: {:?}", e);
}
pub fn toggle_start_stop(&self) {
match (self.tab_active, self.hardware_state_rx.borrow().running) {
(TabActive::Single, false) => {
self.control_tx.try_send(ControlCommand::Start(Mode::Single)).unwrap();
},
(TabActive::Sweep, true) => {
let lead_mode = self.app_state_rx.borrow().lead_mode;
let electrode_config = self.app_state_rx.borrow().electrode_settings.to_electrode_config(self.hardware_state_rx.borrow().connected, lead_mode);
if let Err(e) = self.run_impedancemeter_tx.try_send(StartStopSignal::StartSweep(lead_mode, electrode_config, self.app_state_rx.borrow().sweep_points)) {
error!("Failed to send start command: {:?}", e);
}
(TabActive::Sweep, false) => {
self.control_tx.try_send(ControlCommand::Start(Mode::Sweep)).unwrap();
},
(_, false) => {
if let Err(e) = self.run_impedancemeter_tx.try_send(StartStopSignal::Stop) {
error!("Failed to send stop command: {:?}", e);
}
(_, true) => {
self.control_tx.try_send(ControlCommand::Stop).unwrap();
},
(_, _) => {}
}
@@ -698,7 +679,7 @@ impl eframe::App for App {
// Egui add a top bar
egui::TopBottomPanel::top("top_bar").show(ctx, |ui| {
egui::MenuBar::new().ui(ui, |ui| {
let is_connected = self.hardware_state_rx.borrow().connected != HardwareConnected::None;
let is_connected = self.hardware_state_rx.borrow().hardware_connected != HardwareConnected::None;
egui::widgets::global_theme_preference_switch(ui);
ui.separator();
@@ -707,9 +688,9 @@ impl eframe::App for App {
ui.separator();
let on = *self.on.lock().unwrap();
let running = self.hardware_state_rx.borrow().running;
let (color, text) = match on {
let (color, text) = match running {
true => (Color32::DARK_RED, "Stop"),
false => (Color32::DARK_GREEN, "Start"),
};
@@ -724,8 +705,7 @@ impl eframe::App for App {
.frame(true);
if ui.add_enabled(is_connected, start_stop_button).clicked() {
*self.on.lock().unwrap() = !on;
self.update_start_stop();
self.toggle_start_stop();
}
ui.separator();
@@ -742,7 +722,7 @@ impl eframe::App for App {
let mut logging_enabled = !matches!(gui_logging_state, LoggingStates::Idle);
if ui.add_enabled(is_connected, toggle_start_stop(&mut logging_enabled)).changed() {
if ui.add_enabled(is_connected, custom_toggle_widget(&mut logging_enabled)).changed() {
let signal = match gui_logging_state {
LoggingStates::Idle => LoggingSignal::StartFileLogging(self.log_filename.clone()),
LoggingStates::Starting | LoggingStates::Logging => LoggingSignal::StopFileLogging,
@@ -818,7 +798,7 @@ impl eframe::App for App {
// Spacer to push the LED to the right
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.scope(|ui| {
let (color, tooltip) = match self.hardware_state_rx.borrow().connected {
let (color, tooltip) = match self.hardware_state_rx.borrow().hardware_connected {
HardwareConnected::None => {
(Color32::DARK_RED, "Disconnected")
},
@@ -863,8 +843,7 @@ impl eframe::App for App {
"Single" => {
if self.tab_active != TabActive::Single {
self.tab_active = TabActive::Single;
*self.on.lock().unwrap() = false;
self.update_start_stop();
self.control_tx.try_send(ControlCommand::Stop).unwrap();
if *self.gui_logging_state.lock().unwrap() == LoggingStates::Logging {
self.log_tx.try_send(LoggingSignal::StopFileLogging).unwrap_or_else(|e| {
error!("Failed to send logging logging signal: {:?}", e);
@@ -877,8 +856,7 @@ impl eframe::App for App {
"Sweep" => {
if self.tab_active != TabActive::Sweep {
self.tab_active = TabActive::Sweep;
*self.on.lock().unwrap() = false;
self.update_start_stop();
self.control_tx.try_send(ControlCommand::Stop).unwrap();
if *self.gui_logging_state.lock().unwrap() == LoggingStates::Logging {
self.log_tx.try_send(LoggingSignal::StopFileLogging).unwrap_or_else(|e| {
error!("Failed to send logging logging signal: {:?}", e);
@@ -917,15 +895,12 @@ impl eframe::App for App {
// Space to start/stop measurement
if ctx.input(|i| i.key_pressed(Key::Space))
{
let value = *self.on.lock().unwrap();
*self.on.lock().unwrap() = !value;
self.update_start_stop();
self.toggle_start_stop();
}
// Send stop command when the window is closed
if ctx.input(|i| i.viewport().close_requested()) {
*self.on.lock().unwrap() = false;
self.update_start_stop();
self.toggle_start_stop();
}
// Reset view
@@ -1007,6 +982,6 @@ fn toggle_ui_start_stop(ui: &mut egui::Ui, on: &mut bool) -> egui::Response {
response
}
pub fn toggle_start_stop(on: &mut bool) -> impl egui::Widget + '_ {
pub fn custom_toggle_widget(on: &mut bool) -> impl egui::Widget + '_ {
move |ui: &mut egui::Ui| toggle_ui_start_stop(ui, on)
}