Refactor radar system
This commit is contained in:
@@ -133,37 +133,6 @@ except Exception:
|
||||
echo "[start.sh] Detected radar model: ${RADAR_MODEL} (config: ${config_path})"
|
||||
}
|
||||
|
||||
# radar.replay.dataset_dir of a config, empty unless it replays a recording.
|
||||
replay_dataset_dir() {
|
||||
python3 -c '
|
||||
import json, sys
|
||||
try:
|
||||
radar = json.load(open(sys.argv[1])).get("radar", {})
|
||||
print(str(radar.get("replay", {}).get("dataset_dir", "")).strip())
|
||||
except Exception:
|
||||
print("")
|
||||
' "$1" 2>/dev/null
|
||||
}
|
||||
|
||||
# Acquisition producer for the active model, mirroring the process supervisor's
|
||||
# selection so --producer-only behaves identically to a full pipeline launch: a
|
||||
# replay dataset takes precedence over the model's producer.
|
||||
producer_command() {
|
||||
local config_path="$1"
|
||||
if [[ -n "$(replay_dataset_dir "${config_path}")" ]]; then
|
||||
printf '%s\0' "${PYTHON_CMD}" -m python_app.scripts.replay_raw_producer --config "${config_path}"
|
||||
return
|
||||
fi
|
||||
case "${RADAR_MODEL}" in
|
||||
kamil_adc)
|
||||
printf '%s\0' "${PYTHON_CMD}" -m python_app.scripts.kamil_adc_raw_producer --config "${config_path}" ;;
|
||||
librevna_multi|sn9000)
|
||||
printf '%s\0' "${PYTHON_CMD}" -m python_app.scripts.matrix_raw_producer --config "${config_path}" ;;
|
||||
*)
|
||||
printf '%s\0' "${PROJECT_ROOT}/build/bin/sweep_orchestrator" --config "${config_path}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
check_environment() {
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
echo "python3 is not installed or not found in PATH." >&2
|
||||
@@ -182,13 +151,7 @@ check_environment() {
|
||||
}
|
||||
|
||||
ensure_python_dependencies() {
|
||||
local dependency_check
|
||||
if [[ "${RADAR_MODEL}" == "kamil_adc" ]]; then
|
||||
# Kamil ADC has no VISA dependency (it talks to its own L-Card collector).
|
||||
dependency_check='import numpy, serial, PyQt6, pyqtgraph, usb1'
|
||||
else
|
||||
dependency_check='import numpy, serial, PyQt6, pyqtgraph, usb1, pyvisa'
|
||||
fi
|
||||
local dependency_check='import numpy, serial, PyQt6, pyqtgraph, usb1'
|
||||
|
||||
if [[ ! -x "${VENV_PYTHON}" ]]; then
|
||||
echo "[start.sh] Creating virtual environment..."
|
||||
@@ -257,24 +220,25 @@ ensure_system_dependencies() {
|
||||
fi
|
||||
|
||||
if command -v pkg-config >/dev/null 2>&1 && pkg-config --exists libusb-1.0 \
|
||||
&& ((qt_gui_packages_missing == 0)); then
|
||||
&& ((qt_gui_packages_missing == 0)) \
|
||||
&& python3 -c 'import ctypes; ctypes.CDLL("libatomic.so.1")' >/dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo "[start.sh] Installing system dependencies: libusb-1.0 dev headers (and Qt xcb libraries on apt)..."
|
||||
echo "[start.sh] Installing system dependencies: libusb headers, libatomic and Qt xcb libraries..."
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
run_privileged apt-get update
|
||||
run_privileged apt-get install -y pkg-config libusb-1.0-0-dev libxcb-cursor0 libxkbcommon-x11-0
|
||||
run_privileged apt-get install -y pkg-config libusb-1.0-0-dev libatomic1 libxcb-cursor0 libxkbcommon-x11-0
|
||||
elif command -v dnf >/dev/null 2>&1; then
|
||||
run_privileged dnf install -y pkgconf-pkg-config libusb1-devel
|
||||
run_privileged dnf install -y pkgconf-pkg-config libusb1-devel libatomic
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
run_privileged yum install -y pkgconfig libusb1-devel
|
||||
run_privileged yum install -y pkgconfig libusb1-devel libatomic
|
||||
elif command -v pacman >/dev/null 2>&1; then
|
||||
run_privileged pacman -Sy --needed pkgconf libusb
|
||||
run_privileged pacman -Sy --needed pkgconf libusb gcc-libs
|
||||
elif command -v zypper >/dev/null 2>&1; then
|
||||
run_privileged zypper --non-interactive install pkg-config libusb-1_0-devel
|
||||
run_privileged zypper --non-interactive install pkg-config libusb-1_0-devel libatomic1
|
||||
elif command -v brew >/dev/null 2>&1; then
|
||||
brew install pkg-config libusb
|
||||
brew install pkg-config libusb gcc
|
||||
else
|
||||
echo "Could not detect supported package manager." >&2
|
||||
echo "Install manually: pkg-config and libusb development package." >&2
|
||||
@@ -354,14 +318,11 @@ cleanup_known_shm() {
|
||||
}
|
||||
|
||||
kill_stale_adc_collector() {
|
||||
# The L-Card ADC collector runs in its own session and can outlive a crashed
|
||||
# or force-killed run, holding the E-502 device and hanging the next start.
|
||||
# Kill any leftover hard before launching so acquisition always opens cleanly.
|
||||
if command -v pkill >/dev/null 2>&1; then
|
||||
if pkill -9 -f kamil_adc_collector 2>/dev/null; then
|
||||
echo "[start.sh] Killed leftover ADC collector process(es)."
|
||||
fi
|
||||
fi
|
||||
# Exact executable matching: an argument mentioning the collector is not a process to kill.
|
||||
PYTHONPATH="${PROJECT_ROOT}${PYTHONPATH:+:${PYTHONPATH}}" "${PYTHON_CMD}" -c '
|
||||
from python_app.orchestration.process_supervisor import ProcessSupervisor
|
||||
ProcessSupervisor._kill_kamil_collectors()
|
||||
'
|
||||
}
|
||||
|
||||
run_gui() {
|
||||
@@ -396,13 +357,14 @@ run_producer_only() {
|
||||
fi
|
||||
|
||||
export PYTHONPATH="${PROJECT_ROOT}${PYTHONPATH:+:${PYTHONPATH}}"
|
||||
# Run the acquisition producer the supervisor would pick for this model.
|
||||
local -a command=()
|
||||
while IFS= read -r -d '' token; do
|
||||
command+=("${token}")
|
||||
done < <(producer_command "${config_path}")
|
||||
echo "[start.sh] Starting ${RADAR_MODEL} producer: ${command[*]}"
|
||||
exec "${command[@]}"
|
||||
exec "${PYTHON_CMD}" -c '
|
||||
import os, sys
|
||||
from pathlib import Path
|
||||
from python_app.orchestration.producer_selection import acquisition_command
|
||||
command = acquisition_command(Path(sys.argv[1]), Path(sys.argv[2]))
|
||||
print("[start.sh] Starting producer:", command, flush=True)
|
||||
os.execv(command[0], command)
|
||||
' "${PROJECT_ROOT}" "${config_path}"
|
||||
}
|
||||
|
||||
stop_headless_service() {
|
||||
@@ -426,11 +388,16 @@ verify_cpp_binaries() {
|
||||
# binaries were never built, instead of failing obscurely at spawn time.
|
||||
local missing=0 bin
|
||||
local required_bins="data_processor data_preprocessor"
|
||||
# Kamil ADC also needs its acquisition collector; other models use the C++
|
||||
# sweep_orchestrator, which `all` always builds.
|
||||
if [[ "${RADAR_MODEL}" == "kamil_adc" ]]; then
|
||||
required_bins="${required_bins} kamil_adc_collector"
|
||||
fi
|
||||
local acquisition_binary
|
||||
acquisition_binary="$(PYTHONPATH="${PROJECT_ROOT}${PYTHONPATH:+:${PYTHONPATH}}" "${PYTHON_CMD}" -c '
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from python_app.orchestration.producer_selection import acquisition_command
|
||||
command = acquisition_command(Path(sys.argv[1]), Path(sys.argv[2]))
|
||||
print("kamil_adc_collector" if "python_app.scripts.kamil_adc_raw_producer" in command
|
||||
else "sweep_orchestrator" if len(command) == 3 else "")
|
||||
' "${PROJECT_ROOT}" "${PROFILE_PATH:-${PROJECT_ROOT}/run_config.json}")"
|
||||
required_bins="${required_bins} ${acquisition_binary}"
|
||||
for bin in ${required_bins}; do
|
||||
if [[ ! -x "${PROJECT_ROOT}/build/bin/${bin}" ]]; then
|
||||
echo "Required binary missing or not executable: build/bin/${bin}" >&2
|
||||
@@ -463,18 +430,14 @@ main() {
|
||||
# Skip first-time provisioning (build headers, USB udev rule) in headless
|
||||
# mode: the daemon runs unattended at boot as a non-root user and must not
|
||||
# block on sudo. A fresh machine is provisioned by one interactive launch.
|
||||
# Also skip it for non-LibreVNA devices (e.g. Kamil ADC), which neither use
|
||||
# libusb directly nor need the LibreVNA USB access rule.
|
||||
if [[ "${RADAR_MODEL}" != "kamil_adc" ]] && ((HEADLESS == 0)); then
|
||||
# `all` builds the libusb orchestrator for every model; only the USB access
|
||||
# rule is device-specific. Python/C++ SHM also needs libatomic.
|
||||
if ((HEADLESS == 0)); then
|
||||
ensure_system_dependencies
|
||||
ensure_usb_access_rules
|
||||
if [[ "${RADAR_MODEL}" != "kamil_adc" ]]; then ensure_usb_access_rules; fi
|
||||
fi
|
||||
ensure_python_dependencies
|
||||
|
||||
if ((CLEAN_SHM == 1)); then
|
||||
cleanup_known_shm
|
||||
fi
|
||||
|
||||
if ((SKIP_BUILD == 0)); then
|
||||
build_cpp_binaries
|
||||
fi
|
||||
@@ -493,6 +456,9 @@ main() {
|
||||
stop_headless_service
|
||||
fi
|
||||
acquire_single_instance_lock
|
||||
if ((CLEAN_SHM == 1)); then
|
||||
cleanup_known_shm
|
||||
fi
|
||||
# Clear any ADC collector wedged by a previous run before we launch a new one.
|
||||
kill_stale_adc_collector
|
||||
|
||||
|
||||
Reference in New Issue
Block a user