#!/usr/bin/env python
#
# Python Serial Port Extension for Win32, Linux, BSD, Jython
# module for serial IO for POSIX compatible systems, like Linux
# see __init__.py
#
# (C) 2001-2010 Chris Liechti <cliechti@gmx.net>
# this is distributed under a free software license, see license.txt
#
# parts based on code from Grant B. Edwards  <grante@visi.com>:
#  ftp://ftp.visi.com/users/grante/python/PosixSerial.py
#
# references: http://www.easysw.com/~mike/serial/serial.html

import sys, os, fcntl, termios, struct, select, errno, time
from .serialutil import *

# Do check the Python version as some constants have moved.
if (sys.hexversion < 0x020100f0):
    import TERMIOS
else:
    TERMIOS = termios

if (sys.hexversion < 0x020200f0):
    import FCNTL
else:
    FCNTL = fcntl

# try to detect the OS so that a device can be selected...
# this code block should supply a device() and set_special_baudrate() function
# for the platform
plat = sys.platform.lower()

if   plat[:5] == 'linux':    # Linux (confirmed)

    def device(port):
        return '/dev/ttyS%d' % port

    ASYNC_SPD_MASK = 0x1030
    ASYNC_SPD_CUST = 0x0030

    def set_special_baudrate(port, baudrate):
        import array
        buf = array.array('i', [0] * 32)

        # get serial_struct
        FCNTL.ioctl(port.fd, TERMIOS.TIOCGSERIAL, buf)

        # set custom divisor
        buf[6] = buf[7] / baudrate

        # update flags
        buf[4] &= ~ASYNC_SPD_MASK
        buf[4] |= ASYNC_SPD_CUST

        # set serial_struct
        try:
            res = FCNTL.ioctl(port.fd, TERMIOS.TIOCSSERIAL, buf)
        except IOError:
            raise ValueError('Failed to set custom baud rate: %r' % baudrate)

    baudrate_constants = {
        0:       0000000,  # hang up
        50:      0o000001,
        75:      0o000002,
        110:     0o000003,
        134:     0o000004,
        150:     0o000005,
        200:     0o000006,
        300:     0o000007,
        600:     0o000010,
        1200:    0o000011,
        1800:    0o000012,
        2400:    0o000013,
        4800:    0o000014,
        9600:    0o000015,
        19200:   0o000016,
        38400:   0o000017,
        57600:   0o010001,
        115200:  0o010002,
        230400:  0o010003,
        460800:  0o010004,
        500000:  0o010005,
        576000:  0o010006,
        921600:  0o010007,
        1000000: 0o010010,
        1152000: 0o010011,
        1500000: 0o010012,
        2000000: 0o010013,
        2500000: 0o010014,
        3000000: 0o010015,
        3500000: 0o010016,
        4000000: 0o010017
    }

elif plat == 'cygwin':       # cygwin/win32 (confirmed)

    def device(port):
        return '/dev/com%d' % (port + 1)

    def set_special_baudrate(port, baudrate):
        raise ValueError("sorry don't know how to handle non standard baud rate on this platform")

    baudrate_constants = {}

elif plat == 'openbsd3':    # BSD (confirmed)

    def device(port):
        return '/dev/ttyp%d' % port

    def set_special_baudrate(port, baudrate):
        raise ValueError("sorry don't know how to handle non standard baud rate on this platform")

    baudrate_constants = {}

elif plat[:3] == 'bsd' or  \
     plat[:7] == 'freebsd' or \
     plat[:7] == 'openbsd':  # BSD (confirmed for freebsd4: cuaa%d)

    def device(port):
        return '/dev/cuad%d' % port

    def set_special_baudrate(port, baudrate):
        raise ValueError("sorry don't know how to handle non standard baud rate on this platform")

    baudrate_constants = {}

elif plat[:6] == 'darwin':   # OS X

    version = os.uname()[2].split('.')
    # Tiger or above can support arbitrary serial speeds
    if int(version[0]) >= 8:
        def set_special_baudrate(port, baudrate):
            # use IOKit-specific call to set up high speeds
            import array, fcntl
            buf = array.array('i', [baudrate])
            IOSSIOSPEED = 0x80045402 #_IOW('T', 2, speed_t)
            fcntl.ioctl(port.fd, IOSSIOSPEED, buf, 1)
    else: # version < 8
        def set_special_baudrate(port, baudrate):
            raise ValueError("baud rate not supported")

    def device(port):
        return '/dev/cuad%d' % port

    baudrate_constants = {}


elif plat[:6] == 'netbsd':   # NetBSD 1.6 testing by Erk

    def device(port):
        return '/dev/dty%02d' % port

    def set_special_baudrate(port, baudrate):
        raise ValueError("sorry don't know how to handle non standard baud rate on this platform")

    baudrate_constants = {}

