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

Source Code for Module phones.com_samsungspha900

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2008 Stephen Wood <saw@bitpim.org> 
  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_samsungspha900.py 3918 2007-01-19 05:15:12Z djpham $ 
  9   
 10  """Communicate with a Samsung SPH-A900""" 
 11   
 12  import sha 
 13  import re 
 14  import struct 
 15   
 16  import common 
 17  import commport 
 18  import p_brew 
 19  import p_samsungspha900 
 20  import com_brew 
 21  import com_phone 
 22  import prototypes 
 23  import helpids 
 24   
 25  numbertypetab=('cell','home','office','pager','none') 
 26   
27 -class Phone(com_phone.Phone, com_brew.BrewProtocol):
28 "Talk to a Samsung SPH-A900 phone" 29 30 desc="SPH-A900" 31 helpid=helpids.ID_PHONE_SAMSUNGOTHERS 32 protocolclass=p_samsungspha900 33 serialsname='spha900' 34 35 MODEPHONEBOOK="modephonebook" # can speak the phonebook protocol 36 37 # jpeg Remove first 124 characters 38 39 imagelocations=( 40 # offset, index file, files location, origin, maximumentries, header offset 41 # Offset is arbitrary. 100 is reserved for amsRegistry indexed files 42 (400, "cam/dldJpeg", "camera", 100, 124), 43 (300, "cam/jpeg", "camera", 100, 124), 44 ) 45 46 ringtonelocations=( 47 # offset, index file, files location, type, maximumentries, header offset 48 ) 49 50
51 - def __init__(self, logtarget, commport):
52 com_phone.Phone.__init__(self, logtarget, commport) 53 com_brew.BrewProtocol.__init__(self) 54 self.numbertypetab=numbertypetab 55 self.mode=self.MODENONE
56
57 - def _setmodephonebook(self):
58 self.setmode(self.MODEBREW) 59 req=self.protocolclass.firmwarerequest() 60 respc=self.protocolclass.firmwareresponse 61 try: 62 self.sendpbcommand(req, respc, callsetmode=False) 63 return 1 64 except com_phone.modeignoreerrortypes: 65 pass 66 try: 67 self.comm.setbaudrate(38400) 68 self.sendpbcommand(req, respc, callsetmode=False) 69 return 1 70 except com_phone.modeignoreerrortypes: 71 pass 72 return 0
73
74 - def sendpbcommand(self, request, responseclass, callsetmode=True, writemode=False, numsendretry=0, returnerror=False):
75 if writemode: 76 numretry=3 77 else: 78 numretry=0 79 80 if callsetmode: 81 self.setmode(self.MODEPHONEBOOK) 82 buffer=prototypes.buffer() 83 84 request.writetobuffer(buffer, logtitle="Samsung phonebook request") 85 data=buffer.getvalue() 86 firsttwo=data[:2] 87 data=common.pppescape(data+common.crcs(data))+common.pppterminator 88 isendretry=numsendretry 89 while isendretry>=0: 90 try: 91 rdata=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False, numfailures=numretry) 92 break 93 except com_phone.modeignoreerrortypes: 94 if isendretry>0: 95 self.log("Resending request packet...") 96 time.sleep(0.3) 97 else: 98 self.comm.success=False 99 self.mode=self.MODENONE 100 self.raisecommsdnaexception("manipulating the phonebook") 101 isendretry-=1 102 103 self.comm.success=True 104 105 origdata=rdata 106 # sometimes there is junk at the beginning, eg if the user 107 # turned off the phone and back on again. So if there is more 108 # than one 7e in the escaped data we should start after the 109 # second to last one 110 d=rdata.rfind(common.pppterminator,0,-1) 111 if d>=0: 112 self.log("Multiple Samsung packets in data - taking last one starting at "+`d+1`) 113 self.logdata("Original Samsung data", origdata, None) 114 rdata=rdata[d+1:] 115 116 # turn it back to normal 117 data=common.pppunescape(rdata) 118 119 # Sometimes there is other crap at the beginning. But it might 120 # be a Sanyo error byte. So strip off bytes from the beginning 121 # until the crc agrees, or we get to the first two bytes of the 122 # request packet. 123 d=data.find(firsttwo) 124 crc=data[-3:-1] 125 crcok=False 126 for i in range(0,d+1): 127 trydata=data[i:-3] 128 if common.crcs(trydata)==crc: 129 crcok=True 130 break 131 132 if not crcok: 133 self.logdata("first two",firsttwo, None) 134 self.logdata("Original Sanyo data", origdata, None) 135 self.logdata("Working on Sanyo data", data, None) 136 raise common.CommsDataCorruption("Sanyo packet failed CRC check", self.desc) 137 138 res=responseclass() 139 if d>0: 140 if d==i: 141 self.log("Junk at beginning of Sanyo packet, data at "+`d`) 142 self.logdata("Original Sanyo data", origdata, None) 143 self.logdata("Working on Sanyo data", data, None) 144 else: 145 if returnerror: 146 res=self.protocolclass.sanyoerror() 147 else: 148 self.log("Sanyo Error code "+`ord(data[0])`) 149 self.logdata("sanyo phonebook response", data, None) 150 raise SanyoCommandException(ord(data[0])) 151 152 data=trydata 153 154 # parse data 155 buffer=prototypes.buffer(data) 156 res.readfrombuffer(buffer, logtitle="sanyo phonebook response") 157 return res
158
159 - def getfundamentals(self, results):
160 """Gets information fundamental to interopating with the phone and UI.""" 161 results['uniqueserial']=1 162 return results
163
164 - def getphonebook(self,result):
165 pbook={} 166 167 count = 0 168 numcount = 0 169 numemail = 0 170 numurl = 0 171 172 reqname=self.protocolclass.namerequest() 173 reqnumber=self.protocolclass.numberrequest() 174 for slot in range(1,self.protocolclass.NUMPHONEBOOKENTRIES+1): 175 reqname.slot=slot 176 resname=self.sendpbcommand(reqname, self.protocolclass.nameresponse) 177 bitmask=resname.entry.bitmask 178 if bitmask: 179 entry={} 180 name=resname.entry.name 181 entry['serials']=[ {'sourcetype': self.serialsname, 182 183 'slot': slot, 184 'sourceuniqueid': result['uniqueserial']} ] 185 entry['names']=[{'full':name}] 186 entry['numbers']=[] 187 bit=1 188 print resname.entry.p2,name 189 for num in range(self.protocolclass.NUMPHONENUMBERS): 190 bit <<= 1 191 if bitmask & bit: 192 numslot=resname.entry.numberps[num].slot 193 reqnumber.slot=numslot 194 resnumber=self.sendpbcommand(reqnumber, self.protocolclass.numberresponse) 195 numhash={'number':resnumber.entry.num, 'type' : self.numbertypetab[resnumber.entry.numbertype-1]} 196 entry['numbers'].append(numhash) 197 198 print " ",self.numbertypetab[resnumber.entry.numbertype-1]+": ",numslot,resnumber.entry.num 199 bit <<= 1 200 if bitmask & bit: 201 reqnumber.slot=resname.entry.emailp 202 resnumber=self.sendpbcommand(reqnumber, self.protocolclass.numberresponse) 203 print " Email: ",resname.entry.emailp,resnumber.entry.num 204 entry['emails']=[] 205 entry['emails'].append({'email':resnumber.entry.num}) 206 bit <<= 1 207 if bitmask & bit: 208 reqnumber.slot=resname.entry.urlp 209 resnumber=self.sendpbcommand(reqnumber, self.protocolclass.numberresponse) 210 print " URL: ",resname.entry.urlp,resnumber.entry.num 211 entry['urls']=[{'url':resnumber.entry.num}] 212 if resname.entry.nickname: 213 print " Nick: ",resname.entry.nickname 214 if resname.entry.memo: 215 print " Memo ",resname.entry.memo 216 entry['memos']=[{'memo':resname.entry.memo}] 217 218 pbook[count]=entry 219 self.progress(slot, self.protocolclass.NUMPHONEBOOKENTRIES+1, name) 220 count+=1 221 numcount+=len(entry['numbers']) 222 if entry.has_key('emails'): 223 numemail+=len(entry['emails']) 224 if entry.has_key('urls'): 225 numurl+=len(entry['urls']) 226 227 self.progress(slot,slot,"Phonebook read completed") 228 self.log("Phone contains "+`count`+" contacts, "+`numcount`+" phone numbers, "+`numemail`+" Emails, "+`numurl`+" URLs") 229 result['phonebook']=pbook 230 231 return pbook
232
233 - def writewait(self):
234 """Loop until phone status indicates ready to write""" 235 for i in range(100): 236 req=self.protocolclass.statusrequest() 237 res=self.sendpbcommand(req, self.protocolclass.statusresponse) 238 # print res.flag0, res.ready, res.flag2, res.flag3 239 if res.ready==res.readyvalue: 240 return 241 time.sleep(0.1) 242 243 self.log("Phone did not transfer to ready to write state") 244 self.log("Waiting a bit longer and trying anyway") 245 return
246
247 - def savephonebook(self, data):
248 newphonebook={} 249 250 nump=2 251 urlp=0 252 memop=0 253 addressp=0 254 emailp=0 255 slotsused=1 256 257 namemap=[] 258 contactmap=[] 259 urlmap=[] 260 261 pbook=data['phonebook'] 262 self.log("Putting phone into write mode") 263 req=self.protocolclass.beginendupdaterequest() 264 req.beginend=1 # Start update 265 res=self.sendpbcommand(req, self.protocolclass.beginendupdateresponse, writemode=True) 266 # self.writewait() 267 268 req=self.protocolclass.writeenable() 269 try: 270 res=self.sendpbcommand(req, self.protocolclass.writeenableresponse, writemode=True) 271 except: 272 pass 273 274 keys=pbook.keys() 275 keys.sort() 276 nnames = len(keys) 277 278 reqnumber=self.protocolclass.numberupdaterequest() 279 for ikey in keys: 280 ii=pbook[ikey] 281 slot=slotsused 282 slotsused+=1 283 284 reqname=self.protocolclass.nameupdaterequest() 285 reqname.slot=slot 286 name=ii['name'] 287 self.progress(slot-1, nnames, "Writing "+name) 288 self.log("Writing "+`name`+" to slot "+`slot`) 289 namemap.append((slot,name)) 290 291 reqname.entry.name=name 292 reqname.entry.name_len=ii['name_len'] 293 294 bitmask=0 295 bit=1 296 for numindex in range(len(ii['numbers'])): 297 reqnumber.slot=nump 298 reqnumber.entry.num=ii['numbers'][numindex] 299 reqnumber.entry.numlen=len(ii['numbers'][numindex]) 300 numbertype=ii['numbertypes'][numindex] 301 reqnumber.entry.numbertype=numbertype 302 reqnumber.entry.pos=numindex+1 303 304 resnumber=self.sendpbcommand(reqnumber,self.protocolclass.numberresponse) 305 306 reqname.entry.numberps.append(nump) 307 bitmask |= bit 308 bit <<= 1 309 310 nump+=1 311 312 for numindex in range(len(ii['numbers']),self.protocolclass.NUMPHONENUMBERS): 313 reqname.entry.numberps.append(0) 314 315 reqname.entry.bitmask=bitmask 316 resname=self.sendpbcommand(reqname,self.protocolclass.nameresponse) 317 318 # Zero out unused slots 319 for slot in range(nump,self.protocolclass.NUMPHONEBOOKENTRIES+2): 320 reqnumber.slot=slot 321 reqnumber.entry.num='' 322 reqnumber.entry.numlen=0 323 reqnumber.entry.numbertype=0 324 reqnumber.entry.pos=0 325 resnumber=self.sendpbcommand(reqnumber,self.protocolclass.numberresponse) 326 for slot in range(slotsused,self.protocolclass.NUMPHONEBOOKENTRIES+1): 327 reqname=self.protocolclass.nameupdaterequest() 328 reqname.slot=slot 329 reqname.entry.name='' 330 reqname.entry.name_len=0 331 for numindex in range(self.protocolclass.NUMPHONENUMBERS): 332 reqname.entry.numberps.append(0) 333 reqname.entry.bitmask=0 334 resname=self.sendpbcommand(reqname,self.protocolclass.nameresponse) 335 336 self.progress(1,1, "Phonebook write completed") 337 338 req=self.protocolclass.beginendupdaterequest() 339 req.beginend=2 # Finish update 340 res=self.sendpbcommand(req, self.protocolclass.beginendupdateresponse, writemode=True) 341 req=p_brew.setmodemmoderequest() 342 res=self.sendpbcommand(req, p_brew.setmoderesponse, writemode=True)
343 #data['rebootphone']=1 344
345 - def getcalendar(self, results):
346 return result
347 348 getwallpapers=None 349 getringtones=None
350 351
352 -class Profile(com_phone.Profile):
353 deviceclasses=("modem",) 354 355 usbids=( ( 0x04e8, 0x6601, 1), # Samsung internal USB interface 356 ) 357 # which device classes we are. 358 deviceclasses=("modem","serial") 359 360 protocolclass=Phone.protocolclass 361 serialsname=Phone.serialsname 362 phone_manufacturer='SAMSUNG' 363 phone_model='SPH-A900/154' 364 365 _supportedsyncs=( 366 ('phonebook', 'read', None), # all phonebook reading 367 ('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook 368 ) 369
370 - def __init__(self):
373
374 - def convertphonebooktophone(self, helper, data):
375 "Converts the data to what will be used by the phone" 376 377 results={} 378 379 slotsused={} 380 pb=data['phonebook'] 381 for pbentry in pb: 382 entry=pb[pbentry] 383 slot=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'slot', -1) 384 if(slot > 0 and slot <= self.protocolclass.NUMPHONEBOOKENTRIES): 385 slotsused[slot]=1 386 387 lastunused=0 # One more than last unused slot 388 389 for pbentry in pb: 390 e={} # entry out 391 entry=pb[pbentry] # entry in 392 try: 393 try: 394 e['name']=helper.getfullname(entry.get('names', []),1,1,20)[0] 395 except: 396 e['name']='' 397 e['name_len']=len(e['name']) 398 if len(e['name'])==0: 399 print "Entry with no name" 400 401 # cat=helper.makeone(helper.getcategory(entry.get('categories',[]),0,1,16), None) 402 # if cat is None: 403 # e['group']=0 404 # else: 405 # key,value=self._getgroup(cat, data['groups']) 406 # if key is not None: 407 # e['group']=key 408 # else: 409 # e['group']=0 410 e['group']=0 411 412 serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'slot', -1) 413 414 if(slot > 0 and slot <= self.protocolclass.NUMPHONEBOOKENTRIES): 415 e['slot']=slot 416 else: # A new entry. Must find unused slot 417 while(slotsused.has_key(lastunused)): 418 lastunused+=1 419 if(lastunused > self.protocolclass.NUMPHONEBOOKENTRIES): 420 raise helper.ConversionFailed() 421 e['slot']=lastunused 422 slotsused[lastunused]=1 423 424 # e['emails']=helper.getemails(entry.get('emails', []),0,self.protocolclass.NUMEMAILS,self.protocolclass.MAXEMAILLEN) 425 426 # e['url']=helper.makeone(helper.geturls(entry.get('urls', []), 0,1,self.protocolclass.MAXURLLEN), "") 427 428 e['memo']=helper.makeone(helper.getmemos(entry.get('memos', []), 0,1,self.protocolclass.MAXMEMOLEN), "") 429 430 numbers=helper.getnumbers(entry.get('numbers', []),0,self.protocolclass.NUMPHONENUMBERS) 431 e['numbertypes']=[] 432 e['numbers']=[] 433 e['numberspeeds']=[] 434 435 for numindex in range(len(numbers)): 436 num=numbers[numindex] 437 type=num['type'] 438 numtype=len(self.numbertypetab) # None type is default 439 for i,t in enumerate(self.numbertypetab): 440 if type==t: 441 numtype=i+1 442 break 443 # If type not found, give it "none" type 444 e['numbertypes'].append(numtype) 445 446 # Need to enforce phone number length limit 447 number=self.phonize(num['number']) 448 e['numbers'].append(number) 449 450 # deal with speed dial 451 # sd=num.get("speeddial", 0xFF) 452 # if sd>=self.protocolclass.FIRSTSPEEDDIAL and sd<=self.protocolclass.LASTSPEEDDIAL: 453 # e['numberspeeds'].append(sd) 454 # else: 455 # e['numberspeeds'].append(0) 456 457 #e['numberspeeds']=helper.filllist(e['numberspeeds'], self.protocolclass.NUMPHONENUMBERS, 0xFF) 458 #e['numbertypes']=helper.filllist(e['numbertypes'], self.protocolclass.NUMPHONENUMBERS, 0) 459 #e['numbers']=helper.filllist(e['numbers'], self.protocolclass.NUMPHONENUMBERS, "") 460 461 462 e['ringtone']=helper.getringtone(entry.get('ringtones', []), 'call', None) 463 e['wallpaper']=helper.getwallpaper(entry.get('wallpapers', []), 'call', None) 464 465 e['secret']=helper.getflag(entry.get('flags', []), 'secret', False) 466 results[pbentry]=e 467 468 except helper.ConversionFailed: 469 #self.log("No Free Slot for "+e['name']) 470 print "No Free Slot for "+e['name'] 471 continue 472 473 data['phonebook']=results 474 return data
475