Package phones :: Module com_phone
[hide private]
[frames] | no frames]

Source Code for Module phones.com_phone

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2003-2004 Roger Binns <rogerb@rogerbinns.com> 
  4  ### 
  5  ### This program is free software; you can redistribute it and/or modify 
  6  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  7  ### 
  8  ### $Id: com_phone.py 4768 2009-11-06 02:17:29Z hjelmn $ 
  9   
 10   
 11  """Generic phone stuff that all models inherit from""" 
 12   
 13   
 14  import common 
 15  import commport 
 16  import copy 
 17  import field_color 
 18  import re 
 19  import sys 
 20  import time 
 21  import prototypes 
 22   
 23   
 24  # when trying to setmode, we ignore various exception types 
 25  # since the types are platform specific (eg on windows we get pywintypes.error) 
 26  # so we have to construct the list here of which ones we ignore 
 27  modeignoreerrortypes=[ commport.CommTimeout,common.CommsDeviceNeedsAttention ] 
 28  try: 
 29      import pywintypes 
 30      modeignoreerrortypes.append(pywintypes.error) 
 31  except: 
 32      pass 
 33   
 34  # has to be tuple or it doesn't work 
 35  modeignoreerrortypes=tuple(modeignoreerrortypes)  
 36   
 37   
38 -class Phone(object):
39 """Base class for all phones""" 40 41 MODENONE="modenone" # not talked to yet 42 MODEMODEM="modemodem" # modem mode 43 44 desc="Someone forget to set desc in derived class" 45
46 - def __init__(self, logtarget, commport):
47 self.logtarget=logtarget 48 self.comm=commport 49 self.mode=self.MODENONE 50 self.__msg=None
51
52 - def close(self):
53 self.comm.close() 54 self.comm=None
55
56 - def log(self, str):
57 "Log a message" 58 if self.logtarget: 59 self.logtarget.log("%s: %s" % (self.desc, str))
60
61 - def logdata(self, str, data, klass=None):
62 "Log some data with option data object/class for the analyser" 63 if self.logtarget: 64 self.logtarget.logdata("%s: %s" % (self.desc, str), data, klass)
65
66 - def alert(self, message, wait):
67 """Raises an alert in the main thread 68 69 @param message: The message to display 70 @param wait: Should this function block until the user confirms the message 71 """ 72 assert not wait 73 assert self.logtarget 74 self.logtarget.log("<!= alert wait=%s =!>%s: %s" % (`wait`, self.desc, message))
75
76 - def progress(self, pos, max, desc):
77 "Update the progress meter" 78 if self.logtarget: 79 self.logtarget.progress(pos, max, desc)
80
81 - def raisecommsdnaexception(self, str):
82 "Raise a comms DeviceNeedsAttention Exception" 83 self.mode=self.MODENONE 84 self.comm.shouldloop=True 85 raise common.CommsDeviceNeedsAttention( "The phone is not responding while "+str+".\n\nSee the help for troubleshooting tips", self.desc+" on "+self.comm.port)
86
87 - def raisecommsexception(self, str, klass):
88 self.mode=self.MODENONE 89 raise klass(str, self.desc+" on "+self.comm.port)
90
91 - def setmode(self, desiredmode):
92 "Ensure the phone is in the right mode" 93 if self.mode==desiredmode: return 94 95 strmode=None 96 strdesiredmode=None 97 for v in dir(self): 98 if len(v)>len('MODE') and v[:4]=='MODE': 99 if self.mode==getattr(self, v): 100 strmode=v[4:] 101 if desiredmode==getattr(self,v): 102 strdesiredmode=v[4:] 103 if strmode is None: 104 raise Exception("No mode for %s" %(self.mode,)) 105 if strdesiredmode is None: 106 raise Exception("No desired mode for %s" %(desiredmode,)) 107 strmode=strmode.lower() 108 strdesiredmode=strdesiredmode.lower() 109 110 for func in ( '_setmode%sto%s' % (strmode, strdesiredmode), 111 '_setmode%s' % (strdesiredmode,)): 112 if hasattr(self,func): 113 try: 114 res=getattr(self, func)() 115 except modeignoreerrortypes: 116 res=False 117 if res: # mode changed! 118 self.mode=desiredmode 119 self.log("Now in "+strdesiredmode+" mode") 120 return 121 122 # failed 123 self.mode=self.MODENONE 124 while self.comm.IsAuto(): 125 self.comm.NextAutoPort() 126 return self.setmode(desiredmode) 127 self.raisecommsdnaexception("transitioning mode from %s to %s" \ 128 % (strmode, strdesiredmode))
129 130
131 - def _setmodemodem(self):
132 for baud in (0, 115200, 38400, 19200, 230400): 133 if baud: 134 if not self.comm.setbaudrate(baud): 135 continue 136 self.comm.write("AT\r\n") 137 try: 138 self.comm.readsome() 139 return True 140 except modeignoreerrortypes: 141 pass 142 return False
143
144 - def readobject(self, filename, object_class, logtitle=None, 145 uselocalfs=False):
146 """Read the specified filename and bind it to the object class""" 147 if uselocalfs: 148 self.log('Reading local file: %s'%filename) 149 _buf=prototypes.buffer(file(filename, 'rb').read()) 150 else: 151 _buf=prototypes.buffer(self.getfilecontents(filename)) 152 _obj=object_class() 153 _obj.readfrombuffer(_buf, logtitle=logtitle) 154 return _obj
155
156 - def writeobject(self, filename, obj, logtitle=None, 157 uselocalfs=False):
158 """Writhe the object into the file""" 159 _buf=prototypes.buffer() 160 obj.writetobuffer(_buf, logtitle=logtitle) 161 if uselocalfs: 162 file(filename, 'wb').write(_buf.getvalue()) 163 else: 164 self.writefile(filename, _buf.getvalue())
165 166 getmemo=NotImplemented 167 gettodo=NotImplemented 168 getsms=NotImplemented 169 getcallhistory=NotImplemented 170 getplaylist=NotImplemented 171 gett9db=NotImplemented
172
173 -class Profile(object):
174 175 BP_Calendar_Version=2 176 177 WALLPAPER_WIDTH=100 178 WALLPAPER_HEIGHT=100 179 MAX_WALLPAPER_BASENAME_LENGTH=64 180 WALLPAPER_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789 ." 181 WALLPAPER_CONVERT_FORMAT="bmp" 182 183 MAX_RINGTONE_BASENAME_LENGTH=64 184 RINGTONE_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789 ." 185 DIALSTRING_CHARS="[^0-9PT#*]" 186 187 field_color_data=field_color.default_field_info 188 # delay auto-detection when the phone is plugged in (in seconds) 189 autodetect_delay=0 190 191 # delay in rebooting the phone after a send data and delay between offline and reboot in seconds. 192 reboot_delay=0 193 194 # which usb ids correspond to us 195 usbids=( 196 ) 197 # which device classes we are. 198 deviceclasses=("modem", "serial") 199
200 - def __init__(self):
201 pass
202 203 _supportedsyncs=( 204 ) 205
206 - def SyncQuery(self, source, action, actiontype):
207 if actiontype=='EXCLUSIVE': 208 # Check for exclusive, shoud not be masked by None 209 return (source, action, actiontype) in self._supportedsyncs 210 else: 211 return (source, action, actiontype) in self._supportedsyncs or \ 212 (source, action, None) in self._supportedsyncs
213 214 # fill in the list of ringtone/sound origins on your phone 215 ringtoneorigins=() 216 #e.g. 217 #ringtoneorigins=('ringers', 'sounds') 218 219 # ringtone origins that are not available for the contact assignment 220 excluded_ringtone_origins=() 221 222 # wallpaper origins that are not available for the contact assignment 223 excluded_wallpaper_origins=('video',) 224 225 # fill in your own image origins using these 226 stockimageorigins={ 227 "images": {'meta-help': 'General images'}, 228 "mms": {'meta-help': 'Multimedia Messages'}, 229 "drm": {'meta-help': 'DRM protected images'}, 230 "camera": {'meta-help': 'Camera images'}, 231 "camera-fullsize": {'meta-help': 'Fullsize camera images'}, 232 "video": {'meta-help': 'Video clips'}, 233 "images(sd)": {'meta-help': 'General images stored on removable media'}, 234 "video(sd)": {'meta-help': 'Video clips stored on removable media'}, 235 "picture ids": {'meta-help': 'Images used for contact/group Picture ID'}, 236 } 237 238 stockimagetargets={ 239 # You need to override in your GetTargetsForImageOrigin function and update 240 # for ImgFileInfo fields 241 "wallpaper": {'meta-help': 'Display as wallpaper'}, 242 "pictureid": {'meta-help': 'Display as picture id for a caller'}, 243 "outsidelcd": {'meta-help': 'Display on outside screen'}, 244 "fullscreen": {'meta-help': 'Fullscreen such as startup screen'}, 245 } 246 247 248 # Override in derived class - use this template. Avoid defining new origins - 249 # instead add them to the stock list and use that. That will ensure the 250 # same string and description are used for all phones. 251 imageorigins={} 252 imageorigins.update(common.getkv(stockimageorigins, "images")) 253 imageorigins.update(common.getkv(stockimageorigins, "mms")) 254 imageorigins.update(common.getkv(stockimageorigins, "camera")) 255 imageorigins["<developerneedstoupdate>"]={'meta-help': "The developer needs to update this phone profile"} 256
257 - def GetImageOrigins(self):
258 # Note: only return origins that you can write back to the phone 259 return self.imageorigins
260
261 - def GetTargetsForImageOrigin(self, origin):
262 if False: 263 # this is how you should do it in your derived class. The update dictionary 264 # fields must correspond to what fileinfo.ImgFileInfo uses. The information 265 # is used to save the new file out. 266 targets={} 267 targets.update(common.getkv(self.stockimagetargets, "wallpaper", 268 {'width': 77, 'height': 177, 'format': "BMP"})) 269 targets.update(common.getkv(self.stockimagetargets, "outsidelcd", 270 {'width': 77, 'height': 77, 'format': "JPEG"})) 271 return targets 272 # this code is here to work with the old way we used to do things 273 convert_format_map={'bmp': 'BMP', 274 'jpg': 'JPEG', 275 'png': 'PNG'} 276 return common.getkv(self.stockimagetargets, "wallpaper", 277 {'width': self.WALLPAPER_WIDTH, 278 'height': self.WALLPAPER_HEIGHT, 279 'format': convert_format_map[self.WALLPAPER_CONVERT_FORMAT]})
280 281 282
283 - def QueryAudio(self, origin, currentextension, audiofileinfo):
284 """Query for MP3 file support 285 286 Raise an exception if you cannot support the ringtone or any conversion of 287 it. 288 289 @param audiofileinfo: A L{fileinfo.AudioFileInfo} object specifying file's audio properties 290 @param currentextension: The extension currently used by the file 291 292 @return: ("file extension", audiofile object). The file extension 293 (excluding the leading dot) to make the file use. The audiofile 294 object can be what was passed in unaltered meaning the file is 295 fine as is, or make a new one to specify how the file should 296 be converted. Note there is a MAXSIZE attribute if you need 297 to limit file size. 298 """ 299 # default implementation leaves file unaltered 300 return (currentextension, audiofileinfo)
301
302 - def phonize(self, str):
303 """Convert the phone number into something the phone understands 304 uses DIALSTRING_CHARS to compare phone number with and strips 305 all other characters from the string 306 """ 307 return re.sub(self.DIALSTRING_CHARS, "", str)
308 309
310 -class NoFilesystem:
311
312 - def __raisefna(self, desc):
313 raise common.FeatureNotAvailable(self.desc+" on "+self.comm.port, desc+" is not available with this model phone")
314
315 - def getfirmwareinformation(self):
316 self.__raisefna("getfirmwareinformation")
317
318 - def offlinerequest(self, reset=False, delay=0):
319 self.__raisefna("offlinerequest")
320
321 - def modemmoderequest(self):
322 self.__raisefna("modemmoderequest")
323
324 - def mkdir(self, name):
325 self.__raisefna("filesystem (mkdir)")
326
327 - def mkdirs(self, name):
328 self.__raisefna("filesystem (mkdirs)")
329
330 - def rmdir(self, name):
331 self.__raisefna("filesystem (rmdir)")
332
333 - def rmfile(self, name):
334 self.__raisefna("filesystem (rmfile)")
335
336 - def getfilesystem(self, dir="", recurse=0):
337 self.__raisefna("filesystem (getfilesystem)")
338
339 - def writefile(self, name, contents):
340 self.__raisefna("filesystem (writefile)")
341
342 - def getfilecontents(self, name):
343 self.__raisefna("filesystem (getfilecontents)")
344