#!/usr/bin/env bash # run_debugtest.sh — Launch a small MARTe2 app under DebugService + the web debugger # # Usage: # ./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) # -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 # -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: # 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) # MARTe2_Components_DIR must be set (or passed via -c) set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BUILD_TARGET="${TARGET:-x86-linux}" MARTe_CFG="${SCRIPT_DIR}/Test/Configurations/debug_test.cfg" MARTe_STATE="State1" UI_PORT=7777 DANGEROUS=1 SKIP_BUILD=0 # ── Parse arguments ─────────────────────────────────────────────────────────── 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" ;; f) MARTe_CFG="$OPTARG" ;; t) MARTe_STATE="$OPTARG" ;; p) UI_PORT="$OPTARG" ;; S) DANGEROUS=0 ;; s) SKIP_BUILD=1 ;; h) sed -n '2,40p' "$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 if [[ ! -f "$MARTe_CFG" ]]; then echo "ERROR: MARTe2 config not found: ${MARTe_CFG}" exit 1 fi BUILD_DIR="${SCRIPT_DIR}/Build/${BUILD_TARGET}" 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 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 core TARGET="${BUILD_TARGET}" 2>&1 | tail -5 echo "==> Building debugger client..." (cd "${DEBUGGER_DIR}" && go build -o marte2debugger .) echo "==> Build done." fi 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 # ── Library path ────────────────────────────────────────────────────────────── # DebugService pulls in TCPLogger and UDPStream; everything the config names # beyond MARTe2 core (LinuxTimer, RealTimeThreadSynchronisation, # LoggerDataSource, IOGAM, ConstantGAM) is dlopen'd from MARTe2-components. export LD_LIBRARY_PATH="\ ${MARTe2_DIR}/Build/${BUILD_TARGET}/Core:\ ${BUILD_DIR}/Components/Interfaces/DebugService:\ ${BUILD_DIR}/Components/Interfaces/TCPLogger:\ ${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:-}" # ── Cleanup handler ─────────────────────────────────────────────────────────── MARTE_PID="" UI_PID="" cleanup() { echo "" echo "==> Shutting down..." [[ -n "$UI_PID" ]] && kill "$UI_PID" 2>/dev/null || true [[ -n "$MARTE_PID" ]] && kill "$MARTE_PID" 2>/dev/null || true wait "$UI_PID" 2>/dev/null || true wait "$MARTE_PID" 2>/dev/null || true echo "==> Done." } trap cleanup EXIT INT TERM # ── Launch MARTe2 ───────────────────────────────────────────────────────────── echo "" echo "==> Launching MARTe2 under DebugService..." echo " Binary : ${MARTE2_BIN}" echo " Config : ${MARTe_CFG}" echo " State : ${MARTe_STATE}" echo "" "${MARTE2_BIN}" \ -l RealTimeLoader \ -f "${MARTe_CFG}" \ -s "${MARTe_STATE}" & MARTE_PID="$!" # Give the app time to reach the state and bind the DebugService control port. sleep 1 if ! kill -0 "$MARTE_PID" 2>/dev/null; then echo "ERROR: MARTe2 exited during startup — see the log above." exit 1 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 "" echo " MARTe2 PID : ${MARTE_PID}" echo " Debugger PID : ${UI_PID}" echo "" 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 either child exits ───────────────────────────────────────────── wait -n "${MARTE_PID}" "${UI_PID}" 2>/dev/null || true echo "==> A process exited — stopping the other."