Tabcontrol via controller.rs.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-04-30 09:33:45 +02:00
parent f34e4a4a16
commit c35287c02f
5 changed files with 350 additions and 289 deletions

View File

@@ -16,17 +16,13 @@ use tokio::sync::{mpsc, watch};
use eframe::egui::{self, Button, CollapsingHeader, Color32, ComboBox, DragValue, Id, Key, Label, Layout, Modal, Modifiers, RichText, TextEdit, Widget}; use eframe::egui::{self, Button, CollapsingHeader, Color32, ComboBox, DragValue, Id, Key, Label, Layout, Modal, Modifiers, RichText, TextEdit, Widget};
use egui_plot::{Corner, GridInput, GridMark, Legend, Line, Plot, PlotPoint, Points}; use egui_plot::{Corner, GridInput, GridMark, Legend, Line, Plot, PlotPoint, Points};
use egui_dock::{DockArea, DockState, Style}; use egui_dock::{DockArea, DockState, Style, TabViewer};
use egui_extras::{TableBuilder, Column}; use egui_extras::{TableBuilder, Column};
use crate::state::{AppState, ControlCommand, HardwareConnected, HardwareState, MeasurementDataState, Mode}; use crate::state::{AppState, ControlCommand, HardwareConnected, HardwareState, MeasurementDataState, Mode};
use crate::logging::LoggingStates; use crate::logging::LoggingStates;
use crate::plot::{TimeSeriesPlot, BodePlot}; use crate::signals::LoggingSignal;
use crate::icd::{BioImpedanceLeadMode, IcdDftNum, SweepPoints, ElectrodeOptionsWithMultiplexer};
use crate::signals::{LoggingSignal, StartStopSignal};
use crate::icd::{BioImpedanceLeadMode, IcdDftNum, SweepPoints, ElectrodeConfiguration, ElectrodeOptionsWithMultiplexer};
const LEAD_MODES: [BioImpedanceLeadMode; 2] = [ const LEAD_MODES: [BioImpedanceLeadMode; 2] = [
BioImpedanceLeadMode::TwoLead, BioImpedanceLeadMode::TwoLead,
@@ -46,7 +42,7 @@ const SWEEP_POINTS_VARIANTS: [SweepPoints; 2] = [
]; ];
#[derive(Clone, Copy,Debug, PartialEq, Eq)] #[derive(Clone, Copy,Debug, PartialEq, Eq)]
enum TabActive { pub enum TabActive {
Single, Single,
Sweep, Sweep,
Shortcuts, Shortcuts,
@@ -54,11 +50,11 @@ enum TabActive {
pub struct App { pub struct App {
tree: DockState<String>, tree: DockState<String>,
tab_viewer: TabViewer, tab_viewer: CustomTabs,
tab_active: TabActive, // tab_active: TabActive,
log_tx: mpsc::Sender<LoggingSignal>, log_tx: mpsc::Sender<LoggingSignal>,
pub gui_logging_state: Arc<Mutex<LoggingStates>>, pub gui_logging_state: Arc<Mutex<LoggingStates>>,
log_filename: String, log_filename: Arc<Mutex<String>>,
log_marker_modal: bool, log_marker_modal: bool,
log_marker: String, log_marker: String,
measurement_data: Arc<MeasurementDataState>, measurement_data: Arc<MeasurementDataState>,
@@ -67,9 +63,10 @@ pub struct App {
hardware_state_rx: sync::watch::Receiver<HardwareState> hardware_state_rx: sync::watch::Receiver<HardwareState>
} }
struct TabViewer { struct CustomTabs {
show_settings: bool, show_settings: bool,
show_settings_toggle: Option<bool>, show_settings_toggle: Option<bool>,
log_filename: Arc<Mutex<String>>,
measurement_data: Arc<MeasurementDataState>, measurement_data: Arc<MeasurementDataState>,
control_tx: mpsc::Sender<ControlCommand>, control_tx: mpsc::Sender<ControlCommand>,
app_state_rx: sync::watch::Receiver<AppState>, app_state_rx: sync::watch::Receiver<AppState>,
@@ -139,13 +136,13 @@ fn render_four_lead<T: ElectrodeOption>(
changed changed
} }
impl TabViewer { impl CustomTabs {
fn single_tab(&mut self, ui: &mut egui::Ui) { fn single_tab(&mut self, ui: &mut egui::Ui) {
egui::Frame::default().inner_margin(5).show(ui, |ui| { egui::Frame::default().inner_margin(5).show(ui, |ui| {
let settings = CollapsingHeader::new("Settings") let settings = CollapsingHeader::new("Settings")
.open(self.show_settings_toggle) .open(self.show_settings_toggle)
.show(ui, |ui| { .show(ui, |ui| {
if let running = self.hardware_state_rx.borrow().running { let running = self.hardware_state_rx.borrow().running;
ui.add_enabled_ui(!running, |ui| { ui.add_enabled_ui(!running, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label("Lead Mode:"); ui.label("Lead Mode:");
@@ -245,7 +242,6 @@ impl TabViewer {
} }
}); });
}); });
}
}); });
self.show_settings_toggle = None; self.show_settings_toggle = None;
@@ -303,7 +299,7 @@ impl TabViewer {
let settings = CollapsingHeader::new("Settings") let settings = CollapsingHeader::new("Settings")
.open(self.show_settings_toggle) .open(self.show_settings_toggle)
.show(ui, |ui| { .show(ui, |ui| {
if let running = self.hardware_state_rx.borrow().running { let running = self.hardware_state_rx.borrow().running;
ui.add_enabled_ui(!running, |ui| { ui.add_enabled_ui(!running, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label("Lead Mode:"); ui.label("Lead Mode:");
@@ -433,7 +429,6 @@ impl TabViewer {
}); });
}); });
}); });
}
}); });
self.show_settings_toggle = None; self.show_settings_toggle = None;
@@ -575,7 +570,7 @@ fn log10x_formatter(name: &str, value: &PlotPoint) -> String {
) )
} }
impl egui_dock::TabViewer for TabViewer { impl TabViewer for CustomTabs {
type Tab = String; type Tab = String;
fn title(&mut self, tab: &mut Self::Tab) -> eframe::egui::WidgetText { fn title(&mut self, tab: &mut Self::Tab) -> eframe::egui::WidgetText {
@@ -592,6 +587,32 @@ impl egui_dock::TabViewer for TabViewer {
} }
} }
} }
fn on_tab_button(&mut self, tab: &mut Self::Tab, _response: &egui::Response) {
if _response.clicked() {
let tab_active = match tab.as_str() {
"Single" => {
*self.log_filename.lock().unwrap() = format!("log_{}_single.csv", Local::now().format("%Y%m%d"));
TabActive::Single
},
"Sweep" => {
*self.log_filename.lock().unwrap() = format!("log_{}_sweep.csv", Local::now().format("%Y%m%d"));
TabActive::Sweep
},
"Shortcuts" => TabActive::Shortcuts,
_ => return,
};
self.control_tx.try_send(ControlCommand::Stop).unwrap();
self.control_tx.try_send(ControlCommand::ChangeActiveTab(tab_active)).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);
// });
// }
}
}
} }
impl App { impl App {
@@ -601,28 +622,34 @@ impl App {
app_state_rx: watch::Receiver<AppState>, app_state_rx: watch::Receiver<AppState>,
hardware_state_rx: watch::Receiver<HardwareState>) -> Self { hardware_state_rx: watch::Receiver<HardwareState>) -> Self {
// Step 1: Initialize shared fields first // Step 1: Initialize shared fields first
let tab_active = TabActive::Single; // let tab_active = app_state_rx.borrow().tab_active;
// Step 2: Now we can initialize tab_viewer // Step 2: Now we can initialize tab_viewer
let control_tx_clone = control_tx.clone(); let control_tx_clone = control_tx.clone();
let app_state_clone = app_state_rx.clone(); let app_state_clone = app_state_rx.clone();
let hardware_state_clone = hardware_state_rx.clone(); let hardware_state_clone = hardware_state_rx.clone();
let tab_viewer = TabViewer { measurement_data: measurement_data.clone(), let log_filename = Arc::new(Mutex::new(format!("log_{}_single.csv", Local::now().format("%Y%m%d"))));
let log_filename_clone = log_filename.clone();
let tab_viewer = CustomTabs {
measurement_data: measurement_data.clone(),
show_settings: false, show_settings: false,
show_settings_toggle: None, show_settings_toggle: None,
log_filename: log_filename_clone,
control_tx: control_tx_clone, control_tx: control_tx_clone,
app_state_rx: app_state_clone, app_state_rx: app_state_clone,
hardware_state_rx: hardware_state_clone hardware_state_rx: hardware_state_clone
}; };
// tab_viewer.on_tab_button(&mut "Single".to_string(), &egui::Response::clicked());
// Step 3: Construct App // Step 3: Construct App
let app = App { let app = App {
tree: DockState::new(vec!["Single".to_string(), "Sweep".to_string(), "Shortcuts".to_string()]), tree: DockState::new(vec!["Single".to_string(), "Sweep".to_string(), "Shortcuts".to_string()]),
tab_viewer, tab_viewer,
tab_active, // tab_active,
log_tx, log_tx,
gui_logging_state: Arc::new(Mutex::new(LoggingStates::Idle)), gui_logging_state: Arc::new(Mutex::new(LoggingStates::Idle)),
log_filename: format!("log_{}_single.csv", Local::now().format("%Y%m%d")), log_filename,
log_marker_modal: false, log_marker_modal: false,
log_marker: String::new(), log_marker: String::new(),
measurement_data, measurement_data,
@@ -654,7 +681,7 @@ impl App {
} }
pub fn toggle_start_stop(&self) { pub fn toggle_start_stop(&self) {
match (self.tab_active, self.hardware_state_rx.borrow().running) { match (self.app_state_rx.borrow().tab_active, self.hardware_state_rx.borrow().running) {
(TabActive::Single, false) => { (TabActive::Single, false) => {
self.control_tx.try_send(ControlCommand::Start(Mode::Single)).unwrap(); self.control_tx.try_send(ControlCommand::Start(Mode::Single)).unwrap();
}, },
@@ -724,7 +751,7 @@ impl eframe::App for App {
if ui.add_enabled(is_connected, custom_toggle_widget(&mut logging_enabled)).changed() { if ui.add_enabled(is_connected, custom_toggle_widget(&mut logging_enabled)).changed() {
let signal = match gui_logging_state { let signal = match gui_logging_state {
LoggingStates::Idle => LoggingSignal::StartFileLogging(self.log_filename.clone()), LoggingStates::Idle => LoggingSignal::StartFileLogging(self.log_filename.lock().unwrap().clone()),
LoggingStates::Starting | LoggingStates::Logging => LoggingSignal::StopFileLogging, LoggingStates::Starting | LoggingStates::Logging => LoggingSignal::StopFileLogging,
}; };
@@ -792,7 +819,7 @@ impl eframe::App for App {
ui.add_enabled_ui(gui_logging_state == LoggingStates::Idle, |ui| { ui.add_enabled_ui(gui_logging_state == LoggingStates::Idle, |ui| {
ui.label("Log filename:"); ui.label("Log filename:");
TextEdit::singleline(&mut self.log_filename).desired_width(150.0).id(Id::new("file_name_field")).ui(ui); TextEdit::singleline(&mut *self.log_filename.lock().unwrap()).desired_width(150.0).id(Id::new("file_name_field")).ui(ui);
}); });
// Spacer to push the LED to the right // Spacer to push the LED to the right
@@ -837,48 +864,6 @@ impl eframe::App for App {
.show_inside(ui, &mut self.tab_viewer); .show_inside(ui, &mut self.tab_viewer);
}); });
// Do something when a tab is changed
if let Some((_, tab)) = self.tree.find_active_focused() {
match tab.as_str() {
"Single" => {
if self.tab_active != TabActive::Single {
self.tab_active = TabActive::Single;
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);
});
}
self.log_filename = format!("log_{}_single.csv", Local::now().format("%Y%m%d"));
info!("Switched to Single tab");
}
}
"Sweep" => {
if self.tab_active != TabActive::Sweep {
self.tab_active = TabActive::Sweep;
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);
});
}
self.log_filename = format!("log_{}_sweep.csv", Local::now().format("%Y%m%d"));
info!("Switched to Sweep tab");
}
}
"Shortcuts" => {
// if self.tab_active != TabActive::Shortcuts {
// self.tab_active = TabActive::Shortcuts;
// *self.on.lock().unwrap() = false;
// self.update_start_stop();
// info!("Switched to Shortcuts tab");
// }
}
_ => {
}
}
}
// CMD- or control-W to close window // CMD- or control-W to close window
if ctx.input(|i| i.modifiers.cmd_ctrl_matches(Modifiers::COMMAND)) if ctx.input(|i| i.modifiers.cmd_ctrl_matches(Modifiers::COMMAND))
&& ctx.input(|i| i.key_pressed(Key::W)) && ctx.input(|i| i.key_pressed(Key::W))
@@ -927,7 +912,7 @@ impl eframe::App for App {
} }
}, },
LoggingStates::Idle => { LoggingStates::Idle => {
if let Err(e) = self.log_tx.try_send(LoggingSignal::StartFileLogging(self.log_filename.clone())) { if let Err(e) = self.log_tx.try_send(LoggingSignal::StartFileLogging(self.log_filename.lock().unwrap().clone())) {
error!("Failed to send logging signal: {:?}", e); error!("Failed to send logging signal: {:?}", e);
} }
}, },

