Implemetned better buffering and high frequency tracing

This commit is contained in:
Martino Ferrari
2026-02-23 12:00:14 +01:00
parent 253a4989f9
commit 6b1fc59fc0
4 changed files with 193 additions and 162 deletions

View File

@@ -7,201 +7,166 @@
#include "BasicTCPSocket.h"
#include "RealTimeApplication.h"
#include "GlobalObjectsDatabase.h"
#include "RealTimeLoader.h"
#include <assert.h>
#include <stdio.h>
using namespace MARTe;
const char8 * const config_text =
"+DebugService = {"
// Removed '+' prefix from names for simpler lookup
const char8 * const simple_config =
"DebugService = {"
" Class = DebugService "
" ControlPort = 8080 "
" UdpPort = 8081 "
" StreamIP = \"127.0.0.1\" "
"}"
"+App = {"
"App = {"
" Class = RealTimeApplication "
" +Functions = {"
" Class = ReferenceContainer "
" +GAM1 = {"
" Class = IOGAM "
" InputSignals = {"
" Counter = {"
" DataSource = Timer "
" Type = uint32 "
" Frequency = 100 "
" }"
" Counter = { DataSource = Timer Type = uint32 Frequency = 1000 }"
" Time = { DataSource = Timer Type = uint32 }"
" }"
" OutputSignals = {"
" Counter = {"
" DataSource = DDB "
" Type = uint32 "
" }"
" Counter = { DataSource = DDB Type = uint32 }"
" Time = { DataSource = DDB Type = uint32 }"
" }"
" }"
" }"
" +Data = {"
" Class = ReferenceContainer "
" DefaultDataSource = DDB "
" +Timer = {"
" Class = LinuxTimer "
" SleepTime = 10000 "
" Signals = {"
" Counter = { Type = uint32 }"
" Time = { Type = uint32 }"
" }"
" }"
" +DDB = {"
" Class = GAMDataSource "
" Signals = { Counter = { Type = uint32 } }"
" }"
" +Timer = { Class = LinuxTimer SleepTime = 1000 Signals = { Counter = { Type = uint32 } Time = { Type = uint32 } } }"
" +DDB = { Class = GAMDataSource Signals = { Counter = { Type = uint32 } Time = { Type = uint32 } } }"
" +DAMS = { Class = TimingDataSource }"
" }"
" +States = {"
" Class = ReferenceContainer "
" +State1 = {"
" Class = RealTimeState "
" +Threads = {"
" Class = ReferenceContainer "
" +Thread1 = {"
" Class = RealTimeThread "
" Functions = {GAM1} "
" }"
" }"
" }"
" }"
" +Scheduler = {"
" Class = GAMScheduler "
" TimingDataSource = DAMS "
" +State1 = { Class = RealTimeState +Threads = { Class = ReferenceContainer +Thread1 = { Class = RealTimeThread Functions = {GAM1} } } }"
" }"
" +Scheduler = { Class = GAMScheduler TimingDataSource = DAMS }"
"}";
void RunValidationTest() {
printf("--- MARTe2 100Hz Trace Validation Test ---\n");
printf("--- MARTe2 1kHz Lossless Trace Validation Test ---\n");
ObjectRegistryDatabase::Instance()->Purge();
ConfigurationDatabase cdb;
StreamString ss = config_text;
StreamString ss = simple_config;
ss.Seek(0);
StandardParser parser(ss, cdb);
if (!parser.Parse()) {
printf("ERROR: Failed to parse configuration\n");
return;
}
assert(parser.Parse());
if (!ObjectRegistryDatabase::Instance()->Initialise(cdb)) {
printf("ERROR: Failed to initialise ObjectRegistryDatabase.\n");
return;
}
ReferenceT<DebugService> service = ObjectRegistryDatabase::Instance()->Find("DebugService");
if (!service.IsValid()) {
printf("ERROR: DebugService not found\n");
return;
}
ReferenceT<RealTimeApplication> app = ObjectRegistryDatabase::Instance()->Find("App");
if (!app.IsValid()) {
printf("ERROR: App not found\n");
return;
}
if (!app->ConfigureApplication()) {
printf("ERROR: Failed to configure application\n");
return;
}
if (app->PrepareNextState("State1") != ErrorManagement::NoError) {
printf("ERROR: Failed to prepare state State1\n");
return;
}
if (app->StartNextStateExecution() != ErrorManagement::NoError) {
printf("ERROR: Failed to start execution\n");
return;
}
printf("Application and DebugService are active.\n");
Sleep::MSec(1000);
// DIRECT ACTIVATION: Use the public TraceSignal method
printf("Activating trace directly...\n");
// We try multiple potential paths to be safe
uint32 traceCount = 0;
traceCount += service->TraceSignal("App.Data.Timer.Counter", true, 1);
traceCount += service->TraceSignal("Timer.Counter", true, 1);
traceCount += service->TraceSignal("Counter", true, 1);
printf("Trace enabled (Matched Aliases: %u)\n", traceCount);
// 4. Setup UDP Listener
BasicUDPSocket listener;
if (!listener.Open()) { printf("ERROR: Failed to open UDP socket\n"); return; }
if (!listener.Listen(8081)) { printf("ERROR: Failed to listen on UDP 8081\n"); return; }
// 5. Validate for 10 seconds
printf("Validating telemetry for 10 seconds...\n");
uint32 lastVal = 0;
bool first = true;
uint32 packetCount = 0;
uint32 discontinuityCount = 0;
float64 startTime = HighResolutionTimer::Counter() * HighResolutionTimer::Period();
float64 globalTimeout = startTime + 30.0;
while ((HighResolutionTimer::Counter() * HighResolutionTimer::Period() - startTime) < 10.0) {
if (HighResolutionTimer::Counter() * HighResolutionTimer::Period() > globalTimeout) {
printf("CRITICAL ERROR: Global test timeout reached.\n");
break;
}
char buffer[2048];
uint32 size = 2048;
TimeoutType timeout(200);
cdb.MoveToRoot();
uint32 n = cdb.GetNumberOfChildren();
for (uint32 i=0; i<n; i++) {
const char8* name = cdb.GetChildName(i);
ConfigurationDatabase child;
cdb.MoveRelative(name);
cdb.Copy(child);
cdb.MoveToAncestor(1u);
if (listener.Read(buffer, size, timeout)) {
StreamString className;
child.Read("Class", className);
Reference ref(className.Buffer(), GlobalObjectsDatabase::Instance()->GetStandardHeap());
ref->SetName(name);
assert(ref->Initialise(child));
ObjectRegistryDatabase::Instance()->Insert(ref);
}
Reference serviceGeneric = ObjectRegistryDatabase::Instance()->Find("DebugService");
Reference appGeneric = ObjectRegistryDatabase::Instance()->Find("App");
if (!serviceGeneric.IsValid() || !appGeneric.IsValid()) {
printf("ERROR: Objects NOT FOUND even without prefix\n");
return;
}
DebugService *service = dynamic_cast<DebugService*>(serviceGeneric.operator->());
RealTimeApplication *app = dynamic_cast<RealTimeApplication*>(appGeneric.operator->());
assert(service);
assert(app);
if (!app->ConfigureApplication()) {
printf("ERROR: ConfigureApplication failed.\n");
return;
}
assert(app->PrepareNextState("State1") == ErrorManagement::NoError);
assert(app->StartNextStateExecution() == ErrorManagement::NoError);
printf("Application started at 1kHz. Enabling Traces...\n");
Sleep::MSec(500);
// The registered name in DebugBrokerWrapper depends on GetFullObjectName
// With App as root, it should be App.Data.Timer.Counter
service->TraceSignal("App.Data.Timer.Counter", true, 1);
BasicUDPSocket listener;
listener.Open();
listener.Listen(8081);
printf("Validating for 10 seconds...\n");
uint32 lastCounter = 0;
bool first = true;
uint32 totalSamples = 0;
uint32 discontinuities = 0;
uint32 totalPackets = 0;
float64 startTest = HighResolutionTimer::Counter() * HighResolutionTimer::Period();
while ((HighResolutionTimer::Counter() * HighResolutionTimer::Period() - startTest) < 10.0) {
char buffer[4096];
uint32 size = 4096;
if (listener.Read(buffer, size, TimeoutType(100))) {
totalPackets++;
TraceHeader *h = (TraceHeader*)buffer;
if (h->magic == 0xDA7A57AD && h->count > 0) {
uint32 offset = sizeof(TraceHeader);
// Packet format: [Header][ID:4][Size:4][Value:N]
if (h->magic != 0xDA7A57AD) continue;
uint32 offset = sizeof(TraceHeader);
for (uint32 i=0; i<h->count; i++) {
uint32 sigId = *(uint32*)(&buffer[offset]);
uint32 val = *(uint32*)(&buffer[offset + 8]);
if (!first) {
if (val != lastVal + 1) {
discontinuityCount++;
if (sigId == 0) {
if (!first) {
if (val != lastCounter + 1) {
discontinuities++;
}
}
lastCounter = val;
totalSamples++;
}
lastVal = val;
first = false;
packetCount++;
if (packetCount % 200 == 0) {
printf("Received %u packets... Current Value: %u\n", packetCount, val);
}
uint32 sigSize = *(uint32*)(&buffer[offset + 4]);
offset += (8 + sigSize);
}
first = false;
}
}
printf("Test Finished.\n");
printf("Total Packets Received: %u (Expected ~1000)\n", packetCount);
printf("Discontinuities: %u\n", discontinuityCount);
float64 actualFreq = (float64)packetCount / 10.0;
printf("Average Frequency: %.2f Hz\n", actualFreq);
printf("\n--- Test Results ---\n");
printf("Total UDP Packets: %u\n", totalPackets);
printf("Total Counter Samples: %u\n", totalSamples);
printf("Counter Discontinuities: %u\n", discontinuities);
if (packetCount < 100) {
printf("FAILURE: Almost no packets received. Telemetry is broken.\n");
} else if (packetCount < 800) {
printf("WARNING: Too few packets received (Expected 1000, Got %u).\n", packetCount);
} else if (discontinuityCount > 20) {
printf("FAILURE: Too many discontinuities (%u).\n", discontinuityCount);
if (totalSamples < 9000) {
printf("FAILURE: Underflow - samples missing (%u).\n", totalSamples);
} else if (discontinuities > 10) {
printf("FAILURE: Excessive discontinuities detected! (%u)\n", discontinuities);
} else {
printf("VALIDATION SUCCESSFUL!\n");
printf("VALIDATION SUCCESSFUL: 1kHz Lossless Tracing Verified.\n");
}
app->StopCurrentStateExecution();
listener.Close();
ObjectRegistryDatabase::Instance()->Purge();
}