implemented array support on client and server
This commit is contained in:
@@ -109,10 +109,15 @@ public:
|
|||||||
fprintf(stderr, ">> registering %s.%s [%p]\n", dsPath.Buffer(),
|
fprintf(stderr, ">> registering %s.%s [%p]\n", dsPath.Buffer(),
|
||||||
signalName.Buffer(), mmb);
|
signalName.Buffer(), mmb);
|
||||||
|
|
||||||
|
uint8 dims = 0;
|
||||||
|
uint32 elems = 1;
|
||||||
|
(void)dataSourceIn.GetSignalNumberOfDimensions(dsIdx, dims);
|
||||||
|
(void)dataSourceIn.GetSignalNumberOfElements(dsIdx, elems);
|
||||||
|
|
||||||
// Register canonical name
|
// Register canonical name
|
||||||
StreamString dsFullName;
|
StreamString dsFullName;
|
||||||
dsFullName.Printf("%s.%s", dsPath.Buffer(), signalName.Buffer());
|
dsFullName.Printf("%s.%s", dsPath.Buffer(), signalName.Buffer());
|
||||||
service->RegisterSignal(addr, type, dsFullName.Buffer());
|
service->RegisterSignal(addr, type, dsFullName.Buffer(), dims, elems);
|
||||||
|
|
||||||
// Register alias
|
// Register alias
|
||||||
if (functionName != NULL_PTR(const char8 *)) {
|
if (functionName != NULL_PTR(const char8 *)) {
|
||||||
@@ -140,29 +145,21 @@ public:
|
|||||||
if (gamRef.IsValid()) {
|
if (gamRef.IsValid()) {
|
||||||
StreamString absGamPath;
|
StreamString absGamPath;
|
||||||
DebugService::GetFullObjectName(*(gamRef.operator->()), absGamPath);
|
DebugService::GetFullObjectName(*(gamRef.operator->()), absGamPath);
|
||||||
// Register full path (InputSignals/OutputSignals)
|
// Register short path (In/Out) for GUI compatibility
|
||||||
// gamFullName.fPrintf(stderr, "%s.%s.%s", absGamPath.Buffer(),
|
|
||||||
// dirStr, signalName.Buffer()); signalInfoPointers[i] =
|
|
||||||
// service->RegisterSignal(addr, type, gamFullName.Buffer()); Also
|
|
||||||
// register short path (In/Out) for GUI compatibility
|
|
||||||
gamFullName.Printf("%s.%s.%s", absGamPath.Buffer(), dirStrShort,
|
gamFullName.Printf("%s.%s.%s", absGamPath.Buffer(), dirStrShort,
|
||||||
signalName.Buffer());
|
signalName.Buffer());
|
||||||
signalInfoPointers[i] =
|
signalInfoPointers[i] =
|
||||||
service->RegisterSignal(addr, type, gamFullName.Buffer());
|
service->RegisterSignal(addr, type, gamFullName.Buffer(), dims, elems);
|
||||||
} else {
|
} else {
|
||||||
// Fallback to short name
|
// Fallback to short form
|
||||||
// gamFullName.fPrintf(stderr, "%s.%s.%s", functionName, dirStr,
|
|
||||||
// signalName.Buffer()); signalInfoPointers[i] =
|
|
||||||
// service->RegisterSignal(addr, type, gamFullName.Buffer()); Also
|
|
||||||
// register short form
|
|
||||||
gamFullName.Printf("%s.%s.%s", functionName, dirStrShort,
|
gamFullName.Printf("%s.%s.%s", functionName, dirStrShort,
|
||||||
signalName.Buffer());
|
signalName.Buffer());
|
||||||
signalInfoPointers[i] =
|
signalInfoPointers[i] =
|
||||||
service->RegisterSignal(addr, type, gamFullName.Buffer());
|
service->RegisterSignal(addr, type, gamFullName.Buffer(), dims, elems);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
signalInfoPointers[i] =
|
signalInfoPointers[i] =
|
||||||
service->RegisterSignal(addr, type, dsFullName.Buffer());
|
service->RegisterSignal(addr, type, dsFullName.Buffer(), dims, elems);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ struct DebugSignalInfo {
|
|||||||
void* memoryAddress;
|
void* memoryAddress;
|
||||||
TypeDescriptor type;
|
TypeDescriptor type;
|
||||||
StreamString name;
|
StreamString name;
|
||||||
|
uint8 numberOfDimensions;
|
||||||
|
uint32 numberOfElements;
|
||||||
volatile bool isTracing;
|
volatile bool isTracing;
|
||||||
volatile bool isForcing;
|
volatile bool isForcing;
|
||||||
uint8 forcedValue[1024];
|
uint8 forcedValue[1024];
|
||||||
|
|||||||
@@ -272,7 +272,9 @@ void DebugService::PatchRegistry() {
|
|||||||
|
|
||||||
DebugSignalInfo *DebugService::RegisterSignal(void *memoryAddress,
|
DebugSignalInfo *DebugService::RegisterSignal(void *memoryAddress,
|
||||||
TypeDescriptor type,
|
TypeDescriptor type,
|
||||||
const char8 *name) {
|
const char8 *name,
|
||||||
|
uint8 numberOfDimensions,
|
||||||
|
uint32 numberOfElements) {
|
||||||
printf("<debug> registering: %s\n", name);
|
printf("<debug> registering: %s\n", name);
|
||||||
mutex.FastLock();
|
mutex.FastLock();
|
||||||
DebugSignalInfo *res = NULL_PTR(DebugSignalInfo *);
|
DebugSignalInfo *res = NULL_PTR(DebugSignalInfo *);
|
||||||
@@ -290,6 +292,8 @@ DebugSignalInfo *DebugService::RegisterSignal(void *memoryAddress,
|
|||||||
res->memoryAddress = memoryAddress;
|
res->memoryAddress = memoryAddress;
|
||||||
res->type = type;
|
res->type = type;
|
||||||
res->name = name;
|
res->name = name;
|
||||||
|
res->numberOfDimensions = numberOfDimensions;
|
||||||
|
res->numberOfElements = numberOfElements;
|
||||||
res->isTracing = false;
|
res->isTracing = false;
|
||||||
res->isForcing = false;
|
res->isForcing = false;
|
||||||
res->internalID = sigIdx;
|
res->internalID = sigIdx;
|
||||||
@@ -1167,9 +1171,9 @@ void DebugService::Discover(BasicTCPSocket *client) {
|
|||||||
DebugSignalInfo *sig = signals[aliases[i].signalIndex];
|
DebugSignalInfo *sig = signals[aliases[i].signalIndex];
|
||||||
const char8 *typeName =
|
const char8 *typeName =
|
||||||
TypeDescriptor::GetTypeNameFromTypeDescriptor(sig->type);
|
TypeDescriptor::GetTypeNameFromTypeDescriptor(sig->type);
|
||||||
line.Printf(" {\"name\": \"%s\", \"id\": %d, \"type\": \"%s\"",
|
line.Printf(" {\"name\": \"%s\", \"id\": %d, \"type\": \"%s\", \"dimensions\": %u, \"elements\": %u",
|
||||||
aliases[i].name.Buffer(), sig->internalID,
|
aliases[i].name.Buffer(), sig->internalID,
|
||||||
typeName ? typeName : "Unknown");
|
typeName ? typeName : "Unknown", sig->numberOfDimensions, sig->numberOfElements);
|
||||||
EnrichWithConfig(aliases[i].name.Buffer(), line);
|
EnrichWithConfig(aliases[i].name.Buffer(), line);
|
||||||
line += "}";
|
line += "}";
|
||||||
s = line.Size();
|
s = line.Size();
|
||||||
@@ -1195,10 +1199,16 @@ void DebugService::Discover(BasicTCPSocket *client) {
|
|||||||
const char8 *typeName = TypeDescriptor::GetTypeNameFromTypeDescriptor(
|
const char8 *typeName = TypeDescriptor::GetTypeNameFromTypeDescriptor(
|
||||||
monitoredSignals[i].dataSource->GetSignalType(
|
monitoredSignals[i].dataSource->GetSignalType(
|
||||||
monitoredSignals[i].signalIdx));
|
monitoredSignals[i].signalIdx));
|
||||||
line.Printf(" {\"name\": \"%s\", \"id\": %u, \"type\": \"%s\"",
|
|
||||||
|
uint8 dims = 0;
|
||||||
|
uint32 elems = 1;
|
||||||
|
(void)monitoredSignals[i].dataSource->GetSignalNumberOfDimensions(monitoredSignals[i].signalIdx, dims);
|
||||||
|
(void)monitoredSignals[i].dataSource->GetSignalNumberOfElements(monitoredSignals[i].signalIdx, elems);
|
||||||
|
|
||||||
|
line.Printf(" {\"name\": \"%s\", \"id\": %u, \"type\": \"%s\", \"dimensions\": %u, \"elements\": %u",
|
||||||
monitoredSignals[i].path.Buffer(),
|
monitoredSignals[i].path.Buffer(),
|
||||||
monitoredSignals[i].internalID,
|
monitoredSignals[i].internalID,
|
||||||
typeName ? typeName : "Unknown");
|
typeName ? typeName : "Unknown", dims, elems);
|
||||||
EnrichWithConfig(monitoredSignals[i].path.Buffer(), line);
|
EnrichWithConfig(monitoredSignals[i].path.Buffer(), line);
|
||||||
line += "}";
|
line += "}";
|
||||||
s = line.Size();
|
s = line.Size();
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ public:
|
|||||||
virtual bool Initialise(StructuredDataI &data);
|
virtual bool Initialise(StructuredDataI &data);
|
||||||
|
|
||||||
DebugSignalInfo *RegisterSignal(void *memoryAddress, TypeDescriptor type,
|
DebugSignalInfo *RegisterSignal(void *memoryAddress, TypeDescriptor type,
|
||||||
const char8 *name);
|
const char8 *name, uint8 numberOfDimensions = 0,
|
||||||
|
uint32 numberOfElements = 1);
|
||||||
void ProcessSignal(DebugSignalInfo *signalInfo, uint32 size,
|
void ProcessSignal(DebugSignalInfo *signalInfo, uint32 size,
|
||||||
uint64 timestamp);
|
uint64 timestamp);
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
}
|
}
|
||||||
OutputSignals = {
|
OutputSignals = {
|
||||||
Counter = {
|
Counter = {
|
||||||
DataSource = DDB
|
DataSource = SyncDB
|
||||||
Type = uint32
|
Type = uint32
|
||||||
}
|
}
|
||||||
Time = {
|
Time = {
|
||||||
@@ -48,10 +48,38 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
+GAM3 = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
Frequency = 1
|
||||||
|
Samples = 100
|
||||||
|
Type = uint32
|
||||||
|
DataSource = SyncDB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB3
|
||||||
|
NumberOfElements = 100
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+Data = {
|
+Data = {
|
||||||
Class = ReferenceContainer
|
Class = ReferenceContainer
|
||||||
DefaultDataSource = DDB
|
DefaultDataSource = DDB
|
||||||
|
+SyncDB = {
|
||||||
|
Class = RealTimeThreadSynchronisation
|
||||||
|
Timeout = 200
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+Timer = {
|
+Timer = {
|
||||||
Class = LinuxTimer
|
Class = LinuxTimer
|
||||||
Signals = {
|
Signals = {
|
||||||
@@ -94,6 +122,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
+DDB3 = {
|
||||||
|
AllowNoProducer = 1
|
||||||
|
Class = GAMDataSource
|
||||||
|
}
|
||||||
+DAMS = {
|
+DAMS = {
|
||||||
Class = TimingDataSource
|
Class = TimingDataSource
|
||||||
}
|
}
|
||||||
@@ -112,6 +144,10 @@
|
|||||||
Class = RealTimeThread
|
Class = RealTimeThread
|
||||||
Functions = {GAM2}
|
Functions = {GAM2}
|
||||||
}
|
}
|
||||||
|
+Thread3 = {
|
||||||
|
Class = RealTimeThread
|
||||||
|
Functions = {GAM3}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ void TestFullTracePipeline() {
|
|||||||
|
|
||||||
// 2. Register a mock signal
|
// 2. Register a mock signal
|
||||||
uint32 mockValue = 0;
|
uint32 mockValue = 0;
|
||||||
DebugSignalInfo* sig = service.RegisterSignal(&mockValue, UnsignedInteger32Bit, "TraceTest.Signal");
|
DebugSignalInfo* sig = service.RegisterSignal(&mockValue, UnsignedInteger32Bit, "TraceTest.Signal", 0, 1);
|
||||||
assert(sig != NULL_PTR(DebugSignalInfo*));
|
assert(sig != NULL_PTR(DebugSignalInfo*));
|
||||||
printf("Signal registered with ID: %u\n", sig->internalID);
|
printf("Signal registered with ID: %u\n", sig->internalID);
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public:
|
|||||||
|
|
||||||
// 1. Signal logic
|
// 1. Signal logic
|
||||||
uint32 val = 0;
|
uint32 val = 0;
|
||||||
service.RegisterSignal(&val, UnsignedInteger32Bit, "X.Y.Z");
|
service.RegisterSignal(&val, UnsignedInteger32Bit, "X.Y.Z", 0, 1);
|
||||||
assert(service.TraceSignal("Z", true) == 1);
|
assert(service.TraceSignal("Z", true) == 1);
|
||||||
assert(service.ForceSignal("Z", "123") == 1);
|
assert(service.ForceSignal("Z", "123") == 1);
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,14 @@ struct Signal {
|
|||||||
id: u32,
|
id: u32,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
sig_type: String,
|
sig_type: String,
|
||||||
|
#[serde(default)]
|
||||||
|
dimensions: u8,
|
||||||
|
#[serde(default = "default_elements")]
|
||||||
|
elements: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_elements() -> u32 { 1 }
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct DiscoverResponse {
|
struct DiscoverResponse {
|
||||||
#[serde(rename = "Signals")]
|
#[serde(rename = "Signals")]
|
||||||
@@ -75,6 +81,8 @@ struct TraceData {
|
|||||||
struct SignalMetadata {
|
struct SignalMetadata {
|
||||||
names: Vec<String>,
|
names: Vec<String>,
|
||||||
sig_type: String,
|
sig_type: String,
|
||||||
|
dimensions: u8,
|
||||||
|
elements: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -443,29 +451,57 @@ impl MarteDebugApp {
|
|||||||
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") {
|
||||||
let traceable = item.is_traceable.unwrap_or(false);
|
let elements = item.elements.unwrap_or(1);
|
||||||
let forcable = item.is_forcable.unwrap_or(false);
|
if elements > 1 {
|
||||||
|
let header = egui::CollapsingHeader::new(format!("{} [{}] ({} elems)", label, item.class, elements))
|
||||||
|
.id_salt(¤t_path);
|
||||||
|
header.show(ui, |ui| {
|
||||||
|
for i in 0..elements {
|
||||||
|
let elem_path = format!("{}[{}]", current_path, i);
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label(format!("{}[{}]", item.name, i));
|
||||||
|
if ui.button("Trace").clicked() {
|
||||||
|
let _ = self.tx_cmd.send(format!("TRACE {} 1", current_path));
|
||||||
|
let _ = self.internal_tx.send(InternalEvent::TraceRequested(elem_path.clone(), false));
|
||||||
|
}
|
||||||
|
if item.class == "Signal" {
|
||||||
|
if ui.button("Monitor").clicked() {
|
||||||
|
self.monitoring_dialog = Some(MonitorDialog {
|
||||||
|
signal_path: current_path.clone(),
|
||||||
|
period_ms: "100".to_string(),
|
||||||
|
});
|
||||||
|
// Note: internal monitoring logic will handle individual elements via naming convention
|
||||||
|
let _ = self.internal_tx.send(InternalEvent::TraceRequested(elem_path.clone(), true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let traceable = item.is_traceable.unwrap_or(false);
|
||||||
|
let forcable = item.is_forcable.unwrap_or(false);
|
||||||
|
|
||||||
if traceable && ui.button("Trace").clicked() {
|
if traceable && 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
|
let _ = self
|
||||||
.internal_tx
|
.internal_tx
|
||||||
.send(InternalEvent::TraceRequested(current_path.clone(), false));
|
.send(InternalEvent::TraceRequested(current_path.clone(), false));
|
||||||
}
|
}
|
||||||
if item.class == "Signal" {
|
if item.class == "Signal" {
|
||||||
if ui.button("Monitor").clicked() {
|
if ui.button("Monitor").clicked() {
|
||||||
self.monitoring_dialog = Some(MonitorDialog {
|
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(),
|
signal_path: current_path.clone(),
|
||||||
period_ms: "100".to_string(),
|
value: "".to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if forcable && ui.button("⚡ Force").clicked() {
|
|
||||||
self.forcing_dialog = Some(ForcingDialog {
|
|
||||||
signal_path: current_path.clone(),
|
|
||||||
value: "".to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -841,50 +877,64 @@ fn udp_worker(
|
|||||||
if let Some(meta) = metas.get(&id) {
|
if let Some(meta) = metas.get(&id) {
|
||||||
let _ = tx_events.send(InternalEvent::TelemMatched(id));
|
let _ = tx_events.send(InternalEvent::TelemMatched(id));
|
||||||
let t = meta.sig_type.as_str();
|
let t = meta.sig_type.as_str();
|
||||||
let val = match size {
|
let type_size = if meta.elements > 0 { size / meta.elements } else { size };
|
||||||
1 => {
|
|
||||||
if t.contains('u') {
|
for i in 0..meta.elements {
|
||||||
data_slice[0] as f64
|
let elem_offset = (i * type_size) as usize;
|
||||||
} else {
|
if elem_offset + type_size as usize > data_slice.len() { break; }
|
||||||
(data_slice[0] as i8) as f64
|
let elem_data = &data_slice[elem_offset..elem_offset + type_size as usize];
|
||||||
|
|
||||||
|
let val = match type_size {
|
||||||
|
1 => {
|
||||||
|
if t.contains('u') {
|
||||||
|
elem_data[0] as f64
|
||||||
|
} else {
|
||||||
|
(elem_data[0] as i8) as f64
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
2 => {
|
||||||
2 => {
|
let b = elem_data[0..2].try_into().unwrap();
|
||||||
let b = data_slice[0..2].try_into().unwrap();
|
if t.contains('u') {
|
||||||
if t.contains('u') {
|
u16::from_le_bytes(b) as f64
|
||||||
u16::from_le_bytes(b) as f64
|
} else {
|
||||||
} else {
|
i16::from_le_bytes(b) as f64
|
||||||
i16::from_le_bytes(b) as f64
|
}
|
||||||
}
|
}
|
||||||
}
|
4 => {
|
||||||
4 => {
|
let b = elem_data[0..4].try_into().unwrap();
|
||||||
let b = data_slice[0..4].try_into().unwrap();
|
if t.contains("float") {
|
||||||
if t.contains("float") {
|
f32::from_le_bytes(b) as f64
|
||||||
f32::from_le_bytes(b) as f64
|
} else if t.contains('u') {
|
||||||
} else if t.contains('u') {
|
u32::from_le_bytes(b) as f64
|
||||||
u32::from_le_bytes(b) as f64
|
} else {
|
||||||
} else {
|
i32::from_le_bytes(b) as f64
|
||||||
i32::from_le_bytes(b) as f64
|
}
|
||||||
}
|
}
|
||||||
}
|
8 => {
|
||||||
8 => {
|
let b = elem_data[0..8].try_into().unwrap();
|
||||||
let b = data_slice[0..8].try_into().unwrap();
|
if t.contains("float") {
|
||||||
if t.contains("float") {
|
f64::from_le_bytes(b)
|
||||||
f64::from_le_bytes(b)
|
} else if t.contains('u') {
|
||||||
} else if t.contains('u') {
|
u64::from_le_bytes(b) as f64
|
||||||
u64::from_le_bytes(b) as f64
|
} else {
|
||||||
} else {
|
i64::from_le_bytes(b) as f64
|
||||||
i64::from_le_bytes(b) as f64
|
}
|
||||||
}
|
}
|
||||||
|
_ => 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
for name in &meta.names {
|
||||||
|
let target_name = if meta.elements > 1 {
|
||||||
|
format!("{}[{}]", name, i)
|
||||||
|
} else {
|
||||||
|
name.clone()
|
||||||
|
};
|
||||||
|
local_updates
|
||||||
|
.entry(target_name.clone())
|
||||||
|
.or_default()
|
||||||
|
.push([ts_s, val]);
|
||||||
|
last_values.insert(target_name, val);
|
||||||
}
|
}
|
||||||
_ => 0.0,
|
|
||||||
};
|
|
||||||
for name in &meta.names {
|
|
||||||
local_updates
|
|
||||||
.entry(name.clone())
|
|
||||||
.or_default()
|
|
||||||
.push([ts_s, val]);
|
|
||||||
last_values.insert(name.clone(), val);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset += size as usize;
|
offset += size as usize;
|
||||||
@@ -933,6 +983,8 @@ impl eframe::App for MarteDebugApp {
|
|||||||
let meta = metas.entry(s.id).or_insert_with(|| SignalMetadata {
|
let meta = metas.entry(s.id).or_insert_with(|| SignalMetadata {
|
||||||
names: Vec::new(),
|
names: Vec::new(),
|
||||||
sig_type: s.sig_type.clone(),
|
sig_type: s.sig_type.clone(),
|
||||||
|
dimensions: s.dimensions,
|
||||||
|
elements: s.elements,
|
||||||
});
|
});
|
||||||
if !meta.names.contains(&s.name) {
|
if !meta.names.contains(&s.name) {
|
||||||
meta.names.push(s.name.clone());
|
meta.names.push(s.name.clone());
|
||||||
@@ -1108,9 +1160,36 @@ impl eframe::App for MarteDebugApp {
|
|||||||
.tx_cmd
|
.tx_cmd
|
||||||
.send(format!("MONITOR SIGNAL {} {}", dialog.signal_path, period));
|
.send(format!("MONITOR SIGNAL {} {}", dialog.signal_path, period));
|
||||||
let _ = self.tx_cmd.send("DISCOVER".to_string());
|
let _ = self.tx_cmd.send("DISCOVER".to_string());
|
||||||
let _ = self
|
|
||||||
.internal_tx
|
// Check if it's an array signal to add all elements to view
|
||||||
.send(InternalEvent::TraceRequested(dialog.signal_path.clone(), true));
|
let mut elements = 1;
|
||||||
|
if let Some(tree) = &self.app_tree {
|
||||||
|
// Helper to find item in tree
|
||||||
|
fn find_item<'a>(item: &'a TreeItem, target: &str, current: &str) -> Option<&'a TreeItem> {
|
||||||
|
let path = if current.is_empty() { item.name.clone() } else { format!("{}.{}", current, item.name) };
|
||||||
|
if path == target || (current.is_empty() && item.name == "Root" && target.is_empty()) { return Some(item); }
|
||||||
|
if let Some(children) = &item.children {
|
||||||
|
for child in children {
|
||||||
|
if let Some(found) = find_item(child, target, &path) { return Some(found); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
if let Some(found) = find_item(tree, &dialog.signal_path, "") {
|
||||||
|
elements = found.elements.unwrap_or(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if elements > 1 {
|
||||||
|
for i in 0..elements {
|
||||||
|
let elem_path = format!("{}[{}]", dialog.signal_path, i);
|
||||||
|
let _ = self.internal_tx.send(InternalEvent::TraceRequested(elem_path, true));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let _ = self
|
||||||
|
.internal_tx
|
||||||
|
.send(InternalEvent::TraceRequested(dialog.signal_path.clone(), true));
|
||||||
|
}
|
||||||
close = true;
|
close = true;
|
||||||
}
|
}
|
||||||
if ui.button("Cancel").clicked() {
|
if ui.button("Cancel").clicked() {
|
||||||
|
|||||||
Reference in New Issue
Block a user