Files
2026-07-02 10:10:57 +02:00

192 lines
7.2 KiB
C++

#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<Message> &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();
/**
* @brief Stamp the current udpsDataPayload with an HRT timestamp and send
* it as one UDPS DATA packet.
* @details Factored out of Streamer() so a single drain pass of
* traceBuffer can flush more than once per tick — see the
* pendingInDrain guard in Streamer(): without an eager flush, a
* slot that is written twice within the same drain pass (e.g.
* because the Streamer thread was briefly descheduled and two
* RT cycles' worth of samples piled up in traceBuffer) would
* silently overwrite-and-lose the first of the two samples,
* defeating lossless tracing.
*/
void FlushUdpsFrame();
// -----------------------------------------------------------------------
// 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 <token>". 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