Implemented DebugService with TCPLogger injection

This commit is contained in:
Martino Ferrari
2026-04-09 22:22:39 +02:00
parent b86ede99b9
commit 96d98dfc3d
9 changed files with 894 additions and 245 deletions
@@ -35,6 +35,11 @@ TcpLogger::~TcpLogger() {
clientsMutex.FastUnLock();
}
bool TcpLogger::ExportData(StructuredDataI & data) {
bool ok = data.Write("Port", static_cast<uint32>(port));
return ok;
}
bool TcpLogger::Initialise(StructuredDataI & data) {
if (!ReferenceContainer::Initialise(data)) return false;
@@ -92,64 +97,66 @@ ErrorManagement::ErrorType TcpLogger::Execute(ExecutionInfo & info) {
return ErrorManagement::NoError;
}
while (info.GetStage() == ExecutionInfo::MainStage) {
// 1. Check for new connections
BasicTCPSocket *newClient = server.WaitConnection(1);
if (newClient != NULL_PTR(BasicTCPSocket *)) {
clientsMutex.FastLock();
bool added = false;
for (uint32 i=0; i<MAX_CLIENTS; i++) {
if (activeClients[i] == NULL_PTR(BasicTCPSocket*)) {
activeClients[i] = newClient;
added = true;
break;
}
}
clientsMutex.FastUnLock();
if (!added) {
newClient->Close();
delete newClient;
} else {
(void)newClient->SetBlocking(false);
// Each Execute() call does one cycle. The MARTe2 framework loops Execute()
// so we must NOT spin in an infinite internal loop here — doing so prevents
// the framework from ever delivering the TerminationStage and causes
// Stop() to time out, leaving threads running after the destructor.
// 1. Check for new connections (1 ms timeout → returns promptly)
BasicTCPSocket *newClient = server.WaitConnection(1);
if (newClient != NULL_PTR(BasicTCPSocket *)) {
clientsMutex.FastLock();
bool added = false;
for (uint32 i=0; i<MAX_CLIENTS; i++) {
if (activeClients[i] == NULL_PTR(BasicTCPSocket*)) {
activeClients[i] = newClient;
added = true;
break;
}
}
// 2. Stream data to clients
bool hadData = false;
while (readIdx != writeIdx) {
hadData = true;
uint32 idx = readIdx % QUEUE_SIZE;
TcpLogEntry &entry = queue[idx];
StreamString level;
ErrorManagement::ErrorCodeToStream(entry.info.header.errorType, level);
StreamString packet;
packet.Printf("LOG %s %s\n", level.Buffer(), entry.description);
uint32 size = packet.Size();
clientsMutex.FastLock();
for (uint32 j=0; j<MAX_CLIENTS; j++) {
if (activeClients[j] != NULL_PTR(BasicTCPSocket*)) {
uint32 s = size;
if (!activeClients[j]->Write(packet.Buffer(), s)) {
activeClients[j]->Close();
delete activeClients[j];
activeClients[j] = NULL_PTR(BasicTCPSocket*);
}
}
}
clientsMutex.FastUnLock();
readIdx = (readIdx + 1) % QUEUE_SIZE;
}
if (!hadData) {
(void)eventSem.Wait(TimeoutType(100));
eventSem.Reset();
clientsMutex.FastUnLock();
if (!added) {
newClient->Close();
delete newClient;
} else {
Sleep::MSec(1);
(void)newClient->SetBlocking(false);
}
}
// 2. Stream queued entries to clients
bool hadData = false;
while (readIdx != writeIdx) {
hadData = true;
uint32 idx = readIdx % QUEUE_SIZE;
TcpLogEntry &entry = queue[idx];
StreamString level;
ErrorManagement::ErrorCodeToStream(entry.info.header.errorType, level);
StreamString packet;
packet.Printf("LOG %s %s\n", level.Buffer(), entry.description);
uint32 size = packet.Size();
clientsMutex.FastLock();
for (uint32 j=0; j<MAX_CLIENTS; j++) {
if (activeClients[j] != NULL_PTR(BasicTCPSocket*)) {
uint32 s = size;
if (!activeClients[j]->Write(packet.Buffer(), s)) {
activeClients[j]->Close();
delete activeClients[j];
activeClients[j] = NULL_PTR(BasicTCPSocket*);
}
}
}
clientsMutex.FastUnLock();
readIdx = (readIdx + 1) % QUEUE_SIZE;
}
if (!hadData) {
// Brief wait so we don't busy-spin; return so Stop() can take effect
(void)eventSem.Wait(TimeoutType(10));
eventSem.Reset();
}
return ErrorManagement::NoError;
}