elif plat[:4] == 'irix':     # IRIX (partially tested)

    def device(port):
        return '/dev/ttyf%d' % (port+1) #XXX different device names depending on flow control

    def set_special_baudrate(port, baudrate):
        raise ValueError("sorry don't know how to handle non standard baud rate on this platform")

    baudrate_constants = {}

elif plat[:2] == 'hp':       # HP-UX (not tested)

    def device(port):
        return '/dev/tty%dp0' % (port+1)

    def set_special_baudrate(port, baudrate):
        raise ValueError("sorry don't know how to handle non standard baud rate on this platform")

    baudrate_constants = {}

elif plat[:5] == 'sunos':    # Solaris/SunOS (confirmed)

    def device(port):
        return '/dev/tty%c' % (ord('a')+port)

    def set_special_baudrate(port, baudrate):
        raise ValueError("sorry don't know how to handle non standard baud rate on this platform")

    baudrate_constants = {}

elif plat[:3] == 'aix':      # AIX

    def device(port):
        return '/dev/tty%d' % (port)

    def set_special_baudrate(port, baudrate):
        raise ValueError("sorry don't know how to handle non standard baud rate on this platform")

    baudrate_constants = {}

else:
    # platform detection has failed...
    sys.stderr.write("""\
don't know how to number ttys on this system.
! Use an explicit path (eg /dev/ttyS1) or send this information to
! the author of this module:

sys.platform = %r
os.name = %r
serialposix.py version = %s

also add the device name of the serial port and where the
counting starts for the first serial port.
e.g. 'first serial port: /dev/ttyS0'
and with a bit luck you can get this module running...
""" % (sys.platform, os.name, VERSION))
    # no exception, just continue with a brave attempt to build a device name
    # even if the device name is not correct for the platform it has chances
    # to work using a string with the real device name as port parameter.
    def device(portum):
        return '/dev/ttyS%d' % portnum
    def set_special_baudrate(port, baudrate):
        raise SerialException("sorry don't know how to handle non standard baud rate on this platform")
    baudrate_constants = {}
    #~ raise Exception, "this module does not run on this platform, sorry."

# whats up with "aix", "beos", ....
# they should work, just need to know the device names.


# load some constants for later use.
# try to use values from TERMIOS, use defaults from linux otherwise
TIOCMGET  = hasattr(TERMIOS, 'TIOCMGET') and TERMIOS.TIOCMGET or 0x5415
TIOCMBIS  = hasattr(TERMIOS, 'TIOCMBIS') and TERMIOS.TIOCMBIS or 0x5416
TIOCMBIC  = hasattr(TERMIOS, 'TIOCMBIC') and TERMIOS.TIOCMBIC or 0x5417
TIOCMSET  = hasattr(TERMIOS, 'TIOCMSET') and TERMIOS.TIOCMSET or 0x5418

#TIOCM_LE = hasattr(TERMIOS, 'TIOCM_LE') and TERMIOS.TIOCM_LE or 0x001
TIOCM_DTR = hasattr(TERMIOS, 'TIOCM_DTR') and TERMIOS.TIOCM_DTR or 0x002
TIOCM_RTS = hasattr(TERMIOS, 'TIOCM_RTS') and TERMIOS.TIOCM_RTS or 0x004
#TIOCM_ST = hasattr(TERMIOS, 'TIOCM_ST') and TERMIOS.TIOCM_ST or 0x008
#TIOCM_SR = hasattr(TERMIOS, 'TIOCM_SR') and TERMIOS.TIOCM_SR or 0x010

TIOCM_CTS = hasattr(TERMIOS, 'TIOCM_CTS') and TERMIOS.TIOCM_CTS or 0x020
TIOCM_CAR = hasattr(TERMIOS, 'TIOCM_CAR') and TERMIOS.TIOCM_CAR or 0x040
TIOCM_RNG = hasattr(TERMIOS, 'TIOCM_RNG') and TERMIOS.TIOCM_RNG or 0x080
TIOCM_DSR = hasattr(TERMIOS, 'TIOCM_DSR') and TERMIOS.TIOCM_DSR or 0x100
TIOCM_CD  = hasattr(TERMIOS, 'TIOCM_CD') and TERMIOS.TIOCM_CD or TIOCM_CAR
TIOCM_RI  = hasattr(TERMIOS, 'TIOCM_RI') and TERMIOS.TIOCM_RI or TIOCM_RNG
#TIOCM_OUT1 = hasattr(TERMIOS, 'TIOCM_OUT1') and TERMIOS.TIOCM_OUT1 or 0x2000
#TIOCM_OUT2 = hasattr(TERMIOS, 'TIOCM_OUT2') and TERMIOS.TIOCM_OUT2 or 0x4000
TIOCINQ   = hasattr(TERMIOS, 'FIONREAD') and TERMIOS.FIONREAD or 0x541B

