0001 ### BITPIM 0002 ### 0003 ### Copyright (C) 2006 Denis Tonn <denis@tonn.ca> 0004 ### Inspiration and code liberally adopted from: 0005 ### Stephen A. Wood and Joe Pham 0006 ### 0007 ### This program is free software; you can redistribute it and/or modify 0008 ### it under the terms of the BitPim license as detailed in the LICENSE file. 0009 ### 0010 ### $Id$ 0011 0012 """Communicate with a Samsung SPH-A840 from Telus Canada""" 0013 0014 # Notes: 0015 # 0016 # This Phone does not cleanly return from BREW mode, so everything is 0017 # done through modem mode. 0018 # 0019 # Groups are handled differently on this phone, so I have hard coded 0020 # them. In any event, there is no way to query them as part of a 0021 # PBentry. Restoring data to a phone loses group assignments. 0022 # at#pbgrw does not modify group names - seems to be ignored in phone 0023 # even though it returns OK. 0024 # 0025 # Cannot query/extract Ringtones so that is hard coded. Built in tones 0026 # are ok and can be changed through BitPim. 0027 # 0028 # Cannot query/extract Wallpaper so builtin values are hardcoded and 0029 # everything else is maintained through a write to phone 0030 # 0031 # Special case email and url fields. If these are blank they MUST have 0032 # a quoted space in the write or phone data is corrupted. 0033 # 0034 # uslot 1 should not be used. I have not done anything in this code to 0035 # prevent it, but the phone will complain if you try and edit a 0036 # pbentry with uslot = 1. Change the "location" on the phone and it's 0037 # fine. 0038 # 0039 # There is no way of setting (or unsetting) a "secret" pbentry on this 0040 # phone. 0041 # 0042 # Calendar writes fail (ERROR) unless start_time and end_time are the 0043 # same. 0044 # 0045 # Occasionally the phone will have position 0 as the speeddial number, 0046 # when it has only one number even when that number isn't in position 0047 # 0. 0048 # 0049 0050 import time 0051 import datetime 0052 0053 import sha 0054 import re 0055 import struct 0056 0057 import bpcalendar 0058 import prototypes 0059 import todo 0060 import memo 0061 0062 import common 0063 import commport 0064 import p_brew 0065 import p_samsungspha840_telus 0066 import com_brew 0067 import com_phone 0068 import com_samsung_packet 0069 import helpids 0070 0071 numbertypetab=('home','office','cell','pager','fax') 0072 0073 0074 ### Phone class 0075 0076 parentphone=com_samsung_packet.Phone 0077 class Phone(parentphone): 0078 "Talk to a Samsung SPH-A840 phone (Telus)" 0079 0080 __read_timeout=0.5 0081 __cal_end_datetime_value=None 0082 __cal_alarm_values={0: -1, 1: 0, 2: 10, 3: 30, 4: 60 } 0083 __cal_max_name_len=32 0084 _cal_max_events_per_day=5 0085 0086 desc="SPH-A840 (Telus)" 0087 helpid=helpids.ID_PHONE_SAMSUNGOTHERS 0088 protocolclass=p_samsungspha840_telus 0089 serialsname='spha840T' 0090 0091 builtin_ringtones=( 0092 (0, ['Default Tone']), 0093 (1, ['Ring %02d'%x for x in range(1, 6)]), 0094 (6, ['Melody %02d'%x for x in range(1, 6)]), 0095 ) 0096 0097 # wallpaper values 0098 # 8 = no image 0099 # 3 = human 1-20 0100 # 4 = animal 1-15 0101 # 5 = others 1-10 0102 # 2 = gallery - and wallpaper_pic_path points to the file name 0103 # 7 = image clips 0104 0105 # wallpaper_modifier 0106 # selects specific image in human, animal, others 0107 # selects offset in file for image clips 0108 # must be 0 if no image 0109 # value ignored if gallery image 0110 0111 builtin_pictures=( 0112 (0, ['Human %02d'%x for x in range(1, 21)]), 0113 (30, ['Animal %02d'%x for x in range(1, 16)]), 0114 (60, ['Other %02d'%x for x in range(1, 11)]), 0115 (80, ['On Phone Image']), 0116 ) 0117 0118 def __init__(self, logtarget, commport): 0119 com_samsung_packet.Phone.__init__(self, logtarget, commport) 0120 self.numbertypetab=numbertypetab 0121 self.mode=self.MODENONE 0122 0123 def getfundamentals(self, results): 0124 """Gets information fundamental to interoperating with the phone and UI.""" 0125 # use a hash of ESN and other stuff (being paranoid) 0126 self.log("Retrieving fundamental phone information") 0127 self.log("Phone serial number") 0128 self.setmode(self.MODEMODEM) 0129 results['uniqueserial']=sha.new(self.get_esn()).hexdigest() 0130 # getting ringtone-index 0131 self.log("Setting up Built in Ring Tone index") 0132 results['ringtone-index']=self._get_builtin_index(self.builtin_ringtones) 0133 # getting wallpaper-index 0134 self.log("Setting up Built in Wallpaper index") 0135 results['wallpaper-index']=self.get_wallpaper_index() 0136 self.log("Ignoring Corrupted Phone group information") 0137 # groups are hard coded since this phone corrupts the read of groups 0138 results['groups']=self.read_groups() 0139 self.log("Fundamentals retrieved") 0140 return results 0141 0142 def _get_builtin_index(self, builtin_list): 0143 _res={} 0144 for _starting_idx,_list in builtin_list: 0145 _idx=_starting_idx 0146 for _entry in _list: 0147 _res[_idx]={ 'name': _entry, 0148 'origin': 'builtin' } 0149 _idx+=1 0150 return _res 0151 0152 def get_wallpaper_index(self): 0153 _res=self._get_builtin_index(self.builtin_pictures) 0154 return _res 0155 0156 def pblinerepair(self, line): 0157 "Extend incomplete lines" 0158 nfields=24 # Can we get this from packet def? 0159 ncommas=self.countcommas(line) 0160 if ncommas<0: # Un terminated quote 0161 line+='"' 0162 ncommas = -ncommas 0163 if nfields-ncommas>1: 0164 line=line+","*(nfields-ncommas-1) 0165 return line 0166 0167 def countcommas(self, line): 0168 inquote=False 0169 ncommas=0 0170 for c in line: 0171 if c == '"': 0172 inquote = not inquote 0173 elif not inquote and c == ',': 0174 ncommas+=1 0175 if inquote: 0176 ncommas = -ncommas 0177 return ncommas 0178 0179 def savewallpapers(self, result): 0180 raise NotImplementedError() 0181 0182 def saveringtones(self, result): 0183 raise NotImplementedError() 0184 0185 def getringtones(self, results): 0186 raise NotImplementedError() 0187 0188 def getwallpapers(self, results): 0189 raise NotImplementedError() 0190 0191 def read_groups(self): 0192 # This phone returns crap for group names which causes an assertion error in the database 0193 # because of duplicate "blank" names in the groups. 0194 # so to bypass I have set the group names manually 0195 g={} 0196 g[0]={'name': "Friends"} 0197 g[1]={'name': "Business"} 0198 g[2]={'name': "Family"} 0199 g[3]={'name': "General"} 0200 g[4]={'name': "No Group"} 0201 return g 0202 0203 0204 def savegroups(self, data): 0205 """This phone doesn't save or read groups properly 0206 so we are skipping the save""" 0207 return 0208 0209 0210 0211 # 0212 # 0213 # Called by extractphonebookentry to extract wallpaper from phone entry data 0214 # 0215 # 0216 def _extract_wallpaper(self, res, entry, fundamentals): 0217 # wallpaper values 0218 # 8 = no image 0219 # 3 = human 1-20 res index 1-20 0220 # 4 = animal 1-15 res index 30-45 0221 # 5 = others 1-10 res index 60-70 0222 # 2 = gallery - and wallpaper_pic_path points to the file name 0223 # 6 or 7 = image clips - modifier selects offset in image file 0224 # 1 = I assume downloaded - never downloaded a wallpaper 0225 # gallery and images and downloads are treated separately as index 80 0226 # - save just keeps whatever wallpaper data the phone already has and is not managed by bitpim 0227 0228 # wallpaper_modifier 0229 # selects specific image in human, animal, others 0230 # selects offset in file for image clips 0231 # must be 0 if no image 0232 # value ignored if gallery image file name 0233 _wp_index=fundamentals.get('wallpaper-index', {}) 0234 if entry.wallpaper==8: 0235 return # no image 0236 if entry.wallpaper in (0,1,2,6,7): 0237 wallpaper_index=80 # use "on phone" dict entry name in bitpim and recycle current phone data 0238 if entry.wallpaper==3: 0239 wallpaper_index=entry.wallpaper_modifier 0240 if entry.wallpaper==4: 0241 wallpaper_index=30+entry.wallpaper_modifier 0242 if entry.wallpaper==5: 0243 wallpaper_index=60+entry.wallpaper_modifier 0244 # get the name out of the dict 0245 _wp_name=_wp_index.get(wallpaper_index, {}).get('name', None) 0246 if _wp_name: 0247 res['wallpapers']=[{ 'wallpaper': _wp_name, 'use': 'call' }] 0248 0249 # 0250 # 0251 # Called by extractphonebookentry to extract ringtone from phone entry data 0252 # 0253 # 0254 def _extract_ringtone(self, res, entry, fundamentals): 0255 _rt_index=fundamentals.get('ringtone-index', {}) 0256 _rt_name=_rt_index.get(entry.ringtone, {}).get('name', None) 0257 if _rt_name: 0258 res['ringtones']=[{ 'ringtone': _rt_name, 'use': 'call' }] 0259 0260 # 0261 # 0262 # Called by getphonebook to extract single phone entry data 0263 # 0264 # 0265 def extractphonebookentry(self, entry, fundamentals): 0266 res={} 0267 res['serials']=[ {'sourcetype': self.serialsname, 0268 'slot': entry.slot, 0269 'sourceuniqueid': fundamentals['uniqueserial']} ] 0270 # only one name 0271 res['names']=[ {'full': entry.name} ] 0272 # only one category 0273 cat=fundamentals['groups'].get(entry.group, {'name': "Unassigned"})['name'] 0274 if cat!="Unassigned": 0275 res['categories']=[ {'category': cat} ] 0276 # only one email 0277 if len(entry.email): 0278 res['emails']=[ {'email': entry.email} ] 0279 # only one url 0280 if len(entry.url): 0281 res['urls']=[ {'url': entry.url} ] 0282 res['numbers']=[] 0283 secret=0 0284 speeddialtype=entry.speeddial 0285 speeddial_has_been_set=0 # need this for fix for bad phonebook data 0286 numberindex=0 0287 for type in self.numbertypetab: 0288 if len(entry.numbers[numberindex].number): 0289 numhash={'number': entry.numbers[numberindex].number, 'type': type } 0290 # if entry.numbers[numberindex].secret==1: 0291 # secret=1 0292 self.log("ENTRY -speeddial : "+str(speeddialtype)+" -index : "+str(numberindex)+" -uslot : "+str(entry.slot)) 0293 # fix possible bad phone data - always force dial entry to first number as safety measure 0294 # Otherwise we will lose the uslot data completely 0295 if speeddial_has_been_set==0: 0296 numhash['speeddial']=entry.uslot 0297 speeddial_has_been_set=1 0298 if speeddialtype==numberindex: 0299 numhash['speeddial']=entry.uslot 0300 speeddial_has_been_set=1 0301 self.log("EXIT -speeddial : "+str(speeddialtype)+" -index : "+str(numberindex)+" -uslot : "+str(entry.slot)) 0302 res['numbers'].append(numhash) 0303 numberindex+=1 0304 0305 # Field after each number is secret flag. Setting secret on 0306 # phone sets secret flag for every defined phone number 0307 res['flags']=[ {'secret': secret} ] 0308 _args=(res, entry, fundamentals) 0309 self._extract_wallpaper(*_args) 0310 self._extract_ringtone(*_args) 0311 return res 0312 0313 # 0314 # 0315 # Get the phone book 0316 # 0317 # 0318 def getphonebook(self, result): 0319 """Read the phonebook data.""" 0320 pbook={} 0321 self.setmode(self.MODEPHONEBOOK) 0322 0323 count=0 0324 req=self.protocolclass.phonebookslotrequest() 0325 lastname="" 0326 for slot in range(1,self.protocolclass.NUMPHONEBOOKENTRIES+1): 0327 req.slot=slot 0328 res=self.sendpbcommand(req, self.protocolclass.phonebookslotresponse, fixup=self.pblinerepair) 0329 if len(res) > 0: 0330 lastname=res[0].entry.name 0331 if len(lastname)>0: 0332 self.log(`slot`+": "+lastname+" uSlot : "+str(res[0].entry.uslot)) 0333 entry=self.extractphonebookentry(res[0].entry, result) 0334 pbook[count]=entry 0335 count+=1 0336 self.progress(slot, self.protocolclass.NUMPHONEBOOKENTRIES, lastname) 0337 result['phonebook']=pbook 0338 cats=[] 0339 for i in result['groups']: 0340 if result['groups'][i]['name']!='Unassigned': 0341 cats.append(result['groups'][i]['name']) 0342 result['categories']=cats 0343 self.setmode(self.MODEMODEM) 0344 return pbook 0345 0346 # 0347 # 0348 # Called by savephonebook to create an initial phone book entry 0349 # 0350 # 0351 def makeentry(self, entry, data): 0352 e=self.protocolclass.pbentry() 0353 for k in entry: 0354 # special treatment for lists 0355 if k=='numbertypes' or k=='secrets': 0356 continue 0357 # get a phone index for the ring tone name 0358 if k=='ringtone': 0359 _rt_index=data.get('ringtone-index', {}) 0360 for rgt in _rt_index.keys(): 0361 _rt_name=_rt_index.get(rgt, {}).get('name', None) 0362 if _rt_name==entry['ringtone']: 0363 e.ringtone=rgt # and save it for the phonebook entry 0364 continue 0365 # get a a pair of indexs for the wallpaper name - wallpaper and wallpaper_modifier 0366 elif k=='wallpaper': 0367 # setup default values - no image 0368 e.wallpaper=8 0369 e.wallpaper_modifier=0 0370 e.wallpaper_file="" 0371 # now see if we have anything stored in the database 0372 _wp_index=data.get('wallpaper-index', {}) 0373 for wpn in _wp_index.keys(): 0374 _wp_name=_wp_index.get(wpn, {}).get('name', None) 0375 if _wp_name==entry['wallpaper']: # found the name, now convert to a pair of phone indexes 0376 if wpn<30: # built in Human type, modifier is wpn 0377 e.wallpaper=3 0378 e.wallpaper_modifier=wpn 0379 if wpn>29 and wpn<60: # built in Animals type, modifier is wpn-30 0380 e.wallpaper=4 0381 e.wallpaper_modifier=wpn-30 0382 if wpn>59 and wpn<80: # built in Others type, modifier is wpn-60 0383 e.wallpaper=5 0384 e.wallpaper_modifier=wpn-60 0385 if wpn==80: # on phone - special processing in caller code 0386 e.wallpaper=8 0387 e.wallpaper_modifier=8 # will not be stored on phone just a sig 0388 continue 0389 elif k=='numbers': 0390 for numberindex in range(self.protocolclass.NUMPHONENUMBERS): 0391 enpn=self.protocolclass.phonenumber() 0392 e.numbers.append(enpn) 0393 for i in range(len(entry[k])): 0394 numberindex=entry['numbertypes'][i] 0395 e.numbers[numberindex].number=entry[k][i] 0396 # e.numbers[numberindex].secret=entry['secrets'][i] 0397 e.numbers[numberindex].secret=0 0398 continue 0399 # everything else we just set 0400 setattr(e, k, entry[k]) 0401 0402 return e 0403 0404 # 0405 # 0406 # Save the phone book 0407 # 0408 # 0409 def savephonebook(self, data): 0410 "Saves out the phonebook" 0411 0412 pb=data['phonebook'] 0413 keys=pb.keys() 0414 keys.sort() 0415 keys=keys[:self.protocolclass.NUMPHONEBOOKENTRIES] 0416 0417 self.setmode(self.MODEPHONEBOOK) 0418 # 1- Read the existing phonebook so that we cache birthday field and wallpaper file path and stuff 0419 # 2- Erase all entries. 0420 uslots={} 0421 names={} 0422 birthdays={} 0423 wallpaper_s={} 0424 wallpaper_files={} 0425 wallpaper_modifiers={} 0426 req=self.protocolclass.phonebookslotrequest() 0427 0428 self.log('Erasing '+self.desc+' phonebook') 0429 progressmax=self.protocolclass.NUMPHONEBOOKENTRIES+len(keys) 0430 for slot in range(1,self.protocolclass.NUMPHONEBOOKENTRIES+1): 0431 req.slot=slot 0432 self.progress(slot,progressmax,"Erasing "+`slot`) 0433 try: 0434 res=self.sendpbcommand(req,self.protocolclass.phonebookslotresponse, fixup=self.pblinerepair) 0435 if len(res) > 0: 0436 self.log("Starting capture data for : "+res[0].entry.name) 0437 names[slot]=res[0].entry.name 0438 birthdays[slot]=res[0].entry.birthday 0439 wallpaper_s[slot]=res[0].entry.wallpaper 0440 wallpaper_files[slot]=res[0].entry.wallpaper_file 0441 wallpaper_modifiers[slot]=res[0].entry.wallpaper_modifier 0442 self.log("Captured data for : "+res[0].entry.name) 0443 self.log("User Slot from phone: "+str(res[0].entry.uslot)) 0444 else: 0445 names[slot]="" 0446 except: 0447 names[slot]="" 0448 self.log("Slot "+`slot`+" Empty slot or read failed") 0449 reqerase=self.protocolclass.phonebooksloterase() 0450 reqerase.slot=slot 0451 self.sendpbcommand(reqerase, self.protocolclass.phonebookslotupdateresponse) 0452 # Skip this.. the group save commands don't work 0453 # self.savegroups(data) 0454 0455 for i in range(len(keys)): 0456 slot=keys[i] 0457 req=self.protocolclass.phonebookslotupdaterequest() 0458 req.entry=self.makeentry(pb[slot],data) 0459 # groups are not handled through the phonebook data on this phone 0460 req.entry.group=self.protocolclass.DEFAULT_GROUP 0461 0462 # force a single space into email and url if they are zero length 0463 if len(req.entry.email)==0: 0464 req.entry.email=" " 0465 if len(req.entry.url)==0: 0466 req.entry.url=" " 0467 # restore the stuff we may not have in the database 0468 if names[slot]==req.entry.name: 0469 req.entry.birthday=birthdays[slot] # no analogy on bitpim database, just keep with entry 0470 # test for internal sig and keep whatever wallpaper is already on the phone 0471 if req.entry.wallpaper==self.protocolclass.DEFAULT_WALLPAPER and req.entry.wallpaper_modifier==8: # yup, keep previous stuff 0472 req.entry.wallpaper=wallpaper_s[slot] 0473 req.entry.wallpaper_file=wallpaper_files[slot] 0474 req.entry.wallpaper_modifier=wallpaper_modifiers[slot] 0475 # make sure the default wallpaper has no modifier applied 0476 if req.entry.wallpaper==self.protocolclass.DEFAULT_WALLPAPER: 0477 req.entry.wallpaper_modifier=self.protocolclass.DEFAULT_WALLPAPER_MODIFIER 0478 self.log('Writing entry '+`slot`+" - "+req.entry.name+" uSlot : "+str(req.entry.uslot)) 0479 self.log('Request: '+str(req)) 0480 self.progress(i+self.protocolclass.NUMPHONEBOOKENTRIES,progressmax,"Writing "+req.entry.name) 0481 self.sendpbcommand(req, self.protocolclass.phonebookslotupdateresponse) 0482 self.progress(progressmax+1,progressmax+1, "Phone book write completed") 0483 self.setmode(self.MODEMODEM) 0484 return data 0485 # 0486 # 0487 # Get the phone Calendar 0488 # 0489 # 0490 def getcalendar(self, result): 0491 entries = {} 0492 self.log("Getting calendar entries") 0493 self.setmode(self.MODEPHONEBOOK) 0494 req=self.protocolclass.eventrequest() 0495 cal_cnt=0 0496 for slot in range(self.protocolclass.NUMCALENDAREVENTS): 0497 req.slot=slot 0498 res=self.sendpbcommand(req,self.protocolclass.eventresponse) 0499 if len(res) > 0: 0500 self.progress(slot+1, self.protocolclass.NUMCALENDAREVENTS, 0501 res[0].eventname) 0502 # build a calendar entry 0503 entry=bpcalendar.CalendarEntry() 0504 # start time date 0505 entry.start=res[0].start[0:5] 0506 if res[0].end: 0507 # valid end time 0508 entry.end=res[0].start[0:5] 0509 else: 0510 entry.end=entry.start 0511 # description 0512 entry.description=res[0].eventname 0513 try: 0514 alarm=self.__cal_alarm_values[res[0].alarm] 0515 except: 0516 alarm=None 0517 entry.alarm=alarm 0518 # update calendar dict 0519 entries[entry.id]=entry 0520 cal_cnt += 1 0521 result['calendar']=entries 0522 self.setmode(self.MODEMODEM) 0523 return result 0524 0525 # 0526 # 0527 # Save the phone Calendar 0528 # 0529 # 0530 def savecalendar(self, dict, merge): 0531 self.log("Sending calendar entries") 0532 cal=self.process_calendar(dict['calendar']) 0533 # testing 0534 if __debug__: 0535 print 'processed calendar: ', len(cal), ' items' 0536 for c in cal: 0537 print c.description,':', c.start 0538 self.setmode(self.MODEPHONEBOOK) 0539 self.log("Saving calendar entries") 0540 cal_cnt=0 0541 req=self.protocolclass.eventupdaterequest() 0542 l = self.protocolclass.NUMCALENDAREVENTS 0543 for c in cal: 0544 # Save this entry to phone 0545 # self.log('Item %d' %k) 0546 # pos 0547 req.slot=cal_cnt 0548 # start date time 0549 # print "Start ",c.start 0550 req.start=list(c.start)+[0] 0551 # end date time must be the same as start time for this phone write 0552 req.end=req.start 0553 # time stamp 0554 req.timestamp=list(time.localtime(time.time())[0:6]) 0555 # print "Alarm ",c.alarm 0556 req.alarm=c.alarm 0557 # Name, check for bad char & proper length 0558 # name=c.description.replace('"', '') 0559 name=c.description 0560 if len(name)>self.__cal_max_name_len: 0561 name=name[:self.__cal_max_name_len] 0562 req.eventname=name 0563 # and save it 0564 self.progress(cal_cnt+1, l, "Updating "+name) 0565 self.sendpbcommand(req,self.protocolclass.eventupdateresponse) 0566 cal_cnt += 1 0567 # delete the rest of the calendar slots 0568 self.log('Deleting unused entries') 0569 for k in range(cal_cnt, l): 0570 self.progress(k, l, "Deleting entry %d" % k) 0571 reqerase=self.protocolclass.eventsloterase() 0572 reqerase.slot=k 0573 self.sendpbcommand(reqerase, self.protocolclass.eventupdateresponse) 0574 self.setmode(self.MODEMODEM) 0575 0576 return dict 0577 0578 #### Profile class 0579 0580 parentprofile=com_samsung_packet.Profile 0581 class Profile(parentprofile): 0582 deviceclasses=("modem",) 0583 0584 BP_Calendar_Version=3 0585 protocolclass=Phone.protocolclass 0586 serialsname=Phone.serialsname 0587 phone_manufacturer='SAMSUNG ELECTRONICS CO.,LTD.' 0588 phone_model='SCH-A850 /180' 0589 0590 def __init__(self): 0591 parentprofile.__init__(self) 0592 self.numbertypetab=numbertypetab 0593 0594 _supportedsyncs=( 0595 ('phonebook', 'read', None), # all phonebook reading 0596 ('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook 0597 ('calendar', 'read', None), # all calendar reading 0598 ('calendar', 'write', 'OVERWRITE') # only overwriting calendar 0599 ) 0600 0601 # fill in the list of ringtone/sound origins on your phone 0602 ringtoneorigins=('ringers') 0603 #e.g. 0604 #ringtoneorigins=('ringers', 'sounds') 0605 0606 class Samsung_Calendar: 0607 _cal_alarm_values={ 0608 10: 2, 30: 3, 60: 4, -1: 0, 0: 1 } 0609 0610 def __init__(self, calendar_entry, new_date=None): 0611 self._start=self._end=self._alarm=self._desc=None 0612 self._extract_cal_info(calendar_entry, new_date) 0613 0614 def _extract_cal_info(self, cal_entry, new_date): 0615 s=cal_entry.start 0616 if new_date is not None: 0617 s=new_date[:3]+s[3:] 0618 self._start=s 0619 self._end=cal_entry.end 0620 self._desc=cal_entry.description 0621 # approximate the alarm value 0622 self._alarm=0 0623 alarm=cal_entry.alarm 0624 _keys=self._cal_alarm_values.keys() 0625 _keys.sort() 0626 _keys.reverse() 0627 for k in _keys: 0628 if alarm>=k: 0629 self._alarm=self._cal_alarm_values[k] 0630 break 0631 0632 def __lt__(self, rhs): 0633 return self.start<rhs.start 0634 def __le__(self, rhs): 0635 return self.start<=rhs.start 0636 def __eq__(self, rhs): 0637 return self.start==rhs.start 0638 def __ne__(self, rhs): 0639 return self.start!=rhs.start 0640 def __gt__(self, rhs): 0641 return self.start>rhs.start 0642 def __ge__(self, rhs): 0643 return self.start>=rhs.start 0644 0645 def _get_start(self): 0646 return self._start 0647 start=property(fget=_get_start) 0648 0649 def _get_end(self): 0650 return self._end 0651 end=property(fget=_get_end) 0652 0653 def _get_desc(self): 0654 return self._desc 0655 description=property(fget=_get_desc) 0656 0657 def _get_alarm(self): 0658 return self._alarm 0659 alarm=property(fget=_get_alarm) 0660
Generated by PyXR 0.9.4