#!/bin/bash # # Author : Gaston Gonzalez # Date : 1 January 2025 # Updated : 16 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/vgc-vrn76.bt.json" DEVICE_NAME="VR-N76" BT_DEVICE="/dev/rfcomm0" AX25_PORT="wl2k" AX25_CONF_FILE="/etc/ax25/axports" function usage() { echo "Usage: $(basename $0) " 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 usage exit 1 fi 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 stop_all_services() { et-kill-all } exit_if_no_active_radio () { if [ ! -e ${ACTIVE_RADIO} ]; then echo "${ACTIVE_RADIO} file not found" exit 1 fi } get_mac_or_exit () { MAC=$(cat ${ACTIVE_RADIO} | jq -e -r .bluetooth.mac) if [ $? -ne 0 ]; then echo "No MAC address found in ${ACTIVE_RADIO}." exit 1 fi } update_ax25_conf() { [ -z "$ET_USER_CONFIG" ] && ET_USER_CONFIG="${HOME}/.config/emcomm-tools/user.json" CALLSIGN=$(cat ${ET_USER_CONFIG} | jq -r .callsign) if [ "${CALLSIGN}" = "N0CALL" ]; then et-log "No callsign set. Run et-user first." exit 1 fi GREP_OUT=$(grep ${AX25_PORT} ${AX25_CONF_FILE}) if [ $? -eq 0 ]; then # 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 # inline replacement. ed modifies the file directly. printf "g/^${AX25_PORT}/d\nw\nq\n" | ed ${AX25_CONF_FILE} > /dev/null 2>&1 fi echo "${AX25_PORT} ${CALLSIGN} 1200 255 2 1200 Packet" >> ${AX25_CONF_FILE} } 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 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 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 echo "Device with MAC ${MAC} is already paired." exit 1 fi fi echo -e "${YELLOW}" 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 "" echo "Searching for ${DEVICE_NAME}..." HCI_OUT=$(hcitool scan | grep "${DEVICE_NAME}") if [ $? -ne 0 ]; then echo "Can't find ${DEVICE_NAME}. Make sure that the radio is on and in pairing mode." exit 1 fi MAC=$(echo ${HCI_OUT} | awk '{print $1}') # Update configuration file detected MAC address sed -i "s|.*mac.*| \"mac\": \"${MAC}\"|g" ${ACTIVE_RADIO} # Generate an expect script to automatically pair our device. PAIR_SCRIPT="${HOME}/pair" cat < ${PAIR_SCRIPT} #!/usr/bin/expect -f set device "${MAC}" set timeout 60 spawn bluetoothctl expect "Agent registered" send "power on\r" expect "Changing power on succeeded" send "scan on\r" expect "${MAC}" send "pair ${MAC}\r" expect "Pairing successful" send "trust ${MAC}\r" expect "trust succeeded" send "exit\r" expect eof EOF sleep 1 && chmod 755 ${PAIR_SCRIPT} && expect ${PAIR_SCRIPT} ;; u|unpair) MAC=$(cat ${ACTIVE_RADIO} | jq -e -r .bluetooth.mac) if [ $? -ne 0 ]; then echo "No MAC found in radio configuration file." exit 1 fi PAIR_STATUS=$(bluetoothctl info "${MAC}") if [ $? -ne 0 ]; then echo "No device with ${MAC} found. Can't unpair." exit 1 fi 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 ${DEVICE_NAME}" echo -e "under Menu > General Settings > Connection > Paired Devices." echo -e "${NC}" ;; c|connect) get_mac_or_exit echo -e "${YELLOW}" 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 "${DEVICE_NAME} is not paired. Run: '$(basename $0) pair'" echo -e "${NC}" exit 1 fi echo -e "Found ${DEVICE_NAME} with MAC address: ${MAC}" update_ax25_conf sudo rfcomm connect /dev/rfcomm0 ${MAC} 1>/dev/null 2>&1 & sleep 10 && reset if [[ ! -e "${BT_DEVICE}" ]]; then echo -e "${RED}Failed to connect via Bluetooth${NC}" echo -e "${YELLOW}" echo -e "1. Try turning off and back on your radio." echo -e "2. Check your radio and ensure that ${BLUE}$(hostname)${YELLOW} is listed under:" echo -e " Menu > General Settings> Connection > Paired Devices: $(hostname)." echo -e "" echo -e " If it is not listed, re-run: ${WHITE}$(basename $0) pair${NC}\n" exit 1 fi stop_all_services echo -e "\nSelect a packet application to start:" options=("axcall" "QtTermTCP" "Winlink" "YAAC" "Exit") 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 Connect directly to a node " echo -e "axcall wl2k 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 ;; "YAAC") et-yaac start break ;; "Exit") break ;; *) echo "Invalid option, please select a number from the list." ;; esac done ;; *) et-log "Invalid command." usage exit 1 ;; esac