-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgpsReader.py
More file actions
377 lines (334 loc) · 12.9 KB
/
gpsReader.py
File metadata and controls
377 lines (334 loc) · 12.9 KB
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
import serial # apt install python-serial
import zmq # apt install python-zmq
from Logger import Logger
import signal
import sys
from time import sleep
class gpsReader():
def __init__(self):
self.disconected = True
self.enabled = True
self.manSerial = False
self.normalRun = True
self.ToWrite = False
self.serBaud = 38400
self.zmqOutPort = "10100"
self.zmqInPort = "10300"
self.mserial = ""
self.zmqID = "defaultGPS"
self.parsedVTG = -1
self.parsedGGA = -1
self.parsedGLL = -1
self.pos_err = -1
self.get_args()
zmq_cont = zmq.Context()
self.publisher = zmq_cont.socket(zmq.PUB)
self.subscriber = zmq_cont.socket(zmq.SUB)
signal.signal(signal.SIGINT, self.sigINT_Handler)
self.logger = Logger(self.zmqID)
if(self.connect_serial() and self.connect_zmq()):
self.main_loop()
def sigINT_Handler(self, signal, frame):
print (self.zmqID + " detected SigINT signal")
self.logger.save_line("Signal SigINT detected")
self.enabled = False
self.publisher.disconnect('tcp://127.0.0.1:'+str(self.zmqOutPort))
if self.normalRun:
self.ser.close()
self.logger.close()
sys.exit(0)
def get_args(self):
if(len(sys.argv) < 2):
print ("Usage: " + str(sys.argv[0]) + " <PATH TO TTY PORT>" +
"[opt: <BaudRate> <ZMQPort> <ID>]" )
print ("Secondary use: " + str(sys.argv[0])
+ " <PATH TO RAW LOGFILE>")
sys.exit(0)
if(len(sys.argv) >= 2):
self.mserial = sys.argv[1]
if(sys.argv[1].find("/dev/") >= 0):
#normal run from physical device
self.normalRun = True
elif(sys.argv[1].find("Logs/") >= 0):
# Run from LOG
self.normalRun = False
if(len(sys.argv) >= 3):
self.mbaud = int(sys.argv[2])
if(len(sys.argv) >= 4):
self.zmqOutPort = str(sys.argv[3])
if(len(sys.argv) >= 5):
self.zmqID = str(sys.argv[4])
print("Settings -> Serial: " + self.mserial + " speed: "
+ str(self.mbaud) + " ZMQ port: " + self.zmqOutPort
+ " gps ID: " + str(self.zmqID))
def connect_serial(self):
if self.disconected:
if self.normalRun:
try:
self.ser = serial.Serial(self.mserial, self.mbaud)
self.ser.bytesize = serial.EIGHTBITS
self.ser.parity = serial.PARITY_NONE
self.ser.stopbits = serial.STOPBITS_ONE
self.disconected = False
print( "Connected to " + self.mserial)
if(self.ser.readable()):
self.ser.flush()
self.ser.readline()
return True
except:
print( "Failed connecting to " + self.mserial)
return False
else:
try:
logfile = open(self.mserial,'rb')
self.LogData = []
for line in logfile:
if(line.find("$")>=0):
if(line.find(" : ")>=0):
splt = line.split(" : ")
self.LogData.append(splt[1])
else:
self.LogData.append(line)
logfile.close()
return True
except:
self.logger.save_line("Opening log file <" + self.mserial
+"> failed")
return False
def connect_zmq(self):
try:
self.publisher.bind('tcp://127.0.0.1:'+str(self.zmqOutPort))
self.logger.save_line("Binded to local port: " + self.zmqOutPort)
self.publisher.send_string(self.zmqID + " binded on port "
+ self.zmqOutPort)
except:
self.logger.save_line("Failed to bind localPort "
+ self.zmqOutPort)
try:
self.subscriber.connect('tcp://127.0.0.1:'+self.zmqInPort)
self.subscriber.setsockopt(zmq.SUBSCRIBE, b"")
self.logger.save_line("Connected to local port: " + self.zmqInPort)
except:
self.logger.save_line("Failed to connect localPort "
+ self.zmqInPort)
return False
finally:
sleep(1)
return True
def parseRMC(self,line):
## RMC message:
# Time fix,
# status (Active/Void)
# Latitude,N
# Longitude,E
# Speed over ground (Kn)
# Track angle (true deg.)
# Date (DDMMYY)
# Magnetic variation
return 10
def parseVTG(self,line):
## VTG Message:
# True track made good
# Magnetic track made good
# Ground speed (Kn)
# Ground speed (km/h)
try:
datas = line.split(",")
self.gps_dir = float(datas[1])
self.gps_dir = int(self.gps_dir)
return 0
except:
return 1
def parseGGA(self,line):
## GGA message -
# Time fix,
# Latitude,N
# Longitude,E
# FixQuality
# NumberOfSatelites
# Horizontal dilution of position
# Altitude
##
data_split = line.split(",")
try: # to parse time:
self.gps_time = data_split[1]
except:
return 4 # Parsing failed totally
try: # to parse positon
self.latitude = round(float(data_split[2])/100,7)
self.longitude = round(float(data_split[4])/100,7)
self.lat_ns = data_split[3]
self.lon_we = data_split[5]
except:
return 3 #Time parsed, position failed
try:
self.pos_err = data_split[8]
except:
return 2 # Time and position parsed, pos.Error failed
try:
self.altitude = data_split[9]
return 0 # Parsing succesfull
except:
return 1 # Time, position and posErr parsed, altitude failed
def parseGLL(self,line):
## GLL message:
# Latitude,N
# Longitude,E
# time Fix
# Status (A/V - Active/Void)
try:
data_split = line.split(",")
self.lat_ns = data_split[2]
self.lon_we = data_split[4]
self.longitude = round(float(data_split[3])/100,7)
self.latitude = round(float(data_split[1])/100,7)
self.gps_time = data_split[5]
return 0
except:
self.lat_ns = " "
self.lon_we = " "
self.longitude = -1.0
self.latitude = -1.0
self.gps_time = -1.0
try:
if(float(data_split[5]) > 10):
self.gps_time = data_split[5]
return 1
except:
pass
return 2
def sendZMQPosition(self):
data = "ID:"+str(self.zmqID)
data+= ";TIME:"+str(self.gps_time)
data+= ";LON:"+str(self.longitude)+","+self.lon_we
data+= ";LAT:"+str(self.latitude)+","+self.lat_ns
data+= ";P_ERR:"+str(self.pos_err)
self.publisher.send_string(data)
def sendZMQTime(self):
data = "ID:"+str(self.zmqID)
data+= ";TIME:"+str(self.gps_time)
self.publisher.send_string(data)
def sendZMQAll(self):
data = "ID:"+str(self.zmqID)
data+= ";TIME:"+str(self.gps_time)
data+= ";LON:"+str(self.longitude)+","+self.lon_we
data+= ";LAT:"+str(self.latitude)+","+self.lat_ns
data+= ";P_ERR:"+str(self.pos_err)
data+= ";DIR:"+str(self.gps_dir)
self.publisher.send_string(data)
def sortLine(self,line):
## drop data about satelites
if(str(line).find("GSV,") == -1):
self.logger.save_line(line)
line = str(line)
if(line.find("GNRMC") >= 0):
## first message from chunk - reset all parsed values
self.parsedVTG = -1
self.parsedGGA = -1
self.parsedGLL = -1
parsed = self.parseRMC(line)
elif(line.find("$GNVTG")>=0):
# VTG - minimal information about direction and speed
self.parsedVTG = self.parseVTG(line)
elif(line.find("$GNGGA") >= 0):
# GGA - complex information about 3D position and pos.dilution
# GGA is main source of needed information
self.parsedGGA = self.parseGGA(line)
elif(line.find("$GNGLL") >= 0):
# GLL - minimal information about position
self.parsedGLL = self.parseGLL(line)
self.sendColected()
def sendColected(self):
## possibilities:
# 1) got only time
# 2) got 1) + position and dilution of position
# 3) got 2) + speed and direction
if(self.parsedGGA == 3) or (self.parsedGLL == 1): # time only
self.sendZMQTime()
if(self.parsedGGA < 3): # Got position
if(self.parsedVTG == 0): # Got speed and direction
self.sendZMQAll()
else:
self.sendZMQPosition()
def syncLog(self):
for i in range(10):
if(self.LogData[i].find("RMC") >= 0):
return i
def parseMessage(self, data):
if(data.find(self.zmqID)>=0):
split = data.split(";")
for item in split:
name,value = item.split(":")
if(value.find("COLDSTART") >= 0):
self.ToWrite = True
self.MsgType = "COLD"
elif(value.find("WARMSTART")>=0):
self.ToWrite = True
self.MsgType = "WARM"
else:
self.logger.save_line("Unsupported message: <" +data
+ "> with argument: <" + value + ">")
else:
self.logger.save_line("Unrecognized message: <" +data+ ">")
def ColdStart(self):
#msg = [0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x0E, 0x61]
msg = 'B56206040400FFFF02000E61'
self.logger.save_line("Cold start requested")
if self.normalRun:
success = self.ser.write(msg.decode("hex"))
else:
success = True
self.logger.save_line("Message: <" + msg + ">")
return success
def WarmStart(self):
#msg = [0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x11, 0x6C]
msg = 'B5620604040001000200116C'
self.logger.save_line("Warm start requested")
if self.normalRun:
success = self.ser.write(msg.decode("hex"))
else:
success = True
self.logger.save_line("Message: <" + msg + ">")
return success
def writeMessage(self):
self.ToWrite = False
if(self.MsgType is "WARM"):
self.WarmStart()
elif(self.MsgType is "COLD"):
self.ColdStart()
else:
self.logger.save_line("Unsupported message type: <" + self.MsgType + ">")
def main_loop(self):
if self.normalRun:
while self.enabled:
waitingMSG = self.subscriber.poll(20,zmq.POLLIN)
while(waitingMSG > 0):
msg = self.subscriber.recv_string()
self.parseMessage(msg)
waitingMSG = self.subscriber.poll(20,zmq.POLLIN)
if(self.ser.writable() and self.ToWrite):
self.writeMessage()
if(self.ser.readable()):
line = self.ser.readline()
self.sortLine(line)
sleep(0.0001)
self.ser.close()
else:
lineIndex = self.syncLog()
maxIndex = len(self.LogData)
while(lineIndex < maxIndex):
waitingMSG = self.subscriber.poll(20,zmq.POLLIN)
while(waitingMSG > 0):
msg = self.subscriber.recv_string()
self.parseMessage(msg)
waitingMSG = self.subscriber.poll(20,zmq.POLLIN)
if(self.ToWrite):
self.writeMessage()
self.sortLine(self.LogData[lineIndex])
if(self.LogData[lineIndex].find("GLL") >= 0):
sleep(0.1) ## corresponds to GPS settings (10Hz)
lineIndex += 1
self.enabled = False
self.logger.close()
B = gpsReader()
B.main_loop()