~ubuntu-branches/ubuntu/quantal/agtl/quantal

« back to all changes in this revision

Viewing changes to files/advancedcaching/gpsreader.py

  • Committer: Bazaar Package Importer
  • Author(s): Angel Abad
  • Date: 2011-01-23 13:14:08 UTC
  • mfrom: (4.1.4 sid)
  • Revision ID: james.westby@ubuntu.com-20110123131408-4wy5aefap3o6a4lw
Tags: 0.8.0.3-1ubuntu1
* Merge from debian unstable.  Remaining changes:
  - debian/control: Switch section from python to misc
  - Add category Geography to .desktop

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python
2
2
# -*- coding: utf-8 -*-
3
3
 
4
 
#        Copyright (C) 2009 Daniel Fett
5
 
#         This program is free software: you can redistribute it and/or modify
 
4
#   Copyright (C) 2010 Daniel Fett
 
5
#   This program is free software: you can redistribute it and/or modify
6
6
#   it under the terms of the GNU General Public License as published by
7
7
#   the Free Software Foundation, either version 3 of the License, or
8
8
#   (at your option) any later version.
15
15
#   You should have received a copy of the GNU General Public License
16
16
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
17
#
18
 
#        Author: Daniel Fett advancedcaching@fragcom.de
 
18
#   Author: Daniel Fett agtl@danielfett.de
 
19
#   Jabber: fett.daniel@jaber.ccc.de
 
20
#   Bugtracker and GIT Repository: http://github.com/webhamster/advancedcaching
19
21
#
20
22
 
21
23
import geo
22
 
import socket
 
24
from socket import socket, AF_INET, SOCK_STREAM
 
25
from datetime import datetime
 
26
import logging
 
27
 
 
28
logger = logging.getLogger('gpsreader')
 
29
 
 
30
try:
 
31
    import location
 
32
except (ImportError):
 
33
    logger.warning("If you're on maemo, please install python-location")
23
34
 
24
35
class Fix():
 
36
    BEARING_HOLD_EPD = 90 # arbitrary, yet non-random value
 
37
    last_bearing = 0
 
38
    # tracking the minimum difference between a received fix time and
 
39
    # our current internal time. 
 
40
    min_timediff = datetime.utcnow() - datetime.utcfromtimestamp(0)
 
41
    
25
42
    def __init__(self,
26
43
            position = None,
27
44
            altitude = None,
31
48
            sats_known = 0,
32
49
            dgps = False,
33
50
            quality = 0,
34
 
            error = 0):
 
51
            error = 0,
 
52
            error_bearing = 0,
 
53
            timestamp = None):
35
54
        self.position = position
36
55
        self.altitude = altitude
37
56
        self.bearing = bearing
41
60
        self.dgps = dgps
42
61
        self.quality = quality
43
62
        self.error = error
 
63
        self.error_bearing = error_bearing
 
64
        if timestamp == None:
 
65
            self.timestamp = datetime.utcnow()
 
66
        else:
 
67
            self.timestamp = timestamp
 
68
 
 
69
 
44
70
 
45
71
class GpsReader():
46
72
 
47
73
    BEARING_HOLD_SPEED = 0.62 # meters per second. empirical value.
48
74
    QUALITY_LOW_BOUND = 5.0 # meters of HDOP.
49
75
    DGPS_ADVANTAGE = 1 # see below for usage
50
 
 
 
76
    PORT = 2947
 
77
    HOST = '127.0.0.1'
51
78
 
52
79
    EMPTY = Fix()
53
80
 
54
 
    def __init__(self, gui):
55
 
        self.gui = gui
 
81
    def __init__(self):
 
82
        logger.info("Using GPSD gps reader on port %d host %s" % (self.PORT, self.HOST))
56
83
        self.status = "connecting..."
57
84
        self.connected = False
58
85
        self.last_bearing = 0
63
90
    def connect(self):
64
91
        try:
65
92
 
66
 
            self.gpsd_connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
67
 
            self.gpsd_connection.connect(("127.0.0.1", 2947))
 
93
            self.gpsd_connection = socket(AF_INET, SOCK_STREAM)
 
94
            self.gpsd_connection.connect((self.HOST, self.PORT))
 
