Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Faraday-APRS Persistent Across Network Failures #271

Merged
merged 28 commits into from
Sep 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
dad1f90
Initial addition of APRS BASE91 Code
kb1lqc Sep 5, 2017
62263c5
ADC0, ADC1, ADC3, ADC6, and BOARDTEMP BASE91
kb1lqc Sep 5, 2017
5ccd19a
Added telemetry sequence to sendPosition
kb1lqc Sep 5, 2017
74212a3
Working telemetry and some hacked in telemetry seq
kb1lqc Sep 5, 2017
eb55358
Per @rossengeorgiev there is a width for BASE91
kb1lqc Sep 5, 2017
d132474
Cleaned up APRS Position Telemetry Code
kb1lqc Sep 5, 2017
0a57a3b
Added IO to position comment data
kb1lqc Sep 7, 2017
7ead5f3
Only send Parameters, Labels, and Equations once
kb1lqc Sep 7, 2017
b82e2fd
Fixed up pytest PEP8 Failures
kb1lqc Sep 8, 2017
161145c
Updated comments for sendPosition() function
kb1lqc Sep 8, 2017
541f10c
Reversed 4095 hardcoded values in sendTelemetry
kb1lqc Sep 8, 2017
e68b408
Just got reconnection working!
kb1lqc Sep 8, 2017
4db85fb
Removed unnecessary comment in sendPositions
kb1lqc Sep 8, 2017
8eafdf5
Simplified packet sending with sendAPRSPacket
kb1lqc Sep 8, 2017
041a922
Removed commented out code and added documentation
kb1lqc Sep 8, 2017
bf2a6f1
Send all packets on 10th loop
kb1lqc Sep 8, 2017
0565340
Implemented sendAPRSPacket() on all packets
kb1lqc Sep 8, 2017
982b169
Updated sendAPRSPacket documenation
kb1lqc Sep 8, 2017
ffe768d
Fixed pytest errors/warnings
kb1lqc Sep 8, 2017
5c47607
Updated parameter names
kb1lqc Sep 8, 2017
83ae953
Fixed reconnection issue on extended network loss
kb1lqc Sep 9, 2017
799b61f
Removed development code/comments
kb1lqc Sep 10, 2017
ac65bd6
Removed extra line under if statement
kb1lqc Sep 10, 2017
b354512
Replaced return status with reture sendAPRSPacket
kb1lqc Sep 10, 2017
a0e6d73
Removed useless break statement after return
kb1lqc Sep 10, 2017
ddcb2ff
Cleaned up commented code and sock initialization
kb1lqc Sep 10, 2017
75d6930
Removed passing of sock variable to threads
kb1lqc Sep 10, 2017
f529c01
Updated reconnect comment and BASE91 comment add
kb1lqc Sep 10, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions etc/faraday/aprs.sample.ini
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ BLABEL7=IO

ADC0PARAM=ADC0
ADC1PARAM=ADC1
ADC2PARAM=ADC2
ADC3PARAM=ADC7
ADC4PARAM=ADC8
ADC2PARAM=ADC3
ADC3PARAM=ADC6
ADC4PARAM=TEMP
IO0PARAM=IO
IO1PARAM=IO
IO2PARAM=IO
Expand All @@ -65,4 +65,4 @@ EQ3B=1
EQ3C=0
EQ4A=0
EQ4B=1
EQ4C=0
EQ4C=0
159 changes: 83 additions & 76 deletions faraday/aprs.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from time import sleep
import sys
import argparse
from aprslib import base91

from classes import helper

Expand Down Expand Up @@ -89,7 +90,7 @@ def configureAPRS(args):
config.write(configfile)


