2929import time
3030from micropython import const
3131
32+ try :
33+ from typing import Optional , Tuple , List
34+ from typing_extensions import Literal
35+ from circuitpython_typing import ReadableBuffer
36+ from busio import UART , I2C
37+ except ImportError :
38+ pass
39+
3240__version__ = "0.0.0+auto.0"
3341__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_GPS.git"
3442
7583# Internal helper parsing functions.
7684# These handle input that might be none or null and return none instead of
7785# throwing errors.
78- def _parse_degrees (nmea_data ) :
86+ def _parse_degrees (nmea_data : str ) -> int :
7987 # Parse a NMEA lat/long data pair 'dddmm.mmmm' into a pure degrees value.
8088 # Where ddd is the degrees, mm.mmmm is the minutes.
8189 if nmea_data is None or len (nmea_data ) < 3 :
@@ -88,52 +96,52 @@ def _parse_degrees(nmea_data):
8896 minutes = int (raw [0 ]) % 100 # the mm.
8997 minutes += int (f"{ raw [1 ][:4 ]:0<4} " ) / 10000
9098 minutes = int (minutes / 60 * 1000000 )
91- return degrees + minutes # return parsed string in the format dddmmmmmm
99+ return degrees + minutes
92100
93101
94- def _parse_int (nmea_data ) :
102+ def _parse_int (nmea_data : str ) -> int :
95103 if nmea_data is None or nmea_data == "" :
96104 return None
97105 return int (nmea_data )
98106
99107
100- def _parse_float (nmea_data ) :
108+ def _parse_float (nmea_data : str ) -> float :
101109 if nmea_data is None or nmea_data == "" :
102110 return None
103111 return float (nmea_data )
104112
105113
106- def _parse_str (nmea_data ) :
114+ def _parse_str (nmea_data : str ) -> str :
107115 if nmea_data is None or nmea_data == "" :
108116 return None
109117 return str (nmea_data )
110118
111119
112- def _read_degrees (data , index , neg ) :
120+ def _read_degrees (data : List [ float ] , index : int , neg : str ) -> float :
113121 # This function loses precision with float32
114122 x = data [index ] / 1000000
115123 if data [index + 1 ].lower () == neg :
116124 x *= - 1.0
117125 return x
118126
119127
120- def _read_int_degrees (data , index , neg ) :
128+ def _read_int_degrees (data : List [ float ] , index : int , neg : str ) -> Tuple [ int , float ] :
121129 deg = data [index ] // 1000000
122130 minutes = data [index ] % 1000000 / 10000
123131 if data [index + 1 ].lower () == neg :
124132 deg *= - 1
125133 return (deg , minutes )
126134
127135
128- def _parse_talker (data_type ) :
136+ def _parse_talker (data_type : bytes ) -> Tuple [ bytes , bytes ] :
129137 # Split the data_type into talker and sentence_type
130138 if data_type [:1 ] == b"P" : # Proprietary codes
131139 return (data_type [:1 ], data_type [1 :])
132140
133141 return (data_type [:2 ], data_type [2 :])
134142
135143
136- def _parse_data (sentence_type , data ) :
144+ def _parse_data (sentence_type : int , data : List [ str ]) -> Optional [ List ] :
137145 """Parse sentence data for the specified sentence type and
138146 return a list of parameters in the correct format, or return None.
139147 """
@@ -217,7 +225,7 @@ class GPS:
217225 GPS modules to read latitude, longitude, and more.
218226 """
219227
220- def __init__ (self , uart , debug = False ):
228+ def __init__ (self , uart : UART , debug : bool = False ) -> None :
221229 self ._uart = uart
222230 # Initialize null starting values for GPS attributes.
223231 self .timestamp_utc = None
@@ -253,7 +261,7 @@ def __init__(self, uart, debug=False):
253261 self ._magnetic_variation = None
254262 self .debug = debug
255263
256- def update (self ):
264+ def update (self ) -> bool :
257265 """Check for updated data from the GPS module and process it
258266 accordingly. Returns True if new data was processed, and False if
259267 nothing new was received.
@@ -303,7 +311,7 @@ def update(self):
303311
304312 return result
305313
306- def send_command (self , command , add_checksum = True ):
314+ def send_command (self , command : bytes , add_checksum : bool = True ) -> None :
307315 """Send a command string to the GPS. If add_checksum is True (the
308316 default) a NMEA checksum will automatically be computed and added.
309317 Note you should NOT add the leading $ and trailing * to the command
@@ -320,48 +328,48 @@ def send_command(self, command, add_checksum=True):
320328 self .write (b"\r \n " )
321329
322330 @property
323- def has_fix (self ):
331+ def has_fix (self ) -> bool :
324332 """True if a current fix for location information is available."""
325333 return self .fix_quality is not None and self .fix_quality >= 1
326334
327335 @property
328- def has_3d_fix (self ):
336+ def has_3d_fix (self ) -> bool :
329337 """Returns true if there is a 3d fix available.
330338 use has_fix to determine if a 2d fix is available,
331339 passing it the same data"""
332340 return self .fix_quality_3d is not None and self .fix_quality_3d >= 2
333341
334342 @property
335- def datetime (self ):
343+ def datetime (self ) -> Optional [ time . struct_time ] :
336344 """Return struct_time object to feed rtc.set_time_source() function"""
337345 return self .timestamp_utc
338346
339347 @property
340- def nmea_sentence (self ):
348+ def nmea_sentence (self ) -> Optional [ str ] :
341349 """Return raw_sentence which is the raw NMEA sentence read from the GPS"""
342350 return self ._raw_sentence
343351
344- def read (self , num_bytes ) :
352+ def read (self , num_bytes : Optional [ int ]) -> Optional [ bytes ] :
345353 """Read up to num_bytes of data from the GPS directly, without parsing.
346- Returns a bytearray with up to num_bytes or None if nothing was read"""
354+ Returns a bytestring with up to num_bytes or None if nothing was read"""
347355 return self ._uart .read (num_bytes )
348356
349- def write (self , bytestr ) :
357+ def write (self , bytestr : ReadableBuffer ) -> Optional [ int ] :
350358 """Write a bytestring data to the GPS directly, without parsing
351359 or checksums"""
352360 return self ._uart .write (bytestr )
353361
354362 @property
355- def in_waiting (self ):
363+ def in_waiting (self ) -> int :
356364 """Returns number of bytes available in UART read buffer"""
357365 return self ._uart .in_waiting
358366
359- def readline (self ):
360- """Returns a newline terminated bytearray , must have timeout set for
367+ def readline (self ) -> Optional [ bytes ] :
368+ """Returns a newline terminated bytestring , must have timeout set for
361369 the underlying UART or this will block forever!"""
362370 return self ._uart .readline ()
363371
364- def _read_sentence (self ):
372+ def _read_sentence (self ) -> Optional [ str ] :
365373 # Parse any NMEA sentence that is available.
366374 # pylint: disable=len-as-condition
367375 # This needs to be refactored when it can be tested.
@@ -394,7 +402,7 @@ def _read_sentence(self):
394402 # At this point we don't have a valid sentence
395403 return None
396404
397- def _parse_sentence (self ):
405+ def _parse_sentence (self ) -> Optional [ Tuple [ str , str ]] :
398406 sentence = self ._read_sentence ()
399407
400408 # sentence is a valid NMEA with a valid checksum
@@ -411,7 +419,7 @@ def _parse_sentence(self):
411419 data_type = sentence [1 :delimiter ]
412420 return (data_type , sentence [delimiter + 1 :])
413421
414- def _update_timestamp_utc (self , time_utc , date = None ):
422+ def _update_timestamp_utc (self , time_utc : str , date : Optional [ str ] = None ) -> None :
415423 hours = int (time_utc [0 :2 ])
416424 mins = int (time_utc [2 :4 ])
417425 secs = int (time_utc [4 :6 ])
@@ -431,7 +439,7 @@ def _update_timestamp_utc(self, time_utc, date=None):
431439 (year , month , day , hours , mins , secs , 0 , 0 , - 1 )
432440 )
433441
434- def _parse_gll (self , data ) :
442+ def _parse_gll (self , data : List [ str ]) -> bool :
435443 # GLL - Geographic Position - Latitude/Longitude
436444
437445 if data is None or len (data ) != 7 :
@@ -459,7 +467,7 @@ def _parse_gll(self, data):
459467
460468 return True
461469
462- def _parse_rmc (self , data ) :
470+ def _parse_rmc (self , data : List [ str ]) -> bool :
463471 # RMC - Recommended Minimum Navigation Information
464472
465473 if data is None or len (data ) not in (12 , 13 ):
@@ -505,7 +513,7 @@ def _parse_rmc(self, data):
505513
506514 return True
507515
508- def _parse_gga (self , data ) :
516+ def _parse_gga (self , data : List [ str ]) -> bool :
509517 # GGA - Global Positioning System Fix Data
510518
511519 if data is None or len (data ) != 14 :
@@ -557,7 +565,7 @@ def _parse_gga(self, data):
557565
558566 return True
559567
560- def _parse_gsa (self , talker , data ) :
568+ def _parse_gsa (self , talker : bytes , data : List [ str ]) -> bool :
561569 # GSA - GPS DOP and active satellites
562570
563571 if data is None or len (data ) not in (17 , 18 ):
@@ -596,7 +604,7 @@ def _parse_gsa(self, talker, data):
596604
597605 return True
598606
599- def _parse_gsv (self , talker , data ) :
607+ def _parse_gsv (self , talker : bytes , data : List [ str ]) -> bool :
600608 # GSV - Satellites in view
601609 # pylint: disable=too-many-branches
602610
@@ -675,8 +683,13 @@ class GPS_GtopI2C(GPS):
675683 """
676684
677685 def __init__ (
678- self , i2c_bus , * , address = _GPSI2C_DEFAULT_ADDRESS , debug = False , timeout = 5
679- ):
686+ self ,
687+ i2c_bus : I2C ,
688+ * ,
689+ address : int = _GPSI2C_DEFAULT_ADDRESS ,
690+ debug : bool = False ,
691+ timeout : float = 5.0 ,
692+ ) -> None :
680693 from adafruit_bus_device import ( # pylint: disable=import-outside-toplevel
681694 i2c_device ,
682695 )
@@ -688,7 +701,7 @@ def __init__(
688701 self ._internalbuffer = []
689702 self ._timeout = timeout
690703
691- def read (self , num_bytes = 1 ) :
704+ def read (self , num_bytes : int = 1 ) -> bytearray :
692705 """Read up to num_bytes of data from the GPS directly, without parsing.
693706 Returns a bytearray with up to num_bytes or None if nothing was read"""
694707 result = []
@@ -704,19 +717,19 @@ def read(self, num_bytes=1):
704717 self ._lastbyte = char # keep track of the last character approved
705718 return bytearray (result )
706719
707- def write (self , bytestr ) :
720+ def write (self , bytestr : ReadableBuffer ) -> None :
708721 """Write a bytestring data to the GPS directly, without parsing
709722 or checksums"""
710723 with self ._i2c as i2c :
711724 i2c .write (bytestr )
712725
713726 @property
714- def in_waiting (self ):
727+ def in_waiting (self ) -> Literal [ 16 ] :
715728 """Returns number of bytes available in UART read buffer, always 16
716729 since I2C does not have the ability to know how much data is available"""
717730 return 16
718731
719- def readline (self ):
732+ def readline (self ) -> Optional [ bytearray ] :
720733 """Returns a newline terminated bytearray, must have timeout set for
721734 the underlying UART or this will block forever!"""
722735 timeout = time .monotonic () + self ._timeout
0 commit comments