95
            self.gpsd_connection.setblocking(False)
68
96
            self.status = "connected"
69
97
            self.connected = True
70
98
        except:
71
 
            self.status = "Could not connect to GPSD on Localhost, Port 2947"
72
 
            print "Could not connect"
 
99
            text = "Could not connect to GPSD!"
 
100
            logger.warning(text)
 
101
            self.status = text
73
102
            self.connected = False
74
103
 
75
104
    def get_data(self):
124
153
                splitted = data.split(' ')
125
154
                lat, lon, alt, err_hor = splitted[3:7]
126
155
                track, speed = splitted[8:10]
 
156
                err_track = splitted[11]
 
157
                time = datetime.utcfromtimestamp(int(float(splitted[1])))
127
158
            except:
128
 
                print "GPSD Output: \n%s\n  -- cannot be parsed." % data
 
159
                logger.info("GPSD Output: \n%s\n  -- cannot be parsed." % data)
129
160
                self.status = "Could not read GPSD output."
 
161
                return Fix()
130
162
            alt = self.to_float(alt)
131
163
            track = self.to_float(track)
132
164
            speed = self.to_float(speed)
133
165
            err_hor = self.to_float(err_hor)
 
166
            err_track = self.to_float(err_track)
134
167
 
135
168
            # the following is probably wrong:
136
169
            #
153
186
            #self.speeds.append(speed)
154
187
            #print "Aktuell %f, max: %f" % (speed, max(self.speeds))
155
188
 
156
 
            if speed < self.BEARING_HOLD_SPEED:
157
 
                track = self.last_bearing
158
 
            else:
159
 
                self.last_bearing = track
160
189
            return Fix(
161
190
                position =geo.Coordinate(float(lat), float(lon)),
162
191
                altitude = alt,
166
195
                sats_known = sats_known,
167
196
                dgps = dgps,
168
197
                quality = quality,
169
 
                error = err_hor
 
198
                error = err_hor,
 
199
                error_bearing = err_track,
 
200
                timestamp = time
170
201
                )
171
 
        except Exception as e:
172
 
            print "Fehler beim Auslesen der Daten: %s " % e
 
202
        except Exception, e:
 
203
            logger.exception("Fehler beim Auslesen der Daten: %s " % e)
173
204
            return self.EMPTY
174
205
 
175
206
    @staticmethod
179
210
        except:
180
211
            return 0.0
181
212
 
 
213
class LocationGpsReader():
 
214
    TIMEOUT = 5
 
215
    BEARING_HOLD_SPEED = 2.5 # km/h
 
216
 
 
217
    def __init__(self, cb_error, cb_changed):
 
218
        logger.info("Using liblocation GPS device")
 
219
 
 
220
        control = location.GPSDControl.get_default()
 
221
        device = location.GPSDevice()
 
222
        control.set_properties(preferred_method = location.METHOD_CWP | location.METHOD_ACWP | location.METHOD_GNSS | location.METHOD_AGNSS, preferred_interval=location.INTERVAL_1S)
 
223
        control.connect("error-verbose", cb_error)
 
224
        device.connect("changed", cb_changed)
 
225
        self.last_gps_bearing = 0
 
226
        self.control = control
 
227
        self.device = device
 
228
 
 
229
 
 
230
    def start(self):
 
231
        self.control.start()
 
232
        return False
 
233
 
 
234
    @staticmethod
 
235
    def get_error_from_code(error):
 
236
        if error == location.ERROR_USER_REJECTED_DIALOG:
 
237
            return "Requested GPS method not enabled"
 
238
        elif error == location.ERROR_USER_REJECTED_SETTINGS:
 
239
            return "Location disabled due to change in settings"
 
240
        elif error == location.ERROR_BT_GPS_NOT_AVAILABLE:
 
241
            return "Problems with BT GPS"
 
242
        elif error == location.ERROR_METHOD_NOT_ALLOWED_IN_OFFLINE_MODE:
 
243
            return "Requested method is not allowed in offline mode"
 
244
        elif error == location.ERROR_SYSTEM:
 
245
            return "System error"
 
246
 
 
247
    def fix_from_tuple(self, f, device):
 
248
        a = Fix()
 
249
        # check if this is an actual fix
 
