#ifndef DEBUGSERVICE_H #define DEBUGSERVICE_H #include "BasicTCPSocket.h" #include "BasicUDPSocket.h" #include "ConfigurationDatabase.h" #include "DebugCore.h" #include "EmbeddedServiceMethodBinderI.h" #include "MessageI.h" #include "Object.h" #include "ReferenceContainer.h" #include "ReferenceT.h" #include "SingleThreadService.h" #include "StreamString.h" #include "Vec.h" namespace MARTe { class MemoryMapBroker; class DataSourceI; struct SignalAlias { StreamString name; uint32 signalIndex; }; struct BrokerInfo { DebugSignalInfo **signalPointers; uint32 numSignals; MemoryMapBroker *broker; volatile bool *anyActiveFlag; Vec *activeIndices; Vec *activeSizes; FastPollingMutexSem *activeMutex; // Conditional break — mirrors activeIndices but for break-enabled signals volatile bool *anyBreakFlag; Vec *breakIndices; // GAM association for step-by-GAM StreamString gamName; bool isOutput; }; class DebugService : public ReferenceContainer, public MessageI, public EmbeddedServiceMethodBinderI { public: friend class DebugServiceTest; CLASS_REGISTER_DECLARATION() DebugService(); virtual ~DebugService(); virtual bool Initialise(StructuredDataI &data); DebugSignalInfo *RegisterSignal(void *memoryAddress, TypeDescriptor type, const char8 *name, uint8 numberOfDimensions = 0, uint32 numberOfElements = 1); void ProcessSignal(DebugSignalInfo *signalInfo, uint32 size, uint64 timestamp); void RegisterBroker(DebugSignalInfo **signalPointers, uint32 numSignals, MemoryMapBroker *broker, volatile bool *anyActiveFlag, Vec *activeIndices, Vec *activeSizes, FastPollingMutexSem *activeMutex, volatile bool *anyBreakFlag, Vec *breakIndices, const char8 *gamName = NULL_PTR(const char8 *), bool isOutput = false); virtual ErrorManagement::ErrorType Execute(ExecutionInfo &info); virtual ErrorManagement::ErrorType HandleMessage(ReferenceT &data); bool IsPaused() const { return isPaused; } 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); uint32 ForceSignal(const char8 *name, const char8 *valueStr); uint32 UnforceSignal(const char8 *name); 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); void Discover(BasicTCPSocket *client); void InfoNode(const char8 *path, BasicTCPSocket *client); void ListNodes(const char8 *path, BasicTCPSocket *client); void ServeConfig(BasicTCPSocket *client); void SetFullConfig(ConfigurationDatabase &config); void RebuildConfigFromRegistry(); struct MonitoredSignal { ReferenceT dataSource; uint32 signalIdx; uint32 internalID; uint32 periodMs; uint64 lastPollTime; uint32 size; StreamString path; }; uint32 RegisterMonitorSignal(const char8 *path, uint32 periodMs); uint32 UnmonitorSignal(const char8 *path); private: void HandleCommand(StreamString cmd, BasicTCPSocket *client); void UpdateBrokersActiveStatus(); void UpdateBrokersBreakStatus(); void InjectTcpLoggerIfNeeded(); uint32 ExportTree(ReferenceContainer *container, StreamString &json, const char8 *pathPrefix); void PatchRegistry(); void EnrichWithConfig(const char8 *path, StreamString &json); static void JsonifyDatabase(ConfigurationDatabase &db, StreamString &json); ErrorManagement::ErrorType Server(ExecutionInfo &info); ErrorManagement::ErrorType Streamer(ExecutionInfo &info); uint16 controlPort; uint16 streamPort; uint16 logPort; StreamString streamIP; bool isServer; bool suppressTimeoutLogs; volatile bool isPaused; volatile uint32 stepRemaining; StreamString pausedAtGam; StreamString stepThreadFilter; // empty = all threads; non-empty = only this OS thread name BasicTCPSocket tcpServer; BasicUDPSocket udpSocket; class ServiceBinder : public EmbeddedServiceMethodBinderI { public: enum ServiceType { ServerType, StreamerType }; ServiceBinder(DebugService *parent, ServiceType type) : parent(parent), type(type) {} virtual ErrorManagement::ErrorType Execute(ExecutionInfo &info) { if (type == StreamerType) { return parent->Streamer(info); } return parent->Server(info); } private: DebugService *parent; ServiceType type; }; ServiceBinder binderServer; ServiceBinder binderStreamer; SingleThreadService threadService; SingleThreadService streamerService; ThreadIdentifier serverThreadId; ThreadIdentifier streamerThreadId; Vec signals; Vec aliases; Vec brokers; Vec monitoredSignals; FastPollingMutexSem mutex; TraceRingBuffer traceBuffer; BasicTCPSocket *activeClient; // Streamer state persisted across Execute() calls (framework loops Execute) uint8 streamerPacketBuffer[4096]; uint32 streamerPacketOffset; uint32 streamerSequenceNumber; ConfigurationDatabase fullConfig; bool manualConfigSet; static DebugService *instance; }; } // namespace MARTe #endif