Ticket #130: gps-logging-improvements.diff
| File gps-logging-improvements.diff, 12.0 KB (added by fso@…, 4 years ago) |
|---|
-
conf/example/frameworkd.conf
diff --git a/conf/example/frameworkd.conf b/conf/example/frameworkd.conf index ec6e84a..89fdbb4 100644
a b device = UBXDevice 53 53 channel = SerialChannel 54 54 path = /dev/ttyACM0 55 55 log_level = INFO 56 # print the status of every channel (SV tracked, etc) every X seconds. 57 # 0 to disable. 58 svprint_interval = 60 59 60 # Logging of UBX packet processing is managed separately as it can be very 61 # verbose. 62 [ogpsd.ubx] 63 log_level = INFO 56 64 57 65 [opreferencesd] 58 66 log_level = DEBUG -
framework/subsystems/ogpsd/ubx.py
diff --git a/framework/subsystems/ogpsd/ubx.py b/framework/subsystems/ogpsd/ubx.py index b6718cc..f4857b0 100644
a b import struct 14 14 import dbus 15 15 from gpsdevice import GPSDevice 16 16 import calendar 17 import time 18 19 from framework.config import config 17 20 18 21 import logging 19 22 logger = logging.getLogger('ogpsd') 23 # Separate logger for ubx packet parsing for extra control. 24 ubxpkt_logger = logging.getLogger('ogpsd.ubx') 20 25 26 CONFIG_MODULE = "ogpsd" 21 27 DBUS_INTERFACE = "org.freesmartphone.GPS" 22 28 23 29 SYNC1=0xb5 … … MSGFMT = { 257 263 # TIM - Timekeeping 258 264 } 259 265 266 # self.gpsfixstatus value constants. 267 STATUS_NO_FIX = 1 268 STATUS_2D_FIX = 2 269 STATUS_3D_FIX = 3 270 271 # status to readable names 272 status_to_name = { 273 STATUS_NO_FIX: "No", 274 STATUS_2D_FIX: "2D", 275 STATUS_3D_FIX: "3D" 276 } 277 278 # GPSfix field values (from UBX spec) 279 GPSFIX_NONE = 0x0 280 GPSFIX_DEAD_RECKONING = 0x01 281 GPSFIX_2D = 0x02 282 GPSFIX_3D = 0x03 283 GPSFIX_GPS_DEAD_RECKONING = 0x04 284 GPSFIX_TIME_ONLY = 0x05 285 286 # GPSfix to gpsfixstatus mapping 287 fix_to_status = { 288 GPSFIX_NONE: STATUS_NO_FIX, 289 GPSFIX_DEAD_RECKONING: STATUS_2D_FIX, 290 GPSFIX_2D: STATUS_2D_FIX, 291 GPSFIX_3D: STATUS_3D_FIX, 292 GPSFIX_GPS_DEAD_RECKONING: STATUS_2D_FIX, 293 GPSFIX_TIME_ONLY: STATUS_NO_FIX 294 } 295 296 # GPSfix to readable names 297 fix_to_name = { 298 GPSFIX_NONE: "None", 299 GPSFIX_DEAD_RECKONING: "Dead reckoning only", 300 GPSFIX_2D: "2D", 301 GPSFIX_3D: "3D", 302 GPSFIX_GPS_DEAD_RECKONING: "GPS + Dead reckoning combined", 303 GPSFIX_TIME_ONLY: "Time only" 304 } 305 306 # Signal Quality Indicator values (from UBX spec) 307 sq_mapping = { 308 0: "Idle", 309 1: "Searching", 310 2: "Searching", 311 3: "Unusable signal", 312 4: "Code lock", 313 5: "Code and Carrier lock", 314 6: "Code and Carrier lock", 315 7: "Receiving data" 316 } 317 260 318 MSGFMT_INV = dict( [ [(CLIDPAIR[clid], le),v + [clid]] for (clid, le),v in MSGFMT.items() ] ) 261 319 262 320 class UBXDevice( GPSDevice ): … … class UBXDevice( GPSDevice ): 267 325 self.buffer = "" 268 326 self.gpschannel = gpschannel 269 327 self.gpschannel.setCallback( self.parse ) 328 self._svcache = {} 329 self._svchn_map = {} 330 self._svprint_interval = 0 331 self._lastsvprint = 0 270 332 271 333 self.ack = {"CFG-PRT" : 0} 272 334 self.ubx = {} … … class UBXDevice( GPSDevice ): 295 357 self.send("CFG-MSG", 3, {"Class" : CLIDPAIR["NAV-DOP"][0] , "MsgID" : CLIDPAIR["NAV-DOP"][1] , "Rate" : 1 }) 296 358 # Send NAV SVINFO 297 359 self.send("CFG-MSG", 3, {"Class" : CLIDPAIR["NAV-SVINFO"][0] , "MsgID" : CLIDPAIR["NAV-SVINFO"][1] , "Rate" : 5 }) 360 # Setup SV status printing 361 self._svprint_interval = config.getInt( CONFIG_MODULE, 362 "svprint_interval", 60 ) 363 self._lastsvprint = time.time() 298 364 299 365 def deconfigure( self ): 300 366 # Disable UBX packets … … class UBXDevice( GPSDevice ): 311 377 # Reset 312 378 self.gpsfixstatus = 0 313 379 self.buffer = "" 380 self._svcache = {} 381 self._svchn_map = {} 382 self._lastsvprint = 0 314 383 self._reset() 315 384 316 385 def parse( self, data ): … … class UBXDevice( GPSDevice ): 319 388 # Find the beginning of a UBX message 320 389 start = self.buffer.find( chr( SYNC1 ) + chr( SYNC2 ) ) 321 390 if start != 0: 322 logger.info( "Discarded data not UBX \"%s\"" % repr(self.buffer[:start]) )391 ubxpkt_logger.debug( "Discarded data not UBX \"%s\"" % repr(self.buffer[:start]) ) 323 392 self.buffer = self.buffer[start:] 324 393 # Minimum packet length is 8 325 394 if len(self.buffer) < 8: … … class UBXDevice( GPSDevice ): 330 399 return 331 400 332 401 if self.checksum(self.buffer[2:length+6]) != struct.unpack("<BB", self.buffer[length+6:length+8]): 333 logger.warning( "UBX packed class 0x%x, id 0x%x, length %i failed checksum" % (cl, id, length) )402 ubxpkt_logger.warning( "UBX packed class 0x%x, id 0x%x, length %i failed checksum" % (cl, id, length) ) 334 403 self.buffer = self.buffer[2:] 335 404 continue 336 405 … … class UBXDevice( GPSDevice ): 341 410 self.buffer = self.buffer[length+8:] 342 411 343 412 def send( self, clid, length, payload ): 344 logger.debug( "Sending UBX packet of type %s: %s" % ( clid, payload ) )413 ubxpkt_logger.debug( "Sending UBX packet of type %s: %s" % ( clid, payload ) ) 345 414 346 415 stream = struct.pack("<BBBBH", SYNC1, SYNC2, CLIDPAIR[clid][0], CLIDPAIR[clid][1], length) 347 416 if length > 0: … … class UBXDevice( GPSDevice ): 356 425 payload_base = payload[0] 357 426 payload_rep = payload[1:] 358 427 if (length - fmt_base[0])%fmt_rep[0] != 0: 359 logger.error( "Cannot send: Variable length message class \428 ubxpkt_logger.error( "Cannot send: Variable length message class \ 360 429 0x%x, id 0x%x has wrong length %i" % ( cl, id, length ) ) 361 430 return 362 431 stream = stream + struct.pack(fmt_base[1], *[payload_base[i] for i in fmt_base[2]]) … … class UBXDevice( GPSDevice ): 389 458 fmt_rep = format[3:] 390 459 # Check if the length matches 391 460 if (length - fmt_base[0])%fmt_rep[0] != 0: 392 logger.error( "Variable length message class 0x%x, id 0x%x \461 ubxpkt_logger.error( "Variable length message class 0x%x, id 0x%x \ 393 462 has wrong length %i" % ( cl, id, length ) ) 394 463 return 395 464 data.append(dict(zip(fmt_base[2], struct.unpack(fmt_base[1], payload[:fmt_base[0]])))) … … class UBXDevice( GPSDevice ): 398 467 data.append(dict(zip(fmt_rep[2], struct.unpack(fmt_rep[1], payload[offset:offset+fmt_rep[0]])))) 399 468 400 469 except KeyError: 401 logger.info( "Unknown message class 0x%x, id 0x%x, length %i" % ( cl, id, length ) )470 ubxpkt_logger.info( "Unknown message class 0x%x, id 0x%x, length %i" % ( cl, id, length ) ) 402 471 return 403 472 404 logger.debug( "Got UBX packet of type %s: %s" % (format[-1] , data ) )473 ubxpkt_logger.debug( "Got UBX packet of type %s: %s" % (format[-1] , data ) ) 405 474 methodname = "handle_"+format[-1].replace("-", "_") 406 475 try: 407 476 method = getattr( self, methodname ) … … class UBXDevice( GPSDevice ): 427 496 428 497 def handle_NAV_STATUS( self, data ): 429 498 data = data[0] 430 fixtranstbl = [ 1, 1, 2, 3, 2, 1 ]431 self.gpsfixstatus = fixtranstbl[ data["GPSfix"] ]432 499 if data["Flags"]&0x01 == 0: 433 self.gpsfixstatus = 1 500 newstatus = STATUS_NO_FIX 501 else: 502 newstatus = fix_to_status.get(data["GPSfix"], STATUS_NO_FIX) 503 if newstatus != self.gpsfixstatus: 504 logger.info( "New fix state from GPS: %s" % 505 fix_to_name.get(data["GPSfix"], "None") ) 506 self.gpsfixstatus = newstatus 434 507 self._updateFixStatus( self.gpsfixstatus ) 435 508 436 509 def handle_NAV_POSLLH( self, data ): 437 510 scaling = 10000000.0 438 if self.gpsfixstatus == 3:511 if self.gpsfixstatus == STATUS_3D_FIX: 439 512 valid = 7 440 elif self.gpsfixstatus == 2:513 elif self.gpsfixstatus == STATUS_2D_FIX: 441 514 valid = 3 442 515 else: 443 516 valid = 0 … … class UBXDevice( GPSDevice ): 446 519 data["LON"]/scaling, data["HEIGHT"]/1000.0 ) 447 520 448 521 def handle_NAV_DOP( self, data ): 449 if self.gpsfixstatus == 3:522 if self.gpsfixstatus == STATUS_3D_FIX: 450 523 valid = 7 451 elif self.gpsfixstatus == 2:524 elif self.gpsfixstatus == STATUS_2D_FIX: 452 525 valid = 2 453 526 else: 454 527 valid = 0 … … class UBXDevice( GPSDevice ): 457 530 data["HDOP"]/100.0, data["VDOP"]/100.0 ) 458 531 459 532 def handle_NAV_VELNED( self, data ): 460 if self.gpsfixstatus == 3:533 if self.gpsfixstatus == STATUS_3D_FIX: 461 534 valid = 7 462 elif self.gpsfixstatus == 2:535 elif self.gpsfixstatus == STATUS_2D_FIX: 463 536 valid = 3 464 537 else: 465 538 valid = 0 … … class UBXDevice( GPSDevice ): 472 545 base = data[0] 473 546 data = data[1:] 474 547 for sat in data: 548 self._cacheSV(sat) 475 549 in_use = bool(sat["Flags"] & 0x01) 476 550 # Don't include satellites that are below the horizon 477 551 # (Gypsy interface requires positive elevation) 478 552 if sat["Elev"] > 0: 479 553 satellites.append( (sat["SVID"], in_use, sat["Elev"], sat["Azim"], sat["CNO"]) ) 480 554 self._updateSatellites( satellites ) 555 if not self._svprint_interval: 556 return 557 print_age = time.time() - self._lastsvprint 558 if not self._lastsvprint or print_age > self._svprint_interval: 559 logger.info( "SV State (%s Fix)" % 560 status_to_name[self.gpsfixstatus]) 561 logger.info( "========" ) 562 t = [ (d[0], sv) for sv, d in self._svcache.items()] 563 for ch, sv in sorted(t): 564 self._logSV("", sv, True, False) 565 logger.info( "========" ) 566 self._lastsvprint = time.time() 567 568 def _cacheSV(self, sv_data): 569 id = sv_data["SVID"] 570 if id == 0: 571 return 572 in_use = bool(sv_data["Flags"] & 0x01) 573 has_orbit = bool(sv_data["Flags"] & 0x04) 574 has_ephm = bool(sv_data["Flags"] & 0x08) 575 qi = sq_mapping.get(sv_data["QI"], "Unknown") 576 data_tuple = (sv_data["chn"], in_use, has_orbit, has_ephm, qi, 577 sv_data["CNO"], sv_data["Elev"], sv_data["Azim"]) 578 txt = None 579 check_channel = False 580 if id not in self._svcache: 581 txt = "New" 582 check_channel = True 583 elif data_tuple[:4] != self._svcache[id][:4]: 584 txt = "Update" 585 if self._svcache[id][0] != data_tuple[0]: 586 txt = "Channel Change" 587 check_channel = True 588 if check_channel: 589 old_sv = self._svchn_map.get(data_tuple[0], None) 590 sv = self._svcache.get(old_sv, (0,)) 591 if old_sv and sv[0] == data_tuple[0]: 592 del self._svcache[old_sv] 593 logger.debug("Removed SV%02d from Ch%02d" % (old_sv, data_tuple[0])) 594 self._svcache[id] = data_tuple 595 self._svchn_map[data_tuple[0]] = id 596 if txt: 597 self._logSV(txt, id) 598 599 def _logSV(self, prefix, svid, full_data=False, log_debug=True): 600 chn, in_use, has_orbit, has_ephm, qi, cno, elev, azim = self._svcache[svid] 601 a_txt = in_use and "*" or "-" 602 o_txt = has_orbit and "O" or "-" 603 e_txt = has_ephm and "E" or "-" 604 data = "%s SV%02d %s%s%s on Ch%02d (%s)" % (prefix, svid, a_txt, o_txt, 605 e_txt, chn, qi) 606 if full_data: 607 data += " at %s dbHz, Elev %s, Azim %s" % (cno, elev, azim) 608 if log_debug: 609 logger.debug( data ) 610 else: 611 logger.info ( data ) 481 612 482 613 def handle_NAV_TIMEUTC( self, data ): 483 614 data = data[0] … … class UBXDevice( GPSDevice ): 495 626 # Ignore ACK packets for now 496 627 def handle_ACK_ACK( self, data ): 497 628 data = data[0] 498 logger.debug("Got ACK %s" % data )629 ubxpkt_logger.debug("Got ACK %s" % data ) 499 630 if (data["ClsID"], data["MsgID"]) == CLIDPAIR["CFG-PRT"]: 500 631 self.ack["CFG-PRT"] = 1 501 632
