205 lines
5.5 KiB
Bash
Executable File
205 lines
5.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="${SCRIPT_DIR}"
|
|
VENV_PYTHON="${PROJECT_ROOT}/.venv/bin/python"
|
|
VENV_PIP="${PROJECT_ROOT}/.venv/bin/pip"
|
|
GUI_ENTRY="${PROJECT_ROOT}/python_app/gui/main.py"
|
|
REQUIREMENTS_FILE="${PROJECT_ROOT}/requirements.txt"
|
|
|
|
SKIP_BUILD=0
|
|
BUILD_ONLY=0
|
|
CLEAN_SHM=0
|
|
|
|
print_usage() {
|
|
cat <<'EOF'
|
|
Usage: ./start.sh [options]
|
|
|
|
Options:
|
|
--skip-build Skip C++ build step and only run GUI
|
|
--build-only Build C++ binaries and exit
|
|
--clean-shm Remove known radar shared-memory segments before start
|
|
-h, --help Show this help
|
|
EOF
|
|
}
|
|
|
|
parse_args() {
|
|
while (($# > 0)); do
|
|
case "$1" in
|
|
--skip-build)
|
|
SKIP_BUILD=1
|
|
;;
|
|
--build-only)
|
|
BUILD_ONLY=1
|
|
;;
|
|
--clean-shm)
|
|
CLEAN_SHM=1
|
|
;;
|
|
-h|--help)
|
|
print_usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $1" >&2
|
|
print_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
}
|
|
|
|
check_environment() {
|
|
if ! command -v python3 >/dev/null 2>&1; then
|
|
echo "python3 is not installed or not found in PATH." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "${REQUIREMENTS_FILE}" ]]; then
|
|
echo "Requirements file not found: ${REQUIREMENTS_FILE}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "${GUI_ENTRY}" ]]; then
|
|
echo "GUI entry not found: ${GUI_ENTRY}" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
ensure_python_dependencies() {
|
|
if [[ ! -x "${VENV_PYTHON}" ]]; then
|
|
echo "[start.sh] Creating virtual environment..."
|
|
python3 -m venv "${PROJECT_ROOT}/.venv"
|
|
fi
|
|
|
|
if [[ ! -x "${VENV_PIP}" ]]; then
|
|
echo "pip is missing in virtual environment: ${VENV_PIP}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "[start.sh] Installing Python dependencies..."
|
|
"${VENV_PIP}" install --upgrade pip
|
|
"${VENV_PIP}" install -r "${REQUIREMENTS_FILE}"
|
|
}
|
|
|
|
run_privileged() {
|
|
if [[ "${EUID}" -eq 0 ]]; then
|
|
"$@"
|
|
return
|
|
fi
|
|
if command -v sudo >/dev/null 2>&1; then
|
|
sudo "$@"
|
|
return
|
|
fi
|
|
echo "Need elevated privileges to run: $*" >&2
|
|
echo "Run as root or install 'sudo'." >&2
|
|
exit 1
|
|
}
|
|
|
|
ensure_system_dependencies() {
|
|
if command -v pkg-config >/dev/null 2>&1 && pkg-config --exists libusb-1.0; then
|
|
return
|
|
fi
|
|
|
|
echo "[start.sh] Installing system dependency: libusb-1.0 dev headers..."
|
|
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
|
|
elif command -v dnf >/dev/null 2>&1; then
|
|
run_privileged dnf install -y pkgconf-pkg-config libusb1-devel
|
|
elif command -v yum >/dev/null 2>&1; then
|
|
run_privileged yum install -y pkgconfig libusb1-devel
|
|
elif command -v pacman >/dev/null 2>&1; then
|
|
run_privileged pacman -Sy --needed pkgconf libusb
|
|
elif command -v zypper >/dev/null 2>&1; then
|
|
run_privileged zypper --non-interactive install pkg-config libusb-1_0-devel
|
|
elif command -v brew >/dev/null 2>&1; then
|
|
brew install pkg-config libusb
|
|
else
|
|
echo "Could not detect supported package manager." >&2
|
|
echo "Install manually: pkg-config and libusb development package." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v pkg-config >/dev/null 2>&1 || ! pkg-config --exists libusb-1.0; then
|
|
echo "libusb-1.0 development package is still unavailable after install attempt." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
ensure_usb_access_rules() {
|
|
if [[ "$(uname -s)" != "Linux" ]]; then
|
|
return
|
|
fi
|
|
if ! command -v udevadm >/dev/null 2>&1; then
|
|
return
|
|
fi
|
|
|
|
local rule_file="/etc/udev/rules.d/99-radar-librevna.rules"
|
|
local tmp_rule
|
|
tmp_rule="$(mktemp)"
|
|
|
|
cat > "${tmp_rule}" <<'EOF'
|
|
# LibreVNA USB access for non-root users
|
|
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="564e", TAG+="uaccess"
|
|
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="4121", TAG+="uaccess"
|
|
SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="4121", TAG+="uaccess"
|
|
EOF
|
|
|
|
if [[ -f "${rule_file}" ]] && cmp -s "${tmp_rule}" "${rule_file}"; then
|
|
rm -f "${tmp_rule}"
|
|
return
|
|
fi
|
|
|
|
echo "[start.sh] Installing udev rule for LibreVNA USB access..."
|
|
run_privileged install -m 0644 "${tmp_rule}" "${rule_file}"
|
|
rm -f "${tmp_rule}"
|
|
|
|
run_privileged udevadm control --reload-rules
|
|
run_privileged udevadm trigger
|
|
echo "[start.sh] udev rules updated. Reconnect USB device if it is already plugged in."
|
|
}
|
|
|
|
build_cpp_binaries() {
|
|
local jobs
|
|
jobs="${BUILD_JOBS:-$(nproc)}"
|
|
echo "[start.sh] Building C++ binaries (jobs=${jobs})..."
|
|
make -C "${PROJECT_ROOT}" -j"${jobs}" all
|
|
}
|
|
|
|
cleanup_known_shm() {
|
|
echo "[start.sh] Cleaning known shared-memory segments..."
|
|
rm -f /dev/shm/radar_raw /dev/shm/radar_preprocessed /dev/shm/radar_results || true
|
|
}
|
|
|
|
run_gui() {
|
|
echo "[start.sh] Launching GUI..."
|
|
exec "${VENV_PYTHON}" "${GUI_ENTRY}"
|
|
}
|
|
|
|
main() {
|
|
parse_args "$@"
|
|
check_environment
|
|
ensure_system_dependencies
|
|
ensure_usb_access_rules
|
|
ensure_python_dependencies
|
|
|
|
if ((CLEAN_SHM == 1)); then
|
|
cleanup_known_shm
|
|
fi
|
|
|
|
if ((SKIP_BUILD == 0)); then
|
|
build_cpp_binaries
|
|
fi
|
|
|
|
if ((BUILD_ONLY == 1)); then
|
|
echo "[start.sh] Build completed."
|
|
exit 0
|
|
fi
|
|
|
|
run_gui
|
|
}
|
|
|
|
main "$@"
|