Compare with Previous | Blame | View Log
# Script to set the Series 60 phone's time from the GPS time, received # from a GPS Bluetooth receiver. Because Python for Series 60 doesn't # allow access to the current time zone setting, and because the value # returned by the gmtime() function is off by one hour if DST is set, # we have to do some groovy stick handling to convert the GMT/UTC value # returned by the GPS to the proper local time. I welcome suggestions # for better ways of doing this. # # GPL # # Significant assistance and much of the code taken from "S60 Python NMEA Location Viewer" by # Nick Burch - http://gagravarr.org/code/show_nmea_location.py # # Peter Rukavina - Version 0.02 - July 14, 2006 import appuifw import socket import e32 import time # Bluetooth address to connect to # Change this to your GPS's bluetooth address! # On a Mac OS X machine you can see this under System Preferences | Bluetooth | Devices # but you'll have to translate the dashes on the Mac to colons for this script. gps_addr='00:0B:0D:16:D1:BD' # We want icons etc appuifw.app.screen='normal' # Define title etc appuifw.app.title=u"GPS Time" # Connect to the bluetooth GPS using the serial service sock=socket.socket(socket.AF_BT, socket.SOCK_STREAM) target=(gps_addr,1) sock.connect(target) appuifw.note(u"Connected to the GPS") # This is set to 0 to request a quit going = 1 ############################################################################# # Generate the checksum for some data # (Checksum is all the data XOR'd, then turned into hex) def generate_checksum(data): csum = 0 for c in data: csum = csum ^ ord(c) hex_csum = "%02x" % csum return hex_csum.upper() # Turn an NMEA timestamp, along with today's date, into an Epoch time number def format_time(gpstime): import time hh = int(gpstime[0:2]) mm = int(gpstime[2:4]) ss = int(gpstime[4:6]) now = time.gmtime() yyyy = int(now[0]) MM = int(now[1]) dd = int(now[2]) timetuple = (yyyy,MM,dd,hh,mm,ss,0,0,0) return timetuple ############################################################################# def readline(sock): """Read one single line from the socket""" line = "" while 1: char = sock.recv(1) if not char: break line += char if char == "\n": break return line def exit_key_pressed(): """Function called when the user requests exit""" # TODO Figure out why going in the main thread isn't updated going = 0 appuifw.app.exit_key_handler = None ############################################################################# # Get the location from a GGA sentence def get_gga_location(data): d = data.split(',') ret = {} ret['type'] = 'GGA' ret['lat'] = "%s%s" % (d[1],d[2]) ret['long'] = "%s%s" % (d[3],d[4]) ret['time'] = format_time(d[0]) return ret # Get the location from a GLL sentence def get_gll_location(data): d = data.split(',') ret = {} ret['type'] = 'GLL' ret['lat'] = "%s%s" % (d[0],d[1]) ret['long'] = "%s%s" % (d[2],d[3]) ret['time'] = format_time(d[4]) return ret # Get the location from a RMC sentence def get_rmc_location(data): d = data.split(',') ret = {} ret['type'] = 'RMC' ret['lat'] = "%s%s" % (d[2],d[3]) ret['long'] = "%s%s" % (d[4],d[5]) ret['time'] = format_time(d[0]) return ret # Calculate the difference between local time and GMT def calculate_time_diff(utctime): import time ltime = time.localtime() gtime = time.gmtime() # Same day both local and GMT if (gtime[2] == ltime[2]): timediff = ltime[3] - gtime[3] # GMT is a day ahead elif (gtime[2] > ltime[2]): timediff = ltime[3] - (gtime[3] + 12) # GMT is a day behind else: timediff = (ltime[3] + 12) - gtime[3] utchour = utctime[3] gmhour = gtime[3] # If the value returned by gmtime() is greater than the UTC hour, we know we're in DST and # that we thus need to add an hour to the setting of the local time. if (gmhour > utchour): dst = 1 else: dst = 0 lhour = utchour + timediff if (dst == 1): lhour = lhour + 1 timetuple = (utctime[0],utctime[1],utctime[2],lhour,utctime[4],utctime[5],0,0,0) return time.mktime(timetuple) ############################################################################# # Loop while active appuifw.app.exit_key_handler = exit_key_pressed while going == 1: rawdata = readline(sock) if not rawdata: break data = rawdata.strip() # Ensure it starts with $GP if not data[0:3] == '$GP': continue # If it has a checksum, ensure that's correct # (Checksum follows *, and is XOR of everything from # the $ to the *, exclusive) if data[-3] == '*': exp_checksum = generate_checksum(data[1:-3]) if not exp_checksum == data[-2:]: print "Invalid checksum %s, expecting %s" % (data[-2:], exp_checksum) continue # Strip the checksum data = data[:-3] # Grab the parts of the sentence talker = data[1:3] sentence_id = data[3:6] sentence_data = data[7:] # The NMEA sentences we're interested in are: # GGA - Global Positioning System Fix Data # GLL - Geographic Position # RMC - GPS Transit Data location = {} if sentence_id == 'GGA': location = get_gga_location(sentence_data) if sentence_id == 'GLL': location = get_gll_location(sentence_data) if sentence_id == 'RMC': location = get_rmc_location(sentence_data) # If we got a location, print it if not location == {}: # Check the location is valid if location['lat'] == '0000.0000N' and location['long'] == '0000.0000E': print "Invalid GPS location found" else: newtime = calculate_time_diff(location['time']) e32.set_home_time(newtime) appuifw.note(u"Set time to %s" % time.asctime(), 'info') going = 0 print "" # For debugging #print data # All done sock.close() appuifw.app.set_exit()