#!/usr/bin/env python
"""
This script talks to a GlobalSat BT-308 GPS receiver in SiRF mode and tells
it to switch to NMEA mode (GSV and RMC messages only; because that's what
Maemo Mapper uses).  I do not know what will happen if you run this script
when the GPS is already in NMEA mode; probably nothing.

You have to bind /dev/rfcomm3 to your GPS device.  Run

    rfcomm bind rfcomm3 xx:xx:xx:xx:xx:xx

(replace xx:xx:xx:xx:xx:xx with the MAC address)

You can find the description of the SiRF protocol at
http://www.usglobalsat.com/downloads/SiRF_Binary_Protocol.pdf

You can tell whether your BT-308 GPS is in NMEA mode by looking at the
green indicator light.  It is always off in SiRF mode (as far as I could tell),
and it is steady/blinks in NMEA mode (blinking = GPS fix; steady = no GPS fix).
"""

DEVICE = "/dev/rfcomm3"


def high_endian(value):
    h, l = divmod(value, 256)
    return chr(h) + chr(l)

def checksum(payload):
    csum = 0
    for c in payload:
        csum += ord(c)
    return high_endian(csum & 0x7FFF)

def sirf_message(payload):
    return ('\xA0\xA2' + high_endian(len(payload)) + payload +
            checksum(payload) + '\xB0\xB3')

def switch_to_nmea():
    mode = '\x02'
        # 0 = Enable NMEA debug messages
        # 1 = Disable NMEA debug messages
        # 2 = Do not change NMEA debug setting
    gga_rate = '\x00' # numer of GGA messages per second; 0 = off
    gga_checksum = '\x01' # 0 = off, 1 = on
    gll_rate = '\x00' # numer of GLL messages per second; 0 = off
    gll_checksum = '\x01' # 0 = off, 1 = on
    gsa_rate = '\x00' # numer of GSA messages per second; 0 = off
    gsa_checksum = '\x01' # 0 = off, 1 = on
    gsv_rate = '\x05' # numer of GSV messages per second; 0 = off
    gsv_checksum = '\x01' # 0 = off, 1 = on
    rmc_rate = '\x01' # numer of RMC messages per second; 0 = off
    rmc_checksum = '\x01' # 0 = off, 1 = on
    vtg_rate = '\x00' # numer of VTG messages per second; 0 = off
    vtg_checksum = '\x01' # 0 = off, 1 = on
    mss_rate = '\x00' # numer of MSS messages per second; 0 = off
    mss_checksum = '\x01' # 0 = off, 1 = on
    zda_rate = '\x00' # numer of ZDA messages per second; 0 = off
    zda_checksum = '\x01' # 0 = off, 1 = on
    baud_rate = high_endian(38400)
    return sirf_message('\x81' + mode + gga_rate + gga_checksum +
                        gll_rate + gll_checksum +
                        gsa_rate + gsa_checksum +
                        gsv_rate + gsv_checksum +
                        rmc_rate + rmc_checksum +
                        vtg_rate + vtg_checksum +
                        mss_rate + mss_checksum +
                        '\x00\x00' +
                        zda_rate + zda_checksum +
                        '\x00\x00' +
                        baud_rate)

def main():
    packet = switch_to_nmea()
    f = open(DEVICE, 'w')
    f.write(packet)
    f.close()

if __name__ == '__main__':
    main()
