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: commport.py 4436 2007-10-30 23:10:47Z djpham $ 0009 0010 """Encapsulates the serial port device""" 0011 0012 import serial 0013 import sys 0014 import common 0015 import time 0016 import threading 0017 import data_recording 0018 0019 try: 0020 import native.usb as usb 0021 except: 0022 usb=None 0023 0024 # have to work around an annoying bug in LGE drivers 0025 try: 0026 import pywintypes 0027 except: 0028 pywintypes=None 0029 0030 class CommTimeout(Exception): 0031 def __init__(self, str=None, partial=None): 0032 Exception.__init__(self, str) 0033 self.partial=partial 0034 0035 class ATError(Exception): 0036 def __init__(self, str=None, partial=None): 0037 Exception.__init__(self, str) 0038 self.partial=partial 0039 0040 class CommConnection: 0041 usbwhine=0 0042 def __init__(self, logtarget, port, baud=115200, timeout=3, hardwareflow=0, 0043 softwareflow=0, autolistfunc=None, autolistargs=None, configparameters=None): 0044 self._brokennotifications=0 0045 self.ser=None 0046 self.port=port 0047 self.logtarget=logtarget 0048 self.clearcounters() 0049 if usb is None and self.usbwhine<1: 0050 self.log("USB support is not available") 0051 self.success=False 0052 self.shouldloop=False 0053 self.ports=None 0054 self.autolistfunc=autolistfunc 0055 self.autolistargs=autolistargs 0056 self.configparameters=configparameters 0057 self.params=(baud,timeout,hardwareflow,softwareflow) 0058 self.readahead="" 0059 assert port!="auto" or (port=="auto" and autolistfunc is not None) 0060 if autolistfunc is not None: 0061 self._isauto=True 0062 else: 0063 self._isauto=False 0064 if port=="auto": 0065 self.log("Auto detected port requested") 0066 self.NextAutoPort() 0067 else: 0068 self._openport(self.port, *self.params) 0069 0070 def IsAuto(self): 0071 return self._isauto 0072 0073 def close(self): 0074 if self.ser is not None: 0075 try: 0076 # sometimes this gives invalid handles and similar issues 0077 self.ser.close() 0078 except: 0079 pass 0080 self.ser=None 0081 0082 def _openport(self, port, baud, timeout, hardwareflow, softwareflow, description=None): 0083 if data_recording.DR_Play: 0084 # we're doing playback, ignore this 0085 self.log('Open of comm port ignored') 0086 return 0087 self.close() 0088 self.log("Opening port %s, %d baud, timeout %f, hardwareflow %d, softwareflow %d" % 0089 (port, baud, float(timeout), hardwareflow, softwareflow) ) 0090 if description is not None: 0091 self.log(description) 0092 # we try twice since some platforms fail the first time 0093 for dummy in range(2): 0094 try: 0095 self.close() 0096 if port.startswith("usb::"): 0097 self.ser=self._openusb(port, timeout) 0098 else: 0099 useport=port 0100 if sys.platform=='win32' and port.lower().startswith("com"): useport="\\\\?\\"+port 0101 self.ser=serial.Serial(useport, baud, timeout=timeout, rtscts=hardwareflow, xonxoff=softwareflow) 0102 self.log("Open of comm port suceeded") 0103 self.port=port 0104 self.clearcounters() 0105 return 0106 except serial.serialutil.SerialException,e: 0107 if dummy: 0108 self.log('Open of comm port failed') 0109 raise common.CommsOpenFailure(e.__str__(), port) 0110 time.sleep(2) 0111 0112 def _openusb(self, name, timeout): 0113 self.close() 0114 if usb is None: 0115 self.log("USB module not available - unable to open "+name) 0116 raise Exception("USB module not available - unable to open "+name) 0117 _,wantedbus,wanteddev,wantediface=name.split("::") 0118 wantediface=int(wantediface) 0119 usb.UpdateLists() 0120 for bus in usb.AllBusses(): 0121 if bus.name()!=wantedbus: 0122 continue 0123 for device in bus.devices(): 0124 if device.name()!=wanteddev: 0125 continue 0126 for iface in device.interfaces(): 0127 if iface.number()!=wantediface: 0128 continue 0129 return _usbdevicewrapper(iface.openbulk(), timeout) 0130 self.log("Failed to find "+name+". You may need to rescan.") 0131 raise common.CommsOpenFailure("Failed to find usb device "+name) 0132 0133 0134 def reset(self): 0135 self._openport(self.port, *self.params) 0136 0137 def _refreshautoports(self): 0138 # ensure we close current port first 0139 self.close() 0140 self.ports=self.autolistfunc(*self.autolistargs) 0141 assert self.ports is not None 0142 self.success=False 0143 self.portstried=self.ports 0144 0145 def NextAutoPort(self): 0146 # do we need to refresh list? 0147 if (self.ports is None and self.autolistfunc is not None) or \ 0148 ( len(self.ports)==0 and (self.success or self.shouldloop)): 0149 self._refreshautoports() 0150 self.shouldloop=False 0151 # have we run out? 0152 if len(self.ports)==0: 0153 self.ports=None # so user can retry 0154 raise common.AutoPortsFailure(map(lambda x: x[0], self.portstried)) 0155 # try first in list 0156 self.log("Trying next auto port") 0157 description=self.ports[0][1]['description'] 0158 self.port=self.ports[0][0] 0159 self.ports=self.ports[1:] 0160 try: 0161 self._openport(self.port, *(self.params+(description,))) 0162 except common.CommsOpenFailure: 0163 self.NextAutoPort() 0164 0165 def clearcounters(self): 0166 self.readbytes=0 0167 self.readrequests=0 0168 self.writebytes=0 0169 self.writerequests=0 0170 0171 def log(self, str): 0172 if self.logtarget: 0173 self.logtarget.log(self.port+": "+str) 0174 0175 def logdata(self, str, data, data_type=None): 0176 if self.logtarget: 0177 self.logtarget.logdata(self.port+": "+str, data, 0178 None, data_type) 0179 0180 def setbaudrate(self, rate): 0181 """Change to the specified baud rate 0182 0183 @rtype: Boolean 0184 @returns: True on success, False on failure 0185 """ 0186 try: 0187 self.ser.setBaudrate(rate) 0188 self.log("Changed port speed to "+`rate`) 0189 time.sleep(.5) 0190 return True 0191 except SilentException: 0192 return False 0193 except Exception,e: 0194 self.log("Port speed "+`rate`+" not supported") 0195 return False 0196 0197 def setdtr(self, dtr): 0198 """Set or Clear DTR 0199 0200 @rtype: Boolean 0201 @returns: True on success, False on failure 0202 """ 0203 try: 0204 self.ser.setDTR(dtr) 0205 self.log("DTR set to "+`dtr`) 0206 return True 0207 except SilentException: 0208 return False 0209 0210 def setrts(self, rts): 0211 """Set or Clear RTS 0212 0213 @rtype: Boolean 0214 @returns: True on success, False on failure 0215 """ 0216 try: 0217 self.ser.setRTS(rts) 0218 self.log("RTS set to "+`rts`) 0219 return True 0220 except SilentException: 0221 return False 0222 0223 def _write(self, data, log=True): 0224 self.writerequests+=1 0225 # if we're doing data play back, just ignore this, for now! 0226 if data_recording.DR_Play: 0227 return 0228 if log or data_recording.DR_On: 0229 self.logdata("Writing", data, data_recording.DR_Type_Write) 0230 self.ser.write(data) 0231 self.writebytes+=len(data) 0232 0233 def write_thread(self, data, log): 0234 try: 0235 self._write(data, log) 0236 self._write_res=True 0237 except Exception,e: 0238 self.log('Write Exception: '+str(e)) 0239 def write(self, data, log=True): 0240 _t=threading.Thread(target=self.write_thread, args=(data, log)) 0241 self._write_res=False 0242 _t.start() 0243 _t.join(self.params[1]+1) 0244 if _t.isAlive(): 0245 _t._Thread__stop() 0246 if not self._write_res: 0247 raise CommTimeout() 0248 0249 def sendatcommand(self, atcommand, ignoreerror=False, retry=False): 0250 #print "sendatcommand: "+atcommand 0251 0252 if not data_recording.DR_Play: 0253 # Flush leftover characters 0254 b=self.ser.inWaiting() 0255 if b: 0256 self.read(b,0) 0257 0258 fullline="AT"+atcommand 0259 self.write(str(fullline+"\r\n")) 0260 # Cache response 0261 try: 0262 self.readatresponse(ignoreerror) 0263 except CommTimeout: 0264 if retry: 0265 # try to read a response 1 more time 0266 self.readatresponse(ignoreerror) 0267 else: 0268 raise 0269 0270 res=[] 0271 0272 line=self.getcleanline() 0273 if line==fullline: 0274 line=self.getcleanline() 0275 while line!="OK" and line: 0276 if line=="ERROR": 0277 if not ignoreerror: 0278 raise ATError 0279 else: 0280 res.append(line) 0281 line=self.getcleanline() 0282 0283 return res 0284 0285 def peekline(self): 0286 return self.getcleanline(peek=True) 0287 0288 def getcleanline(self, peek=False): 0289 i=0 0290 sbuf=self.readahead 0291 if len(sbuf)==0: 0292 return "" 0293 while sbuf[i]!='\n' and sbuf[i]!='\r': 0294 i+=1 0295 firstline=sbuf[0:i] 0296 if not peek: 0297 i+=1 0298 while i<len(sbuf): 0299 if sbuf[i]!='\n' and sbuf[i]!='\r': 0300 break 0301 i+=1 0302 self.readahead=self.readahead[i:] 0303 return firstline 0304 0305 def readatresponse(self, ignoreerror, log=True): 0306 """Read until OK, ERROR or a timeout""" 0307 self.readrequests+=1 0308 if data_recording.DR_Play: 0309 res=data_recording.get_data(data_recording.DR_Type_Read_ATResponse) 0310 if res: 0311 self.readahead=res 0312 return 0313 else: 0314 raise CommTimeout() 0315 res="" 0316 while True: 0317 b=self.ser.inWaiting() 0318 if b: 0319 res=res+self.read(b,0) 0320 if res.find("OK\r")>=0 or (res.find("ERROR\r")>=0 and not ignoreerror): 0321 break 0322 continue 0323 r=self.read(1,0) 0324 if len(r): 0325 res=res+r 0326 continue 0327 break 0328 0329 while len(res)>0 and (res[0]=='\n' or res[0]=='\r'): 0330 res=res[1:] 0331 0332 if len(res)==0: 0333 self.logdata("Reading remaining data", '', 0334 data_recording.DR_Type_Read_ATResponse) 0335 raise CommTimeout() 0336 0337 self.readbytes+=len(res) 0338 self.readahead=res 0339 if log or data_recording.DR_On: 0340 self.logdata("Reading remaining data", res, 0341 data_recording.DR_Type_Read_ATResponse) 0342 return 0343 0344 def readline(self): 0345 return self.getcleanline(peek=False) 0346 0347 def _isbrokendriver(self, e): 0348 if pywintypes is None or not isinstance(e, pywintypes.error) or e[0]!=121: 0349 return False 0350 return True 0351 0352 def _brokendriverread(self, numchars): 0353 # we handle timeouts ourselves in this code 0354 self._brokennotifications+=1 0355 if self._brokennotifications==3: 0356 self.log("This driver is broken - enabling workaround") 0357 basetime=time.time() 0358 while time.time()-basetime<self.params[1]: 0359 try: 0360 res=self.ser.read(numchars) 0361 return res 0362 except Exception,e: 0363 if not self._isbrokendriver(e): 0364 raise 0365 raise CommTimeout() 0366 0367 def _read(self, numchars=1, log=True): 0368 self.readrequests+=1 0369 if data_recording.DR_Play: 0370 return data_recording.get_data(data_recording.DR_Type_Read) 0371 try: 0372 res=self.ser.read(numchars) 0373 except Exception,e: 0374 if not self._isbrokendriver(e): 0375 raise 0376 res=self._brokendriverread(numchars) 0377 if log or data_recording.DR_On: 0378 self.logdata("Reading exact data - requested "+`numchars`, res, 0379 data_recording.DR_Type_Read) 0380 self.readbytes+=len(res) 0381 return res 0382 0383 def read_thread(self, numchars=1, log=True): 0384 try: 0385 self._read_res=self._read(numchars, log) 0386 except Exception,e: 0387 self.log('Read Exception: '+str(e)) 0388 0389 def read(self, numchars=1, log=True): 0390 _t=threading.Thread(target=self.read_thread, args=(numchars, log)) 0391 self._read_res=None 0392 _t.start() 0393 _t.join(self.params[1]+1) 0394 if _t.isAlive(): 0395 _t._Thread__stop() 0396 if self._read_res is None: 0397 raise CommTimeout() 0398 return self._read_res 0399 0400 def readsome(self, log=True, numchars=None): 0401 self.readrequests+=1 0402 if data_recording.DR_Play: 0403 return data_recording.get_data(data_recording.DR_Type_Read_Some) 0404 res="" 0405 while True: 0406 if numchars is not None and len(res)>= numchars: 0407 break 0408 b=self.ser.inWaiting() 0409 if b: 0410 res=res+self.read(b,0) 0411 continue 0412 r=self.read(1,0) 0413 if len(r): 0414 res=res+r 0415 continue 0416 break 0417 if len(res)==0: 0418 raise CommTimeout() 0419 self.readbytes+=len(res) 0420 if log or data_recording.DR_On: 0421 self.logdata("Reading remaining data", res, 0422 data_recording.DR_Type_Read_Some) 0423 return res 0424 0425 def readuntil(self, char, log=True, logsuccess=True, numfailures=0): 0426 # Keeps reading until it hits char 0427 self.readrequests+=1 0428 if data_recording.DR_Play: 0429 return data_recording.get_data(data_recording.DR_Type_Read_Until) 0430 if False: # don't log this anymore 0431 self.logdata("Begin reading until 0x%02x" % (ord(char),), None) 0432 0433 # set numfailures to non-zero for retries on timeouts 0434 res='' 0435 while len(res)==0 or res[-1]!=char: 0436 if hasattr(self.ser, 'readuntil'): 0437 # usb does it directly 0438 res2=self.ser.readuntil(char) 0439 b=-99999 0440 else: 0441 b=self.ser.inWaiting() 0442 if b<1: b=1 0443 res2=self.read(b,0) 0444 if len(res2)<1: 0445 if numfailures==0: 0446 if log: 0447 self.log("Timed out waiting for %02x, requested bytes %d - %d bytes read" % 0448 (ord(char), b, len(res))) 0449 self.logdata("Incomplete read was", res) 0450 self.readbytes+=len(res) 0451 raise CommTimeout(partial=res) 0452 else: 0453 numfailures-=1 0454 self.log("Timed out - flushing and trying again") 0455 res=res+res2 0456 0457 self.readbytes+=len(res) 0458 if logsuccess or data_recording.DR_On: 0459 self.logdata("Read completed", res, 0460 data_recording.DR_Type_Read_Until) 0461 return res 0462 0463 # these methods here consolidate calls, which makes the BitFling stuff a lot faster due 0464 # to fewer roundtrips 0465 def writethenreaduntil(self, data, logwrite, char, logreaduntil=True, logreaduntilsuccess=True, numfailures=1): 0466 self.write(data, logwrite) 0467 return self.readuntil(char, logreaduntil, logreaduntilsuccess, numfailures) 0468 0469 class SilentException(Exception): pass 0470 0471 class _usbdevicewrapper: 0472 0473 def __init__(self, dev, timeout): 0474 self.dev=dev 0475 self.timeout=int(timeout*1000) 0476 0477 def inWaiting(self): 0478 # This will cause one byte at a time reads in the other code. 0479 # It isn't really possible to fix until we have built in 0480 # buffering for the comm stuff. 0481 return 0 0482 0483 def read(self, numchars=1): 0484 return self.dev.read(numchars, self.timeout) 0485 0486 def flushInput(self): 0487 self.dev.resetep() 0488 0489 def write(self, data): 0490 self.dev.write(data, self.timeout) 0491 0492 def close(self): 0493 self.dev.close() 0494 0495 def readuntil(self, char): 0496 # try and get it all in one shot 0497 try: 0498 data=self.dev.read(999999, self.timeout) 0499 if len(data) and data[-1]==char: 0500 return data 0501 except usb.USBException: 0502 # ahh, buggy hardware or something 0503 self.dev.resetep() 0504 data="" 0505 # do it the old fashioned way 0506 basetime=time.time() 0507 while 1000*(time.time()-basetime)<self.timeout: 0508 try: 0509 more=self.dev.read(99999, max(100,self.timeout-1000*(time.time()-basetime))) 0510 data+=more 0511 if len(data) and data[-1]==char: 0512 return data 0513 except usb.USBException: 0514 pass 0515 # timed out 0516 return data 0517
Generated by PyXR 0.9.4