-
Notifications
You must be signed in to change notification settings - Fork 1
/
gpsd_i2c.py
executable file
·88 lines (72 loc) · 2.32 KB
/
gpsd_i2c.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/usr/bin/env python3
"""
A simple way to read raw NMEA 0183 data from a GPS module that has I²C output capability.
"""
import os
import signal
import sys
import smbus2
def parse_int(val, default):
"Parse integer from string, first as decimal then as hex"
try:
result = int(val)
except (TypeError, ValueError):
try:
result = int(val,16)
except (TypeError, ValueError):
result = default
return result
# Default to device 0-0042; can be overriden via environment
I2C_BUS = parse_int(os.environ.get("I2C_BUS", None), 0)
I2C_ADDRESS = parse_int(os.environ.get("I2C_ADDRESS", None), 0x42)
def handle_ctrl_c(sig, frame):
"Exit handler"
# pylint: disable=unused-argument
sys.exit(130)
# This will capture exit when using [Ctrl]+[C] for a graceful exit
signal.signal(signal.SIGINT, handle_ctrl_c)
def parse_response(gps_line):
"Parse GPS line"
# Check #1 -- make sure line starts with $ and $ doesn't appear twice
if gps_line[0] != 36 or gps_line.count(36) != 1:
return
# Check #2 -- 83 is maximum NMEA sentence length
if len(gps_line) > 83:
return
# Check #3 -- make sure that only readable ASCII characters
# and carriage return are seen
for char in gps_line:
if (char < 32 or char > 122) and char != 13:
return
gps_chars = ''.join(chr(char) for char in gps_line)
# Check #4 -- skip txbuff allocation error
if 'txtbuf' in gps_chars:
return
# Check #5 -- only split twice to avoid unpack error
gps_str, chk_sum = gps_chars.split('*', 2)
# Remove the $ and do a manual checksum on the rest of the NMEA sentence
chk_val = 0
for char in gps_str[1:]:
chk_val ^= ord(char)
# Compare the calculated checksum with the one in the NMEA sentence
if chk_val != int(chk_sum, 16):
return
# All checks passed
print(gps_chars)
def read_gps(bus):
"read bytes from I2C device"
response = []
try:
while True:
byte = bus.read_byte(I2C_ADDRESS)
if byte == 255:
return
if byte == ord('\n'):
break
response.append(byte)
parse_response(response)
except IOError:
bus = smbus2.SMBus(I2C_BUS)
BUS = smbus2.SMBus(I2C_BUS)
while True:
read_gps(BUS)