View File

@@ -64,12 +64,12 @@ async fn main() {
tokio::spawn(async move { log_data(log_rx, gui_logging_state_1).await }); tokio::spawn(async move { log_data(log_rx, gui_logging_state_1).await });
// TCP command server in separate thread // TCP command server in separate thread
// let rt = Runtime::new().expect("Unable to create Runtime"); let rt = Runtime::new().expect("Unable to create Runtime");
// let tcp_run_impedancemeter_tx = hardware_control_tx.clone(); let app_control_tx_clone = app_control_tx.clone();
// std::thread::spawn(move || { std::thread::spawn(move || {
// rt.block_on(bioz_host_rs::tcp::tcp_command_server(tcp_run_impedancemeter_tx)); rt.block_on(bioz_host_rs::tcp::tcp_command_server(app_control_tx_clone));
// }); });
// Execute the runtime in its own thread. // Execute the runtime in its own thread.
let rt = Runtime::new().expect("Unable to create Runtime"); let rt = Runtime::new().expect("Unable to create Runtime");

View File

@@ -1,6 +1,6 @@
use log::info; use log::info;
use tokio::sync::{mpsc, watch}; use tokio::sync::{mpsc, watch};
use crate::{signals::StartStopSignal, state::{AppState, ControlCommand, HardwareConnected, HardwareState}}; use crate::{app::TabActive, signals::StartStopSignal, state::{AppState, ControlCommand, HardwareConnected, HardwareState}};
use crate::state::Mode; use crate::state::Mode;
@@ -32,29 +32,41 @@ pub async fn app_control_loop(mut app_control_rx: mpsc::Receiver<ControlCommand>
state.sweep_points = sweep_points; state.sweep_points = sweep_points;
info!("Sweep points changed to {:?}!", sweep_points); info!("Sweep points changed to {:?}!", sweep_points);
} }
ControlCommand::ChangeActiveTab(tab_active) => {
state.tab_active = tab_active;
info!("Active tab changed to {:?}!", tab_active);
}
ControlCommand::Start(mode) => { ControlCommand::Start(mode) => {
if hardware_state_rx.borrow().hardware_connected == HardwareConnected::None {
info!("Cannot start measurement: No hardware connected!");
continue;
}
state.mode = mode; state.mode = mode;
info!("Starting impedance hardware with mode {:?}...", mode); info!("Starting impedance hardware with mode {:?}...", mode);
match (mode, hardware_state_rx.borrow().hardware_connected) { match (mode, hardware_state_rx.borrow().hardware_connected) {
(Mode::Single, HardwareConnected::WithoutMultiplexer) => { (Mode::Single, HardwareConnected::WithoutMultiplexer) => {
info!("Starting single measurement..."); info!("Starting single measurement...");
state.tab_active = TabActive::Single;
hardware_control_tx.try_send(StartStopSignal::StartSingle( hardware_control_tx.try_send(StartStopSignal::StartSingle(
state.single_frequency, state.lead_mode, None, state.dft_num)).unwrap(); state.single_frequency, state.lead_mode, None, state.dft_num)).unwrap();
} }
(Mode::Single, HardwareConnected::WithMultiplexer) => { (Mode::Single, HardwareConnected::WithMultiplexer) => {
info!("Starting single measurement..."); info!("Starting single measurement...");
state.tab_active = TabActive::Single;
let electrode_config = state.electrode_settings.to_electrode_config(hardware_state_rx.borrow().hardware_connected, state.lead_mode); let electrode_config = state.electrode_settings.to_electrode_config(hardware_state_rx.borrow().hardware_connected, state.lead_mode);
hardware_control_tx.try_send(StartStopSignal::StartSingle( hardware_control_tx.try_send(StartStopSignal::StartSingle(
state.single_frequency, state.lead_mode, electrode_config, state.dft_num)).unwrap(); state.single_frequency, state.lead_mode, electrode_config, state.dft_num)).unwrap();
} }
(Mode::Sweep, HardwareConnected::WithoutMultiplexer) => { (Mode::Sweep, HardwareConnected::WithoutMultiplexer) => {
info!("Starting sweep measurement..."); info!("Starting sweep measurement...");
state.tab_active = TabActive::Sweep;
hardware_control_tx.try_send(StartStopSignal::StartSweep( hardware_control_tx.try_send(StartStopSignal::StartSweep(
state.lead_mode, None, state.sweep_points)).unwrap(); state.lead_mode, None, state.sweep_points)).unwrap();
} }
(Mode::Sweep, HardwareConnected::WithMultiplexer) => { (Mode::Sweep, HardwareConnected::WithMultiplexer) => {
info!("Starting sweep measurement..."); info!("Starting sweep measurement...");
state.tab_active = TabActive::Sweep;
let electrode_config = state.electrode_settings.to_electrode_config(hardware_state_rx.borrow().hardware_connected, state.lead_mode); let electrode_config = state.electrode_settings.to_electrode_config(hardware_state_rx.borrow().hardware_connected, state.lead_mode);
hardware_control_tx.try_send(StartStopSignal::StartSweep( hardware_control_tx.try_send(StartStopSignal::StartSweep(
state.lead_mode, electrode_config, state.sweep_points)).unwrap(); state.lead_mode, electrode_config, state.sweep_points)).unwrap();
@@ -65,6 +77,10 @@ pub async fn app_control_loop(mut app_control_rx: mpsc::Receiver<ControlCommand>
} }
} }
ControlCommand::Stop => { ControlCommand::Stop => {
if hardware_state_rx.borrow().hardware_connected == HardwareConnected::None {
info!("Cannot stop measurement: No hardware connected!");
continue;
}
info!("Stopping impedance hardware..."); info!("Stopping impedance hardware...");
if let Err(e) = hardware_control_tx.try_send(StartStopSignal::Stop) { if let Err(e) = hardware_control_tx.try_send(StartStopSignal::Stop) {
info!("Failed to send stop command: {:?}", e); info!("Failed to send stop command: {:?}", e);

View File

@@ -1,8 +1,7 @@
use std::default;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use crate::app::TabActive;
use crate::icd::{BioImpedanceLeadMode, IcdDftNum, SweepPoints, ElectrodeConfiguration, ElectrodeOptionsWithMultiplexer}; use crate::icd::{BioImpedanceLeadMode, IcdDftNum, SweepPoints, ElectrodeConfiguration, ElectrodeOptionsWithMultiplexer};
use crate::logging::LoggingStates; use crate::logging::LoggingStates;
use crate::plot::{TimeSeriesPlot, BodePlot}; use crate::plot::{TimeSeriesPlot, BodePlot};
@@ -45,6 +44,7 @@ pub enum ControlCommand {
ChangeDftNum(IcdDftNum), ChangeDftNum(IcdDftNum),
ChangeElectrodeSettings(ElectrodeSettings), ChangeElectrodeSettings(ElectrodeSettings),
ChangeSweepPoints(SweepPoints), ChangeSweepPoints(SweepPoints),
ChangeActiveTab(TabActive),
Start(Mode), Start(Mode),
Stop, Stop,
} }
@@ -107,6 +107,7 @@ pub struct AppState {
pub dft_num: IcdDftNum, pub dft_num: IcdDftNum,
pub electrode_settings: ElectrodeSettings, pub electrode_settings: ElectrodeSettings,
pub sweep_points: SweepPoints, pub sweep_points: SweepPoints,
pub tab_active: TabActive,
pub logging: LoggingStates, pub logging: LoggingStates,
} }
@@ -119,6 +120,7 @@ impl Default for AppState {
dft_num: IcdDftNum::Num2048, dft_num: IcdDftNum::Num2048,
electrode_settings: ElectrodeSettings::new(), electrode_settings: ElectrodeSettings::new(),
sweep_points: SweepPoints::Eighteen, sweep_points: SweepPoints::Eighteen,
tab_active: TabActive::Single,
logging: LoggingStates::Idle, logging: LoggingStates::Idle,
} }
} }

View File

@@ -2,9 +2,9 @@ use tokio::net::TcpListener;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader, BufWriter}; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader, BufWriter};
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
use crate::signals::StartStopSignal; use crate::state::ControlCommand;
pub async fn tcp_command_server(tx: Sender<StartStopSignal>) { pub async fn tcp_command_server(app_control_tx: Sender<ControlCommand>) {
let listener = TcpListener::bind("127.0.0.1:12345").await.unwrap(); let listener = TcpListener::bind("127.0.0.1:12345").await.unwrap();
println!("TCP command server listening on 12345"); println!("TCP command server listening on 12345");
@@ -12,12 +12,12 @@ pub async fn tcp_command_server(tx: Sender<StartStopSignal>) {
let (socket, addr) = listener.accept().await.unwrap(); let (socket, addr) = listener.accept().await.unwrap();
println!("Client connected: {:?}", addr); println!("Client connected: {:?}", addr);
let tx = tx.clone(); let tx = app_control_tx.clone();
tokio::spawn(async move { tokio::spawn(async move {
let (reader, writer) = socket.into_split(); let (reader, writer) = socket.into_split();
let mut reader = BufReader::new(reader); let reader = BufReader::new(reader);
let mut writer = BufWriter::new(writer); let mut writer = BufWriter::new(writer);
let mut lines = reader.lines(); let mut lines = reader.lines();
@@ -46,11 +46,69 @@ pub async fn tcp_command_server(tx: Sender<StartStopSignal>) {
} }
} }
fn parse_command(line: &str) -> Option<StartStopSignal> { fn parse_command(line: &str) -> Option<ControlCommand> {
let parts: Vec<&str> = line.split_whitespace().collect(); let parts: Vec<&str> = line.split_whitespace().collect();
match parts.as_slice() { match parts.as_slice() {
["STOP"] => Some(StartStopSignal::Stop), // ["SET_FREQ", freq_str] => {
// if let Ok(freq) = freq_str.parse::<f32>() {
// Some(ControlCommand::SetFrequency(freq))
// } else {
// None
// }
// }
// ["SET_LEAD_MODE", mode_str] => {
// match mode_str.to_uppercase().as_str() {
// "LEAD_OFF" => Some(ControlCommand::ChangeLeadMode(crate::state::LeadMode::LeadOff)),
// "LEAD_I" => Some(ControlCommand::ChangeLeadMode(crate::state::LeadMode::LeadI)),
// "LEAD_II" => Some(ControlCommand::ChangeLeadMode(crate::state::LeadMode::LeadII)),
// "LEAD_III" => Some(ControlCommand::ChangeLeadMode(crate::state::LeadMode::LeadIII)),
// _ => None,
// }
// }
// ["SET_DFT_NUM", dft_num_str] => {
// if let Ok(dft_num) = dft_num_str.parse::<u32>() {
// Some(ControlCommand::ChangeDftNum(IcdDftNum(dft_num)))
// } else {
// None
// }
// }
// ["SET_SWEEP_POINTS", sweep_points_str] => {
// if let Ok(sweep_points) = sweep_points_str.parse::<u32>() {
// Some(ControlCommand::ChangeSweepPoints(SweepPoints(sweep_points)))
// } else {
// None
// }
// }
// ["SET_ELECTRODE_CONFIG", config_str] => {
// // Example: "SET_ELECTRODE_CONFIG 1,0,1,0,1,0,1,0"
// let config_parts: Vec<&str> = config_str.split(',').collect();
// if config_parts.len() == 8 {
// let mut config = [false; 8];
// for (i, part) in config_parts.iter().enumerate() {
// if let Ok(val) = part.parse::<u8>() {
// config[i] = val != 0;
// } else {
// return None;
// }
// }
// Some(ControlCommand::ChangeElectrodeSettings(crate::state::ElectrodeSettings(config)))
// } else {
// None
// }
// }
["START", mode_str] => {
match mode_str.to_uppercase().as_str() {
"SINGLE" => {
Some(ControlCommand::Start(crate::state::Mode::Single))
},
"SWEEP" => {
Some(ControlCommand::Start(crate::state::Mode::Sweep))
},
_ => None,
}
}
["STOP"] => Some(ControlCommand::Stop),
_ => { _ => {
eprintln!("Unknown command: {}", line); eprintln!("Unknown command: {}", line);