Initial commit
This commit is contained in:
167
Headers/DebugBrokerWrapper.h
Normal file
167
Headers/DebugBrokerWrapper.h
Normal 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
133
Headers/DebugCore.h
Normal 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
141
Headers/DebugService.h
Normal 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
|
||||
Reference in New Issue
Block a user