aboutsummaryrefslogtreecommitdiff
path: root/serial/serialposix.py
diff options
context:
space:
mode:
Diffstat (limited to 'serial/serialposix.py')
-rw-r--r--serial/serialposix.py74
1 files changed, 59 insertions, 15 deletions
diff --git a/serial/serialposix.py b/serial/serialposix.py
index bb2fa03..507e2fe 100644
--- a/serial/serialposix.py
+++ b/serial/serialposix.py
@@ -26,6 +26,8 @@
# - aix (AIX) /dev/tty%d
+from __future__ import absolute_import
+
# pylint: disable=abstract-method
import errno
import fcntl
@@ -49,6 +51,9 @@ class PlatformSpecificBase(object):
def _set_rs485_mode(self, rs485_settings):
raise NotImplementedError('RS485 not supported on this platform')
+ def set_low_latency_mode(self, low_latency_settings):
+ raise NotImplementedError('Low latency not supported on this platform')
+
# some systems support an extra flag to enable the two in POSIX unsupported
# paritiy settings for MARK and SPACE
@@ -113,6 +118,24 @@ if plat[:5] == 'linux': # Linux (confirmed) # noqa
4000000: 0o010017
}
+ def set_low_latency_mode(self, low_latency_settings):
+ buf = array.array('i', [0] * 32)
+
+ try:
+ # get serial_struct
+ fcntl.ioctl(self.fd, termios.TIOCGSERIAL, buf)
+
+ # set or unset ASYNC_LOW_LATENCY flag
+ if low_latency_settings:
+ buf[4] |= 0x2000
+ else:
+ buf[4] &= ~0x2000
+
+ # set serial_struct
+ fcntl.ioctl(self.fd, termios.TIOCSSERIAL, buf)
+ except IOError as e:
+ raise ValueError('Failed to update ASYNC_LOW_LATENCY flag to {}: {}'.format(low_latency_settings, e))
+
def _set_special_baudrate(self, baudrate):
# right size is 44 on x86_64, allow for some growth
buf = array.array('i', [0] * 64)
@@ -503,24 +526,27 @@ class Serial(SerialBase, PlatformSpecific):
read.extend(buf)
except OSError as e:
# this is for Python 3.x where select.error is a subclass of
- # OSError ignore EAGAIN errors. all other errors are shown
- if e.errno != errno.EAGAIN and e.errno != errno.EINTR:
+ # OSError ignore BlockingIOErrors and EINTR. other errors are shown
+ # https://www.python.org/dev/peps/pep-0475.
+ if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
raise SerialException('read failed: {}'.format(e))
except select.error as e:
# this is for Python 2.x
- # ignore EAGAIN errors. all other errors are shown
+ # ignore BlockingIOErrors and EINTR. all errors are shown
# see also http://www.python.org/dev/peps/pep-3151/#select
- if e[0] != errno.EAGAIN:
+ if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
raise SerialException('read failed: {}'.format(e))
if timeout.expired():
break
return bytes(read)
def cancel_read(self):
- os.write(self.pipe_abort_read_w, b"x")
+ if self.is_open:
+ os.write(self.pipe_abort_read_w, b"x")
def cancel_write(self):
- os.write(self.pipe_abort_write_w, b"x")
+ if self.is_open:
+ os.write(self.pipe_abort_write_w, b"x")
def write(self, data):
"""Output the given byte string over the serial port."""
@@ -560,12 +586,20 @@ class Serial(SerialBase, PlatformSpecific):
tx_len -= n
except SerialException:
raise
- except OSError as v:
- if v.errno != errno.EAGAIN:
- raise SerialException('write failed: {}'.format(v))
- # still calculate and check timeout
- if timeout.expired():
- raise writeTimeoutError
+ except OSError as e:
+ # this is for Python 3.x where select.error is a subclass of
+ # OSError ignore BlockingIOErrors and EINTR. other errors are shown
+ # https://www.python.org/dev/peps/pep-0475.
+ if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
+ raise SerialException('write failed: {}'.format(e))
+ except select.error as e:
+ # this is for Python 2.x
+ # ignore BlockingIOErrors and EINTR. all errors are shown
+ # see also http://www.python.org/dev/peps/pep-3151/#select
+ if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
+ raise SerialException('write failed: {}'.format(e))
+ if not timeout.is_non_blocking and timeout.expired():
+ raise writeTimeoutError
return length - len(d)
def flush(self):
@@ -722,21 +756,28 @@ class PosixPollSerial(Serial):
if not self.is_open:
raise portNotOpenError
read = bytearray()
+ timeout = Timeout(self._timeout)
poll = select.poll()
poll.register(self.fd, select.POLLIN | select.POLLERR | select.POLLHUP | select.POLLNVAL)
+ poll.register(self.pipe_abort_read_r, 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):
+ for fd, event in poll.poll(None if timeout.is_infinite else (timeout.time_left() * 1000)):
+ if fd == self.pipe_abort_read_r:
+ break
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
+ if fd == self.pipe_abort_read_r:
+ os.read(self.pipe_abort_read_r, 1000)
+ break
buf = os.read(self.fd, size - len(read))
read.extend(buf)
- if ((self._timeout is not None and self._timeout >= 0) or
- (self._inter_byte_timeout is not None and self._inter_byte_timeout > 0)) and not buf:
+ if timeout.expired() \
+ or (self._inter_byte_timeout is not None and self._inter_byte_timeout > 0) and not buf:
break # early abort on timeout
return bytes(read)
@@ -748,6 +789,9 @@ class VTIMESerial(Serial):
the error handling is degraded.
Overall timeout is disabled when inter-character timeout is used.
+
+ Note that this implementation does NOT support cancel_read(), it will
+ just ignore that.
"""
def _reconfigure_port(self, force_update=True):