def aprs_worker(config, sock):
def aprs_worker(config):
"""
Obtains telemetry with infinite loop, forwards to APRS-IS server

Expand All @@ -102,6 +103,7 @@ def aprs_worker(config, sock):

# Local variable initialization
telemSequence = 0
conn = False

# Start infinite loop to send station data to APRS-IS
while True:
Expand All @@ -114,11 +116,20 @@ def aprs_worker(config, sock):
logger.info(str.format(len(stations)))

# Iterate through all stations sending telemetry and position data
sendPositions(stationData, sock)
telemSequence = sendtelemetry(stationData, telemSequence, sock)
sendTelemLabels(stationData, sock)
sendParameters(stationData, sock)
sendEquations(stationData, sock)
if not conn:
sock = connectAPRSIS()
try:
conn = sendPositions(telemSequence, stationData, sock)

# Just send labels, Parameters, and Equations every 10th loop
if telemSequence % 10 == 0:
sendTelemLabels(stationData, sock)
sendParameters(stationData, sock)
sendEquations(stationData, sock)
telemSequence += 1

except StandardError as e:
logger.error(e)

# Sleep for intended update rate (seconds)
sleep(rate)
Expand Down Expand Up @@ -231,10 +242,33 @@ def nmeaToDegDecMin(latitude, longitude):
return [latString, lonString]


def sendPositions(stations, socket):
def sendAPRSPacket(socket, packet):
"""
Sends an APRS packet (just a string) to the socket specified. If an
error occurs a False is returned while a True is returned if successful.
On an error, the socket is closed as it is no longer useful.

:param socket: APRS-IS server internet socket
:param packet: String to be sent to APRS-IS
:return: Boolean
"""
Constructs an APRS position string for station and sends to a socket

try:
socket.sendall(packet)
return True

except IOError as e:
logger.error(e)
socket.close()
return False


def sendPositions(telemSequence, stations, socket):
"""
Constructs an APRS position string for station and sends to a socket.
Includes BASE91 comment telemetry functionality as well.

:param telemSequence: Telemetry sequence number
:param stations: List of dictionary organized station data
:param socket: APRS-IS server internet socket
:return: None
Expand Down Expand Up @@ -268,11 +302,37 @@ def sendPositions(stations, socket):
altSymbol = aprsConfig.get('APRS', 'ALTSYMBOL')
comment = aprsConfig.get('APRS', 'COMMENT')
altComment = aprsConfig.get('APRS', 'ALTCOMMENT')
ioSource = aprsConfig.get('APRS', 'IOSOURCE').upper()

# Create nodes from GPS data
node = sourceCallsign + "-" + str(sourceID)
destNode = destinationCallsign + "-" + str(destinationID)

#Obtain GPIO data
gpioValues = station["GPIOSTATE"]
rfValues = station["RFSTATE"]

# Extract IO data
if ioSource == 'GPIO':
ioList = gpioValues
elif ioSource == 'RF':
ioList = rfValues

# Generate BASE91 telemetry with aprslib using a width of 2
b91seq = base91.from_decimal(telemSequence, 2)
b91a = base91.from_decimal(station["ADC0"], 2)
b91b = base91.from_decimal(station["ADC1"], 2)
b91c = base91.from_decimal(station["ADC3"], 2)
b91d = base91.from_decimal(station["ADC6"], 2)
b91e = base91.from_decimal(station["BOARDTEMP"], 2)
b91f = base91.from_decimal(ioList, 2)

b91Tlm = "|{0}{1}{2}{3}{4}{5}{6}|".format(b91seq, b91a, b91b, b91c, b91d, b91e, b91f)

# add telemetry to comments
comment += b91Tlm
altComment += b91Tlm

# Convert position to APRS-IS compliant string
latString, lonString = nmeaToDegDecMin(latitude, longitude)

Expand Down Expand Up @@ -317,11 +377,7 @@ def sendPositions(stations, socket):

logger.debug(positionString)

try:
socket.sendall(positionString)

except IOError as e:
logger.error(e)
return sendAPRSPacket(socket, positionString)

elif node == destNode:
# APRS string is for local node
Expand All @@ -342,12 +398,7 @@ def sendPositions(stations, socket):
altComment)
logger.debug(positionString)

try:
socket.sendall(positionString)

except IOError as e:
logger.error("SendPosition")
logger.error(e)
return sendAPRSPacket(socket, positionString)


