conduit r1401 - in trunk: . conduit/modules/PhoneModule scripts
- From: jstowers svn gnome org
- To: svn-commits-list gnome org
- Subject: conduit r1401 - in trunk: . conduit/modules/PhoneModule scripts
- Date: Fri, 28 Mar 2008 12:28:30 +0000 (GMT)
Author: jstowers
Date: Fri Mar 28 12:28:30 2008
New Revision: 1401
URL: http://svn.gnome.org/viewvc/conduit?rev=1401&view=rev
Log:
2008-03-29 John Stowers <john stowers gmail com>
* conduit/modules/PhoneModule/Data.py:
* conduit/modules/PhoneModule/Gammu.py:
* conduit/modules/PhoneModule/PhoneModule.py:
* conduit/modules/PhoneModule/ScanThreads.py:
* conduit/modules/PhoneModule/__init__.py: Add initial mobile phone support
based on python-bluetooth/bluez and gammu.
* scripts/ListPhones.py: Utility script to list connected phones
Added:
trunk/conduit/modules/PhoneModule/
trunk/conduit/modules/PhoneModule/Data.py
trunk/conduit/modules/PhoneModule/Gammu.py
trunk/conduit/modules/PhoneModule/PhoneModule.py
trunk/conduit/modules/PhoneModule/ScanThreads.py
trunk/conduit/modules/PhoneModule/__init__.py
trunk/scripts/ListPhones.py
Modified:
trunk/ChangeLog
Added: trunk/conduit/modules/PhoneModule/Data.py
==============================================================================
--- (empty file)
+++ trunk/conduit/modules/PhoneModule/Data.py Fri Mar 28 12:28:30 2008
@@ -0,0 +1,306 @@
+# Generated from http://standards.ieee.org/regauth/oui/oui.txt
+MAC_PREFIXES = {
+ 'Sony-Ericsson' : (
+ '00:01:EC',
+ '00:0A:D9',
+ '00:0E:07',
+ '00:0F:DE',
+ '00:12:EE',
+ '00:15:E0',
+ '00:16:20',
+ '00:16:B8',
+ '00:18:13',
+ '00:19:63',
+ '00:1A:75',
+ '00:1B:59',
+ '00:1C:A4',
+ '00:1D:28',
+ '00:1E:45',
+ '00:80:37',
+ ),
+ 'Nokia' : (
+ '00:02:EE',
+ '00:0B:E1',
+ '00:0E:ED',
+ '00:0F:BB',
+ '00:10:B3',
+ '00:11:9F',
+ '00:12:62',
+ '00:13:70',
+ '00:13:FD',
+ '00:14:A7',
+ '00:15:2A',
+ '00:15:A0',
+ '00:15:DE',
+ '00:16:4E',
+ '00:16:BC',
+ '00:17:4B',
+ '00:17:B0',
+ '00:18:0F',
+ '00:18:42',
+ '00:18:8D',
+ '00:18:C5',
+ '00:19:2D',
+ '00:19:4F',
+ '00:19:79',
+ '00:19:B7',
+ '00:1A:16',
+ '00:1A:89',
+ '00:1A:DC',
+ '00:1B:33',
+ '00:1B:AF',
+ '00:1B:EE',
+ '00:1C:35',
+ '00:1C:9A',
+ '00:1C:D4',
+ '00:1C:D6',
+ '00:1D:3B',
+ '00:1D:6E',
+ '00:1D:98',
+ '00:1D:E9',
+ '00:1D:FD',
+ '00:1E:3A',
+ '00:1E:3B',
+ '00:1E:A3',
+ '00:1E:A4',
+ '00:40:43',
+ '00:A0:8E',
+ '00:E0:03',
+ ),
+ 'Siemens' : (
+ '00:01:E3',
+ '00:05:19',
+ '00:0B:23',
+ '00:0B:A3',
+ '00:0D:41',
+ '00:0E:8C',
+ '00:0F:BB',
+ '00:11:06',
+ '00:11:33',
+ '00:13:A3',
+ '00:18:D1',
+ '00:19:28',
+ '00:19:99',
+ '00:1A:D0',
+ '00:1A:E8',
+ '00:1B:1B',
+ '00:1C:06',
+ '00:30:05',
+ '00:50:07',
+ '00:90:40',
+ '00:C0:E4',
+ '08:00:06',
+ ),
+ 'Samsung' : (
+ '00:00:F0',
+ '00:02:78',
+ '00:09:18',
+ '00:0D:AE',
+ '00:0D:E5',
+ '00:0F:73',
+ '00:12:47',
+ '00:12:FB',
+ '00:13:77',
+ '00:15:99',
+ '00:15:B9',
+ '00:16:32',
+ '00:16:6B',
+ '00:16:6C',
+ '00:16:DB',
+ '00:17:C9',
+ '00:17:D5',
+ '00:18:AF',
+ '00:1A:8A',
+ '00:1B:98',
+ '00:1C:43',
+ '00:1D:25',
+ '00:1D:F6',
+ '00:1E:7D',
+ '00:E0:64',
+ ),
+ 'LG' : (
+ '00:05:C9',
+ '00:0B:29',
+ '00:12:56',
+ '00:14:80',
+ '00:19:A1',
+ '00:1C:62',
+ '00:1E:75',
+ '00:1E:B2',
+ '00:50:CE',
+ '00:E0:91',
+ ),
+ 'BenQ' : (
+ '00:03:9D',
+ '00:17:CA',
+ ),
+ 'Motorola' : (
+ '00:01:AF',
+ '00:04:56',
+ '00:04:BD',
+ '00:08:0E',
+ '00:0A:28',
+ '00:0B:06',
+ '00:0C:E5',
+ '00:0E:5C',
+ '00:0E:C7',
+ '00:0F:9F',
+ '00:11:1A',
+ '00:11:80',
+ '00:11:AE',
+ '00:12:25',
+ '00:12:8A',
+ '00:12:C9',
+ '00:13:71',
+ '00:14:04',
+ '00:14:9A',
+ '00:14:E8',
+ '00:15:2F',
+ '00:15:9A',
+ '00:15:A8',
+ '00:16:26',
+ '00:16:75',
+ '00:16:B5',
+ '00:17:00',
+ '00:17:84',
+ '00:17:E2',
+ '00:17:EE',
+ '00:18:A4',
+ '00:18:C0',
+ '00:19:2C',
+ '00:19:5E',
+ '00:19:A6',
+ '00:19:C0',
+ '00:1A:1B',
+ '00:1A:66',
+ '00:1A:77',
+ '00:1A:AD',
+ '00:1A:DB',
+ '00:1A:DE',
+ '00:1B:52',
+ '00:1B:DD',
+ '00:1C:11',
+ '00:1C:12',
+ '00:1C:C1',
+ '00:1C:FB',
+ '00:1D:6B',
+ '00:1D:BE',
+ '00:1E:46',
+ '00:1E:5A',
+ '00:1E:8D',
+ '00:20:40',
+ '00:20:75',
+ '00:A0:BF',
+ '00:C0:F9',
+ '00:E0:0C',
+ ),
+ 'Alcatel' : (
+ '00:07:72',
+ '00:08:9A',
+ '00:0E:86',
+ '00:0F:62',
+ '00:11:3F',
+ '00:11:8B',
+ '00:15:3F',
+ '00:16:4D',
+ '00:17:CC',
+ '00:19:8F',
+ '00:1A:F0',
+ '00:1C:8E',
+ '00:1D:4C',
+ '00:20:32',
+ '00:20:60',
+ '00:20:DA',
+ '00:80:21',
+ '00:80:39',
+ '00:80:9F',
+ '00:A0:81',
+ '00:C0:BE',
+ '00:D0:95',
+ '00:D0:F6',
+ '00:E0:B1',
+ '00:E0:DA',
+ ),
+ 'Sharp' : (
+ '00:17:5C',
+ '00:1C:EE',
+ '08:00:1F'
+ )
+}
+
+GAMMU_CONN_BLUETOOTH_ALL = (
+ 'bluephonet',
+ 'bluefbus',
+ 'bluerfgnapbus',
+ 'blueat',
+ 'blueobex',
+ 'bluerfobex',
+ 'bluerfphonet',
+ 'bluerffbus',
+ 'bluerfat',
+)
+GAMMU_CONN_BLUETOOTH_NOKIA = (
+ 'bluephonet',
+ 'bluefbus',
+ 'bluerfgnapbus',
+ 'bluerfphonet',
+ 'bluerffbus',
+ 'blueat',
+ 'bluerfat',
+ 'blueobex',
+ 'bluerfobex',
+)
+GAMMU_CONN_BLUETOOTH_STANDARD = (
+ 'blueat',
+ 'blueobex',
+ 'bluerfgnapbus',
+)
+GAMMU_CONN_BLUETOOTH = {
+ 'Sony-Ericsson' : GAMMU_CONN_BLUETOOTH_STANDARD,
+ 'Siemens' : GAMMU_CONN_BLUETOOTH_STANDARD,
+ 'BenQ' : GAMMU_CONN_BLUETOOTH_STANDARD,
+ 'Samsung' : GAMMU_CONN_BLUETOOTH_STANDARD,
+ 'LG' : GAMMU_CONN_BLUETOOTH_STANDARD,
+ 'Motorola' : GAMMU_CONN_BLUETOOTH_STANDARD,
+ 'Nokia' : GAMMU_CONN_BLUETOOTH_NOKIA,
+ 'Alcatel' : GAMMU_CONN_BLUETOOTH_STANDARD,
+ 'Sharp' : GAMMU_CONN_BLUETOOTH_STANDARD,
+}
+
+GAMMU_CONN_CABLE = (
+ 'at19200',
+ 'at115200',
+ 'fbusdlr3',
+ 'fbus',
+ 'mbus',
+ 'fbuspl2303',
+ 'phonetblue',
+ 'fbusblue',
+)
+GAMMU_CONN_IRDA = (
+ 'irdaphonet',
+ 'at19200',
+)
+GAMMU_CONN_BLUERF = (
+ 'at19200',
+)
+GAMMU_CONN_DEVICES = (
+ (('/dev/ttyS%d' % i for i in range(3)), GAMMU_CONN_CABLE ),
+ (('/dev/ttyUSB%d' % i for i in range(3)), GAMMU_CONN_CABLE ),
+ (('/dev/ttyACM%d' % i for i in range(3)), GAMMU_CONN_CABLE ),
+ (('/dev/rfrcomm%d' % i for i in range(1)), GAMMU_CONN_BLUERF ),
+ (('/dev/ircomm%d' % i for i in range(1)), GAMMU_CONN_IRDA ),
+ (('/dev/usb/tts/%d' % i for i in range(3)), GAMMU_CONN_CABLE ))
+
+def get_vendor_from_bluetooth_address(address):
+ for vendor in MAC_PREFIXES.keys():
+ if address[:8].upper() in MAC_PREFIXES[vendor]:
+ return vendor
+ return None
+
+def get_connections_from_bluetooth_address(address):
+ vendor = get_vendor_from_bluetooth_address(address)
+ if vendor:
+ return GAMMU_CONN_BLUETOOTH[vendor]
+ return GAMMU_CONN_BLUETOOTH_ALL
+
Added: trunk/conduit/modules/PhoneModule/Gammu.py
==============================================================================
--- (empty file)
+++ trunk/conduit/modules/PhoneModule/Gammu.py Fri Mar 28 12:28:30 2008
@@ -0,0 +1,355 @@
+#FIXME: Proper license and attribution
+#Most code adapted from gammu (GPL2) and phonetooth (GPL2)
+
+import os
+import bluetooth
+import logging
+log = logging.getLogger("modules.Phone")
+
+import conduit.dataproviders.DataProvider as DataProvider
+import conduit.utils as Utils
+import ScanThreads
+import Data
+
+try:
+ import gammu
+ log.info("Module Information: %s" % Utils.get_module_information(gammu, "__version__"))
+ GAMMU_SUPPORTED = True
+except ImportError:
+ log.info("Gammu based phone support disabled")
+ GAMMU_SUPPORTED = False
+
+class GammuPhone:
+ """
+ Encapsulates the basic connection to a phone using gammu.
+ """
+ def __init__(self, address, connection, model=''):
+ """
+ Attempts to connect to the phone at address and connection and
+ get all available phone informatin, like the model, manufacturer, etc.
+ """
+ self.address = address
+ self.connection = connection
+ self.model = model
+ self.isKnownToGammu = False
+ self.info = {}
+
+ self.sm = gammu.StateMachine()
+ self.sm.SetConfig(0, {
+ 'StartInfo' : 'no',
+ 'UseGlobalDebugFile' : 1,
+ 'DebugFile' : '',
+ 'SyncTime' : 'no',
+ 'Connection' : connection,
+ 'LockDevice' : 'no',
+ 'DebugLevel' : 'nothing',
+ 'Device' : address,
+ 'Localize' : None,
+ 'Model' : model}
+ )
+ #dont catch errors thrown here....
+ self.sm.Init()
+ #if we got here, then we managed a rudimentary connection
+ self.info['connection'] = connection
+
+ #catch non fatal errors because some phones might not
+ #support these fields
+ try:
+ self.info['manufacturer'] = self.sm.GetManufacturer()
+ except gammu.ERR_NOTSUPPORTED, gammu.ERR_NOTIMPLEMENTED:
+ self.info['manufacturer'] = "Unknown"
+
+ model = "Unknown"
+ try:
+ m = self.sm.GetModel()
+ if m[0] == '' or m[0] == 'unknown':
+ model = m[1]
+ else:
+ model = m[0]
+ self.isKnownToGammu = True
+ except gammu.ERR_NOTSUPPORTED, gammu.ERR_NOTIMPLEMENTED:
+ model = "Unknown"
+ self.info['model'] = model
+
+ try:
+ self.info['firmware'] = self.sm.GetFirmware()[0]
+ except gammu.ERR_NOTSUPPORTED, gammu.ERR_NOTIMPLEMENTED:
+ self.info['firmware'] = "Unknown"
+
+class Bluetooth(ScanThreads.ScanThread):
+ def __init__(self, foundCallback):
+ ScanThreads.ScanThread.__init__(self)
+ self.foundCallback = foundCallback
+ self.discovery = ScanThreads.DeviceDiscovererFilter(self)
+
+ #keep a track of what phones we have seen, so we dont need to find
+ #their services over and over again
+ # address : name
+ self._phones = {}
+
+ def lookup_model_information(self, address):
+ #try all bluetooth connections
+ for connection in Data.get_connections_from_bluetooth_address(address):
+ log.info("Connecting to %s Using: %s" % (address,connection))
+ try:
+ phone = GammuPhone(address, connection)
+ phone.sm.Terminate()
+ log.info("\t ---> OK (%s)" % ', '.join(phone.info.values()))
+ return phone.info
+
+ except gammu.GSMError, val:
+ log.warn("\t ---> Failed")
+
+ #connection = None means we tried to connect and failed
+ return {
+ 'connection' : None
+ }
+
+ def run(self):
+ while self.is_cancelled() == False:
+ log.info("Beginning Bluetooth Scan")
+ try:
+ self.discovery.find_devices()
+ self.discovery.process_inquiry()
+ for address,info in self._found.items():
+ if address in os.environ.get('PHONE_BLACKLIST',"").split(","):
+ log.info("Skipping %s, blacklisted" % address)
+ continue
+ #Use gammu to lookup the model information. This also tests
+ #if gammu can actually connect to the phone
+ if not info.has_key('connection'):
+ #gammu info
+ info.update(
+ self.lookup_model_information(address)
+ )
+ #services, which may be useful for things like obexftp,
+ #and other dataproviders in the PhoneModule
+ services = bluetooth.find_service(address=address)
+ log.info("Supported services: %s" % ", ".join([i['name'] for i in services]))
+ info['services'] = services
+
+ self.foundCallback(address,info['name'],"bluetooth",info)
+ except bluetooth.BluetoothError:
+ log.warn("Error discovering services")
+
+ self.pause_scanning()
+
+ def cancel(self):
+ ScanThreads.ScanThread.cancel(self)
+ self.discovery.cancel_inquiry()
+
+class Contact:
+ def __init__(self, name, phoneNumber):
+ self.name = name
+ self.phoneNumber = phoneNumber
+
+ def __str__(self):
+ return self.name + " - " + self.phoneNumber
+
+class GammuDataProvider(DataProvider.DataSource):
+
+ _name_ = "Contacts"
+ _module_type_ = "source"
+ _in_type_ = "contact"
+ _out_type_ = "contact"
+
+ #FIXME: What does this mean??
+ MAX_EMPTY_GUESS = 5
+ MAX_EMPTY_KNOWN = 5
+
+ def __init__(self, address, connection):
+ DataProvider.DataSource.__init__(self)
+ self.address = address
+ self.connection = connection
+ #FIXME: Stupid sharp phone obex over bluetooth is broken, so
+ #default to at
+ self.model = "at"
+ self.phone = None
+
+ def get_UID(self):
+ return self.address
+
+ def _guess_num_items(self):
+ return 200
+
+ def _get_first_entry(self):
+ '''
+ Initiates get next sequence.
+
+ Should be implemented in subclases.
+ '''
+ raise NotImplementedError
+
+ def _get_next_entry(self, location):
+ '''
+ Gets next entry.
+
+ Should be implemented in subclases.
+ '''
+ raise NotImplementedError
+
+ def _get_entry(self, location):
+ '''
+ Gets entry.
+
+ Should be implemented in subclases.
+ '''
+ raise NotImplementedError
+
+ def _get_num_items(self):
+ '''
+ Gets status of entries.
+
+ Should be implemented in subclases.
+ '''
+ raise NotImplementedError
+
+ def _parse_entry(self):
+ '''
+ Parses entry.
+
+ Should be implemented in subclases.
+ '''
+ raise NotImplementedError
+
+ def Send(self):
+ '''
+ Sends entries to parent.
+
+ Should be implemented in subclases.
+ '''
+ raise NotImplementedError
+
+ def Run(self):
+ '''
+ UNFINISHED PORT OF WAMMU's SUBCLASSABLE APPROACH FOR GETTING DATA
+ '''
+ guess = False
+ try:
+ total = self._get_num_items()
+ except gammu.GSMError, val:
+ guess = True
+ total = self._guess_num_items()
+
+ remain = total
+
+ data = []
+
+ try:
+ start = True
+ while remain > 0:
+ #if self.canceled:
+ # self.Canceled()
+ # return
+ try:
+ if start:
+ value = self._get_first_entry()
+ start = False
+ else:
+ try:
+ loc = value['Location']
+ except TypeError:
+ loc = value[0]['Location']
+ value = self._get_next_entry(loc)
+ except gammu.ERR_CORRUPTED:
+ log.warn('While reading, entry on location %d seems to be corrupted, ignoring it!' % loc)
+ continue
+ except gammu.ERR_EMPTY:
+ break
+
+ self._parse_entry(value)
+ if type(value) == list:
+ for i in range(len(value)):
+ value[i]['Synced'] = True
+ else:
+ value['Synced'] = True
+ data.append(value)
+ remain = remain - 1
+ except (gammu.ERR_NOTSUPPORTED, gammu.ERR_NOTIMPLEMENTED):
+ location = 1
+ empty = 0
+ while remain > 0:
+ #if self.canceled:
+ # self.Canceled()
+ # return
+ try:
+ value = self._get_entry(location)
+ self._parse_entry(value)
+ if type(value) == list:
+ for i in range(len(value)):
+ value[i]['Synced'] = True
+ else:
+ value['Synced'] = True
+ data.append(value)
+ remain = remain - 1
+ # If we didn't know count and reached end, try some more entries
+ if remain == 0 and guess:
+ remain = 20
+ total = total + 20
+ empty = 0
+ except gammu.ERR_EMPTY, val:
+ empty = empty + 1
+ # If we didn't know count and saw many empty entries, stop right now
+ if empty >= self.MAX_EMPTY_GUESS and guess:
+ break
+ # If we didn't read anything for long time, we bail out (workaround bad count reported by phone)
+ if empty >= self.MAX_EMPTY_KNOWN and remain < 10:
+ self.ShowError(val[0])
+ remain = 0
+ except gammu.ERR_CORRUPTED:
+ log.warn('While reading, entry on location %d seems to be corrupted, ignoring it!' % location)
+ continue
+ except gammu.GSMError, val:
+ log.critical(val[0])
+ return
+ location = location + 1
+ except gammu.ERR_INVALIDLOCATION, val:
+ # if we reached end with guess, it is okay
+ if not guess:
+ log.critical(val[0])
+ return
+ except gammu.GSMError, val:
+ log.critical(val[0])
+ return
+
+ #self.Send(data)
+
+ def refresh(self):
+ if not self.phone:
+ self.phone = GammuPhone(self.address, self.connection, self.model)
+ log.debug("Connected to phone: %s" % (self.phone.info['model']))
+ self.get_all()
+
+ def get_all(self):
+ #phone = ME, sim = SM
+ location = "ME"
+ contactList = []
+
+ status = self.phone.sm.GetMemoryStatus(Type=location)
+ remain = status['Used']
+ log.debug("%s contacts on phone" % remain)
+
+ start = True
+ while remain > 0:
+ if start:
+ entry = self.phone.sm.GetNextMemory(Start=True, Type=location)
+ start = False
+ else:
+ entry = self.phone.sm.GetNextMemory(Location=entry['Location'], Type=location)
+
+ remain = remain - 1
+
+ contact = Contact('', '')
+ for v in entry['Entries']:
+ if v['Type'] == 'Number_General':
+ contact.phoneNumber = v['Value']
+ elif v['Type'] == 'Text_Name':
+ contact.name = v['Value']
+
+ if len(contact.name) > 0 and len(contact.phoneNumber) > 0:
+ print "*"*20,contact
+ #contactList.append(contact)
+
+ return contactList
+
+
Added: trunk/conduit/modules/PhoneModule/PhoneModule.py
==============================================================================
--- (empty file)
+++ trunk/conduit/modules/PhoneModule/PhoneModule.py Fri Mar 28 12:28:30 2008
@@ -0,0 +1,130 @@
+import logging
+log = logging.getLogger("modules.Phone")
+
+import conduit.dataproviders.File as FileDataProvider
+import conduit.dataproviders.DataProvider as DataProvider
+import conduit.dataproviders.DataProviderCategory as DataProviderCategory
+import conduit.utils as Utils
+import conduit.Exceptions as Exceptions
+
+try:
+ import bluetooth
+ MODULES = {
+ "PhoneFactory" : { "type": "dataprovider-factory" },
+ }
+except ImportError:
+ MODULES = {}
+ log.info("Phone support disabled (bluez/python-bluetooth not installed)")
+
+Utils.dataprovider_add_dir_to_path(__file__, "")
+import Gammu
+
+class PhoneFactory(DataProvider.DataProviderFactory):
+ """
+ Looks for phones connected via bluetooth
+ """
+ def __init__(self, **kwargs):
+ DataProvider.DataProviderFactory.__init__(self, **kwargs)
+ self._cats = {}
+ self._phones = {}
+
+ #Scan multiple interfaces at once
+ self.threads = []
+ if Gammu.GAMMU_SUPPORTED:
+ self.threads.append(
+ Gammu.Bluetooth(self._found_phone_callback)
+ #Gammu.Cable
+ )
+ #else:
+ # phonetooth based scan
+
+ def _found_phone_callback(self, address, name, driver, info):
+ #Get/create the named phone category
+ if name not in self._cats:
+ self._cats[name] = DataProviderCategory.DataProviderCategory(
+ name,
+ "phone",
+ address)
+ category = self._cats[name]
+
+ #create the klass for controlling the phone
+ klass = None
+ if driver == "test":
+ self.emit_added(
+ klass=Test,
+ initargs=(address,),
+ category=category
+ )
+ elif driver == "bluetooth":
+ #check it supports obex file transfer class for file dps
+ done = False
+ for i in ObexFileDataProvider.SUPPORTED_BLUETOOTH_CLASSES:
+ if done: break
+ for service in info.get('services',()):
+ if i in service['service-classes']:
+ self.emit_added(
+ klass=ObexFileDataProvider,
+ initargs=(address,),
+ category=category
+ )
+ done = True
+ break
+
+ #check that gammu found a working connection to the phone
+ if info.get('connection',None):
+ if Gammu.GAMMU_SUPPORTED:
+ self.emit_added(
+ klass=Gammu.GammuDataProvider,
+ initargs=(address,info['connection']),
+ category=category
+ )
+ #else phonetooth based contacts
+ #
+
+ else:
+ log.warn("No driver supports %s %s" % (driver,address))
+
+ def probe(self):
+ log.info("Starting Scan Threads")
+ for t in self.threads:
+ t.start()
+
+ def quit(self):
+ log.info("Stopping Scan Threads")
+ for t in self.threads:
+ t.cancel()
+
+class ObexFileDataProvider(FileDataProvider.FolderTwoWay):
+
+ _name_ = "Pictures"
+
+ #FIXME: Does gnomevfs-obexftp support obexpush also?
+ SUPPORTED_BLUETOOTH_CLASSES = (
+ bluetooth.OBEX_FILETRANS_CLASS,
+ )
+
+ def __init__(self, address, *args):
+ FileDataProvider.FolderTwoWay.__init__(
+ self,
+ folder= "obex://[%s]" % address,
+ folderGroupName="Test",
+ includeHidden=False,
+ compareIgnoreMtime=False
+ )
+ self.address = address
+ #FIXME: In the land of GIO, I think I need to gio-mount this
+ #location before I can do anything with it...
+
+ def get_UID(self):
+ return self.address
+
+class Test(DataProvider.DataSource):
+ _name_ = "Test Phone"
+ _description_ = "Test Phone"
+ _module_type_ = "source"
+ def __init__(self, address, *args):
+ DataProvider.DataSource.__init__(self)
+
+ def get_UID(self):
+ return ""
+
Added: trunk/conduit/modules/PhoneModule/ScanThreads.py
==============================================================================
--- (empty file)
+++ trunk/conduit/modules/PhoneModule/ScanThreads.py Fri Mar 28 12:28:30 2008
@@ -0,0 +1,63 @@
+import logging
+log = logging.getLogger("modules.Phone")
+
+import thread
+
+import threading
+import bluetooth
+import time
+
+import conduit
+
+UNKNOWN_VALUE = "Unknown"
+
+class ScanThread(threading.Thread):
+ SLEEP_TIME = 20
+ SLEEP = 0.1
+ def __init__(self):
+ threading.Thread.__init__(self)
+ self._found = {}
+ self._cancelled = False
+ self._foundLock = threading.Lock()
+
+ def found_phone(self, address, name):
+ #locked because, AIUI, the DeviceDiscover callsback anytime,
+ #from another thread
+ self._foundLock.acquire()
+ if address not in self._found:
+ log.info("Thread %s Found Phone: %s" % (thread.get_ident(),address))
+ self._found[address] = {"name":name}
+ self._foundLock.release()
+
+ def pause_scanning(self):
+ i = 0
+ while ( i < (self.SLEEP_TIME/self.SLEEP) ) and ( self.is_cancelled() == False ):
+ time.sleep(self.SLEEP)
+ i += 1
+
+ def is_cancelled(self):
+ return conduit.GLOBALS.cancelled or self._cancelled
+
+ def cancel(self):
+ self._cancelled = True
+
+class DeviceDiscovererFilter(bluetooth.DeviceDiscoverer):
+ def __init__(self, parent):
+ bluetooth.DeviceDiscoverer.__init__(self)
+ self.parent = parent
+
+ def device_discovered(self, address, device_class, name):
+ '''
+ Called when device is iscovered, checks device is phone
+ '''
+ log.info("Bluetooth Device Discovered: %s %s" % (name,address))
+ major_class = ( device_class & 0xf00 ) >> 8
+ # We want only devices with phone class
+ # See https://www.bluetooth.org/apps/content/?doc_id=49706
+ if major_class == 2:
+ self.parent.found_phone(address, name)
+
+ def inquiry_complete(self):
+ log.debug("Bluetooth Search Complete")
+
+
Added: trunk/conduit/modules/PhoneModule/__init__.py
==============================================================================
--- (empty file)
+++ trunk/conduit/modules/PhoneModule/__init__.py Fri Mar 28 12:28:30 2008
@@ -0,0 +1 @@
+
Added: trunk/scripts/ListPhones.py
==============================================================================
--- (empty file)
+++ trunk/scripts/ListPhones.py Fri Mar 28 12:28:30 2008
@@ -0,0 +1,54 @@
+import sys
+import os.path
+import bluetooth
+import gammu
+
+# make sure we have conduit folder in path!
+my_path = os.path.dirname(__file__)
+base_path = os.path.abspath(os.path.join(my_path, '..'))
+sys.path.insert(0, base_path)
+
+import conduit.Logging as Logging
+import conduit.modules.PhoneModule.Data as Data
+import conduit.modules.PhoneModule.ScanThreads as ScanThreads
+import conduit.modules.PhoneModule.Gammu as Gammu
+
+import logging
+log = logging.getLogger("ListPhones")
+
+class FoundPhones:
+ def __init__(self):
+ self._found = {}
+
+ def found_phone(self, address, name):
+ log.info("Phone Manufacturer: %s" % Data.get_vendor_from_bluetooth_address(address))
+ if address not in self._found:
+ self._found[address] = name
+
+ def lookup_model_information(self):
+ for address,name in self._found.items():
+ if address in os.environ.get('PHONE_BLACKLIST',"").split(","):
+ log.info("Skipping %s, blacklisted" % address)
+ continue
+ #try all bluetooth connections
+ for connection in Data.get_connections_from_bluetooth_address(address):
+ log.info("Connecting to %s Using: %s" % (name,connection))
+ try:
+ phone = Gammu.GammuPhone(address, connection)
+ phone.sm.Terminate()
+ log.info("\t ---> OK (%s)" % ', '.join(phone.info.values()))
+ break
+ except gammu.GSMError, val:
+ log.info("\t ---> Failed")
+
+#discover all the phones
+log.info("Searching for Phones")
+found = FoundPhones()
+discoverer = ScanThreads.DeviceDiscovererFilter(found)
+discoverer.find_devices()
+discoverer.process_inquiry()
+
+#use gammu to get their manufacturer
+found.lookup_model_information()
+
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]