mirror of
https://github.com/hubaldv/bioz-host-rs.git
synced 2026-07-24 00:57:44 +00:00
Route start/stop via middle layer.
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
91
src/app.rs
91
src/app.rs
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user