summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--documentation/pyserial_api.rst10
-rw-r--r--documentation/shortintro.rst17
-rw-r--r--documentation/url_handlers.rst11
-rw-r--r--serial/serialposix.py13
-rw-r--r--serial/tools/list_ports_linux.py19
-rw-r--r--serial/tools/list_ports_posix.py32
-rw-r--r--serial/tools/miniterm.py3
-rw-r--r--serial/urlhandler/protocol_spy.py47
8 files changed, 114 insertions, 38 deletions
diff --git a/documentation/pyserial_api.rst b/documentation/pyserial_api.rst
index 12a7765..fd15db5 100644
--- a/documentation/pyserial_api.rst
+++ b/documentation/pyserial_api.rst
@@ -150,7 +150,7 @@ Native ports
:rtype: bytes
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
+ return fewer characters than requested. With no timeout it will block
until the requested number of bytes is read.
.. versionchanged:: 2.5
@@ -166,7 +166,7 @@ Native ports
Read until an expected sequence is found ('\\n' by default), the size
is exceeded or until timeout occurs. If a timeout is set it may
- return less characters as requested. With no timeout it will block
+ return fewer characters than requested. With no timeout it will block
until the requested number of bytes is read.
.. versionchanged:: 2.5
@@ -486,11 +486,11 @@ Native ports
.. method:: readline(size=-1)
- Provided via :meth:`io.IOBase.readline`
+ Provided via :meth:`io.IOBase.readline` See also ref:`shortintro_readline`.
.. method:: readlines(hint=-1)
- Provided via :meth:`io.IOBase.readlines`
+ Provided via :meth:`io.IOBase.readlines`. See also ref:`shortintro_readline`.
.. method:: writelines(lines)
@@ -1188,7 +1188,7 @@ This module provides classes to simplify working with threads and protocols.
.. attribute:: UNICODE_HANDLING = 'replace'
- Unicode error handly policy.
+ Unicode error handling policy.
.. method:: handle_packet(packet)
diff --git a/documentation/shortintro.rst b/documentation/shortintro.rst
index b9230e3..11b2ea0 100644
--- a/documentation/shortintro.rst
+++ b/documentation/shortintro.rst
@@ -53,13 +53,24 @@ Also supported with :ref:`context manager <context-manager>`::
ser.write(b'hello')
+.. _shortintro_readline:
+
Readline
========
+:meth:`readline` reads up to one line, including the `\n` at the end.
Be careful when using :meth:`readline`. Do specify a timeout when opening the
serial port otherwise it could block forever if no newline character is
-received. Also note that :meth:`readlines` only works with a timeout.
-:meth:`readlines` depends on having a timeout and interprets that as EOF (end
-of file). It raises an exception if the port is not opened correctly.
+received. If the `\n` is missing in the return value, it returned on timeout.
+
+:meth:`readlines` tries to read "all" lines which is not well defined for a
+serial port that is still open. Therefore :meth:`readlines` depends on having
+a timeout on the port and interprets that as EOF (end of file). It raises an
+exception if the port is not opened correctly. The returned list of lines do
+not include the `\n`.
+
+Both functions call :meth:`read` to get their data and the serial port timeout
+is acting on this function. Therefore the effective timeout, especially for
+:meth:`readlines`, can be much larger.
Do also have a look at the example files in the examples directory in the
source distribution or online.
diff --git a/documentation/url_handlers.rst b/documentation/url_handlers.rst
index 42a53fa..5c57615 100644
--- a/documentation/url_handlers.rst
+++ b/documentation/url_handlers.rst
@@ -140,6 +140,13 @@ Supported options in the URL are:
hex dump). In this mode, no control line and other commands are logged.
- ``all`` also show ``in_waiting`` and empty ``read()`` calls (hidden by
default because of high traffic).
+- ``log`` or ``log=LOGGERNAME`` output to stdlib ``logging`` module. Default
+ channel name is ``serial``. This variant outputs hex dump.
+- ``rawlog`` or ``rawlog=LOGGERNAME`` output to stdlib ``logging`` module. Default
+ channel name is ``serial``. This variant outputs text (``repr``).
+
+The ``log`` and ``rawlog`` options require that the logging is set up, in order
+to see the log output.
Example::
@@ -208,6 +215,7 @@ not interpreted by the shell::
The spy output will be live in the second terminal window.
.. versionadded:: 3.0
+.. versionchanged:: 3.6 Added ``log`` and ``rawlog`` options
``alt://``
@@ -236,9 +244,9 @@ Examples::
.. versionadded:: 3.0
+
``cp2110://``
=============
-
This backend implements support for HID-to-UART devices manufactured by Silicon
Labs and marketed as CP2110 and CP2114. The implementation is (mostly)
OS-independent and in userland. It relies on `cython-hidapi`_.
@@ -264,4 +272,3 @@ Examples
- ``spy://COM54?file=log.txt``
- ``alt:///dev/ttyUSB0?class=PosixPollSerial``
- ``cp2110://0001:004a:00``
-
diff --git a/serial/serialposix.py b/serial/serialposix.py
index 7aceb76..0464075 100644
--- a/serial/serialposix.py
+++ b/serial/serialposix.py
@@ -32,6 +32,7 @@ from __future__ import absolute_import
import errno
import fcntl
import os
+import platform
import select
import struct
import sys
@@ -80,8 +81,14 @@ if plat[:5] == 'linux': # Linux (confirmed) # noqa
CMSPAR = 0o10000000000 # Use "stick" (mark/space) parity
# baudrate ioctls
- TCGETS2 = 0x802C542A
- TCSETS2 = 0x402C542B
+ if platform.machine().lower() == "mips":
+ TCGETS2 = 0x4030542A
+ TCSETS2 = 0x8030542B
+ BAUDRATE_OFFSET = 10
+ else:
+ TCGETS2 = 0x802C542A
+ TCSETS2 = 0x402C542B
+ BAUDRATE_OFFSET = 9
BOTHER = 0o010000
# RS485 ioctls
@@ -154,7 +161,7 @@ if plat[:5] == 'linux': # Linux (confirmed) # noqa
# set custom speed
buf[2] &= ~termios.CBAUD
buf[2] |= BOTHER
- buf[9] = buf[10] = baudrate
+ buf[BAUDRATE_OFFSET] = buf[BAUDRATE_OFFSET + 1] = baudrate
# set serial_struct
fcntl.ioctl(self.fd, TCSETS2, buf)
diff --git a/serial/tools/list_ports_linux.py b/serial/tools/list_ports_linux.py
index c8c1cfc..0dc1b6e 100644
--- a/serial/tools/list_ports_linux.py
+++ b/serial/tools/list_ports_linux.py
@@ -89,15 +89,18 @@ class SysFS(list_ports_common.ListPortInfo):
def comports(include_links=False):
- devices = glob.glob('/dev/ttyS*') # built-in serial ports
- devices.extend(glob.glob('/dev/ttyUSB*')) # usb-serial with own driver
- devices.extend(glob.glob('/dev/ttyXRUSB*')) # xr-usb-serial port exar (DELL Edge 3001)
- devices.extend(glob.glob('/dev/ttyACM*')) # usb-serial with CDC-ACM profile
- devices.extend(glob.glob('/dev/ttyAMA*')) # ARM internal port (raspi)
- devices.extend(glob.glob('/dev/rfcomm*')) # BT serial devices
- devices.extend(glob.glob('/dev/ttyAP*')) # Advantech multi-port serial controllers
+ devices = set()
+ devices.update(glob.glob('/dev/ttyS*')) # built-in serial ports
+ devices.update(glob.glob('/dev/ttyUSB*')) # usb-serial with own driver
+ devices.update(glob.glob('/dev/ttyXRUSB*')) # xr-usb-serial port exar (DELL Edge 3001)
+ devices.update(glob.glob('/dev/ttyACM*')) # usb-serial with CDC-ACM profile
+ devices.update(glob.glob('/dev/ttyAMA*')) # ARM internal port (raspi)
+ devices.update(glob.glob('/dev/rfcomm*')) # BT serial devices
+ devices.update(glob.glob('/dev/ttyAP*')) # Advantech multi-port serial controllers
+ devices.update(glob.glob('/dev/ttyGS*')) # https://www.kernel.org/doc/Documentation/usb/gadget_serial.txt
+
if include_links:
- devices.extend(list_ports_common.list_links(devices))
+ devices.update(list_ports_common.list_links(devices))
return [info
for info in [SysFS(d) for d in devices]
if info.subsystem != "platform"] # hide non-present internal serial ports
diff --git a/serial/tools/list_ports_posix.py b/serial/tools/list_ports_posix.py
index 79bc8ed..b115754 100644
--- a/serial/tools/list_ports_posix.py
+++ b/serial/tools/list_ports_posix.py
@@ -37,63 +37,63 @@ elif plat == 'cygwin': # cygwin/win32
# (such as 'open' call, explicit 'ls'), but 'glob.glob'
# and bare 'ls' do not; so use /dev/ttyS* instead
def comports(include_links=False):
- devices = glob.glob('/dev/ttyS*')
+ devices = set(glob.glob('/dev/ttyS*'))
if include_links:
- devices.extend(list_ports_common.list_links(devices))
+ devices.update(list_ports_common.list_links(devices))
return [list_ports_common.ListPortInfo(d) for d in devices]
elif plat[:7] == 'openbsd': # OpenBSD
def comports(include_links=False):
- devices = glob.glob('/dev/cua*')
+ devices = set(glob.glob('/dev/cua*'))
if include_links:
- devices.extend(list_ports_common.list_links(devices))
+ devices.update(list_ports_common.list_links(devices))
return [list_ports_common.ListPortInfo(d) for d in devices]
elif plat[:3] == 'bsd' or plat[:7] == 'freebsd':
def comports(include_links=False):
- devices = glob.glob('/dev/cua*[!.init][!.lock]')
+ devices = set(glob.glob('/dev/cua*[!.init][!.lock]'))
if include_links:
- devices.extend(list_ports_common.list_links(devices))
+ devices.update(list_ports_common.list_links(devices))
return [list_ports_common.ListPortInfo(d) for d in devices]
elif plat[:6] == 'netbsd': # NetBSD
def comports(include_links=False):
"""scan for available ports. return a list of device names."""
- devices = glob.glob('/dev/dty*')
+ devices = set(glob.glob('/dev/dty*'))
if include_links:
- devices.extend(list_ports_common.list_links(devices))
+ devices.update(list_ports_common.list_links(devices))
return [list_ports_common.ListPortInfo(d) for d in devices]
elif plat[:4] == 'irix': # IRIX
def comports(include_links=False):
"""scan for available ports. return a list of device names."""
- devices = glob.glob('/dev/ttyf*')
+ devices = set(glob.glob('/dev/ttyf*'))
if include_links:
- devices.extend(list_ports_common.list_links(devices))
+ devices.update(list_ports_common.list_links(devices))
return [list_ports_common.ListPortInfo(d) for d in devices]
elif plat[:2] == 'hp': # HP-UX (not tested)
def comports(include_links=False):
"""scan for available ports. return a list of device names."""
- devices = glob.glob('/dev/tty*p0')
+ devices = set(glob.glob('/dev/tty*p0'))
if include_links:
- devices.extend(list_ports_common.list_links(devices))
+ devices.update(list_ports_common.list_links(devices))
return [list_ports_common.ListPortInfo(d) for d in devices]
elif plat[:5] == 'sunos': # Solaris/SunOS
def comports(include_links=False):
"""scan for available ports. return a list of device names."""
- devices = glob.glob('/dev/tty*c')
+ devices = set(glob.glob('/dev/tty*c'))
if include_links:
- devices.extend(list_ports_common.list_links(devices))
+ devices.update(list_ports_common.list_links(devices))
return [list_ports_common.ListPortInfo(d) for d in devices]
elif plat[:3] == 'aix': # AIX
def comports(include_links=False):
"""scan for available ports. return a list of device names."""
- devices = glob.glob('/dev/tty*')
+ devices = set(glob.glob('/dev/tty*'))
if include_links:
- devices.extend(list_ports_common.list_links(devices))
+ devices.update(list_ports_common.list_links(devices))
return [list_ports_common.ListPortInfo(d) for d in devices]
else:
diff --git a/serial/tools/miniterm.py b/serial/tools/miniterm.py
index 8de7c71..236d917 100644
--- a/serial/tools/miniterm.py
+++ b/serial/tools/miniterm.py
@@ -372,7 +372,8 @@ def ask_for_port():
sys.stderr.write('--- {:2}: {:20} {!r}\n'.format(n, port, desc))
ports.append(port)
while True:
- port = raw_input('--- Enter port index or full name: ')
+ sys.stderr.write('--- Enter port index or full name: ')
+ port = raw_input('')
try:
index = int(port) - 1
if not 0 <= index < len(ports):
diff --git a/serial/urlhandler/protocol_spy.py b/serial/urlhandler/protocol_spy.py
index 67c700b..55e3765 100644
--- a/serial/urlhandler/protocol_spy.py
+++ b/serial/urlhandler/protocol_spy.py
@@ -22,6 +22,7 @@
from __future__ import absolute_import
+import logging
import sys
import time
@@ -152,6 +153,46 @@ class FormatHexdump(object):
self.write_line(time.time() - self.start_time, name, value)
+class FormatLog(object):
+ """\
+ Write data to logging module.
+ """
+
+ def __init__(self, output, color):
+ # output and color is ignored
+ self.log = logging.getLogger(output)
+
+ def rx(self, data):
+ """show received data"""
+ if data:
+ self.log.info('RX {!r}'.format(data))
+
+ def tx(self, data):
+ """show transmitted data"""
+ self.log.info('TX {!r}'.format(data))
+
+ def control(self, name, value):
+ """show control calls"""
+ self.log.info('{}: {}'.format(name, value))
+
+
+class FormatLogHex(FormatLog):
+ """\
+ Write data to logging module.
+ """
+
+ def rx(self, data):
+ """show received data"""
+ if data:
+ for offset, row in hexdump(data):
+ self.log.info('RX {}{}'.format('{:04X} '.format(offset), row))
+
+ def tx(self, data):
+ """show transmitted data"""
+ for offset, row in hexdump(data):
+ self.log.info('TX {}{}'.format('{:04X} '.format(offset), row))
+
+
class Serial(serial.Serial):
"""\
Inherit the native Serial port implementation and wrap all the methods and
@@ -189,6 +230,12 @@ class Serial(serial.Serial):
color = True
elif option == 'raw':
formatter = FormatRaw
+ elif option == 'rawlog':
+ formatter = FormatLog
+ output = values[0] if values[0] else 'serial'
+ elif option == 'log':
+ formatter = FormatLogHex
+ output = values[0] if values[0] else 'serial'
elif option == 'all':
self.show_all = True
else: