Home | History | Annotate | Download | only in serial
      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