#!/bin/bash ################################################################################## # Background process started by the initializing script start_aprs_server.sh # # # # It processes all incomming messages for PE1RXF and sends acknowledges when # # if asked for (via kissutil for ax0 and beacon for ax1. It also prosesses the # # special telemetry messages from PE1RXF devices. # # # # (C)2021 M.T. Konstapel https://meezenest.nl/mees # # # # This file is part of PE1RXF-APRS-server. # # # # PE1RXF-APRS-server is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # PE1RXF-APRS-server is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with PE1RXF-APRS-server If not, see . # # # ################################################################################## # Filters out all APRS messages to PE1RXF (all suffixes) and saves these to file. # Generate and send acknowledge message when incomming message ask for it (only for -1, -2 and -3 suffixes). # Also, reads APRS message and when it is telemetry converts it to a format readeble by gnuplot # # The script aprs_utils.sh starts a filters means of tail | grep on the log file of aprx. # The output of this command goes to this script via stdin. This script reads this line by line # and sends an acknowledgement to the stations asking for one. This is done via kissutil, which # is also started the script aprs_utils.sh # Directory where kissutils expect files to send APRS_SEND_MESSAGE_DIRECTORY=/home/marcel/ham/aprs_utils/aprs_files_to_transmit/ # Directory where APRS messages are stored APRS_RECEIVED_MESSAGES_DIR=/home/marcel/ham/aprs_utils/aprs_log/ MESSAGE_FILE=aprs_received_messages.log # Get current date YYYY-MM-DD #CURRENT_DATE=$(date +"%Y-%m-%d") #Read file line by line and send acknowledge if needed while read LINE do ################# # Section: filter out APRS messages and generate acknowledge if needed ################# # Get current date YYYY-MM-DD (do this every time, because a day may already have passed) CURRENT_DATE=$(date +"%Y-%m-%d") CURRENT_DATE_TIME=$(date +"%Y-%m-%d %H:%M:%S") # figure out who sent the message # Check channel 1 (internal radio) #CALL="$(grep -o -P "(?<=PE1RXF-1 R \*).+?\>"<<<$LINE)" CALL="$(grep -oP "(?<=PE1RXF-1 R ).+?\>"<<<$LINE)" PORT="ax0" # If call is empty, frame not from channel 1, maybe from channel 2? if [ -z $CALL ]; then #CALL="$(grep -o -P "(?<=PE1RXF-2 R \*).+?\>"<<<$LINE)" CALL="$(grep -oP "(?<=PE1RXF-2 R ).+?\>"<<<$LINE)" PORT="ax1" fi # If call is empty, frame not from channel 1 or 2, maybe from channel 3? if [ -z $CALL ]; then #CALL="$(grep -o -P "(?<=PE1RXF-2 R \*).+?\>"<<<$LINE)" CALL="$(grep -oP "(?<=PE1RXF-3 R ).+?\>"<<<$LINE)" PORT="ax2" fi # If call is empty, frame not from channel 1, 2 or 3, maybe from channel APRSIS? if [ -z $CALL ]; then #CALL="$(grep -o -P "(?<=PE1RXF-2 R \*).+?\>"<<<$LINE)" CALL="$(grep -oP "(?<=APRSIS R ).+?\>"<<<$LINE)" PORT="aprsis" fi # Lets do something with the message from channel 1 or 2 if [[ $CALL ]]; then # Remove last character from string CALL=${CALL::-1} ACKNOWLEDGE_NUMBER="$(grep -o -P '(?<={).*'<<<$LINE)" #Write messages to file with name "YYYY-MM-DD_messages_from_NOCALL.log (append) #echo "$LINE" >> "$APRS_RECEIVED_MESSAGES_DIR""$CURRENT_DATE""_messages_from_""$CALL"".log" # Get full path of message if [ $PORT == "ax0" ]; then #FULL_PATH="$(grep -o -P '(?<=PE1RXF-1 R \*).+?:'<<<$LINE)" FULL_PATH="$(grep -oP "(?<=PE1RXF-1 R ).+?:"<<<$LINE)" elif [ $PORT == "ax1" ]; then #FULL_PATH="$(grep -o -P '(?<=PE1RXF-2 R \*).+?:'<<<$LINE)" FULL_PATH="$(grep -oP "(?<=PE1RXF-2 R ).+?:"<<<$LINE)" elif [ $PORT == "ax2" ]; then #FULL_PATH="$(grep -o -P '(?<=PE1RXF-2 R \*).+?:'<<<$LINE)" FULL_PATH="$(grep -oP "(?<=PE1RXF-3 R ).+?:"<<<$LINE)" elif [ $PORT == "aprsis" ]; then #FULL_PATH="$(grep -o -P '(?<=PE1RXF-2 R \*).+?:'<<<$LINE)" FULL_PATH="$(grep -oP "(?<=APRSIS R ).+?:"<<<$LINE)" fi FULL_PATH="$(grep -o -P '(?<=\>).*'<<<$FULL_PATH)" # Remove last character from string FULL_PATH=${FULL_PATH::-1} # Messages direct from sender do not contain a '*' in the path DIRECT="$(grep '*' <<<$FULL_PATH)" if [ -z $DIRECT ]; then DIRECT="true" else unset DIRECT fi # First call in path is destination DESTINATION="$(awk -F "," '{ print $1} ' <<<$FULL_PATH)" # get the message MESSAGE="$(grep -o -P '(?<=::).*'<<<$LINE)" MESSAGE="$(grep -o -P '(?<=:).*'<<<$MESSAGE)" # get the receipient of the message RECEIPIENT="$(grep -o -P '(?<=::).+?:'<<<$LINE)" RECEIPIENT=${RECEIPIENT::-1} # Write message to file echo "$CURRENT_DATE_TIME"",""$PORT"",""$CALL"",""$DESTINATION",\"$MESSAGE\" >> "$APRS_RECEIVED_MESSAGES_DIR""$MESSAGE_FILE" #Send incomming message as email #echo "$LINE" | /home/marcel/ham/aprs_utils/send_aprs_message_to_email.sh #Generate acknowledge frame and put in in de directory where kissutil can find (ax0) it or (for channels ax1 and ax2) send it via beacon if [[ $RECEIPIENT == "PE1RXF-1 " || $RECEIPIENT == "PE1RXF-2 " || $RECEIPIENT == "PE1RXF-3 " ]]; then if [[ $ACKNOWLEDGE_NUMBER ]]; then # if call is less than 9 characters, add spaces at the end (according to the APRS protocol) printf -v FORMATTED_CALL %-9.9s "$CALL" OWN_CALL="$(grep "PE1RXF"<<<$CALL)" # Message on port ax0 if [ $PORT == "ax0" ]; then # Local (own) stations do not need to be digipeated if [ $OWN_CALL ]; then APRS_FRAME="PE1RXF-1>APRX29::$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" # Everyone else is digipeated else APRS_FRAME="PE1RXF-1>APRX29,WIDE2-2::$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" fi # Send acknowledge frame APRS_TRANSMIT_FILE="acknowledge_""$FORMATTED_CALL""_message_""$ACKNOWLEDGE_NUMBER" echo "$APRS_FRAME" > "$APRS_SEND_MESSAGE_DIRECTORY$APRS_TRANSMIT_FILE" # Message on port ax1 elif [ $PORT == "ax1" ]; then # Local (own) stations do not need to be digipeated if [ $OWN_CALL ]; then APRS_HEADER="APRX29" APRS_FRAME="::$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" args[0]=-d args[1]="APRX29" args[2]=-s args[3]=ax1 args[4]=":$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" # Everyone else is digipeated else APRS_HEADER="APRX29 WIDE2-2" APRS_FRAME="::$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" args[0]=-d args[1]="APRX29 WIDE2-2" args[2]=-s args[3]=ax1 args[4]=":$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" fi # use beacon to send acknowledge frame #echo "/usr/sbin/beacon -d '$APRS_HEADER' -s ax1 '$APRS_FRAME'" #/usr/sbin/beacon -d "$APRS_HEADER" -s ax1 "$APRS_FRAME" /usr/sbin/beacon "${args[@]}" # Message on port ax2 elif [ $PORT == "ax2" ]; then # Local (own) stations do not need to be digipeated if [ $OWN_CALL ]; then APRS_HEADER="APRX29" APRS_FRAME="::$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" args[0]=-d args[1]="APRX29" args[2]=-s args[3]=ax2 args[4]=":$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" # Everyone else is digipeated else APRS_HEADER="APRX29 WIDE2-2" APRS_FRAME="::$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" args[0]=-d args[1]="APRX29 WIDE2-2" args[2]=-s args[3]=ax2 args[4]=":$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" fi # use beacon to send acknowledge frame #echo "/usr/sbin/beacon -d '$APRS_HEADER' -s ax1 '$APRS_FRAME'" #/usr/sbin/beacon -d "$APRS_HEADER" -s ax1 "$APRS_FRAME" /usr/sbin/beacon "${args[@]}" # Message on port aprsis, send ack on LoRa as this channel has the most iGATEs elif [ $PORT == "aprsis" ]; then # Local (own) stations do not need to be digipeated if [ $OWN_CALL ]; then APRS_HEADER="APRX29" APRS_FRAME="::$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" args[0]=-d args[1]="APRX29" args[2]=-s args[3]=ax2 args[4]=":$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" # Everyone else is digipeated else APRS_HEADER="APRX29 WIDE2-2" APRS_FRAME="::$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" args[0]=-d args[1]="APRX29 WIDE2-2" args[2]=-s args[3]=ax2 args[4]=":$FORMATTED_CALL:ack$ACKNOWLEDGE_NUMBER" fi # use beacon to send acknowledge frame #echo "/usr/sbin/beacon -d '$APRS_HEADER' -s ax1 '$APRS_FRAME'" #/usr/sbin/beacon -d "$APRS_HEADER" -s ax1 "$APRS_FRAME" /usr/sbin/beacon "${args[@]}" fi fi fi ################# # Section: process APRS telemetry to format readable by gnuplot ################# # get date field DATE="$(echo $LINE | cut -b 1-10)" # get time field TIME="$(echo $LINE | cut -b 12-16)" # get telemetry fields and remove empty spaces and optional acknowledge message if it is present #TELEMETRY="$(echo $LINE | cut -b 64- | sed 's/{.*//' | tr -d "[:blank:]")" TELEMETRY="$(echo $LINE | cut -b 63- | sed 's/{.*//' | tr -d "[:blank:]")" echo $LINE echo $TELEMETRY #Datafiled should have comma as field seperator, so asume this and put values in array for later testing if data is valid IFS=',' read -r -a array <<< "$TELEMETRY" # Test if message contains valid numbers. It could be an acknowledge or beacon etc. TELEMETRY_ERROR=0 for index in "${!array[@]}" do if ! [[ ${array[index]} =~ ^-?[0-9]+([.][0-9]+)?$ ]] ; then TELEMETRY_ERROR=1 fi done # If telemetry message is valid, store it (change APRS date/time (UTM) with local time) if [ $TELEMETRY_ERROR -eq 0 ] ; then # Get current date and time YYYY-MM-DD %H:%M for local time stamp (do this every time, because a day may already have passed) LOCAL_DATE_TIME=$(date +"%Y-%m-%d %H:%M") #Format line by combining all needed fields DATA_STRING="$(echo "$LOCAL_DATE_TIME","$TELEMETRY")" #| tr -d "[:blank:]")" #Write messages to file with name "YYYY-MM-DD_telemetry_NOCALL.log (append) echo "$DATA_STRING" >> "$APRS_RECEIVED_MESSAGES_DIR""$CURRENT_DATE""_telemetry_""$CALL"".dat" #Write last telemetry message to file (overwrite) for current values echo "$TELEMETRY" > "$APRS_RECEIVED_MESSAGES_DIR""latest_telemetry_""$CALL"".dat" fi fi # end channel 1 done < /dev/stdin