mirror of
https://github.com/hubaldv/bioz-host-rs.git
synced 2025-12-06 05:11:17 +00:00
Implement basic logging channels.
This commit is contained in:
18
Cargo.lock
generated
18
Cargo.lock
generated
@@ -3019,18 +3019,28 @@ checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.219"
|
version = "1.0.228"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.219"
|
version = "1.0.228"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
49
src/app.rs
49
src/app.rs
@@ -56,6 +56,7 @@ pub struct App {
|
|||||||
pub measurement_points: Arc<Mutex<MeasurementPointSet>>,
|
pub measurement_points: Arc<Mutex<MeasurementPointSet>>,
|
||||||
pub periods_per_dft: Arc<Mutex<Option<f32>>>,
|
pub periods_per_dft: Arc<Mutex<Option<f32>>>,
|
||||||
pub periods_per_dft_multi: Arc<Mutex<(Vec<f32>, Option<Vec<f32>>)>>,
|
pub periods_per_dft_multi: Arc<Mutex<(Vec<f32>, Option<Vec<f32>>)>>,
|
||||||
|
pub gui_logging_enabled: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TabViewer {
|
struct TabViewer {
|
||||||
@@ -327,8 +328,9 @@ impl TabViewer {
|
|||||||
fn shortcuts(&mut self, ui: &mut egui::Ui) {
|
fn shortcuts(&mut self, ui: &mut egui::Ui) {
|
||||||
ui.heading("Shortcuts");
|
ui.heading("Shortcuts");
|
||||||
ui.label("Space: Start/Stop measurement");
|
ui.label("Space: Start/Stop measurement");
|
||||||
ui.label("C: Clear plots");
|
ui.label("R: Reset view/plots");
|
||||||
ui.label("S: Toggle settings");
|
ui.label("S: Toggle settings");
|
||||||
|
ui.label("L: Toggle logging");
|
||||||
ui.label("CMD-W: Close window");
|
ui.label("CMD-W: Close window");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -462,25 +464,26 @@ impl App {
|
|||||||
measurement_points,
|
measurement_points,
|
||||||
periods_per_dft,
|
periods_per_dft,
|
||||||
periods_per_dft_multi,
|
periods_per_dft_multi,
|
||||||
|
gui_logging_enabled: Arc::new(AtomicBool::new(false)),
|
||||||
};
|
};
|
||||||
|
|
||||||
// For testing purposes, populate the Bode plot with a sample low-pass filter response
|
// For testing purposes, populate the Bode plot with a sample low-pass filter response
|
||||||
let fc = 1000.0; // cutoff frequency in Hz
|
// let fc = 1000.0; // cutoff frequency in Hz
|
||||||
|
|
||||||
let freqs = MeasurementPointSet::Eighteen.values().to_vec();
|
// let freqs = MeasurementPointSet::Eighteen.values().to_vec();
|
||||||
let magnitudes = freqs.iter()
|
// let magnitudes = freqs.iter()
|
||||||
.map(|&f| {
|
// .map(|&f| {
|
||||||
1.0 / (1.0 + (f / fc).powi(2)).sqrt()
|
// 1.0 / (1.0 + (f / fc).powi(2)).sqrt()
|
||||||
})
|
// })
|
||||||
.collect::<Vec<f32>>();
|
// .collect::<Vec<f32>>();
|
||||||
let phases = freqs.iter()
|
// let phases = freqs.iter()
|
||||||
.map(|&f| {
|
// .map(|&f| {
|
||||||
-(f / fc).atan() * 180.0 / PI
|
// -(f / fc).atan() * 180.0 / PI
|
||||||
})
|
// })
|
||||||
.collect::<Vec<f32>>();
|
// .collect::<Vec<f32>>();
|
||||||
|
|
||||||
app.bode_plot.lock().unwrap().update_magnitudes(MeasurementPointSet::Eighteen, magnitudes);
|
// app.bode_plot.lock().unwrap().update_magnitudes(MeasurementPointSet::Eighteen, magnitudes);
|
||||||
app.bode_plot.lock().unwrap().update_phases(MeasurementPointSet::Eighteen, phases);
|
// app.bode_plot.lock().unwrap().update_phases(MeasurementPointSet::Eighteen, phases);
|
||||||
|
|
||||||
app.update_start_stop();
|
app.update_start_stop();
|
||||||
app
|
app
|
||||||
@@ -537,6 +540,13 @@ impl eframe::App for App {
|
|||||||
self.reset_view();
|
self.reset_view();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
let mut gui_logging_enabled = self.gui_logging_enabled.load(Ordering::Relaxed);
|
||||||
|
if ui.add(egui::Checkbox::new(&mut gui_logging_enabled, "Logging")).changed() {
|
||||||
|
self.gui_logging_enabled.store(gui_logging_enabled, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
// Spacer to push the LED to the right
|
// Spacer to push the LED to the right
|
||||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||||
ui.scope(|ui| {
|
ui.scope(|ui| {
|
||||||
@@ -625,10 +635,17 @@ impl eframe::App for App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reset view
|
// Reset view
|
||||||
if ctx.input(|i| i.key_pressed(Key::C)) {
|
if ctx.input(|i| i.key_pressed(Key::R)) {
|
||||||
self.reset_view();
|
self.reset_view();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enable/disable GUI logging
|
||||||
|
if ctx.input(|i| i.key_pressed(egui::Key::L)) {
|
||||||
|
let mut gui_logging_enabled = self.gui_logging_enabled.load(Ordering::Relaxed);
|
||||||
|
gui_logging_enabled = !gui_logging_enabled;
|
||||||
|
self.gui_logging_enabled.store(gui_logging_enabled, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
// Toggle setttings view
|
// Toggle setttings view
|
||||||
if ctx.input(|i| i.key_pressed(egui::Key::S)) {
|
if ctx.input(|i| i.key_pressed(egui::Key::S)) {
|
||||||
self.tab_viewer.show_settings = !self.tab_viewer.show_settings;
|
self.tab_viewer.show_settings = !self.tab_viewer.show_settings;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use simple_logger::SimpleLogger;
|
|||||||
use log::info;
|
use log::info;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
use bioz_host_rs::app::App;
|
use bioz_host_rs::{app::App, signals::LoggingSignal};
|
||||||
|
|
||||||
use bioz_host_rs::communication::communicate_with_hardware;
|
use bioz_host_rs::communication::communicate_with_hardware;
|
||||||
|
|
||||||
@@ -10,7 +10,8 @@ use tokio::sync::mpsc::{self};
|
|||||||
|
|
||||||
use bioz_host_rs::signals::StartStopSignal;
|
use bioz_host_rs::signals::StartStopSignal;
|
||||||
|
|
||||||
fn main() {
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
SimpleLogger::new().init().expect("Failed to initialize logger");
|
SimpleLogger::new().init().expect("Failed to initialize logger");
|
||||||
log::set_max_level(log::LevelFilter::Info);
|
log::set_max_level(log::LevelFilter::Info);
|
||||||
info!("Starting Bioz Impedance Visualizer...");
|
info!("Starting Bioz Impedance Visualizer...");
|
||||||
@@ -20,9 +21,13 @@ fn main() {
|
|||||||
// Enter the runtime so that `tokio::spawn` is available immediately.
|
// Enter the runtime so that `tokio::spawn` is available immediately.
|
||||||
// let _enter = rt.enter();
|
// let _enter = rt.enter();
|
||||||
|
|
||||||
|
// Channel to communicate with the communication task.
|
||||||
let (run_impedancemeter_tx, run_impedancemeter_rx) = mpsc::channel::<StartStopSignal>(2);
|
let (run_impedancemeter_tx, run_impedancemeter_rx) = mpsc::channel::<StartStopSignal>(2);
|
||||||
let run_impedancemeter_tx_clone = run_impedancemeter_tx.clone();
|
let run_impedancemeter_tx_clone = run_impedancemeter_tx.clone();
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
let (log_tx, mut log_rx) = mpsc::channel::<LoggingSignal>(10);
|
||||||
|
|
||||||
let app = App::new(run_impedancemeter_tx);
|
let app = App::new(run_impedancemeter_tx);
|
||||||
let magnitude_clone = app.magnitude.clone();
|
let magnitude_clone = app.magnitude.clone();
|
||||||
let phase_clone = app.phase.clone();
|
let phase_clone = app.phase.clone();
|
||||||
@@ -36,6 +41,30 @@ fn main() {
|
|||||||
let periods_per_dft = app.periods_per_dft.clone();
|
let periods_per_dft = app.periods_per_dft.clone();
|
||||||
let periods_per_dft_multi = app.periods_per_dft_multi.clone();
|
let periods_per_dft_multi = app.periods_per_dft_multi.clone();
|
||||||
|
|
||||||
|
let gui_logging_enabled = app.gui_logging_enabled.clone();
|
||||||
|
|
||||||
|
// Log thread
|
||||||
|
tokio::spawn(async move {
|
||||||
|
loop {
|
||||||
|
match log_rx.recv().await {
|
||||||
|
Some(signal) => {
|
||||||
|
match signal {
|
||||||
|
LoggingSignal::SingleImpedance(magnitude, phase) => {
|
||||||
|
info!("Single Impedance - Magnitude: {:.3}, Phase: {:.3}", magnitude, phase);
|
||||||
|
}
|
||||||
|
LoggingSignal::MultiImpedance(magnitudes, phases) => {
|
||||||
|
info!("Multi Impedance - Magnitudes: {:?}, Phases: {:?}", magnitudes, phases);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// Channel closed
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Execute the runtime in its own thread.
|
// Execute the runtime in its own thread.
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
rt.block_on(communicate_with_hardware(
|
rt.block_on(communicate_with_hardware(
|
||||||
@@ -50,6 +79,8 @@ fn main() {
|
|||||||
data_frequency_clone,
|
data_frequency_clone,
|
||||||
periods_per_dft,
|
periods_per_dft,
|
||||||
periods_per_dft_multi,
|
periods_per_dft_multi,
|
||||||
|
gui_logging_enabled,
|
||||||
|
log_tx,
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use crate::client::WorkbookClient;
|
|||||||
|
|
||||||
use crate::plot::{TimeSeriesPlot, BodePlot};
|
use crate::plot::{TimeSeriesPlot, BodePlot};
|
||||||
|
|
||||||
use crate::signals::StartStopSignal;
|
use crate::signals::{LoggingSignal, StartStopSignal};
|
||||||
|
|
||||||
pub async fn communicate_with_hardware(
|
pub async fn communicate_with_hardware(
|
||||||
mut run_impedancemeter_rx: Receiver<StartStopSignal>,
|
mut run_impedancemeter_rx: Receiver<StartStopSignal>,
|
||||||
@@ -29,6 +29,8 @@ pub async fn communicate_with_hardware(
|
|||||||
data_frequency: Arc<AtomicF32>,
|
data_frequency: Arc<AtomicF32>,
|
||||||
periods_per_dft: Arc<Mutex<Option<f32>>>,
|
periods_per_dft: Arc<Mutex<Option<f32>>>,
|
||||||
periods_per_dft_multi: Arc<Mutex<(Vec<f32>, Option<Vec<f32>>)>>,
|
periods_per_dft_multi: Arc<Mutex<(Vec<f32>, Option<Vec<f32>>)>>,
|
||||||
|
gui_logging_enabled: Arc<AtomicBool>,
|
||||||
|
log_tx: Sender<LoggingSignal>,
|
||||||
) {
|
) {
|
||||||
let data_counter = Arc::new(AtomicU32::new(0));
|
let data_counter = Arc::new(AtomicU32::new(0));
|
||||||
let data_counter_clone = data_counter.clone();
|
let data_counter_clone = data_counter.clone();
|
||||||
@@ -73,8 +75,13 @@ pub async fn communicate_with_hardware(
|
|||||||
let data = (magnitude_series.clone(), phase_series.clone(), magnitude.clone(), phase.clone());
|
let data = (magnitude_series.clone(), phase_series.clone(), magnitude.clone(), phase.clone());
|
||||||
let data_counter_clone_single = data_counter_clone.clone();
|
let data_counter_clone_single = data_counter_clone.clone();
|
||||||
|
|
||||||
|
// Clone log_tx for the task
|
||||||
|
let gui_logging_enabled_clone = gui_logging_enabled.clone();
|
||||||
|
let log_tx_clone = log_tx.clone();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
while let Ok(val) = single_impedance_sub.recv().await {
|
while let Ok(val) = single_impedance_sub.recv().await {
|
||||||
|
{
|
||||||
let mut mag_plot = data.0.lock().unwrap();
|
let mut mag_plot = data.0.lock().unwrap();
|
||||||
let mut phase_plot = data.1.lock().unwrap();
|
let mut phase_plot = data.1.lock().unwrap();
|
||||||
let mut mag_val = data.2.lock().unwrap();
|
let mut mag_val = data.2.lock().unwrap();
|
||||||
@@ -88,6 +95,13 @@ pub async fn communicate_with_hardware(
|
|||||||
|
|
||||||
data_counter_clone_single.fetch_add(1, Ordering::Relaxed);
|
data_counter_clone_single.fetch_add(1, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
// Send logging signal
|
||||||
|
if gui_logging_enabled_clone.load(Ordering::Relaxed) {
|
||||||
|
if let Err(e) = log_tx_clone.try_send(LoggingSignal::SingleImpedance(val.magnitude, val.phase)) {
|
||||||
|
error!("Failed to send logging signal: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
info!("SingleImpedanceOutputTopic subscription ended.");
|
info!("SingleImpedanceOutputTopic subscription ended.");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -101,23 +115,42 @@ pub async fn communicate_with_hardware(
|
|||||||
let data = bode_series.clone();
|
let data = bode_series.clone();
|
||||||
let data_counter_clone_multi = data_counter_clone.clone();
|
let data_counter_clone_multi = data_counter_clone.clone();
|
||||||
|
|
||||||
|
// Clone log_tx for the task
|
||||||
|
let gui_logging_enabled_clone = gui_logging_enabled.clone();
|
||||||
|
let log_tx_clone = log_tx.clone();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
while let Ok(val) = multi_impedance_sub.recv().await {
|
while let Ok(val) = multi_impedance_sub.recv().await {
|
||||||
let mut bode_plot = data.lock().unwrap();
|
|
||||||
|
|
||||||
match val.points {
|
match val.points {
|
||||||
|
|
||||||
MeasurementPointSet::Eight => {
|
MeasurementPointSet::Eight => {
|
||||||
let magnitudes: Vec<f32> = val.magnitudes_8.into_iter().collect();
|
let magnitudes: Vec<f32> = val.magnitudes_8.into_iter().collect();
|
||||||
let phases: Vec<f32> = val.phases_8.into_iter().collect();
|
let phases: Vec<f32> = val.phases_8.into_iter().collect();
|
||||||
bode_plot.update_magnitudes(MeasurementPointSet::Eight, magnitudes);
|
{
|
||||||
bode_plot.update_phases(MeasurementPointSet::Eight, phases);
|
let mut bode_plot = data.lock().unwrap();
|
||||||
|
bode_plot.update_magnitudes(MeasurementPointSet::Eight, magnitudes.clone());
|
||||||
|
bode_plot.update_phases(MeasurementPointSet::Eight, phases.clone());
|
||||||
|
}
|
||||||
|
if gui_logging_enabled_clone.load(Ordering::Relaxed) {
|
||||||
|
if let Err(e) = log_tx_clone.try_send(LoggingSignal::MultiImpedance(magnitudes.clone(), phases.clone())) {
|
||||||
|
error!("Failed to send logging signal: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
MeasurementPointSet::Eighteen => {
|
MeasurementPointSet::Eighteen => {
|
||||||
let magnitudes: Vec<f32> = val.magnitudes_18.into_iter().collect();
|
let magnitudes: Vec<f32> = val.magnitudes_18.into_iter().collect();
|
||||||
let phases: Vec<f32> = val.phases_18.into_iter().collect();
|
let phases: Vec<f32> = val.phases_18.into_iter().collect();
|
||||||
bode_plot.update_magnitudes(MeasurementPointSet::Eighteen, magnitudes);
|
{
|
||||||
bode_plot.update_phases(MeasurementPointSet::Eighteen, phases);
|
let mut bode_plot = data.lock().unwrap();
|
||||||
|
bode_plot.update_magnitudes(MeasurementPointSet::Eighteen, magnitudes.clone());
|
||||||
|
bode_plot.update_phases(MeasurementPointSet::Eighteen, phases.clone());
|
||||||
|
}
|
||||||
|
if gui_logging_enabled_clone.load(Ordering::Relaxed) {
|
||||||
|
if let Err(e) = log_tx_clone.try_send(LoggingSignal::MultiImpedance(magnitudes.clone(), phases.clone())) {
|
||||||
|
error!("Failed to send logging signal: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,3 +6,8 @@ pub enum StartStopSignal {
|
|||||||
StartMulti(MeasurementPointSet), // DFT number, number of points per measurement
|
StartMulti(MeasurementPointSet), // DFT number, number of points per measurement
|
||||||
Stop,
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum LoggingSignal {
|
||||||
|
SingleImpedance(f32, f32), // magnitude, phase
|
||||||
|
MultiImpedance(Vec<f32>, Vec<f32>), // magnitude, phase
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user