TIOCM_zero_str = struct.pack('I', 0)
TIOCM_RTS_str = struct.pack('I', TIOCM_RTS)
TIOCM_DTR_str = struct.pack('I', TIOCM_DTR)

TIOCSBRK  = hasattr(TERMIOS, 'TIOCSBRK') and TERMIOS.TIOCSBRK or 0x5427
TIOCCBRK  = hasattr(TERMIOS, 'TIOCCBRK') and TERMIOS.TIOCCBRK or 0x5428


class PosixSerial(SerialBase):
    """Serial port class POSIX implementation. Serial port configuration is 
    done with termios and fcntl. Runs on Linux and many other Un*x like
    systems."""

    def open(self):
        """Open port with current settings. This may throw a SerialException
           if the port cannot be opened."""
        self.fd = None
        if self._port is None:
            raise SerialException("Port must be configured before it can be used.")
        # open
        try:
            self.fd = os.open(self.portstr, os.O_RDWR|os.O_NOCTTY|os.O_NONBLOCK)
        except Exception as msg:
            self.fd = None
            raise SerialException("could not open port %s: %s" % (self._port, msg))
        #~ fcntl.fcntl(self.fd, FCNTL.F_SETFL, 0)  # set blocking

        try:
            self._reconfigurePort()
        except:
            try:
                os.close(self.fd)
            except:
                # ignore any exception when closing the port
                # also to keep original exception that happened when setting up
                pass
            self.fd = None
            raise
        else:
            self._isOpen = True
        #~ self.flushInput()


    def _reconfigurePort(self):
        """Set communication parameters on opened port."""
        if self.fd is None:
            raise SerialException("Can only operate on a valid file descriptor")
        custom_baud = None

        vmin = vtime = 0                # timeout is done via select
        if self._interCharTimeout is not None:
            vmin = 1
            vtime = int(self._interCharTimeout * 10)
        try:
            iflag, oflag, cflag, lflag, ispeed, ospeed, cc = termios.tcgetattr(self.fd)
        except termios.error as msg:      # if a port is nonexistent but has a /dev file, it'll fail here
            raise SerialException("Could not configure port: %s" % msg)
        # set up raw mode / no echo / binary
        cflag |=  (TERMIOS.CLOCAL|TERMIOS.CREAD)
        lflag &= ~(TERMIOS.ICANON|TERMIOS.ECHO|TERMIOS.ECHOE|TERMIOS.ECHOK|TERMIOS.ECHONL|
                     TERMIOS.ISIG|TERMIOS.IEXTEN) #|TERMIOS.ECHOPRT
        for flag in ('ECHOCTL', 'ECHOKE'): # netbsd workaround for Erk
            if hasattr(TERMIOS, flag):
                lflag &= ~getattr(TERMIOS, flag)

        oflag &= ~(TERMIOS.OPOST)
        iflag &= ~(TERMIOS.INLCR|TERMIOS.IGNCR|TERMIOS.ICRNL|TERMIOS.IGNBRK)
        if hasattr(TERMIOS, 'IUCLC'):
            iflag &= ~TERMIOS.IUCLC
        if hasattr(TERMIOS, 'PARMRK'):
            iflag &= ~TERMIOS.PARMRK

        # setup baud rate
        try:
            ispeed = ospeed = getattr(TERMIOS, 'B%s' % (self._baudrate))
        except AttributeError:
            try:
                ispeed = ospeed = baudrate_constants[self._baudrate]
            except KeyError:
                #~ raise ValueError('Invalid baud rate: %r' % self._baudrate)
                # may need custom baud rate, it isn't in our list.
                ispeed = ospeed = getattr(TERMIOS, 'B38400')
                try:
                    custom_baud = int(self._baudrate) # store for later
                except ValueError:
                    raise ValueError('Invalid baud rate: %r' % self._baudrate)
                else:
                    if custom_baud < 0:
                        raise ValueError('Invalid baud rate: %r' % self._baudrate)

        # setup char len
        cflag &= ~TERMIOS.CSIZE
        if self._bytesize == 8:
            cflag |= TERMIOS.CS8
        elif self._bytesize == 7:
            cflag |= TERMIOS.CS7
        elif self._bytesize == 6:
            cflag |= TERMIOS.CS6
        elif self._bytesize == 5:
            cflag |= TERMIOS.CS5
        else:
            raise ValueError('Invalid char len: %r' % self._bytesize)
        # setup stopbits
        if self._stopbits == STOPBITS_ONE:
            cflag &= ~(TERMIOS.CSTOPB)
        elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
            cflag |=  (TERMIOS.CSTOPB)  # XXX same as TWO.. there is no POSIX support for 1.5
        elif self._stopbits == STOPBITS_TWO:
            cflag |=  (TERMIOS.CSTOPB)
        else:
            raise ValueError('Invalid stop bit specification: %r' % self._stopbits)
        # setup parity
        iflag &= ~(TERMIOS.INPCK|TERMIOS.ISTRIP)
        if self._parity == PARITY_NONE:
            cflag &= ~(TERMIOS.PARENB|TERMIOS.PARODD)
        elif self._parity == PARITY_EVEN:
            cflag &= ~(TERMIOS.PARODD)
            cflag |=  (TERMIOS.PARENB)
        elif self._parity == PARITY_ODD:
            cflag |=  (TERMIOS.PARENB|TERMIOS.PARODD)
        else:
            raise ValueError('Invalid parity: %r' % self._parity)
        # setup flow control
        # xonxoff
        if hasattr(TERMIOS, 'IXANY'):
            if self._xonxoff:
                iflag |=  (TERMIOS.IXON|TERMIOS.IXOFF) #|TERMIOS.IXANY)
            else:
                iflag &= ~(TERMIOS.IXON|TERMIOS.IXOFF|TERMIOS.IXANY)
        else:
            if self._xonxoff:
                iflag |=  (TERMIOS.IXON|TERMIOS.IXOFF)
            else:
                iflag &= ~(TERMIOS.IXON|TERMIOS.IXOFF)
        # rtscts
        if hasattr(TERMIOS, 'CRTSCTS'):
            if self._rtscts:
                cflag |=  (TERMIOS.CRTSCTS)
            else:
                cflag &= ~(TERMIOS.CRTSCTS)
        elif hasattr(TERMIOS, 'CNEW_RTSCTS'):   # try it with alternate constant name
            if self._rtscts:
                cflag |=  (TERMIOS.CNEW_RTSCTS)
            else:
                cflag &= ~(TERMIOS.CNEW_RTSCTS)
        # XXX should there be a warning if setting up rtscts (and xonxoff etc) fails??

        # buffer
        # vmin "minimal number of characters to be read. = for non blocking"
        if vmin < 0 or vmin > 255:
            raise ValueError('Invalid vmin: %r ' % vmin)
        cc[TERMIOS.VMIN] = vmin
        # vtime
        if vtime < 0 or vtime > 255:
            raise ValueError('Invalid vtime: %r' % vtime)
        cc[TERMIOS.VTIME] = vtime
        # activate settings
        termios.tcsetattr(self.fd, TERMIOS.TCSANOW, [iflag, oflag, cflag, lflag, ispeed, ospeed, cc])

        # apply custom baud rate, if any
        if custom_baud is not None:
            set_special_baudrate(self, custom_baud)

    def close(self):
        """Close port"""
        if self._isOpen:
            if self.fd is not None:
                os.close(self.fd)
                self.fd = None
            self._isOpen = False

    def makeDeviceName(self, port):
        return device(port)

    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

    def inWaiting(self):
        """Return the number of characters currently in the input buffer."""
        #~ s = fcntl.ioctl(self.fd, TERMIOS.FIONREAD, TIOCM_zero_str)
        s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str)
        return struct.unpack('I',s)[0]

    # select based implementation, proved to work on many systems
    def read(self, size=1):
        """Read size bytes from the serial port. If a timeout is set it may
           return less characters as requested. With no timeout it will block
           until the requested number of bytes is read."""
        if self.fd is None: raise portNotOpenError
        read = bytearray()
        while len(read) < size:
            ready,_,_ = select.select([self.fd],[],[], self._timeout)
            # If select was used with a timeout, and the timeout occurs, it
            # returns with empty lists -> thus abort read operation.
            # For timeout == 0 (non-blocking operation) also abort when there
            # is nothing to read.
            if not ready:
                break   # timeout
            buf = os.read(self.fd, size-len(read))
            # read should always return some data as select reported it was
            # ready to read when we get to this point.
            if not buf:
                # Disconnected devices, at least on Linux, show the
                # behavior that they are always ready to read immediately
                # but reading returns nothing.
                raise SerialException('device reports readiness to read but returned no data (device disconnected?)')
            read.extend(buf)
        return bytes(read)

    def write(self, data):
        """Output the given string over the serial port."""
        if self.fd is None: raise portNotOpenError
        t = len(data)
        d = data
        if self._writeTimeout is not None and self._writeTimeout > 0:
            timeout = time.time() + self._writeTimeout
        else:
            timeout = None
        while t > 0:
            try:
                n = os.write(self.fd, d)
                if timeout:
                    # when timeout is set, use select to wait for being ready
                    # with the time left as timeout
                    timeleft = timeout - time.time()
                    if timeleft < 0:
                        raise writeTimeoutError
                    _, ready, _ = select.select([], [self.fd], [], timeleft)
                    if not ready:
                        raise writeTimeoutError
                d = d[n:]
                t = t - n
            except OSError as v:
                if v.errno != errno.EAGAIN:
                    raise SerialException('write failed: %s' % (v,))
        return len(data)

    def flush(self):
        """Flush of file like objects. In this case, wait until all data
           is written."""
        self.drainOutput()

    def flushInput(self):
        """Clear input buffer, discarding all that is in the buffer."""
        if self.fd is None:
            raise portNotOpenError
        termios.tcflush(self.fd, TERMIOS.TCIFLUSH)

    def flushOutput(self):
        """Clear output buffer, aborting the current output and
        discarding all that is in the buffer."""
        if self.fd is None:
            raise portNotOpenError
        termios.tcflush(self.fd, TERMIOS.TCOFLUSH)

    def sendBreak(self, duration=0.25):
        """Send break condition. Timed, returns to idle state after given duration."""
        if self.fd is None:
            raise portNotOpenError
        termios.tcsendbreak(self.fd, int(duration/0.25))

    def setBreak(self, level=1):
        """Set break: Controls TXD. When active, no transmitting is possible."""
        if self.fd is None: raise portNotOpenError
        if level:
            fcntl.ioctl(self.fd, TIOCSBRK)
        else:
            fcntl.ioctl(self.fd, TIOCCBRK)

    def setRTS(self, level=1):
        """Set terminal status line: Request To Send"""
        if self.fd is None: raise portNotOpenError
        if level:
            fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_RTS_str)
        else:
            fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_RTS_str)

    def setDTR(self, level=1):
        """Set terminal status line: Data Terminal Ready"""
        if self.fd is None: raise portNotOpenError
        if level:
            fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_DTR_str)
        else:
            fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_DTR_str)

    def getCTS(self):
        """Read terminal status line: Clear To Send"""
        if self.fd is None: raise portNotOpenError
        s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
        return struct.unpack('I',s)[0] & TIOCM_CTS != 0

    def getDSR(self):
        """Read terminal status line: Data Set Ready"""
        if self.fd is None: raise portNotOpenError
        s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
        return struct.unpack('I',s)[0] & TIOCM_DSR != 0

    def getRI(self):
        """Read terminal status line: Ring Indicator"""
        if self.fd is None: raise portNotOpenError
        s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
        return struct.unpack('I',s)[0] & TIOCM_RI != 0

    def getCD(self):
        """Read terminal status line: Carrier Detect"""
        if self.fd is None: raise portNotOpenError
        s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
        return struct.unpack('I',s)[0] & TIOCM_CD != 0

    # - - platform specific - - - -

    def drainOutput(self):
        """internal - not portable!"""
        if self.fd is None: raise portNotOpenError
        termios.tcdrain(self.fd)

    def nonblocking(self):
        """internal - not portable!"""
        if self.fd is None:
            raise portNotOpenError
        fcntl.fcntl(self.fd, FCNTL.F_SETFL, os.O_NONBLOCK)

    def fileno(self):
        """For easier use of the serial port instance with select.
           WARNING: this function is not portable to different platforms!"""
        if self.fd is None: raise portNotOpenError
        return self.fd

    def flowControl(self, enable):
        """manually control flow - when hardware or software flow control is
        enabled"""
        if enable:
            termios.tcflow(self.fd, TERMIOS.TCION)
        else:
            termios.tcflow(self.fd, TERMIOS.TCIOFF)


