diff --git a/run_debugtest.sh b/run_debugtest.sh index 791a414..1bee414 100755 --- a/run_debugtest.sh +++ b/run_debugtest.sh @@ -1,29 +1,35 @@ #!/usr/bin/env bash -# run_streamhub.sh — Launch a MARTe2 app with UDPStreamer + StreamHub +# run_debugtest.sh — Launch a small MARTe2 app under DebugService + the web debugger # # Usage: -# ./run_streamhub.sh [OPTIONS] +# ./run_debugtest.sh [OPTIONS] # # Options: # -m Override MARTe2 installation dir (default: $MARTe2_DIR) # -c Override MARTe2-components dir (default: $MARTe2_Components_DIR) # -b Build target (default: x86-linux) -# -p StreamHub WebSocket port (default: 8090) -# -n StreamHub ring-buffer size per signal (default: 10000) +# -f MARTe2 config (default: Test/Configurations/debug_test.cfg) +# -t RealTimeState to start in (default: State1) +# -p Debugger web UI port (default: 7777) +# -S Safe mode: do NOT allow FORCE/PAUSE/RESUME/STEP/BREAK +# from the browser (they are enabled by default here, +# since exercising them is the point of this script) # -s Skip building — run with whatever is already built -# -g Launch the ImGui desktop client after start -# -w Build and launch the web UI server (Client/webui) # -h Show this help # +# What it runs: +# MARTeApp.ex with debug_test.cfg — three RT threads over a LinuxTimer: +# GAM1 (1 kHz counter/time), GAM2 (1 Hz + a ConstantGAM float), +# GAM3 (100-sample block), plus a +DebugService object. +# Client/debugger (Go) — serves the browser debugger; the page connects to the +# app's control port itself, so the app can be restarted underneath it. +# # Ports used: -# 44500/udp UDPStreamer scalar signals (unicast control) -# 44503/udp UDPStreamer scalar signals (multicast data, group 239.0.0.1) -# 44501/udp UDPStreamer array signals (FirstSample / LastSample) -# 44502/udp UDPStreamer array signals (FullArray) -# 8080/tcp DebugService control -# 8081/udp DebugService stream -# 9090/tcp TCPLogger -# 8090/tcp StreamHub WebSocket (default, override with -p) +# 8080/tcp DebugService control (text commands) +# 8081/udp DebugService trace telemetry +# 8082/tcp TcpLogger (auto-injected by DebugService) +# 7777/tcp Debugger web UI (default, override with -p) +# The three DebugService ports come from the config file, not from this script. # # Environment: # MARTe2_DIR must be set (or passed via -m) @@ -32,28 +38,26 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -MARTe_CFG="${SCRIPT_DIR}/Test/Configurations/streamhub_demo.cfg" BUILD_TARGET="${TARGET:-x86-linux}" -WS_PORT=8090 -MAX_POINTS=1000000 +MARTe_CFG="${SCRIPT_DIR}/Test/Configurations/debug_test.cfg" +MARTe_STATE="State1" +UI_PORT=7777 +DANGEROUS=1 SKIP_BUILD=0 -START_GUI=0 -START_WEBUI=0 -WEBUI_PORT=8080 # ── Parse arguments ─────────────────────────────────────────────────────────── -while getopts "m:c:b:p:n:sgwh" opt; do +while getopts "m:c:b:f:t:p:Ssh" opt; do case "$opt" in m) MARTe2_DIR="$OPTARG" ;; c) MARTe2_Components_DIR="$OPTARG" ;; b) BUILD_TARGET="$OPTARG" ;; - p) WS_PORT="$OPTARG" ;; - n) MAX_POINTS="$OPTARG" ;; + f) MARTe_CFG="$OPTARG" ;; + t) MARTe_STATE="$OPTARG" ;; + p) UI_PORT="$OPTARG" ;; + S) DANGEROUS=0 ;; s) SKIP_BUILD=1 ;; - g) START_GUI=1 ;; - w) START_WEBUI=1 ;; h) - sed -n '2,30p' "$0" | grep '^#' | sed 's/^# \?//' + sed -n '2,40p' "$0" | grep '^#' | sed 's/^# \?//' exit 0 ;; *) echo "Unknown option: -$OPTARG" >&2; exit 1 ;; @@ -70,216 +74,132 @@ if [[ -z "${MARTe2_Components_DIR:-}" ]]; then echo "ERROR: MARTe2_Components_DIR is not set. Source env.sh first or pass -c ." exit 1 fi +if [[ ! -f "$MARTe_CFG" ]]; then + echo "ERROR: MARTe2 config not found: ${MARTe_CFG}" + exit 1 +fi BUILD_DIR="${SCRIPT_DIR}/Build/${BUILD_TARGET}" -STREAMHUB_EX="${BUILD_DIR}/StreamHub/StreamHub.ex" -IMGUI_CLIENT="${SCRIPT_DIR}/Client/streamhub/build/StreamHubClient" -WEBUI_DIR="${SCRIPT_DIR}/Client/webui" -WEBUI_BIN="${WEBUI_DIR}/streamhub-webui" +COMP_DIR="${MARTe2_Components_DIR}/Build/${BUILD_TARGET}/Components" +DEBUGGER_DIR="${SCRIPT_DIR}/Client/debugger" +DEBUGGER_BIN="${DEBUGGER_DIR}/marte2debugger" MARTE2_BIN="${MARTe2_DIR}/Build/${BUILD_TARGET}/App/MARTeApp.ex" if [[ ! -x "$MARTE2_BIN" ]]; then - MARTE2_BIN="${MARTe2_DIR}/Build/${BUILD_TARGET}/App/MARTe2.sh" -fi -if [[ ! -x "$MARTE2_BIN" ]]; then - echo "ERROR: MARTe2 executable not found at ${MARTe2_DIR}/Build/${BUILD_TARGET}/App/" + echo "ERROR: MARTeApp.ex not found at ${MARTe2_DIR}/Build/${BUILD_TARGET}/App/" exit 1 fi +# The DebugService ports live in the config, so read them back rather than +# printing numbers this script does not actually control. +cfg_port() { + grep -E "^[[:space:]]*$1[[:space:]]*=" "$MARTe_CFG" \ + | head -1 | tr -d ' \t' | cut -d= -f2 || true +} +CTRL_PORT="$(cfg_port ControlPort)"; CTRL_PORT="${CTRL_PORT:-8080}" +UDP_PORT="$(cfg_port UdpPort)"; UDP_PORT="${UDP_PORT:-8081}" +LOG_PORT="$(cfg_port LogPort)"; LOG_PORT="${LOG_PORT:-8082}" + # ── Build ───────────────────────────────────────────────────────────────────── if [[ "$SKIP_BUILD" -eq 0 ]]; then echo "==> Building MARTe2 components (TARGET=${BUILD_TARGET})..." - make -C "${SCRIPT_DIR}" -f Makefile.gcc TARGET="${BUILD_TARGET}" 2>&1 | tail -10 + make -C "${SCRIPT_DIR}" -f Makefile.gcc core TARGET="${BUILD_TARGET}" 2>&1 | tail -5 - echo "==> Building StreamHub (TARGET=${BUILD_TARGET})..." - make -C "${SCRIPT_DIR}/Source/Applications/StreamHub" \ - -f Makefile.gcc TARGET="${BUILD_TARGET}" \ - MARTe2_DIR="${MARTe2_DIR}" 2>&1 | tail -10 - - if [[ "$START_GUI" -eq 1 ]]; then - if [[ -d "${SCRIPT_DIR}/Client/streamhub/build" ]]; then - echo "==> Building ImGui client (a full rebuild can take ~2 min;" - echo " ImPlot's implot_items.cpp is one slow -O3 translation unit)..." - cmake --build "${SCRIPT_DIR}/Client/streamhub/build" -j"$(nproc)" - fi - fi - - if [[ "$START_WEBUI" -eq 1 ]]; then - echo "==> Building web UI server..." - (cd "${WEBUI_DIR}" && go build -o streamhub-webui .) - fi + echo "==> Building debugger client..." + (cd "${DEBUGGER_DIR}" && go build -o marte2debugger .) echo "==> Build done." fi -# ── Sanity-check binaries ───────────────────────────────────────────────────── -if [[ ! -x "$STREAMHUB_EX" ]]; then - echo "ERROR: StreamHub binary not found: ${STREAMHUB_EX}" - echo " Build it with: make -C Source/Applications/StreamHub -f Makefile.gcc" +if [[ ! -x "$DEBUGGER_BIN" ]]; then + echo "ERROR: debugger client not found: ${DEBUGGER_BIN}" + echo " Build it with: cd Client/debugger && go build -o marte2debugger ." exit 1 fi -# ── Write StreamHub config ──────────────────────────────────────────────────── -HUB_CFG="$(mktemp /tmp/streamhub_XXXXXX.cfg)" - -cat > "$HUB_CFG" < Shutting down..." - [[ -n "$WEBUI_PID" ]] && kill "$WEBUI_PID" 2>/dev/null || true - [[ -n "$GUI_PID" ]] && kill "$GUI_PID" 2>/dev/null || true - [[ -n "$HUB_PID" ]] && kill "$HUB_PID" 2>/dev/null || true + [[ -n "$UI_PID" ]] && kill "$UI_PID" 2>/dev/null || true [[ -n "$MARTE_PID" ]] && kill "$MARTE_PID" 2>/dev/null || true - wait "$WEBUI_PID" 2>/dev/null || true - wait "$GUI_PID" 2>/dev/null || true - wait "$HUB_PID" 2>/dev/null || true + wait "$UI_PID" 2>/dev/null || true wait "$MARTE_PID" 2>/dev/null || true - rm -f "$HUB_CFG" echo "==> Done." } trap cleanup EXIT INT TERM # ── Launch MARTe2 ───────────────────────────────────────────────────────────── echo "" -echo "==> Launching MARTe2..." +echo "==> Launching MARTe2 under DebugService..." echo " Binary : ${MARTE2_BIN}" echo " Config : ${MARTe_CFG}" -echo " Signals: Sine1 (1 Hz), Sine2 (0.3 Hz), Ch1-Ch4 (arrays)" +echo " State : ${MARTe_STATE}" echo "" "${MARTE2_BIN}" \ -l RealTimeLoader \ -f "${MARTe_CFG}" \ - -s Running \ - -m StateMachine:START & + -s "${MARTe_STATE}" & MARTE_PID="$!" -# Give MARTe2 a moment to bind its UDP ports before StreamHub connects +# Give the app time to reach the state and bind the DebugService control port. sleep 1 - -# ── Launch StreamHub ────────────────────────────────────────────────────────── -echo "==> Launching StreamHub..." -echo " Binary : ${STREAMHUB_EX}" -echo " Config : ${HUB_CFG}" -echo " WS port : ${WS_PORT}" -echo " MaxPoints: ${MAX_POINTS}" -echo "" - -"${STREAMHUB_EX}" -cfg "${HUB_CFG}" & -HUB_PID="$!" - -# ── Optionally launch the ImGui client ─────────────────────────────────────── -if [[ "$START_GUI" -eq 1 ]]; then - if [[ ! -x "$IMGUI_CLIENT" ]]; then - echo "WARNING: ImGui client not found at ${IMGUI_CLIENT}" - echo " Build it with: cd Client/streamhub && cmake -B build && cmake --build build" - else - sleep 0.5 - echo "==> Launching ImGui client (127.0.0.1:${WS_PORT})..." - "${IMGUI_CLIENT}" -host 127.0.0.1 -port "${WS_PORT}" & - GUI_PID="$!" - fi +if ! kill -0 "$MARTE_PID" 2>/dev/null; then + echo "ERROR: MARTe2 exited during startup — see the log above." + exit 1 fi -# ── Optionally launch the web UI server ────────────────────────────────────── -if [[ "$START_WEBUI" -eq 1 ]]; then - if [[ ! -x "$WEBUI_BIN" ]]; then - echo "WARNING: webui binary not found at ${WEBUI_BIN}" - echo " Build it with: cd Client/webui && go build -o streamhub-webui ." - else - echo "==> Launching web UI server (:${WEBUI_PORT})..." - "${WEBUI_BIN}" -addr ":${WEBUI_PORT}" \ - -hub "localhost:${WS_PORT}" \ - -static "${SCRIPT_DIR}/Client/udpstreamer/static" & - WEBUI_PID="$!" - fi +# ── Launch the debugger web client ──────────────────────────────────────────── +echo "==> Launching debugger client (:${UI_PORT})..." +DANGEROUS_FLAG=() +if [[ "$DANGEROUS" -eq 1 ]]; then + DANGEROUS_FLAG=(-enable-dangerous-commands) fi +"${DEBUGGER_BIN}" -addr ":${UI_PORT}" "${DANGEROUS_FLAG[@]}" & +UI_PID="$!" + +sleep 0.5 + # ── Status ──────────────────────────────────────────────────────────────────── -echo " MARTe2 PID : ${MARTE_PID}" -echo " StreamHub PID: ${HUB_PID}" -[[ -n "$GUI_PID" ]] && echo " ImGui PID : ${GUI_PID}" -[[ -n "$WEBUI_PID" ]] && echo " WebUI PID : ${WEBUI_PID}" echo "" -echo " StreamHub WebSocket: ws://127.0.0.1:${WS_PORT}" -[[ -n "$WEBUI_PID" ]] && echo " Browser client : http://localhost:${WEBUI_PORT}/" -[[ -x "$IMGUI_CLIENT" ]] && echo " ImGui client : ${IMGUI_CLIENT} -host 127.0.0.1 -port ${WS_PORT}" +echo " MARTe2 PID : ${MARTE_PID}" +echo " Debugger PID : ${UI_PID}" echo "" -echo " Press Ctrl-C to stop all processes." +echo " Debugger UI : http://localhost:${UI_PORT}/" +echo " DebugService : control tcp/${CTRL_PORT}, trace udp/${UDP_PORT}, log tcp/${LOG_PORT}" +if [[ "$DANGEROUS" -eq 1 ]]; then + echo " FORCE/PAUSE/RESUME/STEP/BREAK: enabled (pass -S to disable)" +else + echo " FORCE/PAUSE/RESUME/STEP/BREAK: disabled (-S)" +fi +echo "" +echo " In the browser, press Connect (defaults to 127.0.0.1:${CTRL_PORT})," +echo " then Discover to list the app's GAMs and signals." +echo "" +echo " Press Ctrl-C to stop both processes." echo "" -# ── Wait until any child exits ──────────────────────────────────────────────── -wait -n "${MARTE_PID}" "${HUB_PID}" ${GUI_PID:-} ${WEBUI_PID:-} 2>/dev/null || true -echo "==> A process exited — stopping remaining processes." +# ── Wait until either child exits ───────────────────────────────────────────── +wait -n "${MARTE_PID}" "${UI_PID}" 2>/dev/null || true +echo "==> A process exited — stopping the other." diff --git a/run_udp_producer.sh b/run_udp_producer.sh index a097a3f..44cf8cd 100755 --- a/run_udp_producer.sh +++ b/run_udp_producer.sh @@ -81,11 +81,16 @@ fi # Distinct amplitude/frequency/phase per channel so traces stay tellable apart # (and so a shared-Y-axis view has a spread of magnitudes to cope with). AMPS=(1.0 2.5 0.5 5.0 1.5 3.0 0.8 4.0 2.0 0.3 6.0 1.2 3.5) -FREQS=(1000 2000 5000 500 10000 3000 20000 1500 7000 50000 800 4000 15000) +FREQS=(1 2000 5000 500 10000 3000 20000 1500 7000 50000 800 4000 15000) PHASES=(0.0 0.7854 1.5708 2.3562 3.1416 3.9270 4.7124 5.4978 0.3927 1.1781 1.9635 2.7489 3.5343) -ELEMS=1000 # samples per cycle -RATE=1000 # cycles per second -> 1 Msps +ELEMS=10000 # samples per cycle +RATE=100 # cycles per second -> 1 Msps +# Declared to UDPStreamer as SamplingRate, which is the only per-signal rate it +# puts on the wire. Without it the CONFIG descriptor carries 0 and consumers show +# no rate — decoding is unaffected (FullArray signals are dated per element from +# TimeArray), but the metadata is what a client displays. +SAMPLING_RATE=$(( ELEMS * RATE )) CYCLE_BYTES=$(( 8 * ELEMS + CHANNELS * 4 * ELEMS )) PAYLOAD=$(( CYCLE_BYTES + 2000 )) # headroom for header + descriptors @@ -137,6 +142,7 @@ for (( i = 1; i <= CHANNELS; i++ )); do RangeMax = ${amp} TimeMode = \"FullArray\" TimeSignal = TimeArray + SamplingRate = ${SAMPLING_RATE}.0 }" func_list+=", SineGAM${i}" done @@ -242,7 +248,7 @@ ${sine_gams} // One cycle is ${CYCLE_BYTES} B; sizing the payload above that sends each // cycle as a single datagram, which keeps the receiver's reassembly pool // from evicting in-flight cycles and gapping the trace. - MaxPayloadSize = ${PAYLOAD} + MaxPayloadSize = 1400 //${PAYLOAD} PublishingMode = "Strict" Signals = { TimeArray = { @@ -250,6 +256,7 @@ ${sine_gams} Unit = "ns" NumberOfDimensions = 1 NumberOfElements = ${ELEMS} + SamplingRate = ${SAMPLING_RATE}.0 }${stream_sigs} } }