Module gpsparser
[hide private]
[frames] | no frames]

Source Code for Module gpsparser

  1  #!/usr/bin/env python 
  2   
  3  __version__ = '$Revision: 4799 $'.split()[1] 
  4  __date__ = '$Date: 2008-11-20 11:09:02 -0400 (Mon, 25 Sep 2006) $'.split()[1] 
  5  __author__ = 'Val Schmidt' 
  6  __doc__ = ''' 
  7  GPSparser, a Python GPS NMEA String parsing module.  
  8   
  9  This module provides GPS NMEA string parsing through the GPSString 
 10  class. A GPSstring is an object whose I{msg} is any ASCII text string 
 11  containing a NMEA GPS string somewhere within it. NMEA strings 
 12  characteristicly start with the leading "$" and end with the *hh where 
 13  hh is the two character checksum. All of the following examples are fine: 
 14   
 15      - C{$GPGGA,154809.00,4305.52462642,N,07051.89568468,W,1,3,4.1,48.971,M,-32.985,M,,*54} 
 16      - C{RTK1_GPS         DATA    2008-11-21T15:48:10.510017      $GPGGA,154809.00,4305.52462642,N,07051.89568468,W,1,3,4.1,48.971,M,-32.985,M,,*5} 
 17      - C{09/12/2003,04:01:46.666,$GPGGA,040145.871,7117.3458,N,15700.3788,W,1,06,1.4,014.6,M,-000.4,M,,*50} 
 18      - C{posnav  2008:226:18:31:34.1365  $INGGA,183133.898,7120.91996,N,15651.72629,W,1,11,0.8,-1.06,M,,,,*19} 
 19   
 20  GPSparser provides methods for extracting the NMEA string from the 
 21  larger set of ASCII characters, verifying its checksum and parsing the 
 22  string's fields. The fields may then be accessed as attributes of GPSString 
 23  (i.e. C{GPSString.latitude}). The complete set of attributes available 
 24  after a string has been parsed can be found in the attribute list 
 25  C{GPSString.fieldnames}. Some fields are not returned, such as those that 
 26  provide units which, by standard or convention, never seem to change.  
 27   
 28  GPSparser is designed for follow-on processing and plotting of values, 
 29  and therefore every effort is made to convert all fields to 
 30  meaningful, numeric values (objects of the Decimal Class). For example, Latitude and 
 31  Longitude are converted to decimal degrees to 10 digits past the 
 32  decimal point. Similarly, GPS fix type in RMC strings are indicated by an "A" 
 33  when the GPS has a fix and a "V" when it does not. These values are 
 34  reported by GPSParser as 1 and 0, respectively.  
 35   
 36  Time in GPS strings are converted to datetime objects (see the 
 37  datetime module). Many NMEA strings contain time-of-day, but not date 
 38  (GGA for example). GPSparser will, by default, convert these strings 
 39  to datetime.time objects. However if the GPSString.date attribute is 
 40  set with a datetime.date object prior to calling the parse() method, a 
 41  full datetime.datetime object will be returned combining the supplied 
 42  date and time parsed from the string. This is a handy way to produce 
 43  full date-time stamps for each string. 
 44   
 45  A common thing to overlook, however, when parsing a file of strings 
 46  from a parent script, in which the times rotate over a UTC day, one 
 47  must be sure to also rotate the value used to set the GPSString.date 
 48  attribute. 
 49   
 50  When the module is called as a script, it will parse a file for a 
 51  single string type, which must be specified on the command-line (see 
 52  C{gpsparser.py -h}). The fields are written in tab-delimited format to 
 53  standard-out. Date-time stamps are written as tab-delimited vectors 
 54  (C{YYYY MM DD HH MM SS}). This format makes reading parsed data files 
 55  into Octave or MATLAB trivial ( C{load('datafile')} ), with the notable 
 56  exception of GSV strings which have variable numbers of fields 
 57  depending on the number of satellites tracked. 
 58   
 59  @author: U{'''+__author__+'''<http://aliceandval.com/valswork>} 
 60  @organization: Center for Coastal and Ocean Mapping, University of New Hampshire  
 61  @version: ''' + __version__ +''' 
 62  @copyright: 2008 
 63  @status: under development 
 64  @license: GPL 
 65   
 66  @todo: Standard method of operation is to parse only a particular string specified 
 67  by the -s flag (e.g. -s GGA ). It would be nicer to be able to specify multiple -s 
 68  flags or a comma delimited list of strings to parsed and have all of them parsed.  
 69  The potential problem is how to tell which is which when you're done? 
 70  ''' 
 71   
 72  import os 
 73  import sys 
 74  import datetime 
 75  import re 
 76  import string 
 77  import decimal as dec 
 78  import pdb 
 79  from operator import xor 
 80  import exceptions  
 81   
