#ifndef DEBUGSERVICEBASE_H #define DEBUGSERVICEBASE_H /** * @file DebugServiceBase.h * @brief Shared base class for DebugService and WebDebugService. * * Extracts all signal-management, command-handling and config logic that is * common to both the TCP/UDP transport (DebugService) and the HTTP/SSE * transport (WebDebugService), eliminating the previous code duplication. */ #include "ConfigurationDatabase.h" #include "DataSourceI.h" #include "DebugServiceI.h" #include "FastPollingMutexSem.h" #include "ReferenceContainer.h" #include "ReferenceT.h" #include "StreamString.h" namespace MARTe { /** * @brief Intermediate base class that holds all shared debugging logic. * * Inherits from ReferenceContainer (to be a MARTe2 Object) and DebugServiceI * (to expose the RT-path / control-path interface). Transport subclasses * (DebugService, WebDebugService) inherit from this class and add only their * transport-specific threading and socket logic. */ class DebugServiceBase : public ReferenceContainer, public DebugServiceI { public: friend class DebugServiceTest; DebugServiceBase(); virtual ~DebugServiceBase(); // ========================================================================= // DebugServiceI RT-path overrides (shared implementation) // ========================================================================= virtual DebugSignalInfo *RegisterSignal(void *memoryAddress, TypeDescriptor type, const char8 *name, uint8 numberOfDimensions = 0, uint32 numberOfElements = 1); virtual void ProcessSignal(DebugSignalInfo *signalInfo, uint32 size, uint64 timestamp); virtual void RegisterBroker(DebugSignalInfo **signalPointers, uint32 numSignals, MemoryMapBroker *broker, volatile bool *anyActiveFlag, Vector *activeIndices, Vector *activeSizes, FastPollingMutexSem *activeMutex, volatile bool *anyBreakFlag, Vector *breakIndices, const char8 *gamName = NULL_PTR(const char8 *), bool isOutput = false); virtual bool IsPaused() const { return isPaused; } virtual void SetPaused(bool paused) { isPaused = paused; } virtual bool IsStepPending() const { return stepRemaining > 0u; } virtual void ConsumeStepIfNeeded(const char8 *gamName, const char8 *threadName = NULL_PTR(const char8 *)); // ========================================================================= // DebugServiceI control-path overrides (shared implementation) // ========================================================================= virtual uint32 ForceSignal (const char8 *name, const char8 *valueStr); virtual uint32 UnforceSignal(const char8 *name); virtual uint32 TraceSignal (const char8 *name, bool enable, uint32 decimation = 1); virtual uint32 SetBreak (const char8 *name, uint8 op, float64 threshold); virtual uint32 ClearBreak (const char8 *name); virtual bool IsInstrumented(const char8 *fullPath, bool &traceable, bool &forcable); virtual uint32 RegisterMonitorSignal(const char8 *path, uint32 periodMs); virtual uint32 UnmonitorSignal (const char8 *path); // ========================================================================= // Shared control-path methods (used by transport subclasses) // ========================================================================= /** * @brief Parse and dispatch a debug command; write text response to @p out. * * Handles: TRACE, FORCE, UNFORCE, BREAK, PAUSE, RESUME, STEP, STEP_STATUS, * VALUE, DISCOVER, TREE, INFO, LS, CONFIG, MONITOR, UNMONITOR, * SERVICE_INFO, MSG. * * SERVICE_INFO delegates to GetServiceInfo() so each transport can fill in * its own port/state information. */ void HandleCommand(const StreamString &cmdIn, StreamString &out); void GetStepStatus(StreamString &out); void GetSignalValue(const char8 *name, StreamString &out); void Discover (StreamString &out); void InfoNode (const char8 *path, StreamString &out); void ListNodes (const char8 *path, StreamString &out); void ServeConfig (StreamString &out); void SetFullConfig(ConfigurationDatabase &config); void RebuildConfigFromRegistry(); // ========================================================================= // Struct shared by both transports // ========================================================================= struct MonitoredSignal { ReferenceT dataSource; uint32 signalIdx; uint32 internalID; uint32 periodMs; uint64 lastPollTime; uint32 size; StreamString path; }; // ========================================================================= // Constants // ========================================================================= static const uint32 GET_VALUE_MAX_ELEMENTS = 256u; /** * @brief Pre-build DISCOVER and TREE response caches. * * Called automatically by SetFullConfig() once the application is fully * initialised. After this point, DISCOVER and TREE are served from the * pre-built string with no mutex contention and no JSON generation cost. * Both caches are invalidated whenever a new signal is registered (which * normally only happens during broker init, before SetFullConfig). */ void BuildDiscoverCache(); void BuildTreeCache(); // Number of signals per DISCOVER_PART TCP chunk. Responses larger than // this are split so the Go client can start parsing immediately. static const uint32 DISCOVER_CHUNK_SIGNALS = 256u; protected: // ========================================================================= // Virtual hooks for transport subclasses // ========================================================================= /** * @brief Fill the SERVICE_INFO response text (transport-specific). * * Called by HandleCommand when the SERVICE_INFO command is received. * The base implementation writes nothing; subclasses override to append * e.g. "OK SERVICE_INFO TCP_CTRL:8080 UDP_STREAM:8081 STATE:RUNNING\n". */ virtual void GetServiceInfo(StreamString &out) = 0; /** * @brief Write back transport-specific config keys after RebuildConfigFromRegistry(). * * Called at the end of RebuildConfigFromRegistry() so that port numbers * and other transport parameters that were read in Initialise() are * reflected back into fullConfig (ExportData on ReferenceContainers * doesn't re-emit config-file parameters). */ virtual void RebuildTransportConfig() {} // ========================================================================= // Shared protected helpers // ========================================================================= void Step(uint32 n, const char8 *threadName = NULL_PTR(const char8 *)); void UpdateBrokersActiveStatus(); void UpdateBrokersBreakStatus(); void PatchRegistry(); void ExportTreeNode(const char8 *path, StreamString &out); void EnrichWithConfig(const char8 *path, StreamString &json); static void JsonifyDatabase(ConfigurationDatabase &db, StreamString &json); // ========================================================================= // Shared data members // ========================================================================= Vector signals; Vector aliases; Vector brokers; Vector monitoredSignals; FastPollingMutexSem mutex; FastPollingMutexSem tracePushMutex; TraceRingBuffer traceBuffer; volatile bool isPaused; volatile uint32 stepRemaining; StreamString pausedAtGam; StreamString stepThreadFilter; ConfigurationDatabase fullConfig; bool manualConfigSet; // Pre-built response caches. Guarded by mutex (brief lock for swap, // none needed for reads once cacheValid is true and construction is done). StreamString discoverCache; // full chunked DISCOVER_PART+DISCOVER payload StreamString treeCache; // full TREE payload including sentinel volatile bool discoverCacheValid; volatile bool treeCacheValid; }; } // namespace MARTe #endif // DEBUGSERVICEBASE_H