PyXR

c:\projects\bitpim\src \ phone_detect.py



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2004 Joe Pham <djpham@bitpim.org>
0004 ###
0005 ### This program is free software; you can redistribute it and/or modify
0006 ### it under the terms of the BitPim license as detailed in the LICENSE file.
0007 ###
0008 ### $Id: phone_detect.py 4656 2008-08-02 15:57:20Z hjelmn $
0009 
0010 """
0011 Auto detect of phones.
0012 This module provides functionality to perform auto-detection of connected phone.
0013 To implement auto-detection for your phone, perform the following:
0014 
0015 1.  If your phone can be determined by examining the Phone Manufacturer and
0016 Phone Model values returned by +GMI and +GMM commands, just set the following
0017 attributes in your Profile class:
0018 
0019 phone_manufacturer='string'
0020 phone_model='string'
0021 
0022 The phone_manufacturer attribute will be checked for substring ie, 'SAMSUNG' in
0023 'SAMSUNG ELECTRONICS CO.,LTD.'; phone_model must match exactly.
0024 
0025 2.  If your phone detection scheme is more complex, define a staticmethod
0026 'detectphone' in your Phone class.  The declaration of the method is:
0027 
0028 def detectphone(ports, likely_ports, detect_dict)
0029 
0030 ports: list of available ports returned from comscan
0031 likely_ports: list of likely ports as returned from comdiagnose.islikelyport,
0032             ie ['com1', 'com2'].
0033 where detect_dict is a dict with the following key/value pairs:
0034 'port': {
0035 'mode_modem': True if the phone can be set to modem mode, False otherwise
0036 'mode_brew': True if the phone can be set to DM mode, False otherwise.  This
0037              value is not currently set since I'm not sure all phones can
0038              transition out of DM mode.
0039 'manufacturer': string value returned by +GMI
0040 'model': string value returned by +GMM
0041 'firmware_version': string value returned by +GMR
0042 'esn': ESN value of this phone, will be used to associate a name with it.
0043 'firmwareresponse': response data based on BREW firmwarerequest command.
0044                     Currently not implemented.
0045 }
0046 
0047 If a possitive identification is made, method detectphone should return the
0048 port associated with that phone, otherwise just return None.
0049 
0050 """
0051 
0052 # standard modules
0053 import Queue
0054 import threading
0055 
0056 # wx modules
0057 
0058 # BitPim modules
0059 import comdiagnose
0060 import common
0061 import commport
0062 import comscan
0063 import phones
0064 import usbscan
0065 
0066 class DetectPhone(object):
0067     __default_timeout=1
0068     def __init__(self, log=None):
0069         # get standard commport parameters
0070         self.__log=log
0071         self.__data={}
0072         self.__data_lock=threading.Lock()
0073         self.__q_log=Queue.Queue(0)
0074         self.__q_on=False
0075 
0076     def log(self, log_str):
0077         if self.__log is None:
0078             print log_str
0079         else:
0080             if self.__q_on:
0081                 self.__q_log.put_nowait(log_str)
0082             else:
0083                 self.__log.log(log_str)
0084     def logdata(self, log_str, log_data, klass=None, data_type=None):
0085         if self.__log is None:
0086             print log_str,log_data, klass
0087         else:
0088             if self.__q_on:
0089                 self.__q_log.put_nowait((log_str, log_data, klass, data_type))
0090             else:
0091                 self.__log.logdata(log_str, log_data, klass, data_type)
0092 
0093     def progress(self, pos, max, desc=""):
0094         if self.__log:
0095             self.__log.progress(pos, max, desc)
0096 
0097     def __get_mode_modem(self, comm):
0098         """ check if this port supports mode modem"""
0099         try:
0100             resp=comm.sendatcommand('E0V1')
0101             return True
0102         except:
0103             return False
0104     def __send_at_and_get(self, comm, cmd):
0105         try:
0106             resp=comm.sendatcommand(cmd)
0107             return ': '.join(resp[0].split(': ')[1:])
0108         except:
0109             return None
0110     def __get_manufacturer(self, comm):
0111         return self.__send_at_and_get(comm, '+GMI')
0112     def __get_model(self, comm):
0113         return self.__send_at_and_get(comm, '+GMM')
0114     def __get_firmware_version(self, comm):
0115         return self.__send_at_and_get(comm, '+GMR')
0116     def __get_esn(self, comm):
0117         return self.__send_at_and_get(comm, '+GSN')
0118     def __get_mode_brew(self, comm):
0119         raise NotImplementedError
0120 ##        try:
0121 ##            resp=comm.sendatcommand('$QCDMG')
0122 ##            return True
0123 ##        except:
0124 ##            return False
0125     def __get_firmware_response(self, comm):
0126         raise NotImplementedError
0127 
0128     def __get_data(self, port):
0129         r={ 'mode_modem': False, 'mode_brew': False,
0130             'manufacturer': None, 'model': None, 'firmware_version': None,
0131             'esn': None, 'firmwareresponse': None }
0132         try:
0133             c=commport.CommConnection(self, port,
0134                                       timeout=self.__default_timeout)
0135         except:
0136             self.log('Failed to open port: '+port)
0137             return r
0138         r['mode_modem']=self.__get_mode_modem(c)
0139         if r['mode_modem']:
0140             # in modem mode, ok to try other info
0141             r['manufacturer']=self.__get_manufacturer(c)
0142             r['model']=self.__get_model(c)
0143             r['firmware_version']=self.__get_firmware_version(c)
0144             r['esn']=self.__get_esn(c)
0145         c.close()
0146         return r
0147 
0148     def __check_profile(self, profile):
0149         if not hasattr(profile, 'phone_manufacturer') or \
0150            not hasattr(profile, 'phone_model'):
0151             return None
0152         res=None
0153         phone_model=profile.phone_model
0154         phone_manufacturer=profile.phone_manufacturer
0155         deviceclasses=profile.deviceclasses
0156         phone_needsbrew=getattr(profile, 'brew_required', 0)
0157         for k,e in self.__data.items():
0158             match=False
0159             # check to see if the port supports brew if it is required by phone
0160             if phone_needsbrew and not e['mode_brew']:
0161                 continue
0162             if e['manufacturer'] is None or\
0163                e['model'] is None:
0164                 continue
0165             if phone_manufacturer in e['manufacturer'] and \
0166                phone_model==e['model'][:len(phone_model)]:
0167                 return k
0168 
0169     def __check_for_other_cdma(self):
0170         "If no phone is detected see if any of the scanned ports contain a Brew device"
0171         for k,e in self.__data.items():
0172             if e['mode_brew']:
0173                 return k, 'Other CDMA phone'
0174         return None, None
0175                     
0176     def do_get_data(self, port):
0177         self.log('Gathering data on port: '+port)
0178         r=self.__get_data(port)
0179         self.__data_lock.acquire()
0180         self.__data[port]=r
0181         self.__data_lock.release()
0182         self.log('Done on port: '+port)
0183 
0184     def detect(self, using_port=None, using_model=None):
0185         # start the detection process
0186         # 1st, get the list of available ports
0187         coms=comscan.comscan()+usbscan.usbscan()
0188         self.log('coms:'+str(coms))
0189         available_modem_coms=[x['name'] for x in coms if x['available'] \
0190                               and x.get('class', None)=='modem']
0191         if not using_port:
0192             available_coms=[x['name'] for x in coms if x['available']]
0193         else:
0194             available_coms=[using_port]
0195             available_modem_coms=[x for x in available_coms if x in available_modem_coms]
0196         # loop through each port and gather data
0197         self.log('Available ports: '+str(available_coms))
0198         self.log('Available modem ports: '+str(available_modem_coms))
0199         # only try those AT commands on modem ports
0200         # using threads
0201         self.__q_on=True
0202         threads=[threading.Thread(target=self.do_get_data, args=(e,)) \
0203                  for e in available_modem_coms]
0204         for t in threads:
0205             t.start()
0206         for t in threads:
0207             t.join()
0208         self.__q_on=False
0209         while not self.__q_log.empty():
0210             q=self.__q_log.get_nowait()
0211             if isinstance(q, (list, tuple)):
0212                 self.logdata(*q)
0213             else:
0214                 self.log(q)
0215         # non-thread version
0216 ##        for e in available_modem_coms:
0217 ##            self.do_get_data(e)
0218         # go through each phone and ask it
0219 ##        pm=phones.phonemodels
0220         if using_model:
0221             models=[using_model]
0222         else:
0223             models=phones.phonemodels
0224         found_port=found_model=None
0225         for model in models:
0226             self.log('Checking for model: '+model)
0227             module=common.importas(phones.module(model))
0228             # check for detectphone in module.Phone or
0229             # phone_model and phone_manufacturer in module.Profile
0230             if hasattr(module.Phone, 'detectphone'):
0231                 if using_port is None:
0232                     likely_ports=[x['name'] for x in coms if \
0233                                   x['available'] and \
0234                                   comdiagnose.islikelyport(x, module)]
0235                 else:
0236                     likely_ports=[using_port]
0237                 self.log('Likely ports:'+str(likely_ports))
0238                 found_port=getattr(module.Phone, 'detectphone')(coms,
0239                                                                 likely_ports,
0240                                                                 self.__data,
0241                                                                 module,
0242                                                                 self)
0243                 self.log('Detect Phone result: '+`self.__data`)
0244                 if found_port is not None:
0245                     self.log('Phone '+model+' returned port:'+`found_port`)
0246                     # found it
0247                     found_model=model
0248                     break
0249             found_port=self.__check_profile(module.Profile)
0250             if found_port is not None:
0251                 found_model=model
0252                 break
0253         if found_port is None and using_port is None and using_model is None:
0254             # if we're not looking for a specific model on a specific port,
0255             # scan for other CDMA phone
0256             found_port, found_model=self.__check_for_other_cdma()
0257         if found_port is not None and found_model is not None:
0258             self.log('Found phone:'+found_model+' port:'+`found_port`)
0259             return { 'port': found_port, 'phone_name': found_model,
0260                      'phone_module': phones.module(found_model),
0261                      'phone_esn': self.__data[found_port]['esn'] }
0262     def get(self):
0263         return self.__data
0264 

Generated by PyXR 0.9.4