1 #!/usr/bin/env python 2 # 3 # Python Serial Port Extension for Win32, Linux, BSD, Jython 4 # module for serial IO for POSIX compatible systems, like Linux 5 # see __init__.py 6 # 7 # (C) 2001-2010 Chris Liechti <cliechti (at] gmx.net> 8 # this is distributed under a free software license, see license.txt 9 # 10 # parts based on code from Grant B. Edwards <grante (at] visi.com>: 11 # ftp://ftp.visi.com/users/grante/python/PosixSerial.py 12 # 13 # references: http://www.easysw.com/~mike/serial/serial.html 14 15 import sys, os, fcntl, termios, struct, select, errno, time 16 from serial.serialutil import * 17 18 # Do check the Python version as some constants have moved. 19 if (sys.hexversion < 0x020100f0): 20 import TERMIOS 21 else: 22 TERMIOS = termios 23 24 if (sys.hexversion < 0x020200f0): 25 import FCNTL 26 else: 27 FCNTL = fcntl 28 29 # try to detect the OS so that a device can be selected... 30 # this code block should supply a device() and set_special_baudrate() function 31 # for the platform 32 plat = sys.platform.lower() 33 34 if plat[:5] == 'linux': # Linux (confirmed) 35 36 def device(port): 37 return '/dev/ttyS%d' % port 38 39 TCGETS2 = 0x802C542A 40 TCSETS2 = 0x402C542B 41 BOTHER = 0o010000 42 43 def set_special_baudrate(port, baudrate): 44 # right size is 44 on x86_64, allow for some growth 45 import array 46 buf = array.array('i', [0] * 64) 47 48 try: 49 # get serial_struct 50 FCNTL.ioctl(port.fd, TCGETS2, buf) 51 # set custom speed 52 buf[2] &= ~TERMIOS.CBAUD 53 buf[2] |= BOTHER 54 buf[9] = buf[10] = baudrate 55 56 # set serial_struct 57 res = FCNTL.ioctl(port.fd, TCSETS2, buf) 58 except IOError, e: 59 raise ValueError('Failed to set custom baud rate (%s): %s' % (baudrate, e)) 60 61 baudrate_constants = { 62 0: 0000000, # hang up 63 50: 0000001, 64 75: 0000002, 65 110: 0000003, 66 134: 0000004, 67 150: 0000005, 68 200: 0000006, 69 300: 0000007, 70 600: 0000010, 71 1200: 0000011, 72 1800: 0000012, 73 2400: 0000013, 74 4800: 0000014, 75 9600: 0000015, 76 19200: 0000016, 77 38400: 0000017, 78 57600: 0010001, 79 115200: 0010002, 80 230400: 0010003, 81 460800: 0010004, 82 500000: 0010005, 83 576000: 0010006, 84 921600: 0010007, 85 1000000: 0010010, 86 1152000: 0010011, 87 1500000: 0010012, 88 2000000: 0010013, 89 2500000: 0010014, 90 3000000: 0010015, 91 3500000: 0010016, 92 4000000: 0010017 93 } 94 95 elif plat == 'cygwin': # cygwin/win32 (confirmed) 96 97 def device(port): 98 return '/dev/com%d' % (port + 1) 99 100 def set_special_baudrate(port, baudrate): 101 raise ValueError("sorry don't know how to handle non standard baud rate on this platform") 102 103 baudrate_constants = { 104 128000: 0x01003, 105 256000: 0x01005, 106 500000: 0x01007, 107 576000: 0x01008, 108 921600: 0x01009, 109 1000000: 0x0100a, 110 1152000: 0x0100b, 111 1500000: 0x0100c, 112 2000000: 0x0100d, 113 2500000: 0x0100e, 114 3000000: 0x0100f 115 } 116 117 elif plat[:7] == 'openbsd': # OpenBSD 118 119 def device(port): 120 return '/dev/cua%02d' % port 121 122 def set_special_baudrate(port, baudrate): 123 raise ValueError("sorry don't know how to handle non standard baud rate on this platform") 124 125 baudrate_constants = {} 126 127 elif plat[:3] == 'bsd' or \ 128 plat[:7] == 'freebsd': 129 130 def device(port): 131 return '/dev/cuad%d' % port 132 133 def set_special_baudrate(port, baudrate): 134 raise ValueError("sorry don't know how to handle non standard baud rate on this platform") 135 136 baudrate_constants = {} 137 138 elif plat[:6] == 'darwin': # OS X 139 140 version = os.uname()[2].split('.') 141 # Tiger or above can support arbitrary serial speeds 142 if int(version[0]) >= 8: 143 def set_special_baudrate(port, baudrate): 144 # use IOKit-specific call to set up high speeds 145 import array, fcntl 146 buf = array.array('i', [baudrate]) 147 IOSSIOSPEED = 0x80045402 #_IOW('T', 2, speed_t) 148 fcntl.ioctl(port.fd, IOSSIOSPEED, buf, 1) 149 else: # version < 8 150 def set_special_baudrate(port, baudrate): 151 raise ValueError("baud rate not supported") 152 153 def device(port): 154 return '/dev/cuad%d' % port 155 156 baudrate_constants = {} 157 158 159 elif plat[:6] == 'netbsd': # NetBSD 1.6 testing by Erk 160 161 def device(port): 162 return '/dev/dty%02d' % port 163 164 def set_special_baudrate(port, baudrate): 165 raise ValueError("sorry don't know how to handle non standard baud rate on this platform") 166 167 baudrate_constants = {} 168 169 elif plat[:4] == 'irix': # IRIX (partially tested) 170 171 def device(port): 172 return '/dev/ttyf%d' % (port+1) #XXX different device names depending on flow control 173 174 def set_special_baudrate(port, baudrate): 175 raise ValueError("sorry don't know how to handle non standard baud rate on this platform") 176 177 baudrate_constants = {} 178 179 elif plat[:2] == 'hp': # HP-UX (not tested) 180 181 def device(port): 182 return '/dev/tty%dp0' % (port+1) 183 184 def set_special_baudrate(port, baudrate): 185 raise ValueError("sorry don't know how to handle non standard baud rate on this platform") 186 187 baudrate_constants = {} 188 189 elif plat[:5] == 'sunos': # Solaris/SunOS (confirmed) 190 191 def device(port): 192 return '/dev/tty%c' % (ord('a')+port) 193 194 def set_special_baudrate(port, baudrate): 195 raise ValueError("sorry don't know how to handle non standard baud rate on this platform") 196 197 baudrate_constants = {} 198 199 elif plat[:3] == 'aix': # AIX 200 201 def device(port): 202 return '/dev/tty%d' % (port) 203 204 def set_special_baudrate(port, baudrate): 205 raise ValueError("sorry don't know how to handle non standard baud rate on this platform") 206 207 baudrate_constants = {} 208 209 else: 210 # platform detection has failed... 211 sys.stderr.write("""\ 212 don't know how to number ttys on this system. 213 ! Use an explicit path (eg /dev/ttyS1) or send this information to 214 ! the author of this module: 215 216 sys.platform = %r 217 os.name = %r 218 serialposix.py version = %s 219 220 also add the device name of the serial port and where the 221 counting starts for the first serial port. 222 e.g. 'first serial port: /dev/ttyS0' 223 and with a bit luck you can get this module running... 224 """ % (sys.platform, os.name, VERSION)) 225 # no exception, just continue with a brave attempt to build a device name 226 # even if the device name is not correct for the platform it has chances 227 # to work using a string with the real device name as port parameter. 228 def device(portum): 229 return '/dev/ttyS%d' % portnum 230 def set_special_baudrate(port, baudrate): 231 raise SerialException("sorry don't know how to handle non standard baud rate on this platform") 232 baudrate_constants = {} 233 #~ raise Exception, "this module does not run on this platform, sorry." 234 235 # whats up with "aix", "beos", .... 236 # they should work, just need to know the device names. 237 238 239 # load some constants for later use. 240 # try to use values from TERMIOS, use defaults from linux otherwise 241 TIOCMGET = hasattr(TERMIOS, 'TIOCMGET') and TERMIOS.TIOCMGET or 0x5415 242 TIOCMBIS = hasattr(TERMIOS, 'TIOCMBIS') and TERMIOS.TIOCMBIS or 0x5416 243 TIOCMBIC = hasattr(TERMIOS, 'TIOCMBIC') and TERMIOS.TIOCMBIC or 0x5417 244 TIOCMSET = hasattr(TERMIOS, 'TIOCMSET') and TERMIOS.TIOCMSET or 0x5418 245 246 #TIOCM_LE = hasattr(TERMIOS, 'TIOCM_LE') and TERMIOS.TIOCM_LE or 0x001 247 TIOCM_DTR = hasattr(TERMIOS, 'TIOCM_DTR') and TERMIOS.TIOCM_DTR or 0x002 248 TIOCM_RTS = hasattr(TERMIOS, 'TIOCM_RTS') and TERMIOS.TIOCM_RTS or 0x004 249 #TIOCM_ST = hasattr(TERMIOS, 'TIOCM_ST') and TERMIOS.TIOCM_ST or 0x008 250 #TIOCM_SR = hasattr(TERMIOS, 'TIOCM_SR') and TERMIOS.TIOCM_SR or 0x010 251 252 TIOCM_CTS = hasattr(TERMIOS, 'TIOCM_CTS') and TERMIOS.TIOCM_CTS or 0x020 253 TIOCM_CAR = hasattr(TERMIOS, 'TIOCM_CAR') and TERMIOS.TIOCM_CAR or 0x040 254 TIOCM_RNG = hasattr(TERMIOS, 'TIOCM_RNG') and TERMIOS.TIOCM_RNG or 0x080 255 TIOCM_DSR = hasattr(TERMIOS, 'TIOCM_DSR') and TERMIOS.TIOCM_DSR or 0x100 256 TIOCM_CD = hasattr(TERMIOS, 'TIOCM_CD') and TERMIOS.TIOCM_CD or TIOCM_CAR 257 TIOCM_RI = hasattr(TERMIOS, 'TIOCM_RI') and TERMIOS.TIOCM_RI or TIOCM_RNG 258 #TIOCM_OUT1 = hasattr(TERMIOS, 'TIOCM_OUT1') and TERMIOS.TIOCM_OUT1 or 0x2000 259 #TIOCM_OUT2 = hasattr(TERMIOS, 'TIOCM_OUT2') and TERMIOS.TIOCM_OUT2 or 0x4000 260 if hasattr(TERMIOS, 'TIOCINQ'): 261 TIOCINQ = TERMIOS.TIOCINQ 262 else: 263 TIOCINQ = hasattr(TERMIOS, 'FIONREAD') and TERMIOS.FIONREAD or 0x541B 264 TIOCOUTQ = hasattr(TERMIOS, 'TIOCOUTQ') and TERMIOS.TIOCOUTQ or 0x5411 265 266 TIOCM_zero_str = struct.pack('I', 0) 267 TIOCM_RTS_str = struct.pack('I', TIOCM_RTS) 268 TIOCM_DTR_str = struct.pack('I', TIOCM_DTR) 269 270 TIOCSBRK = hasattr(TERMIOS, 'TIOCSBRK') and TERMIOS.TIOCSBRK or 0x5427 271 TIOCCBRK = hasattr(TERMIOS, 'TIOCCBRK') and TERMIOS.TIOCCBRK or 0x5428 272 273 274 class PosixSerial(SerialBase): 275 """Serial port class POSIX implementation. Serial port configuration is 276 done with termios and fcntl. Runs on Linux and many other Un*x like 277 systems.""" 278 279 def open(self): 280 """Open port with current settings. This may throw a SerialException 281 if the port cannot be opened.""" 282 if self._port is None: 283 raise SerialException("Port must be configured before it can be used.") 284 if self._isOpen: 285 raise SerialException("Port is already open.") 286 self.fd = None 287 # open 288 try: 289 self.fd = os.open(self.portstr, os.O_RDWR|os.O_NOCTTY|os.O_NONBLOCK) 290 except IOError, msg: 291 self.fd = None 292 raise SerialException(msg.errno, "could not open port %s: %s" % (self._port, msg)) 293 #~ fcntl.fcntl(self.fd, FCNTL.F_SETFL, 0) # set blocking 294 295 try: 296 self._reconfigurePort() 297 except: 298 try: 299 os.close(self.fd) 300 except: 301 # ignore any exception when closing the port 302 # also to keep original exception that happened when setting up 303 pass 304 self.fd = None 305 raise 306 else: 307 self._isOpen = True 308 self.flushInput() 309 310 311 def _reconfigurePort(self): 312 """Set communication parameters on opened port.""" 313 if self.fd is None: 314 raise SerialException("Can only operate on a valid file descriptor") 315 custom_baud = None 316 317 vmin = vtime = 0 # timeout is done via select 318 if self._interCharTimeout is not None: 319 vmin = 1 320 vtime = int(self._interCharTimeout * 10) 321 try: 322 orig_attr = termios.tcgetattr(self.fd) 323 iflag, oflag, cflag, lflag, ispeed, ospeed, cc = orig_attr 324 except termios.error, msg: # if a port is nonexistent but has a /dev file, it'll fail here 325 raise SerialException("Could not configure port: %s" % msg) 326 # set up raw mode / no echo / binary 327 cflag |= (TERMIOS.CLOCAL|TERMIOS.CREAD) 328 lflag &= ~(TERMIOS.ICANON|TERMIOS.ECHO|TERMIOS.ECHOE|TERMIOS.ECHOK|TERMIOS.ECHONL| 329 TERMIOS.ISIG|TERMIOS.IEXTEN) #|TERMIOS.ECHOPRT 330 for flag in ('ECHOCTL', 'ECHOKE'): # netbsd workaround for Erk 331 if hasattr(TERMIOS, flag): 332 lflag &= ~getattr(TERMIOS, flag) 333 334 oflag &= ~(TERMIOS.OPOST) 335 iflag &= ~(TERMIOS.INLCR|TERMIOS.IGNCR|TERMIOS.ICRNL|TERMIOS.IGNBRK) 336 if hasattr(TERMIOS, 'IUCLC'): 337 iflag &= ~TERMIOS.IUCLC 338 if hasattr(TERMIOS, 'PARMRK'): 339 iflag &= ~TERMIOS.PARMRK 340 341 # setup baud rate 342 try: 343 ispeed = ospeed = getattr(TERMIOS, 'B%s' % (self._baudrate)) 344 except AttributeError: 345 try: 346 ispeed = ospeed = baudrate_constants[self._baudrate] 347 except KeyError: 348 #~ raise ValueError('Invalid baud rate: %r' % self._baudrate) 349 # may need custom baud rate, it isn't in our list. 350 ispeed = ospeed = getattr(TERMIOS, 'B38400') 351 try: 352 custom_baud = int(self._baudrate) # store for later 353 except ValueError: 354 raise ValueError('Invalid baud rate: %r' % self._baudrate) 355 else: 356 if custom_baud < 0: 357 raise ValueError('Invalid baud rate: %r' % self._baudrate) 358 359 # setup char len 360 cflag &= ~TERMIOS.CSIZE 361 if self._bytesize == 8: 362 cflag |= TERMIOS.CS8 363 elif self._bytesize == 7: 364 cflag |= TERMIOS.CS7 365 elif self._bytesize == 6: 366 cflag |= TERMIOS.CS6 367 elif self._bytesize == 5: 368 cflag |= TERMIOS.CS5 369 else: 370 raise ValueError('Invalid char len: %r' % self._bytesize) 371 # setup stopbits 372 if self._stopbits == STOPBITS_ONE: 373 cflag &= ~(TERMIOS.CSTOPB) 374 elif self._stopbits == STOPBITS_ONE_POINT_FIVE: 375 cflag |= (TERMIOS.CSTOPB) # XXX same as TWO.. there is no POSIX support for 1.5 376 elif self._stopbits == STOPBITS_TWO: 377 cflag |= (TERMIOS.CSTOPB) 378 else: 379 raise ValueError('Invalid stop bit specification: %r' % self._stopbits) 380 # setup parity 381 iflag &= ~(TERMIOS.INPCK|TERMIOS.ISTRIP) 382 if self._parity == PARITY_NONE: 383 cflag &= ~(TERMIOS.PARENB|TERMIOS.PARODD) 384 elif self._parity == PARITY_EVEN: 385 cflag &= ~(TERMIOS.PARODD) 386 cflag |= (TERMIOS.PARENB) 387 elif self._parity == PARITY_ODD: 388 cflag |= (TERMIOS.PARENB|TERMIOS.PARODD) 389 else: 390 raise ValueError('Invalid parity: %r' % self._parity) 391 # setup flow control 392 # xonxoff 393 if hasattr(TERMIOS, 'IXANY'): 394 if self._xonxoff: 395 iflag |= (TERMIOS.IXON|TERMIOS.IXOFF) #|TERMIOS.IXANY) 396 else: 397 iflag &= ~(TERMIOS.IXON|TERMIOS.IXOFF|TERMIOS.IXANY) 398 else: 399 if self._xonxoff: 400 iflag |= (TERMIOS.IXON|TERMIOS.IXOFF) 401 else: 402 iflag &= ~(TERMIOS.IXON|TERMIOS.IXOFF) 403 # rtscts 404 if hasattr(TERMIOS, 'CRTSCTS'): 405 if self._rtscts: 406 cflag |= (TERMIOS.CRTSCTS) 407 else: 408 cflag &= ~(TERMIOS.CRTSCTS) 409 elif hasattr(TERMIOS, 'CNEW_RTSCTS'): # try it with alternate constant name 410 if self._rtscts: 411 cflag |= (TERMIOS.CNEW_RTSCTS) 412 else: 413 cflag &= ~(TERMIOS.CNEW_RTSCTS) 414 # XXX should there be a warning if setting up rtscts (and xonxoff etc) fails?? 415 416 # buffer 417 # vmin "minimal number of characters to be read. = for non blocking" 418 if vmin < 0 or vmin > 255: 419 raise ValueError('Invalid vmin: %r ' % vmin) 420 cc[TERMIOS.VMIN] = vmin 421 # vtime 422 if vtime < 0 or vtime > 255: 423 raise ValueError('Invalid vtime: %r' % vtime) 424 cc[TERMIOS.VTIME] = vtime 425 # activate settings 426 if [iflag, oflag, cflag, lflag, ispeed, ospeed, cc] != orig_attr: 427 termios.tcsetattr(self.fd, TERMIOS.TCSANOW, [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]) 428 429 # apply custom baud rate, if any 430 if custom_baud is not None: 431 set_special_baudrate(self, custom_baud) 432 433 def close(self): 434 """Close port""" 435 if self._isOpen: 436 if self.fd is not None: 437 os.close(self.fd) 438 self.fd = None 439 self._isOpen = False 440 441 def makeDeviceName(self, port): 442 return device(port) 443 444 # - - - - - - - - - - - - - - - - - - - - - - - - 445 446 def inWaiting(self): 447 """Return the number of characters currently in the input buffer.""" 448 #~ s = fcntl.ioctl(self.fd, TERMIOS.FIONREAD, TIOCM_zero_str) 449 s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str) 450 return struct.unpack('I',s)[0] 451 452 # select based implementation, proved to work on many systems 453 def read(self, size=1): 454 """Read size bytes from the serial port. If a timeout is set it may 455 return less characters as requested. With no timeout it will block 456 until the requested number of bytes is read.""" 457 if not self._isOpen: raise portNotOpenError 458 read = bytearray() 459 while len(read) < size: 460 try: 461 ready,_,_ = select.select([self.fd],[],[], self._timeout) 462 # If select was used with a timeout, and the timeout occurs, it 463 # returns with empty lists -> thus abort read operation. 464 # For timeout == 0 (non-blocking operation) also abort when there 465 # is nothing to read. 466 if not ready: 467 break # timeout 468 buf = os.read(self.fd, size-len(read)) 469 # read should always return some data as select reported it was 470 # ready to read when we get to this point. 471 if not buf: 472 # Disconnected devices, at least on Linux, show the 473 # behavior that they are always ready to read immediately 474 # but reading returns nothing. 475 raise SerialException('device reports readiness to read but returned no data (device disconnected or multiple access on port?)') 476 read.extend(buf) 477 except select.error, e: 478 # ignore EAGAIN errors. all other errors are shown 479 # see also http://www.python.org/dev/peps/pep-3151/#select 480 if e[0] != errno.EAGAIN: 481 raise SerialException('read failed: %s' % (e,)) 482 except OSError, e: 483 # ignore EAGAIN errors. all other errors are shown 484 if e.errno != errno.EAGAIN: 485 raise SerialException('read failed: %s' % (e,)) 486 return bytes(read) 487 488 def write(self, data): 489 """Output the given string over the serial port.""" 490 if not self._isOpen: raise portNotOpenError 491 d = to_bytes(data) 492 tx_len = len(d) 493 if self._writeTimeout is not None and self._writeTimeout > 0: 494 timeout = time.time() + self._writeTimeout 495 else: 496 timeout = None 497 while tx_len > 0: 498 try: 499 n = os.write(self.fd, d) 500 if timeout: 501 # when timeout is set, use select to wait for being ready 502 # with the time left as timeout 503 timeleft = timeout - time.time() 504 if timeleft < 0: 505 raise writeTimeoutError 506 _, ready, _ = select.select([], [self.fd], [], timeleft) 507 if not ready: 508 raise writeTimeoutError 509 else: 510 # wait for write operation 511 _, ready, _ = select.select([], [self.fd], [], None) 512 if not ready: 513 raise SerialException('write failed (select)') 514 d = d[n:] 515 tx_len -= n 516 except OSError, v: 517 if v.errno != errno.EAGAIN: 518 raise SerialException('write failed: %s' % (v,)) 519 return len(data) 520 521 def flush(self): 522 """Flush of file like objects. In this case, wait until all data 523 is written.""" 524 self.drainOutput() 525 526 def flushInput(self): 527 """Clear input buffer, discarding all that is in the buffer.""" 528 if not self._isOpen: raise portNotOpenError 529 termios.tcflush(self.fd, TERMIOS.TCIFLUSH) 530 531 def flushOutput(self): 532 """Clear output buffer, aborting the current output and 533 discarding all that is in the buffer.""" 534 if not self._isOpen: raise portNotOpenError 535 termios.tcflush(self.fd, TERMIOS.TCOFLUSH) 536 537 def sendBreak(self, duration=0.25): 538 """Send break condition. Timed, returns to idle state after given duration.""" 539 if not self._isOpen: raise portNotOpenError 540 termios.tcsendbreak(self.fd, int(duration/0.25)) 541 542 def setBreak(self, level=1): 543 """Set break: Controls TXD. When active, no transmitting is possible.""" 544 if self.fd is None: raise portNotOpenError 545 if level: 546 fcntl.ioctl(self.fd, TIOCSBRK) 547 else: 548 fcntl.ioctl(self.fd, TIOCCBRK) 549 550 def setRTS(self, level=1): 551 """Set terminal status line: Request To Send""" 552 if not self._isOpen: raise portNotOpenError 553 if level: 554 fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_RTS_str) 555 else: 556 fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_RTS_str) 557 558 def setDTR(self, level=1): 559 """Set terminal status line: Data Terminal Ready""" 560 if not self._isOpen: raise portNotOpenError 561 if level: 562 fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_DTR_str) 563 else: 564 fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_DTR_str) 565 566 def getCTS(self): 567 """Read terminal status line: Clear To Send""" 568 if not self._isOpen: raise portNotOpenError 569 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) 570 return struct.unpack('I',s)[0] & TIOCM_CTS != 0 571 572 def getDSR(self): 573 """Read terminal status line: Data Set Ready""" 574 if not self._isOpen: raise portNotOpenError 575 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) 576 return struct.unpack('I',s)[0] & TIOCM_DSR != 0 577 578 def getRI(self): 579 """Read terminal status line: Ring Indicator""" 580 if not self._isOpen: raise portNotOpenError 581 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) 582 return struct.unpack('I',s)[0] & TIOCM_RI != 0 583 584 def getCD(self): 585 """Read terminal status line: Carrier Detect""" 586 if not self._isOpen: raise portNotOpenError 587 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) 588 return struct.unpack('I',s)[0] & TIOCM_CD != 0 589 590 # - - platform specific - - - - 591 592 def outWaiting(self): 593 """Return the number of characters currently in the output buffer.""" 594 #~ s = fcntl.ioctl(self.fd, TERMIOS.FIONREAD, TIOCM_zero_str) 595 s = fcntl.ioctl(self.fd, TIOCOUTQ, TIOCM_zero_str) 596 return struct.unpack('I',s)[0] 597 598 def drainOutput(self): 599 """internal - not portable!""" 600 if not self._isOpen: raise portNotOpenError 601 termios.tcdrain(self.fd) 602 603 def nonblocking(self): 604 """internal - not portable!""" 605 if not self._isOpen: raise portNotOpenError 606 fcntl.fcntl(self.fd, FCNTL.F_SETFL, os.O_NONBLOCK) 607 608 def fileno(self): 609 """\ 610 For easier use of the serial port instance with select. 611 WARNING: this function is not portable to different platforms! 612 """ 613 if not self._isOpen: raise portNotOpenError 614 return self.fd 615 616 def setXON(self, level=True): 617 """\ 618 Manually control flow - when software flow control is enabled. 619 This will send XON (true) and XOFF (false) to the other device. 620 WARNING: this function is not portable to different platforms! 621 """ 622 if not self.hComPort: raise portNotOpenError 623 if enable: 624 termios.tcflow(self.fd, TERMIOS.TCION) 625 else: 626 termios.tcflow(self.fd, TERMIOS.TCIOFF) 627 628 def flowControlOut(self, enable): 629 """\ 630 Manually control flow of outgoing data - when hardware or software flow 631 control is enabled. 632 WARNING: this function is not portable to different platforms! 633 """ 634 if not self._isOpen: raise portNotOpenError 635 if enable: 636 termios.tcflow(self.fd, TERMIOS.TCOON) 637 else: 638 termios.tcflow(self.fd, TERMIOS.TCOOFF) 639 640 641 # assemble Serial class with the platform specifc implementation and the base 642 # for file-like behavior. for Python 2.6 and newer, that provide the new I/O 643 # library, derrive from io.RawIOBase 644 try: 645 import io 646 except ImportError: 647 # classic version with our own file-like emulation 648 class Serial(PosixSerial, FileLike): 649 pass 650 else: 651 # io library present 652 class Serial(PosixSerial, io.RawIOBase): 653 pass 654 655 class PosixPollSerial(Serial): 656 """poll based read implementation. not all systems support poll properly. 657 however this one has better handling of errors, such as a device 658 disconnecting while it's in use (e.g. USB-serial unplugged)""" 659 660 def read(self, size=1): 661 """Read size bytes from the serial port. If a timeout is set it may 662 return less characters as requested. With no timeout it will block 663 until the requested number of bytes is read.""" 664 if self.fd is None: raise portNotOpenError 665 read = bytearray() 666 poll = select.poll() 667 poll.register(self.fd, select.POLLIN|select.POLLERR|select.POLLHUP|select.POLLNVAL) 668 if size > 0: 669 while len(read) < size: 670 # print "\tread(): size",size, "have", len(read) #debug 671 # wait until device becomes ready to read (or something fails) 672 for fd, event in poll.poll(self._timeout*1000): 673 if event & (select.POLLERR|select.POLLHUP|select.POLLNVAL): 674 raise SerialException('device reports error (poll)') 675 # we don't care if it is select.POLLIN or timeout, that's 676 # handled below 677 buf = os.read(self.fd, size - len(read)) 678 read.extend(buf) 679 if ((self._timeout is not None and self._timeout >= 0) or 680 (self._interCharTimeout is not None and self._interCharTimeout > 0)) and not buf: 681 break # early abort on timeout 682 return bytes(read) 683 684 685 if __name__ == '__main__': 686 s = Serial(0, 687 baudrate=19200, # baud rate 688 bytesize=EIGHTBITS, # number of data bits 689 parity=PARITY_EVEN, # enable parity checking 690 stopbits=STOPBITS_ONE, # number of stop bits 691 timeout=3, # set a timeout value, None for waiting forever 692 xonxoff=0, # enable software flow control 693 rtscts=0, # enable RTS/CTS flow control 694 ) 695 s.setRTS(1) 696 s.setDTR(1) 697 s.flushInput() 698 s.flushOutput() 699 s.write('hello') 700 sys.stdout.write('%r\n' % s.read(5)) 701 sys.stdout.write('%s\n' % s.inWaiting()) 702 del s 703 704