#ifndef DEBUGSERVICE_H #define DEBUGSERVICE_H #include "BasicTCPSocket.h" #include "DebugServiceBase.h" #include "EmbeddedServiceMethodBinderI.h" #include "MessageI.h" #include "ReferenceT.h" #include "SingleThreadService.h" #include "UDPSServer.h" namespace MARTe { /** * @brief TCP/UDP implementation of DebugServiceI (via DebugServiceBase). * * Signal tracing now uses the UDPS binary protocol (same wire format as * UDPStreamer) so that the same Go web client can consume both sources. * * Flow: * 1. The Go client listens on udpPort. * 2. DebugService binds the same port on its end (or uses the client's * configured IP:port as destination for the old push model). * 3. On startup and on every TRACE change, DebugService sends a CONFIG * packet listing the currently-traced signals. * 4. For each RT drain cycle that contains new data, DebugService sends * one DATA packet (Strict mode) with the most-recent value per signal. */ class DebugService : public DebugServiceBase, public MessageI, public EmbeddedServiceMethodBinderI { public: friend class DebugServiceTest; CLASS_REGISTER_DECLARATION() DebugService(); virtual ~DebugService(); virtual bool Initialise(StructuredDataI &data); virtual ErrorManagement::ErrorType Execute(ExecutionInfo &info); virtual ErrorManagement::ErrorType HandleMessage(ReferenceT &data); /** * @brief Override TraceSignal to trigger a CONFIG re-send after each change. */ virtual uint32 TraceSignal(const char8 *name, bool enable, uint32 decimation = 1u); protected: virtual void GetServiceInfo(StreamString &out); virtual void RebuildTransportConfig(); private: void InjectTcpLoggerIfNeeded(); ErrorManagement::ErrorType Server (ExecutionInfo &info); ErrorManagement::ErrorType Streamer(ExecutionInfo &info); /** * @brief Build and transmit a CONFIG packet for the current traced-signal set. * @details Iterates over all registered signals, selects those with * isTracing == true, builds UDPSSignalDescriptor array, and sends * a (possibly fragmented) UDPS CONFIG packet. Also rebuilds the * udpsSlots table and udpsWirePayload buffer. * @return true on success. */ bool SendUDPSConfig(); // ----------------------------------------------------------------------- // TCP/UDP transport configuration // ----------------------------------------------------------------------- uint16 controlPort; uint16 streamPort; uint16 logPort; StreamString streamIP; bool isServer; bool suppressTimeoutLogs; /** Optional authentication token (CR-5). If set (non-empty), the first * command from a new TCP client must be "AUTH ". All other * commands are rejected until the client authenticates. If empty * (default), no authentication is required (back-compat). */ StreamString authToken; bool clientAuthenticated; BasicTCPSocket tcpServer; UDPSServer udpsServer; ///< Handles fragmentation and multi-client sending // ----------------------------------------------------------------------- // Server-thread helper class // ----------------------------------------------------------------------- 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; FastPollingMutexSem clientMutex; BasicTCPSocket *activeClient; // ----------------------------------------------------------------------- // TCP server rate limiting and idle detection // ----------------------------------------------------------------------- static const uint32 CMD_RATE_LIMIT = 100u; static const uint32 CLIENT_IDLE_TIMEOUT_MS = 120000u; static const uint32 INPUT_BUFFER_MAX = 8192u; uint32 cmdCountInWindow; uint64 cmdWindowStartMs; uint64 lastDataTimeMs; StreamString inputBuffer; // ----------------------------------------------------------------------- // UDPS streaming state (replaces the old custom-format streamer buffers) // ----------------------------------------------------------------------- /** * @brief Per-slot descriptor for DATA packet assembly. * One slot per currently-traced signal; index mirrors CONFIG order. */ struct UDPSSlot { uint32 internalID; ///< DebugSignalInfo::internalID uint32 wireOffset; ///< Byte offset in udpsDataPayload (after 8-byte HRT) uint32 wireSize; ///< Bytes occupied by this signal in the DATA payload bool everFilled; ///< True once at least one sample has been placed }; /** Maximum number of simultaneously traced signals. */ static const uint32 UDPS_MAX_SLOTS = 512u; /** Maximum payload per UDP datagram (signal data bytes, excluding header). */ static const uint32 UDPS_MAX_PAYLOAD = 1400u; /** Hard cap on a single signal's data: 65535 - header(17) - HRT(8). */ static const uint32 UDPS_MAX_SAMPLE_BYTES = 65510u; UDPSSlot udpsSlots[UDPS_MAX_SLOTS]; ///< Slot table (valid for [0, udpsNumSlots)) uint32 udpsNumSlots; ///< Number of active slots /** Heap-allocated DATA payload buffer: [HRT:8][sig0_data]...[sigN_data]. * Re-allocated by SendUDPSConfig(). NULL when no signals are traced. */ uint8 *udpsDataPayload; uint32 udpsDataPayloadSize; /** Staging buffer: a single sample popped from traceBuffer. */ uint8 udpsSampleBuf[65535u]; /** Packet sequence counter (incremented per DATA/CONFIG datagram group). */ uint32 udpsPacketCounter; /** * @brief Set to true by TraceSignal() to request a CONFIG re-send. * Read and cleared by the Streamer thread. */ volatile bool udpsConfigPending; }; } // namespace MARTe #endif // DEBUGSERVICE_H