Files
MARTe_IO_Components/Test/MARTeApp/run.sh
T
Martino Ferrari f85ab8652c Add Auto publishing mode to UDPStreamer; optimise WebUI hub
UDPStreamer:
- Add PublishingMode = "Strict" | "Auto" config parameter
- Add MinRefreshRate (Hz) for Auto mode; uses HRT phase-locked tick
  counting to rate-limit sends without accumulation buffers
- Fix high-frequency integration test configs to use newline-separated
  key-value pairs (MARTe2 StandardParser does not treat ';' as delimiter)
- Add 3 new unit tests (AutoMode_Valid, AutoMode_MissingRefreshRate,
  UnknownPublishingMode); all 33 tests passing

WebUI hub:
- Skip ring-buffer LTTB writes when zoom has not been accessed in 10 s,
  reducing idle CPU usage
- Use unsafe float64→bytes reinterpretation to eliminate per-element
  encoding overhead in the hot broadcast path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 22:29:40 +02:00

239 lines
9.4 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# run.sh Build UDPStreamer and launch the test MARTe2 application.
#
# Usage:
# ./run.sh # run MARTe2 app only
# ./run.sh --webui # also start the WebUI Go client in the background
# ./run.sh --nativeui # also start the NativeUI ImGui client in the background
# ./run.sh --qtui # also start the NativeUI Qt client in the background
# ./run.sh --help # show this message
#
# The clients are started with three sources:
# Streamer @ 127.0.0.1:44500 (scalar signals, PacketTime, 1 kHz)
# FastStreamer @ 127.0.0.1:44501 (packed arrays, FirstSample/LastSample, 5 kHz)
# FullArrStreamer @ 127.0.0.1:44502 (packed arrays, FullArray, 5 kHz)
#
# Prerequisites:
# - marte_env.sh must be present in the repo root (sets MARTe2_DIR, etc.)
# - MARTe2 and MARTe2-components must already be built
#
# The script resolves all paths relative to the repo root so it can be
# called from any working directory.
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
# ── Parse arguments ──────────────────────────────────────────────────────────
START_WEBUI=0
START_NATIVEUI=0
START_QTUI=0
for arg in "$@"; do
case "$arg" in
--webui) START_WEBUI=1 ;;
--nativeui) START_NATIVEUI=1 ;;
--qtui) START_QTUI=1 ;;
--help|-h)
sed -n '2,21p' "$0"
exit 0
;;
esac
done
# ── Load MARTe2 environment ──────────────────────────────────────────────────
ENV_SCRIPT="${REPO_ROOT}/marte_env.sh"
if [ ! -f "${ENV_SCRIPT}" ]; then
echo "ERROR: ${ENV_SCRIPT} not found." >&2
exit 1
fi
# shellcheck source=/dev/null
source "${ENV_SCRIPT}"
if [ -z "${MARTe2_DIR}" ]; then
echo "ERROR: MARTe2_DIR is not set after sourcing marte_env.sh." >&2
exit 1
fi
# ── Build components ─────────────────────────────────────────────────────────
TARGET=x86-linux
UDPSTREAMER_SRC="${REPO_ROOT}/Source/Components/DataSources/UDPStreamer"
UDPSTREAMER_LIB="${REPO_ROOT}/Build/${TARGET}/Components/DataSources/UDPStreamer"
SINEARRAYGAM_SRC="${REPO_ROOT}/Source/Components/GAMs/SineArrayGAM"
SINEARRAYGAM_LIB="${REPO_ROOT}/Build/${TARGET}/Components/GAMs/SineArrayGAM"
TIMEARRAYGAM_SRC="${REPO_ROOT}/Source/Components/GAMs/TimeArrayGAM"
TIMEARRAYGAM_LIB="${REPO_ROOT}/Build/${TARGET}/Components/GAMs/TimeArrayGAM"
echo "==> Building UDPStreamer (TARGET=${TARGET})..."
make -C "${UDPSTREAMER_SRC}" \
-f Makefile.gcc \
TARGET="${TARGET}" \
2>&1 | tail -5
echo "==> Building SineArrayGAM (TARGET=${TARGET})..."
make -C "${SINEARRAYGAM_SRC}" \
-f Makefile.gcc \
TARGET="${TARGET}" \
2>&1 | tail -5
echo "==> Building TimeArrayGAM (TARGET=${TARGET})..."
make -C "${TIMEARRAYGAM_SRC}" \
-f Makefile.gcc \
TARGET="${TARGET}" \
2>&1 | tail -5
echo "==> Build done."
# ── Build WebUI binary (if requested and not already built) ──────────────────
WEBUI_DIR="${REPO_ROOT}/Client/WebUI"
WEBUI_BIN="${WEBUI_DIR}/udpstreamer-webui"
if [ "${START_WEBUI}" -eq 1 ] && [ ! -x "${WEBUI_BIN}" ]; then
echo "==> Building WebUI..."
(cd "${WEBUI_DIR}" && go build -o udpstreamer-webui ./...)
echo "==> WebUI build done."
fi
# ── Build NativeUI (ImGui) binary (if requested and not already built) ───────
NATIVEUI_DIR="${REPO_ROOT}/Client/NativeUI"
NATIVEUI_BUILD="${NATIVEUI_DIR}/build"
NATIVEUI_BIN="${NATIVEUI_BUILD}/daq_viewer"
if [ "${START_NATIVEUI}" -eq 1 ]; then
if [ ! -x "${NATIVEUI_BIN}" ]; then
echo "==> Building NativeUI/ImGui (cmake)..."
cmake -S "${NATIVEUI_DIR}" -B "${NATIVEUI_BUILD}" -DCMAKE_BUILD_TYPE=Release -Wno-dev
cmake --build "${NATIVEUI_BUILD}" --parallel "$(nproc)"
echo "==> NativeUI/ImGui build done."
else
# Rebuild if sources are newer than the binary
if find "${NATIVEUI_DIR}/src" -name '*.cpp' -o -name '*.h' \
| xargs ls -t 2>/dev/null | head -1 \
| xargs -I{} test {} -nt "${NATIVEUI_BIN}" 2>/dev/null; then
echo "==> Sources changed — rebuilding NativeUI/ImGui..."
cmake --build "${NATIVEUI_BUILD}" --parallel "$(nproc)"
echo "==> NativeUI/ImGui rebuild done."
fi
fi
fi
# ── Build NativeUI-Qt binary (if requested and not already built) ─────────────
QTUI_DIR="${REPO_ROOT}/Client/NativeUI-Qt"
QTUI_BUILD="${QTUI_DIR}/build"
QTUI_BIN="${QTUI_BUILD}/daq_viewer"
if [ "${START_QTUI}" -eq 1 ]; then
if [ ! -x "${QTUI_BIN}" ]; then
echo "==> Building NativeUI/Qt (cmake)..."
cmake -S "${QTUI_DIR}" -B "${QTUI_BUILD}" -DCMAKE_BUILD_TYPE=Release -Wno-dev
cmake --build "${QTUI_BUILD}" --parallel "$(nproc)"
echo "==> NativeUI/Qt build done."
else
# Rebuild if sources are newer than the binary
if find "${QTUI_DIR}/src" "${REPO_ROOT}/Client/NativeUI/src" \
\( -name '*.cpp' -o -name '*.h' \) \
| xargs ls -t 2>/dev/null | head -1 \
| xargs -I{} test {} -nt "${QTUI_BIN}" 2>/dev/null; then
echo "==> Sources changed — rebuilding NativeUI/Qt..."
cmake --build "${QTUI_BUILD}" --parallel "$(nproc)"
echo "==> NativeUI/Qt rebuild done."
fi
fi
fi
# ── Set LD_LIBRARY_PATH ───────────────────────────────────────────────────────
COMP="${MARTe2_Components_DIR}/Build/${TARGET}/Components"
export LD_LIBRARY_PATH="\
${UDPSTREAMER_LIB}:\
${SINEARRAYGAM_LIB}:\
${TIMEARRAYGAM_LIB}:\
${MARTe2_DIR}/Build/${TARGET}/Core:\
${COMP}/DataSources/LinuxTimer:\
${COMP}/DataSources/LoggerDataSource:\
${COMP}/GAMs/IOGAM:\
${COMP}/GAMs/WaveformGAM:\
${LD_LIBRARY_PATH}"
echo "==> LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
# ── Create class-name symlinks for MARTe2 auto-loader ────────────────────────
WAVEFORM_DIR="${COMP}/GAMs/WaveformGAM"
for cls in WaveformSin WaveformChirp WaveformPointsDef; do
target="${WAVEFORM_DIR}/${cls}.so"
if [ ! -e "${target}" ]; then
ln -sf "${WAVEFORM_DIR}/WaveformGAM.so" "${target}"
fi
done
# ── Optionally start WebUI ────────────────────────────────────────────────────
WEBUI_PID=""
if [ "${START_WEBUI}" -eq 1 ]; then
echo "==> Starting WebUI on http://localhost:8080..."
"${WEBUI_BIN}" \
--source "Streamer@127.0.0.1:44500" \
--source "FastStreamer@127.0.0.1:44501" \
--source "FullArrStreamer@127.0.0.1:44502" \
--listen :8080 &
WEBUI_PID=$!
echo "==> WebUI PID ${WEBUI_PID}"
fi
# ── Optionally start NativeUI (ImGui) ────────────────────────────────────────
NATIVEUI_PID=""
if [ "${START_NATIVEUI}" -eq 1 ]; then
if [ ! -x "${NATIVEUI_BIN}" ]; then
echo "ERROR: NativeUI/ImGui binary not found at ${NATIVEUI_BIN}" >&2
exit 1
fi
echo "==> Starting NativeUI/ImGui..."
"${NATIVEUI_BIN}" \
"Streamer@127.0.0.1:44500" \
"FastStreamer@127.0.0.1:44501" \
"FullArrStreamer@127.0.0.1:44502" &
NATIVEUI_PID=$!
echo "==> NativeUI/ImGui PID ${NATIVEUI_PID}"
fi
# ── Optionally start NativeUI-Qt ──────────────────────────────────────────────
QTUI_PID=""
if [ "${START_QTUI}" -eq 1 ]; then
if [ ! -x "${QTUI_BIN}" ]; then
echo "ERROR: NativeUI/Qt binary not found at ${QTUI_BIN}" >&2
exit 1
fi
echo "==> Starting NativeUI/Qt..."
"${QTUI_BIN}" \
"Streamer@127.0.0.1:44500" \
"FastStreamer@127.0.0.1:44501" \
"FullArrStreamer@127.0.0.1:44502" &
QTUI_PID=$!
echo "==> NativeUI/Qt PID ${QTUI_PID}"
fi
# ── Launch MARTe2 application ─────────────────────────────────────────────────
MARTE_APP="${MARTe2_DIR}/Build/${TARGET}/App/MARTeApp.ex"
CFG="${SCRIPT_DIR}/TestApp.cfg"
if [ ! -x "${MARTE_APP}" ]; then
echo "ERROR: MARTeApp.ex not found at ${MARTE_APP}" >&2
exit 1
fi
echo "==> Starting MARTe2 application (state=Running)..."
echo "==> Thread1: scalar signals 1 kHz → port 44500"
echo "==> Thread2: packed arrays 5 kHz → port 44501 (FirstSample / LastSample)"
echo "==> Thread3: FullArray arrays 5 kHz → port 44502 (FullArray)"
echo "==> Press Ctrl+C to stop."
echo ""
cleanup() {
echo ""
echo "==> Stopping..."
[ -n "${WEBUI_PID}" ] && kill -0 "${WEBUI_PID}" 2>/dev/null && kill "${WEBUI_PID}"
[ -n "${NATIVEUI_PID}" ] && kill -0 "${NATIVEUI_PID}" 2>/dev/null && kill "${NATIVEUI_PID}"
[ -n "${QTUI_PID}" ] && kill -0 "${QTUI_PID}" 2>/dev/null && kill "${QTUI_PID}"
}
trap cleanup EXIT INT TERM
"${MARTE_APP}" \
-l RealTimeLoader \
-f "${CFG}" \
-s Running