#!/usr/bin/env bash # run_streamhub.sh — Launch a MARTe2 app with UDPStreamer + StreamHub # # Usage: # ./run_streamhub.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) # -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 # # 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) # # Environment: # MARTe2_DIR must be set (or passed via -m) # MARTe2_Components_DIR must be set (or passed via -c) 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 SKIP_BUILD=0 START_GUI=0 START_WEBUI=0 WEBUI_PORT=8080 # ── Parse arguments ─────────────────────────────────────────────────────────── while getopts "m:c:b:p:n:sgwh" 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" ;; s) SKIP_BUILD=1 ;; g) START_GUI=1 ;; w) START_WEBUI=1 ;; h) sed -n '2,30p' "$0" | grep '^#' | sed 's/^# \?//' exit 0 ;; *) echo "Unknown option: -$OPTARG" >&2; exit 1 ;; esac done # ── Validate environment ────────────────────────────────────────────────────── if [[ -z "${MARTe2_DIR:-}" ]]; then echo "ERROR: MARTe2_DIR is not set. Source env.sh first or pass -m ." echo " source ${SCRIPT_DIR}/env.sh" exit 1 fi if [[ -z "${MARTe2_Components_DIR:-}" ]]; then echo "ERROR: MARTe2_Components_DIR is not set. Source env.sh first or pass -c ." 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" 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/" exit 1 fi # ── 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 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 "==> 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" 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 "$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 "$MARTE_PID" 2>/dev/null || true rm -f "$HUB_CFG" echo "==> Done." } trap cleanup EXIT INT TERM # ── Launch MARTe2 ───────────────────────────────────────────────────────────── echo "" echo "==> Launching MARTe2..." echo " Binary : ${MARTE2_BIN}" echo " Config : ${MARTe_CFG}" echo " Signals: Sine1 (1 Hz), Sine2 (0.3 Hz), Ch1-Ch4 (arrays)" echo "" "${MARTE2_BIN}" \ -l RealTimeLoader \ -f "${MARTe_CFG}" \ -s Running \ -m StateMachine:START & MARTE_PID="$!" # Give MARTe2 a moment to bind its UDP ports before StreamHub connects 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 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 fi # ── 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 "" echo " Press Ctrl-C to stop all 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."