refactor aprs for argus
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
# 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)
|
||||
# - Linux kernel AX.25 stack for receive only demodulation of AX.25 packets
|
||||
#
|
||||
# NOTE: This role depends on scanner_digirig having been run first to set up:
|
||||
# - AX.25 packages and kernel modules
|
||||
@@ -12,61 +11,52 @@
|
||||
# - Base directory structure
|
||||
#
|
||||
|
||||
- name: Create direwolf directories
|
||||
- name: Create directories
|
||||
file:
|
||||
path: "{{item}}"
|
||||
state: directory
|
||||
owner: busnet
|
||||
group: busnet
|
||||
owner: argus
|
||||
group: argus
|
||||
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
|
||||
- /opt/argus/scripts
|
||||
- /opt/argus/direwolf
|
||||
- /opt/argus/direwolf/config
|
||||
- /opt/argus/direwolf/logs
|
||||
|
||||
###################################################################################################
|
||||
# AirSpy bash script and Direwolf config
|
||||
###################################################################################################
|
||||
|
||||
- name: Copy airspy_aprs.sh AX.25 stack script
|
||||
- name: Copy aprs_airspy.sh AX.25 stack script
|
||||
copy:
|
||||
src: "templates/airspy_aprs.sh"
|
||||
dest: "/opt/busnet/direwolf/airspy_aprs.sh"
|
||||
owner: busnet
|
||||
group: busnet
|
||||
src: "templates/aprs_airspy.sh"
|
||||
dest: "/opt/argus/scripts/aprs_airspy.sh"
|
||||
owner: argus
|
||||
group: argus
|
||||
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
|
||||
dest: "/opt/argus/direwolf/config/airspy-aprs.conf"
|
||||
owner: argus
|
||||
group: argus
|
||||
|
||||
###################################################################################################
|
||||
# SYSTEMD
|
||||
###################################################################################################
|
||||
|
||||
- name: Install systemd unit file for AirSpy APRS
|
||||
- name: Install systemd unit file for argus-aprs-airspy.service.j2
|
||||
template:
|
||||
src: "templates/airspy-aprs.service.j2"
|
||||
dest: "/etc/systemd/system/airspy-aprs.service"
|
||||
src: "templates/argus-aprs-airspy.service.j2"
|
||||
dest: "/etc/systemd/system/argus-aprs-airspy.service"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Enable airspy-aprs service
|
||||
- name: Enable argus-aprs-airspy.service
|
||||
systemd:
|
||||
name: "airspy-aprs"
|
||||
name: "argus-aprs-airspy.service"
|
||||
daemon_reload: true
|
||||
enabled: true
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
[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
|
||||
@@ -1,87 +0,0 @@
|
||||
#!/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,193 @@
|
||||
#!/bin/bash
|
||||
# Start the APRS Receive-Only APRS AX.25 Stack
|
||||
# @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.
|
||||
#
|
||||
#
|
||||
# Here's a diagram of the stack this creates:
|
||||
# -------------------------------------------------------------------------------------------------
|
||||
#
|
||||
# RF signals! _ RF signals!
|
||||
# \ _/
|
||||
# \ /
|
||||
# +--------+
|
||||
# | AirSpy | ----- RF signals!
|
||||
# +--------+
|
||||
# |
|
||||
# | USB cable
|
||||
# |
|
||||
# +----|----------------------------------------------------------------------------+
|
||||
# | | This is your computer. The things in here are virtual components. |
|
||||
# | | |
|
||||
# | +-----------------+ |
|
||||
# | | airspy-fmradion | <--- software radio FM demodulator |
|
||||
# | +-----------------+ |
|
||||
# | | |
|
||||
# | | <-- UNIX pipe! |
|
||||
# | | |
|
||||
# | +-----------+ +-------+ +------------+ Linux kernel |
|
||||
# | | Direwolf | <---> | Socat | <----> | Kissattach | <------> ax1 interface |
|
||||
# | +-----------+ +-------+ +------------+ / |
|
||||
# | | /--------+ |
|
||||
# | AGWPE port / |
|
||||
# | available for +---------------+ |
|
||||
# | receive only use. | mheard daemon | |
|
||||
# | +---------------+ |
|
||||
# +---------------------------------------------------------------------------------+
|
||||
|
||||
# This software demodulates the FM signal in software from the AirSpy receiver.
|
||||
FMRADION_CMD="airspy-fmradion -m nbfm -t airspy -q -M -c freq=144390000,srate=2500000,lagc,magc,lgain=14,mgain=15,vgain=15"
|
||||
|
||||
# Command to execute direwolf including any options and location of config file.
|
||||
DIREWOLF_CMD="direwolf -q d -c /opt/argus/direwolf/config/airspy-aprs.conf -n 1 -r 48000 -b 16 -"
|
||||
|
||||
# The AX.25 port for the radio defined in /etc/ax25/axports. Note that this is not the same thing as
|
||||
# the kernel AX.25 interfaces, which are named things like ax0, ax1, etc...
|
||||
AX25_PORT_NAME="airspy"
|
||||
|
||||
# The PTY/TTY (whatever it's called) that socat will create for kissattach
|
||||
TNC_DEV="/dev/radio/airspy-tnc"
|
||||
|
||||
# This is the socat command to that connects one end of a virtual pipe to Direwolf's KISS TCP port,
|
||||
# and the other end to the PTY/TTY. The IP and port specified here must match the Direwolf config
|
||||
# file.
|
||||
SOCAT_CMD="/usr/bin/socat PTY,raw,echo=0,link=${TNC_DEV} TCP4:127.0.0.1:8003"
|
||||
|
||||
# These are the commands to create the kernel AX.25 interface using the kissattach utility.
|
||||
KISSATTACH_CMD="/usr/sbin/kissattach ${TNC_DEV} ${AX25_PORT_NAME}"
|
||||
KISSPARAMS_CMD="kissparms -c 5 -p ${AX25_PORT_NAME}"
|
||||
|
||||
|
||||
# Cleanup the AX.25 stack
|
||||
cleanup_stack()
|
||||
{
|
||||
# Kill kissattach explicitly (it forks, so we can't track its PID)
|
||||
sudo pkill -f "kissattach ${TNC_DEV} ${AX25_PORT_NAME}"
|
||||
sleep 1
|
||||
|
||||
# Kill socat by PID
|
||||
if [ -n "$SOCAT_PID" ]; then
|
||||
sudo kill $SOCAT_PID 2>/dev/null
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# Kill demodulator/direwolf by PID and wait for it to finish
|
||||
if [ -n "$PIPELINE_PID" ] && kill -0 $PIPELINE_PID 2>/dev/null; then
|
||||
kill $PIPELINE_PID 2>/dev/null
|
||||
wait $PIPELINE_PID 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Start the AX.25 stack for APRS receive only.
|
||||
start_stack()
|
||||
{
|
||||
# We start the software that demodulates the FM signal then pipes its output stream directly
|
||||
# to Direwolf. Direwolf config says to read from stdin.
|
||||
$FMRADION_CMD | $DIREWOLF_CMD &
|
||||
PIPELINE_PID=$!
|
||||
# NOTE: If Direwolf encounters an error, it will just WAIT something like 15 seconds before
|
||||
# exiting. It does not fail fast. That means that the following check will pass, but then
|
||||
# we go to move on to create socat which will fail. I don't have a good solution for this
|
||||
# case just yet, but I'm recording this note here.
|
||||
if ! kill -0 $PIPELINE_PID; then
|
||||
echo "Direwolf failed to start."
|
||||
cleanup_stack
|
||||
exit 1
|
||||
fi
|
||||
echo "Fm Demodulator --> Direwolf started (PID: $PIPELINE_PID)"
|
||||
|
||||
# Start socat PTY bridge.
|
||||
# socat creates a full duplex/bidirectional pipe between a serial port ${TNC_DEV} and Direwolf's
|
||||
# KISS TCP interface, which is running on localhost:8001. The kissattach program needs a serial
|
||||
# port to work, and this is how we accomplish connecting kissattach to direwolf.
|
||||
sleep 3
|
||||
sudo $SOCAT_CMD &
|
||||
SOCAT_PID=$!
|
||||
if ! kill -0 $SOCAT_PID; then
|
||||
echo "Socat failed to start."
|
||||
cleanup_stack
|
||||
exit 1
|
||||
fi
|
||||
echo "socat started (PID: $SOCAT_PID)"
|
||||
|
||||
# Run kissatach to create an AX.25 network interface on the system.
|
||||
# Kissattach annoyingly forks itself in the background, so we can't directly monitor the process.
|
||||
# Kissattach cannot use KISS over TCP directly to Direwolf. It expects a serial terminal to exist,
|
||||
# which is why we use socat to create the pipe between Direwolf's KISS TCP port and this serial
|
||||
# device.
|
||||
sleep 1
|
||||
sudo $KISSATTACH_CMD
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "kissattach failed to start."
|
||||
cleanup_stack
|
||||
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
|
||||
|
||||
# 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 sudo systemctl is-enabled --quiet mheardd.service; then
|
||||
echo "Restarting mheardd..."
|
||||
sudo systemctl restart mheardd.service
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# 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 APRS Receive-only AX.25 stack."
|
||||
cleanup_stack
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
###################################################################################################
|
||||
#
|
||||
# MAIN ENTRY POINT
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
|
||||
echo ""
|
||||
echo "======================================================================"
|
||||
echo "APRS Receive-only AX.25 Stack 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
|
||||
|
||||
# Load required kernel modules
|
||||
echo "Loading kernel modules..."
|
||||
sudo modprobe ax25
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to load ax25 kernel module"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up any orphaned kissattach processes from previous runs. We must do this because kissattach
|
||||
# forks itself in the background, and we therefore cannot keep track of its PID. We use pkill to
|
||||
# make sure no previous kissattach is running.
|
||||
sudo pkill -f "kissattach ${TNC_DEV} ${AX25_PORT_NAME}"
|
||||
sleep 1
|
||||
|
||||
# Start the AX.25 stack
|
||||
start_stack
|
||||
echo "All processes started. Monitoring via wait..."
|
||||
|
||||
# 'wait -n' waits for ANY background process to exit.
|
||||
# It returns as soon as fmradion, direwolf, or socat exits. Kissattach forks itself so we can't wait on it.
|
||||
wait -n
|
||||
|
||||
# If we get here, one of the processes died. Cleanup the stack and exit.
|
||||
cleanup_stack
|
||||
@@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=APRS AirSpy Receive-Only AX.25 Stack
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/opt/argus/scripts/aprs_airspy.sh
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
User=argus
|
||||
Group=argus
|
||||
|
||||
# Give it time to start up properly
|
||||
TimeoutStartSec=30
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -8,7 +8,7 @@
|
||||
ACHANNELS 1
|
||||
ADEVICE stdin null
|
||||
ARATE 48000
|
||||
MYCALL K0BIT-2
|
||||
MYCALL N0CAL
|
||||
MODEM 1200
|
||||
|
||||
AGWPORT 8002
|
||||
|
||||
Reference in New Issue
Block a user