#!/usr/bin/python
#
# Copyright (C) 2008 Angus Ainslie <angus.ainslie@gmail.com>.
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import sys
import pygtk
pygtk.require('2.0')
import gtk
import os
import time
import dbus
import subprocess
import os, sys
from stat import *

VERSION = 0.3

class BtGPS :
    def __init__(self):
	self.powerOnBT()
        
	self.bus = dbus.SystemBus()

        self.usage_obj = self.bus.get_object('org.freesmartphone.ousaged', '/org/freesmartphone/Usage')
 	self.usage_obj.RequestResource("GPS")
        #gypsy_obj = self.bus.get_object( 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy' )

        #self.position_control = dbus.Interface( gypsy_obj, 'org.freedesktop.Gypsy.Server' )
        #self.position_iface = dbus.Interface( gypsy_obj, 'org.freedesktop.Gypsy.Position' )

        #position = self.position_iface.GetPosition()

	#print "Position:", position

	if self.btPowerFd == None:
	    return None

        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.connect("delete_event", self.delete_event)
        self.window.connect("destroy", self.destroy)
	self.window.set_title( "Bluetooth GPS" )
        self.window.set_border_width(10)
        self.window.set_size_request(400, 300)
        self.scrolled_window = gtk.ScrolledWindow()
        self.scrolled_window.set_policy(  gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC )

        self.buttonBox = gtk.VBox( False, 1 )
        self.window.add( self.scrolled_window )
        self.scrolled_window.add_with_viewport( self.buttonBox )

        self.buttonBox.show()

        self.startButton = gtk.Button( "Start Bluetooth GPS" )
        self.stopButton = gtk.Button( "Stop Bluetooth GPS" )
        self.quitButton = gtk.Button( "Quit" )

        self.buttonBox.pack_start( self.startButton, True, True, 0 )
        self.buttonBox.pack_start( self.stopButton, True, True, 0 )
        self.buttonBox.pack_start( self.quitButton, True, True, 0 )

        self.startButton.show()
        self.stopButton.show()
        self.quitButton.show()

        self.startButton.connect( "released", self.start )
        self.stopButton.connect( "released", self.stop )
        self.quitButton.connect( "released", self.destroy )

        self.scrolled_window.show()

        self.window.show()
                                                                                                        
    def restoreGPSState( self ) :                                                                       
        if self.gpsPowerFd == None :                                                                    
            return                                                                                      
                                                                                                        
        if self.gpsState == 0 :                                                                           
            os.lseek( self.gpsPowerFd, 0, 0 )                                                             
            os.write( self.gpsPowerFd, '0' )                                                              
                                                                                                          
        os.close( self.gpsPowerFd )    

    def restoreBTState( self ) :
	if self.btPowerFd == None :
	    return

	if self.btState == 0 :
	    os.lseek( self.btPowerFd, 0, 0 )                                                                 
            os.write( self.btPowerFd, '0' )

	os.close( self.btPowerFd )

    def powerOnGPS( self ) :                                                                     
        try :                                                                                   
            self.gpsPowerFd = os.open( "/sys/bus/platform/devices/neo1973-pm-bt.0/power_on", os.O_RDWR )
        except :                                                                                       
            print "not running on a Neo FreeRunner"                                                    
            self.gpsPowerFd = None
            return                                                                                     
                                                                                                       
        self.gpsPowerFd = os.open( "/sys/class/i2c-adapter/i2c-0/0-0073/neo1973-pm-gps.0/pwron", os.O_RDWR ) 

	self.gpsState = os.read( self.gpsPowerFd, 1 )
 
        os.lseek( self.gpsPowerFd, 0, 0 )
        os.write( self.gpsPowerFd, '1' )

    def powerOnBT( self ) :
        try :
            self.btPowerFd = os.open( "/sys/bus/platform/devices/neo1973-pm-bt.0/power_on", os.O_RDWR )
        except :
            print "not running on a Neo FreeRunner"
	    self.btPowerFd = None
            return

        resetFd = os.open( "/sys/bus/platform/devices/neo1973-pm-bt.0/reset", os.O_RDWR )

        print "Running on a Neo FreeRunner"

        self.btState = os.read( self.btPowerFd, 1 )
        os.lseek( self.btPowerFd, 0, 0 )

        os.write( self.btPowerFd, '1' )
        os.write( resetFd, '0' )
        os.lseek( self.btPowerFd, 0, 0 )
        os.lseek( resetFd, 0, 0 )
        time.sleep( 2 ) 
        state = os.read( self.btPowerFd, 1 )
        print "BT radio state : ", state
        if state == 0 :
            print "Uh Oh - Bluttooth bug http://docs.openmoko.org/trac/ticket/1744"
            print "Reseting Bluetooth Radio"
            os.write( resetFd, '1' )
            time.sleep( 1 )
            os.write( resetFd, '0' )

	os.close( resetFd )
	
	while not self.CheckForUSBDev( '0a12', '0001' ) :
	    time.sleep( 0.5 )

    def CheckForUSBDev( self, idVendor, idProduct ):
	sys_path = '/sys/bus/usb/devices/'

	print "Checking ", idVendor, idProduct 
    	
	for f in os.listdir(sys_path):
	    vendor = False
	    product = False
            pathname = os.path.join( sys_path , f )
            mode = os.stat(pathname)[ST_MODE]
            if S_ISDIR(mode):
                # It's a directory, recurse into it
                vendorPath = os.path.join( pathname , 'idVendor' )
                mode = os.stat( vendorPath )[ST_MODE]
            	if S_ISREG(mode):
                    # It's a file, call the callback function
                    vendorFd = os.open( vendorPath, os.O_RDONLY )
		    id = os.read( vendorFd, 4 )
		    os.close( vendorFd )
		    if id == idVendor :
			vendor = True

                productPath = os.path.join( pathname , 'idProduct' )
                mode = os.stat( productPath )[ST_MODE]
                if S_ISREG(mode):
                    # It's a file, call the callback function
                    productFd = os.open( productPath, os.O_RDONLY )
                    id = os.read( productFd, 4 )
                    os.close( productFd )
                    if id == idProduct :
                        product = True

	    if idProduct and idVendor :
		print "Found"
		return True

	print "Not Found"
	return False

    def delete_event( self, arg1, arg2 ):
        print "delete event occurred"
        return False

    def destroy(self, widget, data=None):
	#self.restoreGPSState()
        self.restoreBTState()                                                                            
 	self.usage_obj.ReleaseResource("GPS")
 
        gtk.main_quit()

    def main(self):
        gtk.main()

    def start( self, arg ):
	bus = dbus.SystemBus();

	obj = bus.get_object('org.bluez', '/org/bluez/hci0')
	adapter = dbus.Interface(obj, 'org.bluez.Adapter')

	print 'Currrent mode: %s' % (adapter.GetMode())
	print 'Currrent timeout: %s' % (adapter.GetDiscoverableTimeout())

	adapter.SetMode('discoverable')
	adapter.SetDiscoverableTimeout(dbus.UInt32(60))	

	# This is overkill but if the is an rfcomm process running
	# on /dev/rfcomm0 this script will get badly hungup
	os.system( "killall gpspipe" )
	os.system( "killall rfcomm" )
	
	subprocess.Popen( "/bin/sdptool add SP", shell = True )
	self.pid = subprocess.Popen( 'rfcomm -r watch 0 1 sh -c "gpspipe -r >/dev/rfcomm0" &', shell = True )

    def stop( self, arg ):
	#os.kill( self.pid, 9 )
	os.system( "killall gpspipe" )
	os.system( "killall rfcomm" )

gps = BtGPS()

gps.main()

