Compare commits
9 Commits
1af42f5475
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 567ebda9cb | |||
| b900f50d99 | |||
| 572009fa1d | |||
| bceab8607c | |||
| 58abf98eea | |||
| 74816028a8 | |||
| f6eb0a7056 | |||
| d967098ead | |||
| 242b1c4406 |
@@ -7,3 +7,5 @@ bin/
|
||||
dependency/
|
||||
.cache/
|
||||
target/
|
||||
CLAUDE.md
|
||||
Tools/go_web_client/marte2-web-client
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "ObjectBuilder.h"
|
||||
#include "ObjectRegistryDatabase.h"
|
||||
#include "Threads.h"
|
||||
#include "Vec.h"
|
||||
|
||||
// Original broker headers
|
||||
#include "MemoryMapAsyncOutputBroker.h"
|
||||
@@ -105,10 +104,10 @@ public:
|
||||
|
||||
static void Process(DebugServiceI *service,
|
||||
DebugSignalInfo **signalInfoPointers,
|
||||
Vec<uint32> &activeIndices, Vec<uint32> &activeSizes,
|
||||
Vector<uint32> &activeIndices, Vector<uint32> &activeSizes,
|
||||
FastPollingMutexSem &activeMutex,
|
||||
volatile bool *anyBreakFlag,
|
||||
Vec<uint32> *breakIndices) {
|
||||
Vector<uint32> *breakIndices) {
|
||||
if (service == NULL_PTR(DebugServiceI *))
|
||||
return;
|
||||
|
||||
@@ -117,7 +116,7 @@ public:
|
||||
// because that prevents cross-thread EventSem posts from completing.
|
||||
|
||||
activeMutex.FastLock();
|
||||
uint32 n = activeIndices.Size();
|
||||
uint32 n = activeIndices.GetNumberOfElements();
|
||||
if (n > 0 && signalInfoPointers != NULL_PTR(DebugSignalInfo **)) {
|
||||
// Capture timestamp ONCE per broker cycle for lowest impact
|
||||
uint64 ts = (uint64)((float64)HighResolutionTimer::Counter() *
|
||||
@@ -139,13 +138,13 @@ public:
|
||||
// stall would block UpdateBrokersBreakStatus() in the Server thread and
|
||||
// cause unnecessary priority inversion on the RT path.
|
||||
bool shouldCheckBreak = (*anyBreakFlag && !service->IsPaused() &&
|
||||
breakIndices != NULL_PTR(Vec<uint32> *) &&
|
||||
breakIndices != NULL_PTR(Vector<uint32> *) &&
|
||||
signalInfoPointers != NULL_PTR(DebugSignalInfo **));
|
||||
static const uint32 MAX_BREAK_INDICES = 64u;
|
||||
uint32 localBreakIdx[MAX_BREAK_INDICES];
|
||||
uint32 nb = 0u;
|
||||
if (shouldCheckBreak) {
|
||||
nb = breakIndices->Size();
|
||||
nb = breakIndices->GetNumberOfElements();
|
||||
if (nb > MAX_BREAK_INDICES) nb = MAX_BREAK_INDICES;
|
||||
for (uint32 i = 0; i < nb; i++) {
|
||||
localBreakIdx[i] = (*breakIndices)[i];
|
||||
@@ -176,9 +175,9 @@ public:
|
||||
DebugServiceI *&service, DebugSignalInfo **&signalInfoPointers,
|
||||
uint32 numCopies, MemoryMapBrokerCopyTableEntry *copyTable,
|
||||
const char8 *functionName, SignalDirection direction,
|
||||
volatile bool *anyActiveFlag, Vec<uint32> *activeIndices,
|
||||
Vec<uint32> *activeSizes, FastPollingMutexSem *activeMutex,
|
||||
volatile bool *anyBreakFlag, Vec<uint32> *breakIndices) {
|
||||
volatile bool *anyActiveFlag, Vector<uint32> *activeIndices,
|
||||
Vector<uint32> *activeSizes, FastPollingMutexSem *activeMutex,
|
||||
volatile bool *anyBreakFlag, Vector<uint32> *breakIndices) {
|
||||
if (numCopies > 0) {
|
||||
signalInfoPointers = new DebugSignalInfo *[numCopies];
|
||||
for (uint32 i = 0; i < numCopies; i++)
|
||||
@@ -352,9 +351,9 @@ public:
|
||||
volatile bool anyBreakActive;
|
||||
bool isOutput;
|
||||
char8 gamName[256];
|
||||
Vec<uint32> activeIndices;
|
||||
Vec<uint32> activeSizes;
|
||||
Vec<uint32> breakIndices;
|
||||
Vector<uint32> activeIndices;
|
||||
Vector<uint32> activeSizes;
|
||||
Vector<uint32> breakIndices;
|
||||
FastPollingMutexSem activeMutex;
|
||||
};
|
||||
|
||||
@@ -412,9 +411,9 @@ public:
|
||||
volatile bool anyBreakActive;
|
||||
bool isOutput;
|
||||
char8 gamName[256];
|
||||
Vec<uint32> activeIndices;
|
||||
Vec<uint32> activeSizes;
|
||||
Vec<uint32> breakIndices;
|
||||
Vector<uint32> activeIndices;
|
||||
Vector<uint32> activeSizes;
|
||||
Vector<uint32> breakIndices;
|
||||
FastPollingMutexSem activeMutex;
|
||||
};
|
||||
|
||||
@@ -471,9 +470,9 @@ public:
|
||||
volatile bool anyActive;
|
||||
volatile bool anyBreakActive;
|
||||
char8 gamName[256];
|
||||
Vec<uint32> activeIndices;
|
||||
Vec<uint32> activeSizes;
|
||||
Vec<uint32> breakIndices;
|
||||
Vector<uint32> activeIndices;
|
||||
Vector<uint32> activeSizes;
|
||||
Vector<uint32> breakIndices;
|
||||
FastPollingMutexSem activeMutex;
|
||||
};
|
||||
|
||||
@@ -531,9 +530,9 @@ public:
|
||||
volatile bool anyActive;
|
||||
volatile bool anyBreakActive;
|
||||
char8 gamName[256];
|
||||
Vec<uint32> activeIndices;
|
||||
Vec<uint32> activeSizes;
|
||||
Vec<uint32> breakIndices;
|
||||
Vector<uint32> activeIndices;
|
||||
Vector<uint32> activeSizes;
|
||||
Vector<uint32> breakIndices;
|
||||
FastPollingMutexSem activeMutex;
|
||||
};
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ struct DebugSignalInfo {
|
||||
volatile bool isTracing;
|
||||
volatile bool isForcing;
|
||||
uint8 forcedValue[1024];
|
||||
uint8 forcedMask[32]; // bit e set → element e is forced; supports up to 256 elements
|
||||
uint32 internalID;
|
||||
volatile uint32 decimationFactor;
|
||||
volatile uint32 decimationCounter;
|
||||
|
||||
@@ -24,6 +24,10 @@ const uint32 DebugService::CMD_RATE_LIMIT;
|
||||
const uint32 DebugService::CLIENT_IDLE_TIMEOUT_MS;
|
||||
const uint32 DebugService::INPUT_BUFFER_MAX;
|
||||
|
||||
// Maximum data bytes that fit in one sample entry inside a datagram:
|
||||
// STREAMER_BUFFER_SIZE(65535) - TraceHeader(20) - entry_header(16) = 65499
|
||||
static const uint32 MAX_SAMPLE_DATA_SIZE = 65499u;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constructor / Destructor
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -313,12 +317,25 @@ ErrorManagement::ErrorType DebugService::Server(ExecutionInfo &info) {
|
||||
uint32 cmdLen = len;
|
||||
command.Write(raw + lineStart, cmdLen);
|
||||
|
||||
// Dispatch via base HandleCommand, write response to socket
|
||||
// Dispatch via base HandleCommand, write response to socket.
|
||||
// Loop to handle partial writes for large responses.
|
||||
StreamString out;
|
||||
HandleCommand(command, out);
|
||||
if (out.Size() > 0u) {
|
||||
uint32 outSz = out.Size();
|
||||
(void)activeClient->Write(out.Buffer(), outSz);
|
||||
const char8 *wPtr = out.Buffer();
|
||||
uint32 remaining = (uint32)out.Size();
|
||||
lastDataTimeMs = (uint64)((float64)HighResolutionTimer::Counter() *
|
||||
HighResolutionTimer::Period() * 1000.0);
|
||||
while (remaining > 0u) {
|
||||
uint32 wrote = remaining;
|
||||
if (!activeClient->Write(wPtr, wrote) || wrote == 0u) {
|
||||
break;
|
||||
}
|
||||
wPtr += wrote;
|
||||
remaining -= wrote;
|
||||
lastDataTimeMs = (uint64)((float64)HighResolutionTimer::Counter() *
|
||||
HighResolutionTimer::Period() * 1000.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
lineStart = pos + 1u;
|
||||
@@ -374,7 +391,7 @@ ErrorManagement::ErrorType DebugService::Streamer(ExecutionInfo &info) {
|
||||
uint64 currentTimeMs = (uint64)((float64)HighResolutionTimer::Counter() *
|
||||
HighResolutionTimer::Period() * 1000.0);
|
||||
mutex.FastLock();
|
||||
for (uint32 i = 0u; i < monitoredSignals.Size(); i++) {
|
||||
for (uint32 i = 0u; i < monitoredSignals.GetNumberOfElements(); i++) {
|
||||
if (currentTimeMs >= (monitoredSignals[i].lastPollTime +
|
||||
monitoredSignals[i].periodMs)) {
|
||||
monitoredSignals[i].lastPollTime = currentTimeMs;
|
||||
@@ -392,54 +409,62 @@ ErrorManagement::ErrorType DebugService::Streamer(ExecutionInfo &info) {
|
||||
}
|
||||
mutex.FastUnLock();
|
||||
|
||||
// Drain ring buffer into UDP packet(s)
|
||||
static const uint32 SAMPLE_BUF_SIZE = 1024u;
|
||||
typedef char StaticAssert_StreamerBufferTooSmall[
|
||||
(sizeof(TraceHeader) + 16u + SAMPLE_BUF_SIZE <= STREAMER_BUFFER_SIZE) ? 1 : -1];
|
||||
(void)sizeof(StaticAssert_StreamerBufferTooSmall);
|
||||
|
||||
// Drain ring buffer into UDP packet(s).
|
||||
//
|
||||
// Batching strategy:
|
||||
// - Normal samples (entry ≤ STREAMER_MTU): accumulate into a packet and
|
||||
// flush when the next sample would push it past STREAMER_MTU.
|
||||
// - Oversized samples (entry > STREAMER_MTU): flush any pending packet
|
||||
// first, then send the oversized sample as its own datagram (up to
|
||||
// STREAMER_BUFFER_SIZE bytes; handled transparently by IP fragmentation
|
||||
// on loopback / internal networks).
|
||||
// - MAX_SAMPLE_DATA_SIZE (65499 bytes) is the hard cap; larger entries
|
||||
// in the ring buffer are skipped by Pop() and discarded.
|
||||
bool hasData = false;
|
||||
uint32 id, size;
|
||||
uint64 ts;
|
||||
uint8 sampleData[SAMPLE_BUF_SIZE];
|
||||
bool hasData = false;
|
||||
|
||||
while (traceBuffer.Pop(id, ts, sampleData, size, SAMPLE_BUF_SIZE)) {
|
||||
while (traceBuffer.Pop(id, ts, streamerSampleBuffer, size, MAX_SAMPLE_DATA_SIZE)) {
|
||||
hasData = true;
|
||||
if (size > SAMPLE_BUF_SIZE ||
|
||||
streamerPacketOffset + 16u + size > STREAMER_BUFFER_SIZE) {
|
||||
REPORT_ERROR_STATIC(ErrorManagement::Warning,
|
||||
"Streamer: sample size %u would overflow assembly buffer "
|
||||
"(%u bytes used of %u) — sample dropped.",
|
||||
size, streamerPacketOffset, STREAMER_BUFFER_SIZE);
|
||||
continue;
|
||||
}
|
||||
if (streamerPacketOffset == 0u) {
|
||||
TraceHeader header;
|
||||
header.magic = 0xDA7A57ADu;
|
||||
header.seq = streamerSequenceNumber++;
|
||||
header.timestamp = HighResolutionTimer::Counter();
|
||||
header.count = 0u;
|
||||
memcpy(streamerPacketBuffer, &header, sizeof(TraceHeader));
|
||||
streamerPacketOffset = sizeof(TraceHeader);
|
||||
}
|
||||
if (streamerPacketOffset + 16u + size > STREAMER_MTU) {
|
||||
const uint32 entryBytes = 16u + size; // [id:4][ts:8][size:4][data:size]
|
||||
|
||||
// If this entry would push the current packet past the MTU target,
|
||||
// flush what we have before appending (unless the buffer is empty).
|
||||
if (streamerPacketOffset > 0u &&
|
||||
streamerPacketOffset + entryBytes > STREAMER_MTU) {
|
||||
uint32 toWrite = streamerPacketOffset;
|
||||
(void)udpSocket.Write((char8 *)streamerPacketBuffer, toWrite);
|
||||
TraceHeader header;
|
||||
header.magic = 0xDA7A57ADu;
|
||||
header.seq = streamerSequenceNumber++;
|
||||
header.timestamp = HighResolutionTimer::Counter();
|
||||
header.count = 0u;
|
||||
memcpy(streamerPacketBuffer, &header, sizeof(TraceHeader));
|
||||
streamerPacketOffset = sizeof(TraceHeader);
|
||||
streamerPacketOffset = 0u;
|
||||
}
|
||||
memcpy(&streamerPacketBuffer[streamerPacketOffset], &id, 4u);
|
||||
memcpy(&streamerPacketBuffer[streamerPacketOffset + 4u], &ts, 8u);
|
||||
|
||||
// Open a new packet header if the buffer is empty.
|
||||
if (streamerPacketOffset == 0u) {
|
||||
TraceHeader hdr;
|
||||
hdr.magic = 0xDA7A57ADu;
|
||||
hdr.seq = streamerSequenceNumber++;
|
||||
hdr.timestamp = HighResolutionTimer::Counter();
|
||||
hdr.count = 0u;
|
||||
memcpy(streamerPacketBuffer, &hdr, sizeof(TraceHeader));
|
||||
streamerPacketOffset = (uint32)sizeof(TraceHeader);
|
||||
}
|
||||
|
||||
// Append the sample entry.
|
||||
memcpy(&streamerPacketBuffer[streamerPacketOffset], &id, 4u);
|
||||
memcpy(&streamerPacketBuffer[streamerPacketOffset + 4u], &ts, 8u);
|
||||
memcpy(&streamerPacketBuffer[streamerPacketOffset + 12u], &size, 4u);
|
||||
memcpy(&streamerPacketBuffer[streamerPacketOffset + 16u], sampleData, size);
|
||||
streamerPacketOffset += (16u + size);
|
||||
memcpy(&streamerPacketBuffer[streamerPacketOffset + 16u], streamerSampleBuffer, size);
|
||||
streamerPacketOffset += entryBytes;
|
||||
((TraceHeader *)streamerPacketBuffer)->count++;
|
||||
|
||||
// Oversized single sample: send immediately rather than accumulating.
|
||||
if (streamerPacketOffset > STREAMER_MTU) {
|
||||
uint32 toWrite = streamerPacketOffset;
|
||||
(void)udpSocket.Write((char8 *)streamerPacketBuffer, toWrite);
|
||||
streamerPacketOffset = 0u;
|
||||
}
|
||||
}
|
||||
|
||||
// Flush any remaining partial packet.
|
||||
if (streamerPacketOffset > 0u) {
|
||||
uint32 toWrite = streamerPacketOffset;
|
||||
(void)udpSocket.Write((char8 *)streamerPacketBuffer, toWrite);
|
||||
|
||||
@@ -82,15 +82,22 @@ private:
|
||||
BasicTCPSocket *activeClient;
|
||||
|
||||
// Streamer assembly buffer
|
||||
// STREAMER_MTU: target packet size for batching small signals (network-friendly).
|
||||
// STREAMER_BUFFER_SIZE: maximum UDP datagram payload; large single-signal samples
|
||||
// can exceed STREAMER_MTU and are sent as their own datagram up to this limit.
|
||||
static const uint32 STREAMER_MTU = 1400u;
|
||||
static const uint32 STREAMER_BUFFER_SIZE = 4096u;
|
||||
uint8 streamerPacketBuffer[STREAMER_BUFFER_SIZE];
|
||||
static const uint32 STREAMER_BUFFER_SIZE = 65535u;
|
||||
uint8 streamerPacketBuffer[STREAMER_BUFFER_SIZE]; // assembled outgoing packet
|
||||
uint8 streamerSampleBuffer[STREAMER_BUFFER_SIZE]; // staging for one popped sample
|
||||
uint32 streamerPacketOffset;
|
||||
uint32 streamerSequenceNumber;
|
||||
|
||||
// Rate-limiting and idle-timeout constants / state
|
||||
static const uint32 CMD_RATE_LIMIT = 100u;
|
||||
static const uint32 CLIENT_IDLE_TIMEOUT_MS = 30000u;
|
||||
// Idle timeout: time with no incoming bytes before the connection is closed.
|
||||
// Large applications (1000+ signals) can take >30 s to process a DISCOVER/TREE
|
||||
// response, during which no commands are sent — use a generous default.
|
||||
static const uint32 CLIENT_IDLE_TIMEOUT_MS = 120000u;
|
||||
static const uint32 INPUT_BUFFER_MAX = 8192u;
|
||||
|
||||
uint32 cmdCountInWindow;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -52,11 +52,11 @@ public:
|
||||
uint32 numSignals,
|
||||
MemoryMapBroker *broker,
|
||||
volatile bool *anyActiveFlag,
|
||||
Vec<uint32> *activeIndices,
|
||||
Vec<uint32> *activeSizes,
|
||||
Vector<uint32> *activeIndices,
|
||||
Vector<uint32> *activeSizes,
|
||||
FastPollingMutexSem *activeMutex,
|
||||
volatile bool *anyBreakFlag,
|
||||
Vec<uint32> *breakIndices,
|
||||
Vector<uint32> *breakIndices,
|
||||
const char8 *gamName = NULL_PTR(const char8 *),
|
||||
bool isOutput = false);
|
||||
|
||||
@@ -125,6 +125,22 @@ public:
|
||||
|
||||
static const uint32 GET_VALUE_MAX_ELEMENTS = 256u;
|
||||
|
||||
/**
|
||||
* @brief Pre-build DISCOVER and TREE response caches.
|
||||
*
|
||||
* Called automatically by SetFullConfig() once the application is fully
|
||||
* initialised. After this point, DISCOVER and TREE are served from the
|
||||
* pre-built string with no mutex contention and no JSON generation cost.
|
||||
* Both caches are invalidated whenever a new signal is registered (which
|
||||
* normally only happens during broker init, before SetFullConfig).
|
||||
*/
|
||||
void BuildDiscoverCache();
|
||||
void BuildTreeCache();
|
||||
|
||||
// Number of signals per DISCOVER_PART TCP chunk. Responses larger than
|
||||
// this are split so the Go client can start parsing immediately.
|
||||
static const uint32 DISCOVER_CHUNK_SIGNALS = 256u;
|
||||
|
||||
protected:
|
||||
// =========================================================================
|
||||
// Virtual hooks for transport subclasses
|
||||
@@ -160,6 +176,7 @@ protected:
|
||||
|
||||
uint32 ExportTree(ReferenceContainer *container, StreamString &json,
|
||||
const char8 *pathPrefix);
|
||||
void ExportTreeNode(const char8 *path, StreamString &out);
|
||||
void EnrichWithConfig(const char8 *path, StreamString &json);
|
||||
static void JsonifyDatabase(ConfigurationDatabase &db, StreamString &json);
|
||||
|
||||
@@ -167,10 +184,10 @@ protected:
|
||||
// Shared data members
|
||||
// =========================================================================
|
||||
|
||||
Vec<DebugSignalInfo *> signals;
|
||||
Vec<SignalAlias> aliases;
|
||||
Vec<BrokerInfo> brokers;
|
||||
Vec<MonitoredSignal> monitoredSignals;
|
||||
Vector<DebugSignalInfo *> signals;
|
||||
Vector<SignalAlias> aliases;
|
||||
Vector<BrokerInfo> brokers;
|
||||
Vector<MonitoredSignal> monitoredSignals;
|
||||
|
||||
FastPollingMutexSem mutex;
|
||||
FastPollingMutexSem tracePushMutex;
|
||||
@@ -183,6 +200,13 @@ protected:
|
||||
|
||||
ConfigurationDatabase fullConfig;
|
||||
bool manualConfigSet;
|
||||
|
||||
// Pre-built response caches. Guarded by mutex (brief lock for swap,
|
||||
// none needed for reads once cacheValid is true and construction is done).
|
||||
StreamString discoverCache; // full chunked DISCOVER_PART+DISCOVER payload
|
||||
StreamString treeCache; // full TREE payload including sentinel
|
||||
volatile bool discoverCacheValid;
|
||||
volatile bool treeCacheValid;
|
||||
};
|
||||
|
||||
} // namespace MARTe
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "Object.h"
|
||||
#include "StreamString.h"
|
||||
#include "TypeDescriptor.h"
|
||||
#include "Vec.h"
|
||||
|
||||
namespace MARTe {
|
||||
|
||||
@@ -49,11 +48,11 @@ struct BrokerInfo {
|
||||
uint32 numSignals;
|
||||
MemoryMapBroker *broker;
|
||||
volatile bool *anyActiveFlag;
|
||||
Vec<uint32> *activeIndices;
|
||||
Vec<uint32> *activeSizes;
|
||||
Vector<uint32> *activeIndices;
|
||||
Vector<uint32> *activeSizes;
|
||||
FastPollingMutexSem *activeMutex;
|
||||
volatile bool *anyBreakFlag;
|
||||
Vec<uint32> *breakIndices;
|
||||
Vector<uint32> *breakIndices;
|
||||
StreamString gamName;
|
||||
bool isOutput;
|
||||
};
|
||||
@@ -124,11 +123,11 @@ public:
|
||||
uint32 numSignals,
|
||||
MemoryMapBroker *broker,
|
||||
volatile bool *anyActiveFlag,
|
||||
Vec<uint32> *activeIndices,
|
||||
Vec<uint32> *activeSizes,
|
||||
Vector<uint32> *activeIndices,
|
||||
Vector<uint32> *activeSizes,
|
||||
FastPollingMutexSem *activeMutex,
|
||||
volatile bool *anyBreakFlag,
|
||||
Vec<uint32> *breakIndices,
|
||||
Vector<uint32> *breakIndices,
|
||||
const char8 *gamName = NULL_PTR(const char8 *),
|
||||
bool isOutput = false) = 0;
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@ ROOT_DIR=../../../../
|
||||
MAKEDEFAULTDIR=$(MARTe2_DIR)/MakeDefaults
|
||||
include $(MAKEDEFAULTDIR)/MakeStdLibDefs.$(TARGET)
|
||||
|
||||
INCLUDES += -I$(ROOT_DIR)/Source/Core/Types/Result
|
||||
INCLUDES += -I$(ROOT_DIR)/Source/Core/Types/Vec
|
||||
INCLUDES += -I$(ROOT_DIR)/Source/Components/Interfaces/TCPLogger
|
||||
INCLUDES += -I$(ROOT_DIR)/Source/Components/Interfaces/DebugService
|
||||
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L0Types
|
||||
|
||||
@@ -451,7 +451,7 @@ ErrorManagement::ErrorType WebDebugService::Streamer(ExecutionInfo &info) {
|
||||
// Poll monitored signals → SSE monitor events
|
||||
// -----------------------------------------------------------------
|
||||
mutex.FastLock();
|
||||
for (uint32 i = 0u; i < monitoredSignals.Size(); i++) {
|
||||
for (uint32 i = 0u; i < monitoredSignals.GetNumberOfElements(); i++) {
|
||||
if (nowMs >= (monitoredSignals[i].lastPollTime +
|
||||
monitoredSignals[i].periodMs)) {
|
||||
monitoredSignals[i].lastPollTime = nowMs;
|
||||
@@ -468,7 +468,7 @@ ErrorManagement::ErrorType WebDebugService::Streamer(ExecutionInfo &info) {
|
||||
float64 val = WDS_ToFloat64(lb, td);
|
||||
|
||||
StreamString sigName;
|
||||
for (uint32 j = 0u; j < aliases.Size(); j++) {
|
||||
for (uint32 j = 0u; j < aliases.GetNumberOfElements(); j++) {
|
||||
if (signals[aliases[j].signalIndex]->internalID ==
|
||||
monitoredSignals[i].internalID) {
|
||||
sigName = aliases[j].name;
|
||||
@@ -499,24 +499,21 @@ ErrorManagement::ErrorType WebDebugService::Streamer(ExecutionInfo &info) {
|
||||
// -----------------------------------------------------------------
|
||||
// Drain ring buffer → SSE trace events
|
||||
// -----------------------------------------------------------------
|
||||
static const uint32 SAMPLE_BUF_SIZE = 1024u;
|
||||
static const uint32 MAX_TRACE_CYCLE = 50u;
|
||||
uint32 id, size;
|
||||
uint64 sampleTs;
|
||||
uint8 sampleData[SAMPLE_BUF_SIZE];
|
||||
bool hasData = false;
|
||||
uint32 traceCount = 0u;
|
||||
|
||||
while (traceCount < MAX_TRACE_CYCLE &&
|
||||
traceBuffer.Pop(id, sampleTs, sampleData, size, SAMPLE_BUF_SIZE)) {
|
||||
traceBuffer.Pop(id, sampleTs, traceSampleBuffer, size, TRACE_SAMPLE_MAX)) {
|
||||
hasData = true;
|
||||
traceCount++;
|
||||
if (size > SAMPLE_BUF_SIZE) continue;
|
||||
|
||||
StreamString sigName;
|
||||
TypeDescriptor sigType = UnsignedInteger32Bit;
|
||||
mutex.FastLock();
|
||||
for (uint32 i = 0u; i < signals.Size(); i++) {
|
||||
for (uint32 i = 0u; i < signals.GetNumberOfElements(); i++) {
|
||||
if (signals[i]->internalID == id) {
|
||||
sigName = signals[i]->name;
|
||||
sigType = signals[i]->type;
|
||||
@@ -527,7 +524,7 @@ ErrorManagement::ErrorType WebDebugService::Streamer(ExecutionInfo &info) {
|
||||
|
||||
uint32 tsMs = (sampleTs >= streamerT0Ns)
|
||||
? (uint32)((sampleTs - streamerT0Ns) / 1000000u) : 0u;
|
||||
float64 val = WDS_ToFloat64(sampleData, sigType);
|
||||
float64 val = WDS_ToFloat64(traceSampleBuffer, sigType);
|
||||
char8 valBuf[64] = { '\0' };
|
||||
{
|
||||
AnyType vdst(CharString, 0u, valBuf); vdst.SetNumberOfElements(0u, 63u);
|
||||
|
||||
@@ -97,6 +97,10 @@ private:
|
||||
uint32 logHistoryWriteIdx;
|
||||
uint32 logHistoryFill;
|
||||
FastPollingMutexSem logHistoryMutex;
|
||||
|
||||
// Staging buffer for trace ring-buffer pops (max UDP datagram payload).
|
||||
static const uint32 TRACE_SAMPLE_MAX = 65499u;
|
||||
uint8 traceSampleBuffer[TRACE_SAMPLE_MAX];
|
||||
};
|
||||
|
||||
} // namespace MARTe
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
include Makefile.inc
|
||||
@@ -1,46 +0,0 @@
|
||||
#############################################################
|
||||
#
|
||||
# Copyright 2015 F4E | European Joint Undertaking for ITER
|
||||
# and the Development of Fusion Energy ('Fusion for Energy')
|
||||
#
|
||||
# Licensed under the EUPL, Version 1.1 or - as soon they
|
||||
# will be approved by the European Commission - subsequent
|
||||
# versions of the EUPL (the "Licence");
|
||||
# You may not use this work except in compliance with the
|
||||
# Licence.
|
||||
# You may obtain a copy of the Licence at:
|
||||
#
|
||||
# http://ec.europa.eu/idabc/eupl
|
||||
#
|
||||
# Unless required by applicable law or agreed to in
|
||||
# writing, software distributed under the Licence is
|
||||
# distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
# express or implied.
|
||||
# See the Licence for the specific language governing
|
||||
# permissions and limitations under the Licence.
|
||||
#
|
||||
# $Id: Makefile.inc 3 2012-01-15 16:26:07Z aneto $
|
||||
#
|
||||
#############################################################
|
||||
|
||||
SPB =
|
||||
|
||||
|
||||
ROOT_DIR=../../..
|
||||
|
||||
|
||||
PACKAGE=Core
|
||||
ROOT_DIR=../../..
|
||||
ABS_ROOT_DIR=$(abspath $(ROOT_DIR))
|
||||
MAKEDEFAULTDIR=$(MARTe2_DIR)/MakeDefaults
|
||||
|
||||
include $(MAKEDEFAULTDIR)/MakeStdLibDefs.$(TARGET)
|
||||
|
||||
all: $(OBJS) $(SUBPROJ)
|
||||
echo $(OBJS)
|
||||
|
||||
include depends.$(TARGET)
|
||||
|
||||
include $(MAKEDEFAULTDIR)/MakeStdLibRules.$(TARGET)
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
#ifndef __RESULT_H
|
||||
#define __RESULT_H
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace MARTe {
|
||||
|
||||
/**
|
||||
* @brief Namespace for result error codes.
|
||||
*/
|
||||
namespace Errors {
|
||||
enum ErrorT {
|
||||
None = 0,
|
||||
Generic = 1,
|
||||
OutOfMemory = 2,
|
||||
IndexOutOfBounds = 3,
|
||||
ValueOutOfRange = 4,
|
||||
WrongType = 5,
|
||||
Empty = 6,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A simple Result type for error handling.
|
||||
* @details This implementation is header-only to ensure template linkage.
|
||||
* Requirement: T and E must have default constructors and be copyable.
|
||||
*/
|
||||
template <typename T, typename E = Errors::ErrorT>
|
||||
class Result {
|
||||
public:
|
||||
static Result Success(const T &t) {
|
||||
return Result(t, true);
|
||||
}
|
||||
|
||||
static Result Fail(const E &e) {
|
||||
return Result(e, false);
|
||||
}
|
||||
|
||||
Result() : state(false), val(T()), err(E()) {}
|
||||
Result(const Result &r) : state(r.state), val(r.val), err(r.err) {}
|
||||
|
||||
Result& operator=(const Result &r) {
|
||||
if (this != &r) {
|
||||
state = r.state;
|
||||
val = r.val;
|
||||
err = r.err;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Ok() const { return state; }
|
||||
bool IsOk() const { return state; }
|
||||
|
||||
// Const accessors
|
||||
const T &Val() const { assert(state); return val; }
|
||||
const E &Err() const { assert(!state); return err; }
|
||||
|
||||
// Non-const accessors
|
||||
T &Val() { assert(state); return val; }
|
||||
E &Err() { assert(!state); return err; }
|
||||
|
||||
operator bool() const { return state; }
|
||||
|
||||
private:
|
||||
Result(const T &v, bool s) : state(s), val(v), err(E()) {}
|
||||
Result(const E &e, bool s) : state(s), val(T()), err(e) {}
|
||||
|
||||
bool state;
|
||||
T val;
|
||||
E err;
|
||||
};
|
||||
|
||||
} // namespace MARTe
|
||||
|
||||
#endif
|
||||
@@ -1 +0,0 @@
|
||||
Result.o: Result.cpp Result.h
|
||||
@@ -1,158 +0,0 @@
|
||||
#ifndef __VEC_H
|
||||
#define __VEC_H
|
||||
|
||||
#include "Result.h"
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <cassert>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace MARTe {
|
||||
|
||||
/**
|
||||
* @brief Simple dynamic array (vector) implementation with fixed growth.
|
||||
* @tparam T The type of elements.
|
||||
* @tparam GROWTH The number of elements to add when the buffer is full.
|
||||
*/
|
||||
template <typename T, size_t GROWTH = 16>
|
||||
class Vec {
|
||||
public:
|
||||
Vec() : size(0), mem_size(GROWTH), arr(NULL) {
|
||||
arr = new T[mem_size];
|
||||
}
|
||||
|
||||
Vec(const Vec<T, GROWTH> &other) : size(other.size), mem_size(other.mem_size), arr(NULL) {
|
||||
arr = new T[mem_size];
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
arr[i] = other.arr[i];
|
||||
}
|
||||
}
|
||||
|
||||
Vec(const T *data, const size_t count) : size(count), mem_size(count + GROWTH), arr(NULL) {
|
||||
arr = new T[mem_size];
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
arr[i] = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
~Vec() {
|
||||
if (arr != NULL) {
|
||||
delete[] arr;
|
||||
arr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Vec& operator=(const Vec<T, GROWTH> &other) {
|
||||
if (this != &other) {
|
||||
T* new_arr = new T[other.mem_size];
|
||||
for (size_t i = 0; i < other.size; ++i) {
|
||||
new_arr[i] = other.arr[i];
|
||||
}
|
||||
if (arr != NULL) {
|
||||
delete[] arr;
|
||||
}
|
||||
arr = new_arr;
|
||||
size = other.size;
|
||||
mem_size = other.mem_size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchange contents with another Vec in O(1) — no allocation, no element copies.
|
||||
*
|
||||
* Used by UpdateBrokersActiveStatus / UpdateBrokersBreakStatus to publish a
|
||||
* freshly built index list to the RT thread with the shortest possible lock
|
||||
* hold time: only three pointer/size swaps happen inside the mutex.
|
||||
* The old arrays end up in @p other and are freed when it leaves scope
|
||||
* AFTER the lock is released.
|
||||
*/
|
||||
void Swap(Vec<T, GROWTH> &other) {
|
||||
T *tmpArr = arr; arr = other.arr; other.arr = tmpArr;
|
||||
size_t tmpSz = size; size = other.size; other.size = tmpSz;
|
||||
size_t tmpMem = mem_size; mem_size = other.mem_size; other.mem_size = tmpMem;
|
||||
}
|
||||
|
||||
size_t Size() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
T* GetInternalBuffer() { return arr; }
|
||||
|
||||
bool Remove(size_t index) {
|
||||
if (index >= size) return false;
|
||||
for (size_t i = index; i < size - 1; ++i) {
|
||||
arr[i] = arr[i + 1];
|
||||
}
|
||||
size--;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Insert(size_t index, const T& val) {
|
||||
if (index > size) return false;
|
||||
if (size == mem_size) extend();
|
||||
|
||||
for (size_t i = size; i > index; --i) {
|
||||
arr[i] = arr[i - 1];
|
||||
}
|
||||
arr[index] = val;
|
||||
size++;
|
||||
return true;
|
||||
}
|
||||
|
||||
Result<T> Get(size_t index) const {
|
||||
if (index >= size) return Result<T>::Fail(Errors::IndexOutOfBounds);
|
||||
return Result<T>::Success(arr[index]);
|
||||
}
|
||||
|
||||
void Push(const T &val) {
|
||||
if (size == mem_size) extend();
|
||||
arr[size++] = val;
|
||||
}
|
||||
|
||||
Result<T> Pop() {
|
||||
if (size == 0) return Result<T>::Fail(Errors::Empty);
|
||||
T last = arr[--size];
|
||||
return Result<T>::Success(last);
|
||||
}
|
||||
|
||||
const T &operator[](const size_t index) const {
|
||||
assert(index < size);
|
||||
return arr[index];
|
||||
}
|
||||
|
||||
T &operator[](const size_t index) {
|
||||
assert(index < size);
|
||||
return arr[index];
|
||||
}
|
||||
|
||||
protected:
|
||||
const T *mem() const { return arr; }
|
||||
size_t memSize() const { return mem_size; }
|
||||
|
||||
private:
|
||||
size_t size;
|
||||
size_t mem_size;
|
||||
T *arr;
|
||||
|
||||
void extend() {
|
||||
size_t new_mem_size = mem_size + GROWTH;
|
||||
T *new_arr = new T[new_mem_size];
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
new_arr[i] = arr[i];
|
||||
}
|
||||
if (arr != NULL) {
|
||||
delete[] arr;
|
||||
}
|
||||
arr = new_arr;
|
||||
mem_size = new_mem_size;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace MARTe
|
||||
|
||||
#endif
|
||||
@@ -1 +0,0 @@
|
||||
../../../..//Build/x86-linux/Core/Types/Vec/Vec.o: Vec.cpp
|
||||
@@ -1 +0,0 @@
|
||||
Vec.o: Vec.cpp
|
||||
@@ -58,16 +58,16 @@ public:
|
||||
|
||||
// 3. Broker Active Status
|
||||
volatile bool active = false;
|
||||
Vec<uint32> indices;
|
||||
Vec<uint32> sizes;
|
||||
Vector<uint32> indices;
|
||||
Vector<uint32> sizes;
|
||||
FastPollingMutexSem mutex;
|
||||
DebugSignalInfo* ptrs[1] = { service.signals[0] };
|
||||
volatile bool anyBreak = false;
|
||||
Vec<uint32> breakIdx;
|
||||
Vector<uint32> breakIdx;
|
||||
service.RegisterBroker(ptrs, 1, NULL_PTR(MemoryMapBroker*), &active, &indices, &sizes, &mutex, &anyBreak, &breakIdx);
|
||||
service.UpdateBrokersActiveStatus();
|
||||
assert(active == true);
|
||||
assert(indices.Size() == 1);
|
||||
assert(indices.GetNumberOfElements() == 1);
|
||||
assert(indices[0] == 0);
|
||||
|
||||
// Helper Process
|
||||
@@ -244,11 +244,11 @@ public:
|
||||
// Register a broker whose signalPointers is NULL but numSignals > 0.
|
||||
// Before the fix this dereferenced NULL → segfault.
|
||||
volatile bool active = false;
|
||||
Vec<uint32> indices;
|
||||
Vec<uint32> sizes;
|
||||
Vector<uint32> indices;
|
||||
Vector<uint32> sizes;
|
||||
FastPollingMutexSem mutex;
|
||||
volatile bool anyBreak = false;
|
||||
Vec<uint32> breakIdx;
|
||||
Vector<uint32> breakIdx;
|
||||
service.RegisterBroker(NULL_PTR(DebugSignalInfo**), 1u,
|
||||
NULL_PTR(MemoryMapBroker*),
|
||||
&active, &indices, &sizes, &mutex,
|
||||
@@ -538,11 +538,11 @@ public:
|
||||
assert(service.TraceSignal("Z", true) == 1);
|
||||
|
||||
volatile bool active = false;
|
||||
Vec<uint32> indices;
|
||||
Vec<uint32> sizes;
|
||||
Vector<uint32> indices;
|
||||
Vector<uint32> sizes;
|
||||
FastPollingMutexSem mutex;
|
||||
volatile bool anyBreak = false;
|
||||
Vec<uint32> breakIdx;
|
||||
Vector<uint32> breakIdx;
|
||||
DebugSignalInfo *ptrs[3] = {
|
||||
service.signals[0], service.signals[1], service.signals[2]
|
||||
};
|
||||
@@ -554,7 +554,7 @@ public:
|
||||
|
||||
// After Swap the broker's activeIndices must hold exactly indices 0 and 2
|
||||
assert(active == true);
|
||||
assert(indices.Size() == 2u);
|
||||
assert(indices.GetNumberOfElements() == 2u);
|
||||
// indices are in order of signal position in the broker (0 then 2)
|
||||
assert(indices[0] == 0u);
|
||||
assert(indices[1] == 2u);
|
||||
@@ -563,7 +563,7 @@ public:
|
||||
// Disable one; Swap again — only index 0 should remain
|
||||
assert(service.TraceSignal("Z", false) == 1);
|
||||
service.UpdateBrokersActiveStatus();
|
||||
assert(indices.Size() == 1u);
|
||||
assert(indices.GetNumberOfElements() == 1u);
|
||||
assert(indices[0] == 0u);
|
||||
printf(" -> PASS: After disabling Z, only index 0 remains\n");
|
||||
}
|
||||
@@ -592,11 +592,11 @@ public:
|
||||
service.UpdateBrokersBreakStatus();
|
||||
|
||||
volatile bool active = false;
|
||||
Vec<uint32> indices;
|
||||
Vec<uint32> sizes;
|
||||
Vector<uint32> indices;
|
||||
Vector<uint32> sizes;
|
||||
FastPollingMutexSem mutex;
|
||||
volatile bool anyBreak = false;
|
||||
Vec<uint32> breakIdx;
|
||||
Vector<uint32> breakIdx;
|
||||
DebugSignalInfo *ptrs[1] = { service.signals[0] };
|
||||
service.RegisterBroker(ptrs, 1u, NULL_PTR(MemoryMapBroker *),
|
||||
&active, &indices, &sizes, &mutex,
|
||||
@@ -605,7 +605,7 @@ public:
|
||||
// UpdateBrokersBreakStatus must propagate the break flag to the broker
|
||||
service.UpdateBrokersBreakStatus();
|
||||
assert(anyBreak == true);
|
||||
assert(breakIdx.Size() == 1u);
|
||||
assert(breakIdx.GetNumberOfElements() == 1u);
|
||||
|
||||
// Process() copies break indices, releases lock, evaluates break.
|
||||
// val = 5 > 3 — service must become paused.
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
BINARY := marte2-web-client
|
||||
GIT_HASH := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
|
||||
TIMESTAMP := $(shell date -u +%Y%m%d-%H%M%S)
|
||||
VERSION := $(GIT_HASH)-$(TIMESTAMP)
|
||||
|
||||
LDFLAGS := -X main.buildVersion=$(VERSION)
|
||||
|
||||
.PHONY: all build clean
|
||||
|
||||
all: build
|
||||
|
||||
build:
|
||||
CGO_ENABLED=0 go build -ldflags "$(LDFLAGS)" -o $(BINARY) .
|
||||
|
||||
clean:
|
||||
rm -f $(BINARY)
|
||||
@@ -0,0 +1,7 @@
|
||||
module marte2-web-client
|
||||
|
||||
go 1.21
|
||||
|
||||
require github.com/gorilla/websocket v1.5.1
|
||||
|
||||
require golang.org/x/net v0.17.0 // indirect
|
||||
@@ -0,0 +1,4 @@
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
@@ -0,0 +1,245 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// buildVersion is injected at link time:
|
||||
//
|
||||
// go build -ldflags "-X main.buildVersion=$(git rev-parse --short HEAD)"
|
||||
var buildVersion = "dev"
|
||||
|
||||
//go:embed static
|
||||
var staticFiles embed.FS
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool { return true },
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Wire message types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type InMsg struct {
|
||||
Type string `json:"type"`
|
||||
Data json.RawMessage `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type ConnectData struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
UDPPort int `json:"udp_port"`
|
||||
LogPort int `json:"log_port"`
|
||||
}
|
||||
|
||||
type CmdData struct {
|
||||
Cmd string `json:"cmd"`
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Hub – fan-out WS messages to all connected browsers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type Hub struct {
|
||||
mu sync.RWMutex
|
||||
clients map[*WSClient]struct{}
|
||||
marte *MarteClient
|
||||
}
|
||||
|
||||
func newHub() *Hub {
|
||||
return &Hub{clients: make(map[*WSClient]struct{})}
|
||||
}
|
||||
|
||||
func (h *Hub) add(c *WSClient) {
|
||||
h.mu.Lock()
|
||||
h.clients[c] = struct{}{}
|
||||
h.mu.Unlock()
|
||||
}
|
||||
|
||||
func (h *Hub) remove(c *WSClient) {
|
||||
h.mu.Lock()
|
||||
delete(h.clients, c)
|
||||
h.mu.Unlock()
|
||||
}
|
||||
|
||||
func (h *Hub) broadcast(msg []byte) {
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
for c := range h.clients {
|
||||
select {
|
||||
case c.send <- msg:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// WSClient – one browser tab
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type WSClient struct {
|
||||
hub *Hub
|
||||
conn *websocket.Conn
|
||||
send chan []byte
|
||||
}
|
||||
|
||||
func (c *WSClient) writePump() {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
defer func() {
|
||||
ticker.Stop()
|
||||
c.conn.Close()
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case msg, ok := <-c.send:
|
||||
c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
|
||||
if !ok {
|
||||
c.conn.WriteMessage(websocket.CloseMessage, []byte{})
|
||||
return
|
||||
}
|
||||
if err := c.conn.WriteMessage(websocket.TextMessage, msg); err != nil {
|
||||
return
|
||||
}
|
||||
case <-ticker.C:
|
||||
c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
|
||||
if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *WSClient) readPump() {
|
||||
defer func() {
|
||||
c.hub.remove(c)
|
||||
c.conn.Close()
|
||||
}()
|
||||
c.conn.SetReadLimit(256 * 1024)
|
||||
c.conn.SetReadDeadline(time.Now().Add(60 * time.Second))
|
||||
c.conn.SetPongHandler(func(string) error {
|
||||
c.conn.SetReadDeadline(time.Now().Add(60 * time.Second))
|
||||
return nil
|
||||
})
|
||||
for {
|
||||
_, raw, err := c.conn.ReadMessage()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
c.conn.SetReadDeadline(time.Now().Add(60 * time.Second))
|
||||
|
||||
var in InMsg
|
||||
if err := json.Unmarshal(raw, &in); err != nil {
|
||||
continue
|
||||
}
|
||||
c.handleIncoming(in)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *WSClient) handleIncoming(in InMsg) {
|
||||
m := c.hub.marte
|
||||
switch in.Type {
|
||||
case "connect":
|
||||
var d ConnectData
|
||||
if err := json.Unmarshal(in.Data, &d); err != nil {
|
||||
return
|
||||
}
|
||||
if d.Host == "" {
|
||||
d.Host = "127.0.0.1"
|
||||
}
|
||||
if d.Port == 0 {
|
||||
d.Port = 8080
|
||||
}
|
||||
if d.UDPPort == 0 {
|
||||
d.UDPPort = 8081
|
||||
}
|
||||
if d.LogPort == 0 {
|
||||
d.LogPort = 8082
|
||||
}
|
||||
log.Printf("[WS] connect request host=%s cmd=%d udp=%d log=%d",
|
||||
d.Host, d.Port, d.UDPPort, d.LogPort)
|
||||
m.Connect(d.Host, d.Port, d.UDPPort, d.LogPort)
|
||||
|
||||
case "disconnect":
|
||||
log.Printf("[WS] disconnect request")
|
||||
m.Disconnect()
|
||||
|
||||
case "cmd":
|
||||
var d CmdData
|
||||
if err := json.Unmarshal(in.Data, &d); err != nil {
|
||||
return
|
||||
}
|
||||
m.SendCommand(d.Cmd)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HTTP handler
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func wsHandler(hub *Hub, w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
log.Println("upgrade:", err)
|
||||
return
|
||||
}
|
||||
c := &WSClient{hub: hub, conn: conn, send: make(chan []byte, 256)}
|
||||
hub.add(c)
|
||||
|
||||
// Send current connection status to newly joined client.
|
||||
if hub.marte.IsConnected() {
|
||||
b, _ := json.Marshal(map[string]any{"type": "connected"})
|
||||
c.send <- b
|
||||
// Also push current signal list if already discovered.
|
||||
hub.marte.SendCachedState(c)
|
||||
}
|
||||
|
||||
go c.writePump()
|
||||
c.readPump() // blocks until client disconnects
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// main
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func main() {
|
||||
addr := flag.String("addr", ":7777", "HTTP listen address")
|
||||
flag.Parse()
|
||||
|
||||
hub := newHub()
|
||||
hub.marte = newMarteClient(hub)
|
||||
|
||||
sub, err := fs.Sub(staticFiles, "static")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fileServer := http.FileServer(http.FS(sub))
|
||||
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
|
||||
wsHandler(hub, w, r)
|
||||
})
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
// Serve index.html for the root path explicitly.
|
||||
if r.URL.Path == "/" {
|
||||
data, err := staticFiles.ReadFile("static/index.html")
|
||||
if err != nil {
|
||||
http.Error(w, "not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.Write(data)
|
||||
return
|
||||
}
|
||||
fileServer.ServeHTTP(w, r)
|
||||
})
|
||||
|
||||
log.Printf("MARTe2 Web Debug Client build=%s listening on %s", buildVersion, *addr)
|
||||
log.Fatal(http.ListenAndServe(*addr, nil))
|
||||
}
|
||||
@@ -0,0 +1,681 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Signal metadata (populated by DISCOVER)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type SignalMeta struct {
|
||||
Name string `json:"name"`
|
||||
ID uint32 `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Dimensions uint8 `json:"dimensions"`
|
||||
Elements uint32 `json:"elements"`
|
||||
Names []string // canonical + alias names mapping to this ID
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Outbound WS message helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type TelemetrySample struct {
|
||||
ID uint32 `json:"id"`
|
||||
Names []string `json:"names"`
|
||||
Ts float64 `json:"ts"`
|
||||
Values []float64 `json:"values"`
|
||||
}
|
||||
|
||||
func broadcast(hub *Hub, v any) {
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
hub.broadcast(b)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// MarteClient
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type MarteClient struct {
|
||||
hub *Hub
|
||||
|
||||
mu sync.Mutex
|
||||
tcpConn net.Conn
|
||||
writer *bufio.Writer
|
||||
|
||||
cmdMu sync.Mutex // serialise TCP writes
|
||||
|
||||
sigMu sync.RWMutex
|
||||
signals map[uint32]*SignalMeta // id -> meta
|
||||
|
||||
baseTs uint64
|
||||
baseTsSet bool
|
||||
basesMu sync.Mutex
|
||||
|
||||
connected int32 // atomic bool
|
||||
|
||||
lastWriteMs int64 // atomic; updated on every TCP write, used by keepalive
|
||||
|
||||
stopCh chan struct{}
|
||||
|
||||
// accumulates signals across DISCOVER_PART chunks; merged on final DISCOVER
|
||||
discoverAcc []discoverSignalJSON
|
||||
|
||||
// cached last-known ports (updated by SERVICE_INFO)
|
||||
host string
|
||||
cmdPort int
|
||||
udpPort int
|
||||
logPort int
|
||||
}
|
||||
|
||||
func newMarteClient(hub *Hub) *MarteClient {
|
||||
return &MarteClient{
|
||||
hub: hub,
|
||||
signals: make(map[uint32]*SignalMeta),
|
||||
stopCh: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MarteClient) IsConnected() bool {
|
||||
return atomic.LoadInt32(&m.connected) == 1
|
||||
}
|
||||
|
||||
// SendCachedState sends the current signal list to a freshly connected browser.
|
||||
func (m *MarteClient) SendCachedState(c *WSClient) {
|
||||
m.sigMu.RLock()
|
||||
defer m.sigMu.RUnlock()
|
||||
if len(m.signals) == 0 {
|
||||
return
|
||||
}
|
||||
sigs := make([]*SignalMeta, 0, len(m.signals))
|
||||
for _, s := range m.signals {
|
||||
sigs = append(sigs, s)
|
||||
}
|
||||
b, _ := json.Marshal(map[string]any{"type": "signal_cache", "signals": sigs})
|
||||
select {
|
||||
case c.send <- b:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Connect / Disconnect
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func (m *MarteClient) Connect(host string, cmdPort, udpPort, logPort int) {
|
||||
m.Disconnect()
|
||||
|
||||
m.mu.Lock()
|
||||
m.host = host
|
||||
m.cmdPort = cmdPort
|
||||
m.udpPort = udpPort
|
||||
m.logPort = logPort
|
||||
m.stopCh = make(chan struct{})
|
||||
m.mu.Unlock()
|
||||
|
||||
go m.runTCP(host, cmdPort)
|
||||
go m.runUDP(host, udpPort)
|
||||
go m.runLog(host, logPort)
|
||||
}
|
||||
|
||||
func (m *MarteClient) Disconnect() {
|
||||
m.mu.Lock()
|
||||
select {
|
||||
case <-m.stopCh:
|
||||
// already closed
|
||||
default:
|
||||
close(m.stopCh)
|
||||
}
|
||||
if m.tcpConn != nil {
|
||||
m.tcpConn.Close()
|
||||
m.tcpConn = nil
|
||||
}
|
||||
m.mu.Unlock()
|
||||
|
||||
atomic.StoreInt32(&m.connected, 0)
|
||||
m.basesMu.Lock()
|
||||
m.baseTsSet = false
|
||||
m.basesMu.Unlock()
|
||||
m.discoverAcc = nil
|
||||
}
|
||||
|
||||
func (m *MarteClient) stopped() bool {
|
||||
select {
|
||||
case <-m.stopCh:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TCP command channel
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func (m *MarteClient) runTCP(host string, port int) {
|
||||
addr := fmt.Sprintf("%s:%d", host, port)
|
||||
for !m.stopped() {
|
||||
conn, err := net.DialTimeout("tcp", addr, 5*time.Second)
|
||||
if err != nil {
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
}
|
||||
conn.(*net.TCPConn).SetNoDelay(true)
|
||||
|
||||
m.mu.Lock()
|
||||
m.tcpConn = conn
|
||||
m.writer = bufio.NewWriter(conn)
|
||||
m.mu.Unlock()
|
||||
|
||||
atomic.StoreInt32(&m.connected, 1)
|
||||
broadcast(m.hub, map[string]any{"type": "connected"})
|
||||
|
||||
// Send SERVICE_INFO to auto-discover ports
|
||||
m.writeCmd("SERVICE_INFO")
|
||||
|
||||
go m.runKeepalive()
|
||||
|
||||
m.readLoop(conn)
|
||||
|
||||
atomic.StoreInt32(&m.connected, 0)
|
||||
broadcast(m.hub, map[string]any{"type": "disconnected"})
|
||||
|
||||
m.mu.Lock()
|
||||
m.tcpConn = nil
|
||||
m.writer = nil
|
||||
m.mu.Unlock()
|
||||
|
||||
if !m.stopped() {
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MarteClient) writeCmd(cmd string) {
|
||||
m.cmdMu.Lock()
|
||||
defer m.cmdMu.Unlock()
|
||||
m.mu.Lock()
|
||||
w := m.writer
|
||||
m.mu.Unlock()
|
||||
if w == nil {
|
||||
return
|
||||
}
|
||||
log.Printf("[→MARTe] %s", cmd)
|
||||
broadcast(m.hub, map[string]any{
|
||||
"type": "log", "time": time.Now().Format("15:04:05.000"),
|
||||
"level": "CMD", "message": fmt.Sprintf("→ %s", cmd),
|
||||
})
|
||||
w.WriteString(cmd + "\n")
|
||||
w.Flush()
|
||||
atomic.StoreInt64(&m.lastWriteMs, time.Now().UnixMilli())
|
||||
}
|
||||
|
||||
// runKeepalive sends INFO every 20 s when no other command has been written
|
||||
// in the last 20 s, keeping the DebugService 30 s idle timer from firing.
|
||||
func (m *MarteClient) runKeepalive() {
|
||||
ticker := time.NewTicker(20 * time.Second)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-m.stopCh:
|
||||
return
|
||||
case <-ticker.C:
|
||||
if !m.IsConnected() {
|
||||
continue
|
||||
}
|
||||
idleMs := time.Now().UnixMilli() - atomic.LoadInt64(&m.lastWriteMs)
|
||||
if idleMs >= 20_000 {
|
||||
m.writeCmd("INFO")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MarteClient) SendCommand(cmd string) {
|
||||
m.writeCmd(cmd)
|
||||
}
|
||||
|
||||
func (m *MarteClient) readLoop(conn net.Conn) {
|
||||
scanner := bufio.NewScanner(conn)
|
||||
scanner.Buffer(make([]byte, 8*1024*1024), 8*1024*1024)
|
||||
|
||||
var jsonAcc strings.Builder
|
||||
inJSON := false
|
||||
|
||||
for scanner.Scan() {
|
||||
if m.stopped() {
|
||||
return
|
||||
}
|
||||
line := scanner.Text()
|
||||
trimmed := strings.TrimSpace(line)
|
||||
if trimmed == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Detect start of JSON block
|
||||
if !inJSON && strings.HasPrefix(trimmed, "{") {
|
||||
inJSON = true
|
||||
jsonAcc.Reset()
|
||||
}
|
||||
|
||||
if inJSON {
|
||||
jsonAcc.WriteString(trimmed)
|
||||
tag, done := detectJSONDone(trimmed)
|
||||
if done {
|
||||
inJSON = false
|
||||
raw := jsonAcc.String()
|
||||
// Strip trailing sentinel
|
||||
idx := strings.Index(raw, "OK "+tag)
|
||||
if idx >= 0 {
|
||||
raw = strings.TrimSpace(raw[:idx])
|
||||
}
|
||||
m.handleJSONResponse(tag, raw)
|
||||
jsonAcc.Reset()
|
||||
}
|
||||
} else {
|
||||
m.handleTextLine(trimmed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// detectJSONDone returns (tag, true) when the line is exactly "OK <TAG>".
|
||||
// DISCOVER_PART must appear before DISCOVER so partial chunks are not mistaken
|
||||
// for the final chunk (though with exact matching this is not strictly
|
||||
// necessary; kept for clarity).
|
||||
func detectJSONDone(line string) (string, bool) {
|
||||
tags := []string{
|
||||
"DISCOVER_PART", "DISCOVER", "TREE", "INFO", "CONFIG", "STEP_STATUS",
|
||||
"VALUE", "MSG", "TRACE", "FORCE", "UNFORCE", "BREAK",
|
||||
"PAUSE", "RESUME", "STEP", "MONITOR", "UNMONITOR", "LS",
|
||||
}
|
||||
for _, t := range tags {
|
||||
if line == "OK "+t {
|
||||
return t, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (m *MarteClient) handleJSONResponse(tag, data string) {
|
||||
log.Printf("[←MARTe] %s %d bytes", tag, len(data))
|
||||
broadcast(m.hub, map[string]any{
|
||||
"type": "log", "time": time.Now().Format("15:04:05.000"),
|
||||
"level": "RESP", "message": fmt.Sprintf("← %s (%d B)", tag, len(data)),
|
||||
})
|
||||
switch tag {
|
||||
case "DISCOVER_PART":
|
||||
// Accumulate this chunk; do NOT broadcast — we wait for the final chunk.
|
||||
var resp discoverResp
|
||||
if err := json.Unmarshal([]byte(data), &resp); err != nil {
|
||||
log.Printf("[DISCOVER_PART] parse error: %v", err)
|
||||
return
|
||||
}
|
||||
m.discoverAcc = append(m.discoverAcc, resp.Signals...)
|
||||
log.Printf("[DISCOVER_PART] accumulated %d signals (total so far: %d)",
|
||||
len(resp.Signals), len(m.discoverAcc))
|
||||
return
|
||||
|
||||
case "DISCOVER":
|
||||
// Merge any previously accumulated part-chunks with this final chunk.
|
||||
var resp discoverResp
|
||||
if err := json.Unmarshal([]byte(data), &resp); err != nil {
|
||||
log.Printf("[DISCOVER] parse error: %v", err)
|
||||
return
|
||||
}
|
||||
all := append(m.discoverAcc, resp.Signals...)
|
||||
m.discoverAcc = nil
|
||||
m.parseDiscoverSignals(all)
|
||||
// Re-marshal the merged list so the browser gets a single consistent blob.
|
||||
merged, _ := json.Marshal(discoverResp{Signals: all})
|
||||
broadcast(m.hub, map[string]any{
|
||||
"type": "response", "tag": "DISCOVER", "data": string(merged),
|
||||
})
|
||||
return
|
||||
|
||||
case "TREE":
|
||||
// Per-node response — forward to browser as-is.
|
||||
broadcast(m.hub, map[string]any{
|
||||
"type": "tree_node",
|
||||
"data": data,
|
||||
})
|
||||
return
|
||||
}
|
||||
broadcast(m.hub, map[string]any{
|
||||
"type": "response",
|
||||
"tag": tag,
|
||||
"data": data,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
func (m *MarteClient) handleTextLine(line string) {
|
||||
if strings.HasPrefix(line, "OK SERVICE_INFO") {
|
||||
// OK SERVICE_INFO TCP_CTRL:8110 UDP_STREAM:8111 TCP_LOG:8082 STATE:RUNNING
|
||||
parts := strings.Fields(line)
|
||||
newUDP, newLog := 0, 0
|
||||
for _, p := range parts {
|
||||
if strings.HasPrefix(p, "UDP_STREAM:") {
|
||||
fmt.Sscanf(p[11:], "%d", &newUDP)
|
||||
}
|
||||
if strings.HasPrefix(p, "TCP_LOG:") {
|
||||
fmt.Sscanf(p[8:], "%d", &newLog)
|
||||
}
|
||||
}
|
||||
// Always forward as a response so the browser can display it.
|
||||
broadcast(m.hub, map[string]any{
|
||||
"type": "response",
|
||||
"tag": "SERVICE_INFO",
|
||||
"data": line[len("OK SERVICE_INFO "):],
|
||||
})
|
||||
if newUDP > 0 || newLog > 0 {
|
||||
broadcast(m.hub, map[string]any{
|
||||
"type": "service_config",
|
||||
"udp_port": newUDP,
|
||||
"log_port": newLog,
|
||||
})
|
||||
// Restart UDP/log workers with updated ports if they differ
|
||||
m.mu.Lock()
|
||||
host := m.host
|
||||
oldUDP := m.udpPort
|
||||
oldLog := m.logPort
|
||||
if newUDP > 0 {
|
||||
m.udpPort = newUDP
|
||||
}
|
||||
if newLog > 0 {
|
||||
m.logPort = newLog
|
||||
}
|
||||
m.mu.Unlock()
|
||||
if newUDP > 0 && newUDP != oldUDP {
|
||||
go m.runUDP(host, newUDP)
|
||||
}
|
||||
if newLog > 0 && newLog != oldLog {
|
||||
go m.runLog(host, newLog)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Forward all text lines to browsers.
|
||||
broadcast(m.hub, map[string]any{
|
||||
"type": "text_line",
|
||||
"data": line,
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// DISCOVER parsing
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type discoverSignalJSON struct {
|
||||
Name string `json:"name"`
|
||||
ID uint32 `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Dimensions uint8 `json:"dimensions"`
|
||||
Elements uint32 `json:"elements"`
|
||||
}
|
||||
|
||||
type discoverResp struct {
|
||||
Signals []discoverSignalJSON `json:"Signals"`
|
||||
}
|
||||
|
||||
func (m *MarteClient) parseDiscoverSignals(sigs []discoverSignalJSON) {
|
||||
m.sigMu.Lock()
|
||||
defer m.sigMu.Unlock()
|
||||
m.signals = make(map[uint32]*SignalMeta, len(sigs))
|
||||
for _, s := range sigs {
|
||||
el := s.Elements
|
||||
if el == 0 {
|
||||
el = 1
|
||||
}
|
||||
// Multiple DISCOVER entries can share the same ID (canonical DataSource
|
||||
// path + one GAM alias per broker). Merge them into one SignalMeta so
|
||||
// that Names carries every alias. This is required for the telemetry
|
||||
// receiver to match whichever name the user traced.
|
||||
if existing, ok := m.signals[s.ID]; ok {
|
||||
existing.Names = append(existing.Names, s.Name)
|
||||
continue
|
||||
}
|
||||
meta := &SignalMeta{
|
||||
Name: s.Name,
|
||||
ID: s.ID,
|
||||
Type: s.Type,
|
||||
Dimensions: s.Dimensions,
|
||||
Elements: el,
|
||||
Names: []string{s.Name},
|
||||
}
|
||||
m.signals[s.ID] = meta
|
||||
}
|
||||
log.Printf("[DISCOVER] registered %d unique signals from %d entries", len(m.signals), len(sigs))
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// UDP telemetry
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const udpMagic uint32 = 0xDA7A57AD
|
||||
|
||||
func (m *MarteClient) runUDP(host string, port int) {
|
||||
addr := fmt.Sprintf("0.0.0.0:%d", port)
|
||||
udpAddr, err := net.ResolveUDPAddr("udp4", addr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
conn, err := net.ListenUDP("udp4", udpAddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
conn.SetReadBuffer(10 * 1024 * 1024)
|
||||
conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
|
||||
|
||||
buf := make([]byte, 65535)
|
||||
var lastSeq uint32
|
||||
var hasLastSeq bool
|
||||
var totalPkts uint64
|
||||
var dropped uint64
|
||||
|
||||
for !m.stopped() {
|
||||
conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
|
||||
n, _, err := conn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if n < 20 {
|
||||
continue
|
||||
}
|
||||
if binary.LittleEndian.Uint32(buf[0:4]) != udpMagic {
|
||||
continue
|
||||
}
|
||||
|
||||
seq := binary.LittleEndian.Uint32(buf[4:8])
|
||||
if hasLastSeq && seq > lastSeq+1 {
|
||||
dropped += uint64(seq - lastSeq - 1)
|
||||
}
|
||||
lastSeq = seq
|
||||
hasLastSeq = true
|
||||
|
||||
totalPkts++
|
||||
if totalPkts%500 == 0 {
|
||||
broadcast(m.hub, map[string]any{
|
||||
"type": "udp_stats",
|
||||
"packets": totalPkts,
|
||||
"dropped": dropped,
|
||||
})
|
||||
}
|
||||
|
||||
count := binary.LittleEndian.Uint32(buf[16:20])
|
||||
offset := 20
|
||||
|
||||
// Resolve base timestamp once per packet.
|
||||
m.basesMu.Lock()
|
||||
if !m.baseTsSet && n >= 20+12 {
|
||||
m.baseTs = binary.LittleEndian.Uint64(buf[20+4 : 20+12])
|
||||
m.baseTsSet = true
|
||||
}
|
||||
baseTs := m.baseTs
|
||||
baseTsSet := m.baseTsSet
|
||||
m.basesMu.Unlock()
|
||||
|
||||
m.sigMu.RLock()
|
||||
samples := make([]TelemetrySample, 0, count)
|
||||
for i := uint32(0); i < count; i++ {
|
||||
if offset+16 > n {
|
||||
break
|
||||
}
|
||||
id := binary.LittleEndian.Uint32(buf[offset : offset+4])
|
||||
tsRaw := binary.LittleEndian.Uint64(buf[offset+4 : offset+12])
|
||||
size := binary.LittleEndian.Uint32(buf[offset+12 : offset+16])
|
||||
offset += 16
|
||||
|
||||
if offset+int(size) > n {
|
||||
break
|
||||
}
|
||||
dataSlice := buf[offset : offset+int(size)]
|
||||
offset += int(size)
|
||||
|
||||
tsS := 0.0
|
||||
if baseTsSet && tsRaw >= baseTs {
|
||||
tsS = float64(tsRaw-baseTs) / 1_000_000.0
|
||||
}
|
||||
|
||||
meta, ok := m.signals[id]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
elements := meta.Elements
|
||||
if elements == 0 {
|
||||
elements = 1
|
||||
}
|
||||
typeSize := uint32(size)
|
||||
if elements > 0 {
|
||||
typeSize = uint32(size) / elements
|
||||
}
|
||||
vals := make([]float64, 0, elements)
|
||||
t := meta.Type
|
||||
|
||||
for e := uint32(0); e < elements; e++ {
|
||||
off := e * typeSize
|
||||
if off+typeSize > uint32(len(dataSlice)) {
|
||||
break
|
||||
}
|
||||
elem := dataSlice[off : off+typeSize]
|
||||
vals = append(vals, parseTypedValue(elem, typeSize, t))
|
||||
}
|
||||
|
||||
samples = append(samples, TelemetrySample{
|
||||
ID: id,
|
||||
Names: meta.Names,
|
||||
Ts: tsS,
|
||||
Values: vals,
|
||||
})
|
||||
}
|
||||
m.sigMu.RUnlock()
|
||||
|
||||
if len(samples) > 0 {
|
||||
broadcast(m.hub, map[string]any{
|
||||
"type": "telemetry",
|
||||
"seq": seq,
|
||||
"signals": samples,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseTypedValue(data []byte, size uint32, t string) float64 {
|
||||
switch size {
|
||||
case 1:
|
||||
if strings.Contains(t, "u") {
|
||||
return float64(data[0])
|
||||
}
|
||||
return float64(int8(data[0]))
|
||||
case 2:
|
||||
if len(data) < 2 {
|
||||
return 0
|
||||
}
|
||||
v := binary.LittleEndian.Uint16(data[:2])
|
||||
if strings.Contains(t, "u") {
|
||||
return float64(v)
|
||||
}
|
||||
return float64(int16(v))
|
||||
case 4:
|
||||
if len(data) < 4 {
|
||||
return 0
|
||||
}
|
||||
v := binary.LittleEndian.Uint32(data[:4])
|
||||
if strings.Contains(t, "float") || strings.Contains(t, "float32") {
|
||||
return float64(math.Float32frombits(v))
|
||||
}
|
||||
if strings.Contains(t, "u") {
|
||||
return float64(v)
|
||||
}
|
||||
return float64(int32(v))
|
||||
case 8:
|
||||
if len(data) < 8 {
|
||||
return 0
|
||||
}
|
||||
v := binary.LittleEndian.Uint64(data[:8])
|
||||
if strings.Contains(t, "float") || strings.Contains(t, "float64") || strings.Contains(t, "double") {
|
||||
return math.Float64frombits(v)
|
||||
}
|
||||
if strings.Contains(t, "u") {
|
||||
return float64(v)
|
||||
}
|
||||
return float64(int64(v))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TCP log channel
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func (m *MarteClient) runLog(host string, port int) {
|
||||
addr := fmt.Sprintf("%s:%d", host, port)
|
||||
for !m.stopped() {
|
||||
conn, err := net.DialTimeout("tcp", addr, 5*time.Second)
|
||||
if err != nil {
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
}
|
||||
scanner := bufio.NewScanner(conn)
|
||||
for scanner.Scan() {
|
||||
if m.stopped() {
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if strings.HasPrefix(line, "LOG ") {
|
||||
rest := line[4:]
|
||||
idx := strings.Index(rest, " ")
|
||||
if idx < 0 {
|
||||
continue
|
||||
}
|
||||
level := rest[:idx]
|
||||
msg := rest[idx+1:]
|
||||
broadcast(m.hub, map[string]any{
|
||||
"type": "log",
|
||||
"time": time.Now().Format("15:04:05.000"),
|
||||
"level": level,
|
||||
"message": msg,
|
||||
})
|
||||
}
|
||||
}
|
||||
conn.Close()
|
||||
if !m.stopped() {
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<rect width="32" height="32" rx="5" fill="#1e1e2e"/>
|
||||
<!-- oscilloscope grid lines -->
|
||||
<line x1="2" y1="16" x2="30" y2="16" stroke="#313244" stroke-width="0.8"/>
|
||||
<line x1="16" y1="3" x2="16" y2="29" stroke="#313244" stroke-width="0.8"/>
|
||||
<!-- waveform -->
|
||||
<polyline points="2,16 7,16 9,7 12,25 16,7 20,25 23,16 25,16 27,11 30,11"
|
||||
fill="none" stroke="#89b4fa" stroke-width="2"
|
||||
stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<!-- scope bezel -->
|
||||
<rect x="1" y="1" width="30" height="30" rx="4"
|
||||
fill="none" stroke="#45475a" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 638 B |
@@ -0,0 +1,503 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>MARTe2 Debug Client</title>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||
<link rel="stylesheet" href="uplot.min.css">
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
html,body{height:100%;overflow:hidden;font-family:'Segoe UI',system-ui,sans-serif;font-size:12px;background:#1e1e2e;color:#cdd6f4}
|
||||
|
||||
/* ── layout ── */
|
||||
#app{display:flex;flex-direction:column;height:100vh}
|
||||
#toolbar{display:flex;align-items:center;gap:6px;padding:4px 8px;background:#181825;border-bottom:1px solid #313244;flex-shrink:0;flex-wrap:wrap}
|
||||
#main{display:flex;flex:1;overflow:hidden}
|
||||
#left-panel{width:240px;flex-shrink:0;display:flex;flex-direction:column;border-right:1px solid #313244;overflow:hidden}
|
||||
#center-panel{flex:1;overflow:hidden;display:flex;flex-direction:column;gap:6px;padding:6px}
|
||||
#right-panel{width:260px;flex-shrink:0;display:flex;flex-direction:column;border-left:1px solid #313244;overflow:hidden}
|
||||
#log-panel{height:160px;flex-shrink:0;border-top:1px solid #313244;display:flex;flex-direction:column;overflow:hidden}
|
||||
|
||||
/* ── toolbar ── */
|
||||
.tb-group{display:flex;align-items:center;gap:4px;padding:0 6px;border-right:1px solid #313244}
|
||||
.tb-group:last-child{border-right:none}
|
||||
input[type=text],input[type=number]{background:#313244;border:1px solid #45475a;color:#cdd6f4;padding:2px 6px;border-radius:4px;width:100px}
|
||||
input[type=number]{width:60px}
|
||||
button{background:#313244;border:1px solid #45475a;color:#cdd6f4;padding:2px 8px;border-radius:4px;cursor:pointer;white-space:nowrap}
|
||||
button:hover{background:#45475a}
|
||||
button.active{background:#89b4fa;color:#1e1e2e;border-color:#89b4fa}
|
||||
button.danger{background:#f38ba8;color:#1e1e2e;border-color:#f38ba8}
|
||||
button.warn{background:#fab387;color:#1e1e2e;border-color:#fab387}
|
||||
button.ok{background:#a6e3a1;color:#1e1e2e;border-color:#a6e3a1}
|
||||
label{color:#a6adc8;user-select:none}
|
||||
#conn-status{width:8px;height:8px;border-radius:50%;background:#f38ba8;display:inline-block;flex-shrink:0;vertical-align:middle}
|
||||
#conn-status.ok{background:#a6e3a1}
|
||||
#udp-stats{color:#585b70;font-size:11px;margin-left:4px}
|
||||
|
||||
/* ── dropdown menus ── */
|
||||
.menu-wrap{position:relative}
|
||||
.dropdown{position:absolute;top:calc(100% + 4px);left:0;z-index:200;background:#1e1e2e;border:1px solid #45475a;border-radius:6px;padding:8px;min-width:260px;display:none;flex-direction:column;gap:6px;box-shadow:0 4px 16px rgba(0,0,0,.5)}
|
||||
.dropdown.open{display:flex}
|
||||
.menu-sep{border:none;border-top:1px solid #313244;margin:2px 0}
|
||||
.menu-row{display:flex;gap:6px;align-items:center}
|
||||
.menu-row input[type=text]{flex:1;min-width:0;width:auto}
|
||||
.menu-row input[type=number]{width:64px}
|
||||
.menu-btn-row{display:flex;gap:6px}
|
||||
.menu-btn-row button{flex:1}
|
||||
|
||||
/* ── panels ── */
|
||||
.panel-header{padding:4px 8px;background:#181825;border-bottom:1px solid #313244;font-weight:600;color:#89b4fa;display:flex;align-items:center;justify-content:space-between;flex-shrink:0}
|
||||
.panel-search{padding:4px;border-bottom:1px solid #313244;flex-shrink:0}
|
||||
.panel-search input{width:100%;background:#313244;border:1px solid #45475a;color:#cdd6f4;padding:3px 6px;border-radius:4px}
|
||||
.panel-body{flex:1;overflow-y:auto}
|
||||
.panel-toggle{background:transparent;border:none;color:#585b70;cursor:pointer;padding:0 2px;font-size:11px;line-height:1}
|
||||
.panel-toggle:hover{color:#cdd6f4;background:transparent}
|
||||
|
||||
/* ── collapsible panels ── */
|
||||
#left-panel{transition:width .15s;position:relative}
|
||||
#left-panel.collapsed{width:0!important;border:none;overflow:hidden}
|
||||
#right-panel{transition:width .15s;position:relative}
|
||||
#right-panel.collapsed{width:0!important;border:none;overflow:hidden}
|
||||
#log-panel{transition:height .15s}
|
||||
#log-panel.collapsed{height:28px;overflow:hidden}
|
||||
/* collapse/resize strips */
|
||||
.panel-strip{width:6px;flex-shrink:0;display:flex;align-items:center;justify-content:center;cursor:col-resize;background:#181825;border:none;color:#585b70;font-size:9px;user-select:none;position:relative}
|
||||
.panel-strip::after{content:'';position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:2px;height:32px;background:#45475a;border-radius:1px;pointer-events:none}
|
||||
.panel-strip:hover{background:#313244}
|
||||
.panel-strip:hover::after{background:#89b4fa}
|
||||
#left-strip{border-right:1px solid #313244}
|
||||
#right-strip{border-left:1px solid #313244}
|
||||
|
||||
/* ── tree ── */
|
||||
.tree-node{padding:1px 0}
|
||||
.tree-leaf{display:flex;align-items:center;gap:2px;padding:1px 4px;cursor:default;user-select:none}
|
||||
.tree-leaf:hover{background:#313244}
|
||||
.tree-leaf.selected{background:#45475a}
|
||||
.tree-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
.tree-class{color:#585b70;font-size:10px;flex-shrink:0}
|
||||
details>summary{list-style:none;cursor:pointer;padding:1px 4px;display:flex;align-items:center;gap:4px;user-select:none}
|
||||
details>summary:hover{background:#313244}
|
||||
details>summary::before{content:'▶';font-size:9px;color:#585b70;width:10px;flex-shrink:0}
|
||||
details[open]>summary::before{content:'▼'}
|
||||
details>.children{padding-left:14px}
|
||||
.tree-loading{padding:2px 4px;color:#585b70;font-size:10px;font-style:italic}
|
||||
.tree-btn{background:transparent;border:1px solid #45475a;color:#a6adc8;padding:0 4px;border-radius:3px;cursor:pointer;font-size:10px;line-height:14px}
|
||||
.tree-btn:hover{background:#45475a;color:#cdd6f4}
|
||||
.tree-btn.t{border-color:#89b4fa;color:#89b4fa}
|
||||
.tree-btn.f{border-color:#a6e3a1;color:#a6e3a1}
|
||||
.tree-btn.b{border-color:#fab387;color:#fab387}
|
||||
|
||||
/* ── right panel tabs ── */
|
||||
.tabs{display:flex;border-bottom:1px solid #313244;flex-shrink:0}
|
||||
.tab{flex:1;padding:4px;text-align:center;cursor:pointer;color:#585b70;border-bottom:2px solid transparent}
|
||||
.tab.active{color:#89b4fa;border-bottom-color:#89b4fa}
|
||||
.tab-content{display:none;flex:1;overflow-y:auto;flex-direction:column}
|
||||
.tab-content.active{display:flex}
|
||||
|
||||
/* ── signal items (right panel) ── */
|
||||
.sig-item{display:flex;align-items:center;gap:4px;padding:3px 6px;border-bottom:1px solid #181825}
|
||||
.sig-item:hover{background:#313244}
|
||||
.sig-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px}
|
||||
.sig-val{color:#a6e3a1;font-size:11px;min-width:60px;text-align:right;font-family:monospace}
|
||||
.sig-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
|
||||
|
||||
/* ── plots ── */
|
||||
.plot-card{background:#181825;border:1px solid #313244;border-radius:6px;overflow:hidden;flex:1;min-height:160px;display:flex;flex-direction:column}
|
||||
.plot-card.drop-active{border-color:#89b4fa}
|
||||
.plot-header{display:flex;align-items:center;gap:6px;padding:4px 8px;background:#11111b;border-bottom:1px solid #313244;flex-shrink:0}
|
||||
.plot-title{font-weight:600;color:#89b4fa;flex:1}
|
||||
.plot-series-bar{display:flex;flex-wrap:wrap;gap:4px;padding:3px 8px;background:#11111b;border-bottom:1px solid #313244;flex-shrink:0}
|
||||
.plot-series-bar:empty{display:none;padding:0;border:none}
|
||||
.series-chip{display:inline-flex;align-items:center;gap:3px;background:#1e1e2e;border:1px solid #45475a;border-radius:10px;padding:1px 3px 1px 6px;font-size:10px}
|
||||
.series-chip-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}
|
||||
.series-chip-name{max-width:130px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#cdd6f4}
|
||||
.series-chip-rm{background:transparent;border:none;color:#585b70;cursor:pointer;padding:0 2px;font-size:12px;line-height:1}
|
||||
.series-chip-rm:hover{color:#f38ba8;background:transparent}
|
||||
.plot-drop{flex:1;display:flex;align-items:center;justify-content:center;color:#45475a;border:2px dashed #313244;margin:8px;border-radius:4px}
|
||||
.plot-drop.over{border-color:#89b4fa;color:#89b4fa}
|
||||
.uplot-wrap{flex:1;min-height:0;padding:2px 4px 4px;display:flex;flex-direction:column}
|
||||
|
||||
/* ── logs ── */
|
||||
#log-toolbar{display:flex;align-items:center;gap:6px;padding:3px 8px;background:#181825;border-bottom:1px solid #313244;flex-shrink:0}
|
||||
#log-body{flex:1;overflow-y:auto;font-family:monospace;font-size:11px;padding:2px 0}
|
||||
.log-line{padding:1px 8px;display:flex;gap:8px}
|
||||
.log-time{color:#585b70;flex-shrink:0}
|
||||
.log-lvl{flex-shrink:0;min-width:50px;font-weight:600}
|
||||
.log-msg{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}
|
||||
.log-line.DEBUG .log-lvl{color:#89b4fa}
|
||||
.log-line.INFO .log-lvl{color:#a6e3a1}
|
||||
.log-line.WARNING .log-lvl{color:#fab387}
|
||||
.log-line.ERROR,.log-line.FatalError,.log-line.FATAL{background:#2d1b1b}
|
||||
.log-line.ERROR .log-lvl,.log-line.FatalError .log-lvl,.log-line.FATAL .log-lvl{color:#f38ba8}
|
||||
.log-hidden{display:none}
|
||||
|
||||
/* ── dialogs ── */
|
||||
.dialog-overlay{position:fixed;inset:0;background:rgba(0,0,0,.6);display:flex;align-items:center;justify-content:center;z-index:100}
|
||||
.dialog{background:#1e1e2e;border:1px solid #45475a;border-radius:8px;padding:16px;min-width:320px;max-width:500px}
|
||||
.dialog h3{margin-bottom:12px;color:#89b4fa}
|
||||
.dialog label{display:block;margin-bottom:4px;color:#a6adc8}
|
||||
.dialog input,.dialog select,.dialog textarea{width:100%;background:#313244;border:1px solid #45475a;color:#cdd6f4;padding:4px 8px;border-radius:4px;margin-bottom:10px}
|
||||
.dialog textarea{height:80px;resize:vertical;font-family:monospace}
|
||||
.dialog .btns{display:flex;gap:8px;justify-content:flex-end;margin-top:4px}
|
||||
.dialog select option{background:#1e1e2e}
|
||||
.form-row{display:flex;gap:8px}
|
||||
.form-row>*{flex:1}
|
||||
.form-check{display:flex;align-items:center;gap:8px;margin-bottom:10px}
|
||||
.form-check input[type=checkbox]{width:auto;margin:0}
|
||||
.form-check label{margin:0;color:#a6adc8}
|
||||
|
||||
/* ── step status bar ── */
|
||||
#step-bar{background:#2d2b45;border-bottom:1px solid #313244;padding:4px 8px;display:none;align-items:center;gap:8px;flex-shrink:0}
|
||||
#step-bar.visible{display:flex}
|
||||
|
||||
/* ── scrollbars ── */
|
||||
::-webkit-scrollbar{width:6px;height:6px}
|
||||
::-webkit-scrollbar-track{background:#181825}
|
||||
::-webkit-scrollbar-thumb{background:#45475a;border-radius:3px}
|
||||
::-webkit-scrollbar-thumb:hover{background:#585b70}
|
||||
|
||||
/* ── grouped array signal in trace list ── */
|
||||
.sig-group{display:flex;align-items:center;gap:4px;padding:3px 6px;border-bottom:1px solid #1e1e2e;user-select:none;cursor:grab}
|
||||
.sig-group:hover{background:#313244}
|
||||
.sig-group-exp{color:#585b70;font-size:10px;width:14px;text-align:center;flex-shrink:0;cursor:pointer}
|
||||
.sig-group-exp:hover{color:#89b4fa}
|
||||
.sig-item-sub{padding-left:24px;background:#11111b;border-left:2px solid #313244;margin-left:2px}
|
||||
.sig-item-sub:hover{background:#1e1e2e}
|
||||
|
||||
/* ── array selection toggle ── */
|
||||
.arr-seg{display:flex;gap:0;margin-bottom:12px;border-radius:4px;overflow:hidden;border:1px solid #45475a}
|
||||
.arr-seg button{flex:1;border:none;border-radius:0;border-right:1px solid #45475a;color:#a6adc8;background:#313244;padding:4px 0;font-size:11px}
|
||||
.arr-seg button:last-child{border-right:none}
|
||||
.arr-seg button.active{background:#89b4fa;color:#1e1e2e}
|
||||
.arr-seg button:hover:not(.active){background:#45475a;color:#cdd6f4}
|
||||
|
||||
/* ── misc ── */
|
||||
.empty-hint{padding:16px;color:#45475a;text-align:center}
|
||||
.break-item{padding:3px 6px;border-bottom:1px solid #181825;display:flex;align-items:center;gap:4px;font-size:11px}
|
||||
.break-sig{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#fab387}
|
||||
.msg-item{padding:3px 6px;border-bottom:1px solid #181825;font-size:11px}
|
||||
.msg-status{width:14px;text-align:center;flex-shrink:0}
|
||||
select{background:#313244;border:1px solid #45475a;color:#cdd6f4;padding:2px 4px;border-radius:4px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- ═══ TOOLBAR ═══ -->
|
||||
<div id="toolbar">
|
||||
<!-- Connection menu -->
|
||||
<div class="menu-wrap tb-group">
|
||||
<button id="conn-menu-btn" onclick="toggleMenu('conn-dropdown')">
|
||||
<span id="conn-status"></span>
|
||||
Connection ▾
|
||||
</button>
|
||||
<div class="dropdown" id="conn-dropdown">
|
||||
<div class="menu-row">
|
||||
<input type="text" id="host" value="127.0.0.1" placeholder="host" style="flex:2">
|
||||
<input type="number" id="port" value="8080" placeholder="ctrl" style="width:60px">
|
||||
<button id="btn-connect" onclick="toggleConnect()">Connect</button>
|
||||
</div>
|
||||
<div class="menu-row" id="port-manual-row" style="display:none">
|
||||
<label style="color:#a6adc8;font-size:11px;flex-shrink:0">UDP:</label>
|
||||
<input type="number" id="udp-port" value="8081" placeholder="udp" style="width:72px">
|
||||
<label style="color:#a6adc8;font-size:11px;flex-shrink:0">Log:</label>
|
||||
<input type="number" id="log-port" value="8082" placeholder="log" style="width:72px">
|
||||
</div>
|
||||
<div class="menu-row">
|
||||
<label class="form-check" style="margin:0;font-size:11px">
|
||||
<input type="checkbox" id="auto-ports" checked onchange="toggleAutoPorts(this.checked)">
|
||||
<span style="color:#a6adc8">Auto ports (SERVICE_INFO)</span>
|
||||
</label>
|
||||
</div>
|
||||
<hr class="menu-sep">
|
||||
<div class="menu-btn-row">
|
||||
<button onclick="discoverCmd()">Discover</button>
|
||||
<button onclick="treeCmd()">Tree</button>
|
||||
<button onclick="serviceInfoCmd()">Info</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tb-group">
|
||||
<button id="btn-pause" onclick="togglePause()">⏸ Pause</button>
|
||||
<button onclick="openStepDialog()">⚙ Step</button>
|
||||
</div>
|
||||
<div class="tb-group">
|
||||
<button onclick="addPlot()">+ Plot</button>
|
||||
</div>
|
||||
<div class="tb-group">
|
||||
<button onclick="openForceDialog()">⚡ Force</button>
|
||||
<button onclick="openBreakDialog()">🔴 Break</button>
|
||||
<button onclick="openMsgDialog()">✉ Msg</button>
|
||||
</div>
|
||||
<div class="tb-group" style="border:none;margin-left:auto">
|
||||
<span id="udp-stats" style="color:#585b70;font-size:11px">0 pkts</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ═══ STEP STATUS BAR ═══ -->
|
||||
<div id="step-bar">
|
||||
<span>⏹ PAUSED at
|
||||
<b id="paused-gam">—</b></span>
|
||||
<span id="step-remaining"></span>
|
||||
<select id="step-thread" style="width:120px"></select>
|
||||
<button onclick="step(1)">Step 1</button>
|
||||
<button onclick="step(5)">Step 5</button>
|
||||
<button onclick="step(20)">Step 20</button>
|
||||
<button class="ok" onclick="togglePause()">▶ Resume</button>
|
||||
</div>
|
||||
<!-- ═══ MAIN ═══ -->
|
||||
<div id="main">
|
||||
<!-- LEFT: object tree -->
|
||||
<div id="left-panel">
|
||||
<div class="panel-header">
|
||||
<span>Object Tree</span>
|
||||
<button style="font-size:10px;padding:1px 6px" onclick="sendCmd('TREE')">↻</button>
|
||||
</div>
|
||||
<div class="panel-search"><input id="tree-search" oninput="filterTree(this.value)" placeholder="Search…"></div>
|
||||
<div class="panel-body" id="tree-body">
|
||||
<div class="empty-hint">Connect to MARTe2 then click Tree</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Left resize/collapse strip -->
|
||||
<div id="left-strip" class="panel-strip" title="Drag to resize · Click to collapse"></div>
|
||||
<!-- CENTER: plots -->
|
||||
<div id="center-panel">
|
||||
<div class="empty-hint" id="no-plots-hint">Add a plot panel to begin — drag signals from the tree or traced list</div>
|
||||
</div>
|
||||
<!-- Right resize/collapse strip -->
|
||||
<div id="right-strip" class="panel-strip" title="Drag to resize · Click to collapse"></div>
|
||||
<!-- RIGHT: tabs -->
|
||||
<div id="right-panel">
|
||||
<div class="tabs">
|
||||
<div class="tab active" onclick="switchTab('traced')">Traced</div>
|
||||
<div class="tab" onclick="switchTab('forced')">Forced</div>
|
||||
<div class="tab" onclick="switchTab('breaks')">Breaks</div>
|
||||
<div class="tab" onclick="switchTab('msgs')">Msgs</div>
|
||||
</div>
|
||||
<div class="tab-content active" id="tab-traced">
|
||||
<div class="empty-hint" id="no-traced-hint">No signals traced</div>
|
||||
</div>
|
||||
<div class="tab-content" id="tab-forced">
|
||||
<div class="empty-hint" id="no-forced-hint">No signals forced</div>
|
||||
</div>
|
||||
<div class="tab-content" id="tab-breaks">
|
||||
<div class="empty-hint" id="no-breaks-hint">No breakpoints set</div>
|
||||
</div>
|
||||
<div class="tab-content" id="tab-msgs">
|
||||
<div class="empty-hint" id="no-msgs-hint">No messages sent</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ═══ LOGS ═══ -->
|
||||
<div id="log-panel">
|
||||
<div id="log-toolbar">
|
||||
<button class="panel-toggle" title="Collapse logs" onclick="togglePanel('log-panel','▼','▲',this)" id="log-toggle-btn">▼</button>
|
||||
<span style="font-weight:600;color:#89b4fa">Logs</span>
|
||||
<label><input type="checkbox" id="lf-service" onchange="renderLogs()">
|
||||
Service</label>
|
||||
<label><input type="checkbox" id="lf-debug" checked onchange="renderLogs()">
|
||||
Debug</label>
|
||||
<label><input type="checkbox" id="lf-info" checked onchange="renderLogs()">
|
||||
Info</label>
|
||||
<label><input type="checkbox" id="lf-warn" checked onchange="renderLogs()">
|
||||
Warn</label>
|
||||
<label><input type="checkbox" id="lf-error" checked onchange="renderLogs()">
|
||||
Error</label>
|
||||
<input type="text" id="log-filter" placeholder="Filter…" oninput="renderLogs()" style="width:150px">
|
||||
<button onclick="logs=[];renderLogs()" style="margin-left:auto">Clear</button>
|
||||
<label><input type="checkbox" id="log-autoscroll" checked>
|
||||
Auto-scroll</label>
|
||||
</div>
|
||||
<div id="log-body"></div>
|
||||
</div>
|
||||
</div><!-- #app -->
|
||||
<!-- ═══ DIALOGS ═══ -->
|
||||
<!-- Force dialog -->
|
||||
<div class="dialog-overlay" id="dlg-force" style="display:none" onclick="if(event.target===this)closeDlg('dlg-force')">
|
||||
<div class="dialog">
|
||||
<h3>⚡ Force Signal</h3>
|
||||
<label>Signal</label>
|
||||
<input id="force-sig" list="force-sig-list" placeholder="Signal path…">
|
||||
<datalist id="force-sig-list"></datalist>
|
||||
<label>Value</label>
|
||||
<input id="force-val" placeholder="e.g. 42">
|
||||
<div class="btns">
|
||||
<button onclick="closeDlg('dlg-force')">Cancel</button>
|
||||
<button class="active" onclick="doForce()">Force</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Unforce confirm -->
|
||||
<div class="dialog-overlay" id="dlg-unforce" style="display:none" onclick="if(event.target===this)closeDlg('dlg-unforce')">
|
||||
<div class="dialog">
|
||||
<h3>Remove Force</h3>
|
||||
<p id="unforce-msg" style="margin-bottom:12px;color:#cdd6f4"></p>
|
||||
<div class="btns">
|
||||
<button onclick="closeDlg('dlg-unforce')">Cancel</button>
|
||||
<button class="danger" onclick="doUnforce()">Unforce</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Break dialog -->
|
||||
<div class="dialog-overlay" id="dlg-break" style="display:none" onclick="if(event.target===this)closeDlg('dlg-break')">
|
||||
<div class="dialog">
|
||||
<h3>🔴 Set Breakpoint</h3>
|
||||
<label>Signal</label>
|
||||
<input id="break-sig" list="break-sig-list" placeholder="Signal path…">
|
||||
<datalist id="break-sig-list"></datalist>
|
||||
<div class="form-row">
|
||||
<div>
|
||||
<label>Operator</label>
|
||||
<select id="break-op">
|
||||
<option>></option><option>>=</option>
|
||||
<option><</option><option><=</option>
|
||||
<option>==</option><option>!=</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label>Threshold</label>
|
||||
<input id="break-thresh" placeholder="0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="btns">
|
||||
<button onclick="closeDlg('dlg-break')">Cancel</button>
|
||||
<button class="active" onclick="doBreak()">Set Break</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Message dialog -->
|
||||
<div class="dialog-overlay" id="dlg-msg" style="display:none" onclick="if(event.target===this)closeDlg('dlg-msg')">
|
||||
<div class="dialog">
|
||||
<h3>✉ Send Message</h3>
|
||||
<label>Destination</label>
|
||||
<input id="msg-dest" list="msg-dest-list" placeholder="e.g. App.Functions.GAM1">
|
||||
<datalist id="msg-dest-list"></datalist>
|
||||
<label>Function</label>
|
||||
<input id="msg-func" placeholder="FunctionName">
|
||||
<label>Payload (key=value lines)</label>
|
||||
<textarea id="msg-payload" placeholder="Key = Value Key2 = Value2"></textarea>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="msg-wait">
|
||||
<label for="msg-wait">Wait for reply</label>
|
||||
</div>
|
||||
<div class="btns">
|
||||
<button onclick="closeDlg('dlg-msg')">Cancel</button>
|
||||
<button class="active" onclick="doSendMsg()">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Array signal dialog (Trace / Force / Break with index/range selection) -->
|
||||
<div class="dialog-overlay" id="dlg-array" style="display:none" onclick="if(event.target===this)closeDlg('dlg-array')">
|
||||
<div class="dialog" style="min-width:360px">
|
||||
<h3 id="arr-dlg-title">Array Signal</h3>
|
||||
<p style="font-size:11px;color:#a6adc8;margin-bottom:14px">
|
||||
<b id="arr-dlg-sig" style="color:#cdd6f4"></b>
|
||||
· <span id="arr-dlg-n" style="color:#89b4fa"></span> elements
|
||||
</p>
|
||||
<!-- Segmented selection toggle -->
|
||||
<label style="margin-bottom:6px">Apply to</label>
|
||||
<div class="arr-seg">
|
||||
<button id="arr-sel-all" class="active" onclick="setArrSel('all')">All</button>
|
||||
<button id="arr-sel-idx" onclick="setArrSel('idx')">Index</button>
|
||||
<button id="arr-sel-rng" onclick="setArrSel('rng')">Range</button>
|
||||
</div>
|
||||
<!-- Index mode: single number input -->
|
||||
<div id="arr-idx-sect" style="display:none">
|
||||
<label>Element index <span style="color:#585b70;font-weight:normal">(0 – <span id="arr-idx-max"></span>)</span></label>
|
||||
<input id="arr-idx" type="number" min="0" value="0">
|
||||
</div>
|
||||
<!-- Range mode: start / end -->
|
||||
<div id="arr-rng-sect" style="display:none">
|
||||
<div class="form-row">
|
||||
<div>
|
||||
<label>From index</label>
|
||||
<input id="arr-r0" type="number" min="0" value="0">
|
||||
</div>
|
||||
<div>
|
||||
<label>To index <span style="color:#585b70;font-weight:normal">inclusive</span></label>
|
||||
<input id="arr-r1" type="number" min="0" value="0">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Force value (shown only for Force action) -->
|
||||
<div id="arr-force-sect" style="display:none">
|
||||
<label>Force value</label>
|
||||
<input id="arr-force-val" placeholder="e.g. 0">
|
||||
</div>
|
||||
<!-- Break condition (shown only for Break action) -->
|
||||
<div id="arr-break-sect" style="display:none">
|
||||
<div class="form-row">
|
||||
<div>
|
||||
<label>Condition</label>
|
||||
<select id="arr-break-op">
|
||||
<option>></option><option>>=</option>
|
||||
<option><</option><option><=</option>
|
||||
<option>==</option><option>!=</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label>Threshold</label>
|
||||
<input id="arr-break-thr" placeholder="0">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btns">
|
||||
<button onclick="closeDlg('dlg-array')">Cancel</button>
|
||||
<button id="arr-ok-btn" class="active" onclick="doArrayOp()">Apply</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Array → plot mode dialog (Sequential / Waterfall) -->
|
||||
<div class="dialog-overlay" id="dlg-arr-plot" style="display:none" onclick="if(event.target===this)closeDlg('dlg-arr-plot')">
|
||||
<div class="dialog" style="min-width:360px">
|
||||
<h3>Plot Array Signal</h3>
|
||||
<p style="font-size:11px;color:#a6adc8;margin-bottom:14px">
|
||||
<b id="arrp-name" style="color:#cdd6f4"></b>
|
||||
· <span id="arrp-n" style="color:#89b4fa"></span>
|
||||
elements
|
||||
</p>
|
||||
<div class="arr-seg" style="margin-bottom:8px">
|
||||
<button id="arrp-sel-sequential" class="active" onclick="setArrpMode('sequential')">Sequential</button>
|
||||
<button id="arrp-sel-waterfall" onclick="setArrpMode('waterfall')">Waterfall</button>
|
||||
</div>
|
||||
<p id="arrp-desc" style="font-size:10px;color:#a6adc8;margin-bottom:16px;min-height:28px"></p>
|
||||
<div class="btns">
|
||||
<button onclick="closeDlg('dlg-arr-plot')">Cancel</button>
|
||||
<button class="active" onclick="doArrayPlotMode()">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Info dialog -->
|
||||
<div class="dialog-overlay" id="dlg-info" style="display:none" onclick="if(event.target===this)closeDlg('dlg-info')">
|
||||
<div class="dialog" style="max-width:600px;width:90vw">
|
||||
<h3 id="info-title">Info</h3>
|
||||
<pre id="info-body" style="background:#11111b;padding:8px;border-radius:4px;overflow:auto;max-height:400px;font-size:11px;color:#cdd6f4;white-space:pre-wrap"></pre>
|
||||
<div class="btns" style="margin-top:12px">
|
||||
<button onclick="closeDlg('dlg-info')">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Step dialog -->
|
||||
<div class="dialog-overlay" id="dlg-step" style="display:none" onclick="if(event.target===this)closeDlg('dlg-step')">
|
||||
<div class="dialog">
|
||||
<h3>⚙ Step Execution</h3>
|
||||
<div class="form-row">
|
||||
<div>
|
||||
<label>Count</label>
|
||||
<input type="number" id="step-count" value="1" min="1">
|
||||
</div>
|
||||
<div>
|
||||
<label>Thread (optional)</label>
|
||||
<input id="step-thread-inp" list="step-thread-list" placeholder="all">
|
||||
<datalist id="step-thread-list"></datalist>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btns">
|
||||
<button onclick="closeDlg('dlg-step')">Cancel</button>
|
||||
<button class="active" onclick="doStep()">Step</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="uplot.min.js"></script>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
+1
@@ -0,0 +1 @@
|
||||
.uplot, .uplot *, .uplot *::before, .uplot *::after {box-sizing: border-box;}.uplot {font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";line-height: 1.5;width: min-content;}.u-title {text-align: center;font-size: 18px;font-weight: bold;}.u-wrap {position: relative;user-select: none;}.u-over, .u-under {position: absolute;}.u-under {overflow: hidden;}.uplot canvas {display: block;position: relative;width: 100%;height: 100%;}.u-axis {position: absolute;}.u-legend {font-size: 14px;margin: auto;text-align: center;}.u-inline {display: block;}.u-inline * {display: inline-block;}.u-inline tr {margin-right: 16px;}.u-legend th {font-weight: 600;}.u-legend th > * {vertical-align: middle;display: inline-block;}.u-legend .u-marker {width: 1em;height: 1em;margin-right: 4px;background-clip: padding-box !important;}.u-inline.u-live th::after {content: ":";vertical-align: middle;}.u-inline:not(.u-live) .u-value {display: none;}.u-series > * {padding: 4px;}.u-series th {cursor: pointer;}.u-legend .u-off > * {opacity: 0.3;}.u-select {background: rgba(0,0,0,0.07);position: absolute;pointer-events: none;}.u-cursor-x, .u-cursor-y {position: absolute;left: 0;top: 0;pointer-events: none;will-change: transform;}.u-hz .u-cursor-x, .u-vt .u-cursor-y {height: 100%;border-right: 1px dashed #607D8B;}.u-hz .u-cursor-y, .u-vt .u-cursor-x {width: 100%;border-bottom: 1px dashed #607D8B;}.u-cursor-pt {position: absolute;top: 0;left: 0;border-radius: 50%;border: 0 solid;pointer-events: none;will-change: transform;/*this has to be !important since we set inline "background" shorthand */background-clip: padding-box !important;}.u-axis.u-off, .u-select.u-off, .u-cursor-x.u-off, .u-cursor-y.u-off, .u-cursor-pt.u-off {display: none;}
|
||||
+2
File diff suppressed because one or more lines are too long
@@ -91,6 +91,7 @@ struct ConnectionConfig {
|
||||
tcp_port: String,
|
||||
udp_port: String,
|
||||
log_port: String,
|
||||
auto_ports: bool, // when true, SERVICE_INFO may override udp_port / log_port
|
||||
version: u64,
|
||||
}
|
||||
|
||||
@@ -314,6 +315,7 @@ impl MarteDebugApp {
|
||||
tcp_port: "8080".to_string(),
|
||||
udp_port: "8081".to_string(),
|
||||
log_port: "8082".to_string(),
|
||||
auto_ports: true,
|
||||
version: 0,
|
||||
};
|
||||
let shared_config = Arc::new(Mutex::new(config.clone()));
|
||||
@@ -1102,7 +1104,7 @@ fn udp_worker(
|
||||
thread::sleep(std::time::Duration::from_secs(1));
|
||||
continue;
|
||||
};
|
||||
let mut buf = [0u8; 4096];
|
||||
let mut buf = [0u8; 65535];
|
||||
let mut total_packets = 0u64;
|
||||
loop {
|
||||
if shared_config.lock().unwrap().version != current_version {
|
||||
@@ -1360,23 +1362,25 @@ impl eframe::App for MarteDebugApp {
|
||||
let _ = self.tx_cmd.send("DISCOVER".to_string());
|
||||
}
|
||||
InternalEvent::ServiceConfig { udp_port, log_port } => {
|
||||
let mut changed = false;
|
||||
if !udp_port.is_empty() && self.config.udp_port != udp_port {
|
||||
self.config.udp_port = udp_port;
|
||||
changed = true;
|
||||
}
|
||||
if !log_port.is_empty() && self.config.log_port != log_port {
|
||||
self.config.log_port = log_port;
|
||||
changed = true;
|
||||
}
|
||||
if changed {
|
||||
self.config.version += 1;
|
||||
*self.shared_config.lock().unwrap() = self.config.clone();
|
||||
self.logs.push_back(LogEntry {
|
||||
time: Local::now().format("%H:%M:%S").to_string(),
|
||||
level: "GUI_INFO".to_string(),
|
||||
message: format!("Config updated from server: UDP={}, LOG={}", self.config.udp_port, self.config.log_port),
|
||||
});
|
||||
if self.config.auto_ports {
|
||||
let mut changed = false;
|
||||
if !udp_port.is_empty() && self.config.udp_port != udp_port {
|
||||
self.config.udp_port = udp_port;
|
||||
changed = true;
|
||||
}
|
||||
if !log_port.is_empty() && self.config.log_port != log_port {
|
||||
self.config.log_port = log_port;
|
||||
changed = true;
|
||||
}
|
||||
if changed {
|
||||
self.config.version += 1;
|
||||
*self.shared_config.lock().unwrap() = self.config.clone();
|
||||
self.logs.push_back(LogEntry {
|
||||
time: Local::now().format("%H:%M:%S").to_string(),
|
||||
level: "GUI_INFO".to_string(),
|
||||
message: format!("Ports auto-configured: UDP={}, LOG={}", self.config.udp_port, self.config.log_port),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
InternalEvent::Disconnected => {
|
||||
@@ -1942,14 +1946,17 @@ impl eframe::App for MarteDebugApp {
|
||||
ui.label("IP:");
|
||||
ui.text_edit_singleline(&mut self.config.ip);
|
||||
ui.end_row();
|
||||
ui.label("Control:");
|
||||
ui.label("Control TCP:");
|
||||
ui.text_edit_singleline(&mut self.config.tcp_port);
|
||||
ui.end_row();
|
||||
ui.label("Telemetry (Auto):");
|
||||
ui.label(&self.config.udp_port);
|
||||
ui.label("Telemetry UDP:");
|
||||
ui.add_enabled(!self.config.auto_ports, egui::TextEdit::singleline(&mut self.config.udp_port));
|
||||
ui.end_row();
|
||||
ui.label("Logs (Auto):");
|
||||
ui.label(&self.config.log_port);
|
||||
ui.label("Log TCP:");
|
||||
ui.add_enabled(!self.config.auto_ports, egui::TextEdit::singleline(&mut self.config.log_port));
|
||||
ui.end_row();
|
||||
ui.label("Auto ports:");
|
||||
ui.checkbox(&mut self.config.auto_ports, "from SERVICE_INFO");
|
||||
ui.end_row();
|
||||
});
|
||||
if ui.button("🔄 Apply").clicked() {
|
||||
|
||||
+188
-293
@@ -2,24 +2,24 @@
|
||||
{
|
||||
"file": "TcpLogger.cpp",
|
||||
"arguments": [
|
||||
"g++",
|
||||
"/usr/bin/g++",
|
||||
"-c",
|
||||
"-I.",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-fPIC",
|
||||
"-Wall",
|
||||
"-std=c++98",
|
||||
@@ -47,25 +47,26 @@
|
||||
{
|
||||
"file": "DebugService.cpp",
|
||||
"arguments": [
|
||||
"g++",
|
||||
"/usr/bin/g++",
|
||||
"-c",
|
||||
"-I../../../..//Source/Core/Types/Result",
|
||||
"-I../../../..//Source/Core/Types/Vec",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-I../../../..//Source/Components/Interfaces/TCPLogger",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-fPIC",
|
||||
"-Wall",
|
||||
"-std=c++98",
|
||||
@@ -90,30 +91,169 @@
|
||||
"directory": "/home/martino/Projects/marte_debug/Source/Components/Interfaces/DebugService",
|
||||
"output": "../../../..//Build/x86-linux/Components/Interfaces/DebugService/DebugService.o"
|
||||
},
|
||||
{
|
||||
"file": "DebugServiceBase.cpp",
|
||||
"arguments": [
|
||||
"/usr/bin/g++",
|
||||
"-c",
|
||||
"-I../../../..//Source/Core/Types/Result",
|
||||
"-I../../../..//Source/Core/Types/Vec",
|
||||
"-I../../../..//Source/Components/Interfaces/TCPLogger",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-fPIC",
|
||||
"-Wall",
|
||||
"-std=c++98",
|
||||
"-Werror",
|
||||
"-Wno-invalid-offsetof",
|
||||
"-Wno-unused-variable",
|
||||
"-fno-strict-aliasing",
|
||||
"-frtti",
|
||||
"-DMARTe2_TEST_ENVIRONMENT=GTest",
|
||||
"-DARCHITECTURE=x86_gcc",
|
||||
"-DENVIRONMENT=Linux",
|
||||
"-DUSE_PTHREAD",
|
||||
"-pthread",
|
||||
"-Wno-deprecated-declarations",
|
||||
"-Wno-unused-value",
|
||||
"-g",
|
||||
"-ggdb",
|
||||
"DebugServiceBase.cpp",
|
||||
"-o",
|
||||
"../../../..//Build/x86-linux/Components/Interfaces/DebugService/DebugServiceBase.o"
|
||||
],
|
||||
"directory": "/home/martino/Projects/marte_debug/Source/Components/Interfaces/DebugService",
|
||||
"output": "../../../..//Build/x86-linux/Components/Interfaces/DebugService/DebugServiceBase.o"
|
||||
},
|
||||
{
|
||||
"file": "WebDebugService.cpp",
|
||||
"arguments": [
|
||||
"/usr/bin/g++",
|
||||
"-c",
|
||||
"-I../../../..//Source/Components/Interfaces/TCPLogger",
|
||||
"-I../../../..//Source/Components/Interfaces/DebugService",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-fPIC",
|
||||
"-Wall",
|
||||
"-std=c++98",
|
||||
"-Werror",
|
||||
"-Wno-invalid-offsetof",
|
||||
"-Wno-unused-variable",
|
||||
"-fno-strict-aliasing",
|
||||
"-frtti",
|
||||
"-DMARTe2_TEST_ENVIRONMENT=GTest",
|
||||
"-DARCHITECTURE=x86_gcc",
|
||||
"-DENVIRONMENT=Linux",
|
||||
"-DUSE_PTHREAD",
|
||||
"-pthread",
|
||||
"-Wno-deprecated-declarations",
|
||||
"-Wno-unused-value",
|
||||
"-g",
|
||||
"-ggdb",
|
||||
"WebDebugService.cpp",
|
||||
"-o",
|
||||
"../../../..//Build/x86-linux/Components/Interfaces/WebDebugService/WebDebugService.o"
|
||||
],
|
||||
"directory": "/home/martino/Projects/marte_debug/Source/Components/Interfaces/WebDebugService",
|
||||
"output": "../../../..//Build/x86-linux/Components/Interfaces/WebDebugService/WebDebugService.o"
|
||||
},
|
||||
{
|
||||
"file": "../../../..//Source/Components/Interfaces/DebugService/DebugServiceBase.cpp",
|
||||
"arguments": [
|
||||
"/usr/bin/g++",
|
||||
"-c",
|
||||
"-I../../../..//Source/Components/Interfaces/TCPLogger",
|
||||
"-I../../../..//Source/Components/Interfaces/DebugService",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-fPIC",
|
||||
"-Wall",
|
||||
"-std=c++98",
|
||||
"-Werror",
|
||||
"-Wno-invalid-offsetof",
|
||||
"-Wno-unused-variable",
|
||||
"-fno-strict-aliasing",
|
||||
"-frtti",
|
||||
"-DMARTe2_TEST_ENVIRONMENT=GTest",
|
||||
"-DARCHITECTURE=x86_gcc",
|
||||
"-DENVIRONMENT=Linux",
|
||||
"-DUSE_PTHREAD",
|
||||
"-pthread",
|
||||
"-Wno-deprecated-declarations",
|
||||
"-Wno-unused-value",
|
||||
"-g",
|
||||
"-ggdb",
|
||||
"../../../..//Source/Components/Interfaces/DebugService/DebugServiceBase.cpp",
|
||||
"-o",
|
||||
"../../../..//Build/x86-linux/Components/Interfaces/WebDebugService/DebugServiceBase.o"
|
||||
],
|
||||
"directory": "/home/martino/Projects/marte_debug/Source/Components/Interfaces/WebDebugService",
|
||||
"output": "../../../..//Build/x86-linux/Components/Interfaces/WebDebugService/DebugServiceBase.o"
|
||||
},
|
||||
{
|
||||
"file": "UnitTests.cpp",
|
||||
"arguments": [
|
||||
"g++",
|
||||
"/usr/bin/g++",
|
||||
"-c",
|
||||
"-I../../Source/Core/Types/Result",
|
||||
"-I../../Source/Core/Types/Vec",
|
||||
"-I../../Source/Components/Interfaces/DebugService",
|
||||
"-I../../Source/Components/Interfaces/TCPLogger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/workspace/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-fPIC",
|
||||
"-Wall",
|
||||
"-std=c++98",
|
||||
@@ -137,250 +277,5 @@
|
||||
],
|
||||
"directory": "/home/martino/Projects/marte_debug/Test/UnitTests",
|
||||
"output": "../../Build/x86-linux/Test/UnitTests/UnitTests/UnitTests.o"
|
||||
},
|
||||
{
|
||||
"file": "SchedulerTest.cpp",
|
||||
"arguments": [
|
||||
"g++",
|
||||
"-c",
|
||||
"-I../../Source/Core/Types/Result",
|
||||
"-I../../Source/Core/Types/Vec",
|
||||
"-I../../Source/Components/Interfaces/DebugService",
|
||||
"-I../../Source/Components/Interfaces/TCPLogger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L6App",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-fPIC",
|
||||
"-Wall",
|
||||
"-std=c++98",
|
||||
"-Werror",
|
||||
"-Wno-invalid-offsetof",
|
||||
"-Wno-unused-variable",
|
||||
"-fno-strict-aliasing",
|
||||
"-frtti",
|
||||
"-DMARTe2_TEST_ENVIRONMENT=GTest",
|
||||
"-DARCHITECTURE=x86_gcc",
|
||||
"-DENVIRONMENT=Linux",
|
||||
"-DUSE_PTHREAD",
|
||||
"-pthread",
|
||||
"-Wno-deprecated-declarations",
|
||||
"-Wno-unused-value",
|
||||
"-g",
|
||||
"-ggdb",
|
||||
"SchedulerTest.cpp",
|
||||
"-o",
|
||||
"../../Build/x86-linux/Test/Integration/Integration/SchedulerTest.o"
|
||||
],
|
||||
"directory": "/home/martino/Projects/marte_debug/Test/Integration",
|
||||
"output": "../../Build/x86-linux/Test/Integration/Integration/SchedulerTest.o"
|
||||
},
|
||||
{
|
||||
"file": "TraceTest.cpp",
|
||||
"arguments": [
|
||||
"g++",
|
||||
"-c",
|
||||
"-I../../Source/Core/Types/Result",
|
||||
"-I../../Source/Core/Types/Vec",
|
||||
"-I../../Source/Components/Interfaces/DebugService",
|
||||
"-I../../Source/Components/Interfaces/TCPLogger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L6App",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-fPIC",
|
||||
"-Wall",
|
||||
"-std=c++98",
|
||||
"-Werror",
|
||||
"-Wno-invalid-offsetof",
|
||||
"-Wno-unused-variable",
|
||||
"-fno-strict-aliasing",
|
||||
"-frtti",
|
||||
"-DMARTe2_TEST_ENVIRONMENT=GTest",
|
||||
"-DARCHITECTURE=x86_gcc",
|
||||
"-DENVIRONMENT=Linux",
|
||||
"-DUSE_PTHREAD",
|
||||
"-pthread",
|
||||
"-Wno-deprecated-declarations",
|
||||
"-Wno-unused-value",
|
||||
"-g",
|
||||
"-ggdb",
|
||||
"TraceTest.cpp",
|
||||
"-o",
|
||||
"../../Build/x86-linux/Test/Integration/Integration/TraceTest.o"
|
||||
],
|
||||
"directory": "/home/martino/Projects/marte_debug/Test/Integration",
|
||||
"output": "../../Build/x86-linux/Test/Integration/Integration/TraceTest.o"
|
||||
},
|
||||
{
|
||||
"file": "ValidationTest.cpp",
|
||||
"arguments": [
|
||||
"g++",
|
||||
"-c",
|
||||
"-I../../Source/Core/Types/Result",
|
||||
"-I../../Source/Core/Types/Vec",
|
||||
"-I../../Source/Components/Interfaces/DebugService",
|
||||
"-I../../Source/Components/Interfaces/TCPLogger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L6App",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-fPIC",
|
||||
"-Wall",
|
||||
"-std=c++98",
|
||||
"-Werror",
|
||||
"-Wno-invalid-offsetof",
|
||||
"-Wno-unused-variable",
|
||||
"-fno-strict-aliasing",
|
||||
"-frtti",
|
||||
"-DMARTe2_TEST_ENVIRONMENT=GTest",
|
||||
"-DARCHITECTURE=x86_gcc",
|
||||
"-DENVIRONMENT=Linux",
|
||||
"-DUSE_PTHREAD",
|
||||
"-pthread",
|
||||
"-Wno-deprecated-declarations",
|
||||
"-Wno-unused-value",
|
||||
"-g",
|
||||
"-ggdb",
|
||||
"ValidationTest.cpp",
|
||||
"-o",
|
||||
"../../Build/x86-linux/Test/Integration/Integration/ValidationTest.o"
|
||||
],
|
||||
"directory": "/home/martino/Projects/marte_debug/Test/Integration",
|
||||
"output": "../../Build/x86-linux/Test/Integration/Integration/ValidationTest.o"
|
||||
},
|
||||
{
|
||||
"file": "ConfigCommandTest.cpp",
|
||||
"arguments": [
|
||||
"g++",
|
||||
"-c",
|
||||
"-I../../Source/Core/Types/Result",
|
||||
"-I../../Source/Core/Types/Vec",
|
||||
"-I../../Source/Components/Interfaces/DebugService",
|
||||
"-I../../Source/Components/Interfaces/TCPLogger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L6App",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-fPIC",
|
||||
"-Wall",
|
||||
"-std=c++98",
|
||||
"-Werror",
|
||||
"-Wno-invalid-offsetof",
|
||||
"-Wno-unused-variable",
|
||||
"-fno-strict-aliasing",
|
||||
"-frtti",
|
||||
"-DMARTe2_TEST_ENVIRONMENT=GTest",
|
||||
"-DARCHITECTURE=x86_gcc",
|
||||
"-DENVIRONMENT=Linux",
|
||||
"-DUSE_PTHREAD",
|
||||
"-pthread",
|
||||
"-Wno-deprecated-declarations",
|
||||
"-Wno-unused-value",
|
||||
"-g",
|
||||
"-ggdb",
|
||||
"ConfigCommandTest.cpp",
|
||||
"-o",
|
||||
"../../Build/x86-linux/Test/Integration/Integration/ConfigCommandTest.o"
|
||||
],
|
||||
"directory": "/home/martino/Projects/marte_debug/Test/Integration",
|
||||
"output": "../../Build/x86-linux/Test/Integration/Integration/ConfigCommandTest.o"
|
||||
},
|
||||
{
|
||||
"file": "IntegrationTests.cpp",
|
||||
"arguments": [
|
||||
"g++",
|
||||
"-c",
|
||||
"-I../../Source/Core/Types/Result",
|
||||
"-I../../Source/Core/Types/Vec",
|
||||
"-I../../Source/Components/Interfaces/DebugService",
|
||||
"-I../../Source/Components/Interfaces/TCPLogger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L6App",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Messages",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L5GAMs",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability",
|
||||
"-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams",
|
||||
"-fPIC",
|
||||
"-Wall",
|
||||
"-std=c++98",
|
||||
"-Werror",
|
||||
"-Wno-invalid-offsetof",
|
||||
"-Wno-unused-variable",
|
||||
"-fno-strict-aliasing",
|
||||
"-frtti",
|
||||
"-DMARTe2_TEST_ENVIRONMENT=GTest",
|
||||
"-DARCHITECTURE=x86_gcc",
|
||||
"-DENVIRONMENT=Linux",
|
||||
"-DUSE_PTHREAD",
|
||||
"-pthread",
|
||||
"-Wno-deprecated-declarations",
|
||||
"-Wno-unused-value",
|
||||
"-g",
|
||||
"-ggdb",
|
||||
"IntegrationTests.cpp",
|
||||
"-o",
|
||||
"../../Build/x86-linux/Test/Integration/Integration/IntegrationTests.o"
|
||||
],
|
||||
"directory": "/home/martino/Projects/marte_debug/Test/Integration",
|
||||
"output": "../../Build/x86-linux/Test/Integration/Integration/IntegrationTests.o"
|
||||
}
|
||||
]
|
||||
@@ -2,8 +2,8 @@
|
||||
# Get the directory of this script
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
export MARTe2_DIR=$DIR/dependency/MARTe2
|
||||
export MARTe2_Components_DIR=$DIR/dependency/MARTe2-components
|
||||
export MARTe2_DIR=$HOME/workspace/MARTe2
|
||||
export MARTe2_Components_DIR=$HOME/workspace/MARTe2-components
|
||||
export TARGET=x86-linux
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_DIR/Build/$TARGET/Core
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_Components_DIR/Build/$TARGET/Components
|
||||
|
||||
Reference in New Issue
Block a user