diff options
| -rw-r--r-- | documentation/pyserial_api.rst | 10 | ||||
| -rw-r--r-- | documentation/shortintro.rst | 17 | ||||
| -rw-r--r-- | documentation/url_handlers.rst | 11 | ||||
| -rw-r--r-- | serial/serialposix.py | 13 | ||||
| -rw-r--r-- | serial/tools/list_ports_linux.py | 19 | ||||
| -rw-r--r-- | serial/tools/list_ports_posix.py | 32 | ||||
| -rw-r--r-- | serial/tools/miniterm.py | 3 | ||||
| -rw-r--r-- | serial/urlhandler/protocol_spy.py | 47 |
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: |
