diff --git a/overlay/etc/adduser.conf b/overlay/etc/adduser.conf index 47cc83b..b1fb999 100644 --- a/overlay/etc/adduser.conf +++ b/overlay/etc/adduser.conf @@ -79,7 +79,7 @@ USERS_GID=1981 # new users to other groups. # This is the list of groups that new non-system users will be added to # Default: -EXTRA_GROUPS="dialout cdrom floppy audio video plugdev users" +EXTRA_GROUPS="bluetooth dialout cdrom floppy audio video plugdev users" # If ADD_EXTRA_GROUPS is set to something non-zero, the EXTRA_GROUPS # option above will be default behavior for adding new, non-system users diff --git a/overlay/etc/sudoers.d/et-rfcomm b/overlay/etc/sudoers.d/et-rfcomm new file mode 100644 index 0000000..b0704af --- /dev/null +++ b/overlay/etc/sudoers.d/et-rfcomm @@ -0,0 +1,7 @@ +%bluetooth ALL=(ALL) NOPASSWD: /usr/bin/rfcomm * +%bluetooth ALL=(ALL) NOPASSWD: /usr/sbin/kissattach /dev/rfcomm0 * +%bluetooth ALL=(ALL) NOPASSWD: /usr/sbin/kissparms * + +%bluetooth ALL=(ALL) NOPASSWD: /usr/bin/killall kissattach +%bluetooth ALL=(ALL) NOPASSWD: /usr/bin/killall kissattach +%bluetooth ALL=(ALL) NOPASSWD: /usr/bin/killall rfcomm diff --git a/overlay/opt/emcomm-tools/bin/et-log b/overlay/opt/emcomm-tools/bin/et-log index fc35879..ce685ad 100755 --- a/overlay/opt/emcomm-tools/bin/et-log +++ b/overlay/opt/emcomm-tools/bin/et-log @@ -2,7 +2,7 @@ # # Author : Gaston Gonzalez # Date : 16 March 2024 -# Updated : 9 October 2024 +# Updated : 2 January 2025 # Purpose : Log message to standard out and log file ET_TEMP_DIR=/tmp/et @@ -27,5 +27,5 @@ fi TIMESTAMP=`date "+%Y-%m-%d %H:%M:%S"` -echo $@ +echo -e $@ echo "$TIMESTAMP $@" >> ${ET_LOG_FILE} diff --git a/overlay/opt/emcomm-tools/bin/et-radio b/overlay/opt/emcomm-tools/bin/et-radio index eb5319b..5231894 100755 --- a/overlay/opt/emcomm-tools/bin/et-radio +++ b/overlay/opt/emcomm-tools/bin/et-radio @@ -23,7 +23,7 @@ while IFS= read -r radio; do MODEL=$(cat $radio | jq -r .model) options+=("$ID" "$VENDOR $MODEL") -done < <(find $ET_HOME/conf/radios.d -type f | sort) +done < <(find $ET_HOME/conf/radios.d -type f | grep -v "bt.json" | sort) SELECTED_RADIO=$(dialog --clear --menu "Select a radio:" 21 60 10 "${options[@]}" 3>&1 1>&2 2>&3) exit_status=$? diff --git a/overlay/opt/emcomm-tools/bin/et-uv-pro b/overlay/opt/emcomm-tools/bin/et-uv-pro new file mode 100755 index 0000000..e54d76c --- /dev/null +++ b/overlay/opt/emcomm-tools/bin/et-uv-pro @@ -0,0 +1,249 @@ +#!/bin/bash +# +# Author : Gaston Gonzalez +# Date : 1 January 2025 +# Updated : 3 January 2025 +# Purpose : Utility for accessing the Bluetooth TNC on the BTECH +# UV PRO. + +ACTIVE_RADIO="${ET_HOME}/conf/radios.d/btech-uvpro.bt.json" +DEVICE_NAME="UV-PRO" +BT_DEVICE="/dev/rfcomm0" +AX25_PORT="pkt1200" +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) " + echo " connect - Connect to radio via Bluetooth" + echo " pair - Pair radio (one-time operation)" + echo " unpair - Unpair radio" +} + +if [ $# -ne 1 ]; then + usage + exit 1 +fi + +error_message() { + echo -e "${RED}" + et-log $* + echo -e "${NC}" +} + +info_message() { + echo -e "${BLUE}" + et-log $* + echo -e "${NC}" +} + +success_message() { + echo -e "${GREEN}" + et-log $* + echo -e "${NC}" +} + +exit_if_no_active_radio () { + if [ ! -e ${ACTIVE_RADIO} ]; then + error_message "${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 + error_message "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 + error_message "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 pkt1200 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/^pkt1200/d\nw\nq\n" | ed ${AX25_CONF_FILE} > /dev/null 2>&1 + + fi + + info_message "Adding AX25 port for ${CALLSIGN}" + echo "pkt1200 ${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 + 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 + fi +} + +exit_if_no_active_radio + +case $1 in + 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." + 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." + + info_message "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." + 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} + + ;; + unpair) + MAC=$(cat ${ACTIVE_RADIO} | jq -e -r .bluetooth.mac) + if [ $? -ne 0 ]; then + error_message "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." + exit 1 + fi + + info_message "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 "under Menu > General Settings > Connection > Paired Devices." + echo -e "${NC}" + + ;; + 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." + + 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'" + echo -e "${NC}" + exit 1 + fi + + echo -e "${GREEN}Found UV Pro with MAC address: ${MAC}" + stop_all_services + + update_ax25_conf + + echo -e "${BLUE}Connecting to radio..." + sudo rfcomm connect /dev/rfcomm0 ${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}" + 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 + + KISS_OUT=$(sudo kissparms -c 1 -p ${AX25_PORT}) + + echo -e "${YELLOW}" + echo -e "SAMPLE COMMANDS DESCRIPTION " + echo -e "------------------------------- --------------------------------" + echo -e "axcall pkt1200 Connect directly to a node " + echo -e "axcall pkt1200 Connect to node via a digipeater" + echo -e "sudo axlisten -a -tttt -c Monitor inbound and outbound traffic" + echo -e "${NC}" + + ;; + *) + et-log "Invalid command." + usage + exit 1 + ;; +esac diff --git a/overlay/opt/emcomm-tools/conf/radios.d/btech-uvpro.bt.json b/overlay/opt/emcomm-tools/conf/radios.d/btech-uvpro.bt.json new file mode 100644 index 0000000..ba3c7a7 --- /dev/null +++ b/overlay/opt/emcomm-tools/conf/radios.d/btech-uvpro.bt.json @@ -0,0 +1,13 @@ +{ + "id": "btech-uvpro", + "vendor": "BTECH", + "model": "UV PRO (BT)", + "bluetooth": { + "mac": "" + }, + "notes": [ + "Menu > General Settings > KISS TNC > Enable KISS TNC = checked" + ], + "fieldNotes": [ + ] +} diff --git a/scripts/install-packet.sh b/scripts/install-packet.sh index 3ddd631..62dd955 100755 --- a/scripts/install-packet.sh +++ b/scripts/install-packet.sh @@ -1,6 +1,7 @@ #!/bin/bash # Author : Gaston Gonzalez # Date : 27 March 2023 +# Updated : 3 January 2025 # Purpose : Install packet packages set -e @@ -8,4 +9,13 @@ et-log "Installing AX.25 packages..." apt install \ ax25-tools \ ax25-apps \ + expect \ -y + +et-log "Installing rfcomm sudoers rules..." +cp -v ../overlay/etc/sudoers.d/* /etc/sudoers.d/ + +et-log "Updating AX.25 port permissions..." +chgrp -v -R $ET_GROUP /etc/ax25/axports +chmod -v 664 /etc/ax25/axports +