# assemble Serial class with the platform specifc implementation and the base
# for file-like behavior. for Python 2.6 and newer, that provide the new I/O
# library, derrive from io.RawIOBase
try:
    import io
except ImportError:
    # classic version with our own file-like emulation
    class Serial(PosixSerial, FileLike):
        pass
else:
    # io library present
    class Serial(PosixSerial, io.RawIOBase):
        pass

class PosixPollSerial(Serial):
    """poll based read implementation. not all systems support poll properly.
    however this one has better handling of errors, such as a device
    disconnecting while it's in use (e.g. USB-serial unplugged)"""

    def read(self, size=1):
        """Read size bytes from the serial port. If a timeout is set it may
           return less characters as requested. With no timeout it will block
           until the requested number of bytes is read."""
        if self.fd is None: raise portNotOpenError
        read = bytearray()
        poll = select.poll()
        poll.register(self.fd, select.POLLIN|select.POLLERR|select.POLLHUP|select.POLLNVAL)
        if size > 0:
            while len(read) < size:
                # print "\tread(): size",size, "have", len(read)    #debug
                # wait until device becomes ready to read (or something fails)
                for fd, event in poll.poll(self._timeout*1000):
                    if event & (select.POLLERR|select.POLLHUP|select.POLLNVAL):
                        raise SerialException('device reports error (poll)')
                    #  we don't care if it is select.POLLIN or timeout, that's
                    #  handled below
                buf = os.read(self.fd, size - len(read))
                read.extend(buf)
                if ((self._timeout is not None and self._timeout >= 0) or 
                    (self._interCharTimeout is not None and self._interCharTimeout > 0)) and not buf:
                    break   # early abort on timeout
        return bytes(read)


