summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--documentation/examples.rst2
-rw-r--r--documentation/pyserial_api.rst13
-rw-r--r--documentation/shortintro.rst17
-rw-r--r--documentation/url_handlers.rst11
-rw-r--r--serial/serialutil.py2
-rw-r--r--serial/tools/list_ports_linux.py17
-rw-r--r--serial/tools/list_ports_posix.py32
-rw-r--r--serial/tools/miniterm.py29
-rw-r--r--serial/urlhandler/protocol_hwgrep.py2
-rw-r--r--serial/urlhandler/protocol_spy.py47
-rwxr-xr-xtest/test_context.py2
11 files changed, 122 insertions, 52 deletions
diff --git a/documentation/examples.rst b/documentation/examples.rst
index 0430267..197c015 100644
--- a/documentation/examples.rst
+++ b/documentation/examples.rst
@@ -199,7 +199,7 @@ port_publisher.sh_
Example init.d script.
.. _port_publisher.py: https://github.com/pyserial/pyserial/blob/master/examples/port_publisher.py
-.. _port_publisher.sh: https://github.com/pyserial/pyserial/blob/master/examples/http://sourceforge.net/p/pyserial/code/HEAD/tree/trunk/pyserial/examples/port_publisher.sh
+.. _port_publisher.sh: https://github.com/pyserial/pyserial/blob/master/examples/port_publisher.sh
wxPython examples
diff --git a/documentation/pyserial_api.rst b/documentation/pyserial_api.rst
index efd82c1..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,13 +166,16 @@ 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
Returns an instance of :class:`bytes` when available (Python 2.6
and newer) and :class:`str` otherwise.
+ .. versionchanged:: 3.5
+ First argument was called ``terminator`` in previous versions.
+
.. method:: write(data)
:param data: Data to send.
@@ -483,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)
@@ -1185,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/serialutil.py b/serial/serialutil.py
index 789219e..f554472 100644
--- a/serial/serialutil.py
+++ b/serial/serialutil.py
@@ -653,7 +653,7 @@ class SerialBase(io.RawIOBase):
def read_until(self, expected=LF, size=None):
"""\
- Read until an expected sequence is found ('\n' by default), the size
+ Read until an expected sequence is found (line feed by default), the size
is exceeded or until timeout occurs.
"""
lenterm = len(expected)
diff --git a/serial/tools/list_ports_linux.py b/serial/tools/list_ports_linux.py
index c8c1cfc..ec2e0ca 100644
--- a/serial/tools/list_ports_linux.py
+++ b/serial/tools/list_ports_linux.py
@@ -89,15 +89,16 @@ 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
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 2cceff6..236d917 100644
--- a/serial/tools/miniterm.py
+++ b/serial/tools/miniterm.py
@@ -104,16 +104,16 @@ if os.name == 'nt': # noqa
class Console(ConsoleBase):
fncodes = {
- ';': '\1bOP', # F1
- '<': '\1bOQ', # F2
- '=': '\1bOR', # F3
- '>': '\1bOS', # F4
- '?': '\1b[15~', # F5
- '@': '\1b[17~', # F6
- 'A': '\1b[18~', # F7
- 'B': '\1b[19~', # F8
- 'C': '\1b[20~', # F9
- 'D': '\1b[21~', # F10
+ ';': '\x1bOP', # F1
+ '<': '\x1bOQ', # F2
+ '=': '\x1bOR', # F3
+ '>': '\x1bOS', # F4
+ '?': '\x1b[15~', # F5
+ '@': '\x1b[17~', # F6
+ 'A': '\x1b[18~', # F7
+ 'B': '\x1b[19~', # F8
+ 'C': '\x1b[20~', # F9
+ 'D': '\x1b[21~', # F10
}
navcodes = {
'H': '\x1b[A', # UP
@@ -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):
@@ -635,7 +636,7 @@ class Miniterm(object):
sys.stderr.write('--- unknown menu character {} --\n'.format(key_description(c)))
def upload_file(self):
- """Ask user for filenname and send its contents"""
+ """Ask user for filename and send its contents"""
sys.stderr.write('\n--- File to upload: ')
sys.stderr.flush()
with self.console:
@@ -810,7 +811,7 @@ class Miniterm(object):
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# default args can be used to override when calling main() from an other script
# e.g to create a miniterm-my-device.py
-def main(default_port=None, default_baudrate=9600, default_rts=None, default_dtr=None):
+def main(default_port=None, default_baudrate=9600, default_rts=None, default_dtr=None, serial_instance=None):
"""Command line tool, entry point"""
import argparse
@@ -959,7 +960,7 @@ def main(default_port=None, default_baudrate=9600, default_rts=None, default_dtr
else:
filters = ['default']
- while True:
+ while serial_instance is None:
# no port given on command line -> ask user now
if args.port is None or args.port == '-':
try:
diff --git a/serial/urlhandler/protocol_hwgrep.py b/serial/urlhandler/protocol_hwgrep.py
index 1a288c9..22805cc 100644
--- a/serial/urlhandler/protocol_hwgrep.py
+++ b/serial/urlhandler/protocol_hwgrep.py
@@ -12,7 +12,7 @@
#
# where <regexp> is a Python regexp according to the re module
#
-# violating the normal definition for URLs, the charachter `&` is used to
+# violating the normal definition for URLs, the character `&` is used to
# separate parameters from the arguments (instead of `?`, but the question mark
# is heavily used in regexp'es)
#
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:
diff --git a/test/test_context.py b/test/test_context.py
index 456c85a..a65a626 100755
--- a/test/test_context.py
+++ b/test/test_context.py
@@ -11,7 +11,7 @@ Part of pySerial (http://pyserial.sf.net) (C)2001-2011 cliechti@gmx.net
Intended to be run on different platforms, to ensure portability of
the code.
-Cover some of the aspects of context managment
+Cover some of the aspects of context management
"""
import unittest