From 92e1b898ed32e07cd7e247d534833710539142e6 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 18 Aug 2018 21:12:20 -0400 Subject: [PATCH 01/10] Convert to only use bytestrings, and a debug flag --- adafruit_gps.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/adafruit_gps.py b/adafruit_gps.py index 66d0eee..04aba58 100644 --- a/adafruit_gps.py +++ b/adafruit_gps.py @@ -76,7 +76,7 @@ class GPS: """GPS parsing module. Can parse simple NMEA data sentences from serial GPS modules to read latitude, longitude, and more. """ - def __init__(self, uart): + def __init__(self, uart, debug=False): self._uart = uart # Initialize null starting values for GPS attributes. self.timestamp_utc = None @@ -90,6 +90,7 @@ def __init__(self, uart): self.velocity_knots = None self.speed_knots = None self.track_angle_deg = None + self.debug = debug def update(self): """Check for updated data from the GPS module and process it @@ -101,11 +102,13 @@ def update(self): sentence = self._parse_sentence() if sentence is None: return False + if self.debug: + print(sentence) data_type, args = sentence - data_type = data_type.upper() - if data_type == 'GPGGA': # GGA, 3d location fix + data_type = data_type.upper().encode() + if data_type == b'GPGGA': # GGA, 3d location fix self._parse_gpgga(args) - elif data_type == 'GPRMC': # RMC, minimum location info + elif data_type == b'GPRMC': # RMC, minimum location info self._parse_gprmc(args) return True @@ -115,15 +118,15 @@ def send_command(self, command, add_checksum=True): Note you should NOT add the leading $ and trailing * to the command as they will automatically be added! """ - self._uart.write('$') + self._uart.write(b'$') self._uart.write(command) if add_checksum: checksum = 0 for char in command: - checksum ^= ord(char) - self._uart.write('*') - self._uart.write('{:02x}'.format(checksum).upper()) - self._uart.write('\r\n') + checksum ^= char + self._uart.write(b'*') + self._uart.write('{:02x}'.format(checksum).upper().encode()) + self._uart.write(b'\r\n') @property def has_fix(self): From a53559b5b9e7ce9aba26debc5dec7de485d8270b Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 18 Aug 2018 21:13:34 -0400 Subject: [PATCH 02/10] add echo test (no fix needed) --- examples/gps_echotest.py | 66 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 examples/gps_echotest.py diff --git a/examples/gps_echotest.py b/examples/gps_echotest.py new file mode 100644 index 0000000..9d4af69 --- /dev/null +++ b/examples/gps_echotest.py @@ -0,0 +1,66 @@ +# Simple GPS module demonstration. +# Will print NMEA sentences received from the GPS, great for testing connection +# Uses the GPS only to send some commands, then reads directly from UART +import time +import board +import busio + +import adafruit_gps + + +# Define RX and TX pins for the board's serial port connected to the GPS. +# These are the defaults you should use for the GPS FeatherWing. +# For other boards set RX = GPS module TX, and TX = GPS module RX pins. +#RX = board.RX +#TX = board.TX + +# Create a serial connection for the GPS connection using default speed and +# a slightly higher timeout (GPS modules typically update once a second). +uart = busio.UART(TX, RX, baudrate=9600, timeout=3000) + +# for a computer, use the pyserial library for uart access +#import serial +#uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=3000) + +# Create a GPS module instance. +gps = adafruit_gps.GPS(uart) + +# Initialize the GPS module by changing what data it sends and at what rate. +# These are NMEA extensions for PMTK_314_SET_NMEA_OUTPUT and +# PMTK_220_SET_NMEA_UPDATERATE but you can send anything from here to adjust +# the GPS module behavior: +# https://cdn-shop.adafruit.com/datasheets/PMTK_A11.pdf + +# Turn on the basic GGA and RMC info (what you typically want) +gps.send_command(b'PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0') +# Turn on just minimum info (RMC only, location): +#gps.send_command(b'PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0') +# Turn off everything: +#gps.send_command(b'PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0') +# Tuen on everything (not all of it is parsed!) +#gps.send_command(b'PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0') + +# Set update rate to once a second (1hz) which is what you typically want. +gps.send_command(b'PMTK220,1000') +# Or decrease to once every two seconds by doubling the millisecond value. +# Be sure to also increase your UART timeout above! +#gps.send_command(b'PMTK220,2000') +# You can also speed up the rate, but don't go too fast or else you can lose +# data during parsing. This would be twice a second (2hz, 500ms delay): +#gps.send_command(b'PMTK220,500') + +# Main loop runs forever printing data as it comes in +timestamp = time.monotonic() +while True: + data = uart.read(32) # read up to 32 bytes + # print(data) # this is a bytearray type + + if data is not None: + # convert bytearray to string + data_string = ''.join([chr(b) for b in data]) + print(data_string, end="") + + if time.monotonic() - timestamp > 5: + # every 5 seconds... + gps.send_command(b'PMTK605') # request firmware version + timestamp = time.monotonic() From 72abd3d132ad47bd25599aa2c85c4801cca5f64b Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 18 Aug 2018 21:14:29 -0400 Subject: [PATCH 03/10] reasonable formatting on lat/long, convert all strings to bytes, add pyserial example --- examples/gps_simpletest.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/examples/gps_simpletest.py b/examples/gps_simpletest.py index 27b742f..e10bb23 100644 --- a/examples/gps_simpletest.py +++ b/examples/gps_simpletest.py @@ -18,8 +18,12 @@ # a slightly higher timeout (GPS modules typically update once a second). uart = busio.UART(TX, RX, baudrate=9600, timeout=3000) +# for a computer, use the pyserial library for uart access +#import serial +#uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=3000) + # Create a GPS module instance. -gps = adafruit_gps.GPS(uart) +gps = adafruit_gps.GPS(uart, debug=False) # Initialize the GPS module by changing what data it sends and at what rate. # These are NMEA extensions for PMTK_314_SET_NMEA_OUTPUT and @@ -28,22 +32,22 @@ # https://cdn-shop.adafruit.com/datasheets/PMTK_A11.pdf # Turn on the basic GGA and RMC info (what you typically want) -gps.send_command('PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0') +gps.send_command(b'PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0') # Turn on just minimum info (RMC only, location): -#gps.send_command('PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0') +#gps.send_command(b'PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0') # Turn off everything: -#gps.send_command('PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0') +#gps.send_command(b'PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0') # Tuen on everything (not all of it is parsed!) -#gps.send_command('PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0') +#gps.send_command(b'PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0') # Set update rate to once a second (1hz) which is what you typically want. -gps.send_command('PMTK220,1000') +gps.send_command(b'PMTK220,1000') # Or decrease to once every two seconds by doubling the millisecond value. # Be sure to also increase your UART timeout above! -#gps.send_command('PMTK220,2000') +#gps.send_command(b'PMTK220,2000') # You can also speed up the rate, but don't go too fast or else you can lose # data during parsing. This would be twice a second (2hz, 500ms delay): -#gps.send_command('PMTK220,500') +#gps.send_command(b'PMTK220,500') # Main loop runs forever printing the location, etc. every second. last_print = time.monotonic() @@ -71,8 +75,8 @@ gps.timestamp_utc.tm_hour, # not get all data like year, day, gps.timestamp_utc.tm_min, # month! gps.timestamp_utc.tm_sec)) - print('Latitude: {} degrees'.format(gps.latitude)) - print('Longitude: {} degrees'.format(gps.longitude)) + print('Latitude: {0:.6f} degrees'.format(gps.latitude)) + print('Longitude: {0:.6f} degrees'.format(gps.longitude)) print('Fix quality: {}'.format(gps.fix_quality)) # Some attributes beyond latitude, longitude and timestamp are optional # and might not be present. Check if they're None before trying to use! From ee5c4038285597249b8422f6886bf3c5f731c6ee Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 18 Aug 2018 21:19:22 -0400 Subject: [PATCH 04/10] the feather examples is pretty involved, its easier to just make a new example for computer/linux logging --- examples/computer_datalogging.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 examples/computer_datalogging.py diff --git a/examples/computer_datalogging.py b/examples/computer_datalogging.py new file mode 100644 index 0000000..853c561 --- /dev/null +++ b/examples/computer_datalogging.py @@ -0,0 +1,31 @@ +# Simple GPS datalogging demonstration for use with a computer like Linux/desktop. +# This actually doesn't even use the GPS library and instead just reads raw +# NMEA sentences from the GPS unit and dumps them to a file. + +import board +import busio +import serial # pyserial is required + +# Path to the file to log GPS data. By default this will be appended to +# which means new lines are added at the end and all old data is kept. +# Change this path to point at the filename desired +LOG_FILE = 'gps.txt' # Example for writing to local file gps.txt + +# File more for opening the log file. Mode 'ab' means append or add new lines +# to the end of the file rather than erasing it and starting over. If you'd +# like to erase the file and start clean each time use the value 'wb' instead. +LOG_MODE = 'ab' + +# Create a serial connection for the GPS connection using default speed and +# a slightly higher timeout (GPS modules typically update once a second). +# Update the serial port name to match the serial connection for the GPS! +uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=3000) + +# Main loop just reads data from the GPS module and writes it back out to +# the output file while also printing to serial output. +with open(LOG_FILE, LOG_MODE) as outfile: + while True: + sentence = uart.readline() + print(str(sentence, 'ascii').strip()) + outfile.write(sentence) + outfile.flush() From de1888a20cf21ff8336b1479a3378eebbb470ab6 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 18 Aug 2018 21:21:11 -0400 Subject: [PATCH 05/10] pyserial required on computers! --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8b13789..f6c1a1f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ - +pyserial From 78c06fc04718c6453323c33794a8165d3e89baac Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 18 Aug 2018 23:42:06 -0400 Subject: [PATCH 06/10] encoding str works in both Cpython and circuitpython. fixed echotest --- adafruit_gps.py | 2 +- examples/gps_echotest.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/adafruit_gps.py b/adafruit_gps.py index 04aba58..7739f3d 100644 --- a/adafruit_gps.py +++ b/adafruit_gps.py @@ -125,7 +125,7 @@ def send_command(self, command, add_checksum=True): for char in command: checksum ^= char self._uart.write(b'*') - self._uart.write('{:02x}'.format(checksum).upper().encode()) + self._uart.write(bytes('{:02x}'.format(checksum).upper(),"utf-8")) self._uart.write(b'\r\n') @property diff --git a/examples/gps_echotest.py b/examples/gps_echotest.py index 9d4af69..21f7ee3 100644 --- a/examples/gps_echotest.py +++ b/examples/gps_echotest.py @@ -11,8 +11,8 @@ # Define RX and TX pins for the board's serial port connected to the GPS. # These are the defaults you should use for the GPS FeatherWing. # For other boards set RX = GPS module TX, and TX = GPS module RX pins. -#RX = board.RX -#TX = board.TX +RX = board.RX +TX = board.TX # Create a serial connection for the GPS connection using default speed and # a slightly higher timeout (GPS modules typically update once a second). From 1a385205b8c605023a0ad4a786c3a710561428c5 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 18 Aug 2018 23:44:00 -0400 Subject: [PATCH 07/10] other encode --- adafruit_gps.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_gps.py b/adafruit_gps.py index 7739f3d..cf48ee0 100644 --- a/adafruit_gps.py +++ b/adafruit_gps.py @@ -105,7 +105,7 @@ def update(self): if self.debug: print(sentence) data_type, args = sentence - data_type = data_type.upper().encode() + data_type = bytes(data_type.upper(), "utf-8") if data_type == b'GPGGA': # GGA, 3d location fix self._parse_gpgga(args) elif data_type == b'GPRMC': # RMC, minimum location info @@ -125,7 +125,7 @@ def send_command(self, command, add_checksum=True): for char in command: checksum ^= char self._uart.write(b'*') - self._uart.write(bytes('{:02x}'.format(checksum).upper(),"utf-8")) + self._uart.write(bytes('{:02x}'.format(checksum).upper(), "utf-8")) self._uart.write(b'\r\n') @property From c62b31bc8235e4af82f07090ee25a60bfa1530ab Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 18 Aug 2018 23:51:01 -0400 Subject: [PATCH 08/10] pylint fixes --- examples/computer_datalogging.py | 2 -- examples/gps_echotest.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/computer_datalogging.py b/examples/computer_datalogging.py index 853c561..0e32132 100644 --- a/examples/computer_datalogging.py +++ b/examples/computer_datalogging.py @@ -2,8 +2,6 @@ # This actually doesn't even use the GPS library and instead just reads raw # NMEA sentences from the GPS unit and dumps them to a file. -import board -import busio import serial # pyserial is required # Path to the file to log GPS data. By default this will be appended to diff --git a/examples/gps_echotest.py b/examples/gps_echotest.py index 21f7ee3..450e6e7 100644 --- a/examples/gps_echotest.py +++ b/examples/gps_echotest.py @@ -54,7 +54,7 @@ while True: data = uart.read(32) # read up to 32 bytes # print(data) # this is a bytearray type - + if data is not None: # convert bytearray to string data_string = ''.join([chr(b) for b in data]) From 2754d0e4e03d94559f5bbc470e32cb2928bd81d2 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 19 Aug 2018 16:05:24 -0400 Subject: [PATCH 09/10] change encoding to "ascii" --- adafruit_gps.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_gps.py b/adafruit_gps.py index cf48ee0..07e3b6b 100644 --- a/adafruit_gps.py +++ b/adafruit_gps.py @@ -105,7 +105,7 @@ def update(self): if self.debug: print(sentence) data_type, args = sentence - data_type = bytes(data_type.upper(), "utf-8") + data_type = bytes(data_type.upper(), "ascii") if data_type == b'GPGGA': # GGA, 3d location fix self._parse_gpgga(args) elif data_type == b'GPRMC': # RMC, minimum location info @@ -125,7 +125,7 @@ def send_command(self, command, add_checksum=True): for char in command: checksum ^= char self._uart.write(b'*') - self._uart.write(bytes('{:02x}'.format(checksum).upper(), "utf-8")) + self._uart.write(bytes('{:02x}'.format(checksum).upper(), "ascii)) self._uart.write(b'\r\n') @property From 567f65c96cec0002ddb6ced143edaeeaaa387e06 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 19 Aug 2018 16:07:27 -0400 Subject: [PATCH 10/10] that was a test to see if travis would catch it ;) --- adafruit_gps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_gps.py b/adafruit_gps.py index 07e3b6b..640aea9 100644 --- a/adafruit_gps.py +++ b/adafruit_gps.py @@ -125,7 +125,7 @@ def send_command(self, command, add_checksum=True): for char in command: checksum ^= char self._uart.write(b'*') - self._uart.write(bytes('{:02x}'.format(checksum).upper(), "ascii)) + self._uart.write(bytes('{:02x}'.format(checksum).upper(), "ascii")) self._uart.write(b'\r\n') @property