if __name__ == '__main__':
    s = Serial(0,
                 baudrate=19200,        # baud rate
                 bytesize=EIGHTBITS,    # number of data bits
                 parity=PARITY_EVEN,    # enable parity checking
                 stopbits=STOPBITS_ONE, # number of stop bits
                 timeout=3,             # set a timeout value, None for waiting forever
                 xonxoff=0,             # enable software flow control
                 rtscts=0,              # enable RTS/CTS flow control
               )
    s.setRTS(1)
    s.setDTR(1)
    s.flushInput()
    s.flushOutput()
    s.write('hello')
    sys.stdout.write('%r\n' % s.read(5))
    sys.stdout.write('%s\n' % s.inWaiting())
    del s


[((32, 7, 32, 27), 'sys.platform.lower', 'sys.platform.lower', ({}, {}), '()', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((252, 17, 252, 36), 'struct.pack', 'struct.pack', ({(252, 29, 252, 32): '"""I"""', (252, 34, 252, 35): '0'}, {}), "('I', 0)", False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((253, 16, 253, 43), 'struct.pack', 'struct.pack', ({(253, 28, 253, 31): '"""I"""', (253, 33, 253, 42): 'TIOCM_RTS'}, {}), "('I', TIOCM_RTS)", False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((254, 16, 254, 43), 'struct.pack', 'struct.pack', ({(254, 28, 254, 31): '"""I"""', (254, 33, 254, 42): 'TIOCM_DTR'}, {}), "('I', TIOCM_DTR)", False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((44, 14, 44, 40), 'array.array', 'array.array', ({(44, 26, 44, 29): '"""i"""', (44, 31, 44, 39): '[0] * 32'}, {}), "('i', [0] * 32)", False, 'import array, fcntl\n'), ((47, 8, 47, 54), 'FCNTL.ioctl', 'FCNTL.ioctl', ({(47, 20, 47, 27): 'port.fd', (47, 29, 47, 48): 'TERMIOS.TIOCGSERIAL', (47, 50, 47, 53): 'buf'}, {}), '(port.fd, TERMIOS.TIOCGSERIAL, buf)', False, 'import FCNTL\n'), ((409, 8, 409, 101), 'termios.tcsetattr', 'termios.tcsetattr', ({(409, 26, 409, 33): 'self.fd', (409, 35, 409, 50): 'TERMIOS.TCSANOW', (409, 52, 409, 100): '[iflag, oflag, cflag, lflag, ispeed, ospeed, cc]'}, {}), '(self.fd, TERMIOS.TCSANOW, [iflag, oflag, cflag, lflag,\n    ispeed, ospeed, cc])', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((431, 12, 431, 57), 'fcntl.ioctl', 'fcntl.ioctl', ({(431, 24, 431, 31): 'self.fd', (431, 33, 431, 40): 'TIOCINQ', (431, 42, 431, 56): 'TIOCM_zero_str'}, {}), '(self.fd, TIOCINQ, TIOCM_zero_str)', False, 'import array, fcntl\n'), ((497, 8, 497, 50), 'termios.tcflush', 'termios.tcflush', ({(497, 24, 497, 31): 'self.fd', (497, 33, 497, 49): 'TERMIOS.TCIFLUSH'}, {}), '(self.fd, TERMIOS.TCIFLUSH)', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((504, 8, 504, 50), 'termios.tcflush', 'termios.tcflush', ({(504, 24, 504, 31): 'self.fd', (504, 33, 504, 49): 'TERMIOS.TCOFLUSH'}, {}), '(self.fd, TERMIOS.TCOFLUSH)', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((539, 12, 539, 58), 'fcntl.ioctl', 'fcntl.ioctl', ({(539, 24, 539, 31): 'self.fd', (539, 33, 539, 41): 'TIOCMGET', (539, 43, 539, 57): 'TIOCM_zero_str'}, {}), '(self.fd, TIOCMGET, TIOCM_zero_str)', False, 'import array, fcntl\n'), ((545, 12, 545, 58), 'fcntl.ioctl', 'fcntl.ioctl', ({(545, 24, 545, 31): 'self.fd', (545, 33, 545, 41): 'TIOCMGET', (545, 43, 545, 57): 'TIOCM_zero_str'}, {}), '(self.fd, TIOCMGET, TIOCM_zero_str)', False, 'import array, fcntl\n'), ((551, 12, 551, 58), 'fcntl.ioctl', 'fcntl.ioctl', ({(551, 24, 551, 31): 'self.fd', (551, 33, 551, 41): 'TIOCMGET', (551, 43, 551, 57): 'TIOCM_zero_str'}, {}), '(self.fd, TIOCMGET, TIOCM_zero_str)', False, 'import array, fcntl\n'), ((557, 12, 557, 58), 'fcntl.ioctl', 'fcntl.ioctl', ({(557, 24, 557, 31): 'self.fd', (557, 33, 557, 41): 'TIOCMGET', (557, 43, 557, 57): 'TIOCM_zero_str'}, {}), '(self.fd, TIOCMGET, TIOCM_zero_str)', False, 'import array, fcntl\n'), ((565, 8, 565, 32), 'termios.tcdrain', 'termios.tcdrain', ({(565, 24, 565, 31): 'self.fd'}, {}), '(self.fd)', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((571, 8, 571, 58), 'fcntl.fcntl', 'fcntl.fcntl', ({(571, 20, 571, 27): 'self.fd', (571, 29, 571, 42): 'FCNTL.F_SETFL', (571, 44, 571, 57): 'os.O_NONBLOCK'}, {}), '(self.fd, FCNTL.F_SETFL, os.O_NONBLOCK)', False, 'import array, fcntl\n'), ((613, 15, 613, 28), 'select.poll', 'select.poll', ({}, {}), '()', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((58, 18, 58, 64), 'FCNTL.ioctl', 'FCNTL.ioctl', ({(58, 30, 58, 37): 'port.fd', (58, 39, 58, 58): 'TERMIOS.TIOCSSERIAL', (58, 60, 58, 63): 'buf'}, {}), '(port.fd, TERMIOS.TIOCSSERIAL, buf)', False, 'import FCNTL\n'), ((273, 22, 273, 80), 'os.open', 'os.open', ({(273, 30, 273, 42): 'self.portstr', (273, 44, 273, 79): 'os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK'}, {}), '(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((306, 61, 306, 87), 'termios.tcgetattr', 'termios.tcgetattr', ({(306, 79, 306, 86): 'self.fd'}, {}), '(self.fd)', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((432, 15, 432, 35), 'struct.unpack', 'struct.unpack', ({(432, 29, 432, 32): '"""I"""', (432, 33, 432, 34): 's'}, {}), "('I', s)", False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((442, 24, 442, 69), 'select.select', 'select.select', ({(442, 38, 442, 47): '[self.fd]', (442, 48, 442, 50): '[]', (442, 51, 442, 53): '[]', (442, 55, 442, 68): 'self._timeout'}, {}), '([self.fd], [], [], self._timeout)', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((516, 12, 516, 42), 'fcntl.ioctl', 'fcntl.ioctl', ({(516, 24, 516, 31): 'self.fd', (516, 33, 516, 41): 'TIOCSBRK'}, {}), '(self.fd, TIOCSBRK)', False, 'import array, fcntl\n'), ((518, 12, 518, 42), 'fcntl.ioctl', 'fcntl.ioctl', ({(518, 24, 518, 31): 'self.fd', (518, 33, 518, 41): 'TIOCCBRK'}, {}), '(self.fd, TIOCCBRK)', False, 'import array, fcntl\n'), ((524, 12, 524, 57), 'fcntl.ioctl', 'fcntl.ioctl', ({(524, 24, 524, 31): 'self.fd', (524, 33, 524, 41): 'TIOCMBIS', (524, 43, 524, 56): 'TIOCM_RTS_str'}, {}), '(self.fd, TIOCMBIS, TIOCM_RTS_str)', False, 'import array, fcntl\n'), ((526, 12, 526, 57), 'fcntl.ioctl', 'fcntl.ioctl', ({(526, 24, 526, 31): 'self.fd', (526, 33, 526, 41): 'TIOCMBIC', (526, 43, 526, 56): 'TIOCM_RTS_str'}, {}), '(self.fd, TIOCMBIC, TIOCM_RTS_str)', False, 'import array, fcntl\n'), ((532, 12, 532, 57), 'fcntl.ioctl', 'fcntl.ioctl', ({(532, 24, 532, 31): 'self.fd', (532, 33, 532, 41): 'TIOCMBIS', (532, 43, 532, 56): 'TIOCM_DTR_str'}, {}), '(self.fd, TIOCMBIS, TIOCM_DTR_str)', False, 'import array, fcntl\n'), ((534, 12, 534, 57), 'fcntl.ioctl', 'fcntl.ioctl', ({(534, 24, 534, 31): 'self.fd', (534, 33, 534, 41): 'TIOCMBIC', (534, 43, 534, 56): 'TIOCM_DTR_str'}, {}), '(self.fd, TIOCMBIC, TIOCM_DTR_str)', False, 'import array, fcntl\n'), ((583, 12, 583, 50), 'termios.tcflow', 'termios.tcflow', ({(583, 27, 583, 34): 'self.fd', (583, 36, 583, 49): 'TERMIOS.TCION'}, {}), '(self.fd, TERMIOS.TCION)', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((585, 12, 585, 51), 'termios.tcflow', 'termios.tcflow', ({(585, 27, 585, 34): 'self.fd', (585, 36, 585, 50): 'TERMIOS.TCIOFF'}, {}), '(self.fd, TERMIOS.TCIOFF)', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((419, 16, 419, 33), 'os.close', 'os.close', ({(419, 25, 419, 32): 'self.fd'}, {}), '(self.fd)', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((466, 22, 466, 33), 'time.time', 'time.time', ({}, {}), '()', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((471, 20, 471, 40), 'os.write', 'os.write', ({(471, 29, 471, 36): 'self.fd', (471, 38, 471, 39): 'd'}, {}), '(self.fd, d)', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((283, 16, 283, 33), 'os.close', 'os.close', ({(283, 25, 283, 32): 'self.fd'}, {}), '(self.fd)', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((478, 34, 478, 76), 'select.select', 'select.select', ({(478, 48, 478, 50): '[]', (478, 52, 478, 61): '[self.fd]', (478, 63, 478, 65): '[]', (478, 67, 478, 75): 'timeleft'}, {}), '([], [self.fd], [], timeleft)', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((540, 15, 540, 35), 'struct.unpack', 'struct.unpack', ({(540, 29, 540, 32): '"""I"""', (540, 33, 540, 34): 's'}, {}), "('I', s)", False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((546, 15, 546, 35), 'struct.unpack', 'struct.unpack', ({(546, 29, 546, 32): '"""I"""', (546, 33, 546, 34): 's'}, {}), "('I', s)", False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((552, 15, 552, 35), 'struct.unpack', 'struct.unpack', ({(552, 29, 552, 32): '"""I"""', (552, 33, 552, 34): 's'}, {}), "('I', s)", False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((558, 15, 558, 35), 'struct.unpack', 'struct.unpack', ({(558, 29, 558, 32): '"""I"""', (558, 33, 558, 34): 's'}, {}), "('I', s)", False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((475, 41, 475, 52), 'time.time', 'time.time', ({}, {}), '()', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((136, 18, 136, 46), 'array.array', 'array.array', ({(136, 30, 136, 33): '"""i"""', (136, 35, 136, 45): '[baudrate]'}, {}), "('i', [baudrate])", False, 'import array, fcntl\n'), ((138, 12, 138, 53), 'fcntl.ioctl', 'fcntl.ioctl', ({(138, 24, 138, 31): 'port.fd', (138, 33, 138, 44): 'IOSSIOSPEED', (138, 46, 138, 49): 'buf', (138, 51, 138, 52): '(1)'}, {}), '(port.fd, IOSSIOSPEED, buf, 1)', False, 'import array, fcntl\n'), ((130, 14, 130, 24), 'os.uname', 'os.uname', ({}, {}), '()', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n'), ((201, 4, 214, 39), 'sys.stderr.write', 'sys.stderr.write', ({(201, 21, 214, 38): '("""don\'t know how to number ttys on this system.\n! Use an explicit path (eg /dev/ttyS1) or send this information to\n! the author of this module:\n\nsys.platform = %r\nos.name = %r\nserialposix.py version = %s\n\nalso add the device name of the serial port and where the\ncounting starts for the first serial port.\ne.g. \'first serial port: /dev/ttyS0\'\nand with a bit luck you can get this module running...\n"""\n     % (sys.platform, os.name, VERSION))'}, {}), '(\n    """don\'t know how to number ttys on this system.\n! Use an explicit path (eg /dev/ttyS1) or send this information to\n! the author of this module:\n\nsys.platform = %r\nos.name = %r\nserialposix.py version = %s\n\nalso add the device name of the serial port and where the\ncounting starts for the first serial port.\ne.g. \'first serial port: /dev/ttyS0\'\nand with a bit luck you can get this module running...\n"""\n     % (sys.platform, os.name, VERSION))', False, 'import sys, os, fcntl, termios, struct, select, errno, time\n')]