0001 ### BITPIM 0002 ### 0003 ### Copyright (C) 2003-2004 Roger Binns <rogerb@rogerbinns.com> 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: com_phone.py 4636 2008-07-21 03:25:38Z djpham $ 0009 0010 0011 """Generic phone stuff that all models inherit from""" 0012 0013 0014 import common 0015 import commport 0016 import copy 0017 import field_color 0018 import re 0019 import sys 0020 import time 0021 import prototypes 0022 0023 0024 # when trying to setmode, we ignore various exception types 0025 # since the types are platform specific (eg on windows we get pywintypes.error) 0026 # so we have to construct the list here of which ones we ignore 0027 modeignoreerrortypes=[ commport.CommTimeout,common.CommsDeviceNeedsAttention ] 0028 try: 0029 import pywintypes 0030 modeignoreerrortypes.append(pywintypes.error) 0031 except: 0032 pass 0033 0034 # has to be tuple or it doesn't work 0035 modeignoreerrortypes=tuple(modeignoreerrortypes) 0036 0037 0038 class Phone(object): 0039 """Base class for all phones""" 0040 0041 MODENONE="modenone" # not talked to yet 0042 MODEMODEM="modemodem" # modem mode 0043 0044 desc="Someone forget to set desc in derived class" 0045 0046 def __init__(self, logtarget, commport): 0047 self.logtarget=logtarget 0048 self.comm=commport 0049 self.mode=self.MODENONE 0050 self.__msg=None 0051 0052 def close(self): 0053 self.comm.close() 0054 self.comm=None 0055 0056 def log(self, str): 0057 "Log a message" 0058 if self.logtarget: 0059 self.logtarget.log("%s: %s" % (self.desc, str)) 0060 0061 def logdata(self, str, data, klass=None): 0062 "Log some data with option data object/class for the analyser" 0063 if self.logtarget: 0064 self.logtarget.logdata("%s: %s" % (self.desc, str), data, klass) 0065 0066 def alert(self, message, wait): 0067 """Raises an alert in the main thread 0068 0069 @param message: The message to display 0070 @param wait: Should this function block until the user confirms the message 0071 """ 0072 assert not wait 0073 assert self.logtarget 0074 self.logtarget.log("<!= alert wait=%s =!>%s: %s" % (`wait`, self.desc, message)) 0075 0076 def progress(self, pos, max, desc): 0077 "Update the progress meter" 0078 if self.logtarget: 0079 self.logtarget.progress(pos, max, desc) 0080 0081 def raisecommsdnaexception(self, str): 0082 "Raise a comms DeviceNeedsAttention Exception" 0083 self.mode=self.MODENONE 0084 self.comm.shouldloop=True 0085 raise common.CommsDeviceNeedsAttention( "The phone is not responding while "+str+".\n\nSee the help for troubleshooting tips", self.desc+" on "+self.comm.port) 0086 0087 def raisecommsexception(self, str, klass): 0088 self.mode=self.MODENONE 0089 raise klass(str, self.desc+" on "+self.comm.port) 0090 0091 def setmode(self, desiredmode): 0092 "Ensure the phone is in the right mode" 0093 if self.mode==desiredmode: return 0094 0095 strmode=None 0096 strdesiredmode=None 0097 for v in dir(self): 0098 if len(v)>len('MODE') and v[:4]=='MODE': 0099 if self.mode==getattr(self, v): 0100 strmode=v[4:] 0101 if desiredmode==getattr(self,v): 0102 strdesiredmode=v[4:] 0103 if strmode is None: 0104 raise Exception("No mode for %s" %(self.mode,)) 0105 if strdesiredmode is None: 0106 raise Exception("No desired mode for %s" %(desiredmode,)) 0107 strmode=strmode.lower() 0108 strdesiredmode=strdesiredmode.lower() 0109 0110 for func in ( '_setmode%sto%s' % (strmode, strdesiredmode), 0111 '_setmode%s' % (strdesiredmode,)): 0112 if hasattr(self,func): 0113 try: 0114 res=getattr(self, func)() 0115 except modeignoreerrortypes: 0116 res=False 0117 if res: # mode changed! 0118 self.mode=desiredmode 0119 self.log("Now in "+strdesiredmode+" mode") 0120 return 0121 0122 # failed 0123 self.mode=self.MODENONE 0124 while self.comm.IsAuto(): 0125 self.comm.NextAutoPort() 0126 return self.setmode(desiredmode) 0127 self.raisecommsdnaexception("transitioning mode from %s to %s" \ 0128 % (strmode, strdesiredmode)) 0129 0130 0131 def _setmodemodem(self): 0132 for baud in (0, 115200, 38400, 19200, 230400): 0133 if baud: 0134 if not self.comm.setbaudrate(baud): 0135 continue 0136 self.comm.write("AT\r\n") 0137 try: 0138 self.comm.readsome() 0139 return True 0140 except modeignoreerrortypes: 0141 pass 0142 return False 0143 0144 def readobject(self, filename, object_class, logtitle=None, 0145 uselocalfs=False): 0146 """Read the specified filename and bind it to the object class""" 0147 if uselocalfs: 0148 self.log('Reading local file: %s'%filename) 0149 _buf=prototypes.buffer(file(filename, 'rb').read()) 0150 else: 0151 _buf=prototypes.buffer(self.getfilecontents(filename)) 0152 _obj=object_class() 0153 _obj.readfrombuffer(_buf, logtitle=logtitle) 0154 return _obj 0155 0156 def writeobject(self, filename, obj, logtitle=None, 0157 uselocalfs=False): 0158 """Writhe the object into the file""" 0159 _buf=prototypes.buffer() 0160 obj.writetobuffer(_buf, logtitle=logtitle) 0161 if uselocalfs: 0162 file(filename, 'wb').write(_buf.getvalue()) 0163 else: 0164 self.writefile(filename, _buf.getvalue()) 0165 0166 getmemo=NotImplemented 0167 gettodo=NotImplemented 0168 getsms=NotImplemented 0169 getcallhistory=NotImplemented 0170 getplaylist=NotImplemented 0171 gett9db=NotImplemented 0172 0173 class Profile(object): 0174 0175 BP_Calendar_Version=2 0176 0177 WALLPAPER_WIDTH=100 0178 WALLPAPER_HEIGHT=100 0179 MAX_WALLPAPER_BASENAME_LENGTH=64 0180 WALLPAPER_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789 ." 0181 WALLPAPER_CONVERT_FORMAT="bmp" 0182 0183 MAX_RINGTONE_BASENAME_LENGTH=64 0184 RINGTONE_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789 ." 0185 DIALSTRING_CHARS="[^0-9PT#*]" 0186 0187 field_color_data=field_color.default_field_info 0188 # delay auto-detection when the phone is plugged in (in seconds) 0189 autodetect_delay=0 0190 0191 # delay in rebooting the phone after a send data and delay between offline and reboot in seconds. 0192 reboot_delay=0 0193 0194 # which usb ids correspond to us 0195 usbids=( 0196 ) 0197 # which device classes we are. 0198 deviceclasses=("modem", "serial") 0199 0200 def __init__(self): 0201 pass 0202 0203 _supportedsyncs=( 0204 ) 0205 0206 def SyncQuery(self, source, action, actiontype): 0207 if actiontype=='EXCLUSIVE': 0208 # Check for exclusive, shoud not be masked by None 0209 return (source, action, actiontype) in self._supportedsyncs 0210 else: 0211 return (source, action, actiontype) in self._supportedsyncs or \ 0212 (source, action, None) in self._supportedsyncs 0213 0214 # fill in the list of ringtone/sound origins on your phone 0215 ringtoneorigins=() 0216 #e.g. 0217 #ringtoneorigins=('ringers', 'sounds') 0218 0219 # ringtone origins that are not available for the contact assignment 0220 excluded_ringtone_origins=() 0221 0222 # wallpaper origins that are not available for the contact assignment 0223 excluded_wallpaper_origins=('video',) 0224 0225 # fill in your own image origins using these 0226 stockimageorigins={ 0227 "images": {'meta-help': 'General images'}, 0228 "mms": {'meta-help': 'Multimedia Messages'}, 0229 "drm": {'meta-help': 'DRM protected images'}, 0230 "camera": {'meta-help': 'Camera images'}, 0231 "camera-fullsize": {'meta-help': 'Fullsize camera images'}, 0232 "video": {'meta-help': 'Video clips'}, 0233 "images(sd)": {'meta-help': 'General images stored on removable media'}, 0234 "video(sd)": {'meta-help': 'Video clips stored on removable media'}, 0235 } 0236 0237 stockimagetargets={ 0238 # You need to override in your GetTargetsForImageOrigin function and update 0239 # for ImgFileInfo fields 0240 "wallpaper": {'meta-help': 'Display as wallpaper'}, 0241 "pictureid": {'meta-help': 'Display as picture id for a caller'}, 0242 "outsidelcd": {'meta-help': 'Display on outside screen'}, 0243 "fullscreen": {'meta-help': 'Fullscreen such as startup screen'}, 0244 } 0245 0246 0247 # Override in derived class - use this template. Avoid defining new origins - 0248 # instead add them to the stock list and use that. That will ensure the 0249 # same string and description are used for all phones. 0250 imageorigins={} 0251 imageorigins.update(common.getkv(stockimageorigins, "images")) 0252 imageorigins.update(common.getkv(stockimageorigins, "mms")) 0253 imageorigins.update(common.getkv(stockimageorigins, "camera")) 0254 imageorigins["<developerneedstoupdate>"]={'meta-help': "The developer needs to update this phone profile"} 0255 0256 def GetImageOrigins(self): 0257 # Note: only return origins that you can write back to the phone 0258 return self.imageorigins 0259 0260 def GetTargetsForImageOrigin(self, origin): 0261 if False: 0262 # this is how you should do it in your derived class. The update dictionary 0263 # fields must correspond to what fileinfo.ImgFileInfo uses. The information 0264 # is used to save the new file out. 0265 targets={} 0266 targets.update(common.getkv(self.stockimagetargets, "wallpaper", 0267 {'width': 77, 'height': 177, 'format': "BMP"})) 0268 targets.update(common.getkv(self.stockimagetargets, "outsidelcd", 0269 {'width': 77, 'height': 77, 'format': "JPEG"})) 0270 return targets 0271 # this code is here to work with the old way we used to do things 0272 convert_format_map={'bmp': 'BMP', 0273 'jpg': 'JPEG', 0274 'png': 'PNG'} 0275 return common.getkv(self.stockimagetargets, "wallpaper", 0276 {'width': self.WALLPAPER_WIDTH, 0277 'height': self.WALLPAPER_HEIGHT, 0278 'format': convert_format_map[self.WALLPAPER_CONVERT_FORMAT]}) 0279 0280 0281 0282 def QueryAudio(self, origin, currentextension, audiofileinfo): 0283 """Query for MP3 file support 0284 0285 Raise an exception if you cannot support the ringtone or any conversion of 0286 it. 0287 0288 @param audiofileinfo: A L{fileinfo.AudioFileInfo} object specifying file's audio properties 0289 @param currentextension: The extension currently used by the file 0290 0291 @return: ("file extension", audiofile object). The file extension 0292 (excluding the leading dot) to make the file use. The audiofile 0293 object can be what was passed in unaltered meaning the file is 0294 fine as is, or make a new one to specify how the file should 0295 be converted. Note there is a MAXSIZE attribute if you need 0296 to limit file size. 0297 """ 0298 # default implementation leaves file unaltered 0299 return (currentextension, audiofileinfo) 0300 0301 def phonize(self, str): 0302 """Convert the phone number into something the phone understands 0303 uses DIALSTRING_CHARS to compare phone number with and strips 0304 all other characters from the string 0305 """ 0306 return re.sub(self.DIALSTRING_CHARS, "", str) 0307 0308 0309 class NoFilesystem: 0310 0311 def __raisefna(self, desc): 0312 raise common.FeatureNotAvailable(self.desc+" on "+self.comm.port, desc+" is not available with this model phone") 0313 0314 def getfirmwareinformation(self): 0315 self.__raisefna("getfirmwareinformation") 0316 0317 def offlinerequest(self, reset=False, delay=0): 0318 self.__raisefna("offlinerequest") 0319 0320 def modemmoderequest(self): 0321 self.__raisefna("modemmoderequest") 0322 0323 def mkdir(self, name): 0324 self.__raisefna("filesystem (mkdir)") 0325 0326 def mkdirs(self, name): 0327 self.__raisefna("filesystem (mkdirs)") 0328 0329 def rmdir(self, name): 0330 self.__raisefna("filesystem (rmdir)") 0331 0332 def rmfile(self, name): 0333 self.__raisefna("filesystem (rmfile)") 0334 0335 def getfilesystem(self, dir="", recurse=0): 0336 self.__raisefna("filesystem (getfilesystem)") 0337 0338 def writefile(self, name, contents): 0339 self.__raisefna("filesystem (writefile)") 0340 0341 def getfilecontents(self, name): 0342 self.__raisefna("filesystem (getfilecontents)") 0343
Generated by PyXR 0.9.4