Major commit adding a control layer in between for later TCP use.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-04-26 18:54:12 +02:00
parent 0636305db5
commit 97bd27c945
9 changed files with 384 additions and 262 deletions

View File

@@ -1,6 +1,7 @@
use std::fmt::Debug;
use log::{info, error};
use tokio::sync;
use core::f32;
@@ -11,69 +12,27 @@ use std::sync::atomic::Ordering;
use chrono::Local;
use atomic_float::AtomicF32;
use tokio::{sync::mpsc::{Sender}};
use tokio::sync::{mpsc, watch};
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_dock::{DockArea, DockState, Style};
use egui_extras::{TableBuilder, Column};
use crate::state::{AppState, ControlCommand, HardwareConnected, HardwareState, MeasurementDataState};
use crate::logging::LoggingStates;
use crate::plot::{TimeSeriesPlot, BodePlot};
use crate::signals::{LoggingSignal, StartStopSignal};
use crate::icd::{BioImpedanceLeadMode, IcdDftNum, MeasurementPointSet, ElectrodeConfiguration, ElectrodeOptionsWithMultiplexer};
use crate::icd::{BioImpedanceLeadMode, IcdDftNum, SweepPoints, ElectrodeConfiguration, ElectrodeOptionsWithMultiplexer};
const LEAD_MODES: [BioImpedanceLeadMode; 2] = [
BioImpedanceLeadMode::TwoLead,
BioImpedanceLeadMode::FourLead,
];
struct ElectrodeSettings {
with_multiplexer_2_lead: [ElectrodeOptionsWithMultiplexer; 2],
with_multiplexer_4_lead: [ElectrodeOptionsWithMultiplexer; 4],
}
impl ElectrodeSettings {
pub fn new() -> Self {
Self {
with_multiplexer_2_lead: [
ElectrodeOptionsWithMultiplexer::E1, // Electrode+ default
ElectrodeOptionsWithMultiplexer::E23, // Electrode- default
],
with_multiplexer_4_lead: [
ElectrodeOptionsWithMultiplexer::E1, // I+ default
ElectrodeOptionsWithMultiplexer::E23, // I- default
ElectrodeOptionsWithMultiplexer::E10, // V+ default
ElectrodeOptionsWithMultiplexer::E12, // V- default
],
}
}
pub fn to_electrode_config(
&self,
hardware_connected: HardwareConnected,
lead_mode: BioImpedanceLeadMode,
) -> Option<ElectrodeConfiguration> {
if hardware_connected != HardwareConnected::WithMultiplexer {
return None;
}
match lead_mode {
BioImpedanceLeadMode::TwoLead => {
let [a, b] = self.with_multiplexer_2_lead;
Some(ElectrodeConfiguration::WithMultiplexer2Lead(a, b))
}
BioImpedanceLeadMode::FourLead => {
let [a, b, c, d] = self.with_multiplexer_4_lead;
Some(ElectrodeConfiguration::WithMultiplexer4Lead(a, b, c, d))
}
}
}
}
const DFTNUM_VARIANTS: [IcdDftNum; 13] = [
IcdDftNum::Num4, IcdDftNum::Num8, IcdDftNum::Num16, IcdDftNum::Num32,
IcdDftNum::Num64, IcdDftNum::Num128, IcdDftNum::Num256, IcdDftNum::Num512,
@@ -81,9 +40,9 @@ const DFTNUM_VARIANTS: [IcdDftNum; 13] = [
IcdDftNum::Num8192, IcdDftNum::Num16384,
];
const MEASUREMENT_POINTS_VARIANTS: [MeasurementPointSet; 2] = [
MeasurementPointSet::Eight,
MeasurementPointSet::Eighteen,
const SWEEP_POINTS_VARIANTS: [SweepPoints; 2] = [
SweepPoints::Eight,
SweepPoints::Eighteen,
];
#[derive(Clone, Copy,Debug, PartialEq, Eq)]
@@ -93,57 +52,31 @@ enum TabActive {
Shortcuts,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum HardwareConnected {
None,
WithoutMultiplexer,
WithMultiplexer,
}
pub struct App {
tree: DockState<String>,
tab_viewer: TabViewer,
run_impedancemeter_tx: Sender<StartStopSignal>,
log_tx: Sender<LoggingSignal>,
pub magnitude: Arc<Mutex<f32>>,
pub phase: Arc<Mutex<f32>>,
pub magnitude_series: Arc<Mutex<TimeSeriesPlot>>,
pub phase_series: Arc<Mutex<TimeSeriesPlot>>,
pub bode_plot: Arc<Mutex<BodePlot>>,
pub hardware_connected: Arc<Mutex<HardwareConnected>>,
pub on: Arc<Mutex<bool>>,
tab_active: TabActive,
pub data_frequency: Arc<AtomicF32>,
pub single_frequency: Arc<Mutex<u32>>,
pub lead_mode: Arc<Mutex<BioImpedanceLeadMode>>,
electrode_settings: Arc<Mutex<ElectrodeSettings>>,
pub dft_num: Arc<Mutex<IcdDftNum>>,
pub measurement_points: Arc<Mutex<MeasurementPointSet>>,
pub periods_per_dft: Arc<Mutex<Option<f32>>>,
pub periods_per_dft_sweep: Arc<Mutex<(Vec<u32>, Option<Vec<f32>>)>>,
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,
log_marker: String,
measurement_data: Arc<MeasurementDataState>,
control_tx: mpsc::Sender<ControlCommand>,
app_state_rx: sync::watch::Receiver<AppState>,
hardware_state_rx: sync::watch::Receiver<HardwareState>
}
struct TabViewer {
magnitude: Arc<Mutex<f32>>,
phase: Arc<Mutex<f32>>,
magnitude_series: Arc<Mutex<TimeSeriesPlot>>,
phase_series: Arc<Mutex<TimeSeriesPlot>>,
bode_plot: Arc<Mutex<BodePlot>>,
on: Arc<Mutex<bool>>,
single_frequency: Arc<Mutex<u32>>,
hardware_connected: Arc<Mutex<HardwareConnected>>,
lead_mode: Arc<Mutex<BioImpedanceLeadMode>>,
electrode_settings: Arc<Mutex<ElectrodeSettings>>,
dft_num: Arc<Mutex<IcdDftNum>>,
measurement_points: Arc<Mutex<MeasurementPointSet>>,
periods_per_dft: Arc<Mutex<Option<f32>>>,
periods_per_dft_sweep: Arc<Mutex<(Vec<u32>, Option<Vec<f32>>)>>,
show_settings: bool,
show_settings_toggle: Option<bool>,
measurement_data: Arc<MeasurementDataState>,
control_tx: mpsc::Sender<ControlCommand>,
app_state_rx: sync::watch::Receiver<AppState>,
hardware_state_rx: sync::watch::Receiver<HardwareState>,
}
trait ElectrodeOption: Copy + Debug + PartialEq + 'static {
@@ -158,46 +91,55 @@ fn electrode_combo<T: ElectrodeOption>(
ui: &mut egui::Ui,
id: &str,
value: &mut T,
) {
) -> bool {
let mut changed = false;
egui::ComboBox::from_id_salt(id)
.selected_text(format!("{:?}", value))
.width(60.0)
.show_ui(ui, |ui| {
for &option in T::ALL {
ui.selectable_value(value, option, format!("{:?}", option));
let response = ui.selectable_value(value, option, format!("{:?}", option));
if response.changed() {
changed = true;
}
}
});
changed
}
fn render_two_lead<T: ElectrodeOption>(
ui: &mut egui::Ui,
values: &mut [T; 2],
) {
) -> bool {
let mut changed = false;
ui.horizontal(|ui| {
ui.label("Drive/sense: Electrode+ (");
electrode_combo(ui, "e1_select", &mut values[0]);
changed |= electrode_combo(ui, "e1_select", &mut values[0]);
ui.label("), Electrode- (");
electrode_combo(ui, "e2_select", &mut values[1]);
changed |= electrode_combo(ui, "e2_select", &mut values[1]);
ui.label(")");
});
changed
}
fn render_four_lead<T: ElectrodeOption>(
ui: &mut egui::Ui,
values: &mut [T; 4],
) {
) -> bool {
let mut changed = false;
ui.horizontal(|ui| {
ui.label("Drive: I+ (");
electrode_combo(ui, "i1_select", &mut values[0]);
changed |= electrode_combo(ui, "i1_select", &mut values[0]);
ui.label("), I- (");
electrode_combo(ui, "i2_select", &mut values[1]);
changed |= electrode_combo(ui, "i2_select", &mut values[1]);
ui.label(") | Sense: V+ (");
electrode_combo(ui, "v1_select", &mut values[2]);
changed |= electrode_combo(ui, "v1_select", &mut values[2]);
ui.label("), V- (");
electrode_combo(ui, "v2_select", &mut values[3]);
changed |= electrode_combo(ui, "v2_select", &mut values[3]);
ui.label(")");
});
changed
}
impl TabViewer {
@@ -211,12 +153,12 @@ impl TabViewer {
ui.horizontal(|ui| {
ui.label("Lead Mode:");
let mut lead_mode = self.lead_mode.lock().unwrap();
let mut lead_mode = self.app_state_rx.borrow().lead_mode;
// Map current lead mode to index
let mut index = LEAD_MODES
.iter()
.position(|&m| m == *lead_mode)
.position(|&m| m == lead_mode)
.unwrap_or(0);
ComboBox::from_id_salt("LeadMode")
@@ -230,19 +172,20 @@ impl TabViewer {
});
// Update lead mode if changed
if *lead_mode != LEAD_MODES[index] {
*lead_mode = LEAD_MODES[index];
info!("Lead Mode setting changed!");
if lead_mode != LEAD_MODES[index] {
lead_mode = LEAD_MODES[index];
self.control_tx.try_send(ControlCommand::ChangeLeadMode(lead_mode)).unwrap();
}
});
ui.horizontal(|ui| {
// Show lead configuration
ui.label("Lead Configuration:");
let hardware_connected = self.hardware_connected.lock().unwrap();
let lead_mode = self.lead_mode.lock().unwrap();
let hardware_connected = self.hardware_state_rx.borrow().connected;
let lead_mode = self.app_state_rx.borrow().lead_mode;
let mut settings = self.electrode_settings.lock().unwrap();
match (*hardware_connected, *lead_mode) {
let mut settings = self.app_state_rx.borrow().electrode_settings;
match (hardware_connected, lead_mode) {
(HardwareConnected::WithoutMultiplexer, BioImpedanceLeadMode::TwoLead) => {
ui.label(format!("Drive/sense: Electrode+ (CE0), Electrode- (AIN1)"));
}
@@ -250,10 +193,14 @@ impl TabViewer {
ui.label(format!("Drive: I+ (CE0), I- (AIN1) | Sense: V+ (AIN2), V- (AIN3)"));
}
(HardwareConnected::WithMultiplexer, BioImpedanceLeadMode::TwoLead) => {
render_two_lead(ui, &mut settings.with_multiplexer_2_lead);
if render_two_lead(ui, &mut settings.with_multiplexer_2_lead) {
self.control_tx.try_send(ControlCommand::ChangeElectrodeSettings(settings)).unwrap();
}
}
(HardwareConnected::WithMultiplexer, BioImpedanceLeadMode::FourLead) => {
render_four_lead(ui, &mut settings.with_multiplexer_4_lead);
if render_four_lead(ui, &mut settings.with_multiplexer_4_lead) {
self.control_tx.try_send(ControlCommand::ChangeElectrodeSettings(settings)).unwrap();
}
}
(HardwareConnected::None, _) => {}
}
@@ -262,31 +209,33 @@ impl TabViewer {
ui.add_enabled_ui(!*on, |ui| {
ui.horizontal(|ui| {
ui.label("Single Frequency:");
if let Ok(mut freq) = self.single_frequency.lock() {
ui.add(DragValue::new(&mut *freq).speed(0.1));
let mut freq = self.app_state_rx.borrow().single_frequency;
let response = ui.add(DragValue::new(&mut freq).speed(0.1));
if response.changed() {
self.control_tx.try_send(ControlCommand::SetFrequency(freq)).unwrap();
}
ui.label("Hz");
});
ui.horizontal(|ui| {
ui.label("ADC samples per DFT:");
let mut dft_num = self.dft_num.lock().unwrap();
let mut index = DFTNUM_VARIANTS.iter().position(|&x| x == *dft_num).unwrap_or(0);
let mut dft_num = self.app_state_rx.borrow().dft_num;
let mut index = DFTNUM_VARIANTS.iter().position(|&x| x == dft_num).unwrap_or(0);
ComboBox::from_id_salt("Dftnum")
.width(75.0)
.show_index(ui, &mut index, DFTNUM_VARIANTS.len(), |i| {
format!("{}", 1 << (2 + i)) // 2^2 = 4, 2^3 = 8, ..., 2^14 = 16384
});
let new_value = DFTNUM_VARIANTS[index];
if *dft_num != new_value {
*dft_num = new_value;
info!("DFTNUM setting changed!");
if dft_num != new_value {
dft_num = new_value;
self.control_tx.try_send(ControlCommand::ChangeDftNum(dft_num)).unwrap();
};
});
});
ui.add_enabled_ui(*on, |ui| {
ui.horizontal(|ui| {
ui.label("Periods per DFT:");
match (*on, *self.periods_per_dft.lock().unwrap()) {
match (*on, self.hardware_state_rx.borrow().periods_per_dft) {
(true, Some(periods)) => {
ui.add(Label::new(format!("{:.2}", periods)));
},
@@ -316,14 +265,14 @@ impl TabViewer {
Layout::top_down(egui::Align::Min),
|ui| {
// Magnitude
let magnitude = self.magnitude_series.lock().unwrap();
let magnitude = self.measurement_data.magnitude_series.lock().unwrap();
Plot::new("magnitude")
.legend(Legend::default().position(Corner::LeftTop))
.y_axis_label("Magnitude [Ω]")
.y_axis_min_width(80.0)
.show(ui, |plot_ui| {
plot_ui.line(
Line::new(format!("Magnitude at {} Hz", self.single_frequency.lock().unwrap()), magnitude.plot_values())
Line::new(format!("Magnitude at {} Hz", self.app_state_rx.borrow().single_frequency), magnitude.plot_values())
.color(Color32::BLUE)
);
});
@@ -335,14 +284,14 @@ impl TabViewer {
Layout::top_down(egui::Align::Min),
|ui| {
// Phase
let phase = self.phase_series.lock().unwrap();
let phase = self.measurement_data.phase_series.lock().unwrap();
Plot::new("phase")
.legend(Legend::default().position(Corner::LeftTop))
.y_axis_label("Phase [rad]")
.y_axis_min_width(80.0)
.show(ui, |plot_ui| {
plot_ui.line(
Line::new(format!("Phase at {} Hz", self.single_frequency.lock().unwrap()), phase.plot_values())
Line::new(format!("Phase at {} Hz", self.app_state_rx.borrow().single_frequency), phase.plot_values())
.color(Color32::RED)
);
});
@@ -362,12 +311,12 @@ impl TabViewer {
ui.horizontal(|ui| {
ui.label("Lead Mode:");
let mut lead_mode = self.lead_mode.lock().unwrap();
let mut lead_mode = self.app_state_rx.borrow().lead_mode;
// Map current lead mode to index
let mut index = LEAD_MODES
.iter()
.position(|&m| m == *lead_mode)
.position(|&m| m == lead_mode)
.unwrap_or(0);
ComboBox::from_id_salt("LeadMode")
@@ -381,19 +330,19 @@ impl TabViewer {
});
// Update lead mode if changed
if *lead_mode != LEAD_MODES[index] {
*lead_mode = LEAD_MODES[index];
info!("Lead Mode setting changed!");
if lead_mode != LEAD_MODES[index] {
lead_mode = LEAD_MODES[index];
self.control_tx.try_send(ControlCommand::ChangeLeadMode(lead_mode)).unwrap();
}
});
ui.horizontal(|ui| {
// Show lead configuration
ui.label("Lead Configuration:");
let hardware_connected = self.hardware_connected.lock().unwrap();
let lead_mode = self.lead_mode.lock().unwrap();
let hardware_connected = self.hardware_state_rx.borrow().connected;
let lead_mode = self.app_state_rx.borrow().lead_mode;
let mut settings = self.electrode_settings.lock().unwrap();
match (*hardware_connected, *lead_mode) {
let mut settings = self.app_state_rx.borrow().electrode_settings;
match (hardware_connected, lead_mode) {
(HardwareConnected::WithoutMultiplexer, BioImpedanceLeadMode::TwoLead) => {
ui.label(format!("Drive/sense: Electrode+ (CE0), Electrode- (AIN1)"));
}
@@ -401,10 +350,14 @@ impl TabViewer {
ui.label("Drive: I+ (CE0), I- (AIN1) | Sense: V+ (AIN2), V- (AIN3)");
}
(HardwareConnected::WithMultiplexer, BioImpedanceLeadMode::TwoLead) => {
render_two_lead(ui, &mut settings.with_multiplexer_2_lead);
if render_two_lead(ui, &mut settings.with_multiplexer_2_lead) {
self.control_tx.try_send(ControlCommand::ChangeElectrodeSettings(settings)).unwrap();
}
}
(HardwareConnected::WithMultiplexer, BioImpedanceLeadMode::FourLead) => {
render_four_lead(ui, &mut settings.with_multiplexer_4_lead);
if render_four_lead(ui, &mut settings.with_multiplexer_4_lead) {
self.control_tx.try_send(ControlCommand::ChangeElectrodeSettings(settings)).unwrap();
}
}
(HardwareConnected::None, _) => {}
}
@@ -413,22 +366,23 @@ impl TabViewer {
ui.add_enabled_ui(!*on, |ui| {
ui.horizontal(|ui| {
ui.label("Measurement Points:");
let mut measurement_points = self.measurement_points.lock().unwrap();
let mut index = MEASUREMENT_POINTS_VARIANTS.iter().position(|&x| x == *measurement_points).unwrap_or(0);
let mut measurement_points = self.app_state_rx.borrow().sweep_points;
let mut index = SWEEP_POINTS_VARIANTS.iter().position(|&x| x == measurement_points).unwrap_or(0);
ComboBox::from_id_salt("MeasurementPoints")
.width(75.0)
.show_index(ui, &mut index, MEASUREMENT_POINTS_VARIANTS.len(), |i| {
format!("{:?}", MEASUREMENT_POINTS_VARIANTS[i].len())
.show_index(ui, &mut index, SWEEP_POINTS_VARIANTS.len(), |i| {
format!("{:?}", SWEEP_POINTS_VARIANTS[i].len())
});
let new_value = MEASUREMENT_POINTS_VARIANTS[index];
if *measurement_points != new_value {
*measurement_points = new_value;
info!("Measurement Points setting changed!");
let new_value = SWEEP_POINTS_VARIANTS[index];
if measurement_points != new_value {
measurement_points = new_value;
self.control_tx.try_send(ControlCommand::ChangeSweepPoints(measurement_points)).unwrap();
info!("Sweep Points setting changed!");
}
});
});
ui.add_enabled_ui(*on, |ui| {
let (freq, periods_per_dft_vec) = self.periods_per_dft_sweep.lock().unwrap().clone();
let (freq, periods_per_dft_vec) = self.hardware_state_rx.borrow().periods_per_dft_sweep.clone();
fn format_frequency(freq: u32) -> String {
if freq >= 1_000 {
@@ -499,7 +453,7 @@ impl TabViewer {
Layout::top_down(egui::Align::Min),
|ui| {
// Magnitude
let bode_plot = self.bode_plot.lock().unwrap();
let bode_plot = self.measurement_data.bode_plot.lock().unwrap();
Plot::new("bode_mag")
.legend(Legend::default().position(Corner::LeftTop))
.y_axis_label("Magnitude [Ω]")
@@ -529,7 +483,7 @@ impl TabViewer {
Layout::top_down(egui::Align::Min),
|ui| {
// Phase
let bode_plot = self.bode_plot.lock().unwrap();
let bode_plot = self.measurement_data.bode_plot.lock().unwrap();
Plot::new("bode_phase")
.legend(Legend::default().position(Corner::LeftTop))
.y_axis_label("Phase [rad]")
@@ -644,70 +598,45 @@ impl egui_dock::TabViewer for TabViewer {
}
impl App {
pub fn new(run_impedancemeter_tx: Sender<StartStopSignal>, log_tx: Sender<LoggingSignal>) -> Self {
// Step 1: Initialize shared fields first
let magnitude = Arc::new(Mutex::new(0.0));
let phase = Arc::new(Mutex::new(0.0));
let magnitude_series = Arc::new(Mutex::new(TimeSeriesPlot::new()));
let phase_series = Arc::new(Mutex::new(TimeSeriesPlot::new()));
let bode_plot = Arc::new(Mutex::new(BodePlot::new()));
let single_frequency = Arc::new(Mutex::new(50000));
let hardware_connected = Arc::new(Mutex::new(HardwareConnected::None));
let lead_mode = Arc::new(Mutex::new(BioImpedanceLeadMode::FourLead));
let electrode_settings = Arc::new(Mutex::new(ElectrodeSettings::new()));
let dft_num = Arc::new(Mutex::new(IcdDftNum::Num2048));
let measurement_points = Arc::new(Mutex::new(MeasurementPointSet::Eighteen));
let periods_per_dft = Arc::new(Mutex::new(None));
let periods_per_dft_sweep = Arc::new(Mutex::new((MeasurementPointSet::Eighteen.values().to_vec(), None)));
pub fn new(run_impedancemeter_tx: mpsc::Sender<StartStopSignal>,
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
let tab_viewer = TabViewer {
magnitude: magnitude.clone(),
phase: phase.clone(),
magnitude_series: magnitude_series.clone(),
phase_series: phase_series.clone(),
bode_plot: bode_plot.clone(),
single_frequency: single_frequency.clone(),
hardware_connected: hardware_connected.clone(),
lead_mode: lead_mode.clone(),
electrode_settings: electrode_settings.clone(),
dft_num: dft_num.clone(),
measurement_points: measurement_points.clone(),
periods_per_dft: periods_per_dft.clone(),
periods_per_dft_sweep: periods_per_dft_sweep.clone(),
let control_tx_clone = control_tx.clone();
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,
app_state_rx: app_state_clone,
hardware_state_rx: hardware_state_clone
};
// Step 3: Construct App
let app = App {
tree: DockState::new(vec!["Single".to_string(), "Sweep".to_string(), "Shortcuts".to_string()]),
tab_viewer,
tab_active,
run_impedancemeter_tx,
log_tx,
magnitude,
phase,
magnitude_series,
phase_series,
bode_plot,
hardware_connected,
on,
tab_active,
data_frequency: Arc::new(AtomicF32::new(0.0)),
single_frequency,
lead_mode,
electrode_settings,
dft_num,
measurement_points,
periods_per_dft,
periods_per_dft_sweep,
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,
log_marker: String::new(),
measurement_data,
control_tx,
app_state_rx,
hardware_state_rx,
};
// For testing purposes, populate the Bode plot with a sample low-pass filter response
@@ -735,17 +664,17 @@ impl App {
pub fn update_start_stop(&self) {
match (self.tab_active, *self.on.lock().unwrap()) {
(TabActive::Single, true) => {
let lead_mode = *self.lead_mode.lock().unwrap();
let electrode_config = self.electrode_settings.lock().unwrap().to_electrode_config(*self.hardware_connected.lock().unwrap(), lead_mode);
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.single_frequency.lock().unwrap(), lead_mode, electrode_config, *self.dft_num.lock().unwrap())) {
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);
}
},
(TabActive::Sweep, true) => {
let lead_mode = *self.lead_mode.lock().unwrap();
let electrode_config = self.electrode_settings.lock().unwrap().to_electrode_config(*self.hardware_connected.lock().unwrap(), lead_mode);
if let Err(e) = self.run_impedancemeter_tx.try_send(StartStopSignal::StartSweep(lead_mode, electrode_config, *self.measurement_points.lock().unwrap())) {
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);
}
},
@@ -759,8 +688,8 @@ impl App {
}
pub fn reset_view(&self) {
self.magnitude_series.lock().unwrap().clear();
self.phase_series.lock().unwrap().clear();
self.measurement_data.magnitude_series.lock().unwrap().clear();
self.measurement_data.phase_series.lock().unwrap().clear();
}
}
@@ -769,12 +698,12 @@ 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_connected.lock().unwrap() != HardwareConnected::None;
let is_connected = self.hardware_state_rx.borrow().connected != HardwareConnected::None;
egui::widgets::global_theme_preference_switch(ui);
ui.separator();
ui.label(format!("Data rate: {} Hz", self.data_frequency.load(Ordering::Relaxed)));
ui.label(format!("Data rate: {} Hz", self.measurement_data.sampling_rate.load(Ordering::Relaxed)));
ui.separator();
@@ -889,7 +818,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_connected.lock().unwrap() {
let (color, tooltip) = match self.hardware_state_rx.borrow().connected {
HardwareConnected::None => {
(Color32::DARK_RED, "Disconnected")
},