#!/bin/bash ################################################################# # /* # * Copyright (C) 2019, 2020, 2021 N4IRR # * # * Permission to use, copy, modify, and/or distribute this software for any # * purpose with or without fee is hereby granted, provided that the above # * copyright notice and this permission notice appear in all copies. # * # * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH # * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # * AND FITNESS. IN NO EVENT SHALL N4IRR BE LIABLE FOR ANY SPECIAL, DIRECT, # * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM # * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE # * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # * PERFORMANCE OF THIS SOFTWARE. # */ ################################################################# #DEBUG=echo #set -xv # this line will enable debug SCRIPT_VERSION="1.6.3" AB_DIR=${AB_DIR:-"/var/lib/dvswitch"} MMDVM_DIR=${MMDVM_DIR:-"/var/lib/mmdvm"} DVSWITCH_INI=${DVSWITCH_INI:-"/opt/MMDVM_Bridge/DVSwitch.ini"} MMDVM_INI=${MMDVM_INI:-"/opt/MMDVM_Bridge/MMDVM_Bridge.ini"} NODE_DIR=${NODE_DIR:-"/tmp"} # Default server and port assignment, but overridden by value in ABInfo TLV_PORT=36000 USRP_PORT=32001 SERVER=127.0.0.1 # HTTP_PORT is used for the simple server that supports data file uploads HTTP_PORT=9042 # Error codes defined below SUCCESSS=0 ERROR_FILE_NOT_FOUND=-1 ERROR_INVALID_ARGUMENT=-2 ERROR_EMPTY_FILE=-3 ERROR_DIR_NOT_FOUND=-4 ERROR_INVALID_FILE=-5 ERROR_LOOKUP_FAILED=-6 ERROR_INI_FAILURE=-7 _ERRORCODE=$SUCCESSS ################################################################# # Return value from ABInfo_xxxx.json # The value may be an value, object/value or object/object/value ################################################################# function getABInfoValue() { declare _json_file=`getABInfoFileName` python3 - </dev/null | head -1` else declare _json_file=$ABINFO # Use the environment variable (probably set by AB) fi echo $_json_file } ################################################################# # Parse and print out an ini file value # parseIniFile fileName stanza tag ################################################################# function parseIniFile() { python3 - < 1 will increase audio level above unity ################################################################# function setUSRPGain() { if [ $# -eq 0 ]; then getABInfoValue usrp to_pcm gain else remoteControlCommand "usrpGain=$1" fi } ################################################################# # Set the digital audio gain ################################################################# function setTLVGain() { if [ $# -eq 0 ]; then getABInfoValue usrp to_ambe gain else remoteControlCommand "tlvGain=$1" fi } ################################################################# # Set the USRP agc params to threshold, slope and decay ################################################################# function setUSRPAgc() { if [ $# -eq 0 ]; then echo "Argument required: AGC parameters (threshold, slope and decay)" _ERRORCODE=$ERROR_INVALID_ARGUMENT else remoteControlCommand "agcUSRP=$1,$2,$3" fi } ################################################################# # Set the TLV agc params to threshold, slope and decay ################################################################# function setTLVAgc() { if [ $# -eq 0 ]; then echo "Argument required: AGC parameters (threshold, slope and decay)" _ERRORCODE=$ERROR_INVALID_ARGUMENT else remoteControlCommand "agcTLV=$1,$2,$3" fi } ################################################################# # Set the USRP audio codec to {SLIN|ULAW|ADPCM} ################################################################# function setUSRPCodec() { if [ $# -eq 0 ]; then echo "Argument required: codec" _ERRORCODE=$ERROR_INVALID_ARGUMENT else string='|SLIN|ULAW|ADPCM|slin|ulaw|adpcm|' if [[ $string == *"|$1|"* ]]; then remoteControlCommand "codec=$1" else echo "Invalid argument: {slin|ulaw|adpcm}" _ERRORCODE=$ERROR_INVALID_ARGUMENT fi fi } ################################################################# # set the AB listener port ################################################################# function setTLVRxPort() { if [ $# -eq 0 ]; then getABInfoValue tlv rx_port else remoteControlCommand "rxport=$1" sleep 1 TLV_PORT=`getTLVPort` # We have changed the listener on AB, so we must adjust our sending port fi } ################################################################# # Set the AB -> MB transmit port ################################################################# function setTLVTxPort() { if [ $# -eq 0 ]; then getABInfoValue tlv tx_port else remoteControlCommand "txport=$1" fi } ################################################################# # Send the info packet to a USRP client (DVSM/UC) ################################################################# function getInfo() { if [ $# -eq 0 ]; then remoteControlCommand "info" else getABInfoValue $1 $2 fi } ################################################################# # mute AB ("OFF", "USRP", "TLV", "BOTH") ################################################################# function setMute() { if [ $# -eq 0 ]; then getABInfoValue mute else remoteControlCommand "mute=$1" fi } ################################################################# # Send "text" message to Mobile ################################################################# function sendMessage() { if [ -z "$1" ]; then echo "Argument required: text" _ERRORCODE=$ERROR_INVALID_ARGUMENT else remoteControlCommand "message=$1" fi } ################################################################# # Send a macro definition or file to Mobile ################################################################# function sendMacro() { if [ -z "$2" ]; then echo "Argument required: file or text" _ERRORCODE=$ERROR_INVALID_ARGUMENT else remoteControlCommand "$1=$2" fi } ################################################################# # Set the ping timer (keep alive) ################################################################# function setPingTimer() { if [ -z "$1" ]; then getABInfoValue usrp ping else remoteControlCommand "ping=$1" fi } ################################################################# # Tell AB to reload database files from disk into memory ################################################################# function reloadDatabase() { remoteControlCommand "reloadDatabase" } ################################################################# # Send the remote control TLV command to Analog_Bridge ################################################################# function remoteControlCommand() { if [ ! -z "${DEBUG}" ]; then echo "remoteControlCommand $1" else PYTHON_ARG="$1" python3 - <iiiiiii',usrpSeq, 0, 0, 0, packetType << 24, 0, 0)) + cmd.encode("utf-8") + struct.pack('>i',0) usrpSeq = (usrpSeq + 1) & 0xffff udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) udp.sendto(usrp, ('$SERVER', $USRP_PORT)) udp.close() except: sys.stderr.write("USRPCommand: error sending command\n") traceback.print_exc() END } ################################################################# # ################################################################# function setCallAndID() { if [ ! -z "${DEBUG}" ]; then echo "setCallAndID $1" else python3 - <> 16) & 0xff),((dmr_id >> 8) & 0xff),(dmr_id & 0xff),0,0,0,0,0,0,0,0,0)[0:14] + call + chr(0) _sock.sendto(cmd, ('$SERVER', $TLV_PORT)) _sock.close() except: sys.stderr.write("setCallAndID: error sending command\n") exit(1) END fi } ################################################################# # Tell AB to upload a file to the Mobile client ################################################################# function pushFileToClient() { if [ ! -z "${DEBUG}" ]; then echo "remoteControlCommand pushFileToClient $1" else if [ ! -f $1 ]; then echo "File $1 does not exist, abort transfer" return fi size=`wc -c $1 | awk '{print $1}'` if (($size == 0)); then echo "file is empty, abort transfer" return fi python3 - < 0 bytes. Arguments are # Directory, Server IP and file name. ################################################################# function pushLocalFileAsURLToClient() { if [ ! -f "$1/$3" ]; then echo "File $1/$3 does not exist, abort transfer" _ERRORCODE=$ERROR_FILE_NOT_FOUND return fi declare size=`wc -c "$1/$3" | awk '{print $1}'` if (($size == 0)); then echo "file is empty, abort transfer" _ERRORCODE=$ERROR_EMPTY_FILE return fi pushURLToClient "$2/$3" } ################################################################# # Send the URL of a file to download to DVSM. DVSM knows that if # the name begins with http it is a URL. ################################################################# function pushURLToClient() { python3 - </dev/null } ################################################################# # Get the current ASL node list (used by allmon) and do a simple # validation (look for my node number) ################################################################# function DownloadAndValidateASLNodeList() { declare _OS=$(uname -s) curl --fail -s https://allmondb.allstarlink.org/allmondb.php | sed -e :a -e '$d;N;2,7ba' -e 'P;D' > "$NODE_DIR/$1" if [ ${_OS} == Darwin ]; then sed -i '' 's/||/||/g' "$NODE_DIR/$1" else sed -i 's/||/||/g' "$NODE_DIR/$1" fi declare isValid=`grep -i N4IRS "$NODE_DIR/$1"` if [ -z "${isValid}" ]; then rm "$NODE_DIR/$1" echo "ASL node list is not valid, ignoring" fi } ################################################################# # ################################################################# function collectProcessDataFiles() { declare gitURL="https://raw.githubusercontent.com/g4klx" echo "Processing NXDN" ParseDVREFNodeFile "NXDNHosts.json" "$NODE_DIR/NXDN_node_list.txt" echo "Processing P25" ParseDVREFNodeFile "P25Hosts.json" "$NODE_DIR/P25_node_list.txt" echo "Processing DMR" ParseTGFile TGList_BM.txt > $NODE_DIR/DMR_node_list.txt 2>/dev/null echo "Processing TGIF" ParseTGFileTGIF TGList_TGIF.txt > $NODE_DIR/TGIF_node_list.txt 2>/dev/null echo "Processing YSF" ParseDVREFNodeFile "YSFHosts.json" "$NODE_DIR/YSF_node_list.txt" echo "Processing DStar" ParseDStarFile DSTAR_Hosts.txt > $NODE_DIR/DSTAR_node_list.txt 2>/dev/null echo "Processing ASL" DownloadAndValidateASLNodeList node_list.txt 2>/dev/null } ################################################################# # Get all mobile data files, proces them into proper format and # push them to the device ################################################################# function collectProcessPushDataFiles() { collectProcessDataFiles echo "Pushing NXDN" pushFileToClient "$NODE_DIR/NXDN_node_list.txt" echo "Pushing P25" pushFileToClient "$NODE_DIR/P25_node_list.txt" echo "Pushing DMR" pushFileToClient "$NODE_DIR/DMR_node_list.txt" echo "Pushing TGIF" pushFileToClient "$NODE_DIR/TGIF_node_list.txt" echo "Pushing YSF" pushFileToClient "$NODE_DIR/YSF_node_list.txt" echo "Pushing DStar" pushFileToClient "$NODE_DIR/DSTAR_node_list.txt" echo "Pushing ASL" pushFileToClient "$NODE_DIR/node_list.txt" } ################################################################# # Utility function to get the primary IP address ################################################################# function getMyIP() { declare _ip _line while IFS=$': \t' read -a _line ;do [ -z "${_line%inet}" ] && _ip=${_line[${#_line[1]}>4?1:2]} && [ "${_ip#127.0.0.1}" ] && echo $_ip && return 0 done< <(LANG=C /sbin/ifconfig) } ################################################################# # Get all mobile data files, proces them into proper format and # push the URL to the device. Starts a simple web server on port # $HTTP_PORT (9042). ################################################################# function collectProcessPushDataFilesHTTP() { declare processID=`ps aux | grep "python3 -m http.server $HTTP_PORT" | grep -v grep | awk '{print $2}'` kill $processID 2>/dev/null pushd "$NODE_DIR" python3 -m http.server $HTTP_PORT & popd declare _MYIP=`getMyIP` PSERVER="http://${_MYIP}:$HTTP_PORT" collectProcessDataFiles echo "Pushing NXDN" pushLocalFileAsURLToClient "$NODE_DIR" "$PSERVER" "NXDN_node_list.txt" sleep 5 echo "Pushing P25" pushLocalFileAsURLToClient "$NODE_DIR" "$PSERVER" "P25_node_list.txt" sleep 5 echo "Pushing DMR" pushLocalFileAsURLToClient "$NODE_DIR" "$PSERVER" "DMR_node_list.txt" sleep 5 echo "Pushing TGIF" pushLocalFileAsURLToClient "$NODE_DIR" "$PSERVER" "TGIF_node_list.txt" sleep 5 echo "Pushing YSF" pushLocalFileAsURLToClient "$NODE_DIR" "$PSERVER" "YSF_node_list.txt" sleep 5 echo "Pushing DStar" pushLocalFileAsURLToClient "$NODE_DIR" "$PSERVER" "DSTAR_node_list.txt" sleep 5 echo "Pushing ASL" pushLocalFileAsURLToClient "$NODE_DIR" "$PSERVER" "node_list.txt" sleep 10 processID=`ps aux | grep "python3 -m http.server $HTTP_PORT" | grep -v grep | awk '{print $2}'` kill $processID 2>/dev/null sendMessage "Database update complete" } ################################################################# # Download and validate a file. This function will use curl to download # a file from a server and test for valid data. The tests include # a warning on download failure, and errors for file size and valid contents. ################################################################# function downloadAndValidate() { ${DEBUG} curl --fail -o "$MMDVM_DIR/$1" -s "http://www.pistar.uk/downloads/$2" if (( $? != 0 )); then echo "Warning, download failure" _ERRORCODE=$ERROR_FILE_NOT_FOUND fi if [ ! -f $MMDVM_DIR/$1 ]; then echo "Error, $1 file does not seem to exist" _ERRORCODE=$ERROR_INVALID_FILE else declare _fileSize=`wc -c $MMDVM_DIR/$1 | awk '{print $1}'` if (( ${_fileSize} < 10 )); then echo "Error, $1 file has no contents" _ERRORCODE=$ERROR_INVALID_FILE else declare isValid=`grep $3 "$MMDVM_DIR/$1"` if [ -z "$isValid" ]; then echo "Error, $1 file does not seem to be valid" _ERRORCODE=$ERROR_INVALID_FILE fi fi fi } ################################################################# # Download all user databases ################################################################# function downloadDatabases() { if [ -d "${MMDVM_DIR}" ] && [ -d "${AB_DIR}" ]; then ${DEBUG} curl -s -N "https://database.radioid.net/static/user.csv" | awk -F, 'NR>1 {if ($1 > "") print $1,$2,$3}' > "${MMDVM_DIR}/DMRIds.dat" ${DEBUG} curl -s -N "https://database.radioid.net/static/user.csv" | awk -F, 'BEGIN{OFS=",";} NR>1 {if ($1 > "") print $1,$2,$3}' > "${AB_DIR}/subscriber_ids.csv" ${DEBUG} curl -s -N "https://database.radioid.net/static/nxdn.csv" > "${MMDVM_DIR}/NXDN.csv" ${DEBUG} curl -s -N "http://www.pistar.uk/downloads/DMR_Hosts.txt" > "${MMDVM_DIR}/DMR_Hosts.txt" downloadAndValidate "NXDNHosts.txt" "NXDN_Hosts.txt" "dvswitch.org" downloadAndValidate "P25Hosts.txt" "P25_Hosts.txt" "dvswitch.org" downloadAndValidate "TGList_BM.txt" "TGList_BM.txt" "DVSWITCH" downloadAndValidate "YSFHosts.txt" "YSF_Hosts.txt" "dvswitch.org" downloadAndValidate "TGList_TGIF.txt" "TGList_TGIF.txt" "TGIF" # TG list direct from BM # curl -X 'GET' 'https://api.brandmeister.network/v2/talkgroup' -H 'accept: */*' # TG list from TGIF # curl -X 'GET' 'https://api.tgif.network/dmr/talkgroups/json' # TG list from FreeDMR # curl -X 'GET' 'https://freedmr.cymru/talkgroups/talkgroup_ids_json.php' downloadAndValidate "FCSRooms.txt" "FCS_Hosts.txt" "FCS00106" downloadAndValidate "DCS_Hosts.txt" "DCS_Hosts.txt" "DCS006" downloadAndValidate "DPlus_Hosts.txt" "DPlus_Hosts.txt" "REF030" downloadAndValidate "DExtra_Hosts.txt" "DExtra_Hosts.txt" "XRF012" downloadAndValidate "XLXHosts.txt" "XLXHosts.txt" "001;" downloadAndValidate "APRS_Hosts.txt" "APRS_Hosts.txt" "noam.aprs2.net" declare isValid=`grep 3113043 "${MMDVM_DIR}/DMRIds.dat"` if [ -z "$isValid" ]; then ${DEBUG} curl -s -N "http://registry.dstar.su/dmr/DMRIds.php" > "${MMDVM_DIR}/DMRIds.dat" ${DEBUG} curl -s -N "http://registry.dstar.su/dmr/DMRIds.php" | awk -F, 'BEGIN{FS=" ";OFS=",";} NR>1 {if ($1 > "") print $1,$2,$3}' > "${AB_DIR}/subscriber_ids.csv" isValid=`grep 3113043 "${MMDVM_DIR}/DMRIds.dat"` if [ -z "$isValid" ]; then echo "Error, DMR ID file does not seem to be valid" _ERRORCODE=$ERROR_INVALID_FILE fi fi else echo "Destination directory does not exist, aborting" _ERRORCODE=$ERROR_DIR_NOT_FOUND fi } ################################################################# # Set digital mode of AB/MB getting the proper ports from DVSwitch.ini ################################################################# function setMode() { if [ $# -eq 0 ]; then # No argument passed, just return the current value echo `getABInfoValue tlv ambe_mode` else declare _MODE=`echo $1 | tr '[:lower:]' '[:upper:]'` if [[ "|DMR|YSF|P25|NXDN|DSTAR|ASL|STFU|" == *"$_MODE"* ]]; then ${DEBUG} setTLVRxPort 30000 # cause AB to stop listening _MBTX=`parseIniFile "$DVSWITCH_INI" "$_MODE" "TXPort"` _MBRX=`parseIniFile "$DVSWITCH_INI" "$_MODE" "RXPort"` if [ ! -z $_MBTX ]; then sendMessage "Setting mode to $_MODE" ${DEBUG} setAmbeMode $_MODE ${DEBUG} setTLVTxPort ${_MBRX} ${DEBUG} setTLVRxPort ${_MBTX} if [ $# -ge 2 ]; then ${DEBUG} setTLVGain $2; setTLVAudioType AUDIO_USE_GAIN; fi if [ $# -ge 3 ]; then ${DEBUG} setUSRPGain $3; setUSRPAudioType AUDIO_USE_GAIN; fi ${DEBUG} getInfo else echo "Error, DVSwitch.ini file not found" _ERRORCODE=$ERROR_FILE_NOT_FOUND fi else echo "Error, Mode must be DMR or YSF or P25 or DSTAR, NXDN, ASL or STFU" _ERRORCODE=$ERROR_INVALID_ARGUMENT fi fi } ################################################################# # Show pretty ABInfo json file ################################################################# function prettyPrintInfo() { declare _abname=`getABInfoFileName` if [ -f ${_abname} ]; then python3 -mjson.tool ${_abname} else echo ABInfo file not found fi } ################################################################# # Lookup info in database file ################################################################# function lookup() { declare databaseName="${MMDVM_DIR}/DMRIds.dat" if [ -f "${databaseName}" ]; then found=`grep -i $1 "${databaseName}"` if [ -z "$found" ]; then _ERRORCODE=$ERROR_LOOKUP_FAILED else echo $found fi else echo DMR ID database file not found at ${databaseName} _ERRORCODE=$ERROR_LOOKUP_FAILED fi } ################################################################# # Get version information from AB and MB ################################################################# function appVersion() { if [ $# -eq 0 ]; then echo "dvswitch.sh version $SCRIPT_VERSION" else case $1 in ab|AB|Analog_Bridge) if [ -f "/opt/Analog_Bridge/Analog_Bridge" ]; then "/opt/Analog_Bridge/Analog_Bridge" -v else declare _ver=`getABInfoValue ab version` echo "Analog_Bridge version ${_ver}" fi ;; mb|MB|MMDVM_Bridge) if [ -f "/opt/MMDVM_Bridge/MMDVM_Bridge" ]; then "/opt/MMDVM_Bridge/MMDVM_Bridge" -v else echo "MMDVM_Bridge version UNKNOWN" fi ;; gw|GW) for gw in P25Gateway NXDNGateway YSFGateway; do if [ -f "/opt/$gw/$gw" ]; then "/opt/$gw/$gw" -v fi done ;; path) if [ -f "$2" ]; then "$2" -v fi ;; all|ALL) appVersion for app in ab mb gw; do appVersion $app done for app in Analog_Reflector STFU; do appVersion path "/opt/${app}/${app}" done ;; esac fi } ################################################################# # Echo the list of "enabled" modes in MB.ini ################################################################# function getEnabledModes() { # For each mode, disable the main section and the network declare _MODE="" declare _NET="" declare enabledModes="" for mode in DMR "System Fusion" P25 D-Star NXDN; do _MODE=`parseIniFile "$MMDVM_INI" "${mode}" "Enable"` _NET=`parseIniFile "$MMDVM_INI" "${mode} Network" "Enable"` #echo "${mode} mode = ${_MODE} and Network = ${_NET}" if [ ${_MODE} == "1" ] && [ ${_NET} == "1" ]; then enabledModes=`echo ${enabledModes}${mode}" " ` fi done echo "$1${enabledModes}" } ################################################################# # Print out the owner for a specified UDP port ################################################################# function getUDPPortOwner() { if [ -z "$1" ]; then echo "Argument required: port number" _ERRORCODE=$ERROR_INVALID_ARGUMENT else declare port=":$1" declare _OS=$(uname -s) if [ ${_OS} == Darwin ]; then declare pid=$(lsof -i udp$port -P +c 0 | awk 'NR>1 {print $2}') if [ -z "$pid" ]; then echo "No processes listening on port $port" else ps -f $pid | awk 'NR>1 {print $8 " " $9 " " $10}' fi else declare pid=$(sudo netstat -unap | grep "$port" | awk '{print $6}' | cut -d'/' -f1) if [ -z "$pid" ]; then echo "No processes listening on port $port" else ps -f $pid | awk 'NR>1 {print $9 " " $10 " " $11}' fi fi fi } ################################################################# # Print out the ports owned by a specified process ################################################################# function getUDPPortsForProcess() { if [ -z "$1" ]; then echo "Argument required: process name" _ERRORCODE=$ERROR_INVALID_ARGUMENT else declare process="$1" declare _OS=$(uname -s) set -f; if [ ${_OS} == Darwin ]; then declare ports=($(lsof -i udp -P +c 0 | grep -i "${process:0:14}" | awk '{if ($9 != "*:*") print $9}' | cut -d':' -f2)) if [ ${#ports[@]} -gt 0 ]; then echo "$process owns UDP ports: ${ports[@]}" fi else declare ports=($(sudo netstat -unap | grep -i "${process:0:14}" | awk '{split($4, a, ":"); print a[2]}')) if [ ${#ports[@]} -gt 0 ]; then echo "$process owns UDP ports: ${ports[@]}" fi fi set +f; fi } ################################################################# # Print out the ports for all DVSwitch processes ################################################################# function getUDPPortsForDVSwitch() { for i in Analog_Bridge MMDVM_Bridge Quantar_Bridge Analog_Reflector STFU P25Gateway NXDNGateway DMRGateway YSFGateway ircddbgateway YSFParrot NXDNParrot md380-emu; do getUDPPortsForProcess "$i" done } ################################################################# # ################################################################# function updateINIFileValue() { declare _file="$1" declare _section="$2" declare _tag="$3" declare _value="${@:4}" if [ $# -ge 2 ]; then # Do we have the correct number of arguments? if [ -f ${_file} ]; then # Check if the file exists (better error message then parseIniFile) declare _secFound=$(grep -i "^\\[${_section}\\]" "${_file}") if [ ! -z "${_secFound}" ]; then # See if the section exists if [ ! -z ${_tag} ]; then declare _tagLine=$(sed -n "/^\[${_section}\]/,/^\[/ p" "${_file}" | sed -n "/${_tag}/p") if [ ! -z "${_tagLine}" ]; then if [ ! -z "${_value}" ]; then declare _oldValue=`parseIniFile "${_file}" "${_section}" "${_tag}"` declare _oldLine="^${_tag}.*=.*${_oldValue}" declare _equal=`[[ "${_tagLine}" == *" = "* ]] && echo " = " || echo "="` declare _newLine="${_tag}${_equal}${_value}" sed -i -e "/^\[${_section}\]/,/^\[/ s/${_oldLine}/${_newLine}/i" "${_file}" else echo "${_tagLine}" fi else echo "Error Tag \"${_tag}\" was not found in section \"${_section}\" of file \"${_file}\"" _ERRORCODE=$ERROR_INI_FAILURE fi else declare _fullSection=$(sed -n "/^\[${_section}\]/,/^\[/ p" "${_file}") echo "${_fullSection}" fi else echo "Error, section \"${_section}\" was not found in file \"${_file}\"" _ERRORCODE=$ERROR_INI_FAILURE fi else echo "INI File \"${_file}\" not found" _ERRORCODE=$ERROR_INI_FAILURE fi else echo "Error, argument number: file section {tag} {value}" _ERRORCODE=$ERROR_INI_FAILURE fi } ################################################################# # ################################################################# function setGpsToIP() { declare ip=$(curl -s ifconfig.me) declare json=$(curl -s -L ipvigilante.com/$ip) latlon=(`python3 - < DVSM/UC audio codec" echo -e "\t tlvPorts rxport txport\t\t\t\t Set Analog_Bridge receive and transmit ports" echo -e "\t info \t\t\t\t\t\t Update ABInfo and send to DVSM/UC" echo -e "\t show \t\t\t\t\t\t Pretty print the ABInfo json file" echo -e "\t lookup \t\t\t\t\t Lookup a DMR ID/call in the local database" echo -e "\t mute {OFF|USRP|TLV|BOTH}\t\t\t Cause Aanlog_Bridge to mute a stream" echo -e "\t message msg\t\t\t\t\t Send a text message to DVSM/UC" echo -e "\t macro {file|text}\t\t\t\t Send a macro collection to DVSM" echo -e "\t pushfile file\t\t\t\t\t Push file to DVSM" echo -e "\t pushurl url\t\t\t\t\t Push URL to DVSM" echo -e "\t collectProcessDataFiles \t\t\t Collect and prepare DVSM data files" echo -e "\t collectProcessPushDataFiles \t\t\t Collect, prepare and upload DVSM data files" echo -e "\t collectProcessPushDataFilesHTTP \t\t Collect, prepare and upload DVSM data files over http" echo -e "\t reloadDatabase \t\t\t\t Tell AB to reload database files into memory" echo -e "\t getEnabledModes \t\t\t\t Return the list of "enabled" modes in MB.ini" echo -e "\t getUDPPortOwner {UDP port}\t\t\t Print out the process owner for the specified port" echo -e "\t getUDPPortsForProcess {process name|ALL}\t Print out the ports owned by the specified process (or all DVSwitch processes)" echo -e "\t updateINIFileValue file section {tag} {value}\t Display or edit a tag in an INI file" echo -e "\t gps lat long \t\t\t\t\t Set GPS coordinates for YSF to lat and long" echo -e "\t setGpsToIP \t\t\t\t\t Set GPS coordinates for YSF to the lat and long of your public IP address" exit 1 } ################################################################# # The main application ################################################################# if [ $# -eq 0 ]; then usage # No arguments, so just report usage information else case $1 in -h|--help|"-?"|help) usage ;; update) downloadDatabases ;; lookup) lookup $2 ;; collectProcessDataFiles|collectprocessdatafiles|cpdf) collectProcessDataFiles ;; version|-v) appVersion $2 ;; getEnabledModes|getenabledmodes|gem) if [ $# -eq 1 ]; then # No argument passed, just return the current value getEnabledModes "Enabled Modes: " else getEnabledModes "$2" fi ;; getUDPPortOwner|getudpportowner|gupo) getUDPPortOwner "$2" ;; getUDPPortsForProcess|getudpportsforprocess|gupfp) if [ -z "$2" ] || [ $2 == "all" ] || [ $2 == "ALL" ]; then getUDPPortsForDVSwitch else for i in "${@:1}"; do getUDPPortsForProcess "$i" done fi ;; updateINIFileValue|updateinifilevalue|uifv) updateINIFileValue "$2" "$3" $4 $5 ${@:6} ;; parseIniFile|parseinifile|pif) parseAnyIniFile "$2" $3 $4 ;; *) # All the commands below require that a valid ABInfo file exists. TLV_PORT=`getTLVPort` # Get the communications port to use before we go further USRP_PORT=`getUSRPPort` # Get the communications port to use before we go further if [ $TLV_PORT == "ERROR" ]; then echo "Can not find /tmp/ABInfo file (have you run Analog_Bridge?), aborting" exit 1 fi case $1 in mode) setMode $2 $3 $4 ;; tune) ${DEBUG} tune $2 ${DEBUG} getInfo ;; ambeSize|ambesize) ${DEBUG} setAmbeSize $2 ;; ambeMode|ambemode) ${DEBUG} setAmbeMode $2 ;; slot) ${DEBUG} setSlot $2 ;; setCallAndId|setcallandid) setCallAndID $2 $3 getInfo ;; tlvAudio|tlvaudio) setTLVAudioType $2 setTLVGain $3 ;; usrpAudio|usrpaudio) setUSRPAudioType $2 setUSRPGain $3 ;; USRPAgc|usrpagc) setUSRPAgc $2 $3 $4 ;; TLVAgc|tlvagc) setTLVAgc $2 $3 $4 ;; usrpCodec|usrpcodec) setUSRPCodec $2 ;; tlvPorts|tlvports) setTLVRxPort $2 setTLVTxPort $3 ;; info) # no arguments fill just tell AB to update the json file # two arguments returns the value of "object" and "name" object{name:value} getInfo $2 $3 ;; show) prettyPrintInfo ;; mute) setMute $2 ;; pushFile|pushfile|pf) pushFileToClient "$2" ;; collectProcessPushDataFiles|collectprocesspushdatafiles|cppdf) collectProcessPushDataFiles ;; pushUrl|pushurl) pushURLToClient "$2" ;; collectProcessPushDataFilesHTTP|collectprocesspushdatafileshttp|cppdfh) collectProcessPushDataFilesHTTP ;; reloadDatabase|reloaddatabase) reloadDatabase ;; message) sendMessage "$2" ;; macro) sendMacro macro "$2" ;; menu) sendMacro menu "$2" ;; ping) setPingTimer "$2" ;; gps) remoteControlCommand "gps=$2,$3" ;; exit) remoteControlCommand "exit=0 0" ;; setGpsToIP) setGpsToIP ;; exitAB|exitab) exitAnalogBridge $2 $3 ;; usrpCommand|usrp) # undocumented ATM/WIP USRPCommand "$2" "$3" ;; *) # unknown option, update branch info (no option is specified, just ordered by placement) echo "Unknown command line option:" $1 usage ;; esac ;; esac fi exit $_ERRORCODE