PyXR

c:\projects\bitpim\src \ phones \ com_phone.py



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