250
        if (not f[1] & (location.GPS_DEVICE_LATLONG_SET | location.GPS_DEVICE_ALTITUDE_SET | location.GPS_DEVICE_TRACK_SET)):
 
251
            return a
 
252
 
 
253
        # location independent data
 
254
        a.sats = device.satellites_in_use
 
255
        a.sats_known = device.satellites_in_view
 
256
        a.dgps = False
 
257
        a.quality = 0
 
258
 
 
259
 
 
260
 
 
261
        # if this fix is too old, discard it
 
262
        if f[2] == f[2]: # is not NaN
 
263
            a.timestamp = datetime.utcfromtimestamp(f[2])
 
264
        else:
 
265
            a.timestamp = datetime.utcfromtimestamp(0)
 
266
 
 
267
        Fix.min_timediff = min(Fix.min_timediff, datetime.utcnow() - a.timestamp)
 
268
        # if this fix is too old, discard it
 
269
        if ((datetime.utcnow() - a.timestamp) - Fix.min_timediff).seconds > LocationGpsReader.TIMEOUT:
 
270
            logger.info("Discarding fix: Timestamp diff is %d, should not be > %d" % (((datetime.utcnow() - a.timestamp) - Fix.min_timediff).seconds, LocationGpsReader.TIMEOUT))
 
271
            return a
 
272
 
 
273
        # now on for location dependent data
 
274
        #if f[10] > Fix.BEARING_HOLD_EPD:
 
275
        #    a.bearing = Fix.last_bearing
 
276
        #else:
 
277
        a.altitude = f[7]
 
278
        a.speed = f[11]
 
279
        if a.speed > self.BEARING_HOLD_SPEED:
 
280
            a.bearing = f[9]
 
281
            self.last_gps_bearing = a.bearing
 
282
        else:
 
283
            a.bearing = self.last_gps_bearing
 
284
 
 
285
        #    Fix.last_bearing = a.bearing
 
286
        a.position = geo.Coordinate(f[4], f[5])
 
287
 
 
288
        a.error = f[6]/100.0
 
289
        a.error_bearing = f[10]
 
290
 
 
291
        return a
182
292
 
183
293
class FakeGpsReader():
184
294
 
185
295
 
186
 
    START_LAT = 49.6
187
 
    START_LON = 6.6
188
 
    INC = 0.001
 
296
    INC = 0.0001
189
297
    
190
298
 
191
 
    def __init__(self, gui):
192
 
        self.gui = gui
193
 
        self.status = "faking..."
194
 
        self.current_lat, self.current_lon = (self.START_LAT, self.START_LON)
 
299
    def __init__(self, something):
 
300
        self.status = "Fake GPS reader."
 
301
        self.index = -1
 
302
        self.data = [x.split('\t') for x in self.TESTDATA.split("\n")]
 
303
        self.lastpos = None
 
304
 
 
305
    @staticmethod
 
306
    def get_target():
 
307
        return geo.Coordinate(50.0000798795372000, 6.9949468020349700)
195
308
 
196
309
    def get_data(self):
197
 
        print "faking"
198
 
        self.current_lat += self.INC
199
 
        self.current_lon += self.INC
 
310
        import random
 
311
        if self.index < len(self.data) - 1:
 
312
            self.index += 1
 
313
        if self.data[self.index][0] == '0':
 
314
            return Fix()
 
315
        pos = geo.Coordinate(float(self.data[self.index][0]), float(self.data[self.index][1]))
 
316
 
 
317
        if self.lastpos != None:
 
318
            bearing = self.lastpos.bearing_to(pos)
 
319
        else:
 
320
            bearing = 0
 
321
        self.lastpos = pos
200
322
        return Fix(
201
 
            position =geo.Coordinate(self.current_lat, self.current_lon),
202
 
            altitude = 212,
203
 
            bearing = 120,
204
 
            speed = 2,
205
 
            sats = 42,
206
 
            sats_known = 42,
 
323
            position = pos,
 
324
            altitude = 5,
 
325
            bearing = bearing,
 
326
            speed = 4,
 
327
            sats = 12,
 
328
            sats_known = 6,
207
329
            dgps = True,
208
 
            quality = 0
209
 
            )
 
 
b'\\ No newline at end of file'
 
