fork(1) download
  1. # Basic script to grab the current location from an NMEA bluetooth GPS,
  2. # and log it to the screen
  3. # Also optionally logs periodic location data to a file, so you can see
  4. # where you were
  5. #
  6. # GPL
  7. #
  8. # Nick Burch - v0.01 (15/01/2006)
  9.  
  10. import appuifw
  11. import socket
  12.  
  13. # Bluetooth address to connect to
  14. # Change this to your GPS's bluetooth address!
  15. gps_addr='00:15:4B:01:14:EE'
  16.  
  17. # How many GGA sentences between logging
  18. # Set to 0 to prevent logging
  19. gga_log_interval = 10
  20. gga_log_count = 0
  21.  
  22. # File to log GGA sentences into
  23. gga_log_file = 'e:\\nmea_gga_log.txt'
  24.  
  25. # We want icons etc
  26. appuifw.app.screen='normal'
  27.  
  28. # Define title etc
  29. appuifw.app.title=u"NMEA Location Disp"
  30.  
  31. # Alert them to the GPS we're going to connect to
  32. appuifw.note(u"Will connect to GPS %s" % gps_addr, 'info')
  33.  
  34. # Connect to the bluetooth GPS using the serial service
  35. sock=socket.socket(socket.AF_BT, socket.SOCK_STREAM)
  36. target=(gps_addr,1)
  37. sock.connect(target)
  38.  
  39. appuifw.note(u"Connected to the GPS")
  40.  
  41. # Open the GGA log file, in append mode
  42. gga_log_fh = open(gga_log_file,'a');
  43.  
  44. # This is set to 0 to request a quit
  45. going = 1
  46.  
  47. #############################################################################
  48.  
  49. # Generate the checksum for some data
  50. # (Checksum is all the data XOR'd, then turned into hex)
  51. def generate_checksum(data):
  52. csum = 0
  53. for c in data:
  54. csum = csum ^ ord(c)
  55. hex_csum = "%02x" % csum
  56. return hex_csum.upper()
  57.  
  58. # Format a NMEA timestamp into something friendly
  59. def format_time(time):
  60. hh = time[0:2]
  61. mm = time[2:4]
  62. ss = time[4:]
  63. return "%s:%s:%s UTC" % (hh,mm,ss)
  64.  
  65. # Format a NMEA date into something friendly
  66. def format_date(date):
  67. months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
  68. dd = date[0:2]
  69. mm = date[2:4]
  70. yy = date[4:6]
  71. yyyy = int(yy) + 2000
  72. return "%s %s %d" % (dd, months[(int(mm)-1)], yyyy)
  73.  
  74. #############################################################################
  75.  
  76. def readline(sock):
  77. """Read one single line from the socket"""
  78. line = ""
  79. while 1:
  80. char = sock.recv(1)
  81. if not char: break
  82. line += char
  83. if char == "\n": break
  84. return line
  85.  
  86. def exit_key_pressed():
  87. """Function called when the user requests exit"""
  88. # TODO Figure out why going in the main thread isn't updated
  89. going = 0
  90. appuifw.app.exit_key_handler = None
  91.  
  92. #############################################################################
  93.  
  94. # Get the location from a GGA sentence
  95. def get_gga_location(data):
  96. d = data.split(',')
  97. ret = {}
  98. ret['type'] = 'GGA'
  99. ret['lat'] = "%s%s" % (d[1],d[2])
  100. ret['long'] = "%s%s" % (d[3],d[4])
  101. ret['time'] = format_time(d[0])
  102. return ret
  103.  
  104. # Get the location from a GLL sentence
  105. def get_gll_location(data):
  106. d = data.split(',')
  107. ret = {}
  108. ret['type'] = 'GLL'
  109. ret['lat'] = "%s%s" % (d[0],d[1])
  110. ret['long'] = "%s%s" % (d[2],d[3])
  111. ret['time'] = format_time(d[4])
  112. return ret
  113.  
  114. # Get the location from a RMC sentence
  115. def get_rmc_location(data):
  116. d = data.split(',')
  117. ret = {}
  118. ret['type'] = 'RMC'
  119. ret['lat'] = "%s%s" % (d[2],d[3])
  120. ret['long'] = "%s%s" % (d[4],d[5])
  121. ret['time'] = format_time(d[0])
  122. return ret
  123.  
  124. #############################################################################
  125.  
  126. # Loop while active
  127. appuifw.app.exit_key_handler = exit_key_pressed
  128. while going == 1:
  129. rawdata = readline(sock)
  130. if not rawdata: break
  131. data = rawdata.strip()
  132.  
  133. # Ensure it starts with $GP
  134. if not data[0:3] == '$GP':
  135. continue
  136.  
  137. # If it has a checksum, ensure that's correct
  138. # (Checksum follows *, and is XOR of everything from
  139. # the $ to the *, exclusive)
  140. if data[-3] == '*':
  141. exp_checksum = generate_checksum(data[1:-3])
  142. if not exp_checksum == data[-2:]:
  143. print "Invalid checksum %s, expecting %s" % (data[-2:], exp_checksum)
  144. continue
  145.  
  146. # Strip the checksum
  147. data = data[:-3]
  148.  
  149. # Grab the parts of the sentence
  150. talker = data[1:3]
  151. sentence_id = data[3:6]
  152. sentence_data = data[7:]
  153.  
  154. # The NMEA sentences we're interested in are:
  155. # GGA - Global Positioning System Fix Data
  156. # GLL - Geographic Position
  157. # RMC - GPS Transit Data
  158. location = {}
  159. if sentence_id == 'GGA':
  160. location = get_gga_location(sentence_data)
  161.  
  162. # Log GGA packets periodically
  163. gga_log_count = gga_log_count + 1
  164. if gga_log_count == gga_log_interval:
  165. gga_log_count = 0
  166. gga_log_fh.write(rawdata)
  167. if sentence_id == 'GLL':
  168. location = get_gll_location(sentence_data)
  169. if sentence_id == 'RMC':
  170. location = get_rmc_location(sentence_data)
  171.  
  172. # If we got a location, print it
  173. if not location == {}:
  174. # Check the location is valid
  175. if location['lat'] == '0000.0000N' and location['long'] == '0000.0000E':
  176. print "Invalid GPS location found"
  177. else:
  178. print "Source of location is %s" % location['type']
  179. print "Lat is %s" % location['lat']
  180. print "Long is %s" % location['long']
  181. print "Time is %s" % location['time']
  182. print ""
  183.  
  184. # Future:
  185. # Grab satellites in view from GSV
  186. # Grab satellites in use from GSA
  187. # Grab speed and direction from VTG
  188.  
  189. # For debugging
  190. #print data
  191.  
  192. # All done
  193. sock.close()
  194. gga_log_fh.close()
  195.  
  196. print "All done"
  197. appuifw.app.set_exit()
  198.  
Runtime error #stdin #stdout 0.03s 6656KB
stdin
Standard input is empty
stdout
Standard output is empty