FIrs
This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
/**
|
||||
* Test MARTe2 application for UDPStreamer DataSource.
|
||||
*
|
||||
* Generates scalar and high-frequency packed signals and streams them via UDPStreamer.
|
||||
* Connect with the WebUI client (Client/WebUI) to visualise the signals.
|
||||
*
|
||||
* Signals produced (scalar, 10 kHz):
|
||||
* Counter – uint32 cycle counter from LinuxTimer
|
||||
* Time – uint32 time in microseconds from LinuxTimer
|
||||
* Sine1 – float32, 1 Hz sine, amplitude 10, quantised to uint16 on wire
|
||||
* Sine2 – float32, 0.3 Hz sine, amplitude 5, raw float32 on wire
|
||||
*
|
||||
* Signals produced (packed temporal arrays, 10 kHz × 1000 samples = 10 MSps):
|
||||
* Ch1 – float32[1000], 1 kHz sine, amplitude 1.0
|
||||
* Ch2 – float32[1000], 1 kHz sine, amplitude 0.5, phase π/2
|
||||
* Both channels use TimeMode=FirstSample with Time as the anchor and
|
||||
* SamplingRate=10000000 so the WebUI reconstructs the per-sample timestamps.
|
||||
*/
|
||||
$TestApp = {
|
||||
Class = RealTimeApplication
|
||||
+Functions = {
|
||||
Class = ReferenceContainer
|
||||
|
||||
// ── Copy Counter + Time from LinuxTimer into the inter-GAM DDB ──────
|
||||
+TimerGAM = {
|
||||
Class = IOGAM
|
||||
InputSignals = {
|
||||
Counter = {
|
||||
DataSource = Timer
|
||||
Type = uint32
|
||||
}
|
||||
Time = {
|
||||
Frequency = 1000
|
||||
DataSource = Timer
|
||||
Type = uint32
|
||||
}
|
||||
}
|
||||
OutputSignals = {
|
||||
Counter = {
|
||||
DataSource = DDB
|
||||
Type = uint32
|
||||
}
|
||||
Time = {
|
||||
DataSource = DDB
|
||||
Type = uint32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 1 Hz sinusoidal signal ───────────────────────────────────────────
|
||||
+SineGAM1 = {
|
||||
Class = WaveformSin
|
||||
Amplitude = 10.0
|
||||
Frequency = 1.0
|
||||
Phase = 0.0
|
||||
Offset = 0.0
|
||||
InputSignals = {
|
||||
Time = {
|
||||
DataSource = DDB
|
||||
Type = uint32
|
||||
}
|
||||
}
|
||||
OutputSignals = {
|
||||
Sine1 = {
|
||||
DataSource = DDB
|
||||
Type = float32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 0.3 Hz sinusoidal signal (phase-shifted) ─────────────────────────
|
||||
+SineGAM2 = {
|
||||
Class = WaveformSin
|
||||
Amplitude = 5.0
|
||||
Frequency = 0.3
|
||||
Phase = 1.0472
|
||||
Offset = 0.0
|
||||
InputSignals = {
|
||||
Time = {
|
||||
DataSource = DDB
|
||||
Type = uint32
|
||||
}
|
||||
}
|
||||
OutputSignals = {
|
||||
Sine2 = {
|
||||
DataSource = DDB
|
||||
Type = float32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 1 kHz sine burst – channel 1 (1000 samples/packet at 10 MSps) ──────
|
||||
+SineGAM3 = {
|
||||
Class = SineArrayGAM
|
||||
Frequency = 1000.0
|
||||
Amplitude = 1.0
|
||||
Phase = 0.0
|
||||
Offset = 0.0
|
||||
SamplingRate = 1000000.0
|
||||
OutputSignals = {
|
||||
Ch1 = {
|
||||
DataSource = DDB
|
||||
Type = float32
|
||||
NumberOfDimensions = 1
|
||||
NumberOfElements = 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 1 kHz sine burst – channel 2 (phase-shifted by π/2) ──────────────
|
||||
+SineGAM4 = {
|
||||
Class = SineArrayGAM
|
||||
Frequency = 1000.0
|
||||
Amplitude = 0.5
|
||||
Phase = 1.5708
|
||||
Offset = 0.0
|
||||
SamplingRate = 1000000.0
|
||||
OutputSignals = {
|
||||
Ch2 = {
|
||||
DataSource = DDB
|
||||
Type = float32
|
||||
NumberOfDimensions = 1
|
||||
NumberOfElements = 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Route signals into UDPStreamer ────────────────────────────────────
|
||||
+StreamerGAM = {
|
||||
Class = IOGAM
|
||||
InputSignals = {
|
||||
Counter = {
|
||||
DataSource = DDB
|
||||
Type = uint32
|
||||
}
|
||||
Time = {
|
||||
DataSource = DDB
|
||||
Type = uint32
|
||||
}
|
||||
Sine1 = {
|
||||
DataSource = DDB
|
||||
Type = float32
|
||||
}
|
||||
Sine2 = {
|
||||
DataSource = DDB
|
||||
Type = float32
|
||||
}
|
||||
Ch1 = {
|
||||
DataSource = DDB
|
||||
Type = float32
|
||||
NumberOfDimensions = 1
|
||||
NumberOfElements = 1000
|
||||
}
|
||||
Ch2 = {
|
||||
DataSource = DDB
|
||||
Type = float32
|
||||
NumberOfDimensions = 1
|
||||
NumberOfElements = 1000
|
||||
}
|
||||
}
|
||||
OutputSignals = {
|
||||
Counter = {
|
||||
DataSource = Streamer
|
||||
Type = uint32
|
||||
}
|
||||
Time = {
|
||||
DataSource = Streamer
|
||||
Type = uint32
|
||||
}
|
||||
Sine1 = {
|
||||
DataSource = Streamer
|
||||
Type = float32
|
||||
}
|
||||
Sine2 = {
|
||||
DataSource = Streamer
|
||||
Type = float32
|
||||
}
|
||||
Ch1 = {
|
||||
DataSource = Streamer
|
||||
Type = float32
|
||||
NumberOfDimensions = 1
|
||||
NumberOfElements = 1000
|
||||
}
|
||||
Ch2 = {
|
||||
DataSource = Streamer
|
||||
Type = float32
|
||||
NumberOfDimensions = 1
|
||||
NumberOfElements = 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+Data = {
|
||||
Class = ReferenceContainer
|
||||
DefaultDataSource = DDB
|
||||
|
||||
// ── Inter-GAM data buffer ────────────────────────────────────────────
|
||||
+DDB = {
|
||||
Class = GAMDataSource
|
||||
}
|
||||
|
||||
// ── Real-time clock / trigger source ─────────────────────────────────
|
||||
+Timer = {
|
||||
Class = LinuxTimer
|
||||
SleepNature = "Default"
|
||||
Signals = {
|
||||
Counter = {
|
||||
Type = uint32
|
||||
}
|
||||
Time = {
|
||||
Type = uint32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── UDP Streamer DataSource ──────────────────────────────────────────
|
||||
+Streamer = {
|
||||
Class = UDPStreamer
|
||||
Port = 44500
|
||||
MaxPayloadSize = 1400
|
||||
Signals = {
|
||||
Counter = {
|
||||
Type = uint32
|
||||
}
|
||||
Time = {
|
||||
Type = uint32
|
||||
Unit = "us"
|
||||
}
|
||||
Sine1 = {
|
||||
Type = float32
|
||||
Unit = "V"
|
||||
RangeMin = -10.0
|
||||
RangeMax = 10.0
|
||||
QuantizedType = "uint16"
|
||||
}
|
||||
Sine2 = {
|
||||
Type = float32
|
||||
Unit = "V"
|
||||
RangeMin = -5.0
|
||||
RangeMax = 5.0
|
||||
}
|
||||
Ch1 = {
|
||||
Type = float32
|
||||
Unit = "V"
|
||||
NumberOfDimensions = 1
|
||||
NumberOfElements = 1000
|
||||
TimeMode = FirstSample
|
||||
TimeSignal = Time
|
||||
SamplingRate = 1000000.0
|
||||
}
|
||||
Ch2 = {
|
||||
Type = float32
|
||||
Unit = "V"
|
||||
NumberOfDimensions = 1
|
||||
NumberOfElements = 1000
|
||||
TimeMode = FirstSample
|
||||
TimeSignal = Time
|
||||
SamplingRate = 1000000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Timing statistics ────────────────────────────────────────────────
|
||||
+Timings = {
|
||||
Class = TimingDataSource
|
||||
}
|
||||
}
|
||||
|
||||
+States = {
|
||||
Class = ReferenceContainer
|
||||
+Running = {
|
||||
Class = RealTimeState
|
||||
+Threads = {
|
||||
Class = ReferenceContainer
|
||||
+Thread1 = {
|
||||
Class = RealTimeThread
|
||||
CPUs = 0x1
|
||||
Functions = {TimerGAM SineGAM1 SineGAM2 SineGAM3 SineGAM4 StreamerGAM}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+Scheduler = {
|
||||
Class = GAMScheduler
|
||||
TimingDataSource = Timings
|
||||
}
|
||||
}
|
||||
Executable
+138
@@ -0,0 +1,138 @@
|
||||
#!/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 --help # show this message
|
||||
#
|
||||
# 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
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--webui) START_WEBUI=1 ;;
|
||||
--help|-h)
|
||||
sed -n '2,12p' "$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 UDPStreamer ─────────────────────────────────────────────────────────
|
||||
TARGET=x86-linux
|
||||
UDPSTREAMER_SRC="${REPO_ROOT}/Source/Components/DataSources/UDPStreamer"
|
||||
UDPSTREAMER_LIB="${REPO_ROOT}/Build/${TARGET}/Components/DataSources/UDPStreamer"
|
||||
|
||||
echo "==> Building UDPStreamer (TARGET=${TARGET})..."
|
||||
make -C "${UDPSTREAMER_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
|
||||
|
||||
# ── Set LD_LIBRARY_PATH ───────────────────────────────────────────────────────
|
||||
COMP="${MARTe2_Components_DIR}/Build/${TARGET}/Components"
|
||||
|
||||
export LD_LIBRARY_PATH="\
|
||||
${UDPSTREAMER_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 ────────────────────────
|
||||
# MARTe2 looks for <ClassName>.so when a class is not yet registered.
|
||||
# Some components bundle multiple classes into one .so (e.g. WaveformGAM.so
|
||||
# contains WaveformSin, WaveformChirp, WaveformPointsDef). We need symlinks
|
||||
# so dlopen("<ClassName>.so") succeeds.
|
||||
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
|
||||
|
||||
# SineArrayGAM is bundled inside UDPStreamer.so; create a symlink so MARTe2
|
||||
# can dlopen("SineArrayGAM.so") before UDPStreamer has been registered.
|
||||
SINE_LINK="${UDPSTREAMER_LIB}/SineArrayGAM.so"
|
||||
if [ ! -e "${SINE_LINK}" ]; then
|
||||
ln -sf "${UDPSTREAMER_LIB}/UDPStreamer.so" "${SINE_LINK}"
|
||||
fi
|
||||
|
||||
# ── Optionally start WebUI ────────────────────────────────────────────────────
|
||||
if [ "${START_WEBUI}" -eq 1 ]; then
|
||||
echo "==> Starting WebUI on http://localhost:8080 (streamer at 127.0.0.1:44500)..."
|
||||
"${WEBUI_BIN}" \
|
||||
--streamer 127.0.0.1:44500 \
|
||||
--listen :8080 \
|
||||
--clientport 44900 &
|
||||
WEBUI_PID=$!
|
||||
echo "==> WebUI PID ${WEBUI_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, 100 Hz)..."
|
||||
echo "==> Press Ctrl+C to stop."
|
||||
echo ""
|
||||
|
||||
cleanup() {
|
||||
echo ""
|
||||
echo "==> Stopping..."
|
||||
if [ "${START_WEBUI}" -eq 1 ] && kill -0 "${WEBUI_PID}" 2>/dev/null; then
|
||||
kill "${WEBUI_PID}"
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
"${MARTE_APP}" \
|
||||
-l RealTimeLoader \
|
||||
-f "${CFG}" \
|
||||
-s Running
|
||||
Reference in New Issue
Block a user