Winlink - In preparation to support VARA FM and HF, I started to refactor the Winlink modes. Added support for Winlink configuration templates. Added supported for native AX.25 packet for devices that use /dev/rfcomm0 and a Bluetooth TNC

This commit is contained in:
Gaston Gonzalez
2025-02-03 16:48:33 -07:00
parent 4f46a72b87
commit 350173ab39
9 changed files with 335 additions and 24 deletions
@@ -0,0 +1,19 @@
# Author : Gaston Gonzalez
# Date : 3 February 2025
# Purpose : User systemd unit file for EmComm Tools Winlink over packet
#
# Usage:
# Check status : systemctl --user status et-service-winlink-native-packet
# Start service : systemctl --user start et-service-winlink-native-packet
# Stop service : systemctl --user stop et-service-winlink-native-packet
# Reload this config : systemctl --user daemon-reload
[Unit]
Description=EmComm Tools Winlink native AX.25 packet service
[Service]
ExecStart=/opt/emcomm-tools/bin/et-winlink start-native-packet
Restart=no
[Install]
WantedBy=multi-user.target
+2 -1
View File
@@ -2,7 +2,7 @@
# #
# Author : Gaston Gonzalez # Author : Gaston Gonzalez
# Date : 12 November 2024 # Date : 12 November 2024
# Updated : 13 January 2025 # Updated : 3 February 2025
# Purpose : Stops all EmComm Tools sound-based services (i.e. modems) and # Purpose : Stops all EmComm Tools sound-based services (i.e. modems) and
# amatuer radio applications to ensure a clean start for the next mode. # amatuer radio applications to ensure a clean start for the next mode.
@@ -11,6 +11,7 @@
stop_all_services() { stop_all_services() {
systemctl --user stop et-service-winlink-ardop systemctl --user stop et-service-winlink-ardop
systemctl --user stop et-service-winlink-packet systemctl --user stop et-service-winlink-packet
systemctl --user stop et-service-winlink-native-packet
systemctl --user stop et-service-ardop systemctl --user stop et-service-ardop
systemctl --user stop et-service-direwolf-300 systemctl --user stop et-service-direwolf-300
systemctl --user stop et-service-direwolf-9600 systemctl --user stop et-service-direwolf-9600
+15 -1
View File
@@ -2,7 +2,7 @@
# #
# Author : Gaston Gonzalez # Author : Gaston Gonzalez
# Date : 6 November 2024 # Date : 6 November 2024
# Updated : 14 January 2025 # Updated : 3 February 2025
# Purpose : Configures the system for a specific mode of operation # Purpose : Configures the system for a specific mode of operation
# Use a simple text file to save the state of the last mode selected # Use a simple text file to save the state of the last mode selected
@@ -87,6 +87,18 @@ select_direwolf_mode () {
fi fi
} }
select_winlink_mode () {
winlink_mode=()
BLUETOOTH_TNC_CHECK=$(ps -ef | grep "[r]fcomm connect")
if [[ $? -eq 0 ]]; then
et-log "AX.25 over Bluetooth connected. Configuring Winlink for native AX.25"
start_and_wait_for_service et-service-winlink-native-packet
min http://localhost:8080
exit 0
fi
}
# Build list of options # Build list of options
options=() options=()
options+=("${MODE_ID_NONE}" "No mode selected") options+=("${MODE_ID_NONE}" "No mode selected")
@@ -150,11 +162,13 @@ if [ $exit_status -eq 0 ]; then
et-log "Packet digipeater now running." et-log "Packet digipeater now running."
;; ;;
${MODE_ID_WINLINK_ARDOP}) ${MODE_ID_WINLINK_ARDOP})
et-log "Using ${PACKET_MODE} as the modem speed."
start_and_wait_for_service et-service-ardop start_and_wait_for_service et-service-ardop
start_and_wait_for_service et-service-winlink-ardop start_and_wait_for_service et-service-winlink-ardop
min http://localhost:8080 min http://localhost:8080
;; ;;
${MODE_ID_WINLINK_PACKET}) ${MODE_ID_WINLINK_PACKET})
select_winlink_mode
start_and_wait_for_service et-service-direwolf-simple start_and_wait_for_service et-service-direwolf-simple
start_and_wait_for_service et-service-winlink-packet start_and_wait_for_service et-service-winlink-packet
min http://localhost:8080 min http://localhost:8080
+8 -2
View File
@@ -2,7 +2,7 @@
# #
# Author : Gaston Gonzalez # Author : Gaston Gonzalez
# Date : 11 October 2024 # Date : 11 October 2024
# Updated : 14 December 2024 # Updated : 3 February 2025
# Purpose : A script for managaing plug-and-play radios # Purpose : A script for managaing plug-and-play radios
set -e set -e
@@ -48,6 +48,13 @@ if [ $exit_status -eq 0 ]; then
VENDOR=$(cat ${ACTIVE_RADIO} | jq -r .vendor) VENDOR=$(cat ${ACTIVE_RADIO} | jq -r .vendor)
MODEL=$(cat ${ACTIVE_RADIO} | jq -r .model) MODEL=$(cat ${ACTIVE_RADIO} | jq -r .model)
BLUETOOTH_TNC_CHECK=$(ps -ef | grep "[r]fcomm connect")
if [[ $? -eq 0 ]]; then
et-log "Killing running processes for Bluetooth TNC"
sudo killall kissattach
sudo killall rfcomm
fi
printf "%-20s %-10s %-10s\n" "Radio ID" "Vendor" "Model" printf "%-20s %-10s %-10s\n" "Radio ID" "Vendor" "Model"
printf "%-20s %-10s %-10s\n\n" $ID "$VENDOR" "$MODEL" printf "%-20s %-10s %-10s\n\n" $ID "$VENDOR" "$MODEL"
@@ -55,7 +62,6 @@ if [ $exit_status -eq 0 ]; then
cat ${ACTIVE_RADIO} | jq -r '.notes[] | "* \(.)"' cat ${ACTIVE_RADIO} | jq -r '.notes[] | "* \(.)"'
echo -e "${NC}" echo -e "${NC}"
printf "${GREEN}REQUIRED ACTIONS\n" printf "${GREEN}REQUIRED ACTIONS\n"
printf "1. Apply the settings above to your radio.\n" printf "1. Apply the settings above to your radio.\n"
printf "2. Plug in the USB cable for your radio. If it is already\n" printf "2. Plug in the USB cable for your radio. If it is already\n"
+7 -7
View File
@@ -2,14 +2,14 @@
# #
# Author : Gaston Gonzalez # Author : Gaston Gonzalez
# Date : 1 January 2025 # Date : 1 January 2025
# Updated : 3 January 2025 # Updated : 3 February 2025
# Purpose : Utility for accessing the Bluetooth TNC on the BTECH # Purpose : Utility for accessing the Bluetooth TNC on the BTECH
# UV PRO. # UV PRO.
ACTIVE_RADIO="${ET_HOME}/conf/radios.d/btech-uvpro.bt.json" ACTIVE_RADIO="${ET_HOME}/conf/radios.d/btech-uvpro.bt.json"
DEVICE_NAME="UV-PRO" DEVICE_NAME="UV-PRO"
BT_DEVICE="/dev/rfcomm0" BT_DEVICE="/dev/rfcomm0"
AX25_PORT="pkt1200" AX25_PORT="wl2k"
AX25_CONF_FILE="/etc/ax25/axports" AX25_CONF_FILE="/etc/ax25/axports"
ESC="\x1B" ESC="\x1B"
@@ -78,15 +78,15 @@ update_ax25_conf() {
GREP_OUT=$(grep ${AX25_PORT} ${AX25_CONF_FILE}) GREP_OUT=$(grep ${AX25_PORT} ${AX25_CONF_FILE})
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
# Delete all existing pkt1200 entries. Note: we can't use sed here # Delete all existing AX.25 port entries. Note: we can't use sed here
# since we do not have permission to create a temporary file with # since we do not have permission to create a temporary file with
# inline replacement. ed modifies the file directly. # inline replacement. ed modifies the file directly.
printf "g/^pkt1200/d\nw\nq\n" | ed ${AX25_CONF_FILE} > /dev/null 2>&1 printf "g/^${AX25_PORT}/d\nw\nq\n" | ed ${AX25_CONF_FILE} > /dev/null 2>&1
fi fi
info_message "Adding AX25 port for ${CALLSIGN}" info_message "Adding AX25 port for ${CALLSIGN}"
echo "pkt1200 ${CALLSIGN} 1200 255 2 1200 Packet" >> ${AX25_CONF_FILE} echo "${AX25_PORT} ${CALLSIGN} 1200 255 2 1200 Packet" >> ${AX25_CONF_FILE}
} }
stop_all_services() { stop_all_services() {
@@ -235,8 +235,8 @@ EOF
echo -e "${YELLOW}" echo -e "${YELLOW}"
echo -e "SAMPLE COMMANDS DESCRIPTION " echo -e "SAMPLE COMMANDS DESCRIPTION "
echo -e "------------------------------- --------------------------------" echo -e "------------------------------- --------------------------------"
echo -e "axcall pkt1200 <STATION> Connect directly to a node " echo -e "axcall ${AX25_PORT} <STATION> Connect directly to a node "
echo -e "axcall pkt1200 <STATION> <DIGI> Connect to node via a digipeater" echo -e "axcall ${AX25_PORT} <DIGI> Connect to node via a digipeater"
echo -e "sudo axlisten -a -tttt -c Monitor inbound and outbound traffic" echo -e "sudo axlisten -a -tttt -c Monitor inbound and outbound traffic"
echo -e "${NC}" echo -e "${NC}"
+37 -10
View File
@@ -2,7 +2,7 @@
# #
# Author : Gaston Gonzalez # Author : Gaston Gonzalez
# Date : 4 November 2024 # Date : 4 November 2024
# Updated : 12 December 2024 # Updated : 3 February 2025
# Purpose : Wrapper script for starting YAAC with PnP support # Purpose : Wrapper script for starting YAAC with PnP support
# #
# Preconditions: # Preconditions:
@@ -13,6 +13,8 @@
# 1. Callsign, Winlink password, and grid are updated are updated # 1. Callsign, Winlink password, and grid are updated are updated
# 2. pat http is started # 2. pat http is started
source /opt/emcomm-tools/bin/et-common
PAT_CONF_FILE=${HOME}/.config/pat/config.json PAT_CONF_FILE=${HOME}/.config/pat/config.json
PAT_CONF_FILE_TEMPLATE=/etc/skel/.config/pat/config.json PAT_CONF_FILE_TEMPLATE=/etc/skel/.config/pat/config.json
@@ -21,6 +23,7 @@ usage() {
echo " <command>" echo " <command>"
echo " start-ardop - Start Pat Winlink in ardop mode" echo " start-ardop - Start Pat Winlink in ardop mode"
echo " start-packet - Start Pat Winlink in packet mode" echo " start-packet - Start Pat Winlink in packet mode"
echo " start-native-packet - Start Pat Winlink in native AX.25 packet mode"
} }
if [ $# -ne 1 ]; then if [ $# -ne 1 ]; then
@@ -69,6 +72,24 @@ start_packet() {
${CMD} ${CMD}
} }
# Only the BTECH UV PRO is supported in this mode
start_native_packet() {
BLUETOOTH_TNC_CHECK=$(ps -ef | grep "[r]fcomm connect")
if [[ $? -ne 0 ]]; then
echo -e "${RED}Can't start Pat in native AX.25 packet mode."
echo -e "If you have a UV Pro, first run: ${YELLOW}et-uv-pro connect${NC}"
exit 1
fi
update_config native-packet
CMD="pat http"
et-log "Starting Pat with: ${CMD}"
${CMD}
}
update_config () { update_config () {
[ -z "$ET_USER_CONFIG" ] && ET_USER_CONFIG="${HOME}/.config/emcomm-tools/user.json" [ -z "$ET_USER_CONFIG" ] && ET_USER_CONFIG="${HOME}/.config/emcomm-tools/user.json"
@@ -82,6 +103,18 @@ update_config () {
exit 1 exit 1
fi fi
case $1 in
ardop)
PAT_CONF_FILE_TEMPLATE=/opt/emcomm-tools/conf/template.d/winlink/config.ardop.json
;;
packet)
PAT_CONF_FILE_TEMPLATE=/opt/emcomm-tools/conf/template.d/winlink/config.ax25-agw.json
;;
native-packet)
PAT_CONF_FILE_TEMPLATE=/opt/emcomm-tools/conf/template.d/winlink/config.ax25-native.json
;;
esac
et-log "Updating Pat configuration file: ${PAT_CONF_FILE}..." et-log "Updating Pat configuration file: ${PAT_CONF_FILE}..."
cp -v ${PAT_CONF_FILE_TEMPLATE} ${PAT_CONF_FILE} cp -v ${PAT_CONF_FILE_TEMPLATE} ${PAT_CONF_FILE}
@@ -89,15 +122,6 @@ update_config () {
sed -i "s|{{ET_WINLINK_PASSWD}}|${WINLINK_PASSWD}|g" ${PAT_CONF_FILE} sed -i "s|{{ET_WINLINK_PASSWD}}|${WINLINK_PASSWD}|g" ${PAT_CONF_FILE}
sed -i "s|{{ET_GRID}}|${GRID}|g" ${PAT_CONF_FILE} sed -i "s|{{ET_GRID}}|${GRID}|g" ${PAT_CONF_FILE}
# Enable the P2P listener for the current mode selected (ARDOP or AX.25)
case $1 in
ardop)
sed -i "s|{{ET_WINLINK_LISTEN}}|ardop|g" ${PAT_CONF_FILE}
;;
packet)
sed -i "s|{{ET_WINLINK_LISTEN}}|ax25|g" ${PAT_CONF_FILE}
;;
esac
} }
case $1 in case $1 in
@@ -107,6 +131,9 @@ case $1 in
start-packet) start-packet)
start_packet start_packet
;; ;;
start-native-packet)
start_native_packet
;;
*) *)
echo "Invalid command." echo "Invalid command."
usage usage
@@ -0,0 +1,83 @@
{
"mycall": "{{ET_CALLSIGN}}",
"secure_login_password": "{{ET_WINLINK_PASSWD}}",
"auxiliary_addresses": [],
"locator": "{{ET_GRID}}",
"service_codes": [
"PUBLIC"
],
"http_addr": "localhost:8080",
"motd": [
"Open source Winlink client - getpat.io"
],
"connect_aliases": {
"telnet": "telnet://{mycall}:CMSTelnet@cms.winlink.org:8772/wl2k"
},
"listen": [ "ardop" ],
"hamlib_rigs": {
"et-rig": {
"address": "localhost:4532",
"network": "tcp"
}
},
"ax25": {
"engine": "agwpe",
"beacon": {
"every": 3600,
"message": "Winlink P2P",
"destination": "IDENT"
},
"agwpe": {"addr": "localhost:8000", "radio_port": 0}
},
"serial-tnc": {
"path": "/dev/ttyUSB0",
"serial_baud": 9600,
"hbaud": 1200,
"type": "Kenwood"
},
"ardop": {
"addr": "localhost:8515",
"arq_bandwidth": {
"Forced": false,
"Max": 500
},
"rig": "et-rig",
"ptt_ctrl": true,
"beacon_interval": 0,
"cwid_enabled": true
},
"pactor": {
"path": "/dev/ttyUSB0",
"baudrate": 57600,
"rig": "",
"custom_init_script": ""
},
"telnet": {
"listen_addr": ":8774",
"password": ""
},
"varahf": {
"host": "localhost",
"cmdPort": 8300,
"dataPort": 8301,
"bandwidth": 2300,
"rig": "",
"ptt_ctrl": false
},
"varafm": {
"host": "localhost",
"cmdPort": 8300,
"dataPort": 8301,
"bandwidth": 0,
"rig": "",
"ptt_ctrl": false
},
"gpsd": {
"enable_http": false,
"allow_forms": false,
"use_server_time": false,
"addr": "localhost:2947"
},
"schedule": {},
"version_reporting_disabled": false
}
@@ -0,0 +1,83 @@
{
"mycall": "{{ET_CALLSIGN}}",
"secure_login_password": "{{ET_WINLINK_PASSWD}}",
"auxiliary_addresses": [],
"locator": "{{ET_GRID}}",
"service_codes": [
"PUBLIC"
],
"http_addr": "localhost:8080",
"motd": [
"Open source Winlink client - getpat.io"
],
"connect_aliases": {
"telnet": "telnet://{mycall}:CMSTelnet@cms.winlink.org:8772/wl2k"
},
"listen": [ "ax25" ],
"hamlib_rigs": {
"et-rig": {
"address": "localhost:4532",
"network": "tcp"
}
},
"ax25": {
"engine": "agwpe",
"beacon": {
"every": 3600,
"message": "Winlink P2P",
"destination": "IDENT"
},
"agwpe": {"addr": "localhost:8000", "radio_port": 0}
},
"serial-tnc": {
"path": "/dev/ttyUSB0",
"serial_baud": 9600,
"hbaud": 1200,
"type": "Kenwood"
},
"ardop": {
"addr": "localhost:8515",
"arq_bandwidth": {
"Forced": false,
"Max": 500
},
"rig": "et-rig",
"ptt_ctrl": true,
"beacon_interval": 0,
"cwid_enabled": true
},
"pactor": {
"path": "/dev/ttyUSB0",
"baudrate": 57600,
"rig": "",
"custom_init_script": ""
},
"telnet": {
"listen_addr": ":8774",
"password": ""
},
"varahf": {
"host": "localhost",
"cmdPort": 8300,
"dataPort": 8301,
"bandwidth": 2300,
"rig": "",
"ptt_ctrl": false
},
"varafm": {
"host": "localhost",
"cmdPort": 8300,
"dataPort": 8301,
"bandwidth": 0,
"rig": "",
"ptt_ctrl": false
},
"gpsd": {
"enable_http": false,
"allow_forms": false,
"use_server_time": false,
"addr": "localhost:2947"
},
"schedule": {},
"version_reporting_disabled": false
}
@@ -0,0 +1,78 @@
{
"mycall": "{{ET_CALLSIGN}}",
"secure_login_password": "{{ET_WINLINK_PASSWD}}",
"auxiliary_addresses": [],
"locator": "{{ET_GRID}}",
"service_codes": [
"PUBLIC"
],
"http_addr": "localhost:8080",
"motd": [
"Open source Winlink client - getpat.io"
],
"connect_aliases": {
"telnet": "telnet://{mycall}:CMSTelnet@cms.winlink.org:8772/wl2k"
},
"listen": [ "ax25" ],
"hamlib_rigs": {
},
"ax25": {
"engine": "linux",
"beacon": {
"every": 3600,
"message": "Winlink P2P",
"destination": "IDENT"
},
"ax25_linux": {"port": "wl2k"}
},
"serial-tnc": {
"path": "/dev/ttyUSB0",
"serial_baud": 9600,
"hbaud": 1200,
"type": "Kenwood"
},
"ardop": {
"addr": "localhost:8515",
"arq_bandwidth": {
"Forced": false,
"Max": 500
},
"ptt_ctrl": true,
"beacon_interval": 0,
"cwid_enabled": true
},
"pactor": {
"path": "/dev/ttyUSB0",
"baudrate": 57600,
"rig": "",
"custom_init_script": ""
},
"telnet": {
"listen_addr": ":8774",
"password": ""
},
"varahf": {
"host": "localhost",
"cmdPort": 8300,
"dataPort": 8301,
"bandwidth": 2300,
"rig": "",
"ptt_ctrl": true
},
"varafm": {
"host": "localhost",
"cmdPort": 8300,
"dataPort": 8301,
"bandwidth": 0,
"rig": "",
"ptt_ctrl": false
},
"gpsd": {
"enable_http": false,
"allow_forms": false,
"use_server_time": false,
"addr": "localhost:2947"
},
"schedule": {},
"version_reporting_disabled": false
}