7.7 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Overview
MARTe2 component library providing real-time signal streaming (UDPStreamer DataSource → StreamHub → web/ImGui oscilloscopes) and zero-code-change debugging (DebugService Interface: trace/force/breakpoint via registry-patched broker wrappers). See ARCHITECTURE.md for full detail and Docs/ for per-component references.
Build & Test
Requires MARTe2 and MARTe2-components built externally; env.sh sets MARTe2_DIR, MARTe2_Components_DIR, TARGET=x86-linux, and LD_LIBRARY_PATH (needed both for building and for running anything).
source env.sh
make -f Makefile.gcc core # all C++ MARTe2 components
make -f Makefile.gcc apps # StreamHub standalone app
make -f Makefile.gcc test # build GTest + Integration tests
make -f Makefile.gcc clean
# Run tests (after source env.sh)
./Build/x86-linux/GTest/MainGTest.ex # unit tests (UDPStreamer)
./Build/x86-linux/GTest/MainGTest.ex --gtest_filter='Name*' # single test
./Build/x86-linux/Test/Integration/Integration/IntegrationTests.ex # DebugService integration tests
# Build a single component (each component dir has its own Makefile.gcc)
make -C Source/Components/DataSources/UDPStreamer -f Makefile.gcc
# Go clients
cd Common/Client/go && go build ./...
cd Client/debugger && go build ./...
# ImGui desktop client (not a MARTe2 component; needs SDL2)
cd Client/streamhub && cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build
# Qt desktop client (not a MARTe2 component; needs Qt5 or Qt6 Widgets + WebSockets)
cd Client/streamhub-qt && cmake -B build && cmake --build build
End-to-end demo script (build + launch full stack, see header for ports/options): ./run_streamhub.sh.
Streaming-chain E2E suite (Test/E2E/suite/):
./Test/E2E/suite/run_e2e.sh [flags]
Flags:
| Flag | Effect |
|---|---|
--skip-build |
Skip C++ component rebuild |
--only <id> |
Run a single scenario by ID |
--pdf-only |
Just compile the Typst PDF report |
--cpp-coverage |
Instrumented gcov rebuild + lcov capture (on by default) |
--skip-coverage |
Disable the coverage pass |
--skip-stress |
Skip the stress matrix |
--skip-datasources |
Skip direct scenarios |
--skip-recorder |
Skip recorder scenarios |
--skip-debug |
Skip debug and debug_pause_resume scenarios |
--skip-tcplogger |
Skip tcplogger scenarios |
Scenario kinds (defined in scenarios.py):
- chain — full streaming pipeline: MARTe2 → UDPStreamer → StreamHub → Go
chain-client(live/zoom/window/trigger). Validates recorded waveform against analytic/fed oracle (validate_waveform.py: fidelity gates correctness, sine shape-fit is a gross-sanity gate + tracked metric). - direct — MARTe2 FileReader → FileWriter round-trip, validates binary output.
- recorder — MARTe2 → StreamHub with history recorder, validates recorded
.binfile. - debug / debug_pause_resume — DebugService scenarios via the Go
debugclient. - tcplogger — TcpLogger scenarios via the Go
debugclient.
After scenarios, the suite runs unit tests + coverage (collect.py: C++ GTest, Go, Python; coverage uses lcov restricted to Source/* — the Test/ harness is excluded), consolidates everything into report_data.json with per-field progression/regression vs the previous run and trend plots (report_build.py, history in Build/x86-linux/E2E/chain/history.jsonl), and compiles a Typst PDF (E2E_Report.typ). Artifacts go to Build/x86-linux/E2E/chain/ (report, logs, PDF) and /tmp/chain_e2e/ (scratch). Results are aggregated into results.json with XFAIL/XPASS handling for known issues.
Python framework unit tests: python3 -m unittest tests_py (in Test/E2E/suite/).
Build output goes to Build/x86-linux/ (shared libs per component, .ex executables).
Architecture
Two independent data paths:
- Streaming path:
UDPStreamerDataSource serialises signals each RT cycle to UDPS binary packets (UDP 44500, unicast/multicast) →StreamHub(Source/Applications/StreamHub/, headless C++ app: ring buffers, LTTB decimation, trigger FSM) → WebSocket 8090 → browser (Client/udpstreamer, Go), native ImGui client (Client/streamhub), or native Qt client (Client/streamhub-qt). - Debug path:
DebugServicepatches theClassRegistryDatabaseatInitialise()so subsequentConfigureApplication()instantiatesDebugBrokerWrapper<T>around allMemoryMap*Brokertypes — no application changes. RT hot path goes throughDebugServiceI(abstract singleton inDebugServiceI.h) for forcing/tracing/breakpoints. Exposes TCP 8080 (text commands), UDP 8081 (trace telemetry), works withTcpLoggeron 8082. Web UI:Client/debugger(Go).
Shared wire format: Common/UDP/UDPSProtocol.h defines the UDPS binary protocol (17-byte packed header, 136-byte signal descriptors, little-endian). It is deliberately MARTe2-free so it's shared by C++ producers (UDPStreamer, DebugService), the C++ consumer (Source/Components/Interfaces/UDPStream/UDPSClient), and the Go decoder (Common/Client/go/udpsprotocol). Changes to the protocol must be mirrored across all of these, plus the JS client parsers.
StreamHub WebSocket protocol: JSON text frames for commands/events, binary frames for data pushes — spec in ARCHITECTURE.md §6. The Go hub (Client/udpstreamer) and C++ StreamHub implement the identical protocol; both clients (browser JS and ImGui) must stay compatible with both.
StreamHub History: HistoryWriter (Source/Applications/StreamHub/HistoryWriter.{h,cpp}) provides disk-backed circular storage of signal data. Each signal is stored in a separate .shist binary file with a 64-byte header and pre-allocated circular data region of (float64 time, float64 value) pairs. Configured via a +History block in the StreamHub config with keys: Directory (required), DurationHours (default 1), Decimation (default 1), FlushIntervalSec (default 5), MinDiskFreeMB (default 500). WS commands: historyInfo (returns metadata), historyZoom (reads time range from disk). Both the web SPA (Client/udpstreamer/static/app.js) and ImGui client support history zoom queries alongside in-memory ring zoom.
Conventions
- No STL in MARTe2 components (
Source/Components/): use MARTe2 types (StreamString,FastPollingMutexSem, fixed arrays). STL/C++17 is fine inClient/streamhub/andSource/Applications/StreamHub/follows MARTe2 style but links MARTe2 core. FastPollingMutexSemon RT hot paths (never OS mutexes).- Each component dir has
Makefile.gcc(wrapper),Makefile.inc(sources/includes), anddepends.x86-linux/dependsRaw.x86-linux(generated dependency files). - EUPL v1.1 license headers on C++ sources.
Qt client (Client/streamhub-qt/): native Widgets oscilloscope, feature/UX-equivalent to the ImGui client, speaking the identical StreamHub WebSocket protocol. CMake autodetects Qt6 (preferred) or Qt5 (find_package(QT NAMES Qt6 Qt5 ...) then Qt${QT_VERSION_MAJOR}:: targets) for old-Linux back-compat. It reuses ../streamhub/Protocol.{h,cpp} and SignalBuffer.h verbatim (framework-free C++17); those structs have members named signals, which collide with Qt's signals/slots/emit macros, so the build sets QT_NO_KEYWORDS and all Qt classes use Q_SIGNALS:/Q_SLOTS:/Q_EMIT. Single GUI thread (QWebSocket signals arrive on the GUI thread, no locks); a 60 Hz QTimer drives repaint. Plotting is custom QPainter (no QtCharts/QCustomPlot) for ImPlot parity and zero extra deps. Run: ./build/StreamHubQtClient --host HOST --port 8090 (long -- options; single-dash -host is misparsed as clustered short flags).