Initial commit

This commit is contained in:
Martino Ferrari
2026-02-21 00:58:56 +01:00
commit 5ef0efe7d6
26 changed files with 7999 additions and 0 deletions

View File

@@ -0,0 +1,167 @@
#ifndef DEBUGBROKERWRAPPER_H
#define DEBUGBROKERWRAPPER_H
#include "DebugService.h"
#include "BrokerI.h"
#include "MemoryMapBroker.h"
#include "ObjectRegistryDatabase.h"
#include "ReferenceT.h"
#include "ObjectBuilder.h"
#include "HighResolutionTimer.h"
// Original broker headers
#include "MemoryMapInputBroker.h"
#include "MemoryMapOutputBroker.h"
#include "MemoryMapSynchronisedInputBroker.h"
#include "MemoryMapSynchronisedOutputBroker.h"
#include "MemoryMapInterpolatedInputBroker.h"
#include "MemoryMapMultiBufferInputBroker.h"
#include "MemoryMapMultiBufferOutputBroker.h"
#include "MemoryMapSynchronisedMultiBufferInputBroker.h"
#include "MemoryMapSynchronisedMultiBufferOutputBroker.h"
namespace MARTe {
/**
* @brief Base implementation for all debug brokers.
*/
class DebugBrokerHelper {
public:
static void Process(BrokerI* broker, DebugService* service, DebugSignalInfo** signalInfoPointers, uint32 numSignals) {
if (service == NULL_PTR(DebugService*)) return;
while (service->IsPaused()) {
Sleep::MSec(10);
}
if (signalInfoPointers != NULL_PTR(DebugSignalInfo**)) {
for (uint32 i = 0; i < numSignals; i++) {
DebugSignalInfo *s = signalInfoPointers[i];
if (s != NULL_PTR(DebugSignalInfo*)) {
if (s->isTracing || s->isForcing) {
uint32 size = broker->GetCopyByteSize(i);
service->ProcessSignal(s, size);
}
}
}
}
}
static void InitSignals(MemoryMapBroker* broker, DataSourceI &dataSourceIn, DebugService* &service, DebugSignalInfo** &signalInfoPointers, uint32 &numSignals, MemoryMapBrokerCopyTableEntry* copyTable, const char8* functionName, SignalDirection direction) {
numSignals = broker->GetNumberOfCopies();
if (numSignals > 0) {
signalInfoPointers = new DebugSignalInfo*[numSignals];
for (uint32 i=0; i<numSignals; i++) signalInfoPointers[i] = NULL_PTR(DebugSignalInfo*);
}
ReferenceContainer *root = ObjectRegistryDatabase::Instance();
Reference serviceRef = root->Find("DebugService");
if (serviceRef.IsValid()) {
service = dynamic_cast<DebugService*>(serviceRef.operator->());
}
if (service && (copyTable != NULL_PTR(MemoryMapBrokerCopyTableEntry*))) {
StreamString dsPath;
DebugService::GetFullObjectName(dataSourceIn, dsPath);
for (uint32 i = 0; i < numSignals; i++) {
void *addr = copyTable[i].dataSourcePointer;
TypeDescriptor type = copyTable[i].type;
uint32 dsIdx = broker->GetDSCopySignalIndex(i);
StreamString signalName;
if (!dataSourceIn.GetSignalName(dsIdx, signalName)) signalName = "Unknown";
// 1. Register canonical DataSource name (Absolute)
StreamString dsFullName;
dsFullName.Printf("%s.%s", dsPath.Buffer(), signalName.Buffer());
service->RegisterSignal(addr, type, dsFullName.Buffer());
// 2. Also register absolute GAM alias
if (functionName != NULL_PTR(const char8*)) {
StreamString gamFullName;
const char8* dirStr = (direction == InputSignals) ? "In" : "Out";
Reference gamRef = ObjectRegistryDatabase::Instance()->Find(functionName);
if (gamRef.IsValid()) {
StreamString absGamPath;
DebugService::GetFullObjectName(*(gamRef.operator->()), absGamPath);
gamFullName.Printf("%s.%s.%s", absGamPath.Buffer(), dirStr, signalName.Buffer());
} else {
gamFullName.Printf("Root.%s.%s.%s", functionName, dirStr, signalName.Buffer());
}
signalInfoPointers[i] = service->RegisterSignal(addr, type, gamFullName.Buffer());
} else {
signalInfoPointers[i] = service->RegisterSignal(addr, type, dsFullName.Buffer());
}
}
}
}
};
#define DECLARE_DEBUG_BROKER_COMMON(BaseClass) \
Debug##BaseClass() : BaseClass() { \
service = NULL_PTR(DebugService*); \
signalInfoPointers = NULL_PTR(DebugSignalInfo**); \
numSignals = 0; \
} \
virtual ~Debug##BaseClass() { \
if (signalInfoPointers) delete[] signalInfoPointers; \
} \
virtual bool Execute() { \
bool ret = BaseClass::Execute(); \
if (ret) DebugBrokerHelper::Process(this, service, signalInfoPointers, numSignals); \
return ret; \
} \
private: \
DebugService *service; \
DebugSignalInfo **signalInfoPointers; \
uint32 numSignals;
#define DECLARE_DEBUG_BROKER(BaseClass) \
class Debug##BaseClass : public BaseClass { \
public: \
DECLARE_DEBUG_BROKER_COMMON(BaseClass) \
virtual bool Init(SignalDirection direction, DataSourceI &ds, const char8 *const name, void *gamMem) { \
bool ret = BaseClass::Init(direction, ds, name, gamMem); \
if (ret) DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers, numSignals, this->copyTable, name, direction); \
return ret; \
} \
virtual bool Init(SignalDirection direction, DataSourceI &ds, const char8 *const name, void *gamMem, const bool optim) { \
bool ret = BaseClass::Init(direction, ds, name, gamMem, optim); \
if (ret) DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers, numSignals, this->copyTable, name, direction); \
return ret; \
} \
}; \
class Debug##BaseClass##Builder : public ObjectBuilder { \
public: \
virtual Object *Build(HeapI* const heap) const { return new (heap) Debug##BaseClass(); } \
};
#define DECLARE_DEBUG_BROKER_NO_OPTIM(BaseClass) \
class Debug##BaseClass : public BaseClass { \
public: \
DECLARE_DEBUG_BROKER_COMMON(BaseClass) \
virtual bool Init(SignalDirection direction, DataSourceI &ds, const char8 *const name, void *gamMem) { \
bool ret = BaseClass::Init(direction, ds, name, gamMem); \
if (ret) DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers, numSignals, this->copyTable, name, direction); \
return ret; \
} \
}; \
class Debug##BaseClass##Builder : public ObjectBuilder { \
public: \
virtual Object *Build(HeapI* const heap) const { return new (heap) Debug##BaseClass(); } \
};
DECLARE_DEBUG_BROKER(MemoryMapInputBroker)
DECLARE_DEBUG_BROKER(MemoryMapOutputBroker)
DECLARE_DEBUG_BROKER(MemoryMapSynchronisedInputBroker)
DECLARE_DEBUG_BROKER(MemoryMapSynchronisedOutputBroker)
DECLARE_DEBUG_BROKER_NO_OPTIM(MemoryMapInterpolatedInputBroker)
DECLARE_DEBUG_BROKER(MemoryMapMultiBufferInputBroker)
DECLARE_DEBUG_BROKER(MemoryMapMultiBufferOutputBroker)
DECLARE_DEBUG_BROKER(MemoryMapSynchronisedMultiBufferInputBroker)
DECLARE_DEBUG_BROKER(MemoryMapSynchronisedMultiBufferOutputBroker)
}
#endif

