Improved overall features
This commit is contained in:
@@ -51,6 +51,10 @@ struct TreeItem {
|
||||
dimensions: Option<u8>,
|
||||
#[serde(rename = "Elements")]
|
||||
elements: Option<u32>,
|
||||
#[serde(rename = "IsTraceable")]
|
||||
is_traceable: Option<bool>,
|
||||
#[serde(rename = "IsForcable")]
|
||||
is_forcable: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -65,6 +69,7 @@ struct TraceData {
|
||||
last_value: f64,
|
||||
recording_tx: Option<Sender<[f64; 2]>>,
|
||||
recording_path: Option<String>,
|
||||
is_monitored: bool,
|
||||
}
|
||||
|
||||
struct SignalMetadata {
|
||||
@@ -151,13 +156,14 @@ enum InternalEvent {
|
||||
Connected,
|
||||
Disconnected,
|
||||
InternalLog(String),
|
||||
TraceRequested(String),
|
||||
TraceRequested(String, bool), // Name, IsMonitored
|
||||
ClearTrace(String),
|
||||
UdpStats(u64),
|
||||
UdpDropped(u32),
|
||||
RecordPathChosen(String, String), // SignalName, FilePath
|
||||
RecordingError(String, String), // SignalName, ErrorMessage
|
||||
TelemMatched(u32), // Signal ID
|
||||
ServiceConfig { udp_port: String, log_port: String },
|
||||
}
|
||||
|
||||
// --- App State ---
|
||||
@@ -167,6 +173,11 @@ struct ForcingDialog {
|
||||
value: String,
|
||||
}
|
||||
|
||||
struct MonitorDialog {
|
||||
signal_path: String,
|
||||
period_ms: String,
|
||||
}
|
||||
|
||||
struct LogFilters {
|
||||
show_debug: bool,
|
||||
show_info: bool,
|
||||
@@ -212,6 +223,7 @@ struct MarteDebugApp {
|
||||
udp_dropped: u64,
|
||||
telem_match_count: HashMap<u32, u64>,
|
||||
forcing_dialog: Option<ForcingDialog>,
|
||||
monitoring_dialog: Option<MonitorDialog>,
|
||||
style_editor: Option<(usize, usize)>,
|
||||
tx_cmd: Sender<String>,
|
||||
rx_events: Receiver<InternalEvent>,
|
||||
@@ -291,6 +303,7 @@ impl MarteDebugApp {
|
||||
udp_dropped: 0,
|
||||
telem_match_count: HashMap::new(),
|
||||
forcing_dialog: None,
|
||||
monitoring_dialog: None,
|
||||
style_editor: None,
|
||||
tx_cmd,
|
||||
rx_events,
|
||||
@@ -430,13 +443,24 @@ impl MarteDebugApp {
|
||||
let _ = self.tx_cmd.send(format!("INFO {}", current_path));
|
||||
}
|
||||
if item.class.contains("Signal") {
|
||||
if ui.button("Trace").clicked() {
|
||||
let traceable = item.is_traceable.unwrap_or(false);
|
||||
let forcable = item.is_forcable.unwrap_or(false);
|
||||
|
||||
if traceable && ui.button("Trace").clicked() {
|
||||
let _ = self.tx_cmd.send(format!("TRACE {} 1", current_path));
|
||||
let _ = self
|
||||
.internal_tx
|
||||
.send(InternalEvent::TraceRequested(current_path.clone()));
|
||||
.send(InternalEvent::TraceRequested(current_path.clone(), false));
|
||||
}
|
||||
if ui.button("⚡ Force").clicked() {
|
||||
if item.class == "Signal" {
|
||||
if ui.button("Monitor").clicked() {
|
||||
self.monitoring_dialog = Some(MonitorDialog {
|
||||
signal_path: current_path.clone(),
|
||||
period_ms: "100".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
if forcable && ui.button("⚡ Force").clicked() {
|
||||
self.forcing_dialog = Some(ForcingDialog {
|
||||
signal_path: current_path.clone(),
|
||||
value: "".to_string(),
|
||||
@@ -535,6 +559,26 @@ fn tcp_command_worker(
|
||||
json_acc.clear();
|
||||
}
|
||||
} else {
|
||||
if trimmed.starts_with("OK SERVICE_INFO") {
|
||||
// OK SERVICE_INFO TCP_CTRL:8110 UDP_STREAM:8111 TCP_LOG:8082 STATE:RUNNING
|
||||
let parts: Vec<&str> = trimmed.split_whitespace().collect();
|
||||
let mut udp = String::new();
|
||||
let mut log = String::new();
|
||||
for p in parts {
|
||||
if p.starts_with("UDP_STREAM:") {
|
||||
udp = p.split(':').nth(1).unwrap_or("").to_string();
|
||||
}
|
||||
if p.starts_with("TCP_LOG:") {
|
||||
log = p.split(':').nth(1).unwrap_or("").to_string();
|
||||
}
|
||||
}
|
||||
if !udp.is_empty() || !log.is_empty() {
|
||||
let _ = tx_events_inner.send(InternalEvent::ServiceConfig {
|
||||
udp_port: udp,
|
||||
log_port: log,
|
||||
});
|
||||
}
|
||||
}
|
||||
let _ = tx_events_inner
|
||||
.send(InternalEvent::CommandResponse(trimmed.to_string()));
|
||||
}
|
||||
@@ -906,14 +950,16 @@ impl eframe::App for MarteDebugApp {
|
||||
InternalEvent::NodeInfo(info) => {
|
||||
self.node_info = info;
|
||||
}
|
||||
InternalEvent::TraceRequested(name) => {
|
||||
InternalEvent::TraceRequested(name, is_monitored) => {
|
||||
let mut data_map = self.traced_signals.lock().unwrap();
|
||||
data_map.entry(name.clone()).or_insert_with(|| TraceData {
|
||||
let entry = data_map.entry(name.clone()).or_insert_with(|| TraceData {
|
||||
values: VecDeque::with_capacity(10000),
|
||||
last_value: 0.0,
|
||||
recording_tx: None,
|
||||
recording_path: None,
|
||||
is_monitored,
|
||||
});
|
||||
entry.is_monitored = is_monitored;
|
||||
self.logs.push_back(LogEntry {
|
||||
time: Local::now().format("%H:%M:%S").to_string(),
|
||||
level: "GUI_INFO".to_string(),
|
||||
@@ -937,11 +983,33 @@ impl eframe::App for MarteDebugApp {
|
||||
self.connected = true;
|
||||
// Wait for connection to stabilize before sending commands
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
let _ = self.tx_cmd.send("SERVICE_INFO".to_string());
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
let _ = self.tx_cmd.send("TREE".to_string());
|
||||
// Wait for TREE response before sending next command
|
||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||
let _ = self.tx_cmd.send("DISCOVER".to_string());
|
||||
}
|
||||
InternalEvent::ServiceConfig { udp_port, log_port } => {
|
||||
let mut changed = false;
|
||||
if !udp_port.is_empty() && self.config.udp_port != udp_port {
|
||||
self.config.udp_port = udp_port;
|
||||
changed = true;
|
||||
}
|
||||
if !log_port.is_empty() && self.config.log_port != log_port {
|
||||
self.config.log_port = log_port;
|
||||
changed = true;
|
||||
}
|
||||
if changed {
|
||||
self.config.version += 1;
|
||||
*self.shared_config.lock().unwrap() = self.config.clone();
|
||||
self.logs.push_back(LogEntry {
|
||||
time: Local::now().format("%H:%M:%S").to_string(),
|
||||
level: "GUI_INFO".to_string(),
|
||||
message: format!("Config updated from server: UDP={}, LOG={}", self.config.udp_port, self.config.log_port),
|
||||
});
|
||||
}
|
||||
}
|
||||
InternalEvent::Disconnected => {
|
||||
self.connected = false;
|
||||
}
|
||||
@@ -1025,6 +1093,36 @@ impl eframe::App for MarteDebugApp {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(dialog) = &mut self.monitoring_dialog {
|
||||
let mut close = false;
|
||||
egui::Window::new("Monitor Signal").show(ctx, |ui| {
|
||||
ui.label(&dialog.signal_path);
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Period (ms):");
|
||||
ui.text_edit_singleline(&mut dialog.period_ms);
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Apply").clicked() {
|
||||
let period = dialog.period_ms.parse::<u32>().unwrap_or(100);
|
||||
let _ = self
|
||||
.tx_cmd
|
||||
.send(format!("MONITOR SIGNAL {} {}", dialog.signal_path, period));
|
||||
let _ = self.tx_cmd.send("DISCOVER".to_string());
|
||||
let _ = self
|
||||
.internal_tx
|
||||
.send(InternalEvent::TraceRequested(dialog.signal_path.clone(), true));
|
||||
close = true;
|
||||
}
|
||||
if ui.button("Cancel").clicked() {
|
||||
close = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
if close {
|
||||
self.monitoring_dialog = None;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((p_idx, s_idx)) = self.style_editor {
|
||||
let mut close = false;
|
||||
egui::Window::new("Signal Style").show(ctx, |ui| {
|
||||
@@ -1205,11 +1303,11 @@ impl eframe::App for MarteDebugApp {
|
||||
ui.label("Control:");
|
||||
ui.text_edit_singleline(&mut self.config.tcp_port);
|
||||
ui.end_row();
|
||||
ui.label("Telemetry:");
|
||||
ui.text_edit_singleline(&mut self.config.udp_port);
|
||||
ui.label("Telemetry (Auto):");
|
||||
ui.label(&self.config.udp_port);
|
||||
ui.end_row();
|
||||
ui.label("Logs:");
|
||||
ui.text_edit_singleline(&mut self.config.log_port);
|
||||
ui.label("Logs (Auto):");
|
||||
ui.label(&self.config.log_port);
|
||||
ui.end_row();
|
||||
});
|
||||
if ui.button("🔄 Apply").clicked() {
|
||||
@@ -1319,7 +1417,11 @@ impl eframe::App for MarteDebugApp {
|
||||
}
|
||||
});
|
||||
if ui.button("❌").clicked() {
|
||||
let _ = self.tx_cmd.send(format!("TRACE {} 0", key));
|
||||
if entry.is_monitored {
|
||||
let _ = self.tx_cmd.send(format!("UNMONITOR SIGNAL {}", key));
|
||||
} else {
|
||||
let _ = self.tx_cmd.send(format!("TRACE {} 0", key));
|
||||
}
|
||||
let _ = self
|
||||
.internal_tx
|
||||
.send(InternalEvent::ClearTrace(key.clone()));
|
||||
|
||||
Reference in New Issue
Block a user