UV Pro - Re-implemented BTECH UV Pro command to support three modes following a connection: axcall, QtTermTCP and Winlink

This commit is contained in:
Gaston Gonzalez
2025-03-15 07:43:27 -07:00
parent fae9030a20
commit 04d11e1306
7 changed files with 330 additions and 104 deletions
+5 -1
View File
@@ -5,7 +5,11 @@ AGWMonEnable=0
AGWPaclen=80
AGWPort=8000
AGWTermCall=N0CALL
AGWToCalls=TTPBBS,
AGWToCalls=TTPBBS
KISSEnable=1
KISSMode=0
KISSSerialPort=rfcomm0
MYCALL=N0CALL
PTT=HAMLIB
PTTBAUD=0
PTTMode=17
+2
View File
@@ -4,3 +4,5 @@
%bluetooth ALL=(ALL) NOPASSWD: /usr/bin/killall kissattach
%bluetooth ALL=(ALL) NOPASSWD: /usr/bin/killall rfcomm
%bluetooth ALL=(ALL) NOPASSWD: /opt/emcomm-tools/bin/et-kill-bt
+40
View File
@@ -0,0 +1,40 @@
#!/bin/bash
# Author : Gaston Gonzalez
# Date : 14 March 2025
# UPdated : 15 March 2025
# Purpose : Stops all services tied to Bluetooth TNC operations
#
# Post Conditions:
# 1. All services started for supporting Bluetooth over serial are stopped.
#
# Note: If you try to re-establish a Bluetooth connection, you will needed to:
# 1. Turn off and turn back on your radio.
# 2. Wait 30 seconds before reconnecting (i.e. ./et-uv-pro connect)
source /opt/emcomm-tools/bin/et-common
stop_all_bt_services() {
PS_OUT=$(ps -ef | grep "[k]issattach");
if [[ $? -eq 0 ]]; then
echo "Killing kissattach processes"
killall kissattach
fi
PS_OUT=$(ps -ef | grep "[r]fcomm0");
if [[ $? -eq 0 ]]; then
ps -ef | grep "[r]fcomm0" | awk '{print $2}' | while read pid; do
echo "Killing rfcomm process: $pid"
kill $pid
done
echo -e "\n${YELLOW}Wait 30 seconds before reconnecting over Bluetooth${NC}\n"
fi
}
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root!"
exit 1
fi
stop_all_bt_services
+2 -14
View File
@@ -2,7 +2,7 @@
#
# Author : Gaston Gonzalez
# Date : 6 November 2024
# Updated : 17 February 2025
# Updated : 15 March 2025
# Purpose : Configures the system for a specific mode of operation
# Use a simple text file to save the state of the last mode selected
@@ -127,18 +127,6 @@ select_term_mode () {
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
options=()
options+=("${MODE_ID_NONE}" "No mode selected")
@@ -248,7 +236,7 @@ if [ $exit_status -eq 0 ]; then
min http://localhost:8080
;;
${MODE_ID_WINLINK_PACKET})
select_winlink_mode
winlink_mode
start_and_wait_for_service et-service-direwolf-simple
start_and_wait_for_service et-service-winlink-packet
min http://localhost:8080
+128
View File
@@ -0,0 +1,128 @@
#!/bin/bash
#
# Author : Gaston Gonzalez
# Date : 10 March 2024
# Purpose : Launches a mode using a connected Bluetooth TNC
source /opt/emcomm-tools/bin/et-common
# Use a simple text file to save the state of the last mode selected
MODE_STATUS_FILE="${HOME}/.config/emcomm-tools/et-mode"
QTTERMTCP_CONF_FILE="${HOME}/.config/QtTermTCP.ini"
# List of supported modes of operation
MODE_ID_NONE="none"
MODE_ID_BBS_CLIENT2="bbs-client2"
MODE_ID_WINLINK_PACKET="winlink-packet"
BLUETOOTH_TNC_CHECK=$(ps -ef | grep "[r]fcomm connect")
if [[ $? -ne 0 ]]; then
et-log "No Bluetooth TNC configured."
exit 1
fi
# Attempt to stop all EmComm Tools services regardless if they are running.
stop_all_services() {
et-kill-all
}
exit_on_service_failure() {
local systemd_unit_name="$1"
systemctl is-active --user --quiet "${systemd_unit_name}"
if [ $? -ne 0 ]; then
et-log "Can't start mode. ${systemd_unit_name} failed to start."
exit 1
fi
}
TIMEOUT=15 # Total time to wait in seconds
INTERVAL=2 # Interval between checks in seconds
start_and_wait_for_service() {
local systemd_unit_name="$1"
local elapsed=0
et-log "Starting ${systemd_unit_name}..."
systemctl --user start ${systemd_unit_name}
et-log "Waiting for ${systemd_unit_name} to become active..."
while ! systemctl is-active --user --quiet "${systemd_unit_name}"; do
sleep "$INTERVAL"
elapsed=$((elapsed + INTERVAL))
if [ "$elapsed" -ge "$TIMEOUT" ]; then
et-log "Timeout reached. ${systemd_unit_name} failed to start."
exit 1
fi
et-log "Waiting for ${systemd_unit_name} to become active..."
done
# Some applications even when started still need a bit of extra time to be available.
# Add a short think time of 2 seconds. The ARDOP modem requies extra time.
sleep 2
# Do one more check to ensure that we are running, otherwise exit.
exit_on_service_failure ${systemd_unit_name}
}
# Build list of options
options=()
options+=("${MODE_ID_NONE}" "No mode selected")
options+=("${MODE_ID_BBS_CLIENT2}" "BBS Client (QtTermTCP)")
options+=("${MODE_ID_WINLINK_PACKET}" "Winlink over VHF/UHF (AX.25 Packet)")
# Prompt user for option and save exit status
SELECTED_MODE=$(dialog --clear --menu "Select a mode:" 0 0 0 "${options[@]}" 3>&1 1>&2 2>&3)
exit_status=$?
tput sgr 0 && clear
if [ $exit_status -eq 0 ]; then
stop_all_services
echo ${SELECTED_MODE} > ${MODE_STATUS_FILE}
case ${SELECTED_MODE} in
${MODE_ID_NONE})
et-log "No mode selected"
;;
${MODE_ID_BBS_CLIENT2})
if [[ -e /dev/rfcomm0 ]]; then
et-log "Starting KISS over TCP"
socat -d TCP-LISTEN:8100,reuseaddr,fork FILE:/dev/rfcomm0,raw &
fi
if [[ $? -ne 0 ]]; then
et-log "Can't start QtTermTCP. KISS over TCP failed to start."
exit 1
fi
et-log "Starting QtTermTCP."
et-qttermtcp start
;;
${MODE_ID_WINLINK_PACKET})
KISS_OUT=$(sudo kissattach ${BT_DEVICE} ${AX25_PORT})
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to setup KISS for Bluetooth TNC.${NC}"
exit 1
fi
KISS_OUT=$(sudo kissparms -c 1 -p ${AX25_PORT})
start_and_wait_for_service et-service-winlink-native-packet
min http://localhost:8080
;;
*)
et-log "Mode ${SELECTED_MODE} not yet supported"
exit 1
;;
esac
else
et-log "No mode selected"
echo ${MODE_ID_NONE} > ${MODE_STATUS_FILE}
exit 1
fi
+8 -1
View File
@@ -2,7 +2,7 @@
#
# Author : Gaston Gonzalez
# Date : 17 December 2024
# Updated : 8 February 2025
# Updated : 15 March 2025
# Purpose : Wrapper script for starting JS8Call with PnP support
#
# Preconditions
@@ -59,11 +59,18 @@ update-config () {
fi
sed -i "s|^AGWTermCall.*|AGWTermCall=${CALLSIGN}|g" ${CONF_FILE}
sed -i "s|^MYCALL.*|MYCALL=${CALLSIGN}|g" ${CONF_FILE}
sed -i "s|^VARATermCall.*|VARATermCall=${CALLSIGN}|g" ${CONF_FILE}
sed -i "s|^YAPPPath.*|YAPPPath=${HOME}/Downloads|" ${CONF_FILE}
et-log "Updated QtTermTCP configuration with user callsign '${CALLSIGN}'"
PS_OUT=$(ps -ef | grep "[r]fcomm0");
if [[ $? -eq 0 ]]; then
et-log "Configuring for use with Bluetooth TNC"
return
fi
# 1. Check if the symlink was created by the udev rules
if [ -e /dev/et-audio ]; then
+145 -88
View File
@@ -2,9 +2,22 @@
#
# Author : Gaston Gonzalez
# Date : 1 January 2025
# Updated : 3 February 2025
# Purpose : Utility for accessing the Bluetooth TNC on the BTECH
# UV PRO.
# Updated : 15 March 2025
# Purpose : Utility for accessing the Bluetooth TNC on the BTECH UV PRO.
source /opt/emcomm-tools/bin/et-common
CLEAN_UP=1
cleanup() {
# Note: We need to reconnect to the Bluetooth device on every mode change.
# As such, we need kill all the rfcomm and kiss process on exit.
if [[ ${CLEAN_UP} -eq 1 ]]; then
sudo /opt/emcomm-tools/bin/et-kill-bt
fi
}
# Kill all Bluetooth TNC services on exit
trap cleanup EXIT
ACTIVE_RADIO="${ET_HOME}/conf/radios.d/btech-uvpro.bt.json"
DEVICE_NAME="UV-PRO"
@@ -12,47 +25,35 @@ BT_DEVICE="/dev/rfcomm0"
AX25_PORT="wl2k"
AX25_CONF_FILE="/etc/ax25/axports"
ESC="\x1B"
RED="${ESC}[1;31m"
BLUE="${ESC}[1;34m"
GREEN="${ESC}[1;32m"
WHITE="${ESC}[97m"
YELLOW="${ESC}[1;33m"
NC="${ESC}[0m"
function usage() {
echo "Usage: $(basename $0) <command>"
echo " connect - Connect to radio via Bluetooth"
echo " pair - Pair radio (one-time operation)"
echo " unpair - Unpair radio"
echo " c, connect - Connect to radio via Bluetooth"
echo " p, pair - Pair radio (one-time operation)"
echo " u, unpair - Unpair radio"
CLEAN_UP=0
}
if [ $# -ne 1 ]; then
if [[ $# -ne 1 ]]; then
usage
exit 1
fi
error_message() {
echo -e "${RED}"
et-log $*
echo -e "${NC}"
}
if [[ -e ${BT_DEVICE} ]]; then
echo -e "${YELLOW}Your ${BLUE}${DEVICE_NAME}${YELLOW} may have a connection that needs to be cleaned up."
echo -e "Press ${WHITE}[ENTER]${YELLOW} to clean-up.${NC}"
read -p ""
cleanup
fi
info_message() {
echo -e "${BLUE}"
et-log $*
echo -e "${NC}"
}
success_message() {
echo -e "${GREEN}"
et-log $*
echo -e "${NC}"
stop_all_services() {
et-kill-all
}
exit_if_no_active_radio () {
if [ ! -e ${ACTIVE_RADIO} ]; then
error_message "${ACTIVE_RADIO} file not found"
echo "${ACTIVE_RADIO} file not found"
exit 1
fi
}
@@ -60,7 +61,7 @@ exit_if_no_active_radio () {
get_mac_or_exit () {
MAC=$(cat ${ACTIVE_RADIO} | jq -e -r .bluetooth.mac)
if [ $? -ne 0 ]; then
error_message "No MAC address found in ${ACTIVE_RADIO}."
echo "No MAC address found in ${ACTIVE_RADIO}."
exit 1
fi
}
@@ -72,7 +73,7 @@ update_ax25_conf() {
CALLSIGN=$(cat ${ET_USER_CONFIG} | jq -r .callsign)
if [ "${CALLSIGN}" = "N0CALL" ]; then
error_message "No callsign set. Run et-user first."
et-log "No callsign set. Run et-user first."
exit 1
fi
@@ -85,51 +86,87 @@ update_ax25_conf() {
fi
info_message "Adding AX25 port for ${CALLSIGN}"
echo "${AX25_PORT} ${CALLSIGN} 1200 255 2 1200 Packet" >> ${AX25_CONF_FILE}
}
stop_all_services() {
PS_OUT=$(ps -ef | grep [k]issattach)
if [ $? -eq 0 ]; then
info_message "Killing kissattach process(es)..."$
sudo killall kissattach
do_kiss_attach() {
echo -e "${BLUE}Connecting KISS interface using ${BT_DEVICE} and AX.25 port: ${AX25_PORT}${NC}"
KISS_OUT=$(sudo kissattach ${BT_DEVICE} ${AX25_PORT})
if [[ $? -ne 0 ]]; then
echo -e "${RED}Failed to attach KISS port.${NC}"
exit 1
fi
sleep 3
PS2_OUT=$(ps -ef | grep -v krfcommd | grep [r]fcomm)
if [ $? -eq 0 ]; then
info_message "Killing rfcomm process(es)..."
sudo killall rfcomm
KISS_OUT=$(sudo kissparms -c 1 -p ${AX25_PORT})
}
exit_on_service_failure() {
local systemd_unit_name="$1"
systemctl is-active --user --quiet "${systemd_unit_name}"
if [ $? -ne 0 ]; then
et-log "Can't start mode. ${systemd_unit_name} failed to start."
exit 1
fi
}
TIMEOUT=15 # Total time to wait in seconds
INTERVAL=2 # Interval between checks in seconds
start_and_wait_for_service() {
local systemd_unit_name="$1"
local elapsed=0
et-log "Starting ${systemd_unit_name}..."
systemctl --user start ${systemd_unit_name}
et-log "Waiting for ${systemd_unit_name} to become active..."
while ! systemctl is-active --user --quiet "${systemd_unit_name}"; do
sleep "$INTERVAL"
elapsed=$((elapsed + INTERVAL))
if [ "$elapsed" -ge "$TIMEOUT" ]; then
et-log "Timeout reached. ${systemd_unit_name} failed to start."
exit 1
fi
et-log "Waiting for ${systemd_unit_name} to become active..."
done
# Some applications even when started still need a bit of extra time to be available.
# Add a short think time of 2 seconds. The ARDOP modem requies extra time.
sleep 2
# Do one more check to ensure that we are running, otherwise exit.
exit_on_service_failure ${systemd_unit_name}
}
exit_if_no_active_radio
case $1 in
pair)
p|pair)
MAC=$(cat ${ACTIVE_RADIO} | jq -e -r .bluetooth.mac)
if [ $? -eq 0 ]; then
PAIR_STATUS=$(bluetoothctl info "${MAC}" | grep "Paired:" | awk '{print $2}')
if [ "${PAIR_STATUS}" == "yes" ]; then
error_message "Device with MAC ${MAC} is already paired."
echo "Device with MAC ${MAC} is already paired."
exit 1
fi
fi
echo -e "${YELLOW}"
echo -e "1. Turn on the BTECH UV PRO"
echo -e "2. Goto Menu > Pairing and press OK"
read -p "3. Press [ENTER] when done."
echo -e "1. Turn off your ${DEVICE_NAME}"
echo -e "2. Turn on your ${DEVICE_NAME}"
echo -e "3. Goto Menu > Pairing and press OK"
echo -e "4. Press ${WHITE}[ENTER]${YELLOW} when done.${NC}"
read -p ""
info_message "Searching for ${DEVICE_NAME}..."
echo "Searching for ${DEVICE_NAME}..."
HCI_OUT=$(hcitool scan | grep "${DEVICE_NAME}")
if [ $? -ne 0 ]; then
error_message "Can't find ${DEVICE_NAME}. Make sure that the radio is on and in pairing mode."
echo "Can't find ${DEVICE_NAME}. Make sure that the radio is on and in pairing mode."
exit 1
fi
@@ -164,81 +201,101 @@ EOF
sleep 1 && chmod 755 ${PAIR_SCRIPT} && expect ${PAIR_SCRIPT}
;;
unpair)
u|unpair)
MAC=$(cat ${ACTIVE_RADIO} | jq -e -r .bluetooth.mac)
if [ $? -ne 0 ]; then
error_message "No MAC found in radio configuration file."
echo "No MAC found in radio configuration file."
exit 1
fi
PAIR_STATUS=$(bluetoothctl info "${MAC}")
if [ $? -ne 0 ]; then
error_message "No device with ${MAC} found. Can't unpair."
echo "No device with ${MAC} found. Can't unpair."
exit 1
fi
info_message "Unpairing ${DEVICE_NAME}..."
echo "Unpairing ${DEVICE_NAME}..."
bluetoothctl untrust ${MAC}
bluetoothctl remove ${MAC}
echo -e "${YELLOW}"
echo -e "You may also want to remove this device from your UV PRO"
echo -e "You may also want to remove this device from your ${DEVICE_NAME}"
echo -e "under Menu > General Settings > Connection > Paired Devices."
echo -e "${NC}"
;;
connect)
c|connect)
get_mac_or_exit
echo -e "${YELLOW}"
echo -e "1. Turn on the BTECH UV PRO"
echo -e "2. Menu > General Settings > KISS TNC = checked"
read -p "3. Press [ENTER] when done."
echo -e "1. Turn off your ${DEVICE_NAME}"
echo -e "2. Turn on your ${DEVICE_NAME}"
echo -e "3. Goto Menu > General Settings > KISS TNC > Enable KISS TNC"
echo -e "4. Press ${WHITE}[ENTER]${YELLOW} when done.${NC}"
read -p ""
is_paired=$(bluetoothctl info ${MAC} | grep "Paired" | awk '{print $2}')
if [ "${is_paired}" != "yes" ]; then
echo -e "${RED}"
et-log "UV Pro is not paired. Run: '$(basename $0) pair'"
et-log "${DEVICE_NAME} is not paired. Run: '$(basename $0) pair'"
echo -e "${NC}"
exit 1
fi
echo -e "${GREEN}Found UV Pro with MAC address: ${MAC}"
stop_all_services
echo -e "Found ${DEVICE_NAME} with MAC address: ${MAC}"
update_ax25_conf
echo -e "${BLUE}Connecting to radio..."
sudo rfcomm connect /dev/rfcomm0 ${MAC} 1>/dev/null 2>&1 &
sudo rfcomm connect ${BT_DEVICE} ${MAC} 1>/dev/null 2>&1 &
sleep 10 && reset
if [ -e /dev/rfcomm0 ]; then
echo -e "${GREEN}UV Pro connected via Bluetooth serial${NC}"
else
echo -e "${RED}UV Pro failed to connect via Bluetooth serial${NC}"
if [[ ! -e "${BT_DEVICE}" ]]; then
echo -e "${RED}Failed to connect via Bluetooth${NC}\n"
echo -e "${YELLOW}Try turning off and back on your radio${NC}\n"
exit 1
fi
echo -e "${BLUE}Connecting KISS interface using ${BT_DEVICE} and AX.25 port: ${AX25_PORT}${NC}"
KISS_OUT=$(sudo kissattach ${BT_DEVICE} ${AX25_PORT})
if [ $? -eq 0 ]; then
echo -e "${GREEN}Packet port ready"
else
echo -e "${RED}Failed to setup radio for packet.${NC}"
exit 1
fi
stop_all_services
KISS_OUT=$(sudo kissparms -c 1 -p ${AX25_PORT})
echo -e "\nSelect a packet application to start:"
options=("axcall" "QtTermTCP" "Winlink" "Exit")
echo -e "${YELLOW}"
echo -e "SAMPLE COMMANDS DESCRIPTION "
echo -e "------------------------------- --------------------------------"
echo -e "axcall ${AX25_PORT} <STATION> Connect directly to a node "
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 "${NC}"
select opt in "${options[@]}"
do
case $opt in
"axcall")
do_kiss_attach
echo -e "${YELLOW}"
echo -e "SAMPLE COMMANDS DESCRIPTION "
echo -e "----------------------------- --------------------------------"
echo -e "axcall wl2k <STATION> Connect directly to a node "
echo -e "axcall wl2k <STATION> <DIGI> Connect to node via a digipeater"
echo -e "sudo axlisten -a -tttt -c Monitor inbound and outbound traffic"
echo -e "${NC}"
# We can't have the rfcomm and kiss processes killed.
CLEAN_UP=0
break
;;
"QtTermTCP")
et-qttermtcp start 1>/dev/null 2>&1
break
;;
"Winlink")
do_kiss_attach
start_and_wait_for_service et-service-winlink-native-packet
min http://localhost:8080 1>/dev/null 2>&1
break
;;
"Exit")
break
;;
*)
echo "Invalid option, please select a number from the list."
;;
esac
done
;;
*)