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

@@ -131,7 +131,8 @@ static float64 DequantValue(float64 raw, uint8 quantType,
UDPStreamerClient::UDPStreamerClient() :
MemoryDataSourceI(),
UDPSClientListener(),
client() {
client(NULL_PTR(UDPSClientI *)) {
client = new UDPSClient();
serverAddress = UDPS_CLIENT_DEFAULT_ADDR;
port = UDPS_CLIENT_DEFAULT_PORT;
maxPayloadSize = UDPS_CLIENT_DEFAULT_MAX_PAYLOAD;
@@ -160,9 +161,13 @@ UDPStreamerClient::UDPStreamerClient() :
UDPStreamerClient::~UDPStreamerClient() {
(void) dataSem.Post();
if (receiverUp) {
(void) client.Stop();
receiverUp = false;
if (client != NULL_PTR(UDPSClientI *)) {
if (receiverUp) {
(void) client->Stop();
receiverUp = false;
}
delete client;
client = NULL_PTR(UDPSClientI *);
}
HeapI *heap = GlobalObjectsDatabase::Instance()->GetStandardHeap();
@@ -258,36 +263,49 @@ bool UDPStreamerClient::Initialise(StructuredDataI &data) {
}
}
/* Forward the transport parameters to the shared UDPSClient receiver,
* translating the DataSource parameter names to the UDPSClient keys. */
if (ok) {
ConfigurationDatabase cdb;
ok = cdb.Write("ServerAddr", serverAddress);
if (ok) { ok = cdb.Write("Port", static_cast<uint32>(port)); }
if (ok && useMulticast) {
ok = cdb.Write("MulticastGroup", multicastGroup);
if (ok) { ok = cdb.Write("DataPort", static_cast<uint32>(dataPort)); }
if (ok && (multicastInterface.Size() > 0u)) {
ok = cdb.Write("Interface", multicastInterface);
}
}
if (ok) { ok = cdb.Write("MaxPayloadSize", maxPayloadSize); }
if (ok) { ok = cdb.Write("KeepAliveInterval", keepAliveInterval); }
if (ok) { ok = cdb.Write("SilenceTimeout", silenceTimeout); }
if (ok) { ok = cdb.Write("CPUMask", cpuMask); }
if (ok) { ok = cdb.Write("StackSize", stackSize); }
if (ok) { ok = cdb.MoveToRoot(); }
if (ok) { ok = client.Initialise(cdb); }
if (!ok) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Could not configure the UDPSClient receiver.");
}
client.SetListener(this);
ok = InitialiseTransport(data);
}
return ok;
}
bool UDPStreamerClient::InitialiseTransport(StructuredDataI &data) {
/* Forward the transport parameters to the shared UDPSClient receiver,
* translating the DataSource parameter names to the UDPSClient keys. */
bool ok = true;
ConfigurationDatabase cdb;
ok = cdb.Write("ServerAddr", serverAddress);
if (ok) { ok = cdb.Write("Port", static_cast<uint32>(port)); }
if (ok && useMulticast) {
ok = cdb.Write("MulticastGroup", multicastGroup);
if (ok) { ok = cdb.Write("DataPort", static_cast<uint32>(dataPort)); }
if (ok && (multicastInterface.Size() > 0u)) {
ok = cdb.Write("Interface", multicastInterface);
}
}
if (ok) { ok = cdb.Write("MaxPayloadSize", maxPayloadSize); }
if (ok) { ok = cdb.Write("KeepAliveInterval", keepAliveInterval); }
if (ok) { ok = cdb.Write("SilenceTimeout", silenceTimeout); }
if (ok) { ok = cdb.Write("CPUMask", cpuMask); }
if (ok) { ok = cdb.Write("StackSize", stackSize); }
if (ok) { ok = cdb.MoveToRoot(); }
if (ok) { ok = client->Initialise(cdb); }
if (!ok) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Could not configure the UDPSClient receiver.");
}
client->SetListener(this);
return ok;
}
void UDPStreamerClient::SetClient(UDPSClientI *newClient) {
if (client != NULL_PTR(UDPSClientI *)) {
delete client;
}
client = newClient;
}
bool UDPStreamerClient::SetConfiguredDatabase(StructuredDataI &data) {
bool ok = MemoryDataSourceI::SetConfiguredDatabase(data);
if (!ok) {
@@ -377,7 +395,7 @@ bool UDPStreamerClient::PrepareNextState(const char8 *const currentStateName,
const char8 *const nextStateName) {
bool ok = true;
if (!receiverUp) {
ok = client.Start();
ok = client->Start();
if (ok) {
receiverUp = true;
}