diff --git a/Cargo.toml b/Cargo.toml index dcb2200..f22e35e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ eframe = { version = "0.32.0"} egui_plot = "0.33.0" log = "0.4.27" simple_logger = "5.0.0" +atomic_float = "1.1.0" [dependencies.bioz-icd-rs] path = "../bioz-icd-rs" diff --git a/src/app.rs b/src/app.rs index 8b5b3bc..27c9fa9 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,8 +1,7 @@ use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicBool, Ordering}; -use std::ops::RangeInclusive; - +use atomic_float::AtomicF32; use tokio::{sync::mpsc::{Sender}}; use eframe::egui::{self, Color32, DragValue, Key, Layout, Modifiers, }; @@ -13,7 +12,6 @@ use crate::plot::TimeSeriesPlot; use crate::signals::FrequencySignal; pub struct App { - frequency: f32, run_impedancemeter_tx: Sender, pub magnitude: Arc>, pub phase: Arc>, @@ -21,12 +19,12 @@ pub struct App { pub phase_series: Arc>, pub connected: Arc, pub on: bool, + pub data_frequency: Arc, } impl App { pub fn new(run_impedancemeter_tx: Sender) -> Self { let app = App { - frequency: 2.0, // Default frequency run_impedancemeter_tx, magnitude: Arc::new(Mutex::new(0.0)), phase: Arc::new(Mutex::new(0.0)), @@ -34,6 +32,7 @@ impl App { phase_series: Arc::new(Mutex::new(TimeSeriesPlot::new())), connected: Arc::new(AtomicBool::new(false)), on: true, + data_frequency: Arc::new(AtomicF32::new(0.0)), }; app.update_start_stop(); app @@ -42,7 +41,7 @@ impl App { pub fn update_start_stop(&self) { match self.on { true => { - if let Err(e) = self.run_impedancemeter_tx.try_send(FrequencySignal::Start(self.frequency)) { + if let Err(e) = self.run_impedancemeter_tx.try_send(FrequencySignal::Start(0.0)) { eprintln!("Failed to send start command: {:?}", e); } }, @@ -65,11 +64,7 @@ impl eframe::App for App { egui::widgets::global_theme_preference_switch(ui); ui.separator(); - let response = ui.add_enabled(connected, DragValue::new(&mut self.frequency).speed(0.1).update_while_editing(false).range(RangeInclusive::new(0, 50))); - - if response.changed() && response.lost_focus() { - self.update_start_stop(); - } + ui.label(format!("{} Hz", self.data_frequency.load(Ordering::Relaxed))); ui.separator(); @@ -104,7 +99,7 @@ impl eframe::App for App { egui::CentralPanel::default().show(ctx, |ui| { let available_height = ui.available_height(); - let half_height = available_height / 4.0; + let half_height = available_height / 2.0; let point_pos = vec![[*self.magnitude.lock().unwrap() as f64, *self.phase.lock().unwrap() as f64]]; @@ -125,7 +120,7 @@ impl eframe::App for App { // Magnitude and phase let magnitude = self.magnitude_series.lock().unwrap(); let phase = self.phase_series.lock().unwrap(); - Plot::new("magnitude_phase") + Plot::new("magnitude") .allow_scroll(false) .allow_drag(false) // .center_y_axis(true) @@ -133,29 +128,47 @@ impl eframe::App for App { .y_axis_label("Value [...]") .y_axis_min_width(2.0) .show(ui, |plot_ui| { - plot_ui.line( Line::new("Magnitude", magnitude.plot_values()) - .color(Color32::LIGHT_GREEN) + .color(Color32::BLUE) ); + }); + }, + ); + // Plot pressure + ui.allocate_ui_with_layout( + egui::vec2(ui.available_width(), half_height), + Layout::top_down(egui::Align::Min), + |ui| { + // Magnitude and phase + let magnitude = self.magnitude_series.lock().unwrap(); + let phase = self.phase_series.lock().unwrap(); + Plot::new("phase") + .allow_scroll(false) + .allow_drag(false) + // .center_y_axis(true) + .legend(Legend::default().position(Corner::LeftTop)) + .y_axis_label("Value [...]") + .y_axis_min_width(2.0) + .show(ui, |plot_ui| { plot_ui.line( Line::new("Phase", phase.plot_values()) - .color(Color32::LIGHT_RED) + .color(Color32::RED) ); }); }, ); }); - Plot::new("State") - .allow_scroll(false) - .allow_drag(false) - .data_aspect(1.0) - .center_y_axis(true) - .show(ui, |plot_ui| { - plot_ui.points(point_pos); - plot_ui.set_plot_bounds(bounds); - }); + // Plot::new("State") + // .allow_scroll(false) + // .allow_drag(false) + // .data_aspect(1.0) + // .center_y_axis(true) + // .show(ui, |plot_ui| { + // plot_ui.points(point_pos); + // plot_ui.set_plot_bounds(bounds); + // }); }); // CMD- or control-W to close window diff --git a/src/bin/main_gui.rs b/src/bin/main_gui.rs index 3f8efd9..5f96680 100644 --- a/src/bin/main_gui.rs +++ b/src/bin/main_gui.rs @@ -29,6 +29,7 @@ fn main() { let magnitude_series_clone = app.magnitude_series.clone(); let phase_series_clone = app.phase_series.clone(); let connected_clone = app.connected.clone(); + let data_frequency_clone = app.data_frequency.clone(); // Execute the runtime in its own thread. std::thread::spawn(move || { @@ -40,6 +41,7 @@ fn main() { magnitude_series_clone, phase_series_clone, connected_clone, + data_frequency_clone, )); }); diff --git a/src/communication.rs b/src/communication.rs index d0d9409..969a35e 100644 --- a/src/communication.rs +++ b/src/communication.rs @@ -3,7 +3,9 @@ use log::{error, info}; use tokio::select; use tokio::sync::mpsc::{Sender, Receiver}; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; +use atomic_float::AtomicF32; + use std::sync::{Arc, Mutex}; use crate::icd; @@ -21,7 +23,18 @@ pub async fn communicate_with_hardware( magnitude_series: Arc>, phase_series: Arc>, connected: Arc, + data_frequency: Arc, ) { + let data_counter = Arc::new(AtomicU32::new(0)); + let data_counter_clone = data_counter.clone(); + tokio::spawn(async move { + loop { + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + data_frequency.store(data_counter.load(Ordering::Relaxed) as f32, Ordering::Relaxed); + data_counter.store(0, Ordering::Relaxed); + } + }); + #[derive(Default)] struct Settings { frequency: Option, @@ -52,6 +65,7 @@ pub async fn communicate_with_hardware( .unwrap(); let data = (magnitude_series.clone(), phase_series.clone(), magnitude.clone(), phase.clone()); + let data_counter_clone = data_counter_clone.clone(); tokio::spawn(async move { while let Ok(val) = sub.recv().await { @@ -65,6 +79,8 @@ pub async fn communicate_with_hardware( mag_plot.add(val.magnitude as f64); phase_plot.add(val.phase as f64); + + data_counter_clone.fetch_add(1, Ordering::Relaxed); } info!("ImpedanceTopic subscription ended.");