133
Headers/DebugCore.h Normal file
View File

@@ -0,0 +1,133 @@
#ifndef DEBUGCORE_H
#define DEBUGCORE_H
#include "CompilerTypes.h"
#include "TypeDescriptor.h"
#include "StreamString.h"
#include "MemoryOperationsHelper.h"
namespace MARTe {
struct DebugSignalInfo {
void* memoryAddress;
TypeDescriptor type;
StreamString name;
volatile bool isTracing;
volatile bool isForcing;
uint8 forcedValue[1024];
uint32 internalID;
volatile uint32 decimationFactor;
volatile uint32 decimationCounter;
};
#pragma pack(push, 1)
struct TraceHeader {
uint32 magic; // 0xDA7A57AD
uint32 seq; // Sequence number
uint64 timestamp; // HighRes timestamp
uint32 count; // Number of samples in payload
};
#pragma pack(pop)
class TraceRingBuffer {
public:
TraceRingBuffer() {
bufferSize = 0;
buffer = NULL_PTR(uint8*);
readIndex = 0;
writeIndex = 0;
}
~TraceRingBuffer() {
if (buffer != NULL_PTR(uint8*)) {
delete[] buffer;
}
}
bool Init(uint32 size) {
if (buffer != NULL_PTR(uint8*)) {
delete[] buffer;
}
bufferSize = size;
buffer = new uint8[bufferSize];
readIndex = 0;
writeIndex = 0;
return (buffer != NULL_PTR(uint8*));
}
bool Push(uint32 signalID, void* data, uint32 size) {
uint32 packetSize = 4 + 4 + size;
uint32 read = readIndex;
uint32 write = writeIndex;
uint32 available = (read <= write) ? (bufferSize - (write - read) - 1) : (read - write - 1);
if (available < packetSize) return false;
// Use temporary write index to ensure atomic update
uint32 tempWrite = write;
WriteToBuffer(&tempWrite, &signalID, 4);
WriteToBuffer(&tempWrite, &size, 4);
WriteToBuffer(&tempWrite, data, size);
// Final atomic update
writeIndex = tempWrite;
return true;
}
bool Pop(uint32 &signalID, void* dataBuffer, uint32 &size, uint32 maxSize) {
uint32 read = readIndex;
uint32 write = writeIndex;
if (read == write) return false;
uint32 tempRead = read;
uint32 tempId, tempSize;
ReadFromBuffer(&tempRead, &tempId, 4);
ReadFromBuffer(&tempRead, &tempSize, 4);
if (tempSize > maxSize) {
// Error case: drop data up to writeIndex
readIndex = write;
return false;
}
ReadFromBuffer(&tempRead, dataBuffer, tempSize);
signalID = tempId;
size = tempSize;
readIndex = tempRead;
return true;
}
uint32 Count() {
uint32 read = readIndex;
uint32 write = writeIndex;
if (write >= read) return write - read;
return bufferSize - (read - write);
}
private:
void WriteToBuffer(uint32 *idx, void* src, uint32 count) {
uint8* s = (uint8*)src;
for (uint32 i=0; i<count; i++) {
buffer[*idx] = s[i];
*idx = (*idx + 1) % bufferSize;
}
}
void ReadFromBuffer(uint32 *idx, void* dst, uint32 count) {
uint8* d = (uint8*)dst;
for (uint32 i=0; i<count; i++) {
d[i] = buffer[*idx];
*idx = (*idx + 1) % bufferSize;
}
}
volatile uint32 readIndex;
volatile uint32 writeIndex;
uint32 bufferSize;
uint8 *buffer;
};
}
#endif