def sendtelemetry(stations, telemSequence, socket):
Expand Down Expand Up @@ -403,12 +454,7 @@ def sendtelemetry(stations, telemSequence, socket):

logger.debug(telemetry)

try:
socket.sendall(telemetry)

except IOError as e:
logger.error("SendTelemetry")
logger.error(e)
return sendAPRSPacket(socket, telemetry)

elif node == destNode:
# APRS string is for local node
Expand All @@ -425,12 +471,7 @@ def sendtelemetry(stations, telemSequence, socket):

logger.debug(telemetry)

try:
socket.sendall(telemetry)

except IOError as e:
logger.error("Sendtelemetry")
logger.error(e)
return sendAPRSPacket(socket, telemetry)

# Check for telemetry sequence rollover
if telemSequence >= 999:
Expand Down Expand Up @@ -493,25 +534,14 @@ def sendTelemLabels(stations, socket):
node, destAddress, qConstruct, destNode, node, unitsAndLabels)
logger.debug(labels)

try:
socket.sendall(labels)

except IOError as e:
logger.error("SendTelemLabels")
logger.error(e)
return sendAPRSPacket(socket, labels)

elif node == destNode:
# APRS string is for local node
labels = '{}>{}::{} :UNIT.{}\r'.format(
node, destAddress, node, unitsAndLabels)

logger.debug(labels)
try:
socket.sendall(labels)

except IOError as e:
logger.error("SendTelemLabels")
logger.error(e)
return sendAPRSPacket(socket, labels)


def sendParameters(stations, socket):
Expand Down Expand Up @@ -564,26 +594,14 @@ def sendParameters(stations, socket):
parameters = '{}>{},{},{}::{} :PARM.{}\r'.format(
node, destAddress, qConstruct, destNode, node, adcAndIoParams)

logger.debug(parameters)
try:
socket.sendall(parameters)

except IOError as e:
logger.error("SendParameters")
logger.error(e)
return sendAPRSPacket(socket, parameters)

elif node == destNode:
# APRS string is for local node
parameters = '{}>{}::{} :PARM.{}\r'.format(
node, destAddress, node, adcAndIoParams)

logger.debug(parameters)
try:
socket.sendall(parameters)

except IOError as e:
logger.error("SendParameters")
logger.error(e)
return sendAPRSPacket(socket, parameters)


def sendEquations(stations, socket):
Expand Down Expand Up @@ -636,26 +654,14 @@ def sendEquations(stations, socket):
equations = '{}>{},{},{}::{} :EQNS.{}\r'.format(
node, destAddress, qConstruct, destNode, node, equationConfig)

logger.debug(equations)
try:
socket.sendall(equations)

except IOError as e:
logger.error("SendEquations")
logger.error(e)
return sendAPRSPacket(socket, equations)

elif node == destNode:
# APRS string is for local node
equations = '{}>{}::{} :EQNS.{}\r'.format(
node, destAddress, node, equationConfig)

logger.debug(equations)
try:
socket.sendall(equations)

except IOError as e:
logger.error("SendEquations")
logger.error(e)
return sendAPRSPacket(socket, equations)


def connectAPRSIS():
Expand Down Expand Up @@ -693,14 +699,16 @@ def connectAPRSIS():
aprssock.sendall(logon_string)

except IOError as e:
# Close socket and setup for next connection attempt
logger.error(e)
aprssock.close()
aprssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

else:
logger.info("Connection successful!")
return aprssock
break

sleep(10) # Try to reconnect every 10 seconds
sleep(2) # Try to reconnect every 2 seconds
return aprssock
else:
while True:
Expand Down Expand Up @@ -762,12 +770,11 @@ def main():
"""

logger.info('Starting Faraday APRS-IS application')
sock = connectAPRSIS()

# Initialize local variables
threads = []

t = threading.Thread(target=aprs_worker, args=(aprsConfig, sock))
t = threading.Thread(target=aprs_worker, args=(aprsConfig,))
threads.append(t)
t.start()

Expand Down