1#!/usr/bin/env python
2#
3# backend for serial IO for POSIX compatible systems, like Linux, OSX
4#
5# This file is part of pySerial. https://github.com/pyserial/pyserial
6# (C) 2001-2020 Chris Liechti <cliechti@gmx.net>
7#
8# SPDX-License-Identifier:    BSD-3-Clause
9#
10# parts based on code from Grant B. Edwards  <grante@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# Collection of port names (was previously used by number_to_device which was
16# removed.
17# - Linux                   /dev/ttyS%d (confirmed)
18# - cygwin/win32            /dev/com%d (confirmed)
19# - openbsd (OpenBSD)       /dev/cua%02d
20# - bsd*, freebsd*          /dev/cuad%d
21# - darwin (OS X)           /dev/cuad%d
22# - netbsd                  /dev/dty%02d (NetBSD 1.6 testing by Erk)
23# - irix (IRIX)             /dev/ttyf%d (partially tested) names depending on flow control
24# - hp (HP-UX)              /dev/tty%dp0 (not tested)
25# - sunos (Solaris/SunOS)   /dev/tty%c (letters, 'a'..'z') (confirmed)
26# - aix (AIX)               /dev/tty%d
27
28
29from __future__ import absolute_import
30
31# pylint: disable=abstract-method
32import errno
33import fcntl
34import os
35import select
36import struct
37import sys
38import termios
39
40import serial
41from serial.serialutil import SerialBase, SerialException, to_bytes, \
42    PortNotOpenError, SerialTimeoutException, Timeout
43
44
45class PlatformSpecificBase(object):
46    BAUDRATE_CONSTANTS = {}
47
48    def _set_special_baudrate(self, baudrate):
49        raise NotImplementedError('non-standard baudrates are not supported on this platform')
50
51    def _set_rs485_mode(self, rs485_settings):
52        raise NotImplementedError('RS485 not supported on this platform')
53
54    def set_low_latency_mode(self, low_latency_settings):
55        raise NotImplementedError('Low latency not supported on this platform')
56
57    def _update_break_state(self):
58        """\
59        Set break: Controls TXD. When active, no transmitting is possible.
60        """
61        if self._break_state:
62            fcntl.ioctl(self.fd, TIOCSBRK)
63        else:
64            fcntl.ioctl(self.fd, TIOCCBRK)
65
66
67# some systems support an extra flag to enable the two in POSIX unsupported
68# paritiy settings for MARK and SPACE
69CMSPAR = 0  # default, for unsupported platforms, override below
70
71# try to detect the OS so that a device can be selected...
72# this code block should supply a device() and set_special_baudrate() function
73# for the platform
74plat = sys.platform.lower()
75
76if plat[:5] == 'linux':    # Linux (confirmed)  # noqa
77    import array
78
79    # extra termios flags
80    CMSPAR = 0o10000000000  # Use "stick" (mark/space) parity
81
82    # baudrate ioctls
83    TCGETS2 = 0x802C542A
84    TCSETS2 = 0x402C542B
85    BOTHER = 0o010000
86
87    # RS485 ioctls
88    TIOCGRS485 = 0x542E
89    TIOCSRS485 = 0x542F
90    SER_RS485_ENABLED = 0b00000001
91    SER_RS485_RTS_ON_SEND = 0b00000010
92    SER_RS485_RTS_AFTER_SEND = 0b00000100
93    SER_RS485_RX_DURING_TX = 0b00010000
94
95    class PlatformSpecific(PlatformSpecificBase):
96        BAUDRATE_CONSTANTS = {
97            0:       0o000000,  # hang up
98            50:      0o000001,
99            75:      0o000002,
100            110:     0o000003,
101            134:     0o000004,
102            150:     0o000005,
103            200:     0o000006,
104            300:     0o000007,
105            600:     0o000010,
106            1200:    0o000011,
107            1800:    0o000012,
108            2400:    0o000013,
109            4800:    0o000014,
110            9600:    0o000015,
111            19200:   0o000016,
112            38400:   0o000017,
113            57600:   0o010001,
114            115200:  0o010002,
115            230400:  0o010003,
116            460800:  0o010004,
117            500000:  0o010005,
118            576000:  0o010006,
119            921600:  0o010007,
120            1000000: 0o010010,
121            1152000: 0o010011,
122            1500000: 0o010012,
123            2000000: 0o010013,
124            2500000: 0o010014,
125            3000000: 0o010015,
126            3500000: 0o010016,
127            4000000: 0o010017
128        }
129
130        def set_low_latency_mode(self, low_latency_settings):
131            buf = array.array('i', [0] * 32)
132
133            try:
134                # get serial_struct
135                fcntl.ioctl(self.fd, termios.TIOCGSERIAL, buf)
136
137                # set or unset ASYNC_LOW_LATENCY flag
138                if low_latency_settings:
139                    buf[4] |= 0x2000
140                else:
141                    buf[4] &= ~0x2000
142
143                # set serial_struct
144                fcntl.ioctl(self.fd, termios.TIOCSSERIAL, buf)
145            except IOError as e:
146                raise ValueError('Failed to update ASYNC_LOW_LATENCY flag to {}: {}'.format(low_latency_settings, e))
147
148        def _set_special_baudrate(self, baudrate):
149            # right size is 44 on x86_64, allow for some growth
150            buf = array.array('i', [0] * 64)
151            try:
152                # get serial_struct
153                fcntl.ioctl(self.fd, TCGETS2, buf)
154                # set custom speed
155                buf[2] &= ~termios.CBAUD
156                buf[2] |= BOTHER
157                buf[9] = buf[10] = baudrate
158
159                # set serial_struct
160                fcntl.ioctl(self.fd, TCSETS2, buf)
161            except IOError as e:
162                raise ValueError('Failed to set custom baud rate ({}): {}'.format(baudrate, e))
163
164        def _set_rs485_mode(self, rs485_settings):
165            buf = array.array('i', [0] * 8)  # flags, delaytx, delayrx, padding
166            try:
167                fcntl.ioctl(self.fd, TIOCGRS485, buf)
168                buf[0] |= SER_RS485_ENABLED
169                if rs485_settings is not None:
170                    if rs485_settings.loopback:
171                        buf[0] |= SER_RS485_RX_DURING_TX
172                    else:
173                        buf[0] &= ~SER_RS485_RX_DURING_TX
174                    if rs485_settings.rts_level_for_tx:
175                        buf[0] |= SER_RS485_RTS_ON_SEND
176                    else:
177                        buf[0] &= ~SER_RS485_RTS_ON_SEND
178                    if rs485_settings.rts_level_for_rx:
179                        buf[0] |= SER_RS485_RTS_AFTER_SEND
180                    else:
181                        buf[0] &= ~SER_RS485_RTS_AFTER_SEND
182                    if rs485_settings.delay_before_tx is not None:
183                        buf[1] = int(rs485_settings.delay_before_tx * 1000)
184                    if rs485_settings.delay_before_rx is not None:
185                        buf[2] = int(rs485_settings.delay_before_rx * 1000)
186                else:
187                    buf[0] = 0  # clear SER_RS485_ENABLED
188                fcntl.ioctl(self.fd, TIOCSRS485, buf)
189            except IOError as e:
190                raise ValueError('Failed to set RS485 mode: {}'.format(e))
191
192
193elif plat == 'cygwin':       # cygwin/win32 (confirmed)
194
195    class PlatformSpecific(PlatformSpecificBase):
196        BAUDRATE_CONSTANTS = {
197            128000: 0x01003,
198            256000: 0x01005,
199            500000: 0x01007,
200            576000: 0x01008,
201            921600: 0x01009,
202            1000000: 0x0100a,
203            1152000: 0x0100b,
204            1500000: 0x0100c,
205            2000000: 0x0100d,
206            2500000: 0x0100e,
207            3000000: 0x0100f
208        }
209
210
211elif plat[:6] == 'darwin':   # OS X
212    import array
213    IOSSIOSPEED = 0x80045402  # _IOW('T', 2, speed_t)
214
215    class PlatformSpecific(PlatformSpecificBase):
216        osx_version = os.uname()[2].split('.')
217        TIOCSBRK = 0x2000747B # _IO('t', 123)
218        TIOCCBRK = 0x2000747A # _IO('t', 122)
219
220        # Tiger or above can support arbitrary serial speeds
221        if int(osx_version[0]) >= 8:
222            def _set_special_baudrate(self, baudrate):
223                # use IOKit-specific call to set up high speeds
224                buf = array.array('i', [baudrate])
225                fcntl.ioctl(self.fd, IOSSIOSPEED, buf, 1)
226
227        def _update_break_state(self):
228            """\
229            Set break: Controls TXD. When active, no transmitting is possible.
230            """
231            if self._break_state:
232                fcntl.ioctl(self.fd, PlatformSpecific.TIOCSBRK)
233            else:
234                fcntl.ioctl(self.fd, PlatformSpecific.TIOCCBRK)
235
236elif plat[:3] == 'bsd' or \
237     plat[:7] == 'freebsd' or \
238     plat[:6] == 'netbsd' or \
239     plat[:7] == 'openbsd':
240
241    class ReturnBaudrate(object):
242        def __getitem__(self, key):
243            return key
244
245    class PlatformSpecific(PlatformSpecificBase):
246        # Only tested on FreeBSD:
247        # The baud rate may be passed in as
248        # a literal value.
249        BAUDRATE_CONSTANTS = ReturnBaudrate()
250
251        TIOCSBRK = 0x2000747B # _IO('t', 123)
252        TIOCCBRK = 0x2000747A # _IO('t', 122)
253
254
255        def _update_break_state(self):
256            """\
257            Set break: Controls TXD. When active, no transmitting is possible.
258            """
259            if self._break_state:
260                fcntl.ioctl(self.fd, PlatformSpecific.TIOCSBRK)
261            else:
262                fcntl.ioctl(self.fd, PlatformSpecific.TIOCCBRK)
263
264else:
265    class PlatformSpecific(PlatformSpecificBase):
266        pass
267
268
269# load some constants for later use.
270# try to use values from termios, use defaults from linux otherwise
271TIOCMGET = getattr(termios, 'TIOCMGET', 0x5415)
272TIOCMBIS = getattr(termios, 'TIOCMBIS', 0x5416)
273TIOCMBIC = getattr(termios, 'TIOCMBIC', 0x5417)
274TIOCMSET = getattr(termios, 'TIOCMSET', 0x5418)
275
276# TIOCM_LE = getattr(termios, 'TIOCM_LE', 0x001)
277TIOCM_DTR = getattr(termios, 'TIOCM_DTR', 0x002)
278TIOCM_RTS = getattr(termios, 'TIOCM_RTS', 0x004)
279# TIOCM_ST = getattr(termios, 'TIOCM_ST', 0x008)
280# TIOCM_SR = getattr(termios, 'TIOCM_SR', 0x010)
281
282TIOCM_CTS = getattr(termios, 'TIOCM_CTS', 0x020)
283TIOCM_CAR = getattr(termios, 'TIOCM_CAR', 0x040)
284TIOCM_RNG = getattr(termios, 'TIOCM_RNG', 0x080)
285TIOCM_DSR = getattr(termios, 'TIOCM_DSR', 0x100)
286TIOCM_CD = getattr(termios, 'TIOCM_CD', TIOCM_CAR)
287TIOCM_RI = getattr(termios, 'TIOCM_RI', TIOCM_RNG)
288# TIOCM_OUT1 = getattr(termios, 'TIOCM_OUT1', 0x2000)
289# TIOCM_OUT2 = getattr(termios, 'TIOCM_OUT2', 0x4000)
290if hasattr(termios, 'TIOCINQ'):
291    TIOCINQ = termios.TIOCINQ
292else:
293    TIOCINQ = getattr(termios, 'FIONREAD', 0x541B)
294TIOCOUTQ = getattr(termios, 'TIOCOUTQ', 0x5411)
295
296TIOCM_zero_str = struct.pack('I', 0)
297TIOCM_RTS_str = struct.pack('I', TIOCM_RTS)
298TIOCM_DTR_str = struct.pack('I', TIOCM_DTR)
299
300TIOCSBRK = getattr(termios, 'TIOCSBRK', 0x5427)
301TIOCCBRK = getattr(termios, 'TIOCCBRK', 0x5428)
302
303
304class Serial(SerialBase, PlatformSpecific):
305    """\
306    Serial port class POSIX implementation. Serial port configuration is
307    done with termios and fcntl. Runs on Linux and many other Un*x like
308    systems.
309    """
310
311    def open(self):
312        """\
313        Open port with current settings. This may throw a SerialException
314        if the port cannot be opened."""
315        if self._port is None:
316            raise SerialException("Port must be configured before it can be used.")
317        if self.is_open:
318            raise SerialException("Port is already open.")
319        self.fd = None
320        # open
321        try:
322            self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)
323        except OSError as msg:
324            self.fd = None
325            raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg))
326        #~ fcntl.fcntl(self.fd, fcntl.F_SETFL, 0)  # set blocking
327
328        self.pipe_abort_read_r, self.pipe_abort_read_w = None, None
329        self.pipe_abort_write_r, self.pipe_abort_write_w = None, None
330
331        try:
332            self._reconfigure_port(force_update=True)
333
334            try:
335                if not self._dsrdtr:
336                    self._update_dtr_state()
337                if not self._rtscts:
338                    self._update_rts_state()
339            except IOError as e:
340                # ignore Invalid argument and Inappropriate ioctl
341                if e.errno not in (errno.EINVAL, errno.ENOTTY):
342                    raise
343
344            self._reset_input_buffer()
345
346            self.pipe_abort_read_r, self.pipe_abort_read_w = os.pipe()
347            self.pipe_abort_write_r, self.pipe_abort_write_w = os.pipe()
348            fcntl.fcntl(self.pipe_abort_read_r, fcntl.F_SETFL, os.O_NONBLOCK)
349            fcntl.fcntl(self.pipe_abort_write_r, fcntl.F_SETFL, os.O_NONBLOCK)
350        except BaseException:
351            try:
352                os.close(self.fd)
353            except Exception:
354                # ignore any exception when closing the port
355                # also to keep original exception that happened when setting up
356                pass
357            self.fd = None
358
359            if self.pipe_abort_read_w is not None:
360                os.close(self.pipe_abort_read_w)
361                self.pipe_abort_read_w = None
362            if self.pipe_abort_read_r is not None:
363                os.close(self.pipe_abort_read_r)
364                self.pipe_abort_read_r = None
365            if self.pipe_abort_write_w is not None:
366                os.close(self.pipe_abort_write_w)
367                self.pipe_abort_write_w = None
368            if self.pipe_abort_write_r is not None:
369                os.close(self.pipe_abort_write_r)
370                self.pipe_abort_write_r = None
371
372            raise
373
374        self.is_open = True
375
376    def _reconfigure_port(self, force_update=False):
377        """Set communication parameters on opened port."""
378        if self.fd is None:
379            raise SerialException("Can only operate on a valid file descriptor")
380
381        # if exclusive lock is requested, create it before we modify anything else
382        if self._exclusive is not None:
383            if self._exclusive:
384                try:
385                    fcntl.flock(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
386                except IOError as msg:
387                    raise SerialException(msg.errno, "Could not exclusively lock port {}: {}".format(self._port, msg))
388            else:
389                fcntl.flock(self.fd, fcntl.LOCK_UN)
390
391        custom_baud = None
392
393        vmin = vtime = 0                # timeout is done via select
394        if self._inter_byte_timeout is not None:
395            vmin = 1
396            vtime = int(self._inter_byte_timeout * 10)
397        try:
398            orig_attr = termios.tcgetattr(self.fd)
399            iflag, oflag, cflag, lflag, ispeed, ospeed, cc = orig_attr
400        except termios.error as msg:      # if a port is nonexistent but has a /dev file, it'll fail here
401            raise SerialException("Could not configure port: {}".format(msg))
402        # set up raw mode / no echo / binary
403        cflag |= (termios.CLOCAL | termios.CREAD)
404        lflag &= ~(termios.ICANON | termios.ECHO | termios.ECHOE |
405                   termios.ECHOK | termios.ECHONL |
406                   termios.ISIG | termios.IEXTEN)  # |termios.ECHOPRT
407        for flag in ('ECHOCTL', 'ECHOKE'):  # netbsd workaround for Erk
408            if hasattr(termios, flag):
409                lflag &= ~getattr(termios, flag)
410
411        oflag &= ~(termios.OPOST | termios.ONLCR | termios.OCRNL)
412        iflag &= ~(termios.INLCR | termios.IGNCR | termios.ICRNL | termios.IGNBRK)
413        if hasattr(termios, 'IUCLC'):
414            iflag &= ~termios.IUCLC
415        if hasattr(termios, 'PARMRK'):
416            iflag &= ~termios.PARMRK
417
418        # setup baud rate
419        try:
420            ispeed = ospeed = getattr(termios, 'B{}'.format(self._baudrate))
421        except AttributeError:
422            try:
423                ispeed = ospeed = self.BAUDRATE_CONSTANTS[self._baudrate]
424            except KeyError:
425                #~ raise ValueError('Invalid baud rate: %r' % self._baudrate)
426
427                # See if BOTHER is defined for this platform; if it is, use
428                # this for a speed not defined in the baudrate constants list.
429                try:
430                    ispeed = ospeed = BOTHER
431                except NameError:
432                    # may need custom baud rate, it isn't in our list.
433                    ispeed = ospeed = getattr(termios, 'B38400')
434
435                try:
436                    custom_baud = int(self._baudrate)  # store for later
437                except ValueError:
438                    raise ValueError('Invalid baud rate: {!r}'.format(self._baudrate))
439                else:
440                    if custom_baud < 0:
441                        raise ValueError('Invalid baud rate: {!r}'.format(self._baudrate))
442
443        # setup char len
444        cflag &= ~termios.CSIZE
445        if self._bytesize == 8:
446            cflag |= termios.CS8
447        elif self._bytesize == 7:
448            cflag |= termios.CS7
449        elif self._bytesize == 6:
450            cflag |= termios.CS6
451        elif self._bytesize == 5:
452            cflag |= termios.CS5
453        else:
454            raise ValueError('Invalid char len: {!r}'.format(self._bytesize))
455        # setup stop bits
456        if self._stopbits == serial.STOPBITS_ONE:
457            cflag &= ~(termios.CSTOPB)
458        elif self._stopbits == serial.STOPBITS_ONE_POINT_FIVE:
459            cflag |= (termios.CSTOPB)  # XXX same as TWO.. there is no POSIX support for 1.5
460        elif self._stopbits == serial.STOPBITS_TWO:
461            cflag |= (termios.CSTOPB)
462        else:
463            raise ValueError('Invalid stop bit specification: {!r}'.format(self._stopbits))
464        # setup parity
465        iflag &= ~(termios.INPCK | termios.ISTRIP)
466        if self._parity == serial.PARITY_NONE:
467            cflag &= ~(termios.PARENB | termios.PARODD | CMSPAR)
468        elif self._parity == serial.PARITY_EVEN:
469            cflag &= ~(termios.PARODD | CMSPAR)
470            cflag |= (termios.PARENB)
471        elif self._parity == serial.PARITY_ODD:
472            cflag &= ~CMSPAR
473            cflag |= (termios.PARENB | termios.PARODD)
474        elif self._parity == serial.PARITY_MARK and CMSPAR:
475            cflag |= (termios.PARENB | CMSPAR | termios.PARODD)
476        elif self._parity == serial.PARITY_SPACE and CMSPAR:
477            cflag |= (termios.PARENB | CMSPAR)
478            cflag &= ~(termios.PARODD)
479        else:
480            raise ValueError('Invalid parity: {!r}'.format(self._parity))
481        # setup flow control
482        # xonxoff
483        if hasattr(termios, 'IXANY'):
484            if self._xonxoff:
485                iflag |= (termios.IXON | termios.IXOFF)  # |termios.IXANY)
486            else:
487                iflag &= ~(termios.IXON | termios.IXOFF | termios.IXANY)
488        else:
489            if self._xonxoff:
490                iflag |= (termios.IXON | termios.IXOFF)
491            else:
492                iflag &= ~(termios.IXON | termios.IXOFF)
493        # rtscts
494        if hasattr(termios, 'CRTSCTS'):
495            if self._rtscts:
496                cflag |= (termios.CRTSCTS)
497            else:
498                cflag &= ~(termios.CRTSCTS)
499        elif hasattr(termios, 'CNEW_RTSCTS'):   # try it with alternate constant name
500            if self._rtscts:
501                cflag |= (termios.CNEW_RTSCTS)
502            else:
503                cflag &= ~(termios.CNEW_RTSCTS)
504        # XXX should there be a warning if setting up rtscts (and xonxoff etc) fails??
505
506        # buffer
507        # vmin "minimal number of characters to be read. 0 for non blocking"
508        if vmin < 0 or vmin > 255:
509            raise ValueError('Invalid vmin: {!r}'.format(vmin))
510        cc[termios.VMIN] = vmin
511        # vtime
512        if vtime < 0 or vtime > 255:
513            raise ValueError('Invalid vtime: {!r}'.format(vtime))
514        cc[termios.VTIME] = vtime
515        # activate settings
516        if force_update or [iflag, oflag, cflag, lflag, ispeed, ospeed, cc] != orig_attr:
517            termios.tcsetattr(
518                self.fd,
519                termios.TCSANOW,
520                [iflag, oflag, cflag, lflag, ispeed, ospeed, cc])
521
522        # apply custom baud rate, if any
523        if custom_baud is not None:
524            self._set_special_baudrate(custom_baud)
525
526        if self._rs485_mode is not None:
527            self._set_rs485_mode(self._rs485_mode)
528
529    def close(self):
530        """Close port"""
531        if self.is_open:
532            if self.fd is not None:
533                os.close(self.fd)
534                self.fd = None
535                os.close(self.pipe_abort_read_w)
536                os.close(self.pipe_abort_read_r)
537                os.close(self.pipe_abort_write_w)
538                os.close(self.pipe_abort_write_r)
539                self.pipe_abort_read_r, self.pipe_abort_read_w = None, None
540                self.pipe_abort_write_r, self.pipe_abort_write_w = None, None
541            self.is_open = False
542
543    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
544
545    @property
546    def in_waiting(self):
547        """Return the number of bytes currently in the input buffer."""
548        #~ s = fcntl.ioctl(self.fd, termios.FIONREAD, TIOCM_zero_str)
549        s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str)
550        return struct.unpack('I', s)[0]
551
552    # select based implementation, proved to work on many systems
553    def read(self, size=1):
554        """\
555        Read size bytes from the serial port. If a timeout is set it may
556        return less characters as requested. With no timeout it will block
557        until the requested number of bytes is read.
558        """
559        if not self.is_open:
560            raise PortNotOpenError()
561        read = bytearray()
562        timeout = Timeout(self._timeout)
563        while len(read) < size:
564            try:
565                ready, _, _ = select.select([self.fd, self.pipe_abort_read_r], [], [], timeout.time_left())
566                if self.pipe_abort_read_r in ready:
567                    os.read(self.pipe_abort_read_r, 1000)
568                    break
569                # If select was used with a timeout, and the timeout occurs, it
570                # returns with empty lists -> thus abort read operation.
571                # For timeout == 0 (non-blocking operation) also abort when
572                # there is nothing to read.
573                if not ready:
574                    break   # timeout
575                buf = os.read(self.fd, size - len(read))
576            except OSError as e:
577                # this is for Python 3.x where select.error is a subclass of
578                # OSError ignore BlockingIOErrors and EINTR. other errors are shown
579                # https://www.python.org/dev/peps/pep-0475.
580                if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
581                    raise SerialException('read failed: {}'.format(e))
582            except select.error as e:
583                # this is for Python 2.x
584                # ignore BlockingIOErrors and EINTR. all errors are shown
585                # see also http://www.python.org/dev/peps/pep-3151/#select
586                if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
587                    raise SerialException('read failed: {}'.format(e))
588            else:
589                # read should always return some data as select reported it was
590                # ready to read when we get to this point.
591                if not buf:
592                    # Disconnected devices, at least on Linux, show the
593                    # behavior that they are always ready to read immediately
594                    # but reading returns nothing.
595                    raise SerialException(
596                        'device reports readiness to read but returned no data '
597                        '(device disconnected or multiple access on port?)')
598                read.extend(buf)
599
600            if timeout.expired():
601                break
602        return bytes(read)
603
604    def cancel_read(self):
605        if self.is_open:
606            os.write(self.pipe_abort_read_w, b"x")
607
608    def cancel_write(self):
609        if self.is_open:
610            os.write(self.pipe_abort_write_w, b"x")
611
612    def write(self, data):
613        """Output the given byte string over the serial port."""
614        if not self.is_open:
615            raise PortNotOpenError()
616        d = to_bytes(data)
617        tx_len = length = len(d)
618        timeout = Timeout(self._write_timeout)
619        while tx_len > 0:
620            try:
621                n = os.write(self.fd, d)
622                if timeout.is_non_blocking:
623                    # Zero timeout indicates non-blocking - simply return the
624                    # number of bytes of data actually written
625                    return n
626                elif not timeout.is_infinite:
627                    # when timeout is set, use select to wait for being ready
628                    # with the time left as timeout
629                    if timeout.expired():
630                        raise SerialTimeoutException('Write timeout')
631                    abort, ready, _ = select.select([self.pipe_abort_write_r], [self.fd], [], timeout.time_left())
632                    if abort:
633                        os.read(self.pipe_abort_write_r, 1000)
634                        break
635                    if not ready:
636                        raise SerialTimeoutException('Write timeout')
637                else:
638                    assert timeout.time_left() is None
639                    # wait for write operation
640                    abort, ready, _ = select.select([self.pipe_abort_write_r], [self.fd], [], None)
641                    if abort:
642                        os.read(self.pipe_abort_write_r, 1)
643                        break
644                    if not ready:
645                        raise SerialException('write failed (select)')
646                d = d[n:]
647                tx_len -= n
648            except SerialException:
649                raise
650            except OSError as e:
651                # this is for Python 3.x where select.error is a subclass of
652                # OSError ignore BlockingIOErrors and EINTR. other errors are shown
653                # https://www.python.org/dev/peps/pep-0475.
654                if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
655                    raise SerialException('write failed: {}'.format(e))
656            except select.error as e:
657                # this is for Python 2.x
658                # ignore BlockingIOErrors and EINTR. all errors are shown
659                # see also http://www.python.org/dev/peps/pep-3151/#select
660                if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
661                    raise SerialException('write failed: {}'.format(e))
662            if not timeout.is_non_blocking and timeout.expired():
663                raise SerialTimeoutException('Write timeout')
664        return length - len(d)
665
666    def flush(self):
667        """\
668        Flush of file like objects. In this case, wait until all data
669        is written.
670        """
671        if not self.is_open:
672            raise PortNotOpenError()
673        termios.tcdrain(self.fd)
674
675    def _reset_input_buffer(self):
676        """Clear input buffer, discarding all that is in the buffer."""
677        termios.tcflush(self.fd, termios.TCIFLUSH)
678
679    def reset_input_buffer(self):
680        """Clear input buffer, discarding all that is in the buffer."""
681        if not self.is_open:
682            raise PortNotOpenError()
683        self._reset_input_buffer()
684
685    def reset_output_buffer(self):
686        """\
687        Clear output buffer, aborting the current output and discarding all
688        that is in the buffer.
689        """
690        if not self.is_open:
691            raise PortNotOpenError()
692        termios.tcflush(self.fd, termios.TCOFLUSH)
693
694    def send_break(self, duration=0.25):
695        """\
696        Send break condition. Timed, returns to idle state after given
697        duration.
698        """
699        if not self.is_open:
700            raise PortNotOpenError()
701        termios.tcsendbreak(self.fd, int(duration / 0.25))
702
703    def _update_rts_state(self):
704        """Set terminal status line: Request To Send"""
705        if self._rts_state:
706            fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_RTS_str)
707        else:
708            fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_RTS_str)
709
710    def _update_dtr_state(self):
711        """Set terminal status line: Data Terminal Ready"""
712        if self._dtr_state:
713            fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_DTR_str)
714        else:
715            fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_DTR_str)
716
717    @property
718    def cts(self):
719        """Read terminal status line: Clear To Send"""
720        if not self.is_open:
721            raise PortNotOpenError()
722        s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
723        return struct.unpack('I', s)[0] & TIOCM_CTS != 0
724
725    @property
726    def dsr(self):
727        """Read terminal status line: Data Set Ready"""
728        if not self.is_open:
729            raise PortNotOpenError()
730        s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
731        return struct.unpack('I', s)[0] & TIOCM_DSR != 0
732
733    @property
734    def ri(self):
735        """Read terminal status line: Ring Indicator"""
736        if not self.is_open:
737            raise PortNotOpenError()
738        s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
739        return struct.unpack('I', s)[0] & TIOCM_RI != 0
740
741    @property
742    def cd(self):
743        """Read terminal status line: Carrier Detect"""
744        if not self.is_open:
745            raise PortNotOpenError()
746        s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
747        return struct.unpack('I', s)[0] & TIOCM_CD != 0
748
749    # - - platform specific - - - -
750
751    @property
752    def out_waiting(self):
753        """Return the number of bytes currently in the output buffer."""
754        #~ s = fcntl.ioctl(self.fd, termios.FIONREAD, TIOCM_zero_str)
755        s = fcntl.ioctl(self.fd, TIOCOUTQ, TIOCM_zero_str)
756        return struct.unpack('I', s)[0]
757
758    def fileno(self):
759        """\
760        For easier use of the serial port instance with select.
761        WARNING: this function is not portable to different platforms!
762        """
763        if not self.is_open:
764            raise PortNotOpenError()
765        return self.fd
766
767    def set_input_flow_control(self, enable=True):
768        """\
769        Manually control flow - when software flow control is enabled.
770        This will send XON (true) or XOFF (false) to the other device.
771        WARNING: this function is not portable to different platforms!
772        """
773        if not self.is_open:
774            raise PortNotOpenError()
775        if enable:
776            termios.tcflow(self.fd, termios.TCION)
777        else:
778            termios.tcflow(self.fd, termios.TCIOFF)
779
780    def set_output_flow_control(self, enable=True):
781        """\
782        Manually control flow of outgoing data - when hardware or software flow
783        control is enabled.
784        WARNING: this function is not portable to different platforms!
785        """
786        if not self.is_open:
787            raise PortNotOpenError()
788        if enable:
789            termios.tcflow(self.fd, termios.TCOON)
790        else:
791            termios.tcflow(self.fd, termios.TCOOFF)
792
793    def nonblocking(self):
794        """DEPRECATED - has no use"""
795        import warnings
796        warnings.warn("nonblocking() has no effect, already nonblocking", DeprecationWarning)
797
798
799class PosixPollSerial(Serial):
800    """\
801    Poll based read implementation. Not all systems support poll properly.
802    However this one has better handling of errors, such as a device
803    disconnecting while it's in use (e.g. USB-serial unplugged).
804    """
805
806    def read(self, size=1):
807        """\
808        Read size bytes from the serial port. If a timeout is set it may
809        return less characters as requested. With no timeout it will block
810        until the requested number of bytes is read.
811        """
812        if not self.is_open:
813            raise PortNotOpenError()
814        read = bytearray()
815        timeout = Timeout(self._timeout)
816        poll = select.poll()
817        poll.register(self.fd, select.POLLIN | select.POLLERR | select.POLLHUP | select.POLLNVAL)
818        poll.register(self.pipe_abort_read_r, select.POLLIN | select.POLLERR | select.POLLHUP | select.POLLNVAL)
819        if size > 0:
820            while len(read) < size:
821                # print "\tread(): size",size, "have", len(read)    #debug
822                # wait until device becomes ready to read (or something fails)
823                for fd, event in poll.poll(None if timeout.is_infinite else (timeout.time_left() * 1000)):
824                    if fd == self.pipe_abort_read_r:
825                        break
826                    if event & (select.POLLERR | select.POLLHUP | select.POLLNVAL):
827                        raise SerialException('device reports error (poll)')
828                    #  we don't care if it is select.POLLIN or timeout, that's
829                    #  handled below
830                if fd == self.pipe_abort_read_r:
831                    os.read(self.pipe_abort_read_r, 1000)
832                    break
833                buf = os.read(self.fd, size - len(read))
834                read.extend(buf)
835                if timeout.expired() \
836                        or (self._inter_byte_timeout is not None and self._inter_byte_timeout > 0) and not buf:
837                    break   # early abort on timeout
838        return bytes(read)
839
840
841class VTIMESerial(Serial):
842    """\
843    Implement timeout using vtime of tty device instead of using select.
844    This means that no inter character timeout can be specified and that
845    the error handling is degraded.
846
847    Overall timeout is disabled when inter-character timeout is used.
848
849    Note that this implementation does NOT support cancel_read(), it will
850    just ignore that.
851    """
852
853    def _reconfigure_port(self, force_update=True):
854        """Set communication parameters on opened port."""
855        super(VTIMESerial, self)._reconfigure_port()
856        fcntl.fcntl(self.fd, fcntl.F_SETFL, 0)  # clear O_NONBLOCK
857
858        if self._inter_byte_timeout is not None:
859            vmin = 1
860            vtime = int(self._inter_byte_timeout * 10)
861        elif self._timeout is None:
862            vmin = 1
863            vtime = 0
864        else:
865            vmin = 0
866            vtime = int(self._timeout * 10)
867        try:
868            orig_attr = termios.tcgetattr(self.fd)
869            iflag, oflag, cflag, lflag, ispeed, ospeed, cc = orig_attr
870        except termios.error as msg:      # if a port is nonexistent but has a /dev file, it'll fail here
871            raise serial.SerialException("Could not configure port: {}".format(msg))
872
873        if vtime < 0 or vtime > 255:
874            raise ValueError('Invalid vtime: {!r}'.format(vtime))
875        cc[termios.VTIME] = vtime
876        cc[termios.VMIN] = vmin
877
878        termios.tcsetattr(
879                self.fd,
880                termios.TCSANOW,
881                [iflag, oflag, cflag, lflag, ispeed, ospeed, cc])
882
883    def read(self, size=1):
884        """\
885        Read size bytes from the serial port. If a timeout is set it may
886        return less characters as requested. With no timeout it will block
887        until the requested number of bytes is read.
888        """
889        if not self.is_open:
890            raise PortNotOpenError()
891        read = bytearray()
892        while len(read) < size:
893            buf = os.read(self.fd, size - len(read))
894            if not buf:
895                break
896            read.extend(buf)
897        return bytes(read)
898
899    # hack to make hasattr return false
900    cancel_read = property()
901