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

@@ -51,6 +51,8 @@ UDPSourceSession::UDPSourceSession()
ringTemporal_(1000000u),
ringScalar_(100000u),
initialised_(false),
client_(static_cast<MARTe::UDPSClientI *>(0)),
external_(false),
numSignals_(0u),
publishMode_(0u),
configured_(false),
@@ -112,7 +114,10 @@ bool UDPSourceSession::Initialise(const char *id, const char *label,
const char *addr, uint16 port,
uint32 maxPts,
const char *mcGroup,
uint16 dataPort) {
uint16 dataPort,
const char *transport,
const char *streamName,
MARTe::UDPSClientI *external) {
(void) Stop();
id_ = id;
@@ -121,25 +126,42 @@ bool UDPSourceSession::Initialise(const char *id, const char *label,
port_ = port;
mcGroup_ = (mcGroup != static_cast<const char *>(0)) ? mcGroup : "";
dataPort_ = dataPort;
transport_ = ((transport != static_cast<const char *>(0)) && (strcmp(transport, "tcp") == 0)) ? "tcp" : "udp";
streamName_ = (streamName != static_cast<const char *>(0)) ? streamName : "";
maxPoints_ = (maxPts > 0u) ? maxPts : 20000u;
/* Build ConfigurationDatabase for UDPSClient */
ConfigurationDatabase cfg;
(void) cfg.Write("ServerAddr", addr);
(void) cfg.Write("Port", static_cast<uint32>(port));
if ((mcGroup != static_cast<const char *>(0)) && (strlen(mcGroup) > 0u)) {
const bool useTcp = (transport_ == "tcp");
if (useTcp) {
if (streamName_.Size() > 0u) {
(void) cfg.Write("StreamName", streamName_.Buffer());
}
} else if ((mcGroup != static_cast<const char *>(0)) && (strlen(mcGroup) > 0u)) {
(void) cfg.Write("MulticastGroup", mcGroup);
if (dataPort > 0u) {
(void) cfg.Write("DataPort", static_cast<uint32>(dataPort));
}
}
if (!client_.Initialise(cfg)) {
external_ = (external != static_cast<MARTe::UDPSClientI *>(0));
if (external_) {
client_ = external; /* already configured by its owner */
}
else {
client_ = useTcp ? static_cast<MARTe::UDPSClientI *>(&tcpClient_)
: static_cast<MARTe::UDPSClientI *>(&udpClient_);
}
if (!external_ && !client_->Initialise(cfg)) {
REPORT_ERROR_STATIC(MARTe::ErrorManagement::FatalError,
"UDPSourceSession[%s]: Failed to initialise UDPSClient.", id);
"UDPSourceSession[%s]: Failed to initialise %s client.",
id, useTcp ? "TCPSClient" : "UDPSClient");
client_ = static_cast<MARTe::UDPSClientI *>(0);
return false;
}
client_.SetListener(this);
client_->SetListener(this);
(void) metaMutex_.FastLock();
numSignals_ = 0u;
@@ -165,12 +187,22 @@ bool UDPSourceSession::Start() {
statByteCount_ = 0u;
stateStr_ = "connecting";
statsMutex_.FastUnLock();
return client_.Start();
return client_->Start();
}
void UDPSourceSession::DetachClient() {
if (!external_) { return; }
(void) Stop();
if (client_ != static_cast<MARTe::UDPSClientI *>(0)) {
client_->SetListener(static_cast<MARTe::UDPSClientListener *>(0));
}
client_ = static_cast<MARTe::UDPSClientI *>(0);
external_ = false;
}
bool UDPSourceSession::Stop() {
if (!initialised_) { return true; }
return client_.Stop();
if (!initialised_ || (client_ == static_cast<MARTe::UDPSClientI *>(0))) { return true; }
return client_->Stop();
}
/*---------------------------------------------------------------------------*/
@@ -200,7 +232,7 @@ void UDPSourceSession::OnUDPSConfig(const uint8 *payload, uint32 payloadSize) {
void UDPSourceSession::OnUDPSData(const uint8 *payload, uint32 payloadSize) {
/* Valid only for the duration of this callback. */
ParseDataPayload(payload, payloadSize, client_.GetLastDataGap());
ParseDataPayload(payload, payloadSize, client_->GetLastDataGap());
}
/*---------------------------------------------------------------------------*/
@@ -947,6 +979,10 @@ StreamString UDPSourceSession::GetMulticastGroup() const { return mcGroup_; }
uint16 UDPSourceSession::GetDataPort() const { return dataPort_; }
StreamString UDPSourceSession::GetTransport() const { return transport_; }
StreamString UDPSourceSession::GetStreamName() const { return streamName_; }
bool UDPSourceSession::IsConfigured() const {
(void) metaMutex_.FastLock();
bool c = configured_;