added test run scirpt

This commit is contained in:
Martino Ferrari committed 2026-11-06 13:42:20 +01:00
1 parent 50d85363a3
commit 05b9490b06
2 files changed
+113 -186

No files matched your search

+102 -182
View File
@@ -1,29 +1,35 @@
#!/usr/bin/env bash #!/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: # Usage:
# ./run_streamhub.sh [OPTIONS] # ./run_debugtest.sh [OPTIONS]
# #
# Options: # Options:
# -m <MARTe2_DIR> Override MARTe2 installation dir (default: $MARTe2_DIR) # -m <MARTe2_DIR> Override MARTe2 installation dir (default: $MARTe2_DIR)
# -c <MARTe2_Components_DIR> Override MARTe2-components dir (default: $MARTe2_Components_DIR) # -c <MARTe2_Components_DIR> Override MARTe2-components dir (default: $MARTe2_Components_DIR)
# -b <BUILD_TARGET> Build target (default: x86-linux) # -b <BUILD_TARGET> Build target (default: x86-linux)
# -p <WS_PORT> StreamHub WebSocket port (default: 8090) # -f <CFG> MARTe2 config (default: Test/Configurations/debug_test.cfg)
# -n <MAX_POINTS> StreamHub ring-buffer size per signal (default: 10000) # -t <STATE> RealTimeState to start in (default: State1)
# -p <PORT> 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 # -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 # -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: # Ports used:
# 44500/udp UDPStreamer scalar signals (unicast control) # 8080/tcp DebugService control (text commands)
# 44503/udp UDPStreamer scalar signals (multicast data, group 239.0.0.1) # 8081/udp DebugService trace telemetry
# 44501/udp UDPStreamer array signals (FirstSample / LastSample) # 8082/tcp TcpLogger (auto-injected by DebugService)
# 44502/udp UDPStreamer array signals (FullArray) # 7777/tcp Debugger web UI (default, override with -p)
# 8080/tcp DebugService control # The three DebugService ports come from the config file, not from this script.
# 8081/udp DebugService stream
# 9090/tcp TCPLogger
# 8090/tcp StreamHub WebSocket (default, override with -p)
# #
# Environment: # Environment:
# MARTe2_DIR must be set (or passed via -m) # MARTe2_DIR must be set (or passed via -m)
@@ -32,28 +38,26 @@
set -euo pipefail set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MARTe_CFG="${SCRIPT_DIR}/Test/Configurations/streamhub_demo.cfg"
BUILD_TARGET="${TARGET:-x86-linux}" BUILD_TARGET="${TARGET:-x86-linux}"
WS_PORT=8090 MARTe_CFG="${SCRIPT_DIR}/Test/Configurations/debug_test.cfg"
MAX_POINTS=1000000 MARTe_STATE="State1"
UI_PORT=7777
DANGEROUS=1
SKIP_BUILD=0 SKIP_BUILD=0
START_GUI=0
START_WEBUI=0
WEBUI_PORT=8080
# ── Parse arguments ─────────────────────────────────────────────────────────── # ── 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 case "$opt" in
m) MARTe2_DIR="$OPTARG" ;; m) MARTe2_DIR="$OPTARG" ;;
c) MARTe2_Components_DIR="$OPTARG" ;; c) MARTe2_Components_DIR="$OPTARG" ;;
b) BUILD_TARGET="$OPTARG" ;; b) BUILD_TARGET="$OPTARG" ;;
p) WS_PORT="$OPTARG" ;; f) MARTe_CFG="$OPTARG" ;;
n) MAX_POINTS="$OPTARG" ;; t) MARTe_STATE="$OPTARG" ;;
p) UI_PORT="$OPTARG" ;;
S) DANGEROUS=0 ;;
s) SKIP_BUILD=1 ;; s) SKIP_BUILD=1 ;;
g) START_GUI=1 ;;
w) START_WEBUI=1 ;;
h) h)
sed -n '2,30p' "$0" | grep '^#' | sed 's/^# \?//' sed -n '2,40p' "$0" | grep '^#' | sed 's/^# \?//'
exit 0 exit 0
;; ;;
*) echo "Unknown option: -$OPTARG" >&2; exit 1 ;; *) 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 <dir>." echo "ERROR: MARTe2_Components_DIR is not set. Source env.sh first or pass -c <dir>."
exit 1 exit 1
fi fi
if [[ ! -f "$MARTe_CFG" ]]; then
echo "ERROR: MARTe2 config not found: ${MARTe_CFG}"
exit 1
fi
BUILD_DIR="${SCRIPT_DIR}/Build/${BUILD_TARGET}" BUILD_DIR="${SCRIPT_DIR}/Build/${BUILD_TARGET}"
STREAMHUB_EX="${BUILD_DIR}/StreamHub/StreamHub.ex" COMP_DIR="${MARTe2_Components_DIR}/Build/${BUILD_TARGET}/Components"
IMGUI_CLIENT="${SCRIPT_DIR}/Client/streamhub/build/StreamHubClient" DEBUGGER_DIR="${SCRIPT_DIR}/Client/debugger"
WEBUI_DIR="${SCRIPT_DIR}/Client/webui" DEBUGGER_BIN="${DEBUGGER_DIR}/marte2debugger"
WEBUI_BIN="${WEBUI_DIR}/streamhub-webui"
MARTE2_BIN="${MARTe2_DIR}/Build/${BUILD_TARGET}/App/MARTeApp.ex" MARTE2_BIN="${MARTe2_DIR}/Build/${BUILD_TARGET}/App/MARTeApp.ex"
if [[ ! -x "$MARTE2_BIN" ]]; then if [[ ! -x "$MARTE2_BIN" ]]; then
MARTE2_BIN="${MARTe2_DIR}/Build/${BUILD_TARGET}/App/MARTe2.sh" echo "ERROR: MARTeApp.ex not found at ${MARTe2_DIR}/Build/${BUILD_TARGET}/App/"
fi
if [[ ! -x "$MARTE2_BIN" ]]; then
echo "ERROR: MARTe2 executable not found at ${MARTe2_DIR}/Build/${BUILD_TARGET}/App/"
exit 1 exit 1
fi 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 ───────────────────────────────────────────────────────────────────── # ── Build ─────────────────────────────────────────────────────────────────────
if [[ "$SKIP_BUILD" -eq 0 ]]; then if [[ "$SKIP_BUILD" -eq 0 ]]; then
echo "==> Building MARTe2 components (TARGET=${BUILD_TARGET})..." 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})..." echo "==> Building debugger client..."
make -C "${SCRIPT_DIR}/Source/Applications/StreamHub" \ (cd "${DEBUGGER_DIR}" && go build -o marte2debugger .)
-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 "==> Build done." echo "==> Build done."
fi fi
# ── Sanity-check binaries ───────────────────────────────────────────────────── if [[ ! -x "$DEBUGGER_BIN" ]]; then
if [[ ! -x "$STREAMHUB_EX" ]]; then echo "ERROR: debugger client not found: ${DEBUGGER_BIN}"
echo "ERROR: StreamHub binary not found: ${STREAMHUB_EX}" echo " Build it with: cd Client/debugger && go build -o marte2debugger ."
echo " Build it with: make -C Source/Applications/StreamHub -f Makefile.gcc"
exit 1 exit 1
fi fi
# ── Write StreamHub config ──────────────────────────────────────────────────── # ── Library path ──────────────────────────────────────────────────────────────
HUB_CFG="$(mktemp /tmp/streamhub_XXXXXX.cfg)" # DebugService pulls in TCPLogger and UDPStream; everything the config names
# beyond MARTe2 core (LinuxTimer, RealTimeThreadSynchronisation,
cat > "$HUB_CFG" <<EOF # LoggerDataSource, IOGAM, ConstantGAM) is dlopen'd from MARTe2-components.
/**
* StreamHub configuration — auto-generated by run_streamhub.sh
*
* Three sources matching the streamhub_demo MARTe2 configuration:
* scalar : 1 kHz scalar sines @ 1 ksps (Sine1, Sine2)
* med : 1 kHz arrays @ 1 Msps (Ch1, Ch2)
* fast : 5 kHz arrays @ 5 Msps (Ch3, Ch4)
*/
Hub = {
WSPort = ${WS_PORT}
MaxPoints = ${MAX_POINTS}
PushRate = 30
MaxPushPoints = 2000
RingTemporal = 1000000
RingScalar = 100000
+History = {
Directory = "/tmp/streamhub_history"
DurationHours = 1
Decimation = 10
FlushIntervalSec = 5
MinDiskFreeMB = 200
}
+Recorder = {
Enabled = 0
AutoStart = 1
Directory = "/tmp/streamhub_rec"
MaxFileMB = 256
KeepFiles = 8
StagingMB = 8
FlushIntervalSec = 5
MinDiskFreeMB = 500
Signals = "all"
}
Sources = {
scalar = {
Label = "Scalar Sines (1 ksps)"
Addr = "127.0.0.1"
Port = 44500
MulticastGroup = "239.0.0.1"
DataPort = 44503
}
med = {
Label = "1 Msps Sines (Ch1 1kHz, Ch2 5kHz)"
Addr = "127.0.0.1"
Port = 44501
}
fast = {
Label = "5 Msps Sines (Ch3 10kHz, Ch4 50kHz)"
Addr = "127.0.0.1"
Port = 44502
}
}
}
EOF
# ── Library path — covers both MARTe2 app and StreamHub ──────────────────────
export LD_LIBRARY_PATH="\ export LD_LIBRARY_PATH="\
${MARTe2_DIR}/Build/${BUILD_TARGET}/Core:\ ${MARTe2_DIR}/Build/${BUILD_TARGET}/Core:\
${MARTe2_Components_DIR}/Build/${BUILD_TARGET}/Components/DataSources/LinuxTimer:\ ${BUILD_DIR}/Components/Interfaces/DebugService:\
${MARTe2_Components_DIR}/Build/${BUILD_TARGET}/Components/GAMs/IOGAM:\ ${BUILD_DIR}/Components/Interfaces/TCPLogger:\
${BUILD_DIR}/Components/DataSources/UDPStreamer:\
${BUILD_DIR}/Components/GAMs/SineArrayGAM:\
${BUILD_DIR}/Components/GAMs/TimeArrayGAM:\
${BUILD_DIR}/Components/Interfaces/UDPStream:\ ${BUILD_DIR}/Components/Interfaces/UDPStream:\
${COMP_DIR}/DataSources/LinuxTimer:\
${COMP_DIR}/DataSources/RealTimeThreadSynchronisation:\
${COMP_DIR}/DataSources/LoggerDataSource:\
${COMP_DIR}/GAMs/IOGAM:\
${COMP_DIR}/GAMs/ConstantGAM:\
${LD_LIBRARY_PATH:-}" ${LD_LIBRARY_PATH:-}"
# ── Cleanup handler ─────────────────────────────────────────────────────────── # ── Cleanup handler ───────────────────────────────────────────────────────────
MARTE_PID="" MARTE_PID=""
HUB_PID="" UI_PID=""
GUI_PID=""
WEBUI_PID=""
cleanup() { cleanup() {
echo "" echo ""
echo "==> Shutting down..." echo "==> Shutting down..."
[[ -n "$WEBUI_PID" ]] && kill "$WEBUI_PID" 2>/dev/null || true [[ -n "$UI_PID" ]] && kill "$UI_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 "$MARTE_PID" ]] && kill "$MARTE_PID" 2>/dev/null || true [[ -n "$MARTE_PID" ]] && kill "$MARTE_PID" 2>/dev/null || true
wait "$WEBUI_PID" 2>/dev/null || true wait "$UI_PID" 2>/dev/null || true
wait "$GUI_PID" 2>/dev/null || true
wait "$HUB_PID" 2>/dev/null || true
wait "$MARTE_PID" 2>/dev/null || true wait "$MARTE_PID" 2>/dev/null || true
rm -f "$HUB_CFG"
echo "==> Done." echo "==> Done."
} }
trap cleanup EXIT INT TERM trap cleanup EXIT INT TERM
# ── Launch MARTe2 ───────────────────────────────────────────────────────────── # ── Launch MARTe2 ─────────────────────────────────────────────────────────────
echo "" echo ""
echo "==> Launching MARTe2..." echo "==> Launching MARTe2 under DebugService..."
echo " Binary : ${MARTE2_BIN}" echo " Binary : ${MARTE2_BIN}"
echo " Config : ${MARTe_CFG}" echo " Config : ${MARTe_CFG}"
echo " Signals: Sine1 (1 Hz), Sine2 (0.3 Hz), Ch1-Ch4 (arrays)" echo " State : ${MARTe_STATE}"
echo "" echo ""
"${MARTE2_BIN}" \ "${MARTE2_BIN}" \
-l RealTimeLoader \ -l RealTimeLoader \
-f "${MARTe_CFG}" \ -f "${MARTe_CFG}" \
-s Running \ -s "${MARTe_STATE}" &
-m StateMachine:START &
MARTE_PID="$!" 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 sleep 1
if ! kill -0 "$MARTE_PID" 2>/dev/null; then
# ── Launch StreamHub ────────────────────────────────────────────────────────── echo "ERROR: MARTe2 exited during startup — see the log above."
echo "==> Launching StreamHub..." exit 1
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
fi fi
# ── Optionally launch the web UI server ────────────────────────────────────── # ── Launch the debugger web client ────────────────────────────────────────────
if [[ "$START_WEBUI" -eq 1 ]]; then echo "==> Launching debugger client (:${UI_PORT})..."
if [[ ! -x "$WEBUI_BIN" ]]; then DANGEROUS_FLAG=()
echo "WARNING: webui binary not found at ${WEBUI_BIN}" if [[ "$DANGEROUS" -eq 1 ]]; then
echo " Build it with: cd Client/webui && go build -o streamhub-webui ." DANGEROUS_FLAG=(-enable-dangerous-commands)
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
fi fi
"${DEBUGGER_BIN}" -addr ":${UI_PORT}" "${DANGEROUS_FLAG[@]}" &
UI_PID="$!"
sleep 0.5
# ── Status ──────────────────────────────────────────────────────────────────── # ── 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 ""
echo " StreamHub WebSocket: ws://127.0.0.1:${WS_PORT}" echo " MARTe2 PID : ${MARTE_PID}"
[[ -n "$WEBUI_PID" ]] && echo " Browser client : http://localhost:${WEBUI_PORT}/" echo " Debugger PID : ${UI_PID}"
[[ -x "$IMGUI_CLIENT" ]] && echo " ImGui client : ${IMGUI_CLIENT} -host 127.0.0.1 -port ${WS_PORT}"
echo "" 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 "" echo ""
# ── Wait until any child exits ──────────────────────────────────────────────── # ── Wait until either child exits ─────────────────────────────────────────────
wait -n "${MARTE_PID}" "${HUB_PID}" ${GUI_PID:-} ${WEBUI_PID:-} 2>/dev/null || true wait -n "${MARTE_PID}" "${UI_PID}" 2>/dev/null || true
echo "==> A process exited — stopping remaining processes." echo "==> A process exited — stopping the other."
+11 -4
View File
@@ -81,11 +81,16 @@ fi
# Distinct amplitude/frequency/phase per channel so traces stay tellable apart # 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). # (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) 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) 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 ELEMS=10000 # samples per cycle
RATE=1000 # cycles per second -> 1 Msps 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 )) CYCLE_BYTES=$(( 8 * ELEMS + CHANNELS * 4 * ELEMS ))
PAYLOAD=$(( CYCLE_BYTES + 2000 )) # headroom for header + descriptors PAYLOAD=$(( CYCLE_BYTES + 2000 )) # headroom for header + descriptors
@@ -137,6 +142,7 @@ for (( i = 1; i <= CHANNELS; i++ )); do
RangeMax = ${amp} RangeMax = ${amp}
TimeMode = \"FullArray\" TimeMode = \"FullArray\"
TimeSignal = TimeArray TimeSignal = TimeArray
SamplingRate = ${SAMPLING_RATE}.0
}" }"
func_list+=", SineGAM${i}" func_list+=", SineGAM${i}"
done done
@@ -242,7 +248,7 @@ ${sine_gams}
// One cycle is ${CYCLE_BYTES} B; sizing the payload above that sends each // 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 // cycle as a single datagram, which keeps the receiver's reassembly pool
// from evicting in-flight cycles and gapping the trace. // from evicting in-flight cycles and gapping the trace.
MaxPayloadSize = ${PAYLOAD} MaxPayloadSize = 1400 //${PAYLOAD}
PublishingMode = "Strict" PublishingMode = "Strict"
Signals = { Signals = {
TimeArray = { TimeArray = {
@@ -250,6 +256,7 @@ ${sine_gams}
Unit = "ns" Unit = "ns"
NumberOfDimensions = 1 NumberOfDimensions = 1
NumberOfElements = ${ELEMS} NumberOfElements = ${ELEMS}
SamplingRate = ${SAMPLING_RATE}.0
}${stream_sigs} }${stream_sigs}
} }
} }