feat(tcp): TCPStreamer DataSources, in-process TCPStreamService, stream multiplexing and TCPStreamJoin

Add TCPStreamer/TCPStreamerClient (TCP transport behind the UDPSServerI/UDPSClientI
seam), an optional single in-process TCPStreamService serving many streams over
worker threads, multiplexed SUBSCRIBE (comma list, stream index in fragmentIdx),
and TCPStreamJoin, which merges several streams into one sample-and-hold stream
paced by a master. StreamHub takes a comma list of streams over one connection.
Includes GTests, E2E scenarios s58-s73 and docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Martino FerrariandClaude Opus 4.6 committed 2026-11-06 13:41:27 +01:00
1 parent 5562877c99
commit 50d85363a3
79 files changed
+12348 -138

No files matched your search

+34 -3
View File
@@ -231,11 +231,27 @@ private:
* @return true if the session was started.
*/
bool AddSourceInternal(const char *label, const char *addrPort,
const char *mcGroup, uint16 dataPort);
const char *mcGroup, uint16 dataPort,
const char *transport = "udp",
const char *streamName = "");
/**
* @brief TCP source whose streamName is a comma separated list "a,b,c": one
* TCPSClient (one socket) feeds one session per stream, labelled
* "<label>_<stream>" (just "<stream>" without a label). Session ids are
* "s<N>", or "<idPrefix>_<stream>" when @p idPrefix (the config node id) is given.
* @return true if every session was started (none is left behind otherwise).
*/
bool AddMuxSourceInternal(const char *label, const char *host, uint32 port,
const char *addrPort, const char *streamList,
const char *idPrefix = static_cast<const char *>(0));
/** @brief Detach @p slot from its shared receiver; frees the receiver with its last session. */
void ReleaseMuxSlot(uint32 slot);
/**
* @brief Load sources and calibration from sourcesFile_ (a flat JSON array
* of {"label","addr","multicastGroup","dataPort"} source blocks and
* of {"label","addr","multicastGroup","dataPort","transport","streamName"} source blocks and
* {"source","signal","scale","offset","unit"} calibration blocks).
* @param skipActive when true, a source whose "host:port" is already
* streaming is left alone instead of being started a second time.
@@ -247,7 +263,7 @@ private:
bool LoadSourcesFile(bool skipActive, bool clearCalibration = false);
/** @return true if a session for this "host:port" is already active. */
bool SourceIsActive(const char *addrPort);
bool SourceIsActive(const char *addrPort, const char *streamName = "");
/**
* @brief Store or replace one calibration entry. An identity entry
@@ -280,6 +296,21 @@ private:
/* ---- Members --------------------------------------------------------- */
/** A multiplexed receiver shared by several sessions (deleted with the last one). */
struct MuxClient {
MuxClient() : client(static_cast<MARTe::TCPSClient *>(0)), refs(0u) {}
~MuxClient() { delete client; }
MARTe::TCPSClient *client;
uint32 refs;
private:
MuxClient(const MuxClient &);
MuxClient &operator=(const MuxClient &);
};
/* Declared before sessions_ so it is destroyed after them: a session stops
* its (facade of a) shared receiver from its own destructor. */
MuxClient muxClients_[kMaxSessions];
MARTe::int32 sessionMux_[kMaxSessions]; ///< Index into muxClients_, or -1
UDPSourceSession sessions_[kMaxSessions];
uint32 numSessions_; ///< Count of active sessions (not an upper slot bound)
bool sessionActive_[kMaxSessions]; ///< Per-slot in-use flag (slots are not compacted on removal)