aprs, digirig and ft991a stuff
This commit is contained in:
72
ansible/roles/scanner_airspy_aprs/tasks/main.yml
Normal file
72
ansible/roles/scanner_airspy_aprs/tasks/main.yml
Normal file
@@ -0,0 +1,72 @@
|
||||
# Role: scanner_airspy_aprs
|
||||
# Configure AirSpy SDR for APRS reception on VHF 144.390 MHz
|
||||
#
|
||||
# This role sets up:
|
||||
# - airspy-fmradion for FM demodulation
|
||||
# - Direwolf for APRS packet decoding
|
||||
# - Full AX.25 stack integration (receive-only)
|
||||
#
|
||||
# NOTE: This role depends on scanner_digirig having been run first to set up:
|
||||
# - AX.25 packages and kernel modules
|
||||
# - System-wide configuration files (axports, nrports, etc.)
|
||||
# - Base directory structure
|
||||
#
|
||||
|
||||
- name: Create direwolf directories
|
||||
file:
|
||||
path: "{{item}}"
|
||||
state: directory
|
||||
owner: busnet
|
||||
group: busnet
|
||||
mode: u=rwx,g=rwx,o=rx
|
||||
with_items:
|
||||
- /opt/busnet/direwolf
|
||||
- /opt/busnet/direwolf/config
|
||||
- /opt/busnet/direwolf/logs
|
||||
|
||||
###################################################################################################
|
||||
# Package Dependencies
|
||||
###################################################################################################
|
||||
|
||||
- name: Install socat for PTY bridging
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- socat
|
||||
state: present
|
||||
|
||||
###################################################################################################
|
||||
# AirSpy bash script and Direwolf config
|
||||
###################################################################################################
|
||||
|
||||
- name: Copy airspy_aprs.sh AX.25 stack script
|
||||
copy:
|
||||
src: "templates/airspy_aprs.sh"
|
||||
dest: "/opt/busnet/direwolf/airspy_aprs.sh"
|
||||
owner: busnet
|
||||
group: busnet
|
||||
mode: "0755"
|
||||
|
||||
- name: Copy Direwolf config for AirSpy APRS
|
||||
template:
|
||||
src: "templates/direwolf_airspy_aprs.conf"
|
||||
dest: "/opt/busnet/direwolf/config/airspy-aprs.conf"
|
||||
owner: busnet
|
||||
group: busnet
|
||||
|
||||
###################################################################################################
|
||||
# SYSTEMD
|
||||
###################################################################################################
|
||||
|
||||
- name: Install systemd unit file for AirSpy APRS
|
||||
template:
|
||||
src: "templates/airspy-aprs.service.j2"
|
||||
dest: "/etc/systemd/system/airspy-aprs.service"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Enable airspy-aprs service
|
||||
systemd:
|
||||
name: "airspy-aprs"
|
||||
daemon_reload: true
|
||||
enabled: true
|
||||
@@ -0,0 +1,18 @@
|
||||
[Unit]
|
||||
Description=AirSpy APRS Receiver with Direwolf and AX.25 Stack
|
||||
Documentation=https://github.com/wb2osz/direwolf
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/opt/busnet/direwolf/airspy_aprs.sh
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
User=busnet
|
||||
Group=busnet
|
||||
|
||||
# Give it time to start up properly
|
||||
TimeoutStartSec=30
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
87
ansible/roles/scanner_airspy_aprs/templates/airspy_aprs.sh
Normal file
87
ansible/roles/scanner_airspy_aprs/templates/airspy_aprs.sh
Normal file
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
# @author Craig McDaniel
|
||||
#
|
||||
# This script runs airspy-fmradion to demodulate FM signals from the AirSpy SDR, pipes the audio
|
||||
# to Direwolf for APRS packet decoding, then sets up the AX.25 stack for kernel integration.
|
||||
#
|
||||
# This is receive-only APRS monitoring on VHF 144.390 MHz.
|
||||
#
|
||||
|
||||
# Configuration
|
||||
FMRADION_CMD="airspy-fmradion -m nbfm -t airspy -q -M -c freq=144390000,srate=2500000,lagc,magc,lgain=14,mgain=15,vgain=15"
|
||||
DIREWOLF_CMD="direwolf -q d -c /opt/busnet/direwolf/config/airspy-aprs.conf -n 1 -r 48000 -b 16 -"
|
||||
SOCAT_CMD="/usr/bin/socat PTY,raw,echo=0,link=/dev/radio/airspy-tnc TCP4:127.0.0.1:8003"
|
||||
KISSATTACH_CMD="/usr/sbin/kissattach /dev/radio/airspy-tnc airspy"
|
||||
KISSPARAMS_CMD="kissparms -c 5 -p airspy"
|
||||
|
||||
cleanup() {
|
||||
echo
|
||||
echo "Exit signal detected. Cleaning up..."
|
||||
trap - SIGTERM # prevent recursion
|
||||
kill 0
|
||||
exit
|
||||
}
|
||||
|
||||
# Trap exit signals
|
||||
trap cleanup SIGINT SIGTERM
|
||||
|
||||
echo
|
||||
echo "======================================================================"
|
||||
echo "Starting AirSpy FM Demodulator → Direwolf pipeline..."
|
||||
echo "======================================================================"
|
||||
echo
|
||||
# Start the pipeline: airspy-fmradion pipes audio to direwolf
|
||||
$FMRADION_CMD | $DIREWOLF_CMD &
|
||||
PIPELINE_PID=$!
|
||||
|
||||
sleep 1
|
||||
if ! kill -0 $PIPELINE_PID 2>/dev/null; then
|
||||
echo "Pipeline failed to start."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Wait 3 seconds for Direwolf to initialize and open KISS TCP port 8003
|
||||
sleep 3
|
||||
|
||||
echo
|
||||
echo "======================================================================"
|
||||
echo "Starting socat PTY bridge..."
|
||||
echo "======================================================================"
|
||||
echo
|
||||
# Start this in the background
|
||||
sudo $SOCAT_CMD &
|
||||
SOCAT_PID=$!
|
||||
if ! kill -0 $SOCAT_PID 2>/dev/null; then
|
||||
echo "Socat failed to start."
|
||||
kill $PIPELINE_PID
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Wait for PTY device to be created
|
||||
sleep 1
|
||||
|
||||
echo
|
||||
echo "======================================================================"
|
||||
echo "Starting kissattach and setting kissparams..."
|
||||
echo "======================================================================"
|
||||
echo
|
||||
# Kissattach will automatically fork itself in background.
|
||||
sudo $KISSATTACH_CMD
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "kissattach failed to start."
|
||||
cleanup
|
||||
fi
|
||||
|
||||
# Configure AX.25 parameters for receive only. This is probably not necessary?
|
||||
# Maybe somebody will do a bunch of tests and see if it actually matters one day.
|
||||
sudo $KISSPARAMS_CMD
|
||||
|
||||
echo
|
||||
echo "AirSpy APRS stack online! Monitoring processes..."
|
||||
|
||||
# 'wait -n' waits for ANY background process to exit.
|
||||
# It returns as soon as the pipeline or socat dies.
|
||||
wait -n
|
||||
|
||||
# If we get here, one of the processes died.
|
||||
cleanup
|
||||
@@ -0,0 +1,15 @@
|
||||
# This direwolf configuration is for piping the magic output of airspy_fmradion to stdin so it can
|
||||
# read the...whatever it is that airspy_fmradion outputs (sound?) and demodulate the 1200 baud tones
|
||||
# into AX.25 frames.
|
||||
#
|
||||
# This is for a receive only AX.25, generally for receiving APRS. It could receive any AX.25 though.
|
||||
#
|
||||
|
||||
ACHANNELS 1
|
||||
ADEVICE stdin null
|
||||
ARATE 48000
|
||||
MYCALL K0BIT-2
|
||||
MODEM 1200
|
||||
|
||||
AGWPORT 8002
|
||||
KISSPORT 8003
|
||||
10
ansible/roles/scanner_digirig/templates/axports
Normal file
10
ansible/roles/scanner_digirig/templates/axports
Normal file
@@ -0,0 +1,10 @@
|
||||
# /etc/ax25/axports
|
||||
#
|
||||
# THIS FILE IS MANAGED BY ANSIBLE. LOCAL CHANGES WILL BE OVERWRITTEN.
|
||||
#
|
||||
# The format of this file is:
|
||||
# name callsign speed paclen window description
|
||||
#
|
||||
digirig K0BIT-1 9600 255 5 VHF Port using ICOM IC-V8000 and Compactenna 2M/440+
|
||||
airspy N0CALL 9600 255 5 AirSpy for VHF packet receive only.
|
||||
ft991a K0BIT-2 9600 255 2 Used when the FT-991A radio is connected
|
||||
19
ansible/roles/scanner_digirig/templates/mheardd.service
Normal file
19
ansible/roles/scanner_digirig/templates/mheardd.service
Normal file
@@ -0,0 +1,19 @@
|
||||
[Unit]
|
||||
Description=AX.25 Packet Radio mheardd Daemon
|
||||
After=digirig-direwolf.service
|
||||
BindTo=digirig-direwolf.service
|
||||
|
||||
# systemd has trouble with this daemon. Presumably it's old code and systemd cannot determine if
|
||||
# the daemon starts. These settings seem to work.
|
||||
[Service]
|
||||
Type=simple
|
||||
RemainAfterExit=yes
|
||||
# -i sends a routing update immediately on start
|
||||
# -t 15 sets the nodes broadcast interval
|
||||
ExecStart=/usr/sbin/mheardd -l 1000
|
||||
ExecStop=pkill -x mheardd
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,22 @@
|
||||
[Unit]
|
||||
Description=Initialize NET/ROM Interfaces at Boot
|
||||
Documentation=man:nrattach(8)
|
||||
After=network.target
|
||||
Before=digirig-direwolf.service ft991a-direwolf.service mheardd.service netromd.service
|
||||
ConditionPathExists=/etc/ax25/nrports
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
|
||||
# Create NET/ROM interfaces for each port in nrports
|
||||
# nrattach finds first free device: digirig-nr gets nr0, ft991a-nr gets nr1
|
||||
ExecStart=/usr/sbin/nrattach digirig-nr
|
||||
ExecStart=/usr/sbin/nrattach ft991a-nr
|
||||
|
||||
# On stop/shutdown, bring down the interfaces cleanly
|
||||
ExecStop=/usr/sbin/ifconfig nr0 down
|
||||
ExecStop=/usr/sbin/ifconfig nr1 down
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
19
ansible/roles/scanner_digirig/templates/netromd.service
Normal file
19
ansible/roles/scanner_digirig/templates/netromd.service
Normal file
@@ -0,0 +1,19 @@
|
||||
[Unit]
|
||||
Description=NET/ROM Routing Daemon
|
||||
After=digirig-direwolf.service
|
||||
BindTo=digirig-direwolf.service
|
||||
|
||||
# systemd has trouble with this daemon. Presumably it's old code and systemd cannot determine if
|
||||
# the daemon starts. These settings seem to work.
|
||||
[Service]
|
||||
Type=simple
|
||||
RemainAfterExit=yes
|
||||
# -i sends a routing update immediately on start
|
||||
# -t 15 sets the nodes broadcast interval
|
||||
ExecStart=/usr/sbin/netromd -i -t 45
|
||||
ExecStop=pkill -x netromd
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
12
ansible/roles/scanner_digirig/templates/nrbroadcast
Normal file
12
ansible/roles/scanner_digirig/templates/nrbroadcast
Normal file
@@ -0,0 +1,12 @@
|
||||
# /etc/ax25/nrbroadcast
|
||||
#
|
||||
# THIS FILE IS MANAGED BY ANSIBLE. CHANGES WILL BE OVERWRITTEN.
|
||||
#
|
||||
# This file tells the netromd program how to transmit the nodes it knows about. In here you specify
|
||||
# the AX25 port in axports to use for transmitting.
|
||||
#
|
||||
# The format of this file is:
|
||||
# ax25_name min_obs def_qual worst_qual verbose
|
||||
#
|
||||
digirig 1 100 50 1
|
||||
#ft991a 1 100 50 0
|
||||
9
ansible/roles/scanner_digirig/templates/nrports
Normal file
9
ansible/roles/scanner_digirig/templates/nrports
Normal file
@@ -0,0 +1,9 @@
|
||||
# /etc/ax25/nrports
|
||||
#
|
||||
# THIS FILE IS MANAGED BY ANSIBLE. LOCAL CHANGES WILL BE OVERWRITTEN.
|
||||
#
|
||||
# The format of this file is:
|
||||
# name callsign alias paclen description
|
||||
#
|
||||
digirig-nr K0BIT-8 8BITS 235 NET/ROM Port
|
||||
ft991a-nr K0BIT-7 7BITS 235 HF NET/ROM Port
|
||||
303
ansible/roles/scanner_ft991a/templates/ft991a-monitor.sh
Normal file
303
ansible/roles/scanner_ft991a/templates/ft991a-monitor.sh
Normal file
@@ -0,0 +1,303 @@
|
||||
#!/bin/bash
|
||||
# @author Craig McDaniel
|
||||
#
|
||||
# This script polls the Yaesu FT-991a by connecting to a running rigctld daemon and asking that
|
||||
# daemon what the current radio's frequency is. If the radio is in any HF frequency, it makes
|
||||
# sure Direwolf is running with a HF AX.25 configuration at 300 baud. If a VHF or UHF frequency
|
||||
# is detected, it restarts Direwolf with a configuration suitable for that band.
|
||||
#
|
||||
# If the radio is unreachable via rigctl due to powering off the radio, then this script will
|
||||
# shut down the AX.25 stack and wait for the radio to become available again. It will then enable
|
||||
# the AX.25 stack automatically.
|
||||
#
|
||||
# By AX.25 stack, we mean:
|
||||
# - Run direwolf
|
||||
# - Run socat to set up a PTY between Direwolf's TCP KISS port and the filesystem.
|
||||
# - Run kissattach to the socat PTY to create a kernel AX.25 interface.
|
||||
# - Make sure mheardd daemon is restarted so it can see new AX.25 interface.
|
||||
#
|
||||
|
||||
# === Configuration ===
|
||||
DIREWOLF_PATH="/usr/local/bin/direwolf"
|
||||
PORT_NAME="ft991a"
|
||||
TNC_DEV="/dev/radio/ft991a-tnc"
|
||||
KISS_TCP_PORT=8006
|
||||
NR_PORT="ft991a-nr"
|
||||
POLL_INTERVAL=5
|
||||
RIGCTLD_HOST="localhost"
|
||||
RIGCTLD_PORT=4000
|
||||
POLL_RETRIES=1
|
||||
|
||||
# Frequency ranges (Hz)
|
||||
HF_MIN=1800000
|
||||
HF_MAX=30000000
|
||||
VHF_MIN=144390000
|
||||
VHF_MAX=145100000
|
||||
UHF_MIN=432000000
|
||||
UHF_MAX=433000000
|
||||
|
||||
# Config files per band
|
||||
CONFIG_HF="/opt/busnet/direwolf/config/ft991a-hf.conf"
|
||||
CONFIG_VHF="/opt/busnet/direwolf/config/ft991a-vhf.conf"
|
||||
CONFIG_UHF="/opt/busnet/direwolf/config/ft991a-uhf.conf"
|
||||
|
||||
# State tracking
|
||||
CUR_BAND="NONE"
|
||||
DIREWOLF_PID=""
|
||||
SOCAT_PID=""
|
||||
CONSECUTIVE_ERRORS=0
|
||||
MAX_CONSECUTIVE_ERRORS=5
|
||||
WAITING_FOR_RADIO=false
|
||||
|
||||
|
||||
# Poll rigctld to get the current band of the FT991A. It does this by asking the radio what the current
|
||||
# VFO frequency is and then determining what band that frequency is in. This returns the band string.
|
||||
#
|
||||
# Returns band name string: "HF", "VHF", "UHF", "UNKNOWN", or "ERROR"
|
||||
poll_rigctld()
|
||||
{
|
||||
local RESP=$(echo "+\\get_freq" | nc -w 2 $RIGCTLD_HOST $RIGCTLD_PORT 2>/dev/null)
|
||||
|
||||
if [ -n "$RESP" ]; then
|
||||
# Parse frequency from response
|
||||
local FREQ=$(echo "$RESP" | grep "Frequency:" | awk '{print $2}')
|
||||
|
||||
if [ -n "$FREQ" ] && [ "$FREQ" -eq "$FREQ" ] 2>/dev/null; then
|
||||
# Determine band
|
||||
if [ $FREQ -ge $HF_MIN ] && [ $FREQ -le $HF_MAX ]; then
|
||||
echo "HF"
|
||||
return 0
|
||||
elif [ $FREQ -ge $VHF_MIN ] && [ $FREQ -le $VHF_MAX ]; then
|
||||
echo "VHF"
|
||||
return 0
|
||||
elif [ $FREQ -ge $UHF_MIN ] && [ $FREQ -le $UHF_MAX ]; then
|
||||
echo "UHF"
|
||||
return 0
|
||||
else
|
||||
echo "UNKNOWN"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "ERROR"
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
# Cleanup the AX.25 stack by shutting down kissattach, socat and Direwolf. This will also automatically
|
||||
# set the corresponding kernel AX.25 interface to down because the carrier is lost.
|
||||
cleanup_stack()
|
||||
{
|
||||
if [ "$CUR_BAND" == "NONE" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Shutting down FT991a AX.25 ${CUR_BAND} stack..."
|
||||
|
||||
# kissattach is annoying! It forks itself in the background, so we can't directly keep track of its
|
||||
# PID in here. We use pkill to match the full process name. This is a bit hackish, but we have no
|
||||
# other choice util somebody updates is and provides a way to stop it from forking.
|
||||
sudo pkill -f "kissattach ${TNC_DEV}"
|
||||
sleep 1
|
||||
|
||||
if [ -n "$SOCAT_PID" ]; then
|
||||
sudo kill $SOCAT_PID 2>/dev/null
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
if [ -n "$DIREWOLF_PID" ] && kill -0 $DIREWOLF_PID 2>/dev/null; then
|
||||
kill $DIREWOLF_PID 2>/dev/null
|
||||
wait $DIREWOLF_PID 2>/dev/null
|
||||
fi
|
||||
|
||||
echo "FT991a AX.25 ${CUR_BAND} stack is now shut down."
|
||||
CUR_BAND="NONE"
|
||||
DIREWOLF_PID=""
|
||||
SOCAT_PID=""
|
||||
}
|
||||
|
||||
|
||||
# Start the AX.25 stack for the current frequency.
|
||||
start_stack()
|
||||
{
|
||||
local BAND=$1
|
||||
local CONFIG=""
|
||||
|
||||
case $BAND in
|
||||
HF) CONFIG="$CONFIG_HF" ;;
|
||||
VHF) CONFIG="$CONFIG_VHF" ;;
|
||||
UHF) CONFIG="$CONFIG_UHF" ;;
|
||||
*)
|
||||
echo "ERROR: Invalid band '$BAND'" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Starting $BAND stack..."
|
||||
|
||||
# Start Direwolf
|
||||
echo "Starting Direwolf..."
|
||||
$DIREWOLF_PATH -t 0 -X 1 -c "$CONFIG" &
|
||||
DIREWOLF_PID=$!
|
||||
sleep 2
|
||||
|
||||
if ! kill -0 $DIREWOLF_PID 2>/dev/null; then
|
||||
echo "FATAL: Direwolf failed to start" >&2
|
||||
DIREWOLF_PID=""
|
||||
return 1
|
||||
fi
|
||||
echo "Direwolf started (PID: $DIREWOLF_PID)"
|
||||
|
||||
# Start socat PTY bridge
|
||||
echo "Starting socat PTY bridge..."
|
||||
sudo socat PTY,raw,echo=0,link=$TNC_DEV TCP4:127.0.0.1:$KISS_TCP_PORT &
|
||||
SOCAT_PID=$!
|
||||
sleep 1
|
||||
|
||||
if ! kill -0 $SOCAT_PID 2>/dev/null; then
|
||||
echo "FATAL: socat failed to start" >&2
|
||||
cleanup_stack
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Wait for PTY device to exist
|
||||
local WAIT_COUNT=0
|
||||
while [ ! -L $TNC_DEV ] && [ $WAIT_COUNT -lt 10 ]; do
|
||||
sleep 0.5
|
||||
((WAIT_COUNT++))
|
||||
done
|
||||
|
||||
if [ ! -L $TNC_DEV ]; then
|
||||
echo "FATAL: PTY device $TNC_DEV not created" >&2
|
||||
cleanup_stack
|
||||
return 1
|
||||
fi
|
||||
echo "socat started (PID: $SOCAT_PID)"
|
||||
|
||||
# Kissattach connects the PTY device created by socat to the kernel.
|
||||
echo "Running kissattach..."
|
||||
sudo kissattach $TNC_DEV $PORT_NAME
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "FATAL: kissattach failed" >&2
|
||||
cleanup_stack
|
||||
return 1
|
||||
fi
|
||||
echo "kissattach completed"
|
||||
|
||||
# Set kissparams depending on what band we're operating on.
|
||||
echo "Setting kissparms..."
|
||||
case $BAND in
|
||||
HF)
|
||||
sudo kissparms -p $PORT_NAME -c 1 -t 350
|
||||
echo "Set kissparams for HF: window=1, txdelay=350ms"
|
||||
;;
|
||||
VHF)
|
||||
sudo kissparms -p $PORT_NAME -c 3 -t 200
|
||||
echo "Set kissparams for VHF: window=3, txdelay=200ms"
|
||||
;;
|
||||
UHF)
|
||||
sudo kissparms -p $PORT_NAME -c 3 -t 150
|
||||
echo "Set kissparams for UHF: window=3, txdelay=150ms"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Restart mheardd daemon. If mheardd was started before ax1, ax2 or other AX.25 kernel interface
|
||||
# was created, and now we receive AX.25 packets on this new interface we just created, mheardd
|
||||
# just throws errors about a new, unknown interface. Ugh.
|
||||
if systemctl is-active --quiet mheardd.service; then
|
||||
echo "Restarting mheardd..."
|
||||
sudo systemctl restart mheardd.service
|
||||
fi
|
||||
|
||||
CUR_BAND="$BAND"
|
||||
echo "FT991a AX.25 ${CUR_BAND} stack is online."
|
||||
echo ""
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
# This is our POSIX signal handler so we cleanly shut down before exiting.
|
||||
handle_signal()
|
||||
{
|
||||
echo "We received a SIGINT or SIGTERM signal. Shutting down FT991a AX.25 stack."
|
||||
cleanup_stack
|
||||
exit 0
|
||||
}
|
||||
|
||||
###################################################################################################
|
||||
#
|
||||
# MAIN LOOP!
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
echo ""
|
||||
echo "======================================================================"
|
||||
echo "FT-991A AX.25 Monitor Started"
|
||||
echo "======================================================================"
|
||||
echo ""
|
||||
|
||||
# This is the bash way of intercepting these signals. We execute the cleanup function when we receive
|
||||
# either one.
|
||||
trap handle_signal SIGINT SIGTERM
|
||||
|
||||
# Check if Direwolf exists
|
||||
if [ ! -f $DIREWOLF_PATH ]; then
|
||||
echo "FATAL: Direwolf executable not found at $DIREWOLF_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while true; do
|
||||
TARGET_BAND=$(poll_rigctld)
|
||||
|
||||
if [ "$WAITING_FOR_RADIO" = true ]; then
|
||||
# In waiting mode - check if radio is back online
|
||||
if [ "$TARGET_BAND" != "ERROR" ]; then
|
||||
echo "Radio detected! Bringing up AX.25 stack for FT-991a..."
|
||||
WAITING_FOR_RADIO=false
|
||||
CONSECUTIVE_ERRORS=0
|
||||
fi
|
||||
# Continue to next iteration if still waiting or if we just detected the radio
|
||||
sleep $POLL_INTERVAL
|
||||
continue
|
||||
fi
|
||||
|
||||
# Normal operation mode
|
||||
if [ "$TARGET_BAND" == "ERROR" ]; then
|
||||
((CONSECUTIVE_ERRORS++))
|
||||
echo "Radio unreachable ($CONSECUTIVE_ERRORS/$MAX_CONSECUTIVE_ERRORS)"
|
||||
|
||||
if [ $CONSECUTIVE_ERRORS -ge $MAX_CONSECUTIVE_ERRORS ]; then
|
||||
echo "Radio offline. Waiting for radio to be reachable again."
|
||||
cleanup_stack
|
||||
WAITING_FOR_RADIO=true
|
||||
CONSECUTIVE_ERRORS=0
|
||||
fi
|
||||
else
|
||||
# Reset error counter on any successful poll
|
||||
CONSECUTIVE_ERRORS=0
|
||||
|
||||
# Only act on valid digital bands (HF, VHF, UHF)
|
||||
if [[ "$TARGET_BAND" =~ ^(HF|VHF|UHF)$ ]]; then
|
||||
# Band switch needed?
|
||||
if [ "$TARGET_BAND" != "$CUR_BAND" ]; then
|
||||
if [ "$CUR_BAND" != "NONE" ]; then
|
||||
echo "Band change detected: $CUR_BAND -> $TARGET_BAND"
|
||||
cleanup_stack
|
||||
fi
|
||||
|
||||
start_stack "$TARGET_BAND"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "FATAL: Failed to start FT991a AX.25 stack for $TARGET_BAND" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
elif [ "$TARGET_BAND" == "UNKNOWN" ]; then
|
||||
# Radio is on a non-packet frequency - do nothing (idempotent)
|
||||
: # No-op
|
||||
fi
|
||||
fi
|
||||
|
||||
# Poll interval sleep
|
||||
sleep $POLL_INTERVAL
|
||||
done
|
||||
Reference in New Issue
Block a user