29
29
import time
30
30
from micropython import const
31
31
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
+
32
40
__version__ = "0.0.0+auto.0"
33
41
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_GPS.git"
34
42
75
83
# Internal helper parsing functions.
76
84
# These handle input that might be none or null and return none instead of
77
85
# throwing errors.
78
- def _parse_degrees (nmea_data ) :
86
+ def _parse_degrees (nmea_data : str ) -> int :
79
87
# Parse a NMEA lat/long data pair 'dddmm.mmmm' into a pure degrees value.
80
88
# Where ddd is the degrees, mm.mmmm is the minutes.
81
89
if nmea_data is None or len (nmea_data ) < 3 :
@@ -88,52 +96,52 @@ def _parse_degrees(nmea_data):
88
96
minutes = int (raw [0 ]) % 100 # the mm.
89
97
minutes += int (f"{ raw [1 ][:4 ]:0<4} " ) / 10000
90
98
minutes = int (minutes / 60 * 1000000 )
91
- return degrees + minutes # return parsed string in the format dddmmmmmm
99
+ return degrees + minutes
92
100
93
101
94
- def _parse_int (nmea_data ) :
102
+ def _parse_int (nmea_data : str ) -> int :
95
103
if nmea_data is None or nmea_data == "" :
96
104
return None
97
105
return int (nmea_data )
98
106
99
107
100
- def _parse_float (nmea_data ) :
108
+ def _parse_float (nmea_data : str ) -> float :
101
109
if nmea_data is None or nmea_data == "" :
102
110
return None
103
111
return float (nmea_data )
104
112
105
113
106
- def _parse_str (nmea_data ) :
114
+ def _parse_str (nmea_data : str ) -> str :
107
115
if nmea_data is None or nmea_data == "" :
108
116
return None
109
117
return str (nmea_data )
110
118
111
119
112
- def _read_degrees (data , index , neg ) :
120
+ def _read_degrees (data : List [ float ] , index : int , neg : str ) -> float :
113
121
# This function loses precision with float32
114
122
x = data [index ] / 1000000
115
123
if data [index + 1 ].lower () == neg :
116
124
x *= - 1.0
117
125
return x
118
126
119
127
120
- def _read_int_degrees (data , index , neg ) :
128
+ def _read_int_degrees (data : List [ float ] , index : int , neg : str ) -> Tuple [ int , float ] :
121
129
deg = data [index ] // 1000000
122
130
minutes = data [index ] % 1000000 / 10000
123
131
if data [index + 1 ].lower () == neg :
124
132
deg *= - 1
125
133
return (deg , minutes )
126
134
127
135
128
- def _parse_talker (data_type ) :
136
+ def _parse_talker (data_type : bytes ) -> Tuple [ bytes , bytes ] :
129
137
# Split the data_type into talker and sentence_type
130
138
if data_type [:1 ] == b"P" : # Proprietary codes
131
139
return (data_type [:1 ], data_type [1 :])
132
140
133
141
return (data_type [:2 ], data_type [2 :])
134
142
135
143
136
- def _parse_data (sentence_type , data ) :
144
+ def _parse_data (sentence_type : int , data : List [ str ]) -> Optional [ List ] :
137
145
"""Parse sentence data for the specified sentence type and
138
146
return a list of parameters in the correct format, or return None.
139
147
"""
@@ -217,7 +225,7 @@ class GPS:
217
225
GPS modules to read latitude, longitude, and more.
218
226
"""
219
227
220
- def __init__ (self , uart , debug = False ):
228
+ def __init__ (self , uart : UART , debug : bool = False ) -> None :
221
229
self ._uart = uart
222
230
# Initialize null starting values for GPS attributes.
223
231
self .timestamp_utc = None
@@ -253,7 +261,7 @@ def __init__(self, uart, debug=False):
253
261
self ._magnetic_variation = None
254
262
self .debug = debug
255
263
256
- def update (self ):
264
+ def update (self ) -> bool :
257
265
"""Check for updated data from the GPS module and process it
258
266
accordingly. Returns True if new data was processed, and False if
259
267
nothing new was received.
@@ -303,7 +311,7 @@ def update(self):
303
311
304
312
return result
305
313
306
- def send_command (self , command , add_checksum = True ):
314
+ def send_command (self , command : bytes , add_checksum : bool = True ) -> None :
307
315
"""Send a command string to the GPS. If add_checksum is True (the
308
316
default) a NMEA checksum will automatically be computed and added.
309
317
Note you should NOT add the leading $ and trailing * to the command
@@ -320,48 +328,48 @@ def send_command(self, command, add_checksum=True):
320
328
self .write (b"\r \n " )
321
329
322
330
@property
323
- def has_fix (self ):
331
+ def has_fix (self ) -> bool :
324
332
"""True if a current fix for location information is available."""
325
333
return self .fix_quality is not None and self .fix_quality >= 1
326
334
327
335
@property
328
- def has_3d_fix (self ):
336
+ def has_3d_fix (self ) -> bool :
329
337
"""Returns true if there is a 3d fix available.
330
338
use has_fix to determine if a 2d fix is available,
331
339
passing it the same data"""
332
340
return self .fix_quality_3d is not None and self .fix_quality_3d >= 2
333
341
334
342
@property
335
- def datetime (self ):
343
+ def datetime (self ) -> Optional [ time . struct_time ] :
336
344
"""Return struct_time object to feed rtc.set_time_source() function"""
337
345
return self .timestamp_utc
338
346
339
347
@property
340
- def nmea_sentence (self ):
348
+ def nmea_sentence (self ) -> Optional [ str ] :
341
349
"""Return raw_sentence which is the raw NMEA sentence read from the GPS"""
342
350
return self ._raw_sentence
343
351
344
- def read (self , num_bytes ) :
352
+ def read (self , num_bytes : Optional [ int ]) -> Optional [ bytes ] :
345
353
"""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"""
347
355
return self ._uart .read (num_bytes )
348
356
349
- def write (self , bytestr ) :
357
+ def write (self , bytestr : ReadableBuffer ) -> Optional [ int ] :
350
358
"""Write a bytestring data to the GPS directly, without parsing
351
359
or checksums"""
352
360
return self ._uart .write (bytestr )
353
361
354
362
@property
355
- def in_waiting (self ):
363
+ def in_waiting (self ) -> int :
356
364
"""Returns number of bytes available in UART read buffer"""
357
365
return self ._uart .in_waiting
358
366
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
361
369
the underlying UART or this will block forever!"""
362
370
return self ._uart .readline ()
363
371
364
- def _read_sentence (self ):
372
+ def _read_sentence (self ) -> Optional [ str ] :
365
373
# Parse any NMEA sentence that is available.
366
374
# pylint: disable=len-as-condition
367
375
# This needs to be refactored when it can be tested.
@@ -394,7 +402,7 @@ def _read_sentence(self):
394
402
# At this point we don't have a valid sentence
395
403
return None
396
404
397
- def _parse_sentence (self ):
405
+ def _parse_sentence (self ) -> Optional [ Tuple [ str , str ]] :
398
406
sentence = self ._read_sentence ()
399
407
400
408
# sentence is a valid NMEA with a valid checksum
@@ -411,7 +419,7 @@ def _parse_sentence(self):
411
419
data_type = sentence [1 :delimiter ]
412
420
return (data_type , sentence [delimiter + 1 :])
413
421
414
- def _update_timestamp_utc (self , time_utc , date = None ):
422
+ def _update_timestamp_utc (self , time_utc : str , date : Optional [ str ] = None ) -> None :
415
423
hours = int (time_utc [0 :2 ])
416
424
mins = int (time_utc [2 :4 ])
417
425
secs = int (time_utc [4 :6 ])
@@ -431,7 +439,7 @@ def _update_timestamp_utc(self, time_utc, date=None):
431
439
(year , month , day , hours , mins , secs , 0 , 0 , - 1 )
432
440
)
433
441
434
- def _parse_gll (self , data ) :
442
+ def _parse_gll (self , data : List [ str ]) -> bool :
435
443
# GLL - Geographic Position - Latitude/Longitude
436
444
437
445
if data is None or len (data ) != 7 :
@@ -459,7 +467,7 @@ def _parse_gll(self, data):
459
467
460
468
return True
461
469
462
- def _parse_rmc (self , data ) :
470
+ def _parse_rmc (self , data : List [ str ]) -> bool :
463
471
# RMC - Recommended Minimum Navigation Information
464
472
465
473
if data is None or len (data ) not in (12 , 13 ):
@@ -505,7 +513,7 @@ def _parse_rmc(self, data):
505
513
506
514
return True
507
515
508
- def _parse_gga (self , data ) :
516
+ def _parse_gga (self , data : List [ str ]) -> bool :
509
517
# GGA - Global Positioning System Fix Data
510
518
511
519
if data is None or len (data ) != 14 :
@@ -557,7 +565,7 @@ def _parse_gga(self, data):
557
565
558
566
return True
559
567
560
- def _parse_gsa (self , talker , data ) :
568
+ def _parse_gsa (self , talker : bytes , data : List [ str ]) -> bool :
561
569
# GSA - GPS DOP and active satellites
562
570
563
571
if data is None or len (data ) not in (17 , 18 ):
@@ -596,7 +604,7 @@ def _parse_gsa(self, talker, data):
596
604
597
605
return True
598
606
599
- def _parse_gsv (self , talker , data ) :
607
+ def _parse_gsv (self , talker : bytes , data : List [ str ]) -> bool :
600
608
# GSV - Satellites in view
601
609
# pylint: disable=too-many-branches
602
610
@@ -675,8 +683,13 @@ class GPS_GtopI2C(GPS):
675
683
"""
676
684
677
685
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 :
680
693
from adafruit_bus_device import ( # pylint: disable=import-outside-toplevel
681
694
i2c_device ,
682
695
)
@@ -688,7 +701,7 @@ def __init__(
688
701
self ._internalbuffer = []
689
702
self ._timeout = timeout
690
703
691
- def read (self , num_bytes = 1 ) :
704
+ def read (self , num_bytes : int = 1 ) -> bytearray :
692
705
"""Read up to num_bytes of data from the GPS directly, without parsing.
693
706
Returns a bytearray with up to num_bytes or None if nothing was read"""
694
707
result = []
@@ -704,19 +717,19 @@ def read(self, num_bytes=1):
704
717
self ._lastbyte = char # keep track of the last character approved
705
718
return bytearray (result )
706
719
707
- def write (self , bytestr ) :
720
+ def write (self , bytestr : ReadableBuffer ) -> None :
708
721
"""Write a bytestring data to the GPS directly, without parsing
709
722
or checksums"""
710
723
with self ._i2c as i2c :
711
724
i2c .write (bytestr )
712
725
713
726
@property
714
- def in_waiting (self ):
727
+ def in_waiting (self ) -> Literal [ 16 ] :
715
728
"""Returns number of bytes available in UART read buffer, always 16
716
729
since I2C does not have the ability to know how much data is available"""
717
730
return 16
718
731
719
- def readline (self ):
732
+ def readline (self ) -> Optional [ bytearray ] :
720
733
"""Returns a newline terminated bytearray, must have timeout set for
721
734
the underlying UART or this will block forever!"""
722
735
timeout = time .monotonic () + self ._timeout
0 commit comments