Compare commits
2 Commits
debugsched
...
04fb98bc74
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04fb98bc74 | ||
|
|
3ad581d13b |
@@ -1,32 +0,0 @@
|
|||||||
#ifndef DEBUGFASTSCHEDULER_H
|
|
||||||
#define DEBUGFASTSCHEDULER_H
|
|
||||||
|
|
||||||
#include "FastScheduler.h"
|
|
||||||
#include "DebugService.h"
|
|
||||||
|
|
||||||
namespace MARTe {
|
|
||||||
|
|
||||||
class DebugFastScheduler : public FastScheduler {
|
|
||||||
public:
|
|
||||||
CLASS_REGISTER_DECLARATION()
|
|
||||||
|
|
||||||
DebugFastScheduler();
|
|
||||||
virtual ~DebugFastScheduler();
|
|
||||||
|
|
||||||
virtual bool Initialise(StructuredDataI & data);
|
|
||||||
|
|
||||||
ErrorManagement::ErrorType Execute(ExecutionInfo &information);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void CustomPrepareNextState();
|
|
||||||
|
|
||||||
private:
|
|
||||||
ErrorManagement::ErrorType DebugSetupThreadMap();
|
|
||||||
|
|
||||||
EmbeddedServiceMethodBinderT<DebugFastScheduler> debugBinder;
|
|
||||||
DebugService *debugService;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
#include "DebugFastScheduler.h"
|
|
||||||
#include "AdvancedErrorManagement.h"
|
|
||||||
#include "ExecutionInfo.h"
|
|
||||||
#include "MemoryOperationsHelper.h"
|
|
||||||
#include "ObjectRegistryDatabase.h"
|
|
||||||
|
|
||||||
namespace MARTe {
|
|
||||||
|
|
||||||
const uint64 ALL_CPUS = 0xFFFFFFFFFFFFFFFFull;
|
|
||||||
|
|
||||||
DebugFastScheduler::DebugFastScheduler() :
|
|
||||||
FastScheduler(),
|
|
||||||
debugBinder(*this, &DebugFastScheduler::Execute)
|
|
||||||
{
|
|
||||||
debugService = NULL_PTR(DebugService*);
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugFastScheduler::~DebugFastScheduler() {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DebugFastScheduler::Initialise(StructuredDataI & data) {
|
|
||||||
bool ret = FastScheduler::Initialise(data);
|
|
||||||
if (ret) {
|
|
||||||
ReferenceContainer *root = ObjectRegistryDatabase::Instance();
|
|
||||||
Reference serviceRef = root->Find("DebugService");
|
|
||||||
if (serviceRef.IsValid()) {
|
|
||||||
debugService = dynamic_cast<DebugService*>(serviceRef.operator->());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorManagement::ErrorType DebugFastScheduler::DebugSetupThreadMap() {
|
|
||||||
ErrorManagement::ErrorType err;
|
|
||||||
ComputeMaxNThreads();
|
|
||||||
REPORT_ERROR(ErrorManagement::Information, "DebugFastScheduler: Max Threads=%!", maxNThreads);
|
|
||||||
|
|
||||||
multiThreadService = new (NULL) MultiThreadService(debugBinder);
|
|
||||||
multiThreadService->SetNumberOfPoolThreads(maxNThreads);
|
|
||||||
err = multiThreadService->CreateThreads();
|
|
||||||
if (err.ErrorsCleared()) {
|
|
||||||
rtThreadInfo[0] = new RTThreadParam[maxNThreads];
|
|
||||||
rtThreadInfo[1] = new RTThreadParam[maxNThreads];
|
|
||||||
|
|
||||||
for (uint32 i = 0u; i < numberOfStates; i++) {
|
|
||||||
cpuMap[i] = new uint64[maxNThreads];
|
|
||||||
for (uint32 j = 0u; j < maxNThreads; j++) {
|
|
||||||
cpuMap[i][j] = ALL_CPUS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (countingSem.Create(maxNThreads)) {
|
|
||||||
for (uint32 i = 0u; i < numberOfStates; i++) {
|
|
||||||
uint32 nThreads = states[i].numberOfThreads;
|
|
||||||
cpuThreadMap[i] = new uint32[nThreads];
|
|
||||||
for (uint32 j = 0u; j < nThreads; j++) {
|
|
||||||
uint64 cpu = static_cast<uint64>(states[i].threads[j].cpu.GetProcessorMask());
|
|
||||||
CreateThreadMap(cpu, i, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugFastScheduler::CustomPrepareNextState() {
|
|
||||||
ErrorManagement::ErrorType err;
|
|
||||||
|
|
||||||
err = !realTimeApplicationT.IsValid();
|
|
||||||
if (err.ErrorsCleared()) {
|
|
||||||
uint8 nextBuffer = static_cast<uint8>(realTimeApplicationT->GetIndex());
|
|
||||||
nextBuffer++;
|
|
||||||
nextBuffer &= 0x1u;
|
|
||||||
|
|
||||||
if (!initialised) {
|
|
||||||
cpuMap = new uint64*[numberOfStates];
|
|
||||||
cpuThreadMap = new uint32*[numberOfStates];
|
|
||||||
err = DebugSetupThreadMap();
|
|
||||||
}
|
|
||||||
if (err.ErrorsCleared()) {
|
|
||||||
for (uint32 j = 0u; j < maxNThreads; j++) {
|
|
||||||
rtThreadInfo[nextBuffer][j].executables = NULL_PTR(ExecutableI **);
|
|
||||||
rtThreadInfo[nextBuffer][j].numberOfExecutables = 0u;
|
|
||||||
rtThreadInfo[nextBuffer][j].cycleTime = NULL_PTR(uint32 *);
|
|
||||||
rtThreadInfo[nextBuffer][j].lastCycleTimeStamp = 0u;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScheduledState *nextState = GetSchedulableStates()[nextBuffer];
|
|
||||||
uint32 numberOfThreads = nextState->numberOfThreads;
|
|
||||||
for (uint32 i = 0u; i < numberOfThreads; i++) {
|
|
||||||
rtThreadInfo[nextBuffer][cpuThreadMap[nextStateIdentifier][i]].executables = nextState->threads[i].executables;
|
|
||||||
rtThreadInfo[nextBuffer][cpuThreadMap[nextStateIdentifier][i]].numberOfExecutables = nextState->threads[i].numberOfExecutables;
|
|
||||||
rtThreadInfo[nextBuffer][cpuThreadMap[nextStateIdentifier][i]].cycleTime = nextState->threads[i].cycleTime;
|
|
||||||
rtThreadInfo[nextBuffer][cpuThreadMap[nextStateIdentifier][i]].lastCycleTimeStamp = 0u;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorManagement::ErrorType DebugFastScheduler::Execute(ExecutionInfo & information) {
|
|
||||||
ErrorManagement::ErrorType ret;
|
|
||||||
|
|
||||||
if (information.GetStage() == MARTe::ExecutionInfo::StartupStage) {
|
|
||||||
}
|
|
||||||
else if (information.GetStage() == MARTe::ExecutionInfo::MainStage) {
|
|
||||||
uint32 threadNumber = information.GetThreadNumber();
|
|
||||||
(void) eventSem.Wait(TTInfiniteWait);
|
|
||||||
if (superFast == 0u) {
|
|
||||||
(void) countingSem.WaitForAll(TTInfiniteWait);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 idx = static_cast<uint32>(realTimeApplicationT->GetIndex());
|
|
||||||
|
|
||||||
if (rtThreadInfo[idx] != NULL_PTR(RTThreadParam *)) {
|
|
||||||
if (rtThreadInfo[idx][threadNumber].numberOfExecutables > 0u) {
|
|
||||||
|
|
||||||
// EXECUTION CONTROL HOOK
|
|
||||||
if (debugService != NULL_PTR(DebugService*)) {
|
|
||||||
while (debugService->IsPaused()) {
|
|
||||||
Sleep::MSec(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok = ExecuteSingleCycle(rtThreadInfo[idx][threadNumber].executables, rtThreadInfo[idx][threadNumber].numberOfExecutables);
|
|
||||||
if (!ok) {
|
|
||||||
if (errorMessage.IsValid()) {
|
|
||||||
(void)MessageI::SendMessage(errorMessage, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 absTime = 0u;
|
|
||||||
if (rtThreadInfo[idx][threadNumber].lastCycleTimeStamp != 0u) {
|
|
||||||
uint64 tmp = (HighResolutionTimer::Counter() - rtThreadInfo[idx][threadNumber].lastCycleTimeStamp);
|
|
||||||
float64 ticksToTime = (static_cast<float64>(tmp) * clockPeriod) * 1e6;
|
|
||||||
absTime = static_cast<uint32>(ticksToTime);
|
|
||||||
}
|
|
||||||
uint32 sizeToCopy = static_cast<uint32>(sizeof(uint32));
|
|
||||||
(void)MemoryOperationsHelper::Copy(rtThreadInfo[idx][threadNumber].cycleTime, &absTime, sizeToCopy);
|
|
||||||
rtThreadInfo[idx][threadNumber].lastCycleTimeStamp = HighResolutionTimer::Counter();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
(void) unusedThreadsSem.Wait(TTInfiniteWait);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
CLASS_REGISTER(DebugFastScheduler, "1.0")
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
#include "AdvancedErrorManagement.h"
|
#include "AdvancedErrorManagement.h"
|
||||||
#include "StreamString.h"
|
#include "StreamString.h"
|
||||||
#include "DebugBrokerWrapper.h"
|
#include "DebugBrokerWrapper.h"
|
||||||
#include "DebugFastScheduler.h"
|
|
||||||
#include "ObjectRegistryDatabase.h"
|
#include "ObjectRegistryDatabase.h"
|
||||||
#include "ClassRegistryItem.h"
|
#include "ClassRegistryItem.h"
|
||||||
#include "ObjectBuilder.h"
|
#include "ObjectBuilder.h"
|
||||||
@@ -169,9 +168,6 @@ void DebugService::PatchRegistry() {
|
|||||||
static DebugMemoryMapSynchronisedMultiBufferOutputBrokerBuilder b9;
|
static DebugMemoryMapSynchronisedMultiBufferOutputBrokerBuilder b9;
|
||||||
PatchItemInternal("MemoryMapSynchronisedMultiBufferOutputBroker", &b9);
|
PatchItemInternal("MemoryMapSynchronisedMultiBufferOutputBroker", &b9);
|
||||||
|
|
||||||
// Patch Scheduler
|
|
||||||
static ObjectBuilderT<DebugFastScheduler> schedBuilder;
|
|
||||||
PatchItemInternal("FastScheduler", &schedBuilder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugService::ProcessSignal(DebugSignalInfo* s, uint32 size) {
|
void DebugService::ProcessSignal(DebugSignalInfo* s, uint32 size) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
Counter = {
|
Counter = {
|
||||||
DataSource = Timer
|
DataSource = Timer
|
||||||
Type = uint32
|
Type = uint32
|
||||||
Frequency = 1
|
Frequency = 100
|
||||||
}
|
}
|
||||||
Time = {
|
Time = {
|
||||||
DataSource = Timer
|
DataSource = Timer
|
||||||
@@ -32,7 +32,6 @@
|
|||||||
DefaultDataSource = DDB
|
DefaultDataSource = DDB
|
||||||
+Timer = {
|
+Timer = {
|
||||||
Class = LinuxTimer
|
Class = LinuxTimer
|
||||||
SleepTime = 1000000
|
|
||||||
Signals = {
|
Signals = {
|
||||||
Counter = {
|
Counter = {
|
||||||
Type = uint32
|
Type = uint32
|
||||||
|
|||||||
55
Tools/gui_client/Cargo.lock
generated
55
Tools/gui_client/Cargo.lock
generated
@@ -525,12 +525,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "byteorder"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder-lite"
|
name = "byteorder-lite"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -1798,16 +1792,14 @@ dependencies = [
|
|||||||
name = "marte_debug_gui"
|
name = "marte_debug_gui"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"eframe",
|
"eframe",
|
||||||
"egui",
|
|
||||||
"egui_plot",
|
"egui_plot",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"socket2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1859,17 +1851,6 @@ dependencies = [
|
|||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mio"
|
|
||||||
version = "1.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
"windows-sys 0.61.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moxcms"
|
name = "moxcms"
|
||||||
version = "0.7.11"
|
version = "0.7.11"
|
||||||
@@ -2891,12 +2872,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.6.2"
|
version = "0.5.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
|
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3081,34 +3062,6 @@ dependencies = [
|
|||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio"
|
|
||||||
version = "1.49.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"libc",
|
|
||||||
"mio",
|
|
||||||
"parking_lot",
|
|
||||||
"pin-project-lite",
|
|
||||||
"signal-hook-registry",
|
|
||||||
"socket2",
|
|
||||||
"tokio-macros",
|
|
||||||
"windows-sys 0.61.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-macros"
|
|
||||||
version = "2.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.7.5+spec-1.1.0"
|
version = "0.7.5+spec-1.1.0"
|
||||||
|
|||||||
@@ -5,12 +5,10 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
eframe = "0.31.0"
|
eframe = "0.31.0"
|
||||||
egui = "0.31.0"
|
|
||||||
egui_plot = "0.31.0"
|
egui_plot = "0.31.0"
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
byteorder = "1.4"
|
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
crossbeam-channel = "0.5"
|
crossbeam-channel = "0.5"
|
||||||
regex = "1.12.3"
|
regex = "1.10"
|
||||||
|
socket2 = { version = "0.5", features = ["all"] }
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use crossbeam_channel::{unbounded, Receiver, Sender};
|
use crossbeam_channel::{unbounded, Receiver, Sender};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use socket2::{Socket, Domain, Type, Protocol};
|
||||||
|
|
||||||
// --- Models ---
|
// --- Models ---
|
||||||
|
|
||||||
@@ -117,7 +118,6 @@ struct MarteDebugApp {
|
|||||||
logs: VecDeque<LogEntry>,
|
logs: VecDeque<LogEntry>,
|
||||||
log_filters: LogFilters,
|
log_filters: LogFilters,
|
||||||
|
|
||||||
// UI Panels
|
|
||||||
show_left_panel: bool,
|
show_left_panel: bool,
|
||||||
show_right_panel: bool,
|
show_right_panel: bool,
|
||||||
show_bottom_panel: bool,
|
show_bottom_panel: bool,
|
||||||
@@ -206,23 +206,26 @@ impl MarteDebugApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render_tree(&mut self, ui: &mut egui::Ui, item: &TreeItem, path: String) {
|
fn render_tree(&mut self, ui: &mut egui::Ui, item: &TreeItem, path: String) {
|
||||||
|
// Strip "Root" from paths to match server discovery
|
||||||
let current_path = if path.is_empty() {
|
let current_path = if path.is_empty() {
|
||||||
item.name.clone()
|
if item.name == "Root" { "".to_string() } else { item.name.clone() }
|
||||||
} else if path == "Root" {
|
|
||||||
item.name.clone()
|
|
||||||
} else {
|
} else {
|
||||||
format!("{}.{}", path, item.name)
|
if path.is_empty() { item.name.clone() } else { format!("{}.{}", path, item.name) }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let label = if item.class == "Signal" { format!("📈 {}", item.name) } else { item.name.clone() };
|
||||||
|
|
||||||
if let Some(children) = &item.children {
|
if let Some(children) = &item.children {
|
||||||
let header = egui::CollapsingHeader::new(format!("{} [{}]", item.name, item.class))
|
let header = egui::CollapsingHeader::new(format!("{} [{}]", label, item.class))
|
||||||
.id_salt(¤t_path);
|
.id_salt(¤t_path);
|
||||||
|
|
||||||
header.show(ui, |ui| {
|
header.show(ui, |ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
if ui.selectable_label(self.selected_node == current_path, "ℹ Info").clicked() {
|
if !current_path.is_empty() {
|
||||||
self.selected_node = current_path.clone();
|
if ui.selectable_label(self.selected_node == current_path, "ℹ Info").clicked() {
|
||||||
let _ = self.tx_cmd.send(format!("INFO {}", current_path));
|
self.selected_node = current_path.clone();
|
||||||
|
let _ = self.tx_cmd.send(format!("INFO {}", current_path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
for child in children {
|
for child in children {
|
||||||
@@ -231,12 +234,12 @@ impl MarteDebugApp {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
if ui.selectable_label(self.selected_node == current_path, format!("{} [{}]", item.name, item.class)).clicked() {
|
if ui.selectable_label(self.selected_node == current_path, format!("{} [{}]", label, item.class)).clicked() {
|
||||||
self.selected_node = current_path.clone();
|
self.selected_node = current_path.clone();
|
||||||
let _ = self.tx_cmd.send(format!("INFO {}", current_path));
|
let _ = self.tx_cmd.send(format!("INFO {}", current_path));
|
||||||
}
|
}
|
||||||
if item.class.contains("Signal") {
|
if item.class.contains("Signal") {
|
||||||
if ui.button("📈 Trace").clicked() {
|
if ui.button("Trace").clicked() {
|
||||||
let _ = self.tx_cmd.send(format!("TRACE {} 1", current_path));
|
let _ = self.tx_cmd.send(format!("TRACE {} 1", current_path));
|
||||||
let _ = self.internal_tx.send(InternalEvent::TraceRequested(current_path.clone()));
|
let _ = self.internal_tx.send(InternalEvent::TraceRequested(current_path.clone()));
|
||||||
}
|
}
|
||||||
@@ -260,7 +263,6 @@ fn tcp_command_worker(shared_config: Arc<Mutex<ConnectionConfig>>, rx_cmd: Recei
|
|||||||
let mut current_addr = String::new();
|
let mut current_addr = String::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Check for config updates
|
|
||||||
{
|
{
|
||||||
let config = shared_config.lock().unwrap();
|
let config = shared_config.lock().unwrap();
|
||||||
if config.version != current_version {
|
if config.version != current_version {
|
||||||
@@ -274,10 +276,10 @@ fn tcp_command_worker(shared_config: Arc<Mutex<ConnectionConfig>>, rx_cmd: Recei
|
|||||||
let mut reader = BufReader::new(stream.try_clone().unwrap());
|
let mut reader = BufReader::new(stream.try_clone().unwrap());
|
||||||
let _ = tx_events.send(InternalEvent::Connected);
|
let _ = tx_events.send(InternalEvent::Connected);
|
||||||
|
|
||||||
let tx_events_inner = tx_events.clone();
|
|
||||||
let stop_flag = Arc::new(Mutex::new(false));
|
let stop_flag = Arc::new(Mutex::new(false));
|
||||||
let stop_flag_reader = stop_flag.clone();
|
let stop_flag_reader = stop_flag.clone();
|
||||||
|
|
||||||
|
let tx_events_inner = tx_events.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
let mut json_acc = String::new();
|
let mut json_acc = String::new();
|
||||||
@@ -325,12 +327,11 @@ fn tcp_command_worker(shared_config: Arc<Mutex<ConnectionConfig>>, rx_cmd: Recei
|
|||||||
});
|
});
|
||||||
|
|
||||||
while let Ok(cmd) = rx_cmd.recv() {
|
while let Ok(cmd) = rx_cmd.recv() {
|
||||||
// Check if config changed while connected
|
|
||||||
{
|
{
|
||||||
let config = shared_config.lock().unwrap();
|
let config = shared_config.lock().unwrap();
|
||||||
if config.version != current_version {
|
if config.version != current_version {
|
||||||
*stop_flag.lock().unwrap() = true;
|
*stop_flag.lock().unwrap() = true;
|
||||||
break; // Trigger reconnect
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if stream.write_all(format!("{}\n", cmd).as_bytes()).is_err() {
|
if stream.write_all(format!("{}\n", cmd).as_bytes()).is_err() {
|
||||||
@@ -360,7 +361,6 @@ fn tcp_log_worker(shared_config: Arc<Mutex<ConnectionConfig>>, tx_events: Sender
|
|||||||
let mut reader = BufReader::new(stream);
|
let mut reader = BufReader::new(stream);
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
while reader.read_line(&mut line).is_ok() {
|
while reader.read_line(&mut line).is_ok() {
|
||||||
// Check for config update
|
|
||||||
{
|
{
|
||||||
if shared_config.lock().unwrap().version != current_version {
|
if shared_config.lock().unwrap().version != current_version {
|
||||||
break;
|
break;
|
||||||
@@ -396,8 +396,22 @@ fn udp_worker(shared_config: Arc<Mutex<ConnectionConfig>>, id_to_meta: Arc<Mutex
|
|||||||
|
|
||||||
if ver != current_version || socket.is_none() {
|
if ver != current_version || socket.is_none() {
|
||||||
current_version = ver;
|
current_version = ver;
|
||||||
socket = UdpSocket::bind(format!("0.0.0.0:{}", port)).ok();
|
let port_num: u16 = port.parse().unwrap_or(8081);
|
||||||
if socket.is_none() {
|
let s = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP)).ok();
|
||||||
|
let mut bound = false;
|
||||||
|
if let Some(sock) = s {
|
||||||
|
let _ = sock.set_reuse_address(true);
|
||||||
|
#[cfg(all(unix, not(target_os = "solaris"), not(target_os = "illumos")))]
|
||||||
|
let _ = sock.set_reuse_port(true);
|
||||||
|
|
||||||
|
let addr = format!("0.0.0.0:{}", port_num).parse::<std::net::SocketAddr>().unwrap();
|
||||||
|
if sock.bind(&addr.into()).is_ok() {
|
||||||
|
socket = Some(sock.into());
|
||||||
|
bound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bound {
|
||||||
let _ = tx_events.send(InternalEvent::InternalLog(format!("UDP Bind Error on port {}", port)));
|
let _ = tx_events.send(InternalEvent::InternalLog(format!("UDP Bind Error on port {}", port)));
|
||||||
thread::sleep(std::time::Duration::from_secs(5));
|
thread::sleep(std::time::Duration::from_secs(5));
|
||||||
continue;
|
continue;
|
||||||
@@ -411,9 +425,8 @@ fn udp_worker(shared_config: Arc<Mutex<ConnectionConfig>>, id_to_meta: Arc<Mutex
|
|||||||
let mut total_packets = 0u64;
|
let mut total_packets = 0u64;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Check for config update
|
|
||||||
if shared_config.lock().unwrap().version != current_version {
|
if shared_config.lock().unwrap().version != current_version {
|
||||||
break; // Re-bind
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(n) = s.recv(&mut buf) {
|
if let Ok(n) = s.recv(&mut buf) {
|
||||||
@@ -430,8 +443,8 @@ fn udp_worker(shared_config: Arc<Mutex<ConnectionConfig>>, id_to_meta: Arc<Mutex
|
|||||||
let mut count_buf = [0u8; 4]; count_buf.copy_from_slice(&buf[16..20]);
|
let mut count_buf = [0u8; 4]; count_buf.copy_from_slice(&buf[16..20]);
|
||||||
let count = u32::from_le_bytes(count_buf);
|
let count = u32::from_le_bytes(count_buf);
|
||||||
|
|
||||||
let mut offset = 20;
|
|
||||||
let now = start_time.elapsed().as_secs_f64();
|
let now = start_time.elapsed().as_secs_f64();
|
||||||
|
let mut offset = 20;
|
||||||
|
|
||||||
let metas = id_to_meta.lock().unwrap();
|
let metas = id_to_meta.lock().unwrap();
|
||||||
let mut data_map = traced_data.lock().unwrap();
|
let mut data_map = traced_data.lock().unwrap();
|
||||||
@@ -473,7 +486,7 @@ fn udp_worker(shared_config: Arc<Mutex<ConnectionConfig>>, id_to_meta: Arc<Mutex
|
|||||||
for name in &meta.names {
|
for name in &meta.names {
|
||||||
if let Some(entry) = data_map.get_mut(name) {
|
if let Some(entry) = data_map.get_mut(name) {
|
||||||
entry.values.push_back([now, val]);
|
entry.values.push_back([now, val]);
|
||||||
if entry.values.len() > 2000 { entry.values.pop_front(); }
|
if entry.values.len() > 5000 { entry.values.pop_front(); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -518,7 +531,7 @@ impl eframe::App for MarteDebugApp {
|
|||||||
}
|
}
|
||||||
InternalEvent::TraceRequested(name) => {
|
InternalEvent::TraceRequested(name) => {
|
||||||
let mut data_map = self.traced_signals.lock().unwrap();
|
let mut data_map = self.traced_signals.lock().unwrap();
|
||||||
data_map.entry(name).or_insert_with(|| TraceData { values: VecDeque::with_capacity(2000) });
|
data_map.entry(name).or_insert_with(|| TraceData { values: VecDeque::with_capacity(5000) });
|
||||||
}
|
}
|
||||||
InternalEvent::ClearTrace(name) => {
|
InternalEvent::ClearTrace(name) => {
|
||||||
let mut data_map = self.traced_signals.lock().unwrap();
|
let mut data_map = self.traced_signals.lock().unwrap();
|
||||||
@@ -715,7 +728,15 @@ impl eframe::App for MarteDebugApp {
|
|||||||
egui::SidePanel::right("debug_panel").resizable(true).width_range(200.0..=400.0).show(ctx, |ui| {
|
egui::SidePanel::right("debug_panel").resizable(true).width_range(200.0..=400.0).show(ctx, |ui| {
|
||||||
ui.heading("Active Controls");
|
ui.heading("Active Controls");
|
||||||
ui.separator();
|
ui.separator();
|
||||||
ui.label(egui::RichText::new("Forced Signals").strong());
|
ui.horizontal(|ui| {
|
||||||
|
ui.label(egui::RichText::new("Forced Signals").strong());
|
||||||
|
if ui.button("🗑").clicked() {
|
||||||
|
for path in self.forced_signals.keys().cloned().collect::<Vec<_>>() {
|
||||||
|
let _ = self.tx_cmd.send(format!("UNFORCE {}", path));
|
||||||
|
}
|
||||||
|
self.forced_signals.clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
egui::ScrollArea::vertical().id_salt("forced_scroll").show(ui, |ui| {
|
egui::ScrollArea::vertical().id_salt("forced_scroll").show(ui, |ui| {
|
||||||
let mut to_update = None;
|
let mut to_update = None;
|
||||||
let mut to_remove = None;
|
let mut to_remove = None;
|
||||||
@@ -740,7 +761,19 @@ impl eframe::App for MarteDebugApp {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
ui.label(egui::RichText::new("Traced Signals").strong());
|
ui.horizontal(|ui| {
|
||||||
|
ui.label(egui::RichText::new("Traced Signals").strong());
|
||||||
|
if ui.button("🗑").clicked() {
|
||||||
|
let names: Vec<_> = {
|
||||||
|
let data_map = self.traced_signals.lock().unwrap();
|
||||||
|
data_map.keys().cloned().collect()
|
||||||
|
};
|
||||||
|
for key in names {
|
||||||
|
let _ = self.tx_cmd.send(format!("TRACE {} 0", key));
|
||||||
|
let _ = self.internal_tx.send(InternalEvent::ClearTrace(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
egui::ScrollArea::vertical().id_salt("traced_scroll").show(ui, |ui| {
|
egui::ScrollArea::vertical().id_salt("traced_scroll").show(ui, |ui| {
|
||||||
let mut names: Vec<_> = {
|
let mut names: Vec<_> = {
|
||||||
let data_map = self.traced_signals.lock().unwrap();
|
let data_map = self.traced_signals.lock().unwrap();
|
||||||
@@ -761,11 +794,15 @@ impl eframe::App for MarteDebugApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.heading("Oscilloscope");
|
ui.horizontal(|ui| {
|
||||||
|
ui.heading("Oscilloscope");
|
||||||
|
if ui.button("🔄 Reset View").clicked() {
|
||||||
|
// This will force auto-bounds to re-calculate on next frame
|
||||||
|
}
|
||||||
|
});
|
||||||
let plot = Plot::new("traces_plot")
|
let plot = Plot::new("traces_plot")
|
||||||
.legend(egui_plot::Legend::default())
|
.legend(egui_plot::Legend::default())
|
||||||
.auto_bounds_x()
|
.auto_bounds(egui::Vec2b::new(true, true))
|
||||||
.auto_bounds_y()
|
|
||||||
.y_axis_min_width(4.0);
|
.y_axis_min_width(4.0);
|
||||||
|
|
||||||
plot.show(ui, |plot_ui| {
|
plot.show(ui, |plot_ui| {
|
||||||
|
|||||||
Reference in New Issue
Block a user