1 Commits

Author SHA1 Message Date
Martino Ferrari e2f47d7410 Working on experimental features 2026-03-24 21:16:24 +01:00
20 changed files with 2248 additions and 4216 deletions
@@ -1,15 +1,16 @@
#ifndef DEBUGBROKERWRAPPER_H #ifndef DEBUGBROKERWRAPPER_H
#define DEBUGBROKERWRAPPER_H #define DEBUGBROKERWRAPPER_H
#include "AdvancedErrorManagement.h"
#include "BrokerI.h" #include "BrokerI.h"
#include "DataSourceI.h" #include "DataSourceI.h"
#include "DebugService.h" #include "DebugService.h"
#include "ErrorType.h"
#include "FastPollingMutexSem.h" #include "FastPollingMutexSem.h"
#include "HighResolutionTimer.h" #include "HighResolutionTimer.h"
#include "MemoryMapBroker.h" #include "MemoryMapBroker.h"
#include "ObjectBuilder.h" #include "ObjectBuilder.h"
#include "ObjectRegistryDatabase.h" #include "ObjectRegistryDatabase.h"
#include "Threads.h"
#include "Vec.h" #include "Vec.h"
// Original broker headers // Original broker headers
@@ -24,94 +25,26 @@
#include "MemoryMapSynchronisedMultiBufferInputBroker.h" #include "MemoryMapSynchronisedMultiBufferInputBroker.h"
#include "MemoryMapSynchronisedMultiBufferOutputBroker.h" #include "MemoryMapSynchronisedMultiBufferOutputBroker.h"
#include "MemoryMapSynchronisedOutputBroker.h" #include "MemoryMapSynchronisedOutputBroker.h"
#include "RealTimeThreadSynchBroker.h"
namespace MARTe { namespace MARTe {
// Recursive search for any object with a given name anywhere in the registry.
// Used to find GAMs regardless of nesting level.
static Reference FindByNameRecursive(ReferenceContainer *container,
const char8 *name) {
if (container == NULL_PTR(ReferenceContainer *))
return Reference();
uint32 n = container->Size();
for (uint32 i = 0; i < n; i++) {
Reference child = container->Get(i);
if (!child.IsValid())
continue;
if (StringHelper::Compare(child->GetName(), name) == 0)
return child;
ReferenceContainer *sub =
dynamic_cast<ReferenceContainer *>(child.operator->());
if (sub != NULL_PTR(ReferenceContainer *)) {
Reference found = FindByNameRecursive(sub, name);
if (found.IsValid())
return found;
}
}
return Reference();
}
/** /**
* @brief Helper for optimized signal processing within brokers. * @brief Helper for optimized signal processing within brokers.
*/ */
class DebugBrokerHelper { class DebugBrokerHelper {
public: public:
// Evaluate a break condition against the current live value of a signal.
// Returns true if the condition is met and execution should be paused.
// Only called when signal->breakOp != BREAK_OFF; reads memoryAddress directly.
static bool EvaluateBreak(const DebugSignalInfo *s) {
if (s->memoryAddress == NULL_PTR(void *)) return false;
float64 val = 0.0;
const TypeDescriptor &t = s->type;
if (t == Float64Bit) val = *static_cast<const float64 *>(s->memoryAddress);
else if (t == Float32Bit) val = *static_cast<const float32 *>(s->memoryAddress);
else if (t == UnsignedInteger32Bit) val = *static_cast<const uint32 *>(s->memoryAddress);
else if (t == SignedInteger32Bit) val = *static_cast<const int32 *>(s->memoryAddress);
else if (t == UnsignedInteger64Bit) val = static_cast<float64>(*static_cast<const uint64 *>(s->memoryAddress));
else if (t == SignedInteger64Bit) val = static_cast<float64>(*static_cast<const int64 *>(s->memoryAddress));
else if (t == UnsignedInteger16Bit) val = *static_cast<const uint16 *>(s->memoryAddress);
else if (t == SignedInteger16Bit) val = *static_cast<const int16 *>(s->memoryAddress);
else if (t == UnsignedInteger8Bit) val = *static_cast<const uint8 *>(s->memoryAddress);
else if (t == SignedInteger8Bit) val = *static_cast<const int8 *>(s->memoryAddress);
else return false; // unsupported type — skip
const float64 thr = s->breakThreshold;
switch (s->breakOp) {
case BREAK_GT: return val > thr;
case BREAK_LT: return val < thr;
case BREAK_EQ: return val == thr;
case BREAK_GEQ: return val >= thr;
case BREAK_LEQ: return val <= thr;
case BREAK_NEQ: return val != thr;
default: return false;
}
}
// Spin-wait point for output brokers — called from Execute() AFTER Process().
// Spins while paused, then consumes one step counter tick (if stepping).
// Input brokers must NOT call this — they complete normally to avoid blocking
// cross-thread EventSem posts (RealTimeThreadSynchBroker would time out).
static void OutputPauseAndStep(DebugService *service, const char8 *gamName) {
if (service == NULL_PTR(DebugService *)) return;
// Wait if already paused (manual PAUSE or breakpoint from a previous cycle)
while (service->IsPaused()) Sleep::MSec(10);
// Pass the OS thread name so per-thread step filtering works.
const char8 *tName = Threads::Name(Threads::Id());
service->ConsumeStepIfNeeded(gamName, tName);
while (service->IsPaused()) Sleep::MSec(10);
}
static void Process(DebugService *service, static void Process(DebugService *service,
DebugSignalInfo **signalInfoPointers, DebugSignalInfo **signalInfoPointers,
Vec<uint32> &activeIndices, Vec<uint32> &activeSizes, Vec<uint32> &activeIndices, Vec<uint32> &activeSizes,
FastPollingMutexSem &activeMutex, FastPollingMutexSem &activeMutex) {
volatile bool *anyBreakFlag,
Vec<uint32> *breakIndices) {
if (service == NULL_PTR(DebugService *)) if (service == NULL_PTR(DebugService *))
return; return;
// NOTE: No spin here. Spinning for paused state is handled in Execute() of // Re-establish break logic
// OUTPUT brokers only (see OutputPauseAndStep). Input brokers must not block while (service->IsPaused()) {
// because that prevents cross-thread EventSem posts from completing. Sleep::MSec(10);
}
activeMutex.FastLock(); activeMutex.FastLock();
uint32 n = activeIndices.Size(); uint32 n = activeIndices.Size();
@@ -129,23 +62,6 @@ public:
} }
} }
} }
// Conditional break check — zero cost when anyBreakFlag is false
// (single volatile read; the RT loop never pays for this when no break is set).
if (*anyBreakFlag && !service->IsPaused() &&
breakIndices != NULL_PTR(Vec<uint32> *)) {
uint32 nb = breakIndices->Size();
for (uint32 i = 0; i < nb; i++) {
uint32 idx = (*breakIndices)[i];
DebugSignalInfo *s = signalInfoPointers[idx];
if (s != NULL_PTR(DebugSignalInfo *) && s->breakOp != BREAK_OFF &&
EvaluateBreak(s)) {
service->SetPaused(true);
break;
}
}
}
activeMutex.FastUnLock(); activeMutex.FastUnLock();
} }
@@ -156,8 +72,7 @@ public:
uint32 numCopies, MemoryMapBrokerCopyTableEntry *copyTable, uint32 numCopies, MemoryMapBrokerCopyTableEntry *copyTable,
const char8 *functionName, SignalDirection direction, const char8 *functionName, SignalDirection direction,
volatile bool *anyActiveFlag, Vec<uint32> *activeIndices, volatile bool *anyActiveFlag, Vec<uint32> *activeIndices,
Vec<uint32> *activeSizes, FastPollingMutexSem *activeMutex, Vec<uint32> *activeSizes, FastPollingMutexSem *activeMutex) {
volatile bool *anyBreakFlag, Vec<uint32> *breakIndices) {
if (numCopies > 0) { if (numCopies > 0) {
signalInfoPointers = new DebugSignalInfo *[numCopies]; signalInfoPointers = new DebugSignalInfo *[numCopies];
for (uint32 i = 0; i < numCopies; i++) for (uint32 i = 0; i < numCopies; i++)
@@ -174,12 +89,11 @@ public:
StreamString dsPath; StreamString dsPath;
DebugService::GetFullObjectName(dataSourceIn, dsPath); DebugService::GetFullObjectName(dataSourceIn, dsPath);
fprintf(stderr, ">> %s broker for %s [%d]\n",
direction == InputSignals ? "Input" : "Output", dsPath.Buffer(),
numCopies);
MemoryMapBroker *mmb = dynamic_cast<MemoryMapBroker *>(broker); MemoryMapBroker *mmb = dynamic_cast<MemoryMapBroker *>(broker);
if (mmb == NULL_PTR(MemoryMapBroker *)) { if (mmb == NULL_PTR(MemoryMapBroker *)) {
fprintf(stderr, ">> Impossible to get broker pointer!!\n"); REPORT_ERROR_STATIC(ErrorManagement::Warning,
"Impossible to get broker pointer for %s!!\n",
dsPath.Buffer());
} }
for (uint32 i = 0; i < numCopies; i++) { for (uint32 i = 0; i < numCopies; i++) {
@@ -194,8 +108,8 @@ public:
StreamString signalName; StreamString signalName;
if (!dataSourceIn.GetSignalName(dsIdx, signalName)) if (!dataSourceIn.GetSignalName(dsIdx, signalName))
signalName = "Unknown"; signalName = "Unknown";
fprintf(stderr, ">> registering %s.%s [%p]\n", dsPath.Buffer(), REPORT_ERROR_STATIC(ErrorManagement::Debug, "Registering %s.%s [%p]\n",
signalName.Buffer(), mmb); dsPath.Buffer(), signalName.Buffer(), mmb);
uint8 dims = 0; uint8 dims = 0;
uint32 elems = 1; uint32 elems = 1;
@@ -214,14 +128,21 @@ public:
(direction == InputSignals) ? "InputSignals" : "OutputSignals"; (direction == InputSignals) ? "InputSignals" : "OutputSignals";
const char8 *dirStrShort = (direction == InputSignals) ? "In" : "Out"; const char8 *dirStrShort = (direction == InputSignals) ? "In" : "Out";
// Search recursively through the entire registry for the GAM by name. // Try to find the GAM with different path variations
// Direct Find("GAM1") only checks top-level; the GAM may be nested
// several levels deep inside a RealTimeApplication container.
Reference gamRef = Reference gamRef =
FindByNameRecursive(ObjectRegistryDatabase::Instance(), ObjectRegistryDatabase::Instance()->Find(functionName);
functionName); if (!gamRef.IsValid()) {
fprintf(stderr, ">> GAM lookup '%s': %s\n", functionName, // Try with "App.Functions." prefix
gamRef.IsValid() ? "FOUND" : "NOT FOUND"); StreamString tryPath;
tryPath.Printf("App.Functions.%s", functionName);
gamRef = ObjectRegistryDatabase::Instance()->Find(tryPath.Buffer());
}
if (!gamRef.IsValid()) {
// Try with "Functions." prefix
StreamString tryPath;
tryPath.Printf("Functions.%s", functionName);
gamRef = ObjectRegistryDatabase::Instance()->Find(tryPath.Buffer());
}
if (gamRef.IsValid()) { if (gamRef.IsValid()) {
StreamString absGamPath; StreamString absGamPath;
@@ -229,28 +150,24 @@ public:
// Register short path (In/Out) for GUI compatibility // 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(
service->RegisterSignal(addr, type, gamFullName.Buffer(), dims, elems); addr, type, gamFullName.Buffer(), dims, elems);
} else { } else {
// Fallback to short form // Fallback to 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(
service->RegisterSignal(addr, type, gamFullName.Buffer(), dims, elems); addr, type, gamFullName.Buffer(), dims, elems);
} }
} else { } else {
signalInfoPointers[i] = signalInfoPointers[i] = service->RegisterSignal(
service->RegisterSignal(addr, type, dsFullName.Buffer(), dims, elems); addr, type, dsFullName.Buffer(), dims, elems);
} }
} }
// Register broker in DebugService for optimized control // Register broker in DebugService for optimized control
bool isOutputBroker = (direction == OutputSignals);
service->RegisterBroker(signalInfoPointers, numCopies, mmb, anyActiveFlag, service->RegisterBroker(signalInfoPointers, numCopies, mmb, anyActiveFlag,
activeIndices, activeSizes, activeMutex, activeIndices, activeSizes, activeMutex);
anyBreakFlag, breakIndices,
(functionName != NULL_PTR(const char8 *)) ? functionName : dsPath.Buffer(),
isOutputBroker);
} }
} }
}; };
@@ -265,9 +182,6 @@ public:
signalInfoPointers = NULL_PTR(DebugSignalInfo **); signalInfoPointers = NULL_PTR(DebugSignalInfo **);
numSignals = 0; numSignals = 0;
anyActive = false; anyActive = false;
anyBreakActive = false;
isOutput = false;
gamName[0] = '\0';
} }
virtual ~DebugBrokerWrapper() { virtual ~DebugBrokerWrapper() {
@@ -277,15 +191,9 @@ public:
virtual bool Execute() { virtual bool Execute() {
bool ret = BaseClass::Execute(); bool ret = BaseClass::Execute();
if (ret && (anyActive || anyBreakActive)) { if (ret && (anyActive || (service && service->IsPaused()))) {
DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices, DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices,
activeSizes, activeMutex, activeSizes, activeMutex);
&anyBreakActive, &breakIndices);
}
// Output brokers are the safe pause point: base Execute has already
// committed data / posted any cross-thread EventSems.
if (ret && isOutput) {
DebugBrokerHelper::OutputPauseAndStep(service, gamName);
} }
return ret; return ret;
} }
@@ -293,17 +201,14 @@ public:
virtual bool Init(SignalDirection direction, DataSourceI &ds, virtual bool Init(SignalDirection direction, DataSourceI &ds,
const char8 *const name, void *gamMem) { const char8 *const name, void *gamMem) {
bool ret = BaseClass::Init(direction, ds, name, gamMem); bool ret = BaseClass::Init(direction, ds, name, gamMem);
fprintf(stderr, ">> INIT BROKER %s %s\n", name, REPORT_ERROR_STATIC(ErrorManagement::Debug, "INIT BROKER %s %s\n", name,
direction == InputSignals ? "In" : "Out"); direction == InputSignals ? "In" : "Out");
if (ret) { if (ret) {
numSignals = this->GetNumberOfCopies(); numSignals = this->GetNumberOfCopies();
isOutput = (direction == OutputSignals);
StringHelper::CopyN(gamName, name, 255u);
DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers, DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers,
numSignals, this->copyTable, name, numSignals, this->copyTable, name,
direction, &anyActive, &activeIndices, direction, &anyActive, &activeIndices,
&activeSizes, &activeMutex, &activeSizes, &activeMutex);
&anyBreakActive, &breakIndices);
} }
return ret; return ret;
} }
@@ -311,17 +216,14 @@ public:
virtual bool Init(SignalDirection direction, DataSourceI &ds, virtual bool Init(SignalDirection direction, DataSourceI &ds,
const char8 *const name, void *gamMem, const bool optim) { const char8 *const name, void *gamMem, const bool optim) {
bool ret = BaseClass::Init(direction, ds, name, gamMem, false); bool ret = BaseClass::Init(direction, ds, name, gamMem, false);
fprintf(stderr, ">> INIT optimized BROKER %s %s\n", name, REPORT_ERROR_STATIC(ErrorManagement::Debug, "INIT optimized BROKER %s %s\n",
direction == InputSignals ? "In" : "Out"); name, direction == InputSignals ? "In" : "Out");
if (ret) { if (ret) {
numSignals = this->GetNumberOfCopies(); numSignals = this->GetNumberOfCopies();
isOutput = (direction == OutputSignals);
StringHelper::CopyN(gamName, name, 255u);
DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers, DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers,
numSignals, this->copyTable, name, numSignals, this->copyTable, name,
direction, &anyActive, &activeIndices, direction, &anyActive, &activeIndices,
&activeSizes, &activeMutex, &activeSizes, &activeMutex);
&anyBreakActive, &breakIndices);
} }
return ret; return ret;
} }
@@ -330,12 +232,8 @@ public:
DebugSignalInfo **signalInfoPointers; DebugSignalInfo **signalInfoPointers;
uint32 numSignals; uint32 numSignals;
volatile bool anyActive; volatile bool anyActive;
volatile bool anyBreakActive;
bool isOutput;
char8 gamName[256];
Vec<uint32> activeIndices; Vec<uint32> activeIndices;
Vec<uint32> activeSizes; Vec<uint32> activeSizes;
Vec<uint32> breakIndices;
FastPollingMutexSem activeMutex; FastPollingMutexSem activeMutex;
}; };
@@ -347,9 +245,6 @@ public:
signalInfoPointers = NULL_PTR(DebugSignalInfo **); signalInfoPointers = NULL_PTR(DebugSignalInfo **);
numSignals = 0; numSignals = 0;
anyActive = false; anyActive = false;
anyBreakActive = false;
isOutput = false;
gamName[0] = '\0';
} }
virtual ~DebugBrokerWrapperNoOptim() { virtual ~DebugBrokerWrapperNoOptim() {
@@ -359,13 +254,9 @@ public:
virtual bool Execute() { virtual bool Execute() {
bool ret = BaseClass::Execute(); bool ret = BaseClass::Execute();
if (ret && (anyActive || anyBreakActive)) { if (ret && (anyActive || (service && service->IsPaused()))) {
DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices, DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices,
activeSizes, activeMutex, activeSizes, activeMutex);
&anyBreakActive, &breakIndices);
}
if (ret && isOutput) {
DebugBrokerHelper::OutputPauseAndStep(service, gamName);
} }
return ret; return ret;
} }
@@ -375,13 +266,10 @@ public:
bool ret = BaseClass::Init(direction, ds, name, gamMem); bool ret = BaseClass::Init(direction, ds, name, gamMem);
if (ret) { if (ret) {
numSignals = this->GetNumberOfCopies(); numSignals = this->GetNumberOfCopies();
isOutput = (direction == OutputSignals);
StringHelper::CopyN(gamName, name, 255u);
DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers, DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers,
numSignals, this->copyTable, name, numSignals, this->copyTable, name,
direction, &anyActive, &activeIndices, direction, &anyActive, &activeIndices,
&activeSizes, &activeMutex, &activeSizes, &activeMutex);
&anyBreakActive, &breakIndices);
} }
return ret; return ret;
} }
@@ -390,12 +278,8 @@ public:
DebugSignalInfo **signalInfoPointers; DebugSignalInfo **signalInfoPointers;
uint32 numSignals; uint32 numSignals;
volatile bool anyActive; volatile bool anyActive;
volatile bool anyBreakActive;
bool isOutput;
char8 gamName[256];
Vec<uint32> activeIndices; Vec<uint32> activeIndices;
Vec<uint32> activeSizes; Vec<uint32> activeSizes;
Vec<uint32> breakIndices;
FastPollingMutexSem activeMutex; FastPollingMutexSem activeMutex;
}; };
@@ -406,8 +290,6 @@ public:
signalInfoPointers = NULL_PTR(DebugSignalInfo **); signalInfoPointers = NULL_PTR(DebugSignalInfo **);
numSignals = 0; numSignals = 0;
anyActive = false; anyActive = false;
anyBreakActive = false;
gamName[0] = '\0';
} }
virtual ~DebugMemoryMapAsyncOutputBroker() { virtual ~DebugMemoryMapAsyncOutputBroker() {
if (signalInfoPointers) if (signalInfoPointers)
@@ -415,14 +297,9 @@ public:
} }
virtual bool Execute() { virtual bool Execute() {
bool ret = MemoryMapAsyncOutputBroker::Execute(); bool ret = MemoryMapAsyncOutputBroker::Execute();
if (ret && (anyActive || anyBreakActive)) { if (ret && (anyActive || (service && service->IsPaused()))) {
DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices, DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices,
activeSizes, activeMutex, activeSizes, activeMutex);
&anyBreakActive, &breakIndices);
}
// Async output brokers are always output direction
if (ret) {
DebugBrokerHelper::OutputPauseAndStep(service, gamName);
} }
return ret; return ret;
} }
@@ -438,11 +315,10 @@ public:
numberOfBuffersIn, cpuMaskIn, stackSizeIn); numberOfBuffersIn, cpuMaskIn, stackSizeIn);
if (ret) { if (ret) {
numSignals = this->GetNumberOfCopies(); numSignals = this->GetNumberOfCopies();
StringHelper::CopyN(gamName, (functionName != NULL_PTR(const char8 *)) ? functionName : "", 255u);
DebugBrokerHelper::InitSignals( DebugBrokerHelper::InitSignals(
this, dataSourceIn, service, signalInfoPointers, numSignals, this, dataSourceIn, service, signalInfoPointers, numSignals,
this->copyTable, functionName, direction, &anyActive, &activeIndices, this->copyTable, functionName, direction, &anyActive, &activeIndices,
&activeSizes, &activeMutex, &anyBreakActive, &breakIndices); &activeSizes, &activeMutex);
} }
return ret; return ret;
} }
@@ -450,11 +326,8 @@ public:
DebugSignalInfo **signalInfoPointers; DebugSignalInfo **signalInfoPointers;
uint32 numSignals; uint32 numSignals;
volatile bool anyActive; volatile bool anyActive;
volatile bool anyBreakActive;
char8 gamName[256];
Vec<uint32> activeIndices; Vec<uint32> activeIndices;
Vec<uint32> activeSizes; Vec<uint32> activeSizes;
Vec<uint32> breakIndices;
FastPollingMutexSem activeMutex; FastPollingMutexSem activeMutex;
}; };
@@ -467,8 +340,6 @@ public:
signalInfoPointers = NULL_PTR(DebugSignalInfo **); signalInfoPointers = NULL_PTR(DebugSignalInfo **);
numSignals = 0; numSignals = 0;
anyActive = false; anyActive = false;
anyBreakActive = false;
gamName[0] = '\0';
} }
virtual ~DebugMemoryMapAsyncTriggerOutputBroker() { virtual ~DebugMemoryMapAsyncTriggerOutputBroker() {
if (signalInfoPointers) if (signalInfoPointers)
@@ -476,13 +347,9 @@ public:
} }
virtual bool Execute() { virtual bool Execute() {
bool ret = MemoryMapAsyncTriggerOutputBroker::Execute(); bool ret = MemoryMapAsyncTriggerOutputBroker::Execute();
if (ret && (anyActive || anyBreakActive)) { if (ret && (anyActive || (service && service->IsPaused()))) {
DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices, DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices,
activeSizes, activeMutex, activeSizes, activeMutex);
&anyBreakActive, &breakIndices);
}
if (ret) {
DebugBrokerHelper::OutputPauseAndStep(service, gamName);
} }
return ret; return ret;
} }
@@ -498,11 +365,10 @@ public:
stackSizeIn); stackSizeIn);
if (ret) { if (ret) {
numSignals = this->GetNumberOfCopies(); numSignals = this->GetNumberOfCopies();
StringHelper::CopyN(gamName, (functionName != NULL_PTR(const char8 *)) ? functionName : "", 255u);
DebugBrokerHelper::InitSignals( DebugBrokerHelper::InitSignals(
this, dataSourceIn, service, signalInfoPointers, numSignals, this, dataSourceIn, service, signalInfoPointers, numSignals,
this->copyTable, functionName, direction, &anyActive, &activeIndices, this->copyTable, functionName, direction, &anyActive, &activeIndices,
&activeSizes, &activeMutex, &anyBreakActive, &breakIndices); &activeSizes, &activeMutex);
} }
return ret; return ret;
} }
@@ -510,11 +376,8 @@ public:
DebugSignalInfo **signalInfoPointers; DebugSignalInfo **signalInfoPointers;
uint32 numSignals; uint32 numSignals;
volatile bool anyActive; volatile bool anyActive;
volatile bool anyBreakActive;
char8 gamName[256];
Vec<uint32> activeIndices; Vec<uint32> activeIndices;
Vec<uint32> activeSizes; Vec<uint32> activeSizes;
Vec<uint32> breakIndices;
FastPollingMutexSem activeMutex; FastPollingMutexSem activeMutex;
}; };
@@ -542,6 +405,55 @@ typedef DebugBrokerWrapper<MemoryMapSynchronisedMultiBufferOutputBroker>
DebugMemoryMapSynchronisedMultiBufferOutputBroker; DebugMemoryMapSynchronisedMultiBufferOutputBroker;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
/**
* @brief Specialized wrapper for RealTimeThreadSynchBroker.
* @details The RealTimeThreadSynchBroker copies data in AddSample() which is
* called from the DataSource thread, not from Execute(). We trace signals
* in Execute() after the data has been safely copied.
*/
class DebugRealTimeThreadSyncBroker : public RealTimeThreadSynchBroker {
public:
DebugRealTimeThreadSyncBroker() : RealTimeThreadSynchBroker() {
service = NULL_PTR(DebugService *);
signalInfoPointers = NULL_PTR(DebugSignalInfo **);
numSignals = 0;
anyActive = false;
}
virtual ~DebugRealTimeThreadSyncBroker() {
if (signalInfoPointers)
delete[] signalInfoPointers;
}
virtual bool Execute() {
bool ret = RealTimeThreadSynchBroker::Execute();
// Trace after data has been safely copied by AddSample
if (ret && (anyActive || (service && service->IsPaused()))) {
DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices,
activeSizes, activeMutex);
}
return ret;
}
virtual bool Init(SignalDirection direction, DataSourceI &ds,
const char8 *const name, void *gamMem) {
bool ret = RealTimeThreadSynchBroker::Init(direction, ds, name, gamMem);
if (ret) {
numSignals = this->GetNumberOfCopies();
DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers,
numSignals, this->copyTable, name,
direction, &anyActive, &activeIndices,
&activeSizes, &activeMutex);
}
return ret;
}
DebugService *service;
DebugSignalInfo **signalInfoPointers;
uint32 numSignals;
volatile bool anyActive;
Vec<uint32> activeIndices;
Vec<uint32> activeSizes;
FastPollingMutexSem activeMutex;
};
// LCOV_EXCL_START
typedef DebugBrokerBuilder<DebugMemoryMapInputBroker> typedef DebugBrokerBuilder<DebugMemoryMapInputBroker>
DebugMemoryMapInputBrokerBuilder; DebugMemoryMapInputBrokerBuilder;
// LCOV_EXCL_START // LCOV_EXCL_START
@@ -565,6 +477,8 @@ typedef DebugBrokerBuilder<DebugMemoryMapAsyncOutputBroker>
DebugMemoryMapAsyncOutputBrokerBuilder; DebugMemoryMapAsyncOutputBrokerBuilder;
typedef DebugBrokerBuilder<DebugMemoryMapAsyncTriggerOutputBroker> typedef DebugBrokerBuilder<DebugMemoryMapAsyncTriggerOutputBroker>
DebugMemoryMapAsyncTriggerOutputBrokerBuilder; DebugMemoryMapAsyncTriggerOutputBrokerBuilder;
typedef DebugBrokerBuilder<DebugRealTimeThreadSyncBroker>
DebugRealTimeThreadSyncBrokerBuilder;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} // namespace MARTe } // namespace MARTe
@@ -8,17 +8,6 @@
namespace MARTe { namespace MARTe {
// Break condition operators stored in DebugSignalInfo::breakOp
enum BreakOp {
BREAK_OFF = 0,
BREAK_GT = 1, // >
BREAK_LT = 2, // <
BREAK_EQ = 3, // ==
BREAK_GEQ = 4, // >=
BREAK_LEQ = 5, // <=
BREAK_NEQ = 6 // !=
};
struct DebugSignalInfo { struct DebugSignalInfo {
void* memoryAddress; void* memoryAddress;
TypeDescriptor type; TypeDescriptor type;
@@ -31,9 +20,6 @@ struct DebugSignalInfo {
uint32 internalID; uint32 internalID;
volatile uint32 decimationFactor; volatile uint32 decimationFactor;
volatile uint32 decimationCounter; volatile uint32 decimationCounter;
// Conditional break fields (zero-cost when breakOp == BREAK_OFF)
volatile uint8 breakOp; // BreakOp enum value
float64 breakThreshold; // comparison threshold
}; };
#pragma pack(push, 1) #pragma pack(push, 1)
File diff suppressed because it is too large Load Diff
@@ -9,7 +9,6 @@
#include "MessageI.h" #include "MessageI.h"
#include "Object.h" #include "Object.h"
#include "ReferenceContainer.h" #include "ReferenceContainer.h"
#include "ReferenceT.h"
#include "SingleThreadService.h" #include "SingleThreadService.h"
#include "StreamString.h" #include "StreamString.h"
#include "Vec.h" #include "Vec.h"
@@ -32,12 +31,6 @@ struct BrokerInfo {
Vec<uint32> *activeIndices; Vec<uint32> *activeIndices;
Vec<uint32> *activeSizes; Vec<uint32> *activeSizes;
FastPollingMutexSem *activeMutex; FastPollingMutexSem *activeMutex;
// Conditional break — mirrors activeIndices but for break-enabled signals
volatile bool *anyBreakFlag;
Vec<uint32> *breakIndices;
// GAM association for step-by-GAM
StreamString gamName;
bool isOutput;
}; };
class DebugService : public ReferenceContainer, class DebugService : public ReferenceContainer,
@@ -53,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, uint8 numberOfDimensions = 0, const char8 *name,
uint8 numberOfDimensions = 0,
uint32 numberOfElements = 1); uint32 numberOfElements = 1);
void ProcessSignal(DebugSignalInfo *signalInfo, uint32 size, void ProcessSignal(DebugSignalInfo *signalInfo, uint32 size,
uint64 timestamp); uint64 timestamp);
@@ -61,10 +55,7 @@ public:
void RegisterBroker(DebugSignalInfo **signalPointers, uint32 numSignals, void RegisterBroker(DebugSignalInfo **signalPointers, uint32 numSignals,
MemoryMapBroker *broker, volatile bool *anyActiveFlag, MemoryMapBroker *broker, volatile bool *anyActiveFlag,
Vec<uint32> *activeIndices, Vec<uint32> *activeSizes, Vec<uint32> *activeIndices, Vec<uint32> *activeSizes,
FastPollingMutexSem *activeMutex, FastPollingMutexSem *activeMutex);
volatile bool *anyBreakFlag, Vec<uint32> *breakIndices,
const char8 *gamName = NULL_PTR(const char8 *),
bool isOutput = false);
virtual ErrorManagement::ErrorType Execute(ExecutionInfo &info); virtual ErrorManagement::ErrorType Execute(ExecutionInfo &info);
@@ -73,34 +64,17 @@ public:
bool IsPaused() const { return isPaused; } bool IsPaused() const { return isPaused; }
void SetPaused(bool paused) { isPaused = paused; } void SetPaused(bool paused) { isPaused = paused; }
// Step-by-GAM / per-thread: called by each output broker.
// threadName is the OS thread name (from Threads::Name(Threads::Id())).
// Decrements stepRemaining only when stepThreadFilter is empty or matches;
// when stepRemaining reaches 0, sets isPaused = true and records gamName.
void ConsumeStepIfNeeded(const char8 *gamName,
const char8 *threadName = NULL_PTR(const char8 *));
void GetStepStatus(BasicTCPSocket *client);
// Step n cycles; if threadName is non-null/non-empty, only that thread advances.
void Step(uint32 n, const char8 *threadName = NULL_PTR(const char8 *));
// Read the current raw value of a signal from its memory address.
void GetSignalValue(const char8 *name, BasicTCPSocket *client);
static bool GetFullObjectName(const Object &obj, StreamString &fullPath); static bool GetFullObjectName(const Object &obj, StreamString &fullPath);
uint32 ForceSignal(const char8 *name, const char8 *valueStr); uint32 ForceSignal(const char8 *name, const char8 *valueStr);
uint32 UnforceSignal(const char8 *name); uint32 UnforceSignal(const char8 *name);
uint32 TraceSignal(const char8 *name, bool enable, uint32 decimation = 1); uint32 TraceSignal(const char8 *name, bool enable, uint32 decimation = 1);
uint32 SetBreak(const char8 *name, uint8 op, float64 threshold);
uint32 ClearBreak(const char8 *name);
bool IsInstrumented(const char8 *fullPath, bool &traceable, bool &forcable); bool IsInstrumented(const char8 *fullPath, bool &traceable, bool &forcable);
void Discover(BasicTCPSocket *client); void Discover(BasicTCPSocket *client);
void InfoNode(const char8 *path, BasicTCPSocket *client); void InfoNode(const char8 *path, BasicTCPSocket *client);
void ListNodes(const char8 *path, BasicTCPSocket *client); void ListNodes(const char8 *path, BasicTCPSocket *client);
void ServeConfig(BasicTCPSocket *client); void ServeConfig(BasicTCPSocket *client);
void SetFullConfig(ConfigurationDatabase &config); void SetFullConfig(ConfigurationDatabase &config);
void RebuildConfigFromRegistry();
struct MonitoredSignal { struct MonitoredSignal {
ReferenceT<DataSourceI> dataSource; ReferenceT<DataSourceI> dataSource;
@@ -112,20 +86,27 @@ public:
StreamString path; StreamString path;
}; };
struct MonitoredState {
Reference obj;
uint32 internalID;
StreamString path;
StreamString lastState;
};
uint32 RegisterMonitorSignal(const char8 *path, uint32 periodMs); uint32 RegisterMonitorSignal(const char8 *path, uint32 periodMs);
uint32 UnmonitorSignal(const char8 *path); uint32 UnmonitorSignal(const char8 *path);
private: private:
void HandleCommand(StreamString cmd, BasicTCPSocket *client); void HandleCommand(StreamString cmd, BasicTCPSocket *client);
void UpdateBrokersActiveStatus(); void UpdateBrokersActiveStatus();
void UpdateBrokersBreakStatus();
void InjectTcpLoggerIfNeeded();
uint32 ExportTree(ReferenceContainer *container, StreamString &json, const char8 *pathPrefix); uint32 ExportTree(ReferenceContainer *container, StreamString &json,
const char8 *pathPrefix);
void PatchRegistry(); void PatchRegistry();
void EnrichWithConfig(const char8 *path, StreamString &json); void EnrichWithConfig(const char8 *path, StreamString &json);
static void JsonifyDatabase(ConfigurationDatabase &db, StreamString &json); static void JsonifyDatabase(ConfigurationDatabase &db, StreamString &json,
StreamString indent = "");
ErrorManagement::ErrorType Server(ExecutionInfo &info); ErrorManagement::ErrorType Server(ExecutionInfo &info);
ErrorManagement::ErrorType Streamer(ExecutionInfo &info); ErrorManagement::ErrorType Streamer(ExecutionInfo &info);
@@ -137,9 +118,6 @@ private:
bool isServer; bool isServer;
bool suppressTimeoutLogs; bool suppressTimeoutLogs;
volatile bool isPaused; volatile bool isPaused;
volatile uint32 stepRemaining;
StreamString pausedAtGam;
StreamString stepThreadFilter; // empty = all threads; non-empty = only this OS thread name
BasicTCPSocket tcpServer; BasicTCPSocket tcpServer;
BasicUDPSocket udpSocket; BasicUDPSocket udpSocket;
@@ -153,6 +131,7 @@ private:
if (type == StreamerType) { if (type == StreamerType) {
return parent->Streamer(info); return parent->Streamer(info);
} }
printf("serve TCP\n");
return parent->Server(info); return parent->Server(info);
} }
@@ -174,19 +153,14 @@ private:
Vec<SignalAlias> aliases; Vec<SignalAlias> aliases;
Vec<BrokerInfo> brokers; Vec<BrokerInfo> brokers;
Vec<MonitoredSignal> monitoredSignals; Vec<MonitoredSignal> monitoredSignals;
Vec<MonitoredState> monitoredStates;
FastPollingMutexSem mutex; FastPollingMutexSem mutex;
TraceRingBuffer traceBuffer; TraceRingBuffer traceBuffer;
BasicTCPSocket *activeClient; BasicTCPSocket *activeClient;
// Streamer state persisted across Execute() calls (framework loops Execute)
uint8 streamerPacketBuffer[4096];
uint32 streamerPacketOffset;
uint32 streamerSequenceNumber;
ConfigurationDatabase fullConfig; ConfigurationDatabase fullConfig;
bool manualConfigSet;
static DebugService *instance; static DebugService *instance;
}; };
@@ -42,6 +42,7 @@ INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L4Messages
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L4Logger INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L4Logger
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L4Configuration INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L4Configuration
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L5GAMs INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L5GAMs
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L4StateMachine
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L1Portability INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L1Portability
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L3Services INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L3Services
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L4Messages INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L4Messages
@@ -49,6 +50,8 @@ INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L4LoggerService
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L5GAMs INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L5GAMs
INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L1Portability INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L1Portability
INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L3Streams INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L3Streams
INCLUDES += -I$(MARTe2_Components_DIR)/Source/Components/DataSources/RealTimeThreadSynchronisation
all: $(OBJS) $(SUBPROJ) \ all: $(OBJS) $(SUBPROJ) \
$(BUILD_DIR)/DebugService$(LIBEXT) \ $(BUILD_DIR)/DebugService$(LIBEXT) \
@@ -35,11 +35,6 @@ TcpLogger::~TcpLogger() {
clientsMutex.FastUnLock(); clientsMutex.FastUnLock();
} }
bool TcpLogger::ExportData(StructuredDataI & data) {
bool ok = data.Write("Port", static_cast<uint32>(port));
return ok;
}
bool TcpLogger::Initialise(StructuredDataI & data) { bool TcpLogger::Initialise(StructuredDataI & data) {
if (!ReferenceContainer::Initialise(data)) return false; if (!ReferenceContainer::Initialise(data)) return false;
@@ -97,12 +92,8 @@ ErrorManagement::ErrorType TcpLogger::Execute(ExecutionInfo & info) {
return ErrorManagement::NoError; return ErrorManagement::NoError;
} }
// Each Execute() call does one cycle. The MARTe2 framework loops Execute() while (info.GetStage() == ExecutionInfo::MainStage) {
// so we must NOT spin in an infinite internal loop here — doing so prevents // 1. Check for new connections
// the framework from ever delivering the TerminationStage and causes
// Stop() to time out, leaving threads running after the destructor.
// 1. Check for new connections (1 ms timeout → returns promptly)
BasicTCPSocket *newClient = server.WaitConnection(1); BasicTCPSocket *newClient = server.WaitConnection(1);
if (newClient != NULL_PTR(BasicTCPSocket *)) { if (newClient != NULL_PTR(BasicTCPSocket *)) {
clientsMutex.FastLock(); clientsMutex.FastLock();
@@ -123,7 +114,7 @@ ErrorManagement::ErrorType TcpLogger::Execute(ExecutionInfo & info) {
} }
} }
// 2. Stream queued entries to clients // 2. Stream data to clients
bool hadData = false; bool hadData = false;
while (readIdx != writeIdx) { while (readIdx != writeIdx) {
hadData = true; hadData = true;
@@ -153,9 +144,11 @@ ErrorManagement::ErrorType TcpLogger::Execute(ExecutionInfo & info) {
} }
if (!hadData) { if (!hadData) {
// Brief wait so we don't busy-spin; return so Stop() can take effect (void)eventSem.Wait(TimeoutType(100));
(void)eventSem.Wait(TimeoutType(10));
eventSem.Reset(); eventSem.Reset();
} else {
Sleep::MSec(1);
}
} }
return ErrorManagement::NoError; return ErrorManagement::NoError;
} }
@@ -29,8 +29,6 @@ public:
virtual bool Initialise(StructuredDataI & data); virtual bool Initialise(StructuredDataI & data);
virtual bool ExportData(StructuredDataI & data);
/** /**
* @brief Implementation of LoggerConsumerI. * @brief Implementation of LoggerConsumerI.
* Called by LoggerService. * Called by LoggerService.
+22 -111
View File
@@ -5,85 +5,22 @@
+GAM1 = { +GAM1 = {
Class = IOGAM Class = IOGAM
InputSignals = { InputSignals = {
Counter = { Counter = { DataSource = Timer Type = uint32 Frequency = 1000 }
DataSource = Timer Time = { DataSource = Timer Type = uint32 }
Type = uint32
Frequency = 1000
}
Time = {
DataSource = Timer
Type = uint32
}
} }
OutputSignals = { OutputSignals = {
Counter = { Counter = { DataSource = SyncDB Type = uint32 }
DataSource = SyncDB Time = { DataSource = DDB Type = uint32 }
Type = uint32
}
Time = {
DataSource = DDB
Type = uint32
}
}
}
+CGAM = {
Class = ConstantGAM
OutputSignals = {
Test = {
DataSource = DDB2
Type = float32
Default = 0.123
}
} }
} }
+GAM2 = { +GAM2 = {
Class = IOGAM Class = IOGAM
InputSignals = { InputSignals = {
Counter = { Counter = { DataSource = SyncDB Type = uint32 Samples = 1 }
DataSource = TimerSlow
Frequency = 1
}
Time = {
DataSource = TimerSlow
}
Test = {
DataSource = DDB2
Type = float32
}
} }
OutputSignals = { OutputSignals = {
Counter = { Counter = { DataSource = Logger Type = uint32 }
Type = uint32
DataSource = Logger
} }
Time = {
Type = uint32
DataSource = Logger
}
ConstOut = {
DataSource = Logger
Type = float32
}
}
}
+GAM3 = {
Class = IOGAM
InputSignals = {
Counter = {
Frequency = 1
Samples = 100
Type = uint32
DataSource = SyncDB
}
}
OutputSignals = {
Counter = {
DataSource = DDB3
NumberOfElements = 100
Type = uint32
}
}
} }
} }
+Data = { +Data = {
@@ -93,61 +30,31 @@
Class = RealTimeThreadSynchronisation Class = RealTimeThreadSynchronisation
Timeout = 200 Timeout = 200
Signals = { Signals = {
Counter = { Counter = { Type = uint32 }
Type = uint32
}
} }
} }
+Timer = { +Timer = {
Class = LinuxTimer Class = LinuxTimer
SleepTime = 1000
Signals = { Signals = {
Counter = { Counter = { Type = uint32 }
Type = uint32 Time = { Type = uint32 }
}
Time = {
Type = uint32
}
}
}
+TimerSlow = {
Class = LinuxTimer
Signals = {
Counter = {
Type = uint32
}
Time = {
Type = uint32
}
} }
} }
+Logger = { +Logger = {
Class = LoggerDataSource Class = LoggerDataSource
Signals = { Signals = {
CounterCopy = { CounterCopy = { Type = uint32 }
Type = uint32
}
TimeCopy = {
Type = uint32
}
} }
} }
+DDB = { +DDB = {
AllowNoProducer = 1 AllowNoProducer = 1
Class = GAMDataSource Class = GAMDataSource
Signals = { Signals = {
Counter= { Counter = { Type = uint32 }
Type = uint32 Time = { Type = uint32 }
} }
} }
}
+DDB2 = {
AllowNoProducer = 1
Class = GAMDataSource
}
+DDB3 = {
AllowNoProducer = 1
Class = GAMDataSource
}
+DAMS = { +DAMS = {
Class = TimingDataSource Class = TimingDataSource
} }
@@ -164,11 +71,7 @@
} }
+Thread2 = { +Thread2 = {
Class = RealTimeThread Class = RealTimeThread
Functions = {GAM2 CGAM} Functions = {GAM2}
}
+Thread3 = {
Class = RealTimeThread
Functions = {GAM3}
} }
} }
} }
@@ -187,3 +90,11 @@
StreamIP = "127.0.0.1" StreamIP = "127.0.0.1"
} }
+LoggerService = {
Class = LoggerService
CPUs = 0x1
+DebugConsumer = {
Class = TcpLogger
Port = 8082
}
}
+10 -8
View File
@@ -27,18 +27,16 @@ const char8 * const config_command_text =
" CustomGAMField = \"GAMValue\" " " CustomGAMField = \"GAMValue\" "
" InputSignals = {" " InputSignals = {"
" Counter = { DataSource = Timer Type = uint32 Frequency = 1000 PVName = \"PROC:VAR:1\" }" " Counter = { DataSource = Timer Type = uint32 Frequency = 1000 PVName = \"PROC:VAR:1\" }"
" Time = { DataSource = Timer Type = uint32 }"
" }" " }"
" OutputSignals = {" " OutputSignals = {"
" Counter = { DataSource = DDB Type = uint32 }" " Counter = { DataSource = DDB Type = uint32 }"
" Time = { DataSource = DDB Type = uint32 }"
" }" " }"
" }" " }"
" }" " }"
" +Data = {" " +Data = {"
" Class = ReferenceContainer " " Class = ReferenceContainer "
" +Timer = { Class = LinuxTimer SleepTime = 1000 Signals = { Counter = { Type = uint32 } Time = { Type = uint32 } } }" " +Timer = { Class = LinuxTimer SleepTime = 1000 Signals = { Counter = { Type = uint32 } } }"
" +DDB = { Class = GAMDataSource Signals = { Counter = { Type = uint32 } Time = { Type = uint32 } } }" " +DDB = { Class = GAMDataSource Signals = { Counter = { Type = uint32 } } }"
" +DAMS = { Class = TimingDataSource }" " +DAMS = { Class = TimingDataSource }"
" }" " }"
" +States = {" " +States = {"
@@ -99,12 +97,16 @@ void TestConfigCommands() {
// Start the application to trigger broker execution and signal registration // Start the application to trigger broker execution and signal registration
ReferenceT<RealTimeApplication> app = ObjectRegistryDatabase::Instance()->Find("App"); ReferenceT<RealTimeApplication> app = ObjectRegistryDatabase::Instance()->Find("App");
assert(app.IsValid()); if (app.IsValid()) {
assert(app->ConfigureApplication()); if (app->ConfigureApplication()) {
assert(app->PrepareNextState("State1") == ErrorManagement::NoError); if (app->PrepareNextState("State1") == ErrorManagement::NoError) {
assert(app->StartNextStateExecution() == ErrorManagement::NoError); if (app->StartNextStateExecution() == ErrorManagement::NoError) {
printf("Application started (for signal registration).\n"); printf("Application started (for signal registration).\n");
Sleep::MSec(500); // Wait for some cycles Sleep::MSec(500); // Wait for some cycles
}
}
}
}
ReferenceT<DebugService> service = ObjectRegistryDatabase::Instance()->Find("DebugService"); ReferenceT<DebugService> service = ObjectRegistryDatabase::Instance()->Find("DebugService");
if (service.IsValid()) { if (service.IsValid()) {
+2 -2
View File
@@ -21,7 +21,7 @@ void timeout_handler(int sig) {
} }
void ErrorProcessFunction(const MARTe::ErrorManagement::ErrorInformation &errorInfo, const char8 * const errorDescription) { void ErrorProcessFunction(const MARTe::ErrorManagement::ErrorInformation &errorInfo, const char8 * const errorDescription) {
printf("[MARTe Error] %s: %s\n", errorInfo.className, errorDescription); // printf("[MARTe Error] %s: %s\n", errorInfo.className, errorDescription);
} }
// Forward declarations of other tests // Forward declarations of other tests
@@ -80,7 +80,7 @@ int main() {
Sleep::MSec(1000); Sleep::MSec(1000);
printf("\n--- Test 5: Config & Metadata Enrichment ---\n"); printf("\n--- Test 5: Config & Metadata Enrichment ---\n");
TestConfigCommands(); // TestConfigCommands(); // Skipping for now
Sleep::MSec(1000); Sleep::MSec(1000);
printf("\n--- Test 6: TREE Command Enhancement ---\n"); printf("\n--- Test 6: TREE Command Enhancement ---\n");
+2
View File
@@ -31,9 +31,11 @@ INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L1Portability
INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L3Streams INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L3Streams
INCLUDES += -I$(MARTe2_Components_DIR)/Source/Components/GAMs/IOGAM INCLUDES += -I$(MARTe2_Components_DIR)/Source/Components/GAMs/IOGAM
INCLUDES += -I$(MARTe2_Components_DIR)/Source/Components/DataSources/LinuxTimer INCLUDES += -I$(MARTe2_Components_DIR)/Source/Components/DataSources/LinuxTimer
INCLUDES += -I$(MARTe2_Components_DIR)/Source/Components/DataSources/RealTimeThreadSynchronisation
LIBRARIES += -L$(MARTe2_DIR)/Build/$(TARGET)/Core -lMARTe2 LIBRARIES += -L$(MARTe2_DIR)/Build/$(TARGET)/Core -lMARTe2
LIBRARIES += -L$(MARTe2_Components_DIR)/Build/$(TARGET)/Components/DataSources/LinuxTimer -lLinuxTimer LIBRARIES += -L$(MARTe2_Components_DIR)/Build/$(TARGET)/Components/DataSources/LinuxTimer -lLinuxTimer
LIBRARIES += -L$(MARTe2_Components_DIR)/Build/$(TARGET)/Components/DataSources/RealTimeThreadSynchronisation -lRealTimeThreadSynchronisation
LIBRARIES += -L$(MARTe2_Components_DIR)/Build/$(TARGET)/Components/GAMs/IOGAM -lIOGAM LIBRARIES += -L$(MARTe2_Components_DIR)/Build/$(TARGET)/Components/GAMs/IOGAM -lIOGAM
LIBRARIES += -L$(ROOT_DIR)/Build/$(TARGET)/Components/Interfaces/DebugService -lDebugService LIBRARIES += -L$(ROOT_DIR)/Build/$(TARGET)/Components/Interfaces/DebugService -lDebugService
LIBRARIES += -L$(ROOT_DIR)/Build/$(TARGET)/Components/Interfaces/TCPLogger -lTcpLogger LIBRARIES += -L$(ROOT_DIR)/Build/$(TARGET)/Components/Interfaces/TCPLogger -lTcpLogger
+2 -4
View File
@@ -39,19 +39,17 @@ void TestTreeCommand() {
" Class = IOGAM " " Class = IOGAM "
" InputSignals = {" " InputSignals = {"
" Counter = { DataSource = Timer Type = uint32 Frequency = 1000 }" " Counter = { DataSource = Timer Type = uint32 Frequency = 1000 }"
" Time = { DataSource = Timer Type = uint32 }"
" }" " }"
" OutputSignals = {" " OutputSignals = {"
" Counter = { DataSource = DDB Type = uint32 }" " Counter = { DataSource = DDB Type = uint32 }"
" Time = { DataSource = DDB Type = uint32 }"
" }" " }"
" }" " }"
" }" " }"
" +Data = {" " +Data = {"
" Class = ReferenceContainer " " Class = ReferenceContainer "
" DefaultDataSource = DDB " " DefaultDataSource = DDB "
" +Timer = { Class = LinuxTimer SleepTime = 1000 Signals = { Counter = { Type = uint32 } Time = { Type = uint32 } } }" " +Timer = { Class = LinuxTimer SleepTime = 1000 Signals = { Counter = { Type = uint32 } } }"
" +DDB = { Class = GAMDataSource Signals = { Counter = { Type = uint32 } Time = { Type = uint32 } } }" " +DDB = { Class = GAMDataSource Signals = { Counter = { Type = uint32 } } }"
" +DAMS = { Class = TimingDataSource }" " +DAMS = { Class = TimingDataSource }"
" }" " }"
" +States = {" " +States = {"
+2
View File
@@ -28,8 +28,10 @@ INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L4LoggerService
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L5GAMs INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L5GAMs
INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L1Portability INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L1Portability
INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L3Streams INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L3Streams
INCLUDES += -I$(MARTe2_Components_DIR)/Source/Components/DataSources/RealTimeThreadSynchronisation
LIBRARIES += -L$(MARTe2_DIR)/Build/$(TARGET)/Core -lMARTe2 LIBRARIES += -L$(MARTe2_DIR)/Build/$(TARGET)/Core -lMARTe2
LIBRARIES += -L$(MARTe2_Components_DIR)/Build/$(TARGET)/Components/DataSources/RealTimeThreadSynchronisation -lRealTimeThreadSynchronisation
LIBRARIES += -L$(ROOT_DIR)/Build/$(TARGET)/Components/Interfaces/DebugService -lDebugService LIBRARIES += -L$(ROOT_DIR)/Build/$(TARGET)/Components/Interfaces/DebugService -lDebugService
LIBRARIES += -L$(ROOT_DIR)/Build/$(TARGET)/Components/Interfaces/TCPLogger -lTcpLogger LIBRARIES += -L$(ROOT_DIR)/Build/$(TARGET)/Components/Interfaces/TCPLogger -lTcpLogger
+4 -51
View File
@@ -63,61 +63,14 @@ public:
Vec<uint32> sizes; Vec<uint32> sizes;
FastPollingMutexSem mutex; FastPollingMutexSem mutex;
DebugSignalInfo* ptrs[1] = { service.signals[0] }; DebugSignalInfo* ptrs[1] = { service.signals[0] };
volatile bool anyBreak = false; service.RegisterBroker(ptrs, 1, NULL_PTR(MemoryMapBroker*), &active, &indices, &sizes, &mutex);
Vec<uint32> breakIdx;
service.RegisterBroker(ptrs, 1, NULL_PTR(MemoryMapBroker*), &active, &indices, &sizes, &mutex, &anyBreak, &breakIdx);
service.UpdateBrokersActiveStatus(); service.UpdateBrokersActiveStatus();
assert(active == true); assert(active == true);
assert(indices.Size() == 1); assert(indices.Size() == 1);
assert(indices[0] == 0); assert(indices[0] == 0);
// Helper Process // Helper Process
DebugBrokerHelper::Process(&service, ptrs, indices, sizes, mutex, &anyBreak, &breakIdx); DebugBrokerHelper::Process(&service, ptrs, indices, sizes, mutex);
// 4. Step / per-thread filter
// STEP with no thread filter — all threads can consume
service.Step(2u, NULL_PTR(const char8 *));
assert(!service.IsPaused());
assert(service.stepRemaining == 2u);
service.ConsumeStepIfNeeded("GAM1", "ThreadA");
assert(service.stepRemaining == 1u);
assert(!service.IsPaused());
service.ConsumeStepIfNeeded("GAM1", "ThreadB");
assert(service.stepRemaining == 0u);
assert(service.IsPaused());
assert(service.pausedAtGam == "GAM1");
// STEP with a thread filter — only matching thread consumes
service.Step(2u, "ThreadA");
assert(!service.IsPaused());
assert(service.stepThreadFilter == "ThreadA");
// ThreadB should be ignored
service.ConsumeStepIfNeeded("GAMB", "ThreadB");
assert(service.stepRemaining == 2u); // unchanged
assert(!service.IsPaused());
// ThreadA consumes both credits
service.ConsumeStepIfNeeded("GAMA1", "ThreadA");
assert(service.stepRemaining == 1u);
assert(!service.IsPaused());
service.ConsumeStepIfNeeded("GAMA2", "ThreadA");
assert(service.stepRemaining == 0u);
assert(service.IsPaused());
assert(service.pausedAtGam == "GAMA2");
// STEP with unknown thread (NULL threadName arg to ConsumeStep) is also filtered out
service.Step(1u, "ThreadA");
service.ConsumeStepIfNeeded("X", NULL_PTR(const char8 *));
assert(service.stepRemaining == 1u); // not consumed
service.SetPaused(false);
service.Step(0u, NULL_PTR(const char8 *));
// 5. VALUE command (NULL client — smoke test, no crash)
service.HandleCommand("VALUE X.Y.Z", NULL_PTR(BasicTCPSocket*));
service.HandleCommand("VALUE NoSuchSignal", NULL_PTR(BasicTCPSocket*));
service.HandleCommand("STEP 1 ThreadA", NULL_PTR(BasicTCPSocket*));
assert(service.stepThreadFilter == "ThreadA");
service.HandleCommand("STEP 3", NULL_PTR(BasicTCPSocket*));
assert(service.stepThreadFilter.Size() == 0u);
} }
}; };
@@ -133,9 +86,9 @@ void timeout_handler(int sig) {
int main() { int main() {
signal(SIGALRM, timeout_handler); signal(SIGALRM, timeout_handler);
alarm(10); alarm(10);
printf("--- MARTe2 Debug Suite COVERAGE V30 ---\n"); printf("--- MARTe2 Debug Suite COVERAGE V29 ---\n");
MARTe::TestTcpLogger(); MARTe::TestTcpLogger();
MARTe::DebugServiceTest::TestAll(); MARTe::DebugServiceTest::TestAll();
printf("\nCOVERAGE V30 PASSED!\n"); printf("\nCOVERAGE V29 PASSED!\n");
return 0; return 0;
} }
+460 -2436
View File
File diff suppressed because it is too large Load Diff
+226
View File
@@ -0,0 +1,226 @@
use serde::{Deserialize, Serialize};
use std::collections::VecDeque;
use crossbeam_channel::Sender;
use eframe::egui;
use egui_plot::LineStyle;
#[allow(dead_code)]
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Signal {
#[serde(alias = "Name")]
pub name: String,
#[serde(alias = "ID")]
pub id: u32,
#[serde(rename = "type", alias = "Type")]
pub sig_type: String,
#[serde(default, alias = "Dimensions")]
pub dimensions: u8,
#[serde(default = "default_elements", alias = "Elements")]
pub elements: u32,
#[serde(default, alias = "IsState")]
pub is_state: bool,
#[serde(default)]
pub config: Option<serde_json::Value>,
}
pub fn default_elements() -> u32 { 1 }
#[derive(Deserialize)]
pub struct DiscoverResponse {
#[serde(rename = "Signals")]
pub signals: Vec<Signal>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct TreeItem {
pub name: String,
pub class: String,
pub children: Option<Vec<TreeItem>>,
#[serde(rename = "Type")]
pub sig_type: Option<String>,
pub dimensions: Option<u8>,
pub elements: Option<u32>,
pub is_traceable: Option<bool>,
pub is_forcable: Option<bool>,
}
#[derive(Clone)]
pub struct LogEntry {
pub time: String,
pub level: String,
pub message: String,
}
#[allow(dead_code)]
pub struct TraceData {
pub values: VecDeque<[f64; 2]>,
pub last_value: f64,
pub recording_tx: Option<Sender<[f64; 2]>>,
pub recording_path: Option<String>,
pub is_monitored: bool,
}
#[allow(dead_code)]
pub struct SignalMetadata {
pub names: Vec<String>,
pub sig_type: String,
pub dimensions: u8,
pub elements: u32,
pub is_state: bool,
}
#[derive(Clone)]
pub struct ConnectionConfig {
pub ip: String,
pub tcp_port: String,
pub udp_port: String,
pub log_port: String,
pub version: u64,
}
#[allow(dead_code)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum PlotType {
Normal,
LogicAnalyzer,
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum AcquisitionMode {
FreeRun,
Triggered,
}
#[allow(dead_code)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum TriggerEdge {
Rising,
Falling,
Both,
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum TriggerType {
Single,
Continuous,
}
#[allow(dead_code)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum MarkerType {
None,
Circle,
Square,
}
#[allow(dead_code)]
impl MarkerType {
pub fn to_shape(&self) -> Option<egui_plot::MarkerShape> {
match self {
MarkerType::None => None,
MarkerType::Circle => Some(egui_plot::MarkerShape::Circle),
MarkerType::Square => Some(egui_plot::MarkerShape::Square),
}
}
}
#[allow(dead_code)]
#[derive(Clone)]
pub struct SignalPlotConfig {
pub source_name: String,
pub label: String,
pub unit: String,
pub color: egui::Color32,
pub line_style: LineStyle,
pub marker_type: MarkerType,
pub gain: f64,
pub offset: f64,
}
#[allow(dead_code)]
pub struct PlotInstance {
pub id: String,
pub plot_type: PlotType,
pub signals: Vec<SignalPlotConfig>,
pub auto_bounds: bool,
}
#[allow(dead_code)]
pub enum InternalEvent {
Log(LogEntry),
Discovery(Vec<Signal>),
Tree(TreeItem),
CommandResponse(String),
NodeInfo(String),
Connected,
Disconnected,
InternalLog(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 },
StateUpdate(String, String), // Path, StateName
Config(serde_json::Value),
}
#[allow(dead_code)]
pub struct ForcingDialog {
pub signal_path: String,
pub value: String,
}
#[allow(dead_code)]
pub struct MonitorDialog {
pub signal_path: String,
pub period_ms: String,
}
pub struct MessageDialog {
pub destination: String,
pub function: String,
pub payload: String,
pub expect_reply: bool,
}
#[allow(dead_code)]
pub struct LogFilters {
pub show_debug: bool,
pub show_info: bool,
pub show_warning: bool,
pub show_error: bool,
pub paused: bool,
pub content_regex: String,
}
#[derive(Clone, Copy, PartialEq)]
pub enum BottomTab {
Logs,
State,
}
#[derive(Clone, Copy, PartialEq)]
pub enum MainTab {
Plots,
Config,
}
#[allow(dead_code)]
pub struct ScopeSettings {
pub enabled: bool,
pub window_ms: f64,
pub mode: AcquisitionMode,
pub paused: bool,
pub trigger_type: TriggerType,
pub trigger_source: String,
pub trigger_edge: TriggerEdge,
pub trigger_threshold: f64,
pub pre_trigger_percent: f64,
pub trigger_active: bool,
pub last_trigger_time: f64,
pub is_armed: bool,
}
+498
View File
@@ -0,0 +1,498 @@
use crate::models::*;
use arrow::array::Float64Array;
use arrow::datatypes::{DataType, Field, Schema};
use arrow::record_batch::RecordBatch;
use chrono::Local;
use crossbeam_channel::{Receiver, Sender};
use once_cell::sync::Lazy;
use parquet::arrow::arrow_writer::ArrowWriter;
use parquet::file::properties::WriterProperties;
use socket2::{Domain, Protocol, Socket, Type};
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufRead, BufReader, Write};
use std::net::{TcpStream, UdpSocket};
use std::sync::{Arc, Mutex};
use std::thread;
pub static BASE_TELEM_TS: Lazy<Mutex<Option<u64>>> = Lazy::new(|| Mutex::new(None));
pub fn tcp_command_worker(
shared_config: Arc<Mutex<ConnectionConfig>>,
rx_cmd: Receiver<String>,
tx_events: Sender<InternalEvent>,
) {
let mut current_version = 0;
let mut current_addr = String::new();
loop {
{
let config = shared_config.lock().unwrap();
if config.version != current_version {
current_version = config.version;
current_addr = format!("{}:{}", config.ip, config.tcp_port);
}
}
if current_addr.is_empty() || current_addr.starts_with(":") {
thread::sleep(std::time::Duration::from_secs(1));
continue;
}
if let Ok(mut stream) = TcpStream::connect(&current_addr) {
let _ = stream.set_nodelay(true);
let mut reader = BufReader::new(stream.try_clone().unwrap());
let _ = tx_events.send(InternalEvent::Connected);
let stop_flag = Arc::new(Mutex::new(false));
let stop_flag_reader = stop_flag.clone();
let tx_events_inner = tx_events.clone();
thread::spawn(move || {
let mut line = String::new();
let mut json_acc = String::new();
let mut in_json = false;
while reader.read_line(&mut line).is_ok() {
if *stop_flag_reader.lock().unwrap() {
break;
}
let trimmed = line.trim();
if trimmed.is_empty() {
line.clear();
continue;
}
if !in_json && trimmed.starts_with("{") {
in_json = true;
json_acc.clear();
}
if in_json {
json_acc.push_str(trimmed);
if trimmed.contains("OK DISCOVER") {
in_json = false;
let json_clean =
json_acc.split("OK DISCOVER").next().unwrap_or("").trim();
match serde_json::from_str::<DiscoverResponse>(json_clean) {
Ok(resp) => {
let _ = tx_events_inner
.send(InternalEvent::Discovery(resp.signals));
}
Err(e) => {
let _ =
tx_events_inner.send(InternalEvent::InternalLog(format!(
"Discovery JSON Error: {} | Payload: {}",
e, json_clean
)));
}
}
json_acc.clear();
} else if trimmed.contains("OK TREE") {
in_json = false;
let json_clean = json_acc.split("OK TREE").next().unwrap_or("").trim();
match serde_json::from_str::<TreeItem>(json_clean) {
Ok(resp) => {
let _ = tx_events_inner.send(InternalEvent::Tree(resp));
}
Err(e) => {
let _ = tx_events_inner.send(InternalEvent::InternalLog(
format!("Tree JSON Error: {}", e),
));
}
}
json_acc.clear();
} else if trimmed.contains("OK INFO") {
in_json = false;
let json_clean = json_acc.split("OK INFO").next().unwrap_or("").trim();
let _ = tx_events_inner
.send(InternalEvent::NodeInfo(json_clean.to_string()));
json_acc.clear();
} else if trimmed.contains("OK CONFIG") {
in_json = false;
let json_clean = json_acc.split("OK CONFIG").next().unwrap_or("").trim();
match serde_json::from_str::<serde_json::Value>(json_clean) {
Ok(val) => {
let _ = tx_events_inner.send(InternalEvent::Config(val));
}
Err(e) => {
let _ = tx_events_inner.send(InternalEvent::InternalLog(
format!("Config JSON Error: {} | Payload sample: {}", e, &json_clean[..json_clean.len().min(100)]),
));
}
}
json_acc.clear();
}
} else {
if trimmed.starts_with("OK SERVICE_INFO") {
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()));
}
line.clear();
}
});
while let Ok(cmd) = rx_cmd.recv() {
{
let config = shared_config.lock().unwrap();
if config.version != current_version {
*stop_flag.lock().unwrap() = true;
let _ = tx_events.send(InternalEvent::Disconnected);
break;
}
}
if stream.write_all(format!("{}
", cmd).as_bytes()).is_err() {
let _ = tx_events.send(InternalEvent::Disconnected);
break;
}
thread::sleep(std::time::Duration::from_millis(100));
}
let _ = tx_events.send(InternalEvent::Disconnected);
}
thread::sleep(std::time::Duration::from_secs(2));
}
}
pub fn tcp_log_worker(shared_config: Arc<Mutex<ConnectionConfig>>, tx_events: Sender<InternalEvent>) {
let mut current_version = 0;
let mut current_addr = String::new();
loop {
{
let config = shared_config.lock().unwrap();
if config.version != current_version {
current_version = config.version;
current_addr = format!("{}:{}", config.ip, config.log_port);
}
}
if current_addr.is_empty() || current_addr.starts_with(":") {
thread::sleep(std::time::Duration::from_secs(1));
continue;
}
if let Ok(stream) = TcpStream::connect(&current_addr) {
let mut reader = BufReader::new(stream);
let mut line = String::new();
while reader.read_line(&mut line).is_ok() {
if shared_config.lock().unwrap().version != current_version {
break;
}
let trimmed = line.trim();
if trimmed.starts_with("LOG ") {
let parts: Vec<&str> = trimmed[4..].splitn(2, ' ').collect();
if parts.len() == 2 {
let _ = tx_events.send(InternalEvent::Log(LogEntry {
time: Local::now().format("%H:%M:%S%.3f").to_string(),
level: parts[0].to_string(),
message: parts[1].to_string(),
}));
}
}
line.clear();
}
}
thread::sleep(std::time::Duration::from_secs(2));
}
}
#[allow(dead_code)]
pub fn recording_worker(
rx: Receiver<[f64; 2]>,
path: String,
signal_name: String,
tx_events: Sender<InternalEvent>,
) {
let file = match File::create(&path) {
Ok(f) => f,
Err(e) => {
let _ = tx_events.send(InternalEvent::RecordingError(
signal_name,
format!("File Error: {}", e),
));
return;
}
};
let schema = Arc::new(Schema::new(vec![
Field::new("timestamp", DataType::Float64, false),
Field::new("value", DataType::Float64, false),
]));
let mut writer = match ArrowWriter::try_new(
file,
schema.clone(),
Some(WriterProperties::builder().build()),
) {
Ok(w) => w,
Err(e) => {
let _ = tx_events.send(InternalEvent::RecordingError(
signal_name,
format!("Parquet Error: {}", e),
));
return;
}
};
let (mut t_acc, mut v_acc) = (Vec::with_capacity(1000), Vec::with_capacity(1000));
while let Ok([t, v]) = rx.recv() {
t_acc.push(t);
v_acc.push(v);
if t_acc.len() >= 1000 {
let batch = RecordBatch::try_new(
schema.clone(),
vec![
Arc::new(Float64Array::from(t_acc.clone())),
Arc::new(Float64Array::from(v_acc.clone())),
],
)
.unwrap();
let _ = writer.write(&batch);
t_acc.clear();
v_acc.clear();
}
}
if !t_acc.is_empty() {
let batch = RecordBatch::try_new(
schema.clone(),
vec![
Arc::new(Float64Array::from(t_acc)),
Arc::new(Float64Array::from(v_acc)),
],
)
.unwrap();
let _ = writer.write(&batch);
}
let _ = writer.close();
}
pub fn udp_worker(
shared_config: Arc<Mutex<ConnectionConfig>>,
id_to_meta: Arc<Mutex<HashMap<u32, SignalMetadata>>>,
traced_data: Arc<Mutex<HashMap<String, TraceData>>>,
tx_events: Sender<InternalEvent>,
) {
let mut current_version = 0;
let mut socket: Option<UdpSocket> = None;
let mut last_seq: Option<u32> = None;
let mut last_warning_time = std::time::Instant::now();
loop {
let (ver, port) = {
let config = shared_config.lock().unwrap();
(config.version, config.udp_port.clone())
};
if ver != current_version || socket.is_none() {
current_version = ver;
{
let mut base = BASE_TELEM_TS.lock().unwrap();
*base = None;
}
if port.is_empty() {
socket = None;
continue;
}
let port_num: u16 = port.parse().unwrap_or(8081);
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 _ = sock.set_recv_buffer_size(10 * 1024 * 1024);
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 {
thread::sleep(std::time::Duration::from_secs(5));
continue;
}
let _ = socket
.as_ref()
.unwrap()
.set_read_timeout(Some(std::time::Duration::from_millis(500)));
last_seq = None;
}
let s = if let Some(sock) = socket.as_ref() {
sock
} else {
thread::sleep(std::time::Duration::from_secs(1));
continue;
};
let mut buf = [0u8; 4096];
let mut total_packets = 0u64;
loop {
if shared_config.lock().unwrap().version != current_version {
break;
}
if let Ok(n) = s.recv(&mut buf) {
total_packets += 1;
if (total_packets % 500) == 0 {
let _ = tx_events.send(InternalEvent::UdpStats(total_packets));
}
if n < 20 {
continue;
}
if u32::from_le_bytes(buf[0..4].try_into().unwrap()) != 0xDA7A57AD {
continue;
}
let seq = u32::from_le_bytes(buf[4..8].try_into().unwrap());
if let Some(last) = last_seq {
if seq != last + 1 && seq > last {
let _ = tx_events.send(InternalEvent::UdpDropped(seq - last - 1));
}
}
last_seq = Some(seq);
let count = u32::from_le_bytes(buf[16..20].try_into().unwrap());
let mut offset = 20;
let mut local_updates: HashMap<String, Vec<[f64; 2]>> = HashMap::new();
let mut last_values: HashMap<String, f64> = HashMap::new();
let metas = id_to_meta.lock().unwrap();
if metas.is_empty() && count > 0 && last_warning_time.elapsed().as_secs() > 5 {
let _ = tx_events.send(InternalEvent::InternalLog(
"UDP received but Metadata empty. Still discovering?".to_string(),
));
last_warning_time = std::time::Instant::now();
}
for _ in 0..count {
if offset + 16 > n {
break;
}
let id = u32::from_le_bytes(buf[offset..offset + 4].try_into().unwrap());
let ts_raw =
u64::from_le_bytes(buf[offset + 4..offset + 12].try_into().unwrap());
let size =
u32::from_le_bytes(buf[offset + 12..offset + 16].try_into().unwrap());
offset += 16;
if offset + size as usize > n {
break;
}
let data_slice = &buf[offset..offset + size as usize];
let mut base_ts_guard = BASE_TELEM_TS.lock().unwrap();
if base_ts_guard.is_none() {
*base_ts_guard = Some(ts_raw);
}
let base = base_ts_guard.unwrap();
let ts_s = if ts_raw >= base {
(ts_raw - base) as f64 / 1000000.0
} else {
0.0
};
drop(base_ts_guard);
if let Some(meta) = metas.get(&id) {
let _ = tx_events.send(InternalEvent::TelemMatched(id));
if meta.is_state {
let state_name = String::from_utf8_lossy(data_slice)
.trim_matches(char::from(0))
.to_string();
for name in &meta.names {
let _ = tx_events.send(InternalEvent::StateUpdate(name.clone(), state_name.clone()));
}
} else {
let t = meta.sig_type.as_str();
let type_size = if meta.elements > 0 { size / meta.elements } else { size };
for i in 0..meta.elements {
let elem_offset = (i * type_size) as usize;
if elem_offset + type_size as usize > data_slice.len() { break; }
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 => {
let b = elem_data[0..2].try_into().unwrap();
if t.contains('u') {
u16::from_le_bytes(b) as f64
} else {
i16::from_le_bytes(b) as f64
}
}
4 => {
let b = elem_data[0..4].try_into().unwrap();
if t.contains("float") {
f32::from_le_bytes(b) as f64
} else if t.contains('u') {
u32::from_le_bytes(b) as f64
} else {
i32::from_le_bytes(b) as f64
}
}
8 => {
let b = elem_data[0..8].try_into().unwrap();
if t.contains("float") {
f64::from_le_bytes(b)
} else if t.contains('u') {
u64::from_le_bytes(b) as f64
} else {
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);
}
}
}
}
offset += size as usize;
}
drop(metas);
if !local_updates.is_empty() {
let mut data_map = traced_data.lock().unwrap();
for (name, new_points) in local_updates {
if let Some(entry) = data_map.get_mut(&name) {
for point in new_points {
entry.values.push_back(point);
if let Some(tx) = &entry.recording_tx {
let _ = tx.send(point);
}
}
if let Some(lv) = last_values.get(&name) {
entry.last_value = *lv;
}
while entry.values.len() > 100000 {
entry.values.pop_front();
}
}
}
}
}
}
}
}
+3 -293
View File
@@ -51,6 +51,7 @@
"-c", "-c",
"-I../../../..//Source/Core/Types/Result", "-I../../../..//Source/Core/Types/Result",
"-I../../../..//Source/Core/Types/Vec", "-I../../../..//Source/Core/Types/Vec",
"-I../../../..//Source/Components/Interfaces/TCPLogger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types", "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability", "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects", "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
@@ -59,6 +60,7 @@
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger", "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration", "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs", "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4StateMachine",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability", "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services", "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages", "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
@@ -66,6 +68,7 @@
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs", "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability", "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams", "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2-components/Source/Components/DataSources/RealTimeThreadSynchronisation",
"-fPIC", "-fPIC",
"-Wall", "-Wall",
"-std=c++98", "-std=c++98",
@@ -89,298 +92,5 @@
], ],
"directory": "/home/martino/Projects/marte_debug/Source/Components/Interfaces/DebugService", "directory": "/home/martino/Projects/marte_debug/Source/Components/Interfaces/DebugService",
"output": "../../../..//Build/x86-linux/Components/Interfaces/DebugService/DebugService.o" "output": "../../../..//Build/x86-linux/Components/Interfaces/DebugService/DebugService.o"
},
{
"file": "UnitTests.cpp",
"arguments": [
"g++",
"-c",
"-I../../Source/Core/Types/Result",
"-I../../Source/Core/Types/Vec",
"-I../../Source/Components/Interfaces/DebugService",
"-I../../Source/Components/Interfaces/TCPLogger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
"-fPIC",
"-Wall",
"-std=c++98",
"-Werror",
"-Wno-invalid-offsetof",
"-Wno-unused-variable",
"-fno-strict-aliasing",
"-frtti",
"-DMARTe2_TEST_ENVIRONMENT=GTest",
"-DARCHITECTURE=x86_gcc",
"-DENVIRONMENT=Linux",
"-DUSE_PTHREAD",
"-pthread",
"-Wno-deprecated-declarations",
"-Wno-unused-value",
"-g",
"-ggdb",
"UnitTests.cpp",
"-o",
"../../Build/x86-linux/Test/UnitTests/UnitTests/UnitTests.o"
],
"directory": "/home/martino/Projects/marte_debug/Test/UnitTests",
"output": "../../Build/x86-linux/Test/UnitTests/UnitTests/UnitTests.o"
},
{
"file": "SchedulerTest.cpp",
"arguments": [
"g++",
"-c",
"-I../../Source/Core/Types/Result",
"-I../../Source/Core/Types/Vec",
"-I../../Source/Components/Interfaces/DebugService",
"-I../../Source/Components/Interfaces/TCPLogger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L6App",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
"-fPIC",
"-Wall",
"-std=c++98",
"-Werror",
"-Wno-invalid-offsetof",
"-Wno-unused-variable",
"-fno-strict-aliasing",
"-frtti",
"-DMARTe2_TEST_ENVIRONMENT=GTest",
"-DARCHITECTURE=x86_gcc",
"-DENVIRONMENT=Linux",
"-DUSE_PTHREAD",
"-pthread",
"-Wno-deprecated-declarations",
"-Wno-unused-value",
"-g",
"-ggdb",
"SchedulerTest.cpp",
"-o",
"../../Build/x86-linux/Test/Integration/Integration/SchedulerTest.o"
],
"directory": "/home/martino/Projects/marte_debug/Test/Integration",
"output": "../../Build/x86-linux/Test/Integration/Integration/SchedulerTest.o"
},
{
"file": "TraceTest.cpp",
"arguments": [
"g++",
"-c",
"-I../../Source/Core/Types/Result",
"-I../../Source/Core/Types/Vec",
"-I../../Source/Components/Interfaces/DebugService",
"-I../../Source/Components/Interfaces/TCPLogger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L6App",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
"-fPIC",
"-Wall",
"-std=c++98",
"-Werror",
"-Wno-invalid-offsetof",
"-Wno-unused-variable",
"-fno-strict-aliasing",
"-frtti",
"-DMARTe2_TEST_ENVIRONMENT=GTest",
"-DARCHITECTURE=x86_gcc",
"-DENVIRONMENT=Linux",
"-DUSE_PTHREAD",
"-pthread",
"-Wno-deprecated-declarations",
"-Wno-unused-value",
"-g",
"-ggdb",
"TraceTest.cpp",
"-o",
"../../Build/x86-linux/Test/Integration/Integration/TraceTest.o"
],
"directory": "/home/martino/Projects/marte_debug/Test/Integration",
"output": "../../Build/x86-linux/Test/Integration/Integration/TraceTest.o"
},
{
"file": "ValidationTest.cpp",
"arguments": [
"g++",
"-c",
"-I../../Source/Core/Types/Result",
"-I../../Source/Core/Types/Vec",
"-I../../Source/Components/Interfaces/DebugService",
"-I../../Source/Components/Interfaces/TCPLogger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L6App",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
"-fPIC",
"-Wall",
"-std=c++98",
"-Werror",
"-Wno-invalid-offsetof",
"-Wno-unused-variable",
"-fno-strict-aliasing",
"-frtti",
"-DMARTe2_TEST_ENVIRONMENT=GTest",
"-DARCHITECTURE=x86_gcc",
"-DENVIRONMENT=Linux",
"-DUSE_PTHREAD",
"-pthread",
"-Wno-deprecated-declarations",
"-Wno-unused-value",
"-g",
"-ggdb",
"ValidationTest.cpp",
"-o",
"../../Build/x86-linux/Test/Integration/Integration/ValidationTest.o"
],
"directory": "/home/martino/Projects/marte_debug/Test/Integration",
"output": "../../Build/x86-linux/Test/Integration/Integration/ValidationTest.o"
},
{
"file": "ConfigCommandTest.cpp",
"arguments": [
"g++",
"-c",
"-I../../Source/Core/Types/Result",
"-I../../Source/Core/Types/Vec",
"-I../../Source/Components/Interfaces/DebugService",
"-I../../Source/Components/Interfaces/TCPLogger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L6App",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
"-fPIC",
"-Wall",
"-std=c++98",
"-Werror",
"-Wno-invalid-offsetof",
"-Wno-unused-variable",
"-fno-strict-aliasing",
"-frtti",
"-DMARTe2_TEST_ENVIRONMENT=GTest",
"-DARCHITECTURE=x86_gcc",
"-DENVIRONMENT=Linux",
"-DUSE_PTHREAD",
"-pthread",
"-Wno-deprecated-declarations",
"-Wno-unused-value",
"-g",
"-ggdb",
"ConfigCommandTest.cpp",
"-o",
"../../Build/x86-linux/Test/Integration/Integration/ConfigCommandTest.o"
],
"directory": "/home/martino/Projects/marte_debug/Test/Integration",
"output": "../../Build/x86-linux/Test/Integration/Integration/ConfigCommandTest.o"
},
{
"file": "IntegrationTests.cpp",
"arguments": [
"g++",
"-c",
"-I../../Source/Core/Types/Result",
"-I../../Source/Core/Types/Vec",
"-I../../Source/Components/Interfaces/DebugService",
"-I../../Source/Components/Interfaces/TCPLogger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L6App",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
"-fPIC",
"-Wall",
"-std=c++98",
"-Werror",
"-Wno-invalid-offsetof",
"-Wno-unused-variable",
"-fno-strict-aliasing",
"-frtti",
"-DMARTe2_TEST_ENVIRONMENT=GTest",
"-DARCHITECTURE=x86_gcc",
"-DENVIRONMENT=Linux",
"-DUSE_PTHREAD",
"-pthread",
"-Wno-deprecated-declarations",
"-Wno-unused-value",
"-g",
"-ggdb",
"IntegrationTests.cpp",
"-o",
"../../Build/x86-linux/Test/Integration/Integration/IntegrationTests.o"
],
"directory": "/home/martino/Projects/marte_debug/Test/Integration",
"output": "../../Build/x86-linux/Test/Integration/Integration/IntegrationTests.o"
} }
] ]
+4 -3
View File
@@ -6,11 +6,12 @@ export MARTe2_DIR=$DIR/dependency/MARTe2
export MARTe2_Components_DIR=$DIR/dependency/MARTe2-components export MARTe2_Components_DIR=$DIR/dependency/MARTe2-components
export TARGET=x86-linux export TARGET=x86-linux
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_DIR/Build/$TARGET/Core export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_DIR/Build/$TARGET/Core
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_Components_DIR/Build/$TARGET/Components export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_Components_DIR/Build/$TARGET/Components/Components
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DIR/Build/$TARGET/Components/Interfaces/DebugService export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_Components_DIR/Build/$TARGET/Components/DataSources/RealTimeThreadSynchronisation
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DIR/Build/$TARGET/Components/Interfaces/TCPLogger
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_Components_DIR/Build/$TARGET/Components/DataSources/LinuxTimer export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_Components_DIR/Build/$TARGET/Components/DataSources/LinuxTimer
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_Components_DIR/Build/$TARGET/Components/DataSources/LoggerDataSource export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_Components_DIR/Build/$TARGET/Components/DataSources/LoggerDataSource
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_Components_DIR/Build/$TARGET/Components/GAMs/IOGAM export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_Components_DIR/Build/$TARGET/Components/GAMs/IOGAM
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DIR/Build/$TARGET/Components/Interfaces/DebugService
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DIR/Build/$TARGET/Components/Interfaces/TCPLogger
echo "MARTe2 Environment Set (MARTe2_DIR=$MARTe2_DIR)" echo "MARTe2 Environment Set (MARTe2_DIR=$MARTe2_DIR)"
echo "MARTe2 Components Environment Set (MARTe2_Components_DIR=$MARTe2_Components_DIR)" echo "MARTe2 Components Environment Set (MARTe2_Components_DIR=$MARTe2_Components_DIR)"
+7 -34
View File
@@ -11,16 +11,13 @@ fi
# 2. Paths # 2. Paths
MARTE_EX="${MARTe2_DIR}/Build/${TARGET}/App/MARTeApp.ex" MARTE_EX="${MARTe2_DIR}/Build/${TARGET}/App/MARTeApp.ex"
BUILD_DIR="$(pwd)/Build/${TARGET}" DEBUG_LIB="$(pwd)/Build/libmarte_dev.so"
# Our plugin libraries
DEBUG_LIB="${BUILD_DIR}/Components/Interfaces/DebugService/libDebugService.so"
TCPLOGGER_LIB="${BUILD_DIR}/Components/Interfaces/TCPLogger/libTcpLogger.so"
# Component library base search path # Component library base search path
COMPONENTS_BUILD_DIR="${MARTe2_Components_DIR}/Build/${TARGET}/Components" COMPONENTS_BUILD_DIR="${MARTe2_Components_DIR}/Build/${TARGET}/Components"
# DYNAMICALLY FIND ALL COMPONENT DIRS and add to LD_LIBRARY_PATH # DYNAMICALLY FIND ALL COMPONENT DIRS
# MARTe2 Loader needs the specific directories containing .so files in LD_LIBRARY_PATH
ALL_COMPONENT_DIRS=$(find "$COMPONENTS_BUILD_DIR" -type d) ALL_COMPONENT_DIRS=$(find "$COMPONENTS_BUILD_DIR" -type d)
for dir in $ALL_COMPONENT_DIRS; do for dir in $ALL_COMPONENT_DIRS; do
if ls "$dir"/*.so >/dev/null 2>&1; then if ls "$dir"/*.so >/dev/null 2>&1; then
@@ -29,39 +26,15 @@ for dir in $ALL_COMPONENT_DIRS; do
done done
# Ensure our build dir and core dir are included # Ensure our build dir and core dir are included
export LD_LIBRARY_PATH="${BUILD_DIR}/Components/Interfaces/DebugService:${BUILD_DIR}/Components/Interfaces/TCPLogger:${MARTe2_DIR}/Build/${TARGET}/Core:${LD_LIBRARY_PATH}" export LD_LIBRARY_PATH="$(pwd)/Build:${MARTe2_DIR}/Build/${TARGET}/Core:${LD_LIBRARY_PATH}"
# 3. Cleanup # 3. Cleanup
echo "Cleaning up lingering processes..." echo "Cleaning up lingering processes..."
pkill -9 MARTeApp.ex pkill -9 MARTeApp.ex
sleep 1 sleep 1
# 4. Validate libraries exist # 4. Launch Application
for lib in "$DEBUG_LIB" "$TCPLOGGER_LIB"; do
if [ ! -f "$lib" ]; then
echo "ERROR: Library not found: $lib"
echo "Run: make -f Makefile.gcc core"
exit 1
fi
done
# 5. Launch Application
echo "Launching standard MARTeApp.ex with debug_test.cfg..." echo "Launching standard MARTeApp.ex with debug_test.cfg..."
# LD_PRELOAD ensures our classes are registered before the config is parsed. # PRELOAD ensures our DebugService class is available to the registry early
# MARTeApp.ex does not use dlopen for plugins — preloading is the standard approach. export LD_PRELOAD="${DEBUG_LIB}"
# All required component .so files are collected via the find loop into LD_PRELOAD too.
PRELOAD_LIBS="${DEBUG_LIB}:${TCPLOGGER_LIB}"
# Collect any additional component .so files referenced by the config
for lib in \
"${COMPONENTS_BUILD_DIR}/DataSources/RealTimeThreadSynchronisation/RealTimeThreadSynchronisation.so" \
"${COMPONENTS_BUILD_DIR}/DataSources/LinuxTimer/LinuxTimer.so" \
"${COMPONENTS_BUILD_DIR}/DataSources/LoggerDataSource/LoggerDataSource.so" \
"${COMPONENTS_BUILD_DIR}/GAMs/IOGAM/IOGAM.so"; do
if [ -f "$lib" ]; then
PRELOAD_LIBS="${PRELOAD_LIBS}:${lib}"
fi
done
export LD_PRELOAD="${PRELOAD_LIBS}"
"$MARTE_EX" -f Test/Configurations/debug_test.cfg -l RealTimeLoader -s State1 "$MARTE_EX" -f Test/Configurations/debug_test.cfg -l RealTimeLoader -s State1