141
Headers/DebugService.h Normal file
View File

@@ -0,0 +1,141 @@
#ifndef DEBUGSERVICE_H
#define DEBUGSERVICE_H
#include "DataSourceI.h"
#include "GAM.h"
#include "MessageI.h"
#include "StreamString.h"
#include "BasicUDPSocket.h"
#include "BasicTCPSocket.h"
#include "ReferenceContainer.h"
#include "SingleThreadService.h"
#include "EmbeddedServiceMethodBinderI.h"
#include "FastMath.h"
#include "CompilerTypes.h"
#include "Object.h"
#include "DebugCore.h"
#include "ClassRegistryDatabase.h"
#include "ErrorManagement.h"
#include "AdvancedErrorManagement.h"
#include "LoggerConsumerI.h"
#include "Threads.h"
#include "EventSem.h"
namespace MARTe {
struct LogEntry {
ErrorManagement::ErrorInformation info;
char8 description[MAX_ERROR_MESSAGE_SIZE];
};
struct SignalAlias {
StreamString name;
uint32 signalIndex;
};
class DebugService : public ReferenceContainer, public MessageI, public EmbeddedServiceMethodBinderI, public LoggerConsumerI {
public:
CLASS_REGISTER_DECLARATION()
DebugService();
virtual ~DebugService();
virtual bool Initialise(StructuredDataI & data);
DebugSignalInfo* RegisterSignal(void* memoryAddress, TypeDescriptor type, const char8* name);
void ProcessSignal(DebugSignalInfo* signalInfo, uint32 size);
virtual ErrorManagement::ErrorType Execute(ExecutionInfo & info);
virtual void ConsumeLogMessage(LoggerPage *logPage);
static void LogCallback(const ErrorManagement::ErrorInformation &errorInfo, const char8 * const errorDescription);
void InsertLogIntoQueue(LoggerPage *logPage);
bool IsPaused() const { return isPaused; }
void SetPaused(bool paused) { isPaused = paused; }
static bool GetFullObjectName(const Object &obj, StreamString &fullPath);
private:
void HandleCommand(StreamString cmd, BasicTCPSocket *client);
uint32 ForceSignal(const char8* name, const char8* valueStr);
uint32 UnforceSignal(const char8* name);
uint32 TraceSignal(const char8* name, bool enable, uint32 decimation = 1);
void Discover(BasicTCPSocket *client);
void ListNodes(const char8* path, BasicTCPSocket *client);
void InfoNode(const char8* path, BasicTCPSocket *client);
uint32 ExportTree(ReferenceContainer *container, StreamString &json);
void PatchRegistry();
ErrorManagement::ErrorType Server(ExecutionInfo & info);
ErrorManagement::ErrorType Streamer(ExecutionInfo & info);
ErrorManagement::ErrorType LogStreamer(ExecutionInfo & info);
uint16 controlPort;
uint16 streamPort;
uint16 logPort;
StreamString streamIP;
bool isServer;
bool suppressTimeoutLogs;
volatile bool isPaused;
BasicTCPSocket tcpServer;
BasicUDPSocket udpSocket;
BasicTCPSocket logServer;
class ServiceBinder : public EmbeddedServiceMethodBinderI {
public:
enum ServiceType { ServerType, StreamerType, LogStreamerType };
ServiceBinder(DebugService *parent, ServiceType type) : parent(parent), type(type) {}
virtual ErrorManagement::ErrorType Execute(ExecutionInfo & info) {
if (type == StreamerType) return parent->Streamer(info);
if (type == LogStreamerType) return parent->LogStreamer(info);
return parent->Server(info);
}
private:
DebugService *parent;
ServiceType type;
};
ServiceBinder binderServer;
ServiceBinder binderStreamer;
ServiceBinder binderLogStreamer;
SingleThreadService threadService;
SingleThreadService streamerService;
SingleThreadService logStreamerService;
ThreadIdentifier serverThreadId;
ThreadIdentifier streamerThreadId;
ThreadIdentifier logStreamerThreadId;
static const uint32 MAX_SIGNALS = 4096;
DebugSignalInfo signals[MAX_SIGNALS];
uint32 numberOfSignals;
static const uint32 MAX_ALIASES = 8192;
SignalAlias aliases[MAX_ALIASES];
uint32 numberOfAliases;
FastPollingMutexSem mutex;
TraceRingBuffer traceBuffer;
static const uint32 MAX_CLIENTS = 16;
BasicTCPSocket* activeClients[MAX_CLIENTS];
FastPollingMutexSem clientsMutex;
BasicTCPSocket* activeLogClients[MAX_CLIENTS];
FastPollingMutexSem logClientsMutex;
static const uint32 LOG_QUEUE_SIZE = 1024;
LogEntry logQueue[LOG_QUEUE_SIZE];
volatile uint32 logQueueRead;
volatile uint32 logQueueWrite;
EventSem logEvent;
static DebugService* instance;
static ErrorManagement::ErrorProcessFunctionType originalLogCallback;
};
}
#endif