PyXR

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



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2008 Stephen Wood <saw@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: com_samsungspha900.py 3918 2007-01-19 05:15:12Z djpham $
0009 
0010 """Communicate with a Samsung SPH-A900"""
0011 
0012 import sha
0013 import re
0014 import struct
0015 
0016 import common
0017 import commport
0018 import p_brew
0019 import p_samsungspha900
0020 import com_brew
0021 import com_phone
0022 import prototypes
0023 import helpids
0024 
0025 numbertypetab=('cell','home','office','pager','none')
0026 
0027 class Phone(com_phone.Phone, com_brew.BrewProtocol):
0028     "Talk to a Samsung SPH-A900 phone"
0029 
0030     desc="SPH-A900"
0031     helpid=helpids.ID_PHONE_SAMSUNGOTHERS
0032     protocolclass=p_samsungspha900
0033     serialsname='spha900'
0034 
0035     MODEPHONEBOOK="modephonebook" # can speak the phonebook protocol
0036 
0037     # jpeg Remove first 124 characters
0038 
0039     imagelocations=(
0040         # offset, index file, files location, origin, maximumentries, header offset
0041         # Offset is arbitrary.  100 is reserved for amsRegistry indexed files
0042         (400, "cam/dldJpeg", "camera", 100, 124),
0043         (300, "cam/jpeg", "camera", 100, 124),
0044         )
0045 
0046     ringtonelocations=(
0047         # offset, index file, files location, type, maximumentries, header offset
0048         )
0049         
0050 
0051     def __init__(self, logtarget, commport):
0052         com_phone.Phone.__init__(self, logtarget, commport)
0053         com_brew.BrewProtocol.__init__(self)
0054         self.numbertypetab=numbertypetab
0055         self.mode=self.MODENONE
0056 
0057     def _setmodephonebook(self):
0058         self.setmode(self.MODEBREW)
0059         req=self.protocolclass.firmwarerequest()
0060         respc=self.protocolclass.firmwareresponse
0061         try:
0062             self.sendpbcommand(req, respc, callsetmode=False)
0063             return 1
0064         except com_phone.modeignoreerrortypes:
0065             pass
0066         try:
0067             self.comm.setbaudrate(38400)
0068             self.sendpbcommand(req, respc, callsetmode=False)
0069             return 1
0070         except com_phone.modeignoreerrortypes:
0071             pass
0072         return 0
0073 
0074     def sendpbcommand(self, request, responseclass, callsetmode=True, writemode=False, numsendretry=0, returnerror=False):
0075         if writemode:
0076             numretry=3
0077         else:
0078             numretry=0
0079             
0080         if callsetmode:
0081             self.setmode(self.MODEPHONEBOOK)
0082         buffer=prototypes.buffer()
0083 
0084         request.writetobuffer(buffer, logtitle="Samsung phonebook request")
0085         data=buffer.getvalue()
0086         firsttwo=data[:2]
0087         data=common.pppescape(data+common.crcs(data))+common.pppterminator
0088         isendretry=numsendretry
0089         while isendretry>=0:
0090             try:
0091                 rdata=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False, numfailures=numretry)
0092                 break
0093             except com_phone.modeignoreerrortypes:
0094                 if isendretry>0:
0095                     self.log("Resending request packet...")
0096                     time.sleep(0.3)
0097                 else:
0098                     self.comm.success=False
0099                     self.mode=self.MODENONE
0100                     self.raisecommsdnaexception("manipulating the phonebook")
0101                 isendretry-=1
0102 
0103         self.comm.success=True
0104 
0105         origdata=rdata
0106         # sometimes there is junk at the beginning, eg if the user
0107         # turned off the phone and back on again.  So if there is more
0108         # than one 7e in the escaped data we should start after the
0109         # second to last one
0110         d=rdata.rfind(common.pppterminator,0,-1)
0111         if d>=0:
0112             self.log("Multiple Samsung packets in data - taking last one starting at "+`d+1`)
0113             self.logdata("Original Samsung data", origdata, None)
0114             rdata=rdata[d+1:]
0115 
0116         # turn it back to normal
0117         data=common.pppunescape(rdata)
0118 
0119         # Sometimes there is other crap at the beginning.  But it might
0120         # be a Sanyo error byte.  So strip off bytes from the beginning
0121         # until the crc agrees, or we get to the first two bytes of the
0122         # request packet.
0123         d=data.find(firsttwo)
0124         crc=data[-3:-1]
0125         crcok=False
0126         for i in range(0,d+1):
0127             trydata=data[i:-3]
0128             if common.crcs(trydata)==crc:
0129                 crcok=True
0130                 break
0131 
0132         if not crcok:
0133             self.logdata("first two",firsttwo, None)
0134             self.logdata("Original Sanyo data", origdata, None)
0135             self.logdata("Working on Sanyo data", data, None)
0136             raise common.CommsDataCorruption("Sanyo packet failed CRC check", self.desc)
0137 
0138         res=responseclass()
0139         if d>0:
0140             if d==i:
0141                 self.log("Junk at beginning of Sanyo packet, data at "+`d`)
0142                 self.logdata("Original Sanyo data", origdata, None)
0143                 self.logdata("Working on Sanyo data", data, None)
0144             else:
0145                 if returnerror:
0146                     res=self.protocolclass.sanyoerror()
0147                 else:
0148                     self.log("Sanyo Error code "+`ord(data[0])`)
0149                     self.logdata("sanyo phonebook response", data, None)
0150                     raise SanyoCommandException(ord(data[0]))
0151             
0152         data=trydata
0153 
0154         # parse data
0155         buffer=prototypes.buffer(data)
0156         res.readfrombuffer(buffer, logtitle="sanyo phonebook response")
0157         return res
0158 
0159     def getfundamentals(self, results):
0160         """Gets information fundamental to interopating with the phone and UI."""
0161         results['uniqueserial']=1
0162         return results
0163 
0164     def getphonebook(self,result):
0165         pbook={}
0166 
0167         count = 0
0168         numcount = 0
0169         numemail = 0
0170         numurl = 0
0171 
0172         reqname=self.protocolclass.namerequest()
0173         reqnumber=self.protocolclass.numberrequest()
0174         for slot in range(1,self.protocolclass.NUMPHONEBOOKENTRIES+1):
0175             reqname.slot=slot
0176             resname=self.sendpbcommand(reqname, self.protocolclass.nameresponse)
0177             bitmask=resname.entry.bitmask
0178             if bitmask:
0179                 entry={}
0180                 name=resname.entry.name
0181                 entry['serials']=[ {'sourcetype': self.serialsname,
0182 
0183                                     'slot': slot,
0184                                     'sourceuniqueid': result['uniqueserial']} ]
0185                 entry['names']=[{'full':name}]
0186                 entry['numbers']=[]
0187                 bit=1
0188                 print resname.entry.p2,name
0189                 for num in range(self.protocolclass.NUMPHONENUMBERS):
0190                     bit <<= 1
0191                     if bitmask & bit:
0192                         numslot=resname.entry.numberps[num].slot
0193                         reqnumber.slot=numslot
0194                         resnumber=self.sendpbcommand(reqnumber, self.protocolclass.numberresponse)
0195                         numhash={'number':resnumber.entry.num, 'type' : self.numbertypetab[resnumber.entry.numbertype-1]}
0196                         entry['numbers'].append(numhash)
0197 
0198                         print " ",self.numbertypetab[resnumber.entry.numbertype-1]+": ",numslot,resnumber.entry.num
0199                 bit <<= 1
0200                 if bitmask & bit:
0201                     reqnumber.slot=resname.entry.emailp
0202                     resnumber=self.sendpbcommand(reqnumber, self.protocolclass.numberresponse)
0203                     print " Email: ",resname.entry.emailp,resnumber.entry.num
0204                     entry['emails']=[]
0205                     entry['emails'].append({'email':resnumber.entry.num})
0206                 bit <<= 1
0207                 if bitmask & bit:
0208                     reqnumber.slot=resname.entry.urlp
0209                     resnumber=self.sendpbcommand(reqnumber, self.protocolclass.numberresponse)
0210                     print " URL:   ",resname.entry.urlp,resnumber.entry.num
0211                     entry['urls']=[{'url':resnumber.entry.num}]
0212                 if resname.entry.nickname:
0213                     print " Nick:  ",resname.entry.nickname
0214                 if resname.entry.memo:
0215                     print " Memo   ",resname.entry.memo
0216                     entry['memos']=[{'memo':resname.entry.memo}]
0217 
0218                 pbook[count]=entry
0219                 self.progress(slot, self.protocolclass.NUMPHONEBOOKENTRIES+1, name)
0220                 count+=1
0221                 numcount+=len(entry['numbers'])
0222                 if entry.has_key('emails'):
0223                     numemail+=len(entry['emails'])
0224                 if entry.has_key('urls'):
0225                     numurl+=len(entry['urls'])
0226 
0227         self.progress(slot,slot,"Phonebook read completed")
0228         self.log("Phone contains "+`count`+" contacts, "+`numcount`+" phone numbers, "+`numemail`+" Emails, "+`numurl`+" URLs")
0229         result['phonebook']=pbook
0230 
0231         return pbook
0232 
0233     def writewait(self):
0234         """Loop until phone status indicates ready to write"""
0235         for i in range(100):
0236             req=self.protocolclass.statusrequest()
0237             res=self.sendpbcommand(req, self.protocolclass.statusresponse)
0238             # print res.flag0, res.ready, res.flag2, res.flag3
0239             if res.ready==res.readyvalue:
0240                 return
0241             time.sleep(0.1)
0242 
0243         self.log("Phone did not transfer to ready to write state")
0244         self.log("Waiting a bit longer and trying anyway")
0245         return
0246 
0247     def savephonebook(self, data):
0248         newphonebook={}
0249 
0250         nump=2
0251         urlp=0
0252         memop=0
0253         addressp=0
0254         emailp=0
0255         slotsused=1
0256 
0257         namemap=[]
0258         contactmap=[]
0259         urlmap=[]
0260 
0261         pbook=data['phonebook']
0262         self.log("Putting phone into write mode")
0263         req=self.protocolclass.beginendupdaterequest()
0264         req.beginend=1 # Start update
0265         res=self.sendpbcommand(req, self.protocolclass.beginendupdateresponse, writemode=True)
0266 #        self.writewait()
0267 
0268         req=self.protocolclass.writeenable()
0269         try:
0270             res=self.sendpbcommand(req, self.protocolclass.writeenableresponse, writemode=True)
0271         except:
0272             pass
0273 
0274         keys=pbook.keys()
0275         keys.sort()
0276         nnames = len(keys)
0277         
0278         reqnumber=self.protocolclass.numberupdaterequest()
0279         for ikey in keys:
0280             ii=pbook[ikey]
0281             slot=slotsused
0282             slotsused+=1
0283 
0284             reqname=self.protocolclass.nameupdaterequest()
0285             reqname.slot=slot
0286             name=ii['name']
0287             self.progress(slot-1, nnames, "Writing "+name)
0288             self.log("Writing "+`name`+" to slot "+`slot`)
0289             namemap.append((slot,name))
0290 
0291             reqname.entry.name=name
0292             reqname.entry.name_len=ii['name_len']
0293 
0294             bitmask=0
0295             bit=1
0296             for numindex in range(len(ii['numbers'])):
0297                 reqnumber.slot=nump
0298                 reqnumber.entry.num=ii['numbers'][numindex]
0299                 reqnumber.entry.numlen=len(ii['numbers'][numindex])
0300                 numbertype=ii['numbertypes'][numindex]
0301                 reqnumber.entry.numbertype=numbertype
0302                 reqnumber.entry.pos=numindex+1
0303 
0304                 resnumber=self.sendpbcommand(reqnumber,self.protocolclass.numberresponse)
0305 
0306                 reqname.entry.numberps.append(nump)
0307                 bitmask |= bit
0308                 bit <<= 1
0309 
0310                 nump+=1
0311             
0312             for numindex in range(len(ii['numbers']),self.protocolclass.NUMPHONENUMBERS):
0313                 reqname.entry.numberps.append(0)
0314 
0315             reqname.entry.bitmask=bitmask
0316             resname=self.sendpbcommand(reqname,self.protocolclass.nameresponse)
0317 
0318         # Zero out unused slots
0319         for slot in range(nump,self.protocolclass.NUMPHONEBOOKENTRIES+2):
0320             reqnumber.slot=slot
0321             reqnumber.entry.num=''
0322             reqnumber.entry.numlen=0
0323             reqnumber.entry.numbertype=0
0324             reqnumber.entry.pos=0
0325             resnumber=self.sendpbcommand(reqnumber,self.protocolclass.numberresponse)
0326         for slot in range(slotsused,self.protocolclass.NUMPHONEBOOKENTRIES+1):
0327             reqname=self.protocolclass.nameupdaterequest()
0328             reqname.slot=slot
0329             reqname.entry.name=''
0330             reqname.entry.name_len=0
0331             for numindex in range(self.protocolclass.NUMPHONENUMBERS):
0332                 reqname.entry.numberps.append(0)
0333             reqname.entry.bitmask=0
0334             resname=self.sendpbcommand(reqname,self.protocolclass.nameresponse)
0335 
0336         self.progress(1,1, "Phonebook write completed")
0337 
0338         req=self.protocolclass.beginendupdaterequest()
0339         req.beginend=2 # Finish update
0340         res=self.sendpbcommand(req, self.protocolclass.beginendupdateresponse, writemode=True)
0341         req=p_brew.setmodemmoderequest()
0342         res=self.sendpbcommand(req, p_brew.setmoderesponse, writemode=True)
0343         #data['rebootphone']=1
0344 
0345     def getcalendar(self, results):
0346         return result
0347 
0348     getwallpapers=None
0349     getringtones=None
0350 
0351 
0352 class Profile(com_phone.Profile):
0353     deviceclasses=("modem",)
0354 
0355     usbids=( ( 0x04e8, 0x6601, 1),  # Samsung internal USB interface
0356         )
0357     # which device classes we are.
0358     deviceclasses=("modem","serial")
0359 
0360     protocolclass=Phone.protocolclass
0361     serialsname=Phone.serialsname
0362     phone_manufacturer='SAMSUNG'
0363     phone_model='SPH-A900/154'
0364 
0365     _supportedsyncs=(
0366         ('phonebook', 'read', None),  # all phonebook reading
0367         ('phonebook', 'write', 'OVERWRITE'),  # only overwriting phonebook
0368     )
0369     
0370     def __init__(self):
0371         self.numbertypetab=numbertypetab
0372         com_phone.Profile.__init__(self)
0373 
0374     def convertphonebooktophone(self, helper, data):
0375         "Converts the data to what will be used by the phone"
0376 
0377         results={}
0378 
0379         slotsused={}
0380         pb=data['phonebook']
0381         for pbentry in pb:
0382             entry=pb[pbentry]
0383             slot=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'slot', -1)
0384             if(slot > 0 and slot <= self.protocolclass.NUMPHONEBOOKENTRIES):
0385                 slotsused[slot]=1
0386 
0387         lastunused=0 # One more than last unused slot
0388         
0389         for pbentry in pb:
0390             e={} # entry out
0391             entry=pb[pbentry] # entry in
0392             try:
0393                 try:
0394                     e['name']=helper.getfullname(entry.get('names', []),1,1,20)[0]
0395                 except:
0396                     e['name']=''
0397                 e['name_len']=len(e['name'])
0398                 if len(e['name'])==0:
0399                     print "Entry with no name"
0400 
0401 #                cat=helper.makeone(helper.getcategory(entry.get('categories',[]),0,1,16), None)
0402 #                if cat is None:
0403 #                    e['group']=0
0404 #                else:
0405 #                    key,value=self._getgroup(cat, data['groups'])
0406 #                    if key is not None:
0407 #                        e['group']=key
0408 #                    else:
0409 #                        e['group']=0
0410                 e['group']=0
0411 
0412                 serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'slot', -1)
0413 
0414                 if(slot > 0 and slot <= self.protocolclass.NUMPHONEBOOKENTRIES):
0415                     e['slot']=slot
0416                 else:  # A new entry.  Must find unused slot
0417                     while(slotsused.has_key(lastunused)):
0418                         lastunused+=1
0419                         if(lastunused > self.protocolclass.NUMPHONEBOOKENTRIES):
0420                             raise helper.ConversionFailed()
0421                     e['slot']=lastunused
0422                     slotsused[lastunused]=1
0423 
0424 #                e['emails']=helper.getemails(entry.get('emails', []),0,self.protocolclass.NUMEMAILS,self.protocolclass.MAXEMAILLEN)
0425 
0426 #                e['url']=helper.makeone(helper.geturls(entry.get('urls', []), 0,1,self.protocolclass.MAXURLLEN), "")
0427 
0428                 e['memo']=helper.makeone(helper.getmemos(entry.get('memos', []), 0,1,self.protocolclass.MAXMEMOLEN), "")
0429 
0430                 numbers=helper.getnumbers(entry.get('numbers', []),0,self.protocolclass.NUMPHONENUMBERS)
0431                 e['numbertypes']=[]
0432                 e['numbers']=[]
0433                 e['numberspeeds']=[]
0434                 
0435                 for numindex in range(len(numbers)):
0436                     num=numbers[numindex]
0437                     type=num['type']
0438                     numtype=len(self.numbertypetab) # None type is default
0439                     for i,t in enumerate(self.numbertypetab):
0440                         if type==t:
0441                             numtype=i+1
0442                             break
0443                     # If type not found, give it "none" type
0444                     e['numbertypes'].append(numtype)
0445 
0446                     # Need to enforce phone number length limit
0447                     number=self.phonize(num['number'])
0448                     e['numbers'].append(number)
0449 
0450                     # deal with speed dial
0451 #                    sd=num.get("speeddial", 0xFF)
0452 #                    if sd>=self.protocolclass.FIRSTSPEEDDIAL and sd<=self.protocolclass.LASTSPEEDDIAL:
0453 #                        e['numberspeeds'].append(sd)
0454 #                    else:
0455 #                        e['numberspeeds'].append(0)
0456                     
0457                 #e['numberspeeds']=helper.filllist(e['numberspeeds'], self.protocolclass.NUMPHONENUMBERS, 0xFF)
0458                 #e['numbertypes']=helper.filllist(e['numbertypes'], self.protocolclass.NUMPHONENUMBERS, 0)
0459                 #e['numbers']=helper.filllist(e['numbers'], self.protocolclass.NUMPHONENUMBERS, "")
0460                 
0461 
0462                 e['ringtone']=helper.getringtone(entry.get('ringtones', []), 'call', None)
0463                 e['wallpaper']=helper.getwallpaper(entry.get('wallpapers', []), 'call', None)
0464 
0465                 e['secret']=helper.getflag(entry.get('flags', []), 'secret', False)
0466                 results[pbentry]=e
0467                 
0468             except helper.ConversionFailed:
0469                 #self.log("No Free Slot for "+e['name'])
0470                 print "No Free Slot for "+e['name']
0471                 continue
0472 
0473         data['phonebook']=results
0474         return data
0475 

Generated by PyXR 0.9.4