330
            quality = 0,
 
331
            error = random.randrange(10, 100),
 
332
            error_bearing = 10
 
333
            )
 
334
 
 
335
    TESTDATA = '''0     0
 
336
0       0
 
337
0       0
 
338
50.0000000000000000     7.0000000000000000
 
339
49.9999706633389000     7.0001229625195300
 
340
49.9997950624675000     7.0003442447632600
 
341
49.9997997563332000     7.0004659499973100
 
342
49.9997218046337000     7.0005903374403700
 
343
49.9995578546077000     7.0006271339952900
 
344
49.9994435254484000     7.0008635874837600
 
345
49.9993037991226000     7.0009828619659000
 
346
49.9992146994919000     7.0010608136653900
 
347
49.9991217441857000     7.0012173876166300
 
348
49.9990843608975000     7.0012444611638800
 
349
49.9990095943213000     7.0015110895037700
 
350
49.9988885596395000     7.0016821641475000
 
351
0       0
 
352
0       0
 
353
0       0
 
354
49.9987537786365000     7.0018086470663600
 
355
49.9985118769109000     7.0020990800112500
 
356
49.9983842205256000     7.0021572504192600
 
357
49.9982605036348000     7.0022816378623300
 
358
49.9980872496963000     7.0023336894810200
 
359
49.9979986529797000     7.0024224538356100
 
360
49.9979185219854000     7.0025429017841800
 
361
49.9978181067854000     7.0025481823831800
 
362
49.9976762011647000     7.0025224499404400
 
363
49.9975882750005000     7.0024726614356000
 
364
49.9974449444562000     7.0023075379431300
 
365
49.9973412603140000     7.0022041890770200
 
366
49.9972049705684000     7.0021101441234400
 
367
0       0
 
368
0       0
 
369
0       0
 
370
49.9970952514559000     7.0020336173474800
 
371
49.9969987757504000     7.0019501335918900
 
372
49.9968421179801000     7.0017190445214500
 
373
49.9967520125210000     7.0016104150563500
 
374
49.9966504238546000     7.0015143584460000
 
375
49.9965638387948000     7.0014302041381600
 
376
49.9964761640877000     7.0013357400894200
 
377
49.9963049218059000     7.0011528469622100
 
378
49.9962143134326000     7.0009845383465300
 
379
49.9961593281478000     7.0008703768253300
 
380
49.9960857350379000     7.0007528625428700
 
381
49.9960248824209000     7.0006081908941300
 
382
49.9959259759635000     7.0004951190203400
 
383
49.9958231300116000     7.0003485195338700
 
384
49.9957155063748000     7.0002043507993200
 
385
49.9956013448536000     7.0000658817589300
 
386
49.9954995047301000     6.9999083019793000
 
387
49.9954301863909000     6.9997342936694600
 
388
49.9954084772617000     6.9995050486177200
 
389
49.9953969940543000     6.9992866162210700
 
390
49.9965626653284000     6.9970068223774400
 
391
49.9966021440923000     6.9968105182051700
 
392
49.9968151282519000     6.9966180697083500
 
393
49.9971344787627000     6.9964923411607700
 
394
49.9972403421998000     6.9964339192956700
 
395
49.9973804876208000     6.9963862262666200
 
396
49.9979287479073000     6.9956857506185800
 
397
49.9980570748448000     6.9955223873257600
 
398
49.9982320051640000     6.9954270012676700
 
399
49.9984868150204000     6.9951742030680200
 
400
49.9985938519239000     6.9949829280376400
 
401
49.9986792635173000     6.9948330596089400
 
402
49.9987863004208000     6.9947258550673700
 
403
49.9990340694785000     6.9947269447147800
 
404
49.9992224946618000     6.9946833588182900
 
405
49.9994972534478000     6.9947828520089400
 
406
49.9996298551559000     6.9948167987167800
 
407
49.9997046217322000     6.9948615580797200
 
408
49.9997673183680000     6.9949107598513400
 
409
49.9999811407179000     6.9948655813932400
 
410
50.0000479444861000     6.9948898889124400
 
411
50.0000799633563000     6.9948716163635300
 
412
50.0000798795372000     6.9949468020349700'''
 
413
    pass
 
414