py-wsjtx/samples/grid_from_gps.py

147 wiersze
5.1 KiB
Python

# using standard NMEA sentences
import os
import sys
import threading
from datetime import datetime
import serial
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import pywsjtx
import pywsjtx.extra.simple_server
import pywsjtx.extra.latlong_to_grid_square
class NMEALocation(object):
# parse the NMEA message for location into a grid square
def __init__(self, grid_changed_callback = None):
self.valid = False
self.grid = ""
self.last_fix_at = None
self.grid_changed_callback = grid_changed_callback
def handle_serial(self,text):
# should be a single line.
if text.startswith('$GPGLL'):
print('nmea sentence: ', text)
grid = pywsjtx.extra.latlong_to_grid_square.LatLongToGridSquare.GPGLL_to_grid(text)
if grid != "":
self.valid = True
self.last_fix_at = datetime.utcnow()
else:
self.valid = False
if self.grid != grid:
print("NMEA = grid mismatch old: {} new: {}".format(self.grid,grid))
self.grid = grid
if (self.grid_changed_callback):
c_thr = threading.Thread(target=self.grid_changed_callback, args=(grid,), kwargs={})
c_thr.start()
class SerialGPS(object):
def __init__(self):
# TODO arbitrate access to line_handlers[]
self.line_handlers = []
self.comm_thread = None
self.comm_device = None
self.stop_signalled = False
pass
def add_handler(self, line_handler):
if (not (line_handler is None)) and (not (line_handler in self.line_handlers)):
self.line_handlers.append(line_handler)
def open(self, comport, baud, line_handler, **serial_kwargs):
if self.comm_device is not None:
self.close()
self.stop_signalled = False
self.comm_device = serial.Serial(comport, baud, **serial_kwargs)
if self.comm_device is not None:
self.add_handler(line_handler)
self.comm_thread = threading.Thread(target=self.serial_worker, args=())
self.comm_thread.start()
def close(self):
self.stop_signalled = True
self.comm_thread.join()
self.comm_device.close()
self.line_handlers = []
self.comm_device = None
self.stop_signalled = False
def remove_handler(self, line_handler):
self.line_handlers.remove(line_handler)
def serial_worker(self):
while (True):
if self.stop_signalled:
return # terminate
line = self.comm_device.readline()
# dispatch the line
if line.startswith(b'$'):
str_line = line.decode("utf-8")
for p in self.line_handlers:
p(str_line)
@classmethod
def example_line_handler(cls, text):
print('serial: ',text)
# set up the serial_gps to run
# get location data from the GPS, update the grid
# get the grid out of the status message from the WSJT-X instance
# if we have a grid, and it's not the same as GPS, then make it the same by sending the message.
# But only do that if triggered by a status message.
# rinse and repeat -- wait for a status message. Once we have a status message, see if
wsjtx_id = None
nmea_p = None
gps_grid = ""
def example_callback(new_grid):
global gps_grid
print("New Grid! {}".format(new_grid))
# this sets the
gps_grid = new_grid
sgps = SerialGPS()
s = pywsjtx.extra.simple_server.SimpleServer()
print("Starting wsjt-x message server")
while True:
(pkt, addr_port) = s.rx_packet()
if (pkt != None):
the_packet = pywsjtx.WSJTXPacketClassFactory.from_udp_packet(addr_port, pkt)
if wsjtx_id is None and (type(the_packet) == pywsjtx.HeartBeatPacket):
# we have an instance of WSJTX
print("wsjtx detected, id is {}".format(the_packet.wsjtx_id))
print("starting gps monitoring")
wsjtx_id = the_packet.wsjtx_id
# start up the GPS reader
nmea_p = NMEALocation(example_callback)
sgps.open('COM8', 9600, nmea_p.handle_serial, timeout=1.0)
if type(the_packet) == pywsjtx.StatusPacket:
if gps_grid != "" and the_packet.de_grid != gps_grid:
print("Sending Grid Change to wsjtx-x, old grid:{} new grid: {}".format(the_packet.de_grid, gps_grid))
grid_change_packet = pywsjtx.LocationChangePacket.Builder(wsjtx_id, "GRID:"+gps_grid)
print(pywsjtx.PacketUtil.hexdump(grid_change_packet))
s.send_packet(the_packet.addr_port, grid_change_packet)
# for fun, change the TX5 message to our grid square, so we don't have to call CQ again
# this only works if the length of the free text message is less than 13 characters.
# if len(the_packet.de_call <= 5):
# free_text_packet = pywsjtx.FreeTextPacket.Builder(wsjtx_id,"73 {} {}".format(the_packet.de_call, the_packet[0:4]),False)
# s.send_packet(addr_port, free_text_packet)
print(the_packet)