82 -class GPSString(object):
83 ''' 84 A GPSString is any string that contains a complete NMEA string someplace 85 within it. The string must start with the leading $ and end with the *hh 86 where hh is the checksum. 87 ''' 88 GPS_IDs = { \ 89 'GGA' : 1, \ 90 'ZDA' : 2, \ 91 'RMC' : 3, \ 92 'GST' : 4, \ 93 'GSV' : 5, \ 94 'VTG' : 6, \ 95 'HDT' : 7 ,\ 96 'PASHR' : 8} 97 98
99 - def __init__(self,msg):
100 ''' 101 Initializes the class with any string containing a single NMEA data string. 102 103 @param msg: The ASCII string containing the NMEA data string. 104 105 ''' 106 self.msg = msg 107 'The message containing the gps string.' 108 self.debug = False 109 'A flag for writing debugging information'
110
111 - def identify(self):
112 ''' 113 This method identifies the string within gps_string, returning an ID index 114 which is required to parse the string. 115 116 Currently the following message types are supported: 117 GGA, ZDA, RMC, GST, GSV, VTG, HDT, PASHR 118 ''' 119 'A dictionary of supported strings and their numeric indentifiers' 120 121 for key in self.GPS_IDs.keys(): 122 if re.search( key, self.msg): 123 self.id = self.GPS_IDs[key] 124 return self.GPS_IDs[key] 125 126 raise NotImplementedError, ("This string is not recognized: " + self.msg)
127
128 - def parse(self):
129 ''' 130 This method pareses a GPSString, defining a set of attributes for the class 131 with the parsing results. How each string is parsed is dependent on the 132 type of string. In any case, the fields returned are defined in 133 "self.fieldnames". 134 135 Before parsing the string's checksum if verified. The GPSString.FailedChecksum 136 exception is raised if the checksum fails. [NOTE: The checksum verification 137 may cause problems for some gps systems which do not calculate the checksum 138 on the proper portion of the string. The NMEA standard specifies calculation 139 on the portions of the string __between__ the leading "$" and "*", but 140 not to include either. ] 141 142 A few general rules are in order. Time stamps are converted to datetime 143 objects. Several GPS strings contain only time fields with no year, month, 144 or day. If gps_string.date is defined with a datetime.date object (i.e. 145 mygpsstring.date = datetime.date(2008,12,1) ) prior to calling the 146 parse() method, the final datetime object will combine the pre-set 147 date with the gps parsed time value. If gps_string.date is not defined 148 the returned datetime object returned from the parse() method will 149 reflect the gps time as a datetime.time() object. 150 151 Latitude and Longitude are converted to decimal degrees with negative 152 values for the Southern and Western hemispheres. They are reported to 8 153 decimal places which equates to just over 1 mm precision. 154 155 Some fields are not parsed because they do not typically change. The 156 units fields of meters for geoid separation in the GGA string is a classic 157 example. 158 159 ''' 160 161 ' Verify Checksum' 162 if not self.checksum(True): 163 raise self.FailedChecksum, ("Checksum: " + self.checksum()) 164 165 166 if self.id == 1: 167 'GGA' 168 exp = '(?P<match>\$..GGA.*)\*(?P<chksum>..)' 169 m = re.search(exp,self.msg) 170 if m: 171 gps_extract = m.group('match') 172 fields = gps_extract.split(',') 173 174 'Handle GGA Fields' 175 self.handlegpstime(fields[1]) 176 self.handle_lat( fields[2], fields[3] ) 177 self.handle_lon ( fields[4], fields[5] ) 178 self.quality = dec.Decimal( fields[6] ) 179 self.svs = dec.Decimal( fields[7] ) 180 self.hdop = dec.Decimal( fields[8]) 181 self.antennaheightMSL = dec.Decimal(fields[9]) 182 try: 183 self.geoid = dec.Decimal(fields[11]) 184 except dec.InvalidOperation: 185 if self.debug: 186 print "The field GEOID Height may not be present." 187 print fields[11] 188 self.geoid = dec.Decimal('NaN') 189 try: 190 self.dgpsage = dec.Decimal(fields[13]) 191 except dec.InvalidOperation: 192 if self.debug: 193 print "The field DGPS Age may not be present." 194 print fields[13] 195 self.dgpspage = dec.Decimal('NaN') 196 try: 197 self.stationid = dec.Decimal(fields[14] ) 198 except dec.InvalidOperation: 199 if self.debug: 200 print "The field DGPS Station ID may not be present." 201 print fields[14] 202 self.stationid = dec.Decimal('NaN') 203 elif self.id == 2: 204 'ZDA' 205 exp = '(?P<match>\$..ZDA.*)\*(?P<chksum>..)' 206 m = re.search(exp,self.msg) 207 if m: 208 gps_extract = m.group('match') 209 fields = gps_extract.split(',') 210 'Handle ZDA Fields' 211 self.datetime = datetime.date(int( fields[4]), \ 212 int(fields[3]), \ 213 int(fields[2])) 214 self.handlegpstime(fields[1]) 215 try: 216 self.tzoffsethours = dec.Decimal( fields[5] ) 217 except dec.InvalidOperation: 218 if self.debug: 219 print "Thef ield Local TZ Offset Hours may not be present." 220 print fields[5] 221 self.tzoffsethours = dec.Decimal('NaN') 222 223 try: 224 self.tzoffsetminutes = dec.Decimal( fields[6] ) 225 except dec.InvalidOperation: 226 if self.debug: 227 print "The field Local TZ Offset Minutes may not be present." 228 print fields[6] 229 self.tzoffsetminutes = dec.Decimal('NaN') 230 231 232 elif self.id == 3: 233 'RMC' 234 exp = '(?P<match>\$..RMC.*)\*(?P<chksum>..)' 235 m = re.search(exp,self.msg) 236 if m: 237 gps_extract = m.group('match') 238 fields = gps_extract.split(',') 239 'Handle RMC Fields' 240 'Getting the date first ensure handlegpstime will return a full' 241 'datetime object' 242 self.datetime.date(int(fields[9][4:6]+2000), 243 int(fields[9][2:4]), 244 int(fields[10][0:2])) 245 self.handlgpstime(fields[1]) 246 if fields[2] == 'A': 247 self.fixstatus = 1 248 else: 249 self.fixstatus = 0 250 self.handlegpslat(fields[3], fields[4]) 251 self.handlegpslon(fields[5], fields[6]) 252 self.knots = fields[7] 253 self.cog = fields[8] 254 255 elif self.id == 4: 256 'GST' 257 exp = '(?P<match>\$..GST.*)\*(?P<chksum>..)' 258 m = re.search(exp,self.msg) 259 if m: 260 gps_extract = m.group('match') 261 fields = gps_extract.split(',') 262 'Handle GST Fields' 263 self.handlegpstime(fields[1]) 264 self.residualrms = dec.Decimal(fields[2]) 265 self.semimajor = dec.Decimal(fields[3]) 266 self.semiminor = dec.Decimal(fields[4]) 267 self.orientation = dec.Decimal(fields[5]) 268 self.lat1sigma = dec.Decimal(fields[6]) 269 self.lon1sigma = dec.Decimal(fields[7]) 270 self.height1sigma = dec.Decimal(fields[8]) 271 272 elif self.id == 5: 273 'GSV' 274 exp = '(?P<match>\$..GSV.*)\*(?P<chksum>..)' 275 m = re.search(exp,self.msg) 276 if m: 277 gps_extract = m.group('match') 278 fields = gps_extract.split(',') 279 'Handle GSV Fields' 280 self.messages = dec.Decimal( fields[1] ) 281 self.messagenum = dec.Decimal ( fields[2] ) 282 self.visibleSVs = dec.Decimal ( fields[3] ) 283 self.PRN = [] 284 self.elevation = [] 285 self.azimuth = [] 286 self.snr = [] 287 if self.debug: 288 print fields 289 for idx in range(4,fields.__len__() - 1, 4): 290 self.PRN.append(dec.Decimal(fields[idx])) 291 self.elevation.append(dec.Decimal(fields[idx + 1])) 292 try: 293 self.azimuth.append(dec.Decimal(fields[idx + 2])) 294 except dec.InvalidOperation: 295 self.azimuth.append(dec.Decimal('NaN')) 296 print "The field Satellite Azimuth may be missing." 297 print fields[idx + 3] 298 try: 299 self.snr.append(dec.Decimal(fields[idx + 3])) 300 except dec.InvalidOperation: 301 # The spec says snr should be null when "not tracking" 302 self.snr.append(dec.Decimal('NaN')) 303 304 elif self.id == 6: 305 'VTG' 306 exp = '(?P<match>\$..VTG.*)\*(?P<chksum>..)' 307 m = re.search(exp,self.msg) 308 if m: 309 gps_extract = m.group('match') 310 fields = gps_extract.split(',') 311 'Handle VTG Fields' 312 self.cog = dec.Decimal(fields[1]) 313 self.knots = dec.Decimal(fields[5]) 314 self.kmph = dec.Decimal(fields[7]) 315 316 317 elif self.id == 7: 318 'HDT' 319 exp = '(?P<match>\$..HDT.*)\*(?P<chksum>..)' 320 m = re.search(exp,self.msg) 321 if m: 322 gps_extract = m.group('match') 323 fields = gps_extract.split(',') 324 'Handle HDT Fields' 325 self.heading = fields[1] 326 elif self.id == 8: 327 'PASHR' 328 exp = '(?P<match>\$PASHR.*)\*(?P<chksum>..)' 329 m = re.search(exp,self.msg) 330 if m: 331 gps_extract = m.group('match') 332 fields = gps_extract.split(',') 333 'Handle PASHR Fields' 334 self.handlegpstime(fields[1]) 335 self.heading = dec.Decimal(fields[2]) 336 self.roll = dec.Decimal(fields[4]) 337 self.pitch = dec.Decimal(fields[5]) 338 self.heave = dec.Decimal(fields[6]) 339 self.rollaccuracy = dec.Decimal(fields[7]) 340 self.pitchaccuracy = dec.Decimal(fields[8]) 341 self.headingaccuracy = dec.Decimal(fields[9]) 342 self.headingalgorithm = dec.Decimal(fields[10]) 343 self.imustatus = dec.Decimal(fields[11]) 344 345 # Create a dictionary of the fields parsed. 346 keys = self.__dict__.keys() 347 keys.remove('debug') 348 keys.remove('msg') 349 keys.remove('id') 350 self.fields = {} 351 for item in keys: 352 self.fields[item] = self.__getattribute__(item)
353
354 - def handlegpstime(self, timestr):
355 ''' 356 An internal method to convert gps time strings to datetime.time objects 357 (default) or datetime.datetime objects when GPSString.date is pre-defined 358 with a datetime.date object. 359 360 @param timestr: A NMEA time string of the form HHMMSS.SSS . 361 362 Since many strings do not contain the date, 363 defining the 'date' attribute of GPSString allows one to manually set 364 the date. 365 ''' 366 tmptime = timestr 367 hour = dec.Decimal(tmptime[0:2]) 368 try: 369 minute = dec.Decimal(tmptime[2:4]) 370 except dec.InvalidOperation: 371 print timestr 372 print tmptime[2:4] 373 print self.msg 374 sys.exit() 375 376 seconds = int(dec.Decimal(tmptime[4:tmptime.__len__()])) 377 microseconds = int( (dec.Decimal(tmptime[4:tmptime.__len__()]) - \ 378 dec.Decimal(seconds) ) * 1000000 ) 379 380 timeval = datetime.time(hour, minute, seconds, microseconds) 381 382 try: 383 self.datetime = datetime.datetime.combine(self.date, timeval) 384 except: 385 self.datetime = timeval
386
387 - def handle_lat(self,lattmp, lathem):
388 ''' 389 Converts latitude strings of arbitrary precision to decimal degrees to 390 10 decimal places of precision (about .000001 meters). 391 392 @param lattmp: The NMEA latitude string. (DDMM.MMMM) 393 @param lathem: The NMEA latitude hemisphere ('N'/'S') 394 ''' 395 self.latitude = '%.10f' % (dec.Decimal(lattmp[0:2]) + 396 dec.Decimal(lattmp[3:lattmp.__len__()]) / 60) 397 self.latitude = dec.Decimal(self.latitude) 398 if lathem == 'S': 399 self.latitude = - self.latitude
400
401 - def handle_lon(self,lontmp, lonhem):
402 ''' 403 Converts longitude strings of arbitrary precision to decimal degrees to 404 10 decimal places of precision (about .000001 meters at the equator). 405 406 @param lontmp: The NMEA longitude string. (DDDMM.MMMM) 407 @param lonhem: The NMEA longitude hemisphere ('E'/'W') 408 ''' 409 self.longitude = '%.10f' % (dec.Decimal(lontmp[0:3]) + 410 dec.Decimal(lontmp[4:lontmp.__len__()]) / 60) 411 self.longitude = dec.Decimal(self.longitude) 412 if lonhem == 'W': 413 self.longitude = - self.longitude
414
415 - def stripisotime(self):
416 ''' 417 Strips and ISO 8601 time stamp from the GPSString and returns a datetime 418 object. 419 420 For many scientific applications GPS strings are logged with the 421 logging computer's date-time stamp. When these time stamps are in 422 ISO 8601 format, this method will extract and parse them, returning a 423 datetime object. 424 ''' 425 iso_exp = re.compile('(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d)T(?P<hour>\d\\d):(?P<minute>\d\d):(?P<seconds>\d\d\.\d+)') 426 m = re.search(iso_exp,self.msg) 427 if m: 428 year = int( m.group('year')) 429 month = int( m.group('month')) 430 day = int( m.group('day')) 431 hour = int(m.group('hour')) 432 minute = int(m.group('minute')) 433 seconds = int(float(m.group('seconds'))) 434 microseconds = int( ( float(m.group('seconds')) - seconds ) * 1000000) 435 dts = datetime.datetime(year, month, day, hour, minute, seconds, microseconds) 436 return dts
437
438 - def datetimevec(self,dts):
439 ''' 440 Converts a datetime stamp in the form of a datetime object to a 441 tab-delimited vector of numeric values. 442 443 @param dts: A datetime object. 444 445 For many scientific applications one often desires to import data into MATLAB 446 or Octave. A simple way to do that is to produce a tab-delimited date time 447 stamp of the form: 448 449 YYYY MH DD HR MN SS 450 451 whiich can be converted to MATLABs internal representation of time with 452 datevec(). This method returns such as time stamp from a datetime object. 453 ''' 454 return "\t".join(map(str,( dts.year, dts.month, dts.day, dts.hour, dts.minute, float(dts.second) + float(dts.microsecond) / 1000000 )))
455
456 - def checksum(self, verify = False):
457 ''' 458 A function to calculate and return a checksum of a NMEA string. 459 460 @param verify: When specified as True, checksum returns True/False 461 rather than the acutal checksum value. 462 463 ''' 464 exp = '(?P<match>\$.*)\*(?P<chksum>..)' 465 m = re.search(exp,self.msg) 466 if m: 467 data = m.group('match') 468 tmp = map(ord, data[1:]) 469 checksum = hex(reduce(xor, tmp)) 470 if verify: 471 return checksum[2:4].upper() == m.group('chksum') 472 else: 473 return checksum[2:4].upper()
474 475 # I'm keeping this because I once had code that simply returned the checksum for 476 # a string (that may not be a well-formatted NMEA string) which is required above. 477 # I'm not convinced this level of generality is necessary or appropriate here just yet. 478 479 # if data.find('*') != -1 : 480 # hasstar = True 481 # tmp = map(ord, data[1:data.index('*')]) 482 # else: 483 # tmp = map(ord, data) 484 # 485 # checksum = reduce(xor, tmp) 486 # checksum = hex(checksum) 487 # return checksum[2:4] 488
489 - class FailedChecksum(Warning):
490 ''' 491 A class creating the exception FailedChecksum, which is derived from the 492 standard exception.Warning. This exception is raised when a GPS string's 493 checksum is incorrect indicating corruption to the data. 494 ''' 495 pass
496 497 ###################################################################################### 498 ######################## Module Code Ends Here. ###################################### 499 ###################################################################################### 500 501 if __name__ == '__main__': 502 503 gpstmp = GPSString('') 504 supportedstrings = gpstmp.GPS_IDs.keys() 505 supportedstrings.sort() 506 supportedstrings = ' '.join(supportedstrings) 507 508 from optparse import OptionParser 509 optionparser = OptionParser(usage="%prog [options]", 510 version="%prog "+__version__+' ('+__date__+')') 511 optionparser.add_option('-f','--filename', dest='filename',action='store', 512 help='specify the filename') 513 optionparser.add_option('-s','--stringtype',dest='stringtype',action='store', 514 type='string', help='specify which string to parse by specifying the three-letter identifier (Currently supported strings: '+ supportedstrings + ' )') 515 516 (options,args) = optionparser.parse_args() 517 518 filename = options.filename 519 stringtype = options.stringtype 520 521 for line in file(filename,'r'): 522 gps = GPSString(line) 523 try: 524 id = gps.identify() 525 except NotImplementedError: 526 sys.stderr.write('Unrecognized NMEA string.\n') 527 continue 528 529 'Only handle string specified' 530 if id != gps.GPS_IDs[stringtype]: 531 continue 532 533 'This will die silently if there is not pc timestamp.' 534 PCtime = gps.stripisotime() 535 536 if id == 1: 537 try: 538 gps.date = PCtime.date() 539 except: 540 gps.date = datetime.datetime.utcnow().date() 541 542 try: 543 gps.parse() 544 except gps.FailedChecksum: 545 sys.stderr.write( "Failed Checksum: " + gps.checksum() + 546 " :: " + gps.msg + '\n') 547 continue 548 549 fieldstoprint = [gps.datetimevec(PCtime), 550 gps.datetimevec(gps.datetime), 551 gps.latitude, 552 gps.longitude, 553 gps.quality, 554 gps.svs, 555 gps.hdop, 556 gps.antennaheightMSL, 557 gps.geoid] 558 print "\t".join(map(str,fieldstoprint)).expandtabs() 559 560 if id == 2: 561 try: 562 gps.date = PCtime.date() 563 except: 564 gps.date = datetime.datetime.utcnow().date() 565 566 try: 567 gps.parse() 568 except gps.FailedChecksum: 569 sys.stderr.write( "Failed Checksum: " + gps.checksum() + 570 " :: " + gps.msg + '\n') 571 572 continue 573 574 fieldstoprint = [gps.datetimevec(PCtime), 575 gps.datetimevec(gps.datetime)] 576 577 print "\t".join(map(str,fieldstoprint)).expandtabs() 578 579 if id == 3: 580 try: 581 gps.date = PCtime.date() 582 except: 583 gps.date = datetime.datetime.utcnow().date() 584 try: 585 gps.parse() 586 except self.FailedChecksum: 587 sys.stderr.write( "Failed Checksum: " + gps.checksum() + 588 " :: " + gps.msg + '\n') 589 continue 590 591 fieldstoprint = [gps.datetimevec(PCtime), 592 gps.datetimevec(gps.datetime), 593 gps.fixstatus, 594 gps.latitude, 595 gps.longitude, 596 gps.knots, 597 gps.cog] 598 print "\t".join(map(str,fieldstoprint)).expandtabs() 599 600 if id == 4: 601 try: 602 gps.date = PCtime.date() 603 except: 604 gps.date = datetime.datetime.utcnow().date() 605 606 try: 607 gps.parse() 608 except self.FailedChecksum: 609 sys.stderr.write( "Failed Checksum: " + gps.checksum() + 610 " :: " + gps.msg + '\n') 611 continue 612 613 fieldstoprint = [gps.datetimevec(PCtime), 614 gps.datetimevec(gps.datetime), 615 gps.residualrms, 616 gps.semimajor, 617 gps.semiminor, 618 gps.orientation, 619 gps.lat1sigma, 620 gps.lon1sigma, 621 gps.height1sigma] 622 print "\t".join(map(str,fieldstoprint)).expandtabs() 623 624 if id == 5: 625 try: 626 gps.date = PCtime.date() 627 except: 628 gps.date = datetime.datetime.utcnow().date() 629 630 try: 631 gps.parse() 632 except self.FailedChecksum: 633 sys.stderr.write( "Failed Checksum: " + gps.checksum() + 634 " :: " + gps.msg + '\n') 635 continue 636 637 fieldstoprint = ([gps.datetimevec(PCtime)] + 638 map(str,gps.PRN) + 639 map(str,gps.elevation) + 640 map(str,gps.azimuth) + 641 map(str,gps.snr) ) 642 print "\t".join(map(str,fieldstoprint)).expandtabs() 643 644 645 if id == 6: 646 try: 647 gps.parse() 648 except self.FailedChecksum: 649 sys.stderr.write( "Failed Checksum:" + gps.checksum() + 650 "::" + gps.msg + '\n') 651 continue 652 653 654 655 if id == 8: 656 try: 657 gps.parse() 658 except self.FailedChecksum: 659 sys.stderr.write( "Failed Checksum:" + gps.checksum() + 660 "::" + gps.msg + '\n') 661 continue 662