192 lines
7.2 KiB
C++
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
|