diff --git a/config_app/src/ui/diagnostics/mod.rs b/config_app/src/ui/diagnostics/mod.rs index c7ed1e2..a55e4ba 100644 --- a/config_app/src/ui/diagnostics/mod.rs +++ b/config_app/src/ui/diagnostics/mod.rs @@ -1,12 +1,17 @@ use crate::ui::status_bar::MainStatusBar; use crate::window::{PageAction, StatusBar}; use backend::diag::Nag52Diag; +use backend::ecu_diagnostics::kwp2000::{KwpSessionTypeByte, KwpSessionType}; use eframe::egui::plot::{Legend, Line, Plot}; use eframe::egui::{Color32, RichText, Ui}; +use std::borrow::Borrow; use std::collections::hash_map::DefaultHasher; use std::collections::VecDeque; use std::hash::{Hash, Hasher}; -use std::time::Instant; +use std::sync::{Arc, RwLock}; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::thread; +use std::time::{Instant, Duration}; pub mod data; pub mod rli; @@ -22,96 +27,110 @@ pub enum CommandStatus { pub struct DiagnosticsPage { bar: MainStatusBar, - nag: Nag52Diag, - text: CommandStatus, - record_data: Option, - record_to_query: Option, - last_query_time: Instant, + query_ecu: Arc, + last_update_time: Arc, + curr_values: Arc>>, + time_since_launch: Instant, + record_to_query: Arc>>, charting_data: VecDeque<(u128, ChartData)>, chart_idx: u128, } impl DiagnosticsPage { pub fn new(nag: Nag52Diag, bar: MainStatusBar) -> Self { + + let run = Arc::new(AtomicBool::new(true)); + let run_t = run.clone(); + + let store = Arc::new(RwLock::new(None)); + let store_t = store.clone(); + + let to_query: Arc>> = Arc::new(RwLock::new(None)); + let to_query_t = to_query.clone(); + + let launch_time = Instant::now(); + let launch_time_t = launch_time.clone(); + + let last_update = Arc::new(AtomicU64::new(0)); + let last_update_t = last_update.clone(); + let _ = thread::spawn(move || { + nag.with_kwp(|server| { + server.kwp_set_session(KwpSessionTypeByte::Standard(KwpSessionType::Normal)) + }); + while run_t.load(Ordering::Relaxed) { + let start = Instant::now(); + if let Some(to_query) = *to_query_t.read().unwrap() { + match nag.with_kwp(|server| to_query.query_ecu(server)) { + Ok(r) => *store_t.write().unwrap() = Some(r), + Err(e) => { + eprintln!("Could not query {}", e); + } + } + } + let taken = start.elapsed().as_millis() as u64; + if taken < rli::RLI_QUERY_INTERVAL { + std::thread::sleep(Duration::from_millis(rli::RLI_QUERY_INTERVAL - taken)); + } + } + }); + Self { - nag, + query_ecu: run, bar, - text: CommandStatus::Ok("".into()), - record_data: None, - record_to_query: None, - last_query_time: Instant::now(), + last_update_time: last_update, + curr_values: store, + record_to_query: to_query, charting_data: VecDeque::new(), chart_idx: 0, + time_since_launch: Instant::now() } } } impl crate::window::InterfacePage for DiagnosticsPage { fn make_ui(&mut self, ui: &mut Ui, _frame: &eframe::Frame) -> PageAction { - let mut pending = false; ui.heading("This is experimental, use with MOST up-to-date firmware"); if ui.button("Query gearbox sensor").clicked() { - self.record_to_query = Some(RecordIdents::GearboxSensors); + *self.record_to_query.write().unwrap() = Some(RecordIdents::GearboxSensors); self.chart_idx = 0; self.charting_data.clear(); - self.record_data = None; + *self.curr_values.write().unwrap() = None; } if ui.button("Query gearbox solenoids").clicked() { - self.record_to_query = Some(RecordIdents::SolenoidStatus); + *self.record_to_query.write().unwrap() = Some(RecordIdents::SolenoidStatus); self.chart_idx = 0; self.charting_data.clear(); - self.record_data = None; + *self.curr_values.write().unwrap() = None; } if ui.button("Query solenoid pressures").clicked() { - self.record_to_query = Some(RecordIdents::PressureStatus); + *self.record_to_query.write().unwrap() = Some(RecordIdents::PressureStatus); self.chart_idx = 0; self.charting_data.clear(); - self.record_data = None; + *self.curr_values.write().unwrap() = None; } if ui.button("Query can Rx data").clicked() { - self.record_to_query = Some(RecordIdents::CanDataDump); + *self.record_to_query.write().unwrap() = Some(RecordIdents::CanDataDump); self.chart_idx = 0; self.charting_data.clear(); - self.record_data = None; + *self.curr_values.write().unwrap() = None; } if ui.button("Query Shift data").clicked() { - self.record_to_query = Some(RecordIdents::SSData); + *self.record_to_query.write().unwrap() = Some(RecordIdents::SSData); self.chart_idx = 0; self.charting_data.clear(); - self.record_data = None; + *self.curr_values.write().unwrap() = None; } if ui.button("Query Performance metrics").clicked() { - self.record_to_query = Some(RecordIdents::SysUsage); + *self.record_to_query.write().unwrap() = Some(RecordIdents::SysUsage); self.chart_idx = 0; self.charting_data.clear(); - self.record_data = None; - } - - match &self.text { - CommandStatus::Ok(res) => { - ui.label(RichText::new(res).color(Color32::from_rgb(0, 255, 0))); - } - CommandStatus::Err(res) => { - ui.label(RichText::new(res).color(Color32::from_rgb(255, 0, 0))); - } + *self.curr_values.write().unwrap() = None; } - if pending || (self.last_query_time.elapsed().as_millis() > 100) { - self.last_query_time = Instant::now(); - self.chart_idx += 100; - if let Some(rid) = self.record_to_query { - match self.nag.with_kwp(|server| rid.query_ecu(server)) { - Ok(r) => self.record_data = Some(r), - Err(e) => { - eprintln!("Could not query {}", e); - } - } - } - } - - if let Some(data) = &self.record_data { + let current_val = self.curr_values.read().unwrap().clone(); + if let Some(data) = current_val { data.to_table(ui); let c = data.get_chart_data(); @@ -119,7 +138,7 @@ impl crate::window::InterfacePage for DiagnosticsPage { if !c.is_empty() { let d = &c[0]; self.charting_data.push_back((self.chart_idx, d.clone())); - + self.chart_idx+=1; if self.charting_data.len() > (20000 / 100) { // 20 seconds let _ = self.charting_data.pop_front(); @@ -129,7 +148,6 @@ impl crate::window::InterfacePage for DiagnosticsPage { // as `d` let mut lines = Vec::new(); let legend = Legend::default(); - for (idx, (key, _, _)) in d.data.iter().enumerate() { let mut points: Vec<[f64; 2]> = Vec::new(); for (timestamp, point) in &self.charting_data { @@ -155,6 +173,7 @@ impl crate::window::InterfacePage for DiagnosticsPage { plot = plot.include_y(*max); } } + plot = plot.include_x(200); plot.show(ui, |plot_ui| { for x in lines { @@ -162,7 +181,6 @@ impl crate::window::InterfacePage for DiagnosticsPage { } }); } - ui.ctx().request_repaint(); } PageAction::None diff --git a/config_app/src/ui/diagnostics/rli.rs b/config_app/src/ui/diagnostics/rli.rs index 6c96a41..442baf7 100644 --- a/config_app/src/ui/diagnostics/rli.rs +++ b/config_app/src/ui/diagnostics/rli.rs @@ -9,6 +9,8 @@ use packed_struct::prelude::{PackedStruct, PrimitiveEnum_u8}; use std::borrow::Borrow; use std::i16::MAX; +pub const RLI_QUERY_INTERVAL: u64 = 100; + #[repr(u8)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] pub enum RecordIdents {