1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import time
18 from client import *
19
20 NaN = float('nan')
21 -def isnan(x): return str(x) == 'nan'
22
23
24 ONLINE_SET = 0x00000001
25 TIME_SET = 0x00000002
26 TIMERR_SET = 0x00000004
27 LATLON_SET = 0x00000008
28 ALTITUDE_SET = 0x00000010
29 SPEED_SET = 0x00000020
30 TRACK_SET = 0x00000040
31 CLIMB_SET = 0x00000080
32 STATUS_SET = 0x00000100
33 MODE_SET = 0x00000200
34 DOP_SET = 0x00000400
35 VERSION_SET = 0x00000800
36 HERR_SET = 0x00001000
37 VERR_SET = 0x00002000
38 ATTITUDE_SET = 0x00004000
39 POLICY_SET = 0x00008000
40 SATELLITE_SET = 0x00010000
41 RAW_SET = 0x00020000
42 USED_SET = 0x00040000
43 SPEEDERR_SET = 0x00080000
44 TRACKERR_SET = 0x00100000
45 CLIMBERR_SET = 0x00200000
46 DEVICE_SET = 0x00400000
47 DEVICELIST_SET = 0x00800000
48 DEVICEID_SET = 0x01000000
49 ERROR_SET = 0x02000000
50 RTCM2_SET = 0x04000000
51 RTCM3_SET = 0x08000000
52 AIS_SET = 0x10000000
53 PACKET_SET = 0x20000000
54 AUXDATA_SET = 0x80000000
55 UNION_SET = (RTCM2_SET|RTCM3_SET|AIS_SET|VERSION_SET|DEVICELIST_SET|ERROR_SET)
56
57 STATUS_NO_FIX = 0
58 STATUS_FIX = 1
59 STATUS_DGPS_FIX = 2
60 MODE_NO_FIX = 1
61 MODE_2D = 2
62 MODE_3D = 3
63 MAXCHANNELS = 20
64 SIGNAL_STRENGTH_UNKNOWN = NaN
65
66 WATCH_NEWSTYLE = 0x00080
67 WATCH_OLDSTYLE = 0x10000
68
85
87 "Position, track, velocity and status information returned by a GPS."
88
90 - def __init__(self, PRN, elevation, azimuth, ss, used=None):
91 self.PRN = PRN
92 self.elevation = elevation
93 self.azimuth = azimuth
94 self.ss = ss
95 self.used = used
97 return "PRN: %3d E: %3d Az: %3d Ss: %3d Used: %s" % (
98 self.PRN, self.elevation, self.azimuth, self.ss, "ny"[self.used]
99 )
100
102
103 self.online = 0
104
105 self.valid = 0
106 self.fix = gpsfix()
107
108 self.status = STATUS_NO_FIX
109 self.utc = ""
110
111 self.satellites_used = 0
112 self.xdop = self.ydop = self.vdop = self.tdop = 0
113 self.pdop = self.hdop = self.gdop = 0.0
114
115 self.epe = 0.0
116
117 self.satellites = []
118
119 self.gps_id = None
120 self.driver_mode = 0
121 self.baudrate = 0
122 self.stopbits = 0
123 self.cycle = 0
124 self.mincycle = 0
125 self.device = None
126 self.devices = []
127
128 self.version = None
129 self.timings = None
130
132 st = "Time: %s (%s)\n" % (self.utc, self.fix.time)
133 st += "Lat/Lon: %f %f\n" % (self.fix.latitude, self.fix.longitude)
134 if isnan(self.fix.altitude):
135 st += "Altitude: ?\n"
136 else:
137 st += "Altitude: %f\n" % (self.fix.altitude)
138 if isnan(self.fix.speed):
139 st += "Speed: ?\n"
140 else:
141 st += "Speed: %f\n" % (self.fix.speed)
142 if isnan(self.fix.track):
143 st += "Track: ?\n"
144 else:
145 st += "Track: %f\n" % (self.fix.track)
146 st += "Status: STATUS_%s\n" % ("NO_FIX", "FIX", "DGPS_FIX")[self.status]
147 st += "Mode: MODE_%s\n" % ("ZERO", "NO_FIX", "2D", "3D")[self.fix.mode]
148 st += "Quality: %d p=%2.2f h=%2.2f v=%2.2f t=%2.2f g=%2.2f\n" % \
149 (self.satellites_used, self.pdop, self.hdop, self.vdop, self.tdop, self.gdop)
150 st += "Y: %s satellites in view:\n" % len(self.satellites)
151 for sat in self.satellites:
152 st += " %r\n" % sat
153 return st
154
155 -class gps(gpsdata, gpsjson):
156 "Client interface to a running gpsd instance."
164
167
169
170 self.fix.time = 0.0
171 fields = buf.strip().split(",")
172 if fields[0] == "GPSD":
173 for field in fields[1:]:
174 if not field or field[1] != '=':
175 continue
176 cmd = field[0].upper()
177 data = field[2:]
178 if data[0] == "?":
179 continue
180 if cmd == 'F':
181 self.device = data
182 elif cmd == 'I':
183 self.gps_id = data
184 elif cmd == 'O':
185 fields = data.split()
186 if fields[0] == '?':
187 self.fix.mode = MODE_NO_FIX
188 else:
189 def default(i, vbit=0, cnv=float):
190 if fields[i] == '?':
191 return NaN
192 else:
193 try:
194 value = cnv(fields[i])
195 except ValueError:
196 return NaN
197 self.valid |= vbit
198 return value
199
200 self.valid &= ~(
201 TIME_SET | TIMERR_SET | LATLON_SET | ALTITUDE_SET |
202 HERR_SET | VERR_SET | TRACK_SET | SPEED_SET |
203 CLIMB_SET | SPEEDERR_SET | CLIMBERR_SET | MODE_SET
204 )
205 self.utc = fields[1]
206 self.fix.time = default(1, TIME_SET)
207 if not isnan(self.fix.time):
208 self.utc = isotime(self.fix.time)
209 self.fix.ept = default(2, TIMERR_SET)
210 self.fix.latitude = default(3, LATLON_SET)
211 self.fix.longitude = default(4)
212 self.fix.altitude = default(5, ALTITUDE_SET)
213 self.fix.epx = self.epy = default(6, HERR_SET)
214 self.fix.epv = default(7, VERR_SET)
215 self.fix.track = default(8, TRACK_SET)
216 self.fix.speed = default(9, SPEED_SET)
217 self.fix.climb = default(10, CLIMB_SET)
218 self.fix.epd = default(11)
219 self.fix.eps = default(12, SPEEDERR_SET)
220 self.fix.epc = default(13, CLIMBERR_SET)
221 if len(fields) > 14:
222 self.fix.mode = default(14, MODE_SET, int)
223 else:
224 if self.valid & ALTITUDE_SET:
225 self.fix.mode = MODE_2D
226 else:
227 self.fix.mode = MODE_3D
228 self.valid |= MODE_SET
229 elif cmd == 'X':
230 self.online = float(data)
231 self.valid |= ONLINE_SET
232 elif cmd == 'Y':
233 satellites = data.split(":")
234 prefix = satellites.pop(0).split()
235 d1 = int(prefix.pop())
236 newsats = []
237 for i in range(d1):
238 newsats.append(gps.satellite(*map(int, satellites[i].split())))
239 self.satellites = newsats
240 self.valid |= SATELLITE_SET
241
243
244 def default(k, dflt, vbit=0):
245 if k not in self.data.keys():
246 return dflt
247 else:
248 self.valid |= vbit
249 return self.data[k]
250 if self.data.get("class") == "VERSION":
251 self.version = self.data
252 elif self.data.get("class") == "DEVICE":
253 self.valid = ONLINE_SET | DEVICE_SET
254 self.path = self.data["path"]
255 self.activated = default("activated", None)
256 driver = default("driver", None, DEVICEID_SET)
257 subtype = default("subtype", None, DEVICEID_SET)
258 self.gps_id = driver
259 if subtype:
260 self.gps_id += " " + subtype
261 self.driver_mode = default("native", 0)
262 self.baudrate = default("bps", 0)
263 self.serialmode = default("serialmode", "8N1")
264 self.cycle = default("cycle", NaN)
265 self.mincycle = default("mincycle", NaN)
266 elif self.data.get("class") == "TPV":
267 self.valid = ONLINE_SET
268 self.fix.time = default("time", NaN, TIME_SET)
269 self.fix.ept = default("ept", NaN, TIMERR_SET)
270 self.fix.latitude = default("lat", NaN, LATLON_SET)
271 self.fix.longitude = default("lon", NaN)
272 self.fix.altitude = default("alt", NaN, ALTITUDE_SET)
273 self.fix.epx = default("epx", NaN, HERR_SET)
274 self.fix.epy = default("epy", NaN, HERR_SET)
275 self.fix.epv = default("epv", NaN, VERR_SET)
276 self.fix.track = default("track", NaN, TRACK_SET)
277 self.fix.speed = default("speed", NaN, SPEED_SET)
278 self.fix.climb = default("climb", NaN, CLIMB_SET)
279 self.fix.epd = default("epd", NaN)
280 self.fix.eps = default("eps", NaN, SPEEDERR_SET)
281 self.fix.epc = default("epc", NaN, CLIMBERR_SET)
282 self.fix.mode = default("mode", 0, MODE_SET)
283 elif self.data.get("class") == "SKY":
284 for attrp in "xyvhpg":
285 setattr(self, attrp+"dop", default(attrp+"dop", NaN, DOP_SET))
286 if "satellites" in self.data.keys():
287 self.satellites = []
288 for sat in self.data['satellites']:
289 self.satellites.append(gps.satellite(PRN=sat['PRN'], elevation=sat['el'], azimuth=sat['az'], ss=sat['ss'], used=sat['used']))
290 self.satellites_used = 0
291 for sat in self.satellites:
292 if sat.used:
293 self.satellites_used += 1
294 self.valid = ONLINE_SET | SATELLITE_SET
295 elif self.data.get("class") == "TIMING":
296 self.data["c_recv"] = self.received
297 self.data["c_decode"] = time.time()
298 self.timings = self.data
299
301 "Read and interpret data from the daemon."
302 status = gpscommon.read(self)
303 if status <= 0:
304 return status
305 if self.raw_hook:
306 self.raw_hook(self.response);
307 if self.response.startswith("{") and self.response.endswith("}\r\n"):
308 self.json_unpack(self.response)
309 self.__oldstyle_shim()
310 self.newstyle = True
311 self.valid |= PACKET_SET
312 elif self.response.startswith("GPSD"):
313 self.__oldstyle_unpack(self.response)
314 self.valid |= PACKET_SET
315 return 0
316
318 if self.poll() == -1:
319 raise StopIteration
320 if hasattr(self, "data"):
321 return self.data
322 else:
323 return self.response
324
325 - def stream(self, flags=0, outfile=None):
349
350 if __name__ == '__main__':
351 import readline, getopt, sys
352 (options, arguments) = getopt.getopt(sys.argv[1:], "v")
353 streaming = False
354 verbose = False
355 for (switch, val) in options:
356 if switch == '-v':
357 verbose = True
358 if len(arguments) > 2:
359 print 'Usage: gps.py [-v] [host [port]]'
360 sys.exit(1)
361
362 opts = { "verbose" : verbose }
363 if len(arguments) > 0:
364 opts["host"] = arguments[0]
365 if len(arguments) > 1:
366 opts["port"] = arguments[1]
367
368 session = gps(**opts)
369 session.set_raw_hook(lambda s: sys.stdout.write(s.strip() + "\n"))
370 session.stream(WATCH_ENABLE|WATCH_NEWSTYLE)
371 for report in session:
372 print report
373
374
375