diff --git a/mFIZ/scripts/mFIZ_extern/serial/__init__.py b/mFIZ/scripts/mFIZ_extern/serial/__init__.py deleted file mode 100644 index 4cd3a25..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/__init__.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python -# -# This is a wrapper module for different platform implementations -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2001-2016 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -import sys -import importlib - -from serial.serialutil import * -#~ SerialBase, SerialException, to_bytes, iterbytes - -__version__ = '3.2.1' - -VERSION = __version__ - -# pylint: disable=wrong-import-position -if sys.platform == 'cli': - from serial.serialcli import Serial -else: - import os - # chose an implementation, depending on os - if os.name == 'nt': # sys.platform == 'win32': - from serial.serialwin32 import Serial - elif os.name == 'posix': - from serial.serialposix import Serial, PosixPollSerial, VTIMESerial # noqa - elif os.name == 'java': - from serial.serialjava import Serial - else: - raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name)) - - -protocol_handler_packages = [ - 'serial.urlhandler', -] - - -def serial_for_url(url, *args, **kwargs): - """\ - Get an instance of the Serial class, depending on port/url. The port is not - opened when the keyword parameter 'do_not_open' is true, by default it - is. All other parameters are directly passed to the __init__ method when - the port is instantiated. - - The list of package names that is searched for protocol handlers is kept in - ``protocol_handler_packages``. - - e.g. we want to support a URL ``foobar://``. A module - ``my_handlers.protocol_foobar`` is provided by the user. Then - ``protocol_handler_packages.append("my_handlers")`` would extend the search - path so that ``serial_for_url("foobar://"))`` would work. - """ - # check and remove extra parameter to not confuse the Serial class - do_open = not kwargs.pop('do_not_open', False) - # the default is to use the native implementation - klass = Serial - try: - url_lowercase = url.lower() - except AttributeError: - # it's not a string, use default - pass - else: - # if it is an URL, try to import the handler module from the list of possible packages - if '://' in url_lowercase: - protocol = url_lowercase.split('://', 1)[0] - module_name = '.protocol_{}'.format(protocol) - for package_name in protocol_handler_packages: - try: - importlib.import_module(package_name) - handler_module = importlib.import_module(module_name, package_name) - except ImportError: - continue - else: - if hasattr(handler_module, 'serial_class_for_url'): - url, klass = handler_module.serial_class_for_url(url) - else: - klass = handler_module.Serial - break - else: - raise ValueError('invalid URL, protocol {!r} not known'.format(protocol)) - # instantiate and open when desired - instance = klass(None, *args, **kwargs) - instance.port = url - if do_open: - instance.open() - return instance diff --git a/mFIZ/scripts/mFIZ_extern/serial/aio.py b/mFIZ/scripts/mFIZ_extern/serial/aio.py deleted file mode 100644 index 8173897..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/aio.py +++ /dev/null @@ -1,428 +0,0 @@ -#!/usr/bin/env python3 -# -# Experimental implementation of asyncio support. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause -"""\ -Support asyncio with serial ports. EXPERIMENTAL - -Posix platforms only, Python 3.4+ only. - -Windows event loops can not wait for serial ports with the current -implementation. It should be possible to get that working though. -""" -import asyncio -import serial - - -class SerialTransport(asyncio.Transport): - """An asyncio transport model of a serial communication channel. - - A transport class is an abstraction of a communication channel. - This allows protocol implementations to be developed against the - transport abstraction without needing to know the details of the - underlying channel, such as whether it is a pipe, a socket, or - indeed a serial port. - - - You generally won’t instantiate a transport yourself; instead, you - will call `create_serial_connection` which will create the - transport and try to initiate the underlying communication channel, - calling you back when it succeeds. - """ - - def __init__(self, loop, protocol, serial_instance): - super().__init__() - self._loop = loop - self._protocol = protocol - self._serial = serial_instance - self._closing = False - self._protocol_paused = False - self._max_read_size = 1024 - self._write_buffer = [] - self._set_write_buffer_limits() - self._has_reader = False - self._has_writer = False - - # XXX how to support url handlers too - - # Asynchronous I/O requires non-blocking devices - self._serial.timeout = 0 - self._serial.write_timeout = 0 - - # These two callbacks will be enqueued in a FIFO queue by asyncio - loop.call_soon(protocol.connection_made, self) - loop.call_soon(self._ensure_reader) - - @property - def serial(self): - """The underlying Serial instance.""" - return self._serial - - def __repr__(self): - return '{self.__class__.__name__}({self._loop}, {self._protocol}, {self.serial})'.format(self=self) - - def is_closing(self): - """Return True if the transport is closing or closed.""" - return self._closing - - def close(self): - """Close the transport gracefully. - - Any buffered data will be written asynchronously. No more data - will be received and further writes will be silently ignored. - After all buffered data is flushed, the protocol's - connection_lost() method will be called with None as its - argument. - """ - if not self._closing: - self._close(None) - - def _read_ready(self): - try: - data = self._serial.read(self._max_read_size) - except serial.SerialException as e: - self._close(exc=e) - else: - if data: - self._protocol.data_received(data) - - def write(self, data): - """Write some data to the transport. - - This method does not block; it buffers the data and arranges - for it to be sent out asynchronously. Writes made after the - transport has been closed will be ignored.""" - if self._closing: - return - - if self.get_write_buffer_size() == 0: - # Attempt to send it right away first - try: - n = self._serial.write(data) - except serial.SerialException as exc: - self._fatal_error(exc, 'Fatal write error on serial transport') - return - if n == len(data): - return # Whole request satisfied - assert n > 0 - data = data[n:] - self._ensure_writer() - - self._write_buffer.append(data) - self._maybe_pause_protocol() - - def can_write_eof(self): - """Serial ports do not support the concept of end-of-file. - - Always returns False. - """ - return False - - def pause_reading(self): - """Pause the receiving end of the transport. - - No data will be passed to the protocol’s data_received() method - until resume_reading() is called. - """ - self._remove_reader() - - def resume_reading(self): - """Resume the receiving end of the transport. - - Incoming data will be passed to the protocol's data_received() - method until pause_reading() is called. - """ - self._ensure_reader() - - def set_write_buffer_limits(self, high=None, low=None): - """Set the high- and low-water limits for write flow control. - - These two values control when call the protocol’s - pause_writing()and resume_writing() methods are called. If - specified, the low-water limit must be less than or equal to - the high-water limit. Neither high nor low can be negative. - """ - self._set_write_buffer_limits(high=high, low=low) - self._maybe_pause_protocol() - - def get_write_buffer_size(self): - """The number of bytes in the write buffer. - - This buffer is unbounded, so the result may be larger than the - the high water mark. - """ - return sum(map(len, self._write_buffer)) - - def write_eof(self): - raise NotImplementedError("Serial connections do not support end-of-file") - - def abort(self): - """Close the transport immediately. - - Pending operations will not be given opportunity to complete, - and buffered data will be lost. No more data will be received - and further writes will be ignored. The protocol's - connection_lost() method will eventually be called. - """ - self._abort(None) - - def _maybe_pause_protocol(self): - """To be called whenever the write-buffer size increases. - - Tests the current write-buffer size against the high water - mark configured for this transport. If the high water mark is - exceeded, the protocol is instructed to pause_writing(). - """ - if self.get_write_buffer_size() <= self._high_water: - return - if not self._protocol_paused: - self._protocol_paused = True - try: - self._protocol.pause_writing() - except Exception as exc: - self._loop.call_exception_handler({ - 'message': 'protocol.pause_writing() failed', - 'exception': exc, - 'transport': self, - 'protocol': self._protocol, - }) - - def _maybe_resume_protocol(self): - """To be called whenever the write-buffer size decreases. - - Tests the current write-buffer size against the low water - mark configured for this transport. If the write-buffer - size is below the low water mark, the protocol is - instructed that is can resume_writing(). - """ - if (self._protocol_paused and - self.get_write_buffer_size() <= self._low_water): - self._protocol_paused = False - try: - self._protocol.resume_writing() - except Exception as exc: - self._loop.call_exception_handler({ - 'message': 'protocol.resume_writing() failed', - 'exception': exc, - 'transport': self, - 'protocol': self._protocol, - }) - - def _write_ready(self): - """Asynchronously write buffered data. - - This method is called back asynchronously as a writer - registered with the asyncio event-loop against the - underlying file descriptor for the serial port. - - Should the write-buffer become empty if this method - is invoked while the transport is closing, the protocol's - connection_lost() method will be called with None as its - argument. - """ - data = b''.join(self._write_buffer) - num_bytes = len(data) - assert data, 'Write buffer should not be empty' - - self._write_buffer.clear() - - try: - n = self._serial.write(data) - except (BlockingIOError, InterruptedError): - self._write_buffer.append(data) - except serial.SerialException as exc: - self._fatal_error(exc, 'Fatal write error on serial transport') - else: - if n == len(data): - assert self._flushed() - self._remove_writer() - self._maybe_resume_protocol() # May cause further writes - # _write_ready may have been invoked by the event loop - # after the transport was closed, as part of the ongoing - # process of flushing buffered data. If the buffer - # is now empty, we can close the connection - if self._closing and self._flushed(): - self._close() - return - - assert n > 0 - data = data[n:] - self._write_buffer.append(data) # Try again later - self._maybe_resume_protocol() - assert self._has_writer - - def _ensure_reader(self): - if (not self._has_reader) and (not self._closing): - self._loop.add_reader(self._serial.fd, self._read_ready) - self._has_reader = True - - def _remove_reader(self): - if self._has_reader: - self._loop.remove_reader(self._serial.fd) - self._has_reader = False - - def _ensure_writer(self): - if (not self._has_writer) and (not self._closing): - self._loop.add_writer(self._serial.fd, self._write_ready) - self._has_writer = True - - def _remove_writer(self): - if self._has_writer: - self._loop.remove_writer(self._serial.fd) - self._has_writer = False - - def _set_write_buffer_limits(self, high=None, low=None): - """Ensure consistent write-buffer limits.""" - if high is None: - high = 64 * 1024 if low is None else 4 * low - if low is None: - low = high // 4 - if not high >= low >= 0: - raise ValueError('high (%r) must be >= low (%r) must be >= 0' % - (high, low)) - self._high_water = high - self._low_water = low - - def _fatal_error(self, exc, message='Fatal error on serial transport'): - """Report a fatal error to the event-loop and abort the transport.""" - self._loop.call_exception_handler({ - 'message': message, - 'exception': exc, - 'transport': self, - 'protocol': self._protocol, - }) - self._abort(exc) - - def _flushed(self): - """True if the write buffer is empty, otherwise False.""" - return self.get_write_buffer_size() == 0 - - def _close(self, exc=None): - """Close the transport gracefully. - - If the write buffer is already empty, writing will be - stopped immediately and a call to the protocol's - connection_lost() method scheduled. - - If the write buffer is not already empty, the - asynchronous writing will continue, and the _write_ready - method will call this _close method again when the - buffer has been flushed completely. - """ - self._closing = True - self._remove_reader() - if self._flushed(): - self._remove_writer() - self._loop.call_soon(self._call_connection_lost, exc) - - def _abort(self, exc): - """Close the transport immediately. - - Pending operations will not be given opportunity to complete, - and buffered data will be lost. No more data will be received - and further writes will be ignored. The protocol's - connection_lost() method will eventually be called with the - passed exception. - """ - self._closing = True - self._remove_reader() - self._remove_writer() # Pending buffered data will not be written - self._loop.call_soon(self._call_connection_lost, exc) - - def _call_connection_lost(self, exc): - """Close the connection. - - Informs the protocol through connection_lost() and clears - pending buffers and closes the serial connection. - """ - assert self._closing - assert not self._has_writer - assert not self._has_reader - self._serial.flush() - try: - self._protocol.connection_lost(exc) - finally: - self._write_buffer.clear() - self._serial.close() - self._serial = None - self._protocol = None - self._loop = None - - -@asyncio.coroutine -def create_serial_connection(loop, protocol_factory, *args, **kwargs): - ser = serial.serial_for_url(*args, **kwargs) - protocol = protocol_factory() - transport = SerialTransport(loop, protocol, ser) - return (transport, protocol) - - -@asyncio.coroutine -def open_serial_connection(**kwargs): - """A wrapper for create_serial_connection() returning a (reader, - writer) pair. - - The reader returned is a StreamReader instance; the writer is a - StreamWriter instance. - - The arguments are all the usual arguments to Serial(). Additional - optional keyword arguments are loop (to set the event loop instance - to use) and limit (to set the buffer limit passed to the - StreamReader. - - This function is a coroutine. - """ - # in order to avoid errors when pySerial is installed under Python 2, - # avoid Pyhthon 3 syntax here. So do not use this function as a good - # example! - loop = kwargs.get('loop', asyncio.get_event_loop()) - limit = kwargs.get('limit', asyncio.streams._DEFAULT_LIMIT) - reader = asyncio.StreamReader(limit=limit, loop=loop) - protocol = asyncio.StreamReaderProtocol(reader, loop=loop) - # in Python 3 we would write "yield transport, _ from c()" - for transport, _ in create_serial_connection( - loop=loop, - protocol_factory=lambda: protocol, - **kwargs): - yield transport, _ - writer = asyncio.StreamWriter(transport, protocol, reader, loop) - # in Python 3 we would write "return reader, writer" - raise StopIteration(reader, writer) - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# test -if __name__ == '__main__': - class Output(asyncio.Protocol): - def connection_made(self, transport): - self.transport = transport - print('port opened', transport) - transport.serial.rts = False - transport.write(b'hello world\n') - - def data_received(self, data): - print('data received', repr(data)) - if b'\n' in data: - self.transport.close() - - def connection_lost(self, exc): - print('port closed') - asyncio.get_event_loop().stop() - - def pause_writing(self): - print('pause writing') - print(self.transport.get_write_buffer_size()) - - def resume_writing(self): - print(self.transport.get_write_buffer_size()) - print('resume writing') - - loop = asyncio.get_event_loop() - coro = create_serial_connection(loop, Output, '/dev/ttyUSB0', baudrate=115200) - loop.run_until_complete(coro) - loop.run_forever() - loop.close() diff --git a/mFIZ/scripts/mFIZ_extern/serial/rfc2217.py b/mFIZ/scripts/mFIZ_extern/serial/rfc2217.py deleted file mode 100644 index dee5c2b..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/rfc2217.py +++ /dev/null @@ -1,1342 +0,0 @@ -#! python -# -# This module implements a RFC2217 compatible client. RF2217 descibes a -# protocol to access serial ports over TCP/IP and allows setting the baud rate, -# modem control lines etc. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2001-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -# TODO: -# - setting control line -> answer is not checked (had problems with one of the -# severs). consider implementing a compatibility mode flag to make check -# conditional -# - write timeout not implemented at all - -# ########################################################################### -# observations and issues with servers -# =========================================================================== -# sredird V2.2.1 -# - http://www.ibiblio.org/pub/Linux/system/serial/ sredird-2.2.2.tar.gz -# - does not acknowledge SET_CONTROL (RTS/DTR) correctly, always responding -# [105 1] instead of the actual value. -# - SET_BAUDRATE answer contains 4 extra null bytes -> probably for larger -# numbers than 2**32? -# - To get the signature [COM_PORT_OPTION 0] has to be sent. -# - run a server: while true; do nc -l -p 7000 -c "sredird debug /dev/ttyUSB0 /var/lock/sredir"; done -# =========================================================================== -# telnetcpcd (untested) -# - http://ftp.wayne.edu/kermit/sredird/telnetcpcd-1.09.tar.gz -# - To get the signature [COM_PORT_OPTION] w/o data has to be sent. -# =========================================================================== -# ser2net -# - does not negotiate BINARY or COM_PORT_OPTION for his side but at least -# acknowledges that the client activates these options -# - The configuration may be that the server prints a banner. As this client -# implementation does a flushInput on connect, this banner is hidden from -# the user application. -# - NOTIFY_MODEMSTATE: the poll interval of the server seems to be one -# second. -# - To get the signature [COM_PORT_OPTION 0] has to be sent. -# - run a server: run ser2net daemon, in /etc/ser2net.conf: -# 2000:telnet:0:/dev/ttyS0:9600 remctl banner -# ########################################################################### - -# How to identify ports? pySerial might want to support other protocols in the -# future, so lets use an URL scheme. -# for RFC2217 compliant servers we will use this: -# rfc2217://:[?option[&option...]] -# -# options: -# - "logging" set log level print diagnostic messages (e.g. "logging=debug") -# - "ign_set_control": do not look at the answers to SET_CONTROL -# - "poll_modem": issue NOTIFY_MODEMSTATE requests when CTS/DTR/RI/CD is read. -# Without this option it expects that the server sends notifications -# automatically on change (which most servers do and is according to the -# RFC). -# the order of the options is not relevant - -import logging -import socket -import struct -import threading -import time -try: - import urlparse -except ImportError: - import urllib.parse as urlparse -try: - import Queue -except ImportError: - import queue as Queue - -import serial -from serial.serialutil import SerialBase, SerialException, to_bytes, \ - iterbytes, portNotOpenError, Timeout - -# port string is expected to be something like this: -# rfc2217://host:port -# host may be an IP or including domain, whatever. -# port is 0...65535 - -# map log level names to constants. used in from_url() -LOGGER_LEVELS = { - 'debug': logging.DEBUG, - 'info': logging.INFO, - 'warning': logging.WARNING, - 'error': logging.ERROR, -} - - -# telnet protocol characters -SE = b'\xf0' # Subnegotiation End -NOP = b'\xf1' # No Operation -DM = b'\xf2' # Data Mark -BRK = b'\xf3' # Break -IP = b'\xf4' # Interrupt process -AO = b'\xf5' # Abort output -AYT = b'\xf6' # Are You There -EC = b'\xf7' # Erase Character -EL = b'\xf8' # Erase Line -GA = b'\xf9' # Go Ahead -SB = b'\xfa' # Subnegotiation Begin -WILL = b'\xfb' -WONT = b'\xfc' -DO = b'\xfd' -DONT = b'\xfe' -IAC = b'\xff' # Interpret As Command -IAC_DOUBLED = b'\xff\xff' - -# selected telnet options -BINARY = b'\x00' # 8-bit data path -ECHO = b'\x01' # echo -SGA = b'\x03' # suppress go ahead - -# RFC2217 -COM_PORT_OPTION = b'\x2c' - -# Client to Access Server -SET_BAUDRATE = b'\x01' -SET_DATASIZE = b'\x02' -SET_PARITY = b'\x03' -SET_STOPSIZE = b'\x04' -SET_CONTROL = b'\x05' -NOTIFY_LINESTATE = b'\x06' -NOTIFY_MODEMSTATE = b'\x07' -FLOWCONTROL_SUSPEND = b'\x08' -FLOWCONTROL_RESUME = b'\x09' -SET_LINESTATE_MASK = b'\x0a' -SET_MODEMSTATE_MASK = b'\x0b' -PURGE_DATA = b'\x0c' - -SERVER_SET_BAUDRATE = b'\x65' -SERVER_SET_DATASIZE = b'\x66' -SERVER_SET_PARITY = b'\x67' -SERVER_SET_STOPSIZE = b'\x68' -SERVER_SET_CONTROL = b'\x69' -SERVER_NOTIFY_LINESTATE = b'\x6a' -SERVER_NOTIFY_MODEMSTATE = b'\x6b' -SERVER_FLOWCONTROL_SUSPEND = b'\x6c' -SERVER_FLOWCONTROL_RESUME = b'\x6d' -SERVER_SET_LINESTATE_MASK = b'\x6e' -SERVER_SET_MODEMSTATE_MASK = b'\x6f' -SERVER_PURGE_DATA = b'\x70' - -RFC2217_ANSWER_MAP = { - SET_BAUDRATE: SERVER_SET_BAUDRATE, - SET_DATASIZE: SERVER_SET_DATASIZE, - SET_PARITY: SERVER_SET_PARITY, - SET_STOPSIZE: SERVER_SET_STOPSIZE, - SET_CONTROL: SERVER_SET_CONTROL, - NOTIFY_LINESTATE: SERVER_NOTIFY_LINESTATE, - NOTIFY_MODEMSTATE: SERVER_NOTIFY_MODEMSTATE, - FLOWCONTROL_SUSPEND: SERVER_FLOWCONTROL_SUSPEND, - FLOWCONTROL_RESUME: SERVER_FLOWCONTROL_RESUME, - SET_LINESTATE_MASK: SERVER_SET_LINESTATE_MASK, - SET_MODEMSTATE_MASK: SERVER_SET_MODEMSTATE_MASK, - PURGE_DATA: SERVER_PURGE_DATA, -} - -SET_CONTROL_REQ_FLOW_SETTING = b'\x00' # Request Com Port Flow Control Setting (outbound/both) -SET_CONTROL_USE_NO_FLOW_CONTROL = b'\x01' # Use No Flow Control (outbound/both) -SET_CONTROL_USE_SW_FLOW_CONTROL = b'\x02' # Use XON/XOFF Flow Control (outbound/both) -SET_CONTROL_USE_HW_FLOW_CONTROL = b'\x03' # Use HARDWARE Flow Control (outbound/both) -SET_CONTROL_REQ_BREAK_STATE = b'\x04' # Request BREAK State -SET_CONTROL_BREAK_ON = b'\x05' # Set BREAK State ON -SET_CONTROL_BREAK_OFF = b'\x06' # Set BREAK State OFF -SET_CONTROL_REQ_DTR = b'\x07' # Request DTR Signal State -SET_CONTROL_DTR_ON = b'\x08' # Set DTR Signal State ON -SET_CONTROL_DTR_OFF = b'\x09' # Set DTR Signal State OFF -SET_CONTROL_REQ_RTS = b'\x0a' # Request RTS Signal State -SET_CONTROL_RTS_ON = b'\x0b' # Set RTS Signal State ON -SET_CONTROL_RTS_OFF = b'\x0c' # Set RTS Signal State OFF -SET_CONTROL_REQ_FLOW_SETTING_IN = b'\x0d' # Request Com Port Flow Control Setting (inbound) -SET_CONTROL_USE_NO_FLOW_CONTROL_IN = b'\x0e' # Use No Flow Control (inbound) -SET_CONTROL_USE_SW_FLOW_CONTOL_IN = b'\x0f' # Use XON/XOFF Flow Control (inbound) -SET_CONTROL_USE_HW_FLOW_CONTOL_IN = b'\x10' # Use HARDWARE Flow Control (inbound) -SET_CONTROL_USE_DCD_FLOW_CONTROL = b'\x11' # Use DCD Flow Control (outbound/both) -SET_CONTROL_USE_DTR_FLOW_CONTROL = b'\x12' # Use DTR Flow Control (inbound) -SET_CONTROL_USE_DSR_FLOW_CONTROL = b'\x13' # Use DSR Flow Control (outbound/both) - -LINESTATE_MASK_TIMEOUT = 128 # Time-out Error -LINESTATE_MASK_SHIFTREG_EMPTY = 64 # Transfer Shift Register Empty -LINESTATE_MASK_TRANSREG_EMPTY = 32 # Transfer Holding Register Empty -LINESTATE_MASK_BREAK_DETECT = 16 # Break-detect Error -LINESTATE_MASK_FRAMING_ERROR = 8 # Framing Error -LINESTATE_MASK_PARTIY_ERROR = 4 # Parity Error -LINESTATE_MASK_OVERRUN_ERROR = 2 # Overrun Error -LINESTATE_MASK_DATA_READY = 1 # Data Ready - -MODEMSTATE_MASK_CD = 128 # Receive Line Signal Detect (also known as Carrier Detect) -MODEMSTATE_MASK_RI = 64 # Ring Indicator -MODEMSTATE_MASK_DSR = 32 # Data-Set-Ready Signal State -MODEMSTATE_MASK_CTS = 16 # Clear-To-Send Signal State -MODEMSTATE_MASK_CD_CHANGE = 8 # Delta Receive Line Signal Detect -MODEMSTATE_MASK_RI_CHANGE = 4 # Trailing-edge Ring Detector -MODEMSTATE_MASK_DSR_CHANGE = 2 # Delta Data-Set-Ready -MODEMSTATE_MASK_CTS_CHANGE = 1 # Delta Clear-To-Send - -PURGE_RECEIVE_BUFFER = b'\x01' # Purge access server receive data buffer -PURGE_TRANSMIT_BUFFER = b'\x02' # Purge access server transmit data buffer -PURGE_BOTH_BUFFERS = b'\x03' # Purge both the access server receive data - # buffer and the access server transmit data buffer - - -RFC2217_PARITY_MAP = { - serial.PARITY_NONE: 1, - serial.PARITY_ODD: 2, - serial.PARITY_EVEN: 3, - serial.PARITY_MARK: 4, - serial.PARITY_SPACE: 5, -} -RFC2217_REVERSE_PARITY_MAP = dict((v, k) for k, v in RFC2217_PARITY_MAP.items()) - -RFC2217_STOPBIT_MAP = { - serial.STOPBITS_ONE: 1, - serial.STOPBITS_ONE_POINT_FIVE: 3, - serial.STOPBITS_TWO: 2, -} -RFC2217_REVERSE_STOPBIT_MAP = dict((v, k) for k, v in RFC2217_STOPBIT_MAP.items()) - -# Telnet filter states -M_NORMAL = 0 -M_IAC_SEEN = 1 -M_NEGOTIATE = 2 - -# TelnetOption and TelnetSubnegotiation states -REQUESTED = 'REQUESTED' -ACTIVE = 'ACTIVE' -INACTIVE = 'INACTIVE' -REALLY_INACTIVE = 'REALLY_INACTIVE' - - -class TelnetOption(object): - """Manage a single telnet option, keeps track of DO/DONT WILL/WONT.""" - - def __init__(self, connection, name, option, send_yes, send_no, ack_yes, - ack_no, initial_state, activation_callback=None): - """\ - Initialize option. - :param connection: connection used to transmit answers - :param name: a readable name for debug outputs - :param send_yes: what to send when option is to be enabled. - :param send_no: what to send when option is to be disabled. - :param ack_yes: what to expect when remote agrees on option. - :param ack_no: what to expect when remote disagrees on option. - :param initial_state: options initialized with REQUESTED are tried to - be enabled on startup. use INACTIVE for all others. - """ - self.connection = connection - self.name = name - self.option = option - self.send_yes = send_yes - self.send_no = send_no - self.ack_yes = ack_yes - self.ack_no = ack_no - self.state = initial_state - self.active = False - self.activation_callback = activation_callback - - def __repr__(self): - """String for debug outputs""" - return "{o.name}:{o.active}({o.state})".format(o=self) - - def process_incoming(self, command): - """\ - A DO/DONT/WILL/WONT was received for this option, update state and - answer when needed. - """ - if command == self.ack_yes: - if self.state is REQUESTED: - self.state = ACTIVE - self.active = True - if self.activation_callback is not None: - self.activation_callback() - elif self.state is ACTIVE: - pass - elif self.state is INACTIVE: - self.state = ACTIVE - self.connection.telnet_send_option(self.send_yes, self.option) - self.active = True - if self.activation_callback is not None: - self.activation_callback() - elif self.state is REALLY_INACTIVE: - self.connection.telnet_send_option(self.send_no, self.option) - else: - raise ValueError('option in illegal state {!r}'.format(self)) - elif command == self.ack_no: - if self.state is REQUESTED: - self.state = INACTIVE - self.active = False - elif self.state is ACTIVE: - self.state = INACTIVE - self.connection.telnet_send_option(self.send_no, self.option) - self.active = False - elif self.state is INACTIVE: - pass - elif self.state is REALLY_INACTIVE: - pass - else: - raise ValueError('option in illegal state {!r}'.format(self)) - - -class TelnetSubnegotiation(object): - """\ - A object to handle subnegotiation of options. In this case actually - sub-sub options for RFC 2217. It is used to track com port options. - """ - - def __init__(self, connection, name, option, ack_option=None): - if ack_option is None: - ack_option = option - self.connection = connection - self.name = name - self.option = option - self.value = None - self.ack_option = ack_option - self.state = INACTIVE - - def __repr__(self): - """String for debug outputs.""" - return "{sn.name}:{sn.state}".format(sn=self) - - def set(self, value): - """\ - Request a change of the value. a request is sent to the server. if - the client needs to know if the change is performed he has to check the - state of this object. - """ - self.value = value - self.state = REQUESTED - self.connection.rfc2217_send_subnegotiation(self.option, self.value) - if self.connection.logger: - self.connection.logger.debug("SB Requesting {} -> {!r}".format(self.name, self.value)) - - def is_ready(self): - """\ - Check if answer from server has been received. when server rejects - the change, raise a ValueError. - """ - if self.state == REALLY_INACTIVE: - raise ValueError("remote rejected value for option {!r}".format(self.name)) - return self.state == ACTIVE - # add property to have a similar interface as TelnetOption - active = property(is_ready) - - def wait(self, timeout=3): - """\ - Wait until the subnegotiation has been acknowledged or timeout. It - can also throw a value error when the answer from the server does not - match the value sent. - """ - timeout_timer = Timeout(timeout) - while not timeout_timer.expired(): - time.sleep(0.05) # prevent 100% CPU load - if self.is_ready(): - break - else: - raise SerialException("timeout while waiting for option {!r}".format(self.name)) - - def check_answer(self, suboption): - """\ - Check an incoming subnegotiation block. The parameter already has - cut off the header like sub option number and com port option value. - """ - if self.value == suboption[:len(self.value)]: - self.state = ACTIVE - else: - # error propagation done in is_ready - self.state = REALLY_INACTIVE - if self.connection.logger: - self.connection.logger.debug("SB Answer {} -> {!r} -> {}".format(self.name, suboption, self.state)) - - -class Serial(SerialBase): - """Serial port implementation for RFC 2217 remote serial ports.""" - - BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200) - - def __init__(self, *args, **kwargs): - super(Serial, self).__init__(*args, **kwargs) - self._thread = None - self._socket = None - self._linestate = 0 - self._modemstate = None - self._modemstate_timeout = Timeout(-1) - self._remote_suspend_flow = False - self._write_lock = None - self.logger = None - self._ignore_set_control_answer = False - self._poll_modem_state = False - self._network_timeout = 3 - self._telnet_options = None - self._rfc2217_port_settings = None - self._rfc2217_options = None - self._read_buffer = None - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened. - """ - self.logger = None - self._ignore_set_control_answer = False - self._poll_modem_state = False - self._network_timeout = 3 - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self.is_open: - raise SerialException("Port is already open.") - try: - self._socket = socket.create_connection(self.from_url(self.portstr), timeout=5) # XXX good value? - self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - except Exception as msg: - self._socket = None - raise SerialException("Could not open port {}: {}".format(self.portstr, msg)) - - # use a thread save queue as buffer. it also simplifies implementing - # the read timeout - self._read_buffer = Queue.Queue() - # to ensure that user writes does not interfere with internal - # telnet/rfc2217 options establish a lock - self._write_lock = threading.Lock() - # name the following separately so that, below, a check can be easily done - mandadory_options = [ - TelnetOption(self, 'we-BINARY', BINARY, WILL, WONT, DO, DONT, INACTIVE), - TelnetOption(self, 'we-RFC2217', COM_PORT_OPTION, WILL, WONT, DO, DONT, REQUESTED), - ] - # all supported telnet options - self._telnet_options = [ - TelnetOption(self, 'ECHO', ECHO, DO, DONT, WILL, WONT, REQUESTED), - TelnetOption(self, 'we-SGA', SGA, WILL, WONT, DO, DONT, REQUESTED), - TelnetOption(self, 'they-SGA', SGA, DO, DONT, WILL, WONT, REQUESTED), - TelnetOption(self, 'they-BINARY', BINARY, DO, DONT, WILL, WONT, INACTIVE), - TelnetOption(self, 'they-RFC2217', COM_PORT_OPTION, DO, DONT, WILL, WONT, REQUESTED), - ] + mandadory_options - # RFC 2217 specific states - # COM port settings - self._rfc2217_port_settings = { - 'baudrate': TelnetSubnegotiation(self, 'baudrate', SET_BAUDRATE, SERVER_SET_BAUDRATE), - 'datasize': TelnetSubnegotiation(self, 'datasize', SET_DATASIZE, SERVER_SET_DATASIZE), - 'parity': TelnetSubnegotiation(self, 'parity', SET_PARITY, SERVER_SET_PARITY), - 'stopsize': TelnetSubnegotiation(self, 'stopsize', SET_STOPSIZE, SERVER_SET_STOPSIZE), - } - # There are more subnegotiation objects, combine all in one dictionary - # for easy access - self._rfc2217_options = { - 'purge': TelnetSubnegotiation(self, 'purge', PURGE_DATA, SERVER_PURGE_DATA), - 'control': TelnetSubnegotiation(self, 'control', SET_CONTROL, SERVER_SET_CONTROL), - } - self._rfc2217_options.update(self._rfc2217_port_settings) - # cache for line and modem states that the server sends to us - self._linestate = 0 - self._modemstate = None - self._modemstate_timeout = Timeout(-1) - # RFC 2217 flow control between server and client - self._remote_suspend_flow = False - - self.is_open = True - self._thread = threading.Thread(target=self._telnet_read_loop) - self._thread.setDaemon(True) - self._thread.setName('pySerial RFC 2217 reader thread for {}'.format(self._port)) - self._thread.start() - - try: # must clean-up if open fails - # negotiate Telnet/RFC 2217 -> send initial requests - for option in self._telnet_options: - if option.state is REQUESTED: - self.telnet_send_option(option.send_yes, option.option) - # now wait until important options are negotiated - timeout = Timeout(self._network_timeout) - while not timeout.expired(): - time.sleep(0.05) # prevent 100% CPU load - if sum(o.active for o in mandadory_options) == sum(o.state != INACTIVE for o in mandadory_options): - break - else: - raise SerialException( - "Remote does not seem to support RFC2217 or BINARY mode {!r}".format(mandadory_options)) - if self.logger: - self.logger.info("Negotiated options: {}".format(self._telnet_options)) - - # fine, go on, set RFC 2271 specific things - self._reconfigure_port() - # all things set up get, now a clean start - if not self._dsrdtr: - self._update_dtr_state() - if not self._rtscts: - self._update_rts_state() - self.reset_input_buffer() - self.reset_output_buffer() - except: - self.close() - raise - - def _reconfigure_port(self): - """Set communication parameters on opened port.""" - if self._socket is None: - raise SerialException("Can only operate on open ports") - - # if self._timeout != 0 and self._interCharTimeout is not None: - # XXX - - if self._write_timeout is not None: - raise NotImplementedError('write_timeout is currently not supported') - # XXX - - # Setup the connection - # to get good performance, all parameter changes are sent first... - if not 0 < self._baudrate < 2 ** 32: - raise ValueError("invalid baudrate: {!r}".format(self._baudrate)) - self._rfc2217_port_settings['baudrate'].set(struct.pack(b'!I', self._baudrate)) - self._rfc2217_port_settings['datasize'].set(struct.pack(b'!B', self._bytesize)) - self._rfc2217_port_settings['parity'].set(struct.pack(b'!B', RFC2217_PARITY_MAP[self._parity])) - self._rfc2217_port_settings['stopsize'].set(struct.pack(b'!B', RFC2217_STOPBIT_MAP[self._stopbits])) - - # and now wait until parameters are active - items = self._rfc2217_port_settings.values() - if self.logger: - self.logger.debug("Negotiating settings: {}".format(items)) - timeout = Timeout(self._network_timeout) - while not timeout.expired(): - time.sleep(0.05) # prevent 100% CPU load - if sum(o.active for o in items) == len(items): - break - else: - raise SerialException("Remote does not accept parameter change (RFC2217): {!r}".format(items)) - if self.logger: - self.logger.info("Negotiated settings: {}".format(items)) - - if self._rtscts and self._xonxoff: - raise ValueError('xonxoff and rtscts together are not supported') - elif self._rtscts: - self.rfc2217_set_control(SET_CONTROL_USE_HW_FLOW_CONTROL) - elif self._xonxoff: - self.rfc2217_set_control(SET_CONTROL_USE_SW_FLOW_CONTROL) - else: - self.rfc2217_set_control(SET_CONTROL_USE_NO_FLOW_CONTROL) - - def close(self): - """Close port""" - self.is_open = False - if self._socket: - try: - self._socket.shutdown(socket.SHUT_RDWR) - self._socket.close() - except: - # ignore errors. - pass - if self._thread: - self._thread.join(7) # XXX more than socket timeout - self._thread = None - # in case of quick reconnects, give the server some time - time.sleep(0.3) - self._socket = None - - def from_url(self, url): - """\ - extract host and port from an URL string, other settings are extracted - an stored in instance - """ - parts = urlparse.urlsplit(url) - if parts.scheme != "rfc2217": - raise SerialException( - 'expected a string in the form ' - '"rfc2217://:[?option[&option...]]": ' - 'not starting with rfc2217:// ({!r})'.format(parts.scheme)) - try: - # process options now, directly altering self - for option, values in urlparse.parse_qs(parts.query, True).items(): - if option == 'logging': - logging.basicConfig() # XXX is that good to call it here? - self.logger = logging.getLogger('pySerial.rfc2217') - self.logger.setLevel(LOGGER_LEVELS[values[0]]) - self.logger.debug('enabled logging') - elif option == 'ign_set_control': - self._ignore_set_control_answer = True - elif option == 'poll_modem': - self._poll_modem_state = True - elif option == 'timeout': - self._network_timeout = float(values[0]) - else: - raise ValueError('unknown option: {!r}'.format(option)) - if not 0 <= parts.port < 65536: - raise ValueError("port not in range 0...65535") - except ValueError as e: - raise SerialException( - 'expected a string in the form ' - '"rfc2217://:[?option[&option...]]": {}'.format(e)) - return (parts.hostname, parts.port) - - # - - - - - - - - - - - - - - - - - - - - - - - - - - @property - def in_waiting(self): - """Return the number of bytes currently in the input buffer.""" - if not self.is_open: - raise portNotOpenError - return self._read_buffer.qsize() - - def read(self, size=1): - """\ - 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 - until the requested number of bytes is read. - """ - if not self.is_open: - raise portNotOpenError - data = bytearray() - try: - while len(data) < size: - if self._thread is None: - raise SerialException('connection failed (reader thread died)') - data += self._read_buffer.get(True, self._timeout) - except Queue.Empty: # -> timeout - pass - return bytes(data) - - def write(self, data): - """\ - Output the given byte string over the serial port. Can block if the - connection is blocked. May raise SerialException if the connection is - closed. - """ - if not self.is_open: - raise portNotOpenError - with self._write_lock: - try: - self._socket.sendall(to_bytes(data).replace(IAC, IAC_DOUBLED)) - except socket.error as e: - raise SerialException("connection failed (socket error): {}".format(e)) - return len(data) - - def reset_input_buffer(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self.is_open: - raise portNotOpenError - self.rfc2217_send_purge(PURGE_RECEIVE_BUFFER) - # empty read buffer - while self._read_buffer.qsize(): - self._read_buffer.get(False) - - def reset_output_buffer(self): - """\ - Clear output buffer, aborting the current output and - discarding all that is in the buffer. - """ - if not self.is_open: - raise portNotOpenError - self.rfc2217_send_purge(PURGE_TRANSMIT_BUFFER) - - def _update_break_state(self): - """\ - Set break: Controls TXD. When active, to transmitting is - possible. - """ - if not self.is_open: - raise portNotOpenError - if self.logger: - self.logger.info('set BREAK to {}'.format('active' if self._break_state else 'inactive')) - if self._break_state: - self.rfc2217_set_control(SET_CONTROL_BREAK_ON) - else: - self.rfc2217_set_control(SET_CONTROL_BREAK_OFF) - - def _update_rts_state(self): - """Set terminal status line: Request To Send.""" - if not self.is_open: - raise portNotOpenError - if self.logger: - self.logger.info('set RTS to {}'.format('active' if self._rts_state else 'inactive')) - if self._rts_state: - self.rfc2217_set_control(SET_CONTROL_RTS_ON) - else: - self.rfc2217_set_control(SET_CONTROL_RTS_OFF) - - def _update_dtr_state(self): - """Set terminal status line: Data Terminal Ready.""" - if not self.is_open: - raise portNotOpenError - if self.logger: - self.logger.info('set DTR to {}'.format('active' if self._dtr_state else 'inactive')) - if self._dtr_state: - self.rfc2217_set_control(SET_CONTROL_DTR_ON) - else: - self.rfc2217_set_control(SET_CONTROL_DTR_OFF) - - @property - def cts(self): - """Read terminal status line: Clear To Send.""" - if not self.is_open: - raise portNotOpenError - return bool(self.get_modem_state() & MODEMSTATE_MASK_CTS) - - @property - def dsr(self): - """Read terminal status line: Data Set Ready.""" - if not self.is_open: - raise portNotOpenError - return bool(self.get_modem_state() & MODEMSTATE_MASK_DSR) - - @property - def ri(self): - """Read terminal status line: Ring Indicator.""" - if not self.is_open: - raise portNotOpenError - return bool(self.get_modem_state() & MODEMSTATE_MASK_RI) - - @property - def cd(self): - """Read terminal status line: Carrier Detect.""" - if not self.is_open: - raise portNotOpenError - return bool(self.get_modem_state() & MODEMSTATE_MASK_CD) - - # - - - platform specific - - - - # None so far - - # - - - RFC2217 specific - - - - - def _telnet_read_loop(self): - """Read loop for the socket.""" - mode = M_NORMAL - suboption = None - try: - while self.is_open: - try: - data = self._socket.recv(1024) - except socket.timeout: - # just need to get out of recv form time to time to check if - # still alive - continue - except socket.error as e: - # connection fails -> terminate loop - if self.logger: - self.logger.debug("socket error in reader thread: {}".format(e)) - break - if not data: - break # lost connection - for byte in iterbytes(data): - if mode == M_NORMAL: - # interpret as command or as data - if byte == IAC: - mode = M_IAC_SEEN - else: - # store data in read buffer or sub option buffer - # depending on state - if suboption is not None: - suboption += byte - else: - self._read_buffer.put(byte) - elif mode == M_IAC_SEEN: - if byte == IAC: - # interpret as command doubled -> insert character - # itself - if suboption is not None: - suboption += IAC - else: - self._read_buffer.put(IAC) - mode = M_NORMAL - elif byte == SB: - # sub option start - suboption = bytearray() - mode = M_NORMAL - elif byte == SE: - # sub option end -> process it now - self._telnet_process_subnegotiation(bytes(suboption)) - suboption = None - mode = M_NORMAL - elif byte in (DO, DONT, WILL, WONT): - # negotiation - telnet_command = byte - mode = M_NEGOTIATE - else: - # other telnet commands - self._telnet_process_command(byte) - mode = M_NORMAL - elif mode == M_NEGOTIATE: # DO, DONT, WILL, WONT was received, option now following - self._telnet_negotiate_option(telnet_command, byte) - mode = M_NORMAL - finally: - self._thread = None - if self.logger: - self.logger.debug("read thread terminated") - - # - incoming telnet commands and options - - def _telnet_process_command(self, command): - """Process commands other than DO, DONT, WILL, WONT.""" - # Currently none. RFC2217 only uses negotiation and subnegotiation. - if self.logger: - self.logger.warning("ignoring Telnet command: {!r}".format(command)) - - def _telnet_negotiate_option(self, command, option): - """Process incoming DO, DONT, WILL, WONT.""" - # check our registered telnet options and forward command to them - # they know themselves if they have to answer or not - known = False - for item in self._telnet_options: - # can have more than one match! as some options are duplicated for - # 'us' and 'them' - if item.option == option: - item.process_incoming(command) - known = True - if not known: - # handle unknown options - # only answer to positive requests and deny them - if command == WILL or command == DO: - self.telnet_send_option((DONT if command == WILL else WONT), option) - if self.logger: - self.logger.warning("rejected Telnet option: {!r}".format(option)) - - def _telnet_process_subnegotiation(self, suboption): - """Process subnegotiation, the data between IAC SB and IAC SE.""" - if suboption[0:1] == COM_PORT_OPTION: - if suboption[1:2] == SERVER_NOTIFY_LINESTATE and len(suboption) >= 3: - self._linestate = ord(suboption[2:3]) # ensure it is a number - if self.logger: - self.logger.info("NOTIFY_LINESTATE: {}".format(self._linestate)) - elif suboption[1:2] == SERVER_NOTIFY_MODEMSTATE and len(suboption) >= 3: - self._modemstate = ord(suboption[2:3]) # ensure it is a number - if self.logger: - self.logger.info("NOTIFY_MODEMSTATE: {}".format(self._modemstate)) - # update time when we think that a poll would make sense - self._modemstate_timeout.restart(0.3) - elif suboption[1:2] == FLOWCONTROL_SUSPEND: - self._remote_suspend_flow = True - elif suboption[1:2] == FLOWCONTROL_RESUME: - self._remote_suspend_flow = False - else: - for item in self._rfc2217_options.values(): - if item.ack_option == suboption[1:2]: - #~ print "processing COM_PORT_OPTION: %r" % list(suboption[1:]) - item.check_answer(bytes(suboption[2:])) - break - else: - if self.logger: - self.logger.warning("ignoring COM_PORT_OPTION: {!r}".format(suboption)) - else: - if self.logger: - self.logger.warning("ignoring subnegotiation: {!r}".format(suboption)) - - # - outgoing telnet commands and options - - def _internal_raw_write(self, data): - """internal socket write with no data escaping. used to send telnet stuff.""" - with self._write_lock: - self._socket.sendall(data) - - def telnet_send_option(self, action, option): - """Send DO, DONT, WILL, WONT.""" - self._internal_raw_write(to_bytes([IAC, action, option])) - - def rfc2217_send_subnegotiation(self, option, value=b''): - """Subnegotiation of RFC2217 parameters.""" - value = value.replace(IAC, IAC_DOUBLED) - self._internal_raw_write(to_bytes([IAC, SB, COM_PORT_OPTION, option] + list(value) + [IAC, SE])) - - def rfc2217_send_purge(self, value): - """\ - Send purge request to the remote. - (PURGE_RECEIVE_BUFFER / PURGE_TRANSMIT_BUFFER / PURGE_BOTH_BUFFERS) - """ - item = self._rfc2217_options['purge'] - item.set(value) # transmit desired purge type - item.wait(self._network_timeout) # wait for acknowledge from the server - - def rfc2217_set_control(self, value): - """transmit change of control line to remote""" - item = self._rfc2217_options['control'] - item.set(value) # transmit desired control type - if self._ignore_set_control_answer: - # answers are ignored when option is set. compatibility mode for - # servers that answer, but not the expected one... (or no answer - # at all) i.e. sredird - time.sleep(0.1) # this helps getting the unit tests passed - else: - item.wait(self._network_timeout) # wait for acknowledge from the server - - def rfc2217_flow_server_ready(self): - """\ - check if server is ready to receive data. block for some time when - not. - """ - #~ if self._remote_suspend_flow: - #~ wait--- - - def get_modem_state(self): - """\ - get last modem state (cached value. If value is "old", request a new - one. This cache helps that we don't issue to many requests when e.g. all - status lines, one after the other is queried by the user (getCTS, getDSR - etc.) - """ - # active modem state polling enabled? is the value fresh enough? - if self._poll_modem_state and self._modemstate_timeout.expired(): - if self.logger: - self.logger.debug('polling modem state') - # when it is older, request an update - self.rfc2217_send_subnegotiation(NOTIFY_MODEMSTATE) - timeout = Timeout(self._network_timeout) - while not timeout.expired(): - time.sleep(0.05) # prevent 100% CPU load - # when expiration time is updated, it means that there is a new - # value - if not self._modemstate_timeout.expired(): - break - else: - if self.logger: - self.logger.warning('poll for modem state failed') - # even when there is a timeout, do not generate an error just - # return the last known value. this way we can support buggy - # servers that do not respond to polls, but send automatic - # updates. - if self._modemstate is not None: - if self.logger: - self.logger.debug('using cached modem state') - return self._modemstate - else: - # never received a notification from the server - raise SerialException("remote sends no NOTIFY_MODEMSTATE") - - -############################################################################# -# The following is code that helps implementing an RFC 2217 server. - -class PortManager(object): - """\ - This class manages the state of Telnet and RFC 2217. It needs a serial - instance and a connection to work with. Connection is expected to implement - a (thread safe) write function, that writes the string to the network. - """ - - def __init__(self, serial_port, connection, logger=None): - self.serial = serial_port - self.connection = connection - self.logger = logger - self._client_is_rfc2217 = False - - # filter state machine - self.mode = M_NORMAL - self.suboption = None - self.telnet_command = None - - # states for modem/line control events - self.modemstate_mask = 255 - self.last_modemstate = None - self.linstate_mask = 0 - - # all supported telnet options - self._telnet_options = [ - TelnetOption(self, 'ECHO', ECHO, WILL, WONT, DO, DONT, REQUESTED), - TelnetOption(self, 'we-SGA', SGA, WILL, WONT, DO, DONT, REQUESTED), - TelnetOption(self, 'they-SGA', SGA, DO, DONT, WILL, WONT, INACTIVE), - TelnetOption(self, 'we-BINARY', BINARY, WILL, WONT, DO, DONT, INACTIVE), - TelnetOption(self, 'they-BINARY', BINARY, DO, DONT, WILL, WONT, REQUESTED), - TelnetOption(self, 'we-RFC2217', COM_PORT_OPTION, WILL, WONT, DO, DONT, REQUESTED, self._client_ok), - TelnetOption(self, 'they-RFC2217', COM_PORT_OPTION, DO, DONT, WILL, WONT, INACTIVE, self._client_ok), - ] - - # negotiate Telnet/RFC2217 -> send initial requests - if self.logger: - self.logger.debug("requesting initial Telnet/RFC 2217 options") - for option in self._telnet_options: - if option.state is REQUESTED: - self.telnet_send_option(option.send_yes, option.option) - # issue 1st modem state notification - - def _client_ok(self): - """\ - callback of telnet option. It gets called when option is activated. - This one here is used to detect when the client agrees on RFC 2217. A - flag is set so that other functions like check_modem_lines know if the - client is OK. - """ - # The callback is used for we and they so if one party agrees, we're - # already happy. it seems not all servers do the negotiation correctly - # and i guess there are incorrect clients too.. so be happy if client - # answers one or the other positively. - self._client_is_rfc2217 = True - if self.logger: - self.logger.info("client accepts RFC 2217") - # this is to ensure that the client gets a notification, even if there - # was no change - self.check_modem_lines(force_notification=True) - - # - outgoing telnet commands and options - - def telnet_send_option(self, action, option): - """Send DO, DONT, WILL, WONT.""" - self.connection.write(to_bytes([IAC, action, option])) - - def rfc2217_send_subnegotiation(self, option, value=b''): - """Subnegotiation of RFC 2217 parameters.""" - value = value.replace(IAC, IAC_DOUBLED) - self.connection.write(to_bytes([IAC, SB, COM_PORT_OPTION, option] + list(value) + [IAC, SE])) - - # - check modem lines, needs to be called periodically from user to - # establish polling - - def check_modem_lines(self, force_notification=False): - """\ - read control lines from serial port and compare the last value sent to remote. - send updates on changes. - """ - modemstate = ( - (self.serial.getCTS() and MODEMSTATE_MASK_CTS) | - (self.serial.getDSR() and MODEMSTATE_MASK_DSR) | - (self.serial.getRI() and MODEMSTATE_MASK_RI) | - (self.serial.getCD() and MODEMSTATE_MASK_CD)) - # check what has changed - deltas = modemstate ^ (self.last_modemstate or 0) # when last is None -> 0 - if deltas & MODEMSTATE_MASK_CTS: - modemstate |= MODEMSTATE_MASK_CTS_CHANGE - if deltas & MODEMSTATE_MASK_DSR: - modemstate |= MODEMSTATE_MASK_DSR_CHANGE - if deltas & MODEMSTATE_MASK_RI: - modemstate |= MODEMSTATE_MASK_RI_CHANGE - if deltas & MODEMSTATE_MASK_CD: - modemstate |= MODEMSTATE_MASK_CD_CHANGE - # if new state is different and the mask allows this change, send - # notification. suppress notifications when client is not rfc2217 - if modemstate != self.last_modemstate or force_notification: - if (self._client_is_rfc2217 and (modemstate & self.modemstate_mask)) or force_notification: - self.rfc2217_send_subnegotiation( - SERVER_NOTIFY_MODEMSTATE, - to_bytes([modemstate & self.modemstate_mask])) - if self.logger: - self.logger.info("NOTIFY_MODEMSTATE: {}".format(modemstate)) - # save last state, but forget about deltas. - # otherwise it would also notify about changing deltas which is - # probably not very useful - self.last_modemstate = modemstate & 0xf0 - - # - outgoing data escaping - - def escape(self, data): - """\ - This generator function is for the user. All outgoing data has to be - properly escaped, so that no IAC character in the data stream messes up - the Telnet state machine in the server. - - socket.sendall(escape(data)) - """ - for byte in iterbytes(data): - if byte == IAC: - yield IAC - yield IAC - else: - yield byte - - # - incoming data filter - - def filter(self, data): - """\ - Handle a bunch of incoming bytes. This is a generator. It will yield - all characters not of interest for Telnet/RFC 2217. - - The idea is that the reader thread pushes data from the socket through - this filter: - - for byte in filter(socket.recv(1024)): - # do things like CR/LF conversion/whatever - # and write data to the serial port - serial.write(byte) - - (socket error handling code left as exercise for the reader) - """ - for byte in iterbytes(data): - if self.mode == M_NORMAL: - # interpret as command or as data - if byte == IAC: - self.mode = M_IAC_SEEN - else: - # store data in sub option buffer or pass it to our - # consumer depending on state - if self.suboption is not None: - self.suboption += byte - else: - yield byte - elif self.mode == M_IAC_SEEN: - if byte == IAC: - # interpret as command doubled -> insert character - # itself - if self.suboption is not None: - self.suboption += byte - else: - yield byte - self.mode = M_NORMAL - elif byte == SB: - # sub option start - self.suboption = bytearray() - self.mode = M_NORMAL - elif byte == SE: - # sub option end -> process it now - self._telnet_process_subnegotiation(bytes(self.suboption)) - self.suboption = None - self.mode = M_NORMAL - elif byte in (DO, DONT, WILL, WONT): - # negotiation - self.telnet_command = byte - self.mode = M_NEGOTIATE - else: - # other telnet commands - self._telnet_process_command(byte) - self.mode = M_NORMAL - elif self.mode == M_NEGOTIATE: # DO, DONT, WILL, WONT was received, option now following - self._telnet_negotiate_option(self.telnet_command, byte) - self.mode = M_NORMAL - - # - incoming telnet commands and options - - def _telnet_process_command(self, command): - """Process commands other than DO, DONT, WILL, WONT.""" - # Currently none. RFC2217 only uses negotiation and subnegotiation. - if self.logger: - self.logger.warning("ignoring Telnet command: {!r}".format(command)) - - def _telnet_negotiate_option(self, command, option): - """Process incoming DO, DONT, WILL, WONT.""" - # check our registered telnet options and forward command to them - # they know themselves if they have to answer or not - known = False - for item in self._telnet_options: - # can have more than one match! as some options are duplicated for - # 'us' and 'them' - if item.option == option: - item.process_incoming(command) - known = True - if not known: - # handle unknown options - # only answer to positive requests and deny them - if command == WILL or command == DO: - self.telnet_send_option((DONT if command == WILL else WONT), option) - if self.logger: - self.logger.warning("rejected Telnet option: {!r}".format(option)) - - def _telnet_process_subnegotiation(self, suboption): - """Process subnegotiation, the data between IAC SB and IAC SE.""" - if suboption[0:1] == COM_PORT_OPTION: - if self.logger: - self.logger.debug('received COM_PORT_OPTION: {!r}'.format(suboption)) - if suboption[1:2] == SET_BAUDRATE: - backup = self.serial.baudrate - try: - (baudrate,) = struct.unpack(b"!I", suboption[2:6]) - if baudrate != 0: - self.serial.baudrate = baudrate - except ValueError as e: - if self.logger: - self.logger.error("failed to set baud rate: {}".format(e)) - self.serial.baudrate = backup - else: - if self.logger: - self.logger.info("{} baud rate: {}".format('set' if baudrate else 'get', self.serial.baudrate)) - self.rfc2217_send_subnegotiation(SERVER_SET_BAUDRATE, struct.pack(b"!I", self.serial.baudrate)) - elif suboption[1:2] == SET_DATASIZE: - backup = self.serial.bytesize - try: - (datasize,) = struct.unpack(b"!B", suboption[2:3]) - if datasize != 0: - self.serial.bytesize = datasize - except ValueError as e: - if self.logger: - self.logger.error("failed to set data size: {}".format(e)) - self.serial.bytesize = backup - else: - if self.logger: - self.logger.info("{} data size: {}".format('set' if datasize else 'get', self.serial.bytesize)) - self.rfc2217_send_subnegotiation(SERVER_SET_DATASIZE, struct.pack(b"!B", self.serial.bytesize)) - elif suboption[1:2] == SET_PARITY: - backup = self.serial.parity - try: - parity = struct.unpack(b"!B", suboption[2:3])[0] - if parity != 0: - self.serial.parity = RFC2217_REVERSE_PARITY_MAP[parity] - except ValueError as e: - if self.logger: - self.logger.error("failed to set parity: {}".format(e)) - self.serial.parity = backup - else: - if self.logger: - self.logger.info("{} parity: {}".format('set' if parity else 'get', self.serial.parity)) - self.rfc2217_send_subnegotiation( - SERVER_SET_PARITY, - struct.pack(b"!B", RFC2217_PARITY_MAP[self.serial.parity])) - elif suboption[1:2] == SET_STOPSIZE: - backup = self.serial.stopbits - try: - stopbits = struct.unpack(b"!B", suboption[2:3])[0] - if stopbits != 0: - self.serial.stopbits = RFC2217_REVERSE_STOPBIT_MAP[stopbits] - except ValueError as e: - if self.logger: - self.logger.error("failed to set stop bits: {}".format(e)) - self.serial.stopbits = backup - else: - if self.logger: - self.logger.info("{} stop bits: {}".format('set' if stopbits else 'get', self.serial.stopbits)) - self.rfc2217_send_subnegotiation( - SERVER_SET_STOPSIZE, - struct.pack(b"!B", RFC2217_STOPBIT_MAP[self.serial.stopbits])) - elif suboption[1:2] == SET_CONTROL: - if suboption[2:3] == SET_CONTROL_REQ_FLOW_SETTING: - if self.serial.xonxoff: - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_SW_FLOW_CONTROL) - elif self.serial.rtscts: - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_HW_FLOW_CONTROL) - else: - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_NO_FLOW_CONTROL) - elif suboption[2:3] == SET_CONTROL_USE_NO_FLOW_CONTROL: - self.serial.xonxoff = False - self.serial.rtscts = False - if self.logger: - self.logger.info("changed flow control to None") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_NO_FLOW_CONTROL) - elif suboption[2:3] == SET_CONTROL_USE_SW_FLOW_CONTROL: - self.serial.xonxoff = True - if self.logger: - self.logger.info("changed flow control to XON/XOFF") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_SW_FLOW_CONTROL) - elif suboption[2:3] == SET_CONTROL_USE_HW_FLOW_CONTROL: - self.serial.rtscts = True - if self.logger: - self.logger.info("changed flow control to RTS/CTS") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_HW_FLOW_CONTROL) - elif suboption[2:3] == SET_CONTROL_REQ_BREAK_STATE: - if self.logger: - self.logger.warning("requested break state - not implemented") - pass # XXX needs cached value - elif suboption[2:3] == SET_CONTROL_BREAK_ON: - self.serial.setBreak(True) - if self.logger: - self.logger.info("changed BREAK to active") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_BREAK_ON) - elif suboption[2:3] == SET_CONTROL_BREAK_OFF: - self.serial.setBreak(False) - if self.logger: - self.logger.info("changed BREAK to inactive") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_BREAK_OFF) - elif suboption[2:3] == SET_CONTROL_REQ_DTR: - if self.logger: - self.logger.warning("requested DTR state - not implemented") - pass # XXX needs cached value - elif suboption[2:3] == SET_CONTROL_DTR_ON: - self.serial.setDTR(True) - if self.logger: - self.logger.info("changed DTR to active") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_DTR_ON) - elif suboption[2:3] == SET_CONTROL_DTR_OFF: - self.serial.setDTR(False) - if self.logger: - self.logger.info("changed DTR to inactive") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_DTR_OFF) - elif suboption[2:3] == SET_CONTROL_REQ_RTS: - if self.logger: - self.logger.warning("requested RTS state - not implemented") - pass # XXX needs cached value - #~ self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_ON) - elif suboption[2:3] == SET_CONTROL_RTS_ON: - self.serial.setRTS(True) - if self.logger: - self.logger.info("changed RTS to active") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_ON) - elif suboption[2:3] == SET_CONTROL_RTS_OFF: - self.serial.setRTS(False) - if self.logger: - self.logger.info("changed RTS to inactive") - self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_OFF) - #~ elif suboption[2:3] == SET_CONTROL_REQ_FLOW_SETTING_IN: - #~ elif suboption[2:3] == SET_CONTROL_USE_NO_FLOW_CONTROL_IN: - #~ elif suboption[2:3] == SET_CONTROL_USE_SW_FLOW_CONTOL_IN: - #~ elif suboption[2:3] == SET_CONTROL_USE_HW_FLOW_CONTOL_IN: - #~ elif suboption[2:3] == SET_CONTROL_USE_DCD_FLOW_CONTROL: - #~ elif suboption[2:3] == SET_CONTROL_USE_DTR_FLOW_CONTROL: - #~ elif suboption[2:3] == SET_CONTROL_USE_DSR_FLOW_CONTROL: - elif suboption[1:2] == NOTIFY_LINESTATE: - # client polls for current state - self.rfc2217_send_subnegotiation( - SERVER_NOTIFY_LINESTATE, - to_bytes([0])) # sorry, nothing like that implemented - elif suboption[1:2] == NOTIFY_MODEMSTATE: - if self.logger: - self.logger.info("request for modem state") - # client polls for current state - self.check_modem_lines(force_notification=True) - elif suboption[1:2] == FLOWCONTROL_SUSPEND: - if self.logger: - self.logger.info("suspend") - self._remote_suspend_flow = True - elif suboption[1:2] == FLOWCONTROL_RESUME: - if self.logger: - self.logger.info("resume") - self._remote_suspend_flow = False - elif suboption[1:2] == SET_LINESTATE_MASK: - self.linstate_mask = ord(suboption[2:3]) # ensure it is a number - if self.logger: - self.logger.info("line state mask: 0x{:02x}".format(self.linstate_mask)) - elif suboption[1:2] == SET_MODEMSTATE_MASK: - self.modemstate_mask = ord(suboption[2:3]) # ensure it is a number - if self.logger: - self.logger.info("modem state mask: 0x{:02x}".format(self.modemstate_mask)) - elif suboption[1:2] == PURGE_DATA: - if suboption[2:3] == PURGE_RECEIVE_BUFFER: - self.serial.reset_input_buffer() - if self.logger: - self.logger.info("purge in") - self.rfc2217_send_subnegotiation(SERVER_PURGE_DATA, PURGE_RECEIVE_BUFFER) - elif suboption[2:3] == PURGE_TRANSMIT_BUFFER: - self.serial.reset_output_buffer() - if self.logger: - self.logger.info("purge out") - self.rfc2217_send_subnegotiation(SERVER_PURGE_DATA, PURGE_TRANSMIT_BUFFER) - elif suboption[2:3] == PURGE_BOTH_BUFFERS: - self.serial.reset_input_buffer() - self.serial.reset_output_buffer() - if self.logger: - self.logger.info("purge both") - self.rfc2217_send_subnegotiation(SERVER_PURGE_DATA, PURGE_BOTH_BUFFERS) - else: - if self.logger: - self.logger.error("undefined PURGE_DATA: {!r}".format(list(suboption[2:]))) - else: - if self.logger: - self.logger.error("undefined COM_PORT_OPTION: {!r}".format(list(suboption[1:]))) - else: - if self.logger: - self.logger.warning("unknown subnegotiation: {!r}".format(suboption)) - - -# simple client test -if __name__ == '__main__': - import sys - s = Serial('rfc2217://localhost:7000', 115200) - sys.stdout.write('{}\n'.format(s)) - - sys.stdout.write("write...\n") - s.write(b"hello\n") - s.flush() - sys.stdout.write("read: {}\n".format(s.read(5))) - s.close() diff --git a/mFIZ/scripts/mFIZ_extern/serial/rs485.py b/mFIZ/scripts/mFIZ_extern/serial/rs485.py deleted file mode 100644 index 2939350..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/rs485.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python - -# RS485 support -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -"""\ -The settings for RS485 are stored in a dedicated object that can be applied to -serial ports (where supported). -NOTE: Some implementations may only support a subset of the settings. -""" - -import time -import serial - - -class RS485Settings(object): - def __init__( - self, - rts_level_for_tx=True, - rts_level_for_rx=False, - loopback=False, - delay_before_tx=None, - delay_before_rx=None): - self.rts_level_for_tx = rts_level_for_tx - self.rts_level_for_rx = rts_level_for_rx - self.loopback = loopback - self.delay_before_tx = delay_before_tx - self.delay_before_rx = delay_before_rx - - -class RS485(serial.Serial): - """\ - A subclass that replaces the write method with one that toggles RTS - according to the RS485 settings. - - NOTE: This may work unreliably on some serial ports (control signals not - synchronized or delayed compared to data). Using delays may be - unreliable (varying times, larger than expected) as the OS may not - support very fine grained delays (no smaller than in the order of - tens of milliseconds). - - NOTE: Some implementations support this natively. Better performance - can be expected when the native version is used. - - NOTE: The loopback property is ignored by this implementation. The actual - behavior depends on the used hardware. - - Usage: - - ser = RS485(...) - ser.rs485_mode = RS485Settings(...) - ser.write(b'hello') - """ - - def __init__(self, *args, **kwargs): - super(RS485, self).__init__(*args, **kwargs) - self._alternate_rs485_settings = None - - def write(self, b): - """Write to port, controlling RTS before and after transmitting.""" - if self._alternate_rs485_settings is not None: - # apply level for TX and optional delay - self.setRTS(self._alternate_rs485_settings.rts_level_for_tx) - if self._alternate_rs485_settings.delay_before_tx is not None: - time.sleep(self._alternate_rs485_settings.delay_before_tx) - # write and wait for data to be written - super(RS485, self).write(b) - super(RS485, self).flush() - # optional delay and apply level for RX - if self._alternate_rs485_settings.delay_before_rx is not None: - time.sleep(self._alternate_rs485_settings.delay_before_rx) - self.setRTS(self._alternate_rs485_settings.rts_level_for_rx) - else: - super(RS485, self).write(b) - - # redirect where the property stores the settings so that underlying Serial - # instance does not see them - @property - def rs485_mode(self): - """\ - Enable RS485 mode and apply new settings, set to None to disable. - See serial.rs485.RS485Settings for more info about the value. - """ - return self._alternate_rs485_settings - - @rs485_mode.setter - def rs485_mode(self, rs485_settings): - self._alternate_rs485_settings = rs485_settings diff --git a/mFIZ/scripts/mFIZ_extern/serial/serialcli.py b/mFIZ/scripts/mFIZ_extern/serial/serialcli.py deleted file mode 100644 index 0727a52..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/serialcli.py +++ /dev/null @@ -1,251 +0,0 @@ -#! python -# -# Backend for .NET/Mono (IronPython), .NET >= 2 -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2008-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -import System -import System.IO.Ports -from serial.serialutil import * - -# must invoke function with byte array, make a helper to convert strings -# to byte arrays -sab = System.Array[System.Byte] - - -def as_byte_array(string): - return sab([ord(x) for x in string]) # XXX will require adaption when run with a 3.x compatible IronPython - - -class Serial(SerialBase): - """Serial port implementation for .NET/Mono.""" - - BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200) - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened. - """ - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self.is_open: - raise SerialException("Port is already open.") - try: - self._port_handle = System.IO.Ports.SerialPort(self.portstr) - except Exception as msg: - self._port_handle = None - raise SerialException("could not open port %s: %s" % (self.portstr, msg)) - - # if RTS and/or DTR are not set before open, they default to True - if self._rts_state is None: - self._rts_state = True - if self._dtr_state is None: - self._dtr_state = True - - self._reconfigure_port() - self._port_handle.Open() - self.is_open = True - if not self._dsrdtr: - self._update_dtr_state() - if not self._rtscts: - self._update_rts_state() - self.reset_input_buffer() - - def _reconfigure_port(self): - """Set communication parameters on opened port.""" - if not self._port_handle: - raise SerialException("Can only operate on a valid port handle") - - #~ self._port_handle.ReceivedBytesThreshold = 1 - - if self._timeout is None: - self._port_handle.ReadTimeout = System.IO.Ports.SerialPort.InfiniteTimeout - else: - self._port_handle.ReadTimeout = int(self._timeout * 1000) - - # if self._timeout != 0 and self._interCharTimeout is not None: - # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:] - - if self._write_timeout is None: - self._port_handle.WriteTimeout = System.IO.Ports.SerialPort.InfiniteTimeout - else: - self._port_handle.WriteTimeout = int(self._write_timeout * 1000) - - # Setup the connection info. - try: - self._port_handle.BaudRate = self._baudrate - except IOError as e: - # catch errors from illegal baudrate settings - raise ValueError(str(e)) - - if self._bytesize == FIVEBITS: - self._port_handle.DataBits = 5 - elif self._bytesize == SIXBITS: - self._port_handle.DataBits = 6 - elif self._bytesize == SEVENBITS: - self._port_handle.DataBits = 7 - elif self._bytesize == EIGHTBITS: - self._port_handle.DataBits = 8 - else: - raise ValueError("Unsupported number of data bits: %r" % self._bytesize) - - if self._parity == PARITY_NONE: - self._port_handle.Parity = getattr(System.IO.Ports.Parity, 'None') # reserved keyword in Py3k - elif self._parity == PARITY_EVEN: - self._port_handle.Parity = System.IO.Ports.Parity.Even - elif self._parity == PARITY_ODD: - self._port_handle.Parity = System.IO.Ports.Parity.Odd - elif self._parity == PARITY_MARK: - self._port_handle.Parity = System.IO.Ports.Parity.Mark - elif self._parity == PARITY_SPACE: - self._port_handle.Parity = System.IO.Ports.Parity.Space - else: - raise ValueError("Unsupported parity mode: %r" % self._parity) - - if self._stopbits == STOPBITS_ONE: - self._port_handle.StopBits = System.IO.Ports.StopBits.One - elif self._stopbits == STOPBITS_ONE_POINT_FIVE: - self._port_handle.StopBits = System.IO.Ports.StopBits.OnePointFive - elif self._stopbits == STOPBITS_TWO: - self._port_handle.StopBits = System.IO.Ports.StopBits.Two - else: - raise ValueError("Unsupported number of stop bits: %r" % self._stopbits) - - if self._rtscts and self._xonxoff: - self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff - elif self._rtscts: - self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSend - elif self._xonxoff: - self._port_handle.Handshake = System.IO.Ports.Handshake.XOnXOff - else: - self._port_handle.Handshake = getattr(System.IO.Ports.Handshake, 'None') # reserved keyword in Py3k - - #~ def __del__(self): - #~ self.close() - - def close(self): - """Close port""" - if self.is_open: - if self._port_handle: - try: - self._port_handle.Close() - except System.IO.Ports.InvalidOperationException: - # ignore errors. can happen for unplugged USB serial devices - pass - self._port_handle = None - self.is_open = False - - # - - - - - - - - - - - - - - - - - - - - - - - - - - @property - def in_waiting(self): - """Return the number of characters currently in the input buffer.""" - if not self.is_open: - raise portNotOpenError - return self._port_handle.BytesToRead - - def read(self, size=1): - """\ - 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 - until the requested number of bytes is read. - """ - if not self.is_open: - raise portNotOpenError - # must use single byte reads as this is the only way to read - # without applying encodings - data = bytearray() - while size: - try: - data.append(self._port_handle.ReadByte()) - except System.TimeoutException: - break - else: - size -= 1 - return bytes(data) - - def write(self, data): - """Output the given string over the serial port.""" - if not self.is_open: - raise portNotOpenError - #~ if not isinstance(data, (bytes, bytearray)): - #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data))) - try: - # must call overloaded method with byte array argument - # as this is the only one not applying encodings - self._port_handle.Write(as_byte_array(data), 0, len(data)) - except System.TimeoutException: - raise writeTimeoutError - return len(data) - - def reset_input_buffer(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self.is_open: - raise portNotOpenError - self._port_handle.DiscardInBuffer() - - def reset_output_buffer(self): - """\ - Clear output buffer, aborting the current output and - discarding all that is in the buffer. - """ - if not self.is_open: - raise portNotOpenError - self._port_handle.DiscardOutBuffer() - - def _update_break_state(self): - """ - Set break: Controls TXD. When active, to transmitting is possible. - """ - if not self.is_open: - raise portNotOpenError - self._port_handle.BreakState = bool(self._break_state) - - def _update_rts_state(self): - """Set terminal status line: Request To Send""" - if not self.is_open: - raise portNotOpenError - self._port_handle.RtsEnable = bool(self._rts_state) - - def _update_dtr_state(self): - """Set terminal status line: Data Terminal Ready""" - if not self.is_open: - raise portNotOpenError - self._port_handle.DtrEnable = bool(self._dtr_state) - - @property - def cts(self): - """Read terminal status line: Clear To Send""" - if not self.is_open: - raise portNotOpenError - return self._port_handle.CtsHolding - - @property - def dsr(self): - """Read terminal status line: Data Set Ready""" - if not self.is_open: - raise portNotOpenError - return self._port_handle.DsrHolding - - @property - def ri(self): - """Read terminal status line: Ring Indicator""" - if not self.is_open: - raise portNotOpenError - #~ return self._port_handle.XXX - return False # XXX an error would be better - - @property - def cd(self): - """Read terminal status line: Carrier Detect""" - if not self.is_open: - raise portNotOpenError - return self._port_handle.CDHolding - - # - - platform specific - - - - - # none diff --git a/mFIZ/scripts/mFIZ_extern/serial/serialjava.py b/mFIZ/scripts/mFIZ_extern/serial/serialjava.py deleted file mode 100644 index 7bd5b3e..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/serialjava.py +++ /dev/null @@ -1,249 +0,0 @@ -#!jython -# -# Backend Jython with JavaComm -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2002-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -from serial.serialutil import * - - -def my_import(name): - mod = __import__(name) - components = name.split('.') - for comp in components[1:]: - mod = getattr(mod, comp) - return mod - - -def detect_java_comm(names): - """try given list of modules and return that imports""" - for name in names: - try: - mod = my_import(name) - mod.SerialPort - return mod - except (ImportError, AttributeError): - pass - raise ImportError("No Java Communications API implementation found") - - -# Java Communications API implementations -# http://mho.republika.pl/java/comm/ - -comm = detect_java_comm([ - 'javax.comm', # Sun/IBM - 'gnu.io', # RXTX -]) - - -def device(portnumber): - """Turn a port number into a device name""" - enum = comm.CommPortIdentifier.getPortIdentifiers() - ports = [] - while enum.hasMoreElements(): - el = enum.nextElement() - if el.getPortType() == comm.CommPortIdentifier.PORT_SERIAL: - ports.append(el) - return ports[portnumber].getName() - - -class Serial(SerialBase): - """\ - Serial port class, implemented with Java Communications API and - thus usable with jython and the appropriate java extension. - """ - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened. - """ - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self.is_open: - raise SerialException("Port is already open.") - if type(self._port) == type(''): # strings are taken directly - portId = comm.CommPortIdentifier.getPortIdentifier(self._port) - else: - portId = comm.CommPortIdentifier.getPortIdentifier(device(self._port)) # numbers are transformed to a comport id obj - try: - self.sPort = portId.open("python serial module", 10) - except Exception as msg: - self.sPort = None - raise SerialException("Could not open port: %s" % msg) - self._reconfigurePort() - self._instream = self.sPort.getInputStream() - self._outstream = self.sPort.getOutputStream() - self.is_open = True - - def _reconfigurePort(self): - """Set communication parameters on opened port.""" - if not self.sPort: - raise SerialException("Can only operate on a valid port handle") - - self.sPort.enableReceiveTimeout(30) - if self._bytesize == FIVEBITS: - jdatabits = comm.SerialPort.DATABITS_5 - elif self._bytesize == SIXBITS: - jdatabits = comm.SerialPort.DATABITS_6 - elif self._bytesize == SEVENBITS: - jdatabits = comm.SerialPort.DATABITS_7 - elif self._bytesize == EIGHTBITS: - jdatabits = comm.SerialPort.DATABITS_8 - else: - raise ValueError("unsupported bytesize: %r" % self._bytesize) - - if self._stopbits == STOPBITS_ONE: - jstopbits = comm.SerialPort.STOPBITS_1 - elif self._stopbits == STOPBITS_ONE_POINT_FIVE: - jstopbits = comm.SerialPort.STOPBITS_1_5 - elif self._stopbits == STOPBITS_TWO: - jstopbits = comm.SerialPort.STOPBITS_2 - else: - raise ValueError("unsupported number of stopbits: %r" % self._stopbits) - - if self._parity == PARITY_NONE: - jparity = comm.SerialPort.PARITY_NONE - elif self._parity == PARITY_EVEN: - jparity = comm.SerialPort.PARITY_EVEN - elif self._parity == PARITY_ODD: - jparity = comm.SerialPort.PARITY_ODD - elif self._parity == PARITY_MARK: - jparity = comm.SerialPort.PARITY_MARK - elif self._parity == PARITY_SPACE: - jparity = comm.SerialPort.PARITY_SPACE - else: - raise ValueError("unsupported parity type: %r" % self._parity) - - jflowin = jflowout = 0 - if self._rtscts: - jflowin |= comm.SerialPort.FLOWCONTROL_RTSCTS_IN - jflowout |= comm.SerialPort.FLOWCONTROL_RTSCTS_OUT - if self._xonxoff: - jflowin |= comm.SerialPort.FLOWCONTROL_XONXOFF_IN - jflowout |= comm.SerialPort.FLOWCONTROL_XONXOFF_OUT - - self.sPort.setSerialPortParams(self._baudrate, jdatabits, jstopbits, jparity) - self.sPort.setFlowControlMode(jflowin | jflowout) - - if self._timeout >= 0: - self.sPort.enableReceiveTimeout(int(self._timeout*1000)) - else: - self.sPort.disableReceiveTimeout() - - def close(self): - """Close port""" - if self.is_open: - if self.sPort: - self._instream.close() - self._outstream.close() - self.sPort.close() - self.sPort = None - self.is_open = False - - # - - - - - - - - - - - - - - - - - - - - - - - - - - @property - def in_waiting(self): - """Return the number of characters currently in the input buffer.""" - if not self.sPort: - raise portNotOpenError - return self._instream.available() - - def read(self, size=1): - """\ - 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 - until the requested number of bytes is read. - """ - if not self.sPort: - raise portNotOpenError - read = bytearray() - if size > 0: - while len(read) < size: - x = self._instream.read() - if x == -1: - if self.timeout >= 0: - break - else: - read.append(x) - return bytes(read) - - def write(self, data): - """Output the given string over the serial port.""" - if not self.sPort: - raise portNotOpenError - if not isinstance(data, (bytes, bytearray)): - raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data))) - self._outstream.write(data) - return len(data) - - def reset_input_buffer(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self.sPort: - raise portNotOpenError - self._instream.skip(self._instream.available()) - - def reset_output_buffer(self): - """\ - Clear output buffer, aborting the current output and - discarding all that is in the buffer. - """ - if not self.sPort: - raise portNotOpenError - self._outstream.flush() - - def send_break(self, duration=0.25): - """Send break condition. Timed, returns to idle state after given duration.""" - if not self.sPort: - raise portNotOpenError - self.sPort.sendBreak(duration*1000.0) - - def _update_break_state(self): - """Set break: Controls TXD. When active, to transmitting is possible.""" - if self.fd is None: - raise portNotOpenError - raise SerialException("The _update_break_state function is not implemented in java.") - - def _update_rts_state(self): - """Set terminal status line: Request To Send""" - if not self.sPort: - raise portNotOpenError - self.sPort.setRTS(self._rts_state) - - def _update_dtr_state(self): - """Set terminal status line: Data Terminal Ready""" - if not self.sPort: - raise portNotOpenError - self.sPort.setDTR(self._dtr_state) - - @property - def cts(self): - """Read terminal status line: Clear To Send""" - if not self.sPort: - raise portNotOpenError - self.sPort.isCTS() - - @property - def dsr(self): - """Read terminal status line: Data Set Ready""" - if not self.sPort: - raise portNotOpenError - self.sPort.isDSR() - - @property - def ri(self): - """Read terminal status line: Ring Indicator""" - if not self.sPort: - raise portNotOpenError - self.sPort.isRI() - - @property - def cd(self): - """Read terminal status line: Carrier Detect""" - if not self.sPort: - raise portNotOpenError - self.sPort.isCD() diff --git a/mFIZ/scripts/mFIZ_extern/serial/serialposix.py b/mFIZ/scripts/mFIZ_extern/serial/serialposix.py deleted file mode 100644 index 01848e9..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/serialposix.py +++ /dev/null @@ -1,789 +0,0 @@ -#!/usr/bin/env python -# -# backend for serial IO for POSIX compatible systems, like Linux, OSX -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2001-2016 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause -# -# parts based on code from Grant B. Edwards : -# ftp://ftp.visi.com/users/grante/python/PosixSerial.py -# -# references: http://www.easysw.com/~mike/serial/serial.html - -# Collection of port names (was previously used by number_to_device which was -# removed. -# - Linux /dev/ttyS%d (confirmed) -# - cygwin/win32 /dev/com%d (confirmed) -# - openbsd (OpenBSD) /dev/cua%02d -# - bsd*, freebsd* /dev/cuad%d -# - darwin (OS X) /dev/cuad%d -# - netbsd /dev/dty%02d (NetBSD 1.6 testing by Erk) -# - irix (IRIX) /dev/ttyf%d (partially tested) names depending on flow control -# - hp (HP-UX) /dev/tty%dp0 (not tested) -# - sunos (Solaris/SunOS) /dev/tty%c (letters, 'a'..'z') (confirmed) -# - aix (AIX) /dev/tty%d - - -# pylint: disable=abstract-method -import errno -import fcntl -import os -import select -import struct -import sys -import termios - -import serial -from serial.serialutil import SerialBase, SerialException, to_bytes, \ - portNotOpenError, writeTimeoutError, Timeout - - -class PlatformSpecificBase(object): - BAUDRATE_CONSTANTS = {} - - def _set_special_baudrate(self, baudrate): - raise NotImplementedError('non-standard baudrates are not supported on this platform') - - def _set_rs485_mode(self, rs485_settings): - raise NotImplementedError('RS485 not supported on this platform') - - -# some systems support an extra flag to enable the two in POSIX unsupported -# paritiy settings for MARK and SPACE -CMSPAR = 0 # default, for unsupported platforms, override below - -# try to detect the OS so that a device can be selected... -# this code block should supply a device() and set_special_baudrate() function -# for the platform -plat = sys.platform.lower() - -if plat[:5] == 'linux': # Linux (confirmed) # noqa - import array - - # extra termios flags - CMSPAR = 0o10000000000 # Use "stick" (mark/space) parity - - # baudrate ioctls - TCGETS2 = 0x802C542A - TCSETS2 = 0x402C542B - BOTHER = 0o010000 - - # RS485 ioctls - TIOCGRS485 = 0x542E - TIOCSRS485 = 0x542F - SER_RS485_ENABLED = 0b00000001 - SER_RS485_RTS_ON_SEND = 0b00000010 - SER_RS485_RTS_AFTER_SEND = 0b00000100 - SER_RS485_RX_DURING_TX = 0b00010000 - - class PlatformSpecific(PlatformSpecificBase): - BAUDRATE_CONSTANTS = { - 0: 0o000000, # hang up - 50: 0o000001, - 75: 0o000002, - 110: 0o000003, - 134: 0o000004, - 150: 0o000005, - 200: 0o000006, - 300: 0o000007, - 600: 0o000010, - 1200: 0o000011, - 1800: 0o000012, - 2400: 0o000013, - 4800: 0o000014, - 9600: 0o000015, - 19200: 0o000016, - 38400: 0o000017, - 57600: 0o010001, - 115200: 0o010002, - 230400: 0o010003, - 460800: 0o010004, - 500000: 0o010005, - 576000: 0o010006, - 921600: 0o010007, - 1000000: 0o010010, - 1152000: 0o010011, - 1500000: 0o010012, - 2000000: 0o010013, - 2500000: 0o010014, - 3000000: 0o010015, - 3500000: 0o010016, - 4000000: 0o010017 - } - - def _set_special_baudrate(self, baudrate): - # right size is 44 on x86_64, allow for some growth - buf = array.array('i', [0] * 64) - try: - # get serial_struct - fcntl.ioctl(self.fd, TCGETS2, buf) - # set custom speed - buf[2] &= ~termios.CBAUD - buf[2] |= BOTHER - buf[9] = buf[10] = baudrate - - # set serial_struct - fcntl.ioctl(self.fd, TCSETS2, buf) - except IOError as e: - raise ValueError('Failed to set custom baud rate ({}): {}'.format(baudrate, e)) - - def _set_rs485_mode(self, rs485_settings): - buf = array.array('i', [0] * 8) # flags, delaytx, delayrx, padding - try: - fcntl.ioctl(self.fd, TIOCGRS485, buf) - buf[0] |= SER_RS485_ENABLED - if rs485_settings is not None: - if rs485_settings.loopback: - buf[0] |= SER_RS485_RX_DURING_TX - else: - buf[0] &= ~SER_RS485_RX_DURING_TX - if rs485_settings.rts_level_for_tx: - buf[0] |= SER_RS485_RTS_ON_SEND - else: - buf[0] &= ~SER_RS485_RTS_ON_SEND - if rs485_settings.rts_level_for_rx: - buf[0] |= SER_RS485_RTS_AFTER_SEND - else: - buf[0] &= ~SER_RS485_RTS_AFTER_SEND - if rs485_settings.delay_before_tx is not None: - buf[1] = int(rs485_settings.delay_before_tx * 1000) - if rs485_settings.delay_before_rx is not None: - buf[2] = int(rs485_settings.delay_before_rx * 1000) - else: - buf[0] = 0 # clear SER_RS485_ENABLED - fcntl.ioctl(self.fd, TIOCSRS485, buf) - except IOError as e: - raise ValueError('Failed to set RS485 mode: {}'.format(e)) - - -elif plat == 'cygwin': # cygwin/win32 (confirmed) - - class PlatformSpecific(PlatformSpecificBase): - BAUDRATE_CONSTANTS = { - 128000: 0x01003, - 256000: 0x01005, - 500000: 0x01007, - 576000: 0x01008, - 921600: 0x01009, - 1000000: 0x0100a, - 1152000: 0x0100b, - 1500000: 0x0100c, - 2000000: 0x0100d, - 2500000: 0x0100e, - 3000000: 0x0100f - } - - -elif plat[:6] == 'darwin': # OS X - import array - IOSSIOSPEED = 0x80045402 # _IOW('T', 2, speed_t) - - class PlatformSpecific(PlatformSpecificBase): - osx_version = os.uname()[2].split('.') - # Tiger or above can support arbitrary serial speeds - if int(osx_version[0]) >= 8: - def _set_special_baudrate(self, baudrate): - # use IOKit-specific call to set up high speeds - buf = array.array('i', [baudrate]) - fcntl.ioctl(self.fd, IOSSIOSPEED, buf, 1) - -elif plat[:3] == 'bsd' or \ - plat[:7] == 'freebsd' or \ - plat[:6] == 'netbsd' or \ - plat[:7] == 'openbsd': - - class ReturnBaudrate(object): - def __getitem__(self, key): - return key - - class PlatformSpecific(PlatformSpecificBase): - # Only tested on FreeBSD: - # The baud rate may be passed in as - # a literal value. - BAUDRATE_CONSTANTS = ReturnBaudrate() - -else: - class PlatformSpecific(PlatformSpecificBase): - pass - - -# load some constants for later use. -# try to use values from termios, use defaults from linux otherwise -TIOCMGET = getattr(termios, 'TIOCMGET', 0x5415) -TIOCMBIS = getattr(termios, 'TIOCMBIS', 0x5416) -TIOCMBIC = getattr(termios, 'TIOCMBIC', 0x5417) -TIOCMSET = getattr(termios, 'TIOCMSET', 0x5418) - -# TIOCM_LE = getattr(termios, 'TIOCM_LE', 0x001) -TIOCM_DTR = getattr(termios, 'TIOCM_DTR', 0x002) -TIOCM_RTS = getattr(termios, 'TIOCM_RTS', 0x004) -# TIOCM_ST = getattr(termios, 'TIOCM_ST', 0x008) -# TIOCM_SR = getattr(termios, 'TIOCM_SR', 0x010) - -TIOCM_CTS = getattr(termios, 'TIOCM_CTS', 0x020) -TIOCM_CAR = getattr(termios, 'TIOCM_CAR', 0x040) -TIOCM_RNG = getattr(termios, 'TIOCM_RNG', 0x080) -TIOCM_DSR = getattr(termios, 'TIOCM_DSR', 0x100) -TIOCM_CD = getattr(termios, 'TIOCM_CD', TIOCM_CAR) -TIOCM_RI = getattr(termios, 'TIOCM_RI', TIOCM_RNG) -# TIOCM_OUT1 = getattr(termios, 'TIOCM_OUT1', 0x2000) -# TIOCM_OUT2 = getattr(termios, 'TIOCM_OUT2', 0x4000) -if hasattr(termios, 'TIOCINQ'): - TIOCINQ = termios.TIOCINQ -else: - TIOCINQ = getattr(termios, 'FIONREAD', 0x541B) -TIOCOUTQ = getattr(termios, 'TIOCOUTQ', 0x5411) - -TIOCM_zero_str = struct.pack('I', 0) -TIOCM_RTS_str = struct.pack('I', TIOCM_RTS) -TIOCM_DTR_str = struct.pack('I', TIOCM_DTR) - -TIOCSBRK = getattr(termios, 'TIOCSBRK', 0x5427) -TIOCCBRK = getattr(termios, 'TIOCCBRK', 0x5428) - - -class Serial(SerialBase, PlatformSpecific): - """\ - Serial port class POSIX implementation. Serial port configuration is - done with termios and fcntl. Runs on Linux and many other Un*x like - systems. - """ - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened.""" - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self.is_open: - raise SerialException("Port is already open.") - self.fd = None - # open - try: - self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK) - except OSError as msg: - self.fd = None - raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg)) - #~ fcntl.fcntl(self.fd, fcntl.F_SETFL, 0) # set blocking - - try: - self._reconfigure_port(force_update=True) - except: - try: - os.close(self.fd) - except: - # ignore any exception when closing the port - # also to keep original exception that happened when setting up - pass - self.fd = None - raise - else: - self.is_open = True - try: - if not self._dsrdtr: - self._update_dtr_state() - if not self._rtscts: - self._update_rts_state() - except IOError as e: - if e.errno in (errno.EINVAL, errno.ENOTTY): - # ignore Invalid argument and Inappropriate ioctl - pass - else: - raise - self.reset_input_buffer() - self.pipe_abort_read_r, self.pipe_abort_read_w = os.pipe() - self.pipe_abort_write_r, self.pipe_abort_write_w = os.pipe() - fcntl.fcntl(self.pipe_abort_read_r, fcntl.F_SETFL, os.O_NONBLOCK) - fcntl.fcntl(self.pipe_abort_write_r, fcntl.F_SETFL, os.O_NONBLOCK) - - def _reconfigure_port(self, force_update=False): - """Set communication parameters on opened port.""" - if self.fd is None: - raise SerialException("Can only operate on a valid file descriptor") - custom_baud = None - - vmin = vtime = 0 # timeout is done via select - if self._inter_byte_timeout is not None: - vmin = 1 - vtime = int(self._inter_byte_timeout * 10) - try: - orig_attr = termios.tcgetattr(self.fd) - iflag, oflag, cflag, lflag, ispeed, ospeed, cc = orig_attr - except termios.error as msg: # if a port is nonexistent but has a /dev file, it'll fail here - raise SerialException("Could not configure port: {}".format(msg)) - # set up raw mode / no echo / binary - cflag |= (termios.CLOCAL | termios.CREAD) - lflag &= ~(termios.ICANON | termios.ECHO | termios.ECHOE | - termios.ECHOK | termios.ECHONL | - termios.ISIG | termios.IEXTEN) # |termios.ECHOPRT - for flag in ('ECHOCTL', 'ECHOKE'): # netbsd workaround for Erk - if hasattr(termios, flag): - lflag &= ~getattr(termios, flag) - - oflag &= ~(termios.OPOST | termios.ONLCR | termios.OCRNL) - iflag &= ~(termios.INLCR | termios.IGNCR | termios.ICRNL | termios.IGNBRK) - if hasattr(termios, 'IUCLC'): - iflag &= ~termios.IUCLC - if hasattr(termios, 'PARMRK'): - iflag &= ~termios.PARMRK - - # setup baud rate - try: - ispeed = ospeed = getattr(termios, 'B{}'.format(self._baudrate)) - except AttributeError: - try: - ispeed = ospeed = self.BAUDRATE_CONSTANTS[self._baudrate] - except KeyError: - #~ raise ValueError('Invalid baud rate: %r' % self._baudrate) - # may need custom baud rate, it isn't in our list. - ispeed = ospeed = getattr(termios, 'B38400') - try: - custom_baud = int(self._baudrate) # store for later - except ValueError: - raise ValueError('Invalid baud rate: {!r}'.format(self._baudrate)) - else: - if custom_baud < 0: - raise ValueError('Invalid baud rate: {!r}'.format(self._baudrate)) - - # setup char len - cflag &= ~termios.CSIZE - if self._bytesize == 8: - cflag |= termios.CS8 - elif self._bytesize == 7: - cflag |= termios.CS7 - elif self._bytesize == 6: - cflag |= termios.CS6 - elif self._bytesize == 5: - cflag |= termios.CS5 - else: - raise ValueError('Invalid char len: {!r}'.format(self._bytesize)) - # setup stop bits - if self._stopbits == serial.STOPBITS_ONE: - cflag &= ~(termios.CSTOPB) - elif self._stopbits == serial.STOPBITS_ONE_POINT_FIVE: - cflag |= (termios.CSTOPB) # XXX same as TWO.. there is no POSIX support for 1.5 - elif self._stopbits == serial.STOPBITS_TWO: - cflag |= (termios.CSTOPB) - else: - raise ValueError('Invalid stop bit specification: {!r}'.format(self._stopbits)) - # setup parity - iflag &= ~(termios.INPCK | termios.ISTRIP) - if self._parity == serial.PARITY_NONE: - cflag &= ~(termios.PARENB | termios.PARODD | CMSPAR) - elif self._parity == serial.PARITY_EVEN: - cflag &= ~(termios.PARODD | CMSPAR) - cflag |= (termios.PARENB) - elif self._parity == serial.PARITY_ODD: - cflag &= ~CMSPAR - cflag |= (termios.PARENB | termios.PARODD) - elif self._parity == serial.PARITY_MARK and CMSPAR: - cflag |= (termios.PARENB | CMSPAR | termios.PARODD) - elif self._parity == serial.PARITY_SPACE and CMSPAR: - cflag |= (termios.PARENB | CMSPAR) - cflag &= ~(termios.PARODD) - else: - raise ValueError('Invalid parity: {!r}'.format(self._parity)) - # setup flow control - # xonxoff - if hasattr(termios, 'IXANY'): - if self._xonxoff: - iflag |= (termios.IXON | termios.IXOFF) # |termios.IXANY) - else: - iflag &= ~(termios.IXON | termios.IXOFF | termios.IXANY) - else: - if self._xonxoff: - iflag |= (termios.IXON | termios.IXOFF) - else: - iflag &= ~(termios.IXON | termios.IXOFF) - # rtscts - if hasattr(termios, 'CRTSCTS'): - if self._rtscts: - cflag |= (termios.CRTSCTS) - else: - cflag &= ~(termios.CRTSCTS) - elif hasattr(termios, 'CNEW_RTSCTS'): # try it with alternate constant name - if self._rtscts: - cflag |= (termios.CNEW_RTSCTS) - else: - cflag &= ~(termios.CNEW_RTSCTS) - # XXX should there be a warning if setting up rtscts (and xonxoff etc) fails?? - - # buffer - # vmin "minimal number of characters to be read. 0 for non blocking" - if vmin < 0 or vmin > 255: - raise ValueError('Invalid vmin: {!r}'.format(vmin)) - cc[termios.VMIN] = vmin - # vtime - if vtime < 0 or vtime > 255: - raise ValueError('Invalid vtime: {!r}'.format(vtime)) - cc[termios.VTIME] = vtime - # activate settings - if force_update or [iflag, oflag, cflag, lflag, ispeed, ospeed, cc] != orig_attr: - termios.tcsetattr( - self.fd, - termios.TCSANOW, - [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]) - - # apply custom baud rate, if any - if custom_baud is not None: - self._set_special_baudrate(custom_baud) - - if self._rs485_mode is not None: - self._set_rs485_mode(self._rs485_mode) - - def close(self): - """Close port""" - if self.is_open: - if self.fd is not None: - os.close(self.fd) - self.fd = None - os.close(self.pipe_abort_read_w) - os.close(self.pipe_abort_read_r) - os.close(self.pipe_abort_write_w) - os.close(self.pipe_abort_write_r) - self.pipe_abort_read_r, self.pipe_abort_read_w = None, None - self.pipe_abort_write_r, self.pipe_abort_write_w = None, None - self.is_open = False - - # - - - - - - - - - - - - - - - - - - - - - - - - - - @property - def in_waiting(self): - """Return the number of bytes currently in the input buffer.""" - #~ s = fcntl.ioctl(self.fd, termios.FIONREAD, TIOCM_zero_str) - s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str) - return struct.unpack('I', s)[0] - - # select based implementation, proved to work on many systems - def read(self, size=1): - """\ - 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 - until the requested number of bytes is read. - """ - if not self.is_open: - raise portNotOpenError - read = bytearray() - timeout = Timeout(self._timeout) - while len(read) < size: - try: - ready, _, _ = select.select([self.fd, self.pipe_abort_read_r], [], [], timeout.time_left()) - if self.pipe_abort_read_r in ready: - os.read(self.pipe_abort_read_r, 1000) - break - # If select was used with a timeout, and the timeout occurs, it - # returns with empty lists -> thus abort read operation. - # For timeout == 0 (non-blocking operation) also abort when - # there is nothing to read. - if not ready: - break # timeout - buf = os.read(self.fd, size - len(read)) - # read should always return some data as select reported it was - # ready to read when we get to this point. - if not buf: - # Disconnected devices, at least on Linux, show the - # behavior that they are always ready to read immediately - # but reading returns nothing. - raise SerialException( - 'device reports readiness to read but returned no data ' - '(device disconnected or multiple access on port?)') - 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: - 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 - # see also http://www.python.org/dev/peps/pep-3151/#select - if e[0] != errno.EAGAIN: - 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") - - def cancel_write(self): - os.write(self.pipe_abort_write_w, b"x") - - def write(self, data): - """Output the given byte string over the serial port.""" - if not self.is_open: - raise portNotOpenError - d = to_bytes(data) - tx_len = len(d) - timeout = Timeout(self._write_timeout) - while tx_len > 0: - try: - n = os.write(self.fd, d) - if timeout.is_non_blocking: - # Zero timeout indicates non-blocking - simply return the - # number of bytes of data actually written - return n - elif not timeout.is_infinite: - # when timeout is set, use select to wait for being ready - # with the time left as timeout - if timeout.expired(): - raise writeTimeoutError - abort, ready, _ = select.select([self.pipe_abort_write_r], [self.fd], [], timeout.time_left()) - if abort: - os.read(self.pipe_abort_write_r, 1000) - break - if not ready: - raise writeTimeoutError - else: - assert timeout.time_left() is None - # wait for write operation - abort, ready, _ = select.select([self.pipe_abort_write_r], [self.fd], [], None) - if abort: - os.read(self.pipe_abort_write_r, 1) - break - if not ready: - raise SerialException('write failed (select)') - d = d[n:] - 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 - return len(data) - - def flush(self): - """\ - Flush of file like objects. In this case, wait until all data - is written. - """ - if not self.is_open: - raise portNotOpenError - termios.tcdrain(self.fd) - - def reset_input_buffer(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self.is_open: - raise portNotOpenError - termios.tcflush(self.fd, termios.TCIFLUSH) - - def reset_output_buffer(self): - """\ - Clear output buffer, aborting the current output and discarding all - that is in the buffer. - """ - if not self.is_open: - raise portNotOpenError - termios.tcflush(self.fd, termios.TCOFLUSH) - - def send_break(self, duration=0.25): - """\ - Send break condition. Timed, returns to idle state after given - duration. - """ - if not self.is_open: - raise portNotOpenError - termios.tcsendbreak(self.fd, int(duration / 0.25)) - - def _update_break_state(self): - """\ - Set break: Controls TXD. When active, no transmitting is possible. - """ - if self._break_state: - fcntl.ioctl(self.fd, TIOCSBRK) - else: - fcntl.ioctl(self.fd, TIOCCBRK) - - def _update_rts_state(self): - """Set terminal status line: Request To Send""" - if self._rts_state: - fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_RTS_str) - else: - fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_RTS_str) - - def _update_dtr_state(self): - """Set terminal status line: Data Terminal Ready""" - if self._dtr_state: - fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_DTR_str) - else: - fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_DTR_str) - - @property - def cts(self): - """Read terminal status line: Clear To Send""" - if not self.is_open: - raise portNotOpenError - s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) - return struct.unpack('I', s)[0] & TIOCM_CTS != 0 - - @property - def dsr(self): - """Read terminal status line: Data Set Ready""" - if not self.is_open: - raise portNotOpenError - s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) - return struct.unpack('I', s)[0] & TIOCM_DSR != 0 - - @property - def ri(self): - """Read terminal status line: Ring Indicator""" - if not self.is_open: - raise portNotOpenError - s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) - return struct.unpack('I', s)[0] & TIOCM_RI != 0 - - @property - def cd(self): - """Read terminal status line: Carrier Detect""" - if not self.is_open: - raise portNotOpenError - s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) - return struct.unpack('I', s)[0] & TIOCM_CD != 0 - - # - - platform specific - - - - - - @property - def out_waiting(self): - """Return the number of bytes currently in the output buffer.""" - #~ s = fcntl.ioctl(self.fd, termios.FIONREAD, TIOCM_zero_str) - s = fcntl.ioctl(self.fd, TIOCOUTQ, TIOCM_zero_str) - return struct.unpack('I', s)[0] - - def fileno(self): - """\ - For easier use of the serial port instance with select. - WARNING: this function is not portable to different platforms! - """ - if not self.is_open: - raise portNotOpenError - return self.fd - - def set_input_flow_control(self, enable=True): - """\ - Manually control flow - when software flow control is enabled. - This will send XON (true) or XOFF (false) to the other device. - WARNING: this function is not portable to different platforms! - """ - if not self.is_open: - raise portNotOpenError - if enable: - termios.tcflow(self.fd, termios.TCION) - else: - termios.tcflow(self.fd, termios.TCIOFF) - - def set_output_flow_control(self, enable=True): - """\ - Manually control flow of outgoing data - when hardware or software flow - control is enabled. - WARNING: this function is not portable to different platforms! - """ - if not self.is_open: - raise portNotOpenError - if enable: - termios.tcflow(self.fd, termios.TCOON) - else: - termios.tcflow(self.fd, termios.TCOOFF) - - def nonblocking(self): - """DEPRECATED - has no use""" - import warnings - warnings.warn("nonblocking() has no effect, already nonblocking", DeprecationWarning) - - -class PosixPollSerial(Serial): - """\ - Poll based read implementation. Not all systems support poll properly. - However this one has better handling of errors, such as a device - disconnecting while it's in use (e.g. USB-serial unplugged). - """ - - def read(self, size=1): - """\ - 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 - until the requested number of bytes is read. - """ - if not self.is_open: - raise portNotOpenError - read = bytearray() - poll = select.poll() - poll.register(self.fd, 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): - 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 - 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: - break # early abort on timeout - return bytes(read) - - -class VTIMESerial(Serial): - """\ - Implement timeout using vtime of tty device instead of using select. - This means that no inter character timeout can be specified and that - the error handling is degraded. - - Overall timeout is disabled when inter-character timeout is used. - """ - - def _reconfigure_port(self, force_update=True): - """Set communication parameters on opened port.""" - super(VTIMESerial, self)._reconfigure_port() - fcntl.fcntl(self.fd, fcntl.F_SETFL, 0) # clear O_NONBLOCK - - if self._inter_byte_timeout is not None: - vmin = 1 - vtime = int(self._inter_byte_timeout * 10) - elif self._timeout is None: - vmin = 1 - vtime = 0 - else: - vmin = 0 - vtime = int(self._timeout * 10) - try: - orig_attr = termios.tcgetattr(self.fd) - iflag, oflag, cflag, lflag, ispeed, ospeed, cc = orig_attr - except termios.error as msg: # if a port is nonexistent but has a /dev file, it'll fail here - raise serial.SerialException("Could not configure port: {}".format(msg)) - - if vtime < 0 or vtime > 255: - raise ValueError('Invalid vtime: {!r}'.format(vtime)) - cc[termios.VTIME] = vtime - cc[termios.VMIN] = vmin - - termios.tcsetattr( - self.fd, - termios.TCSANOW, - [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]) - - def read(self, size=1): - """\ - 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 - until the requested number of bytes is read. - """ - if not self.is_open: - raise portNotOpenError - read = bytearray() - while len(read) < size: - buf = os.read(self.fd, size - len(read)) - if not buf: - break - read.extend(buf) - return bytes(read) - - # hack to make hasattr return false - cancel_read = property() diff --git a/mFIZ/scripts/mFIZ_extern/serial/serialutil.py b/mFIZ/scripts/mFIZ_extern/serial/serialutil.py deleted file mode 100644 index 636a10c..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/serialutil.py +++ /dev/null @@ -1,672 +0,0 @@ -#! python -# -# Base class and support functions used by various backends. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2001-2016 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -import io -import time - -# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)`` -# isn't returning the contents (very unfortunate). Therefore we need special -# cases and test for it. Ensure that there is a ``memoryview`` object for older -# Python versions. This is easier than making every test dependent on its -# existence. -try: - memoryview -except (NameError, AttributeError): - # implementation does not matter as we do not really use it. - # it just must not inherit from something else we might care for. - class memoryview(object): # pylint: disable=redefined-builtin,invalid-name - pass - -try: - unicode -except (NameError, AttributeError): - unicode = str # for Python 3, pylint: disable=redefined-builtin,invalid-name - -try: - basestring -except (NameError, AttributeError): - basestring = (str,) # for Python 3, pylint: disable=redefined-builtin,invalid-name - - -# "for byte in data" fails for python3 as it returns ints instead of bytes -def iterbytes(b): - """Iterate over bytes, returning bytes instead of ints (python3)""" - if isinstance(b, memoryview): - b = b.tobytes() - i = 0 - while True: - a = b[i:i + 1] - i += 1 - if a: - yield a - else: - break - - -# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11' -# so a simple ``bytes(sequence)`` doesn't work for all versions -def to_bytes(seq): - """convert a sequence to a bytes type""" - if isinstance(seq, bytes): - return seq - elif isinstance(seq, bytearray): - return bytes(seq) - elif isinstance(seq, memoryview): - return seq.tobytes() - elif isinstance(seq, unicode): - raise TypeError('unicode strings are not supported, please encode to bytes: {!r}'.format(seq)) - else: - # handle list of integers and bytes (one or more items) for Python 2 and 3 - return bytes(bytearray(seq)) - - -# create control bytes -XON = to_bytes([17]) -XOFF = to_bytes([19]) - -CR = to_bytes([13]) -LF = to_bytes([10]) - - -PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S' -STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2) -FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8) - -PARITY_NAMES = { - PARITY_NONE: 'None', - PARITY_EVEN: 'Even', - PARITY_ODD: 'Odd', - PARITY_MARK: 'Mark', - PARITY_SPACE: 'Space', -} - - -class SerialException(IOError): - """Base class for serial port related exceptions.""" - - -class SerialTimeoutException(SerialException): - """Write timeouts give an exception""" - - -writeTimeoutError = SerialTimeoutException('Write timeout') -portNotOpenError = SerialException('Attempting to use a port that is not open') - - -class Timeout(object): - """\ - Abstraction for timeout operations. Using time.monotonic() if available - or time.time() in all other cases. - - The class can also be initialized with 0 or None, in order to support - non-blocking and fully blocking I/O operations. The attributes - is_non_blocking and is_infinite are set accordingly. - """ - if hasattr(time, 'monotonic'): - # Timeout implementation with time.monotonic(). This function is only - # supported by Python 3.3 and above. It returns a time in seconds - # (float) just as time.time(), but is not affected by system clock - # adjustments. - TIME = time.monotonic - else: - # Timeout implementation with time.time(). This is compatible with all - # Python versions but has issues if the clock is adjusted while the - # timeout is running. - TIME = time.time - - def __init__(self, duration): - """Initialize a timeout with given duration""" - self.is_infinite = (duration is None) - self.is_non_blocking = (duration == 0) - self.duration = duration - if duration is not None: - self.target_time = self.TIME() + duration - else: - self.target_time = None - - def expired(self): - """Return a boolean, telling if the timeout has expired""" - return self.target_time is not None and self.time_left() <= 0 - - def time_left(self): - """Return how many seconds are left until the timeout expires""" - if self.is_non_blocking: - return 0 - elif self.is_infinite: - return None - else: - delta = self.target_time - self.TIME() - if delta > self.duration: - # clock jumped, recalculate - self.target_time = self.TIME() + self.duration - return self.duration - else: - return max(0, delta) - - def restart(self, duration): - """\ - Restart a timeout, only supported if a timeout was already set up - before. - """ - self.duration = duration - self.target_time = self.TIME() + duration - - -class SerialBase(io.RawIOBase): - """\ - Serial port base class. Provides __init__ function and properties to - get/set port settings. - """ - - # default values, may be overridden in subclasses that do not support all values - BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, - 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, - 3000000, 3500000, 4000000) - BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS) - PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE) - STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO) - - def __init__(self, - port=None, - baudrate=9600, - bytesize=EIGHTBITS, - parity=PARITY_NONE, - stopbits=STOPBITS_ONE, - timeout=None, - xonxoff=False, - rtscts=False, - write_timeout=None, - dsrdtr=False, - inter_byte_timeout=None, - **kwargs): - """\ - Initialize comm port object. If a "port" is given, then the port will be - opened immediately. Otherwise a Serial port object in closed state - is returned. - """ - - self.is_open = False - self.portstr = None - self.name = None - # correct values are assigned below through properties - self._port = None - self._baudrate = None - self._bytesize = None - self._parity = None - self._stopbits = None - self._timeout = None - self._write_timeout = None - self._xonxoff = None - self._rtscts = None - self._dsrdtr = None - self._inter_byte_timeout = None - self._rs485_mode = None # disabled by default - self._rts_state = True - self._dtr_state = True - self._break_state = False - - # assign values using get/set methods using the properties feature - self.port = port - self.baudrate = baudrate - self.bytesize = bytesize - self.parity = parity - self.stopbits = stopbits - self.timeout = timeout - self.write_timeout = write_timeout - self.xonxoff = xonxoff - self.rtscts = rtscts - self.dsrdtr = dsrdtr - self.inter_byte_timeout = inter_byte_timeout - # watch for backward compatible kwargs - if 'writeTimeout' in kwargs: - self.write_timeout = kwargs.pop('writeTimeout') - if 'interCharTimeout' in kwargs: - self.inter_byte_timeout = kwargs.pop('interCharTimeout') - if kwargs: - raise ValueError('unexpected keyword arguments: {!r}'.format(kwargs)) - - if port is not None: - self.open() - - # - - - - - - - - - - - - - - - - - - - - - - - - - - # to be implemented by subclasses: - # def open(self): - # def close(self): - - # - - - - - - - - - - - - - - - - - - - - - - - - - - @property - def port(self): - """\ - Get the current port setting. The value that was passed on init or using - setPort() is passed back. - """ - return self._port - - @port.setter - def port(self, port): - """\ - Change the port. - """ - if port is not None and not isinstance(port, basestring): - raise ValueError('"port" must be None or a string, not {}'.format(type(port))) - was_open = self.is_open - if was_open: - self.close() - self.portstr = port - self._port = port - self.name = self.portstr - if was_open: - self.open() - - @property - def baudrate(self): - """Get the current baud rate setting.""" - return self._baudrate - - @baudrate.setter - def baudrate(self, baudrate): - """\ - Change baud rate. It raises a ValueError if the port is open and the - baud rate is not possible. If the port is closed, then the value is - accepted and the exception is raised when the port is opened. - """ - try: - b = int(baudrate) - except TypeError: - raise ValueError("Not a valid baudrate: {!r}".format(baudrate)) - else: - if b < 0: - raise ValueError("Not a valid baudrate: {!r}".format(baudrate)) - self._baudrate = b - if self.is_open: - self._reconfigure_port() - - @property - def bytesize(self): - """Get the current byte size setting.""" - return self._bytesize - - @bytesize.setter - def bytesize(self, bytesize): - """Change byte size.""" - if bytesize not in self.BYTESIZES: - raise ValueError("Not a valid byte size: {!r}".format(bytesize)) - self._bytesize = bytesize - if self.is_open: - self._reconfigure_port() - - @property - def parity(self): - """Get the current parity setting.""" - return self._parity - - @parity.setter - def parity(self, parity): - """Change parity setting.""" - if parity not in self.PARITIES: - raise ValueError("Not a valid parity: {!r}".format(parity)) - self._parity = parity - if self.is_open: - self._reconfigure_port() - - @property - def stopbits(self): - """Get the current stop bits setting.""" - return self._stopbits - - @stopbits.setter - def stopbits(self, stopbits): - """Change stop bits size.""" - if stopbits not in self.STOPBITS: - raise ValueError("Not a valid stop bit size: {!r}".format(stopbits)) - self._stopbits = stopbits - if self.is_open: - self._reconfigure_port() - - @property - def timeout(self): - """Get the current timeout setting.""" - return self._timeout - - @timeout.setter - def timeout(self, timeout): - """Change timeout setting.""" - if timeout is not None: - try: - timeout + 1 # test if it's a number, will throw a TypeError if not... - except TypeError: - raise ValueError("Not a valid timeout: {!r}".format(timeout)) - if timeout < 0: - raise ValueError("Not a valid timeout: {!r}".format(timeout)) - self._timeout = timeout - if self.is_open: - self._reconfigure_port() - - @property - def write_timeout(self): - """Get the current timeout setting.""" - return self._write_timeout - - @write_timeout.setter - def write_timeout(self, timeout): - """Change timeout setting.""" - if timeout is not None: - if timeout < 0: - raise ValueError("Not a valid timeout: {!r}".format(timeout)) - try: - timeout + 1 # test if it's a number, will throw a TypeError if not... - except TypeError: - raise ValueError("Not a valid timeout: {!r}".format(timeout)) - - self._write_timeout = timeout - if self.is_open: - self._reconfigure_port() - - @property - def inter_byte_timeout(self): - """Get the current inter-character timeout setting.""" - return self._inter_byte_timeout - - @inter_byte_timeout.setter - def inter_byte_timeout(self, ic_timeout): - """Change inter-byte timeout setting.""" - if ic_timeout is not None: - if ic_timeout < 0: - raise ValueError("Not a valid timeout: {!r}".format(ic_timeout)) - try: - ic_timeout + 1 # test if it's a number, will throw a TypeError if not... - except TypeError: - raise ValueError("Not a valid timeout: {!r}".format(ic_timeout)) - - self._inter_byte_timeout = ic_timeout - if self.is_open: - self._reconfigure_port() - - @property - def xonxoff(self): - """Get the current XON/XOFF setting.""" - return self._xonxoff - - @xonxoff.setter - def xonxoff(self, xonxoff): - """Change XON/XOFF setting.""" - self._xonxoff = xonxoff - if self.is_open: - self._reconfigure_port() - - @property - def rtscts(self): - """Get the current RTS/CTS flow control setting.""" - return self._rtscts - - @rtscts.setter - def rtscts(self, rtscts): - """Change RTS/CTS flow control setting.""" - self._rtscts = rtscts - if self.is_open: - self._reconfigure_port() - - @property - def dsrdtr(self): - """Get the current DSR/DTR flow control setting.""" - return self._dsrdtr - - @dsrdtr.setter - def dsrdtr(self, dsrdtr=None): - """Change DsrDtr flow control setting.""" - if dsrdtr is None: - # if not set, keep backwards compatibility and follow rtscts setting - self._dsrdtr = self._rtscts - else: - # if defined independently, follow its value - self._dsrdtr = dsrdtr - if self.is_open: - self._reconfigure_port() - - @property - def rts(self): - return self._rts_state - - @rts.setter - def rts(self, value): - self._rts_state = value - if self.is_open: - self._update_rts_state() - - @property - def dtr(self): - return self._dtr_state - - @dtr.setter - def dtr(self, value): - self._dtr_state = value - if self.is_open: - self._update_dtr_state() - - @property - def break_condition(self): - return self._break_state - - @break_condition.setter - def break_condition(self, value): - self._break_state = value - if self.is_open: - self._update_break_state() - - # - - - - - - - - - - - - - - - - - - - - - - - - - # functions useful for RS-485 adapters - - @property - def rs485_mode(self): - """\ - Enable RS485 mode and apply new settings, set to None to disable. - See serial.rs485.RS485Settings for more info about the value. - """ - return self._rs485_mode - - @rs485_mode.setter - def rs485_mode(self, rs485_settings): - self._rs485_mode = rs485_settings - if self.is_open: - self._reconfigure_port() - - # - - - - - - - - - - - - - - - - - - - - - - - - - - _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff', - 'dsrdtr', 'rtscts', 'timeout', 'write_timeout', - 'inter_byte_timeout') - - def get_settings(self): - """\ - Get current port settings as a dictionary. For use with - apply_settings(). - """ - return dict([(key, getattr(self, '_' + key)) for key in self._SAVED_SETTINGS]) - - def apply_settings(self, d): - """\ - Apply stored settings from a dictionary returned from - get_settings(). It's allowed to delete keys from the dictionary. These - values will simply left unchanged. - """ - for key in self._SAVED_SETTINGS: - if key in d and d[key] != getattr(self, '_' + key): # check against internal "_" value - setattr(self, key, d[key]) # set non "_" value to use properties write function - - # - - - - - - - - - - - - - - - - - - - - - - - - - - def __repr__(self): - """String representation of the current port settings and its state.""" - return '{name}(port={p.portstr!r}, ' \ - 'baudrate={p.baudrate!r}, bytesize={p.bytesize!r}, parity={p.parity!r}, ' \ - 'stopbits={p.stopbits!r}, timeout={p.timeout!r}, xonxoff={p.xonxoff!r}, ' \ - 'rtscts={p.rtscts!r}, dsrdtr={p.dsrdtr!r})'.format( - name=self.__class__.__name__, id=id(self), p=self) - - # - - - - - - - - - - - - - - - - - - - - - - - - - # compatibility with io library - # pylint: disable=invalid-name,missing-docstring - - def readable(self): - return True - - def writable(self): - return True - - def seekable(self): - return False - - def readinto(self, b): - data = self.read(len(b)) - n = len(data) - try: - b[:n] = data - except TypeError as err: - import array - if not isinstance(b, array.array): - raise err - b[:n] = array.array('b', data) - return n - - # - - - - - - - - - - - - - - - - - - - - - - - - - # context manager - - def __enter__(self): - return self - - def __exit__(self, *args, **kwargs): - self.close() - - # - - - - - - - - - - - - - - - - - - - - - - - - - - def send_break(self, duration=0.25): - """\ - Send break condition. Timed, returns to idle state after given - duration. - """ - if not self.is_open: - raise portNotOpenError - self.break_condition = True - time.sleep(duration) - self.break_condition = False - - # - - - - - - - - - - - - - - - - - - - - - - - - - # backwards compatibility / deprecated functions - - def flushInput(self): - self.reset_input_buffer() - - def flushOutput(self): - self.reset_output_buffer() - - def inWaiting(self): - return self.in_waiting - - def sendBreak(self, duration=0.25): - self.send_break(duration) - - def setRTS(self, value=1): - self.rts = value - - def setDTR(self, value=1): - self.dtr = value - - def getCTS(self): - return self.cts - - def getDSR(self): - return self.dsr - - def getRI(self): - return self.ri - - def getCD(self): - return self.cd - - def setPort(self, port): - self.port = port - - @property - def writeTimeout(self): - return self.write_timeout - - @writeTimeout.setter - def writeTimeout(self, timeout): - self.write_timeout = timeout - - @property - def interCharTimeout(self): - return self.inter_byte_timeout - - @interCharTimeout.setter - def interCharTimeout(self, interCharTimeout): - self.inter_byte_timeout = interCharTimeout - - def getSettingsDict(self): - return self.get_settings() - - def applySettingsDict(self, d): - self.apply_settings(d) - - def isOpen(self): - return self.is_open - - # - - - - - - - - - - - - - - - - - - - - - - - - - # additional functionality - - def read_all(self): - """\ - Read all bytes currently available in the buffer of the OS. - """ - return self.read(self.in_waiting) - - def read_until(self, terminator=LF, size=None): - """\ - Read until a termination sequence is found ('\n' by default), the size - is exceeded or until timeout occurs. - """ - lenterm = len(terminator) - line = bytearray() - while True: - c = self.read(1) - if c: - line += c - if line[-lenterm:] == terminator: - break - if size is not None and len(line) >= size: - break - else: - break - return bytes(line) - - def iread_until(self, *args, **kwargs): - """\ - Read lines, implemented as generator. It will raise StopIteration on - timeout (empty read). - """ - while True: - line = self.read_until(*args, **kwargs) - if not line: - break - yield line - - -# - - - - - - - - - - - - - - - - - - - - - - - - - -if __name__ == '__main__': - import sys - s = SerialBase() - sys.stdout.write('port name: {}\n'.format(s.name)) - sys.stdout.write('baud rates: {}\n'.format(s.BAUDRATES)) - sys.stdout.write('byte sizes: {}\n'.format(s.BYTESIZES)) - sys.stdout.write('parities: {}\n'.format(s.PARITIES)) - sys.stdout.write('stop bits: {}\n'.format(s.STOPBITS)) - sys.stdout.write('{}\n'.format(s)) diff --git a/mFIZ/scripts/mFIZ_extern/serial/serialwin32.py b/mFIZ/scripts/mFIZ_extern/serial/serialwin32.py deleted file mode 100644 index b275ea3..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/serialwin32.py +++ /dev/null @@ -1,467 +0,0 @@ -#! python -# -# backend for Windows ("win32" incl. 32/64 bit support) -# -# (C) 2001-2015 Chris Liechti -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# SPDX-License-Identifier: BSD-3-Clause -# -# Initial patch to use ctypes by Giovanni Bajo - -# pylint: disable=invalid-name,too-few-public-methods -import ctypes -import time -from serial import win32 - -import serial -from serial.serialutil import SerialBase, SerialException, to_bytes, portNotOpenError, writeTimeoutError - - -class Serial(SerialBase): - """Serial port implementation for Win32 based on ctypes.""" - - BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200) - - def __init__(self, *args, **kwargs): - self._port_handle = None - self._overlapped_read = None - self._overlapped_write = None - super(Serial, self).__init__(*args, **kwargs) - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened. - """ - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self.is_open: - raise SerialException("Port is already open.") - # the "\\.\COMx" format is required for devices other than COM1-COM8 - # not all versions of windows seem to support this properly - # so that the first few ports are used with the DOS device name - port = self.name - try: - if port.upper().startswith('COM') and int(port[3:]) > 8: - port = '\\\\.\\' + port - except ValueError: - # for like COMnotanumber - pass - self._port_handle = win32.CreateFile( - port, - win32.GENERIC_READ | win32.GENERIC_WRITE, - 0, # exclusive access - None, # no security - win32.OPEN_EXISTING, - win32.FILE_ATTRIBUTE_NORMAL | win32.FILE_FLAG_OVERLAPPED, - 0) - if self._port_handle == win32.INVALID_HANDLE_VALUE: - self._port_handle = None # 'cause __del__ is called anyway - raise SerialException("could not open port {!r}: {!r}".format(self.portstr, ctypes.WinError())) - - try: - self._overlapped_read = win32.OVERLAPPED() - self._overlapped_read.hEvent = win32.CreateEvent(None, 1, 0, None) - self._overlapped_write = win32.OVERLAPPED() - #~ self._overlapped_write.hEvent = win32.CreateEvent(None, 1, 0, None) - self._overlapped_write.hEvent = win32.CreateEvent(None, 0, 0, None) - - # Setup a 4k buffer - win32.SetupComm(self._port_handle, 4096, 4096) - - # Save original timeout values: - self._orgTimeouts = win32.COMMTIMEOUTS() - win32.GetCommTimeouts(self._port_handle, ctypes.byref(self._orgTimeouts)) - - self._reconfigure_port() - - # Clear buffers: - # Remove anything that was there - win32.PurgeComm( - self._port_handle, - win32.PURGE_TXCLEAR | win32.PURGE_TXABORT | - win32.PURGE_RXCLEAR | win32.PURGE_RXABORT) - except: - try: - self._close() - except: - # ignore any exception when closing the port - # also to keep original exception that happened when setting up - pass - self._port_handle = None - raise - else: - self.is_open = True - - def _reconfigure_port(self): - """Set communication parameters on opened port.""" - if not self._port_handle: - raise SerialException("Can only operate on a valid port handle") - - # Set Windows timeout values - # timeouts is a tuple with the following items: - # (ReadIntervalTimeout,ReadTotalTimeoutMultiplier, - # ReadTotalTimeoutConstant,WriteTotalTimeoutMultiplier, - # WriteTotalTimeoutConstant) - timeouts = win32.COMMTIMEOUTS() - if self._timeout is None: - pass # default of all zeros is OK - elif self._timeout == 0: - timeouts.ReadIntervalTimeout = win32.MAXDWORD - else: - timeouts.ReadTotalTimeoutConstant = max(int(self._timeout * 1000), 1) - if self._timeout != 0 and self._inter_byte_timeout is not None: - timeouts.ReadIntervalTimeout = max(int(self._inter_byte_timeout * 1000), 1) - - if self._write_timeout is None: - pass - elif self._write_timeout == 0: - timeouts.WriteTotalTimeoutConstant = win32.MAXDWORD - else: - timeouts.WriteTotalTimeoutConstant = max(int(self._write_timeout * 1000), 1) - win32.SetCommTimeouts(self._port_handle, ctypes.byref(timeouts)) - - win32.SetCommMask(self._port_handle, win32.EV_ERR) - - # Setup the connection info. - # Get state and modify it: - comDCB = win32.DCB() - win32.GetCommState(self._port_handle, ctypes.byref(comDCB)) - comDCB.BaudRate = self._baudrate - - if self._bytesize == serial.FIVEBITS: - comDCB.ByteSize = 5 - elif self._bytesize == serial.SIXBITS: - comDCB.ByteSize = 6 - elif self._bytesize == serial.SEVENBITS: - comDCB.ByteSize = 7 - elif self._bytesize == serial.EIGHTBITS: - comDCB.ByteSize = 8 - else: - raise ValueError("Unsupported number of data bits: {!r}".format(self._bytesize)) - - if self._parity == serial.PARITY_NONE: - comDCB.Parity = win32.NOPARITY - comDCB.fParity = 0 # Disable Parity Check - elif self._parity == serial.PARITY_EVEN: - comDCB.Parity = win32.EVENPARITY - comDCB.fParity = 1 # Enable Parity Check - elif self._parity == serial.PARITY_ODD: - comDCB.Parity = win32.ODDPARITY - comDCB.fParity = 1 # Enable Parity Check - elif self._parity == serial.PARITY_MARK: - comDCB.Parity = win32.MARKPARITY - comDCB.fParity = 1 # Enable Parity Check - elif self._parity == serial.PARITY_SPACE: - comDCB.Parity = win32.SPACEPARITY - comDCB.fParity = 1 # Enable Parity Check - else: - raise ValueError("Unsupported parity mode: {!r}".format(self._parity)) - - if self._stopbits == serial.STOPBITS_ONE: - comDCB.StopBits = win32.ONESTOPBIT - elif self._stopbits == serial.STOPBITS_ONE_POINT_FIVE: - comDCB.StopBits = win32.ONE5STOPBITS - elif self._stopbits == serial.STOPBITS_TWO: - comDCB.StopBits = win32.TWOSTOPBITS - else: - raise ValueError("Unsupported number of stop bits: {!r}".format(self._stopbits)) - - comDCB.fBinary = 1 # Enable Binary Transmission - # Char. w/ Parity-Err are replaced with 0xff (if fErrorChar is set to TRUE) - if self._rs485_mode is None: - if self._rtscts: - comDCB.fRtsControl = win32.RTS_CONTROL_HANDSHAKE - else: - comDCB.fRtsControl = win32.RTS_CONTROL_ENABLE if self._rts_state else win32.RTS_CONTROL_DISABLE - comDCB.fOutxCtsFlow = self._rtscts - else: - # checks for unsupported settings - # XXX verify if platform really does not have a setting for those - if not self._rs485_mode.rts_level_for_tx: - raise ValueError( - 'Unsupported value for RS485Settings.rts_level_for_tx: {!r}'.format( - self._rs485_mode.rts_level_for_tx,)) - if self._rs485_mode.rts_level_for_rx: - raise ValueError( - 'Unsupported value for RS485Settings.rts_level_for_rx: {!r}'.format( - self._rs485_mode.rts_level_for_rx,)) - if self._rs485_mode.delay_before_tx is not None: - raise ValueError( - 'Unsupported value for RS485Settings.delay_before_tx: {!r}'.format( - self._rs485_mode.delay_before_tx,)) - if self._rs485_mode.delay_before_rx is not None: - raise ValueError( - 'Unsupported value for RS485Settings.delay_before_rx: {!r}'.format( - self._rs485_mode.delay_before_rx,)) - if self._rs485_mode.loopback: - raise ValueError( - 'Unsupported value for RS485Settings.loopback: {!r}'.format( - self._rs485_mode.loopback,)) - comDCB.fRtsControl = win32.RTS_CONTROL_TOGGLE - comDCB.fOutxCtsFlow = 0 - - if self._dsrdtr: - comDCB.fDtrControl = win32.DTR_CONTROL_HANDSHAKE - else: - comDCB.fDtrControl = win32.DTR_CONTROL_ENABLE if self._dtr_state else win32.DTR_CONTROL_DISABLE - comDCB.fOutxDsrFlow = self._dsrdtr - comDCB.fOutX = self._xonxoff - comDCB.fInX = self._xonxoff - comDCB.fNull = 0 - comDCB.fErrorChar = 0 - comDCB.fAbortOnError = 0 - comDCB.XonChar = serial.XON - comDCB.XoffChar = serial.XOFF - - if not win32.SetCommState(self._port_handle, ctypes.byref(comDCB)): - raise SerialException( - 'Cannot configure port, something went wrong. ' - 'Original message: {!r}'.format(ctypes.WinError())) - - #~ def __del__(self): - #~ self.close() - - def _close(self): - """internal close port helper""" - if self._port_handle is not None: - # Restore original timeout values: - win32.SetCommTimeouts(self._port_handle, self._orgTimeouts) - if self._overlapped_read is not None: - self.cancel_read() - win32.CloseHandle(self._overlapped_read.hEvent) - self._overlapped_read = None - if self._overlapped_write is not None: - self.cancel_write() - win32.CloseHandle(self._overlapped_write.hEvent) - self._overlapped_write = None - win32.CloseHandle(self._port_handle) - self._port_handle = None - - def close(self): - """Close port""" - if self.is_open: - self._close() - self.is_open = False - - # - - - - - - - - - - - - - - - - - - - - - - - - - - @property - def in_waiting(self): - """Return the number of bytes currently in the input buffer.""" - flags = win32.DWORD() - comstat = win32.COMSTAT() - if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)): - raise SerialException('call to ClearCommError failed') - return comstat.cbInQue - - def read(self, size=1): - """\ - 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 - until the requested number of bytes is read. - """ - if not self.is_open: - raise portNotOpenError - if size > 0: - win32.ResetEvent(self._overlapped_read.hEvent) - flags = win32.DWORD() - comstat = win32.COMSTAT() - if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)): - raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError())) - n = min(comstat.cbInQue, size) if self.timeout == 0 else size - if n > 0: - buf = ctypes.create_string_buffer(n) - rc = win32.DWORD() - read_ok = win32.ReadFile( - self._port_handle, - buf, - n, - ctypes.byref(rc), - ctypes.byref(self._overlapped_read)) - if not read_ok and win32.GetLastError() not in (win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING): - raise SerialException("ReadFile failed ({!r})".format(ctypes.WinError())) - result_ok = win32.GetOverlappedResult( - self._port_handle, - ctypes.byref(self._overlapped_read), - ctypes.byref(rc), - True) - if not result_ok: - if win32.GetLastError() != win32.ERROR_OPERATION_ABORTED: - raise SerialException("GetOverlappedResult failed ({!r})".format(ctypes.WinError())) - read = buf.raw[:rc.value] - else: - read = bytes() - else: - read = bytes() - return bytes(read) - - def write(self, data): - """Output the given byte string over the serial port.""" - if not self.is_open: - raise portNotOpenError - #~ if not isinstance(data, (bytes, bytearray)): - #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data))) - # convert data (needed in case of memoryview instance: Py 3.1 io lib), ctypes doesn't like memoryview - data = to_bytes(data) - if data: - #~ win32event.ResetEvent(self._overlapped_write.hEvent) - n = win32.DWORD() - success = win32.WriteFile(self._port_handle, data, len(data), ctypes.byref(n), self._overlapped_write) - if self._write_timeout != 0: # if blocking (None) or w/ write timeout (>0) - if not success and win32.GetLastError() != win32.ERROR_IO_PENDING: - raise SerialException("WriteFile failed ({!r})".format(ctypes.WinError())) - - # Wait for the write to complete. - #~ win32.WaitForSingleObject(self._overlapped_write.hEvent, win32.INFINITE) - win32.GetOverlappedResult(self._port_handle, self._overlapped_write, ctypes.byref(n), True) - if win32.GetLastError() == win32.ERROR_OPERATION_ABORTED: - return n.value # canceled IO is no error - if n.value != len(data): - raise writeTimeoutError - return n.value - else: - errorcode = win32.ERROR_SUCCESS if success else win32.GetLastError() - if errorcode in (win32.ERROR_INVALID_USER_BUFFER, win32.ERROR_NOT_ENOUGH_MEMORY, - win32.ERROR_OPERATION_ABORTED): - return 0 - elif errorcode in (win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING): - # no info on true length provided by OS function in async mode - return len(data) - else: - raise SerialException("WriteFile failed ({!r})".format(ctypes.WinError())) - else: - return 0 - - def flush(self): - """\ - Flush of file like objects. In this case, wait until all data - is written. - """ - while self.out_waiting: - time.sleep(0.05) - # XXX could also use WaitCommEvent with mask EV_TXEMPTY, but it would - # require overlapped IO and it's also only possible to set a single mask - # on the port--- - - def reset_input_buffer(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self.is_open: - raise portNotOpenError - win32.PurgeComm(self._port_handle, win32.PURGE_RXCLEAR | win32.PURGE_RXABORT) - - def reset_output_buffer(self): - """\ - Clear output buffer, aborting the current output and discarding all - that is in the buffer. - """ - if not self.is_open: - raise portNotOpenError - win32.PurgeComm(self._port_handle, win32.PURGE_TXCLEAR | win32.PURGE_TXABORT) - - def _update_break_state(self): - """Set break: Controls TXD. When active, to transmitting is possible.""" - if not self.is_open: - raise portNotOpenError - if self._break_state: - win32.SetCommBreak(self._port_handle) - else: - win32.ClearCommBreak(self._port_handle) - - def _update_rts_state(self): - """Set terminal status line: Request To Send""" - if self._rts_state: - win32.EscapeCommFunction(self._port_handle, win32.SETRTS) - else: - win32.EscapeCommFunction(self._port_handle, win32.CLRRTS) - - def _update_dtr_state(self): - """Set terminal status line: Data Terminal Ready""" - if self._dtr_state: - win32.EscapeCommFunction(self._port_handle, win32.SETDTR) - else: - win32.EscapeCommFunction(self._port_handle, win32.CLRDTR) - - def _GetCommModemStatus(self): - if not self.is_open: - raise portNotOpenError - stat = win32.DWORD() - win32.GetCommModemStatus(self._port_handle, ctypes.byref(stat)) - return stat.value - - @property - def cts(self): - """Read terminal status line: Clear To Send""" - return win32.MS_CTS_ON & self._GetCommModemStatus() != 0 - - @property - def dsr(self): - """Read terminal status line: Data Set Ready""" - return win32.MS_DSR_ON & self._GetCommModemStatus() != 0 - - @property - def ri(self): - """Read terminal status line: Ring Indicator""" - return win32.MS_RING_ON & self._GetCommModemStatus() != 0 - - @property - def cd(self): - """Read terminal status line: Carrier Detect""" - return win32.MS_RLSD_ON & self._GetCommModemStatus() != 0 - - # - - platform specific - - - - - - def set_buffer_size(self, rx_size=4096, tx_size=None): - """\ - Recommend a buffer size to the driver (device driver can ignore this - value). Must be called before the port is opened. - """ - if tx_size is None: - tx_size = rx_size - win32.SetupComm(self._port_handle, rx_size, tx_size) - - def set_output_flow_control(self, enable=True): - """\ - Manually control flow - when software flow control is enabled. - This will do the same as if XON (true) or XOFF (false) are received - from the other device and control the transmission accordingly. - WARNING: this function is not portable to different platforms! - """ - if not self.is_open: - raise portNotOpenError - if enable: - win32.EscapeCommFunction(self._port_handle, win32.SETXON) - else: - win32.EscapeCommFunction(self._port_handle, win32.SETXOFF) - - @property - def out_waiting(self): - """Return how many bytes the in the outgoing buffer""" - flags = win32.DWORD() - comstat = win32.COMSTAT() - if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)): - raise SerialException('call to ClearCommError failed') - return comstat.cbOutQue - - def _cancel_overlapped_io(self, overlapped): - """Cancel a blocking read operation, may be called from other thread""" - # check if read operation is pending - rc = win32.DWORD() - err = win32.GetOverlappedResult( - self._port_handle, - ctypes.byref(overlapped), - ctypes.byref(rc), - False) - if not err and win32.GetLastError() in (win32.ERROR_IO_PENDING, win32.ERROR_IO_INCOMPLETE): - # cancel, ignoring any errors (e.g. it may just have finished on its own) - win32.CancelIoEx(self._port_handle, overlapped) - - def cancel_read(self): - """Cancel a blocking read operation, may be called from other thread""" - self._cancel_overlapped_io(self._overlapped_read) - - def cancel_write(self): - """Cancel a blocking write operation, may be called from other thread""" - self._cancel_overlapped_io(self._overlapped_write) diff --git a/mFIZ/scripts/mFIZ_extern/serial/threaded/__init__.py b/mFIZ/scripts/mFIZ_extern/serial/threaded/__init__.py deleted file mode 100644 index 74b6924..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/threaded/__init__.py +++ /dev/null @@ -1,295 +0,0 @@ -#!/usr/bin/env python3 -# -# Working with threading and pySerial -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2015-2016 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause -"""\ -Support threading with serial ports. -""" -import serial -import threading - - -class Protocol(object): - """\ - Protocol as used by the ReaderThread. This base class provides empty - implementations of all methods. - """ - - def connection_made(self, transport): - """Called when reader thread is started""" - - def data_received(self, data): - """Called with snippets received from the serial port""" - - def connection_lost(self, exc): - """\ - Called when the serial port is closed or the reader loop terminated - otherwise. - """ - if isinstance(exc, Exception): - raise exc - - -class Packetizer(Protocol): - """ - Read binary packets from serial port. Packets are expected to be terminated - with a TERMINATOR byte (null byte by default). - - The class also keeps track of the transport. - """ - - TERMINATOR = b'\0' - - def __init__(self): - self.buffer = bytearray() - self.transport = None - - def connection_made(self, transport): - """Store transport""" - self.transport = transport - - def connection_lost(self, exc): - """Forget transport""" - self.transport = None - super(Packetizer, self).connection_lost(exc) - - def data_received(self, data): - """Buffer received data, find TERMINATOR, call handle_packet""" - self.buffer.extend(data) - while self.TERMINATOR in self.buffer: - packet, self.buffer = self.buffer.split(self.TERMINATOR, 1) - self.handle_packet(packet) - - def handle_packet(self, packet): - """Process packets - to be overridden by subclassing""" - raise NotImplementedError('please implement functionality in handle_packet') - - -class FramedPacket(Protocol): - """ - Read binary packets. Packets are expected to have a start and stop marker. - - The class also keeps track of the transport. - """ - - START = b'(' - STOP = b')' - - def __init__(self): - self.packet = bytearray() - self.in_packet = False - self.transport = None - - def connection_made(self, transport): - """Store transport""" - self.transport = transport - - def connection_lost(self, exc): - """Forget transport""" - self.transport = None - self.in_packet = False - del self.packet[:] - super(FramedPacket, self).connection_lost(exc) - - def data_received(self, data): - """Find data enclosed in START/STOP, call handle_packet""" - for byte in serial.iterbytes(data): - if byte == self.START: - self.in_packet = True - elif byte == self.STOP: - self.in_packet = False - self.handle_packet(bytes(self.packet)) # make read-only copy - del self.packet[:] - elif self.in_packet: - self.packet.extend(byte) - else: - self.handle_out_of_packet_data(byte) - - def handle_packet(self, packet): - """Process packets - to be overridden by subclassing""" - raise NotImplementedError('please implement functionality in handle_packet') - - def handle_out_of_packet_data(self, data): - """Process data that is received outside of packets""" - pass - - -class LineReader(Packetizer): - """ - Read and write (Unicode) lines from/to serial port. - The encoding is applied. - """ - - TERMINATOR = b'\r\n' - ENCODING = 'utf-8' - UNICODE_HANDLING = 'replace' - - def handle_packet(self, packet): - self.handle_line(packet.decode(self.ENCODING, self.UNICODE_HANDLING)) - - def handle_line(self, line): - """Process one line - to be overridden by subclassing""" - raise NotImplementedError('please implement functionality in handle_line') - - def write_line(self, text): - """ - Write text to the transport. ``text`` is a Unicode string and the encoding - is applied before sending ans also the newline is append. - """ - # + is not the best choice but bytes does not support % or .format in py3 and we want a single write call - self.transport.write(text.encode(self.ENCODING, self.UNICODE_HANDLING) + self.TERMINATOR) - - -class ReaderThread(threading.Thread): - """\ - Implement a serial port read loop and dispatch to a Protocol instance (like - the asyncio.Protocol) but do it with threads. - - Calls to close() will close the serial port but it is also possible to just - stop() this thread and continue the serial port instance otherwise. - """ - - def __init__(self, serial_instance, protocol_factory): - """\ - Initialize thread. - - Note that the serial_instance' timeout is set to one second! - Other settings are not changed. - """ - super(ReaderThread, self).__init__() - self.daemon = True - self.serial = serial_instance - self.protocol_factory = protocol_factory - self.alive = True - self._lock = threading.Lock() - self._connection_made = threading.Event() - self.protocol = None - - def stop(self): - """Stop the reader thread""" - self.alive = False - if hasattr(self.serial, 'cancel_read'): - self.serial.cancel_read() - self.join(2) - - def run(self): - """Reader loop""" - if not hasattr(self.serial, 'cancel_read'): - self.serial.timeout = 1 - self.protocol = self.protocol_factory() - try: - self.protocol.connection_made(self) - except Exception as e: - self.alive = False - self.protocol.connection_lost(e) - self._connection_made.set() - return - error = None - self._connection_made.set() - while self.alive and self.serial.is_open: - try: - # read all that is there or wait for one byte (blocking) - data = self.serial.read(self.serial.in_waiting or 1) - except serial.SerialException as e: - # probably some I/O problem such as disconnected USB serial - # adapters -> exit - error = e - break - else: - if data: - # make a separated try-except for called used code - try: - self.protocol.data_received(data) - except Exception as e: - error = e - break - self.alive = False - self.protocol.connection_lost(error) - self.protocol = None - - def write(self, data): - """Thread safe writing (uses lock)""" - with self._lock: - self.serial.write(data) - - def close(self): - """Close the serial port and exit reader thread (uses lock)""" - # use the lock to let other threads finish writing - with self._lock: - # first stop reading, so that closing can be done on idle port - self.stop() - self.serial.close() - - def connect(self): - """ - Wait until connection is set up and return the transport and protocol - instances. - """ - if self.alive: - self._connection_made.wait() - if not self.alive: - raise RuntimeError('connection_lost already called') - return (self, self.protocol) - else: - raise RuntimeError('already stopped') - - # - - context manager, returns protocol - - def __enter__(self): - """\ - Enter context handler. May raise RuntimeError in case the connection - could not be created. - """ - self.start() - self._connection_made.wait() - if not self.alive: - raise RuntimeError('connection_lost already called') - return self.protocol - - def __exit__(self, exc_type, exc_val, exc_tb): - """Leave context: close port""" - self.close() - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# test -if __name__ == '__main__': - # pylint: disable=wrong-import-position - import sys - import time - import traceback - - #~ PORT = 'spy:///dev/ttyUSB0' - PORT = 'loop://' - - class PrintLines(LineReader): - def connection_made(self, transport): - super(PrintLines, self).connection_made(transport) - sys.stdout.write('port opened\n') - self.write_line('hello world') - - def handle_line(self, data): - sys.stdout.write('line received: {!r}\n'.format(data)) - - def connection_lost(self, exc): - if exc: - traceback.print_exc(exc) - sys.stdout.write('port closed\n') - - ser = serial.serial_for_url(PORT, baudrate=115200, timeout=1) - with ReaderThread(ser, PrintLines) as protocol: - protocol.write_line('hello') - time.sleep(2) - - # alternative usage - ser = serial.serial_for_url(PORT, baudrate=115200, timeout=1) - t = ReaderThread(ser, PrintLines) - t.start() - transport, protocol = t.connect() - protocol.write_line('hello') - time.sleep(2) - t.close() diff --git a/mFIZ/scripts/mFIZ_extern/serial/tools/hexlify_codec.py b/mFIZ/scripts/mFIZ_extern/serial/tools/hexlify_codec.py deleted file mode 100644 index 1371da2..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/tools/hexlify_codec.py +++ /dev/null @@ -1,124 +0,0 @@ -#! python -# -# This is a codec to create and decode hexdumps with spaces between characters. used by miniterm. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2015-2016 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause -"""\ -Python 'hex' Codec - 2-digit hex with spaces content transfer encoding. - -Encode and decode may be a bit missleading at first sight... - -The textual representation is a hex dump: e.g. "40 41" -The "encoded" data of this is the binary form, e.g. b"@A" - -Therefore decoding is binary to text and thus converting binary data to hex dump. - -""" - -import codecs -import serial - - -try: - unicode -except (NameError, AttributeError): - unicode = str # for Python 3, pylint: disable=redefined-builtin,invalid-name - - -HEXDIGITS = '0123456789ABCDEF' - - -# Codec APIs - -def hex_encode(data, errors='strict'): - """'40 41 42' -> b'@ab'""" - return (serial.to_bytes([int(h, 16) for h in data.split()]), len(data)) - - -def hex_decode(data, errors='strict'): - """b'@ab' -> '40 41 42'""" - return (unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data))), len(data)) - - -class Codec(codecs.Codec): - def encode(self, data, errors='strict'): - """'40 41 42' -> b'@ab'""" - return serial.to_bytes([int(h, 16) for h in data.split()]) - - def decode(self, data, errors='strict'): - """b'@ab' -> '40 41 42'""" - return unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data))) - - -class IncrementalEncoder(codecs.IncrementalEncoder): - """Incremental hex encoder""" - - def __init__(self, errors='strict'): - self.errors = errors - self.state = 0 - - def reset(self): - self.state = 0 - - def getstate(self): - return self.state - - def setstate(self, state): - self.state = state - - def encode(self, data, final=False): - """\ - Incremental encode, keep track of digits and emit a byte when a pair - of hex digits is found. The space is optional unless the error - handling is defined to be 'strict'. - """ - state = self.state - encoded = [] - for c in data.upper(): - if c in HEXDIGITS: - z = HEXDIGITS.index(c) - if state: - encoded.append(z + (state & 0xf0)) - state = 0 - else: - state = 0x100 + (z << 4) - elif c == ' ': # allow spaces to separate values - if state and self.errors == 'strict': - raise UnicodeError('odd number of hex digits') - state = 0 - else: - if self.errors == 'strict': - raise UnicodeError('non-hex digit found: {!r}'.format(c)) - self.state = state - return serial.to_bytes(encoded) - - -class IncrementalDecoder(codecs.IncrementalDecoder): - """Incremental decoder""" - def decode(self, data, final=False): - return unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data))) - - -class StreamWriter(Codec, codecs.StreamWriter): - """Combination of hexlify codec and StreamWriter""" - - -class StreamReader(Codec, codecs.StreamReader): - """Combination of hexlify codec and StreamReader""" - - -def getregentry(): - """encodings module API""" - return codecs.CodecInfo( - name='hexlify', - encode=hex_encode, - decode=hex_decode, - incrementalencoder=IncrementalEncoder, - incrementaldecoder=IncrementalDecoder, - streamwriter=StreamWriter, - streamreader=StreamReader, - #~ _is_text_encoding=True, - ) diff --git a/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports.py b/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports.py deleted file mode 100644 index 2271dd1..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python -# -# Serial port enumeration. Console tool and backend selection. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2011-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -"""\ -This module will provide a function called comports that returns an -iterable (generator or list) that will enumerate available com ports. Note that -on some systems non-existent ports may be listed. - -Additionally a grep function is supplied that can be used to search for ports -based on their descriptions or hardware ID. -""" - -import sys -import os -import re - -# chose an implementation, depending on os -#~ if sys.platform == 'cli': -#~ else: -if os.name == 'nt': # sys.platform == 'win32': - from serial.tools.list_ports_windows import comports -elif os.name == 'posix': - from serial.tools.list_ports_posix import comports -#~ elif os.name == 'java': -else: - raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name)) - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def grep(regexp): - """\ - Search for ports using a regular expression. Port name, description and - hardware ID are searched. The function returns an iterable that returns the - same tuples as comport() would do. - """ - r = re.compile(regexp, re.I) - for info in comports(): - port, desc, hwid = info - if r.search(port) or r.search(desc) or r.search(hwid): - yield info - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def main(): - import argparse - - parser = argparse.ArgumentParser(description='Serial port enumeration') - - parser.add_argument( - 'regexp', - nargs='?', - help='only show ports that match this regex') - - parser.add_argument( - '-v', '--verbose', - action='store_true', - help='show more messages') - - parser.add_argument( - '-q', '--quiet', - action='store_true', - help='suppress all messages') - - parser.add_argument( - '-n', - type=int, - help='only output the N-th entry') - - args = parser.parse_args() - - hits = 0 - # get iteraror w/ or w/o filter - if args.regexp: - if not args.quiet: - sys.stderr.write("Filtered list with regexp: {!r}\n".format(args.regexp)) - iterator = sorted(grep(args.regexp)) - else: - iterator = sorted(comports()) - # list them - for n, (port, desc, hwid) in enumerate(iterator, 1): - if args.n is None or args.n == n: - sys.stdout.write("{:20}\n".format(port)) - if args.verbose: - sys.stdout.write(" desc: {}\n".format(desc)) - sys.stdout.write(" hwid: {}\n".format(hwid)) - hits += 1 - if not args.quiet: - if hits: - sys.stderr.write("{} ports found\n".format(hits)) - else: - sys.stderr.write("no ports found\n") - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# test -if __name__ == '__main__': - main() diff --git a/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_common.py b/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_common.py deleted file mode 100644 index df12939..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_common.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python -# -# This is a helper module for the various platform dependent list_port -# implementations. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause -import re - - -def numsplit(text): - """\ - Convert string into a list of texts and numbers in order to support a - natural sorting. - """ - result = [] - for group in re.split(r'(\d+)', text): - if group: - try: - group = int(group) - except ValueError: - pass - result.append(group) - return result - - -class ListPortInfo(object): - """Info collection base class for serial ports""" - - def __init__(self, device=None): - self.device = device - self.name = None - self.description = 'n/a' - self.hwid = 'n/a' - # USB specific data - self.vid = None - self.pid = None - self.serial_number = None - self.location = None - self.manufacturer = None - self.product = None - self.interface = None - - def usb_description(self): - """return a short string to name the port based on USB info""" - if self.interface is not None: - return '{} - {}'.format(self.product, self.interface) - elif self.product is not None: - return self.product - else: - return self.name - - def usb_info(self): - """return a string with USB related information about device""" - return 'USB VID:PID={:04X}:{:04X}{}{}'.format( - self.vid or 0, - self.pid or 0, - ' SER={}'.format(self.serial_number) if self.serial_number is not None else '', - ' LOCATION={}'.format(self.location) if self.location is not None else '') - - def apply_usb_info(self): - """update description and hwid from USB data""" - self.description = self.usb_description() - self.hwid = self.usb_info() - - def __eq__(self, other): - return self.device == other.device - - def __lt__(self, other): - return numsplit(self.device) < numsplit(other.device) - - def __str__(self): - return '{} - {}'.format(self.device, self.description) - - def __getitem__(self, index): - """Item access: backwards compatible -> (port, desc, hwid)""" - if index == 0: - return self.device - elif index == 1: - return self.description - elif index == 2: - return self.hwid - else: - raise IndexError('{} > 2'.format(index)) - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# test -if __name__ == '__main__': - print(ListPortInfo('dummy')) diff --git a/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_linux.py b/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_linux.py deleted file mode 100644 index 567df6d..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_linux.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python -# -# This is a module that gathers a list of serial ports including details on -# GNU/Linux systems. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2011-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -import glob -import os -from serial.tools import list_ports_common - - -class SysFS(list_ports_common.ListPortInfo): - """Wrapper for easy sysfs access and device info""" - - def __init__(self, device): - super(SysFS, self).__init__(device) - self.name = os.path.basename(device) - self.usb_device_path = None - if os.path.exists('/sys/class/tty/{}/device'.format(self.name)): - self.device_path = os.path.realpath('/sys/class/tty/{}/device'.format(self.name)) - self.subsystem = os.path.basename(os.path.realpath(os.path.join(self.device_path, 'subsystem'))) - else: - self.device_path = None - self.subsystem = None - # check device type - if self.subsystem == 'usb-serial': - self.usb_device_path = os.path.dirname(os.path.dirname(self.device_path)) - elif self.subsystem == 'usb': - self.usb_device_path = os.path.dirname(self.device_path) - else: - self.usb_device_path = None - # fill-in info for USB devices - if self.usb_device_path is not None: - self.vid = int(self.read_line(self.usb_device_path, 'idVendor'), 16) - self.pid = int(self.read_line(self.usb_device_path, 'idProduct'), 16) - self.serial_number = self.read_line(self.usb_device_path, 'serial') - self.location = os.path.basename(self.usb_device_path) - self.manufacturer = self.read_line(self.usb_device_path, 'manufacturer') - self.product = self.read_line(self.usb_device_path, 'product') - self.interface = self.read_line(self.device_path, 'interface') - - if self.subsystem in ('usb', 'usb-serial'): - self.apply_usb_info() - #~ elif self.subsystem in ('pnp', 'amba'): # PCI based devices, raspi - elif self.subsystem == 'pnp': # PCI based devices - self.description = self.name - self.hwid = self.read_line(self.device_path, 'id') - elif self.subsystem == 'amba': # raspi - self.description = self.name - self.hwid = os.path.basename(self.device_path) - - def read_line(self, *args): - """\ - Helper function to read a single line from a file. - One or more parameters are allowed, they are joined with os.path.join. - Returns None on errors.. - """ - try: - with open(os.path.join(*args)) as f: - line = f.readline().strip() - return line - except IOError: - return None - - -def comports(): - 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/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 - return [info - for info in [SysFS(d) for d in devices] - if info.subsystem != "platform"] # hide non-present internal serial ports - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# test -if __name__ == '__main__': - for port, desc, hwid in sorted(comports()): - print("{}: {} [{}]".format(port, desc, hwid)) diff --git a/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_osx.py b/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_osx.py deleted file mode 100644 index 1d57b96..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_osx.py +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/env python -# -# This is a module that gathers a list of serial ports including details on OSX -# -# code originally from https://github.com/makerbot/pyserial/tree/master/serial/tools -# with contributions from cibomahto, dgs3, FarMcKon, tedbrandston -# and modifications by cliechti, hoihu, hardkrash -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2013-2015 -# -# SPDX-License-Identifier: BSD-3-Clause - - -# List all of the callout devices in OS/X by querying IOKit. - -# See the following for a reference of how to do this: -# http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/SerialDevices.html#//apple_ref/doc/uid/TP30000384-CIHGEAFD - -# More help from darwin_hid.py - -# Also see the 'IORegistryExplorer' for an idea of what we are actually searching - -import ctypes -import ctypes.util - -from serial.tools import list_ports_common - -iokit = ctypes.cdll.LoadLibrary(ctypes.util.find_library('IOKit')) -cf = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation')) - -kIOMasterPortDefault = ctypes.c_void_p.in_dll(iokit, "kIOMasterPortDefault") -kCFAllocatorDefault = ctypes.c_void_p.in_dll(cf, "kCFAllocatorDefault") - -kCFStringEncodingMacRoman = 0 - -iokit.IOServiceMatching.restype = ctypes.c_void_p - -iokit.IOServiceGetMatchingServices.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] -iokit.IOServiceGetMatchingServices.restype = ctypes.c_void_p - -iokit.IORegistryEntryGetParentEntry.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] - -iokit.IORegistryEntryCreateCFProperty.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint32] -iokit.IORegistryEntryCreateCFProperty.restype = ctypes.c_void_p - -iokit.IORegistryEntryGetPath.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] -iokit.IORegistryEntryGetPath.restype = ctypes.c_void_p - -iokit.IORegistryEntryGetName.argtypes = [ctypes.c_void_p, ctypes.c_void_p] -iokit.IORegistryEntryGetName.restype = ctypes.c_void_p - -iokit.IOObjectGetClass.argtypes = [ctypes.c_void_p, ctypes.c_void_p] -iokit.IOObjectGetClass.restype = ctypes.c_void_p - -iokit.IOObjectRelease.argtypes = [ctypes.c_void_p] - - -cf.CFStringCreateWithCString.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int32] -cf.CFStringCreateWithCString.restype = ctypes.c_void_p - -cf.CFStringGetCStringPtr.argtypes = [ctypes.c_void_p, ctypes.c_uint32] -cf.CFStringGetCStringPtr.restype = ctypes.c_char_p - -cf.CFNumberGetValue.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.c_void_p] -cf.CFNumberGetValue.restype = ctypes.c_void_p - -# void CFRelease ( CFTypeRef cf ); -cf.CFRelease.argtypes = [ctypes.c_void_p] -cf.CFRelease.restype = None - -# CFNumber type defines -kCFNumberSInt8Type = 1 -kCFNumberSInt16Type = 2 -kCFNumberSInt32Type = 3 -kCFNumberSInt64Type = 4 - - -def get_string_property(device_type, property): - """ - Search the given device for the specified string property - - @param device_type Type of Device - @param property String to search for - @return Python string containing the value, or None if not found. - """ - key = cf.CFStringCreateWithCString( - kCFAllocatorDefault, - property.encode("mac_roman"), - kCFStringEncodingMacRoman) - - CFContainer = iokit.IORegistryEntryCreateCFProperty( - device_type, - key, - kCFAllocatorDefault, - 0) - output = None - - if CFContainer: - output = cf.CFStringGetCStringPtr(CFContainer, 0) - if output is not None: - output = output.decode('mac_roman') - cf.CFRelease(CFContainer) - return output - - -def get_int_property(device_type, property, cf_number_type): - """ - Search the given device for the specified string property - - @param device_type Device to search - @param property String to search for - @param cf_number_type CFType number - - @return Python string containing the value, or None if not found. - """ - key = cf.CFStringCreateWithCString( - kCFAllocatorDefault, - property.encode("mac_roman"), - kCFStringEncodingMacRoman) - - CFContainer = iokit.IORegistryEntryCreateCFProperty( - device_type, - key, - kCFAllocatorDefault, - 0) - - if CFContainer: - if (cf_number_type == kCFNumberSInt32Type): - number = ctypes.c_uint32() - elif (cf_number_type == kCFNumberSInt16Type): - number = ctypes.c_uint16() - cf.CFNumberGetValue(CFContainer, cf_number_type, ctypes.byref(number)) - cf.CFRelease(CFContainer) - return number.value - return None - - -def IORegistryEntryGetName(device): - pathname = ctypes.create_string_buffer(100) # TODO: Is this ok? - iokit.IOObjectGetClass(device, ctypes.byref(pathname)) - return pathname.value - - -def GetParentDeviceByType(device, parent_type): - """ Find the first parent of a device that implements the parent_type - @param IOService Service to inspect - @return Pointer to the parent type, or None if it was not found. - """ - # First, try to walk up the IOService tree to find a parent of this device that is a IOUSBDevice. - parent_type = parent_type.encode('mac_roman') - while IORegistryEntryGetName(device) != parent_type: - parent = ctypes.c_void_p() - response = iokit.IORegistryEntryGetParentEntry( - device, - "IOService".encode("mac_roman"), - ctypes.byref(parent)) - # If we weren't able to find a parent for the device, we're done. - if response != 0: - return None - device = parent - return device - - -def GetIOServicesByType(service_type): - """ - returns iterator over specified service_type - """ - serial_port_iterator = ctypes.c_void_p() - - iokit.IOServiceGetMatchingServices( - kIOMasterPortDefault, - iokit.IOServiceMatching(service_type.encode('mac_roman')), - ctypes.byref(serial_port_iterator)) - - services = [] - while iokit.IOIteratorIsValid(serial_port_iterator): - service = iokit.IOIteratorNext(serial_port_iterator) - if not service: - break - services.append(service) - iokit.IOObjectRelease(serial_port_iterator) - return services - - -def location_to_string(locationID): - """ - helper to calculate port and bus number from locationID - """ - loc = ['{}-'.format(locationID >> 24)] - while locationID & 0xf00000: - if len(loc) > 1: - loc.append('.') - loc.append('{}'.format((locationID >> 20) & 0xf)) - locationID <<= 4 - return ''.join(loc) - - -class SuitableSerialInterface(object): - pass - - -def scan_interfaces(): - """ - helper function to scan USB interfaces - returns a list of SuitableSerialInterface objects with name and id attributes - """ - interfaces = [] - for service in GetIOServicesByType('IOSerialBSDClient'): - device = get_string_property(service, "IOCalloutDevice") - if device: - usb_device = GetParentDeviceByType(service, "IOUSBInterface") - if usb_device: - name = get_string_property(usb_device, "USB Interface Name") or None - locationID = get_int_property(usb_device, "locationID", kCFNumberSInt32Type) or '' - i = SuitableSerialInterface() - i.id = locationID - i.name = name - interfaces.append(i) - return interfaces - - -def search_for_locationID_in_interfaces(serial_interfaces, locationID): - for interface in serial_interfaces: - if (interface.id == locationID): - return interface.name - return None - - -def comports(): - # Scan for all iokit serial ports - services = GetIOServicesByType('IOSerialBSDClient') - ports = [] - serial_interfaces = scan_interfaces() - for service in services: - # First, add the callout device file. - device = get_string_property(service, "IOCalloutDevice") - if device: - info = list_ports_common.ListPortInfo(device) - # If the serial port is implemented by IOUSBDevice - usb_device = GetParentDeviceByType(service, "IOUSBDevice") - if usb_device: - # fetch some useful informations from properties - info.vid = get_int_property(usb_device, "idVendor", kCFNumberSInt16Type) - info.pid = get_int_property(usb_device, "idProduct", kCFNumberSInt16Type) - info.serial_number = get_string_property(usb_device, "USB Serial Number") - info.product = get_string_property(usb_device, "USB Product Name") or 'n/a' - info.manufacturer = get_string_property(usb_device, "USB Vendor Name") - locationID = get_int_property(usb_device, "locationID", kCFNumberSInt32Type) - info.location = location_to_string(locationID) - info.interface = search_for_locationID_in_interfaces(serial_interfaces, locationID) - info.apply_usb_info() - ports.append(info) - return ports - -# test -if __name__ == '__main__': - for port, desc, hwid in sorted(comports()): - print("{}: {} [{}]".format(port, desc, hwid)) diff --git a/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_posix.py b/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_posix.py deleted file mode 100644 index 6ea4db9..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_posix.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python -# -# This is a module that gathers a list of serial ports on POSIXy systems. -# For some specific implementations, see also list_ports_linux, list_ports_osx -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2011-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -"""\ -The ``comports`` function is expected to return an iterable that yields tuples -of 3 strings: port name, human readable description and a hardware ID. - -As currently no method is known to get the second two strings easily, they are -currently just identical to the port name. -""" - -import glob -import sys -import os -from serial.tools import list_ports_common - -# try to detect the OS so that a device can be selected... -plat = sys.platform.lower() - -if plat[:5] == 'linux': # Linux (confirmed) # noqa - from serial.tools.list_ports_linux import comports - -elif plat[:6] == 'darwin': # OS X (confirmed) - from serial.tools.list_ports_osx import comports - -elif plat == 'cygwin': # cygwin/win32 - # cygwin accepts /dev/com* in many contexts - # (such as 'open' call, explicit 'ls'), but 'glob.glob' - # and bare 'ls' do not; so use /dev/ttyS* instead - def comports(): - devices = glob.glob('/dev/ttyS*') - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:7] == 'openbsd': # OpenBSD - def comports(): - devices = glob.glob('/dev/cua*') - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:3] == 'bsd' or plat[:7] == 'freebsd': - def comports(): - devices = glob.glob('/dev/cua*[!.init][!.lock]') - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:6] == 'netbsd': # NetBSD - def comports(): - """scan for available ports. return a list of device names.""" - devices = glob.glob('/dev/dty*') - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:4] == 'irix': # IRIX - def comports(): - """scan for available ports. return a list of device names.""" - devices = glob.glob('/dev/ttyf*') - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:2] == 'hp': # HP-UX (not tested) - def comports(): - """scan for available ports. return a list of device names.""" - devices = glob.glob('/dev/tty*p0') - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:5] == 'sunos': # Solaris/SunOS - def comports(): - """scan for available ports. return a list of device names.""" - devices = glob.glob('/dev/tty*c') - return [list_ports_common.ListPortInfo(d) for d in devices] - -elif plat[:3] == 'aix': # AIX - def comports(): - """scan for available ports. return a list of device names.""" - devices = glob.glob('/dev/tty*') - return [list_ports_common.ListPortInfo(d) for d in devices] - -else: - # platform detection has failed... - import serial - sys.stderr.write("""\ -don't know how to enumerate ttys on this system. -! I you know how the serial ports are named send this information to -! the author of this module: - -sys.platform = {!r} -os.name = {!r} -pySerial version = {} - -also add the naming scheme of the serial ports and with a bit luck you can get -this module running... -""".format(sys.platform, os.name, serial.VERSION)) - raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name)) - -# test -if __name__ == '__main__': - for port, desc, hwid in sorted(comports()): - print("{}: {} [{}]".format(port, desc, hwid)) diff --git a/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_windows.py b/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_windows.py deleted file mode 100644 index a070559..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/tools/list_ports_windows.py +++ /dev/null @@ -1,284 +0,0 @@ -#! python -# -# Enumerate serial ports on Windows including a human readable description -# and hardware information. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2001-2016 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -# pylint: disable=invalid-name,too-few-public-methods -import re -import ctypes -from ctypes.wintypes import BOOL -from ctypes.wintypes import HWND -from ctypes.wintypes import DWORD -from ctypes.wintypes import WORD -from ctypes.wintypes import LONG -from ctypes.wintypes import ULONG -from ctypes.wintypes import HKEY -from ctypes.wintypes import BYTE -import serial -from serial.win32 import ULONG_PTR -from serial.tools import list_ports_common - - -def ValidHandle(value, func, arguments): - if value == 0: - raise ctypes.WinError() - return value - - -NULL = 0 -HDEVINFO = ctypes.c_void_p -LPCTSTR = ctypes.c_wchar_p -PCTSTR = ctypes.c_wchar_p -PTSTR = ctypes.c_wchar_p -LPDWORD = PDWORD = ctypes.POINTER(DWORD) -#~ LPBYTE = PBYTE = ctypes.POINTER(BYTE) -LPBYTE = PBYTE = ctypes.c_void_p # XXX avoids error about types - -ACCESS_MASK = DWORD -REGSAM = ACCESS_MASK - - -class GUID(ctypes.Structure): - _fields_ = [ - ('Data1', DWORD), - ('Data2', WORD), - ('Data3', WORD), - ('Data4', BYTE * 8), - ] - - def __str__(self): - return "{{{:08x}-{:04x}-{:04x}-{}-{}}}".format( - self.Data1, - self.Data2, - self.Data3, - ''.join(["{:02x}".format(d) for d in self.Data4[:2]]), - ''.join(["{:02x}".format(d) for d in self.Data4[2:]]), - ) - - -class SP_DEVINFO_DATA(ctypes.Structure): - _fields_ = [ - ('cbSize', DWORD), - ('ClassGuid', GUID), - ('DevInst', DWORD), - ('Reserved', ULONG_PTR), - ] - - def __str__(self): - return "ClassGuid:{} DevInst:{}".format(self.ClassGuid, self.DevInst) - - -PSP_DEVINFO_DATA = ctypes.POINTER(SP_DEVINFO_DATA) - -PSP_DEVICE_INTERFACE_DETAIL_DATA = ctypes.c_void_p - -setupapi = ctypes.windll.LoadLibrary("setupapi") -SetupDiDestroyDeviceInfoList = setupapi.SetupDiDestroyDeviceInfoList -SetupDiDestroyDeviceInfoList.argtypes = [HDEVINFO] -SetupDiDestroyDeviceInfoList.restype = BOOL - -SetupDiClassGuidsFromName = setupapi.SetupDiClassGuidsFromNameW -SetupDiClassGuidsFromName.argtypes = [PCTSTR, ctypes.POINTER(GUID), DWORD, PDWORD] -SetupDiClassGuidsFromName.restype = BOOL - -SetupDiEnumDeviceInfo = setupapi.SetupDiEnumDeviceInfo -SetupDiEnumDeviceInfo.argtypes = [HDEVINFO, DWORD, PSP_DEVINFO_DATA] -SetupDiEnumDeviceInfo.restype = BOOL - -SetupDiGetClassDevs = setupapi.SetupDiGetClassDevsW -SetupDiGetClassDevs.argtypes = [ctypes.POINTER(GUID), PCTSTR, HWND, DWORD] -SetupDiGetClassDevs.restype = HDEVINFO -SetupDiGetClassDevs.errcheck = ValidHandle - -SetupDiGetDeviceRegistryProperty = setupapi.SetupDiGetDeviceRegistryPropertyW -SetupDiGetDeviceRegistryProperty.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD] -SetupDiGetDeviceRegistryProperty.restype = BOOL - -SetupDiGetDeviceInstanceId = setupapi.SetupDiGetDeviceInstanceIdW -SetupDiGetDeviceInstanceId.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, PTSTR, DWORD, PDWORD] -SetupDiGetDeviceInstanceId.restype = BOOL - -SetupDiOpenDevRegKey = setupapi.SetupDiOpenDevRegKey -SetupDiOpenDevRegKey.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM] -SetupDiOpenDevRegKey.restype = HKEY - -advapi32 = ctypes.windll.LoadLibrary("Advapi32") -RegCloseKey = advapi32.RegCloseKey -RegCloseKey.argtypes = [HKEY] -RegCloseKey.restype = LONG - -RegQueryValueEx = advapi32.RegQueryValueExW -RegQueryValueEx.argtypes = [HKEY, LPCTSTR , LPDWORD, LPDWORD, LPBYTE, LPDWORD] -RegQueryValueEx.restype = LONG - - -DIGCF_PRESENT = 2 -DIGCF_DEVICEINTERFACE = 16 -INVALID_HANDLE_VALUE = 0 -ERROR_INSUFFICIENT_BUFFER = 122 -SPDRP_HARDWAREID = 1 -SPDRP_FRIENDLYNAME = 12 -SPDRP_LOCATION_PATHS = 35 -DICS_FLAG_GLOBAL = 1 -DIREG_DEV = 0x00000001 -KEY_READ = 0x20019 - - -def iterate_comports(): - """Return a generator that yields descriptions for serial ports""" - GUIDs = (GUID * 8)() # so far only seen one used, so hope 8 are enough... - guids_size = DWORD() - if not SetupDiClassGuidsFromName( - "Ports", - GUIDs, - ctypes.sizeof(GUIDs), - ctypes.byref(guids_size)): - raise ctypes.WinError() - - # repeat for all possible GUIDs - for index in range(guids_size.value): - g_hdi = SetupDiGetClassDevs( - ctypes.byref(GUIDs[index]), - None, - NULL, - DIGCF_PRESENT) # was DIGCF_PRESENT|DIGCF_DEVICEINTERFACE which misses CDC ports - - devinfo = SP_DEVINFO_DATA() - devinfo.cbSize = ctypes.sizeof(devinfo) - index = 0 - while SetupDiEnumDeviceInfo(g_hdi, index, ctypes.byref(devinfo)): - index += 1 - - # get the real com port name - hkey = SetupDiOpenDevRegKey( - g_hdi, - ctypes.byref(devinfo), - DICS_FLAG_GLOBAL, - 0, - DIREG_DEV, # DIREG_DRV for SW info - KEY_READ) - port_name_buffer = ctypes.create_unicode_buffer(250) - port_name_length = ULONG(ctypes.sizeof(port_name_buffer)) - RegQueryValueEx( - hkey, - "PortName", - None, - None, - ctypes.byref(port_name_buffer), - ctypes.byref(port_name_length)) - RegCloseKey(hkey) - - # unfortunately does this method also include parallel ports. - # we could check for names starting with COM or just exclude LPT - # and hope that other "unknown" names are serial ports... - if port_name_buffer.value.startswith('LPT'): - continue - - # hardware ID - szHardwareID = ctypes.create_unicode_buffer(250) - # try to get ID that includes serial number - if not SetupDiGetDeviceInstanceId( - g_hdi, - ctypes.byref(devinfo), - #~ ctypes.byref(szHardwareID), - szHardwareID, - ctypes.sizeof(szHardwareID) - 1, - None): - # fall back to more generic hardware ID if that would fail - if not SetupDiGetDeviceRegistryProperty( - g_hdi, - ctypes.byref(devinfo), - SPDRP_HARDWAREID, - None, - ctypes.byref(szHardwareID), - ctypes.sizeof(szHardwareID) - 1, - None): - # Ignore ERROR_INSUFFICIENT_BUFFER - if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: - raise ctypes.WinError() - # stringify - szHardwareID_str = szHardwareID.value - - info = list_ports_common.ListPortInfo(port_name_buffer.value) - - # in case of USB, make a more readable string, similar to that form - # that we also generate on other platforms - if szHardwareID_str.startswith('USB'): - m = re.search(r'VID_([0-9a-f]{4})(&PID_([0-9a-f]{4}))?(\\(\w+))?', szHardwareID_str, re.I) - if m: - info.vid = int(m.group(1), 16) - if m.group(3): - info.pid = int(m.group(3), 16) - if m.group(5): - info.serial_number = m.group(5) - # calculate a location string - loc_path_str = ctypes.create_unicode_buffer(250) - if SetupDiGetDeviceRegistryProperty( - g_hdi, - ctypes.byref(devinfo), - SPDRP_LOCATION_PATHS, - None, - ctypes.byref(loc_path_str), - ctypes.sizeof(loc_path_str) - 1, - None): - m = re.finditer(r'USBROOT\((\w+)\)|#USB\((\w+)\)', loc_path_str.value) - location = [] - for g in m: - if g.group(1): - location.append('{:d}'.format(int(g.group(1)) + 1)) - else: - if len(location) > 1: - location.append('.') - else: - location.append('-') - location.append(g.group(2)) - if location: - info.location = ''.join(location) - info.hwid = info.usb_info() - elif szHardwareID_str.startswith('FTDIBUS'): - m = re.search(r'VID_([0-9a-f]{4})\+PID_([0-9a-f]{4})(\+(\w+))?', szHardwareID_str, re.I) - if m: - info.vid = int(m.group(1), 16) - info.pid = int(m.group(2), 16) - if m.group(4): - info.serial_number = m.group(4) - # USB location is hidden by FDTI driver :( - info.hwid = info.usb_info() - else: - info.hwid = szHardwareID_str - - # friendly name - szFriendlyName = ctypes.create_unicode_buffer(250) - if SetupDiGetDeviceRegistryProperty( - g_hdi, - ctypes.byref(devinfo), - SPDRP_FRIENDLYNAME, - #~ SPDRP_DEVICEDESC, - None, - ctypes.byref(szFriendlyName), - ctypes.sizeof(szFriendlyName) - 1, - None): - info.description = szFriendlyName.value - #~ else: - # Ignore ERROR_INSUFFICIENT_BUFFER - #~ if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: - #~ raise IOError("failed to get details for %s (%s)" % (devinfo, szHardwareID.value)) - # ignore errors and still include the port in the list, friendly name will be same as port name - yield info - SetupDiDestroyDeviceInfoList(g_hdi) - - -def comports(): - """Return a list of info objects about serial ports""" - return list(iterate_comports()) - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# test -if __name__ == '__main__': - for port, desc, hwid in sorted(comports()): - print("{}: {} [{}]".format(port, desc, hwid)) diff --git a/mFIZ/scripts/mFIZ_extern/serial/tools/miniterm.py b/mFIZ/scripts/mFIZ_extern/serial/tools/miniterm.py deleted file mode 100644 index 7c68e9d..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/tools/miniterm.py +++ /dev/null @@ -1,930 +0,0 @@ -#!/usr/bin/env python -# -# Very simple serial terminal -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C)2002-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause - -import codecs -import os -import sys -import threading - -import serial -from serial.tools.list_ports import comports -from serial.tools import hexlify_codec - -# pylint: disable=wrong-import-order,wrong-import-position - -codecs.register(lambda c: hexlify_codec.getregentry() if c == 'hexlify' else None) - -try: - raw_input -except NameError: - # pylint: disable=redefined-builtin,invalid-name - raw_input = input # in python3 it's "raw" - unichr = chr - - -def key_description(character): - """generate a readable description for a key""" - ascii_code = ord(character) - if ascii_code < 32: - return 'Ctrl+{:c}'.format(ord('@') + ascii_code) - else: - return repr(character) - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -class ConsoleBase(object): - """OS abstraction for console (input/output codec, no echo)""" - - def __init__(self): - if sys.version_info >= (3, 0): - self.byte_output = sys.stdout.buffer - else: - self.byte_output = sys.stdout - self.output = sys.stdout - - def setup(self): - """Set console to read single characters, no echo""" - - def cleanup(self): - """Restore default console settings""" - - def getkey(self): - """Read a single key from the console""" - return None - - def write_bytes(self, byte_string): - """Write bytes (already encoded)""" - self.byte_output.write(byte_string) - self.byte_output.flush() - - def write(self, text): - """Write string""" - self.output.write(text) - self.output.flush() - - def cancel(self): - """Cancel getkey operation""" - - # - - - - - - - - - - - - - - - - - - - - - - - - - # context manager: - # switch terminal temporary to normal mode (e.g. to get user input) - - def __enter__(self): - self.cleanup() - return self - - def __exit__(self, *args, **kwargs): - self.setup() - - -if os.name == 'nt': # noqa - import msvcrt - import ctypes - - class Out(object): - """file-like wrapper that uses os.write""" - - def __init__(self, fd): - self.fd = fd - - def flush(self): - pass - - def write(self, s): - os.write(self.fd, s) - - class Console(ConsoleBase): - def __init__(self): - super(Console, self).__init__() - self._saved_ocp = ctypes.windll.kernel32.GetConsoleOutputCP() - self._saved_icp = ctypes.windll.kernel32.GetConsoleCP() - ctypes.windll.kernel32.SetConsoleOutputCP(65001) - ctypes.windll.kernel32.SetConsoleCP(65001) - self.output = codecs.getwriter('UTF-8')(Out(sys.stdout.fileno()), 'replace') - # the change of the code page is not propagated to Python, manually fix it - sys.stderr = codecs.getwriter('UTF-8')(Out(sys.stderr.fileno()), 'replace') - sys.stdout = self.output - self.output.encoding = 'UTF-8' # needed for input - - def __del__(self): - ctypes.windll.kernel32.SetConsoleOutputCP(self._saved_ocp) - ctypes.windll.kernel32.SetConsoleCP(self._saved_icp) - - def getkey(self): - while True: - z = msvcrt.getwch() - if z == unichr(13): - return unichr(10) - elif z in (unichr(0), unichr(0x0e)): # functions keys, ignore - msvcrt.getwch() - else: - return z - - def cancel(self): - # CancelIo, CancelSynchronousIo do not seem to work when using - # getwch, so instead, send a key to the window with the console - hwnd = ctypes.windll.kernel32.GetConsoleWindow() - ctypes.windll.user32.PostMessageA(hwnd, 0x100, 0x0d, 0) - -elif os.name == 'posix': - import atexit - import termios - import select - - class Console(ConsoleBase): - def __init__(self): - super(Console, self).__init__() - self.fd = sys.stdin.fileno() - # an additional pipe is used in getkey, so that the cancel method - # can abort the waiting getkey method - self.pipe_r, self.pipe_w = os.pipe() - self.old = termios.tcgetattr(self.fd) - atexit.register(self.cleanup) - if sys.version_info < (3, 0): - self.enc_stdin = codecs.getreader(sys.stdin.encoding)(sys.stdin) - else: - self.enc_stdin = sys.stdin - - def setup(self): - new = termios.tcgetattr(self.fd) - new[3] = new[3] & ~termios.ICANON & ~termios.ECHO & ~termios.ISIG - new[6][termios.VMIN] = 1 - new[6][termios.VTIME] = 0 - termios.tcsetattr(self.fd, termios.TCSANOW, new) - - def getkey(self): - ready, _, _ = select.select([self.enc_stdin, self.pipe_r], [], [], None) - if self.pipe_r in ready: - os.read(self.pipe_r, 1) - return - c = self.enc_stdin.read(1) - if c == unichr(0x7f): - c = unichr(8) # map the BS key (which yields DEL) to backspace - return c - - def cancel(self): - os.write(self.pipe_w, b"x") - - def cleanup(self): - termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old) - -else: - raise NotImplementedError( - 'Sorry no implementation for your platform ({}) available.'.format(sys.platform)) - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -class Transform(object): - """do-nothing: forward all data unchanged""" - def rx(self, text): - """text received from serial port""" - return text - - def tx(self, text): - """text to be sent to serial port""" - return text - - def echo(self, text): - """text to be sent but displayed on console""" - return text - - -class CRLF(Transform): - """ENTER sends CR+LF""" - - def tx(self, text): - return text.replace('\n', '\r\n') - - -class CR(Transform): - """ENTER sends CR""" - - def rx(self, text): - return text.replace('\r', '\n') - - def tx(self, text): - return text.replace('\n', '\r') - - -class LF(Transform): - """ENTER sends LF""" - - -class NoTerminal(Transform): - """remove typical terminal control codes from input""" - - REPLACEMENT_MAP = dict((x, 0x2400 + x) for x in range(32) if unichr(x) not in '\r\n\b\t') - REPLACEMENT_MAP.update( - { - 0x7F: 0x2421, # DEL - 0x9B: 0x2425, # CSI - }) - - def rx(self, text): - return text.translate(self.REPLACEMENT_MAP) - - echo = rx - - -class NoControls(NoTerminal): - """Remove all control codes, incl. CR+LF""" - - REPLACEMENT_MAP = dict((x, 0x2400 + x) for x in range(32)) - REPLACEMENT_MAP.update( - { - 0x20: 0x2423, # visual space - 0x7F: 0x2421, # DEL - 0x9B: 0x2425, # CSI - }) - - -class Printable(Transform): - """Show decimal code for all non-ASCII characters and replace most control codes""" - - def rx(self, text): - r = [] - for c in text: - if ' ' <= c < '\x7f' or c in '\r\n\b\t': - r.append(c) - elif c < ' ': - r.append(unichr(0x2400 + ord(c))) - else: - r.extend(unichr(0x2080 + ord(d) - 48) for d in '{:d}'.format(ord(c))) - r.append(' ') - return ''.join(r) - - echo = rx - - -class Colorize(Transform): - """Apply different colors for received and echo""" - - def __init__(self): - # XXX make it configurable, use colorama? - self.input_color = '\x1b[37m' - self.echo_color = '\x1b[31m' - - def rx(self, text): - return self.input_color + text - - def echo(self, text): - return self.echo_color + text - - -class DebugIO(Transform): - """Print what is sent and received""" - - def rx(self, text): - sys.stderr.write(' [RX:{}] '.format(repr(text))) - sys.stderr.flush() - return text - - def tx(self, text): - sys.stderr.write(' [TX:{}] '.format(repr(text))) - sys.stderr.flush() - return text - - -# other ideas: -# - add date/time for each newline -# - insert newline after: a) timeout b) packet end character - -EOL_TRANSFORMATIONS = { - 'crlf': CRLF, - 'cr': CR, - 'lf': LF, -} - -TRANSFORMATIONS = { - 'direct': Transform, # no transformation - 'default': NoTerminal, - 'nocontrol': NoControls, - 'printable': Printable, - 'colorize': Colorize, - 'debug': DebugIO, -} - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def ask_for_port(): - """\ - Show a list of ports and ask the user for a choice. To make selection - easier on systems with long device names, also allow the input of an - index. - """ - sys.stderr.write('\n--- Available ports:\n') - ports = [] - for n, (port, desc, hwid) in enumerate(sorted(comports()), 1): - sys.stderr.write('--- {:2}: {:20} {}\n'.format(n, port, desc)) - ports.append(port) - while True: - port = raw_input('--- Enter port index or full name: ') - try: - index = int(port) - 1 - if not 0 <= index < len(ports): - sys.stderr.write('--- Invalid index!\n') - continue - except ValueError: - pass - else: - port = ports[index] - return port - - -class Miniterm(object): - """\ - Terminal application. Copy data from serial port to console and vice versa. - Handle special keys from the console to show menu etc. - """ - - def __init__(self, serial_instance, echo=False, eol='crlf', filters=()): - self.console = Console() - self.serial = serial_instance - self.echo = echo - self.raw = False - self.input_encoding = 'UTF-8' - self.output_encoding = 'UTF-8' - self.eol = eol - self.filters = filters - self.update_transformations() - self.exit_character = 0x1d # GS/CTRL+] - self.menu_character = 0x14 # Menu: CTRL+T - self.alive = None - self._reader_alive = None - self.receiver_thread = None - self.rx_decoder = None - self.tx_decoder = None - - def _start_reader(self): - """Start reader thread""" - self._reader_alive = True - # start serial->console thread - self.receiver_thread = threading.Thread(target=self.reader, name='rx') - self.receiver_thread.daemon = True - self.receiver_thread.start() - - def _stop_reader(self): - """Stop reader thread only, wait for clean exit of thread""" - self._reader_alive = False - if hasattr(self.serial, 'cancel_read'): - self.serial.cancel_read() - self.receiver_thread.join() - - def start(self): - """start worker threads""" - self.alive = True - self._start_reader() - # enter console->serial loop - self.transmitter_thread = threading.Thread(target=self.writer, name='tx') - self.transmitter_thread.daemon = True - self.transmitter_thread.start() - self.console.setup() - - def stop(self): - """set flag to stop worker threads""" - self.alive = False - - def join(self, transmit_only=False): - """wait for worker threads to terminate""" - self.transmitter_thread.join() - if not transmit_only: - if hasattr(self.serial, 'cancel_read'): - self.serial.cancel_read() - self.receiver_thread.join() - - def close(self): - self.serial.close() - - def update_transformations(self): - """take list of transformation classes and instantiate them for rx and tx""" - transformations = [EOL_TRANSFORMATIONS[self.eol]] + [TRANSFORMATIONS[f] - for f in self.filters] - self.tx_transformations = [t() for t in transformations] - self.rx_transformations = list(reversed(self.tx_transformations)) - - def set_rx_encoding(self, encoding, errors='replace'): - """set encoding for received data""" - self.input_encoding = encoding - self.rx_decoder = codecs.getincrementaldecoder(encoding)(errors) - - def set_tx_encoding(self, encoding, errors='replace'): - """set encoding for transmitted data""" - self.output_encoding = encoding - self.tx_encoder = codecs.getincrementalencoder(encoding)(errors) - - def dump_port_settings(self): - """Write current settings to sys.stderr""" - sys.stderr.write("\n--- Settings: {p.name} {p.baudrate},{p.bytesize},{p.parity},{p.stopbits}\n".format( - p=self.serial)) - sys.stderr.write('--- RTS: {:8} DTR: {:8} BREAK: {:8}\n'.format( - ('active' if self.serial.rts else 'inactive'), - ('active' if self.serial.dtr else 'inactive'), - ('active' if self.serial.break_condition else 'inactive'))) - try: - sys.stderr.write('--- CTS: {:8} DSR: {:8} RI: {:8} CD: {:8}\n'.format( - ('active' if self.serial.cts else 'inactive'), - ('active' if self.serial.dsr else 'inactive'), - ('active' if self.serial.ri else 'inactive'), - ('active' if self.serial.cd else 'inactive'))) - except serial.SerialException: - # on RFC 2217 ports, it can happen if no modem state notification was - # yet received. ignore this error. - pass - sys.stderr.write('--- software flow control: {}\n'.format('active' if self.serial.xonxoff else 'inactive')) - sys.stderr.write('--- hardware flow control: {}\n'.format('active' if self.serial.rtscts else 'inactive')) - sys.stderr.write('--- serial input encoding: {}\n'.format(self.input_encoding)) - sys.stderr.write('--- serial output encoding: {}\n'.format(self.output_encoding)) - sys.stderr.write('--- EOL: {}\n'.format(self.eol.upper())) - sys.stderr.write('--- filters: {}\n'.format(' '.join(self.filters))) - - def reader(self): - """loop and copy serial->console""" - try: - while self.alive and self._reader_alive: - # read all that is there or wait for one byte - data = self.serial.read(self.serial.in_waiting or 1) - if data: - if self.raw: - self.console.write_bytes(data) - else: - text = self.rx_decoder.decode(data) - for transformation in self.rx_transformations: - text = transformation.rx(text) - self.console.write(text) - except serial.SerialException: - self.alive = False - self.console.cancel() - raise # XXX handle instead of re-raise? - - def writer(self): - """\ - Loop and copy console->serial until self.exit_character character is - found. When self.menu_character is found, interpret the next key - locally. - """ - menu_active = False - try: - while self.alive: - try: - c = self.console.getkey() - except KeyboardInterrupt: - c = '\x03' - if not self.alive: - break - if menu_active: - self.handle_menu_key(c) - menu_active = False - elif c == self.menu_character: - menu_active = True # next char will be for menu - elif c == self.exit_character: - self.stop() # exit app - break - else: - #~ if self.raw: - text = c - for transformation in self.tx_transformations: - text = transformation.tx(text) - self.serial.write(self.tx_encoder.encode(text)) - if self.echo: - echo_text = c - for transformation in self.tx_transformations: - echo_text = transformation.echo(echo_text) - self.console.write(echo_text) - except: - self.alive = False - raise - - def handle_menu_key(self, c): - """Implement a simple menu / settings""" - if c == self.menu_character or c == self.exit_character: - # Menu/exit character again -> send itself - self.serial.write(self.tx_encoder.encode(c)) - if self.echo: - self.console.write(c) - elif c == '\x15': # CTRL+U -> upload file - sys.stderr.write('\n--- File to upload: ') - sys.stderr.flush() - with self.console: - filename = sys.stdin.readline().rstrip('\r\n') - if filename: - try: - with open(filename, 'rb') as f: - sys.stderr.write('--- Sending file {} ---\n'.format(filename)) - while True: - block = f.read(1024) - if not block: - break - self.serial.write(block) - # Wait for output buffer to drain. - self.serial.flush() - sys.stderr.write('.') # Progress indicator. - sys.stderr.write('\n--- File {} sent ---\n'.format(filename)) - except IOError as e: - sys.stderr.write('--- ERROR opening file {}: {} ---\n'.format(filename, e)) - elif c in '\x08hH?': # CTRL+H, h, H, ? -> Show help - sys.stderr.write(self.get_help_text()) - elif c == '\x12': # CTRL+R -> Toggle RTS - self.serial.rts = not self.serial.rts - sys.stderr.write('--- RTS {} ---\n'.format('active' if self.serial.rts else 'inactive')) - elif c == '\x04': # CTRL+D -> Toggle DTR - self.serial.dtr = not self.serial.dtr - sys.stderr.write('--- DTR {} ---\n'.format('active' if self.serial.dtr else 'inactive')) - elif c == '\x02': # CTRL+B -> toggle BREAK condition - self.serial.break_condition = not self.serial.break_condition - sys.stderr.write('--- BREAK {} ---\n'.format('active' if self.serial.break_condition else 'inactive')) - elif c == '\x05': # CTRL+E -> toggle local echo - self.echo = not self.echo - sys.stderr.write('--- local echo {} ---\n'.format('active' if self.echo else 'inactive')) - elif c == '\x06': # CTRL+F -> edit filters - sys.stderr.write('\n--- Available Filters:\n') - sys.stderr.write('\n'.join( - '--- {:<10} = {.__doc__}'.format(k, v) - for k, v in sorted(TRANSFORMATIONS.items()))) - sys.stderr.write('\n--- Enter new filter name(s) [{}]: '.format(' '.join(self.filters))) - with self.console: - new_filters = sys.stdin.readline().lower().split() - if new_filters: - for f in new_filters: - if f not in TRANSFORMATIONS: - sys.stderr.write('--- unknown filter: {}\n'.format(repr(f))) - break - else: - self.filters = new_filters - self.update_transformations() - sys.stderr.write('--- filters: {}\n'.format(' '.join(self.filters))) - elif c == '\x0c': # CTRL+L -> EOL mode - modes = list(EOL_TRANSFORMATIONS) # keys - eol = modes.index(self.eol) + 1 - if eol >= len(modes): - eol = 0 - self.eol = modes[eol] - sys.stderr.write('--- EOL: {} ---\n'.format(self.eol.upper())) - self.update_transformations() - elif c == '\x01': # CTRL+A -> set encoding - sys.stderr.write('\n--- Enter new encoding name [{}]: '.format(self.input_encoding)) - with self.console: - new_encoding = sys.stdin.readline().strip() - if new_encoding: - try: - codecs.lookup(new_encoding) - except LookupError: - sys.stderr.write('--- invalid encoding name: {}\n'.format(new_encoding)) - else: - self.set_rx_encoding(new_encoding) - self.set_tx_encoding(new_encoding) - sys.stderr.write('--- serial input encoding: {}\n'.format(self.input_encoding)) - sys.stderr.write('--- serial output encoding: {}\n'.format(self.output_encoding)) - elif c == '\x09': # CTRL+I -> info - self.dump_port_settings() - #~ elif c == '\x01': # CTRL+A -> cycle escape mode - #~ elif c == '\x0c': # CTRL+L -> cycle linefeed mode - elif c in 'pP': # P -> change port - with self.console: - try: - port = ask_for_port() - except KeyboardInterrupt: - port = None - if port and port != self.serial.port: - # reader thread needs to be shut down - self._stop_reader() - # save settings - settings = self.serial.getSettingsDict() - try: - new_serial = serial.serial_for_url(port, do_not_open=True) - # restore settings and open - new_serial.applySettingsDict(settings) - new_serial.rts = self.serial.rts - new_serial.dtr = self.serial.dtr - new_serial.open() - new_serial.break_condition = self.serial.break_condition - except Exception as e: - sys.stderr.write('--- ERROR opening new port: {} ---\n'.format(e)) - new_serial.close() - else: - self.serial.close() - self.serial = new_serial - sys.stderr.write('--- Port changed to: {} ---\n'.format(self.serial.port)) - # and restart the reader thread - self._start_reader() - elif c in 'bB': # B -> change baudrate - sys.stderr.write('\n--- Baudrate: ') - sys.stderr.flush() - with self.console: - backup = self.serial.baudrate - try: - self.serial.baudrate = int(sys.stdin.readline().strip()) - except ValueError as e: - sys.stderr.write('--- ERROR setting baudrate: {} ---\n'.format(e)) - self.serial.baudrate = backup - else: - self.dump_port_settings() - elif c == '8': # 8 -> change to 8 bits - self.serial.bytesize = serial.EIGHTBITS - self.dump_port_settings() - elif c == '7': # 7 -> change to 8 bits - self.serial.bytesize = serial.SEVENBITS - self.dump_port_settings() - elif c in 'eE': # E -> change to even parity - self.serial.parity = serial.PARITY_EVEN - self.dump_port_settings() - elif c in 'oO': # O -> change to odd parity - self.serial.parity = serial.PARITY_ODD - self.dump_port_settings() - elif c in 'mM': # M -> change to mark parity - self.serial.parity = serial.PARITY_MARK - self.dump_port_settings() - elif c in 'sS': # S -> change to space parity - self.serial.parity = serial.PARITY_SPACE - self.dump_port_settings() - elif c in 'nN': # N -> change to no parity - self.serial.parity = serial.PARITY_NONE - self.dump_port_settings() - elif c == '1': # 1 -> change to 1 stop bits - self.serial.stopbits = serial.STOPBITS_ONE - self.dump_port_settings() - elif c == '2': # 2 -> change to 2 stop bits - self.serial.stopbits = serial.STOPBITS_TWO - self.dump_port_settings() - elif c == '3': # 3 -> change to 1.5 stop bits - self.serial.stopbits = serial.STOPBITS_ONE_POINT_FIVE - self.dump_port_settings() - elif c in 'xX': # X -> change software flow control - self.serial.xonxoff = (c == 'X') - self.dump_port_settings() - elif c in 'rR': # R -> change hardware flow control - self.serial.rtscts = (c == 'R') - self.dump_port_settings() - else: - sys.stderr.write('--- unknown menu character {} --\n'.format(key_description(c))) - - def get_help_text(self): - """return the help text""" - # help text, starts with blank line! - return """ ---- pySerial ({version}) - miniterm - help ---- ---- {exit:8} Exit program ---- {menu:8} Menu escape key, followed by: ---- Menu keys: ---- {menu:7} Send the menu character itself to remote ---- {exit:7} Send the exit character itself to remote ---- {info:7} Show info ---- {upload:7} Upload file (prompt will be shown) ---- {repr:7} encoding ---- {filter:7} edit filters ---- Toggles: ---- {rts:7} RTS {dtr:7} DTR {brk:7} BREAK ---- {echo:7} echo {eol:7} EOL ---- ---- Port settings ({menu} followed by the following): ---- p change port ---- 7 8 set data bits ---- N E O S M change parity (None, Even, Odd, Space, Mark) ---- 1 2 3 set stop bits (1, 2, 1.5) ---- b change baud rate ---- x X disable/enable software flow control ---- r R disable/enable hardware flow control -""".format(version=getattr(serial, 'VERSION', 'unknown version'), - exit=key_description(self.exit_character), - menu=key_description(self.menu_character), - rts=key_description('\x12'), - dtr=key_description('\x04'), - brk=key_description('\x02'), - echo=key_description('\x05'), - info=key_description('\x09'), - upload=key_description('\x15'), - repr=key_description('\x01'), - filter=key_description('\x06'), - eol=key_description('\x0c')) - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# 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): - """Command line tool, entry point""" - - import argparse - - parser = argparse.ArgumentParser( - description="Miniterm - A simple terminal program for the serial port.") - - parser.add_argument( - "port", - nargs='?', - help="serial port name ('-' to show port list)", - default=default_port) - - parser.add_argument( - "baudrate", - nargs='?', - type=int, - help="set baud rate, default: %(default)s", - default=default_baudrate) - - group = parser.add_argument_group("port settings") - - group.add_argument( - "--parity", - choices=['N', 'E', 'O', 'S', 'M'], - type=lambda c: c.upper(), - help="set parity, one of {N E O S M}, default: N", - default='N') - - group.add_argument( - "--rtscts", - action="store_true", - help="enable RTS/CTS flow control (default off)", - default=False) - - group.add_argument( - "--xonxoff", - action="store_true", - help="enable software flow control (default off)", - default=False) - - group.add_argument( - "--rts", - type=int, - help="set initial RTS line state (possible values: 0, 1)", - default=default_rts) - - group.add_argument( - "--dtr", - type=int, - help="set initial DTR line state (possible values: 0, 1)", - default=default_dtr) - - group.add_argument( - "--ask", - action="store_true", - help="ask again for port when open fails", - default=False) - - group = parser.add_argument_group("data handling") - - group.add_argument( - "-e", "--echo", - action="store_true", - help="enable local echo (default off)", - default=False) - - group.add_argument( - "--encoding", - dest="serial_port_encoding", - metavar="CODEC", - help="set the encoding for the serial port (e.g. hexlify, Latin1, UTF-8), default: %(default)s", - default='UTF-8') - - group.add_argument( - "-f", "--filter", - action="append", - metavar="NAME", - help="add text transformation", - default=[]) - - group.add_argument( - "--eol", - choices=['CR', 'LF', 'CRLF'], - type=lambda c: c.upper(), - help="end of line mode", - default='CRLF') - - group.add_argument( - "--raw", - action="store_true", - help="Do no apply any encodings/transformations", - default=False) - - group = parser.add_argument_group("hotkeys") - - group.add_argument( - "--exit-char", - type=int, - metavar='NUM', - help="Unicode of special character that is used to exit the application, default: %(default)s", - default=0x1d) # GS/CTRL+] - - group.add_argument( - "--menu-char", - type=int, - metavar='NUM', - help="Unicode code of special character that is used to control miniterm (menu), default: %(default)s", - default=0x14) # Menu: CTRL+T - - group = parser.add_argument_group("diagnostics") - - group.add_argument( - "-q", "--quiet", - action="store_true", - help="suppress non-error messages", - default=False) - - group.add_argument( - "--develop", - action="store_true", - help="show Python traceback on error", - default=False) - - args = parser.parse_args() - - if args.menu_char == args.exit_char: - parser.error('--exit-char can not be the same as --menu-char') - - if args.filter: - if 'help' in args.filter: - sys.stderr.write('Available filters:\n') - sys.stderr.write('\n'.join( - '{:<10} = {.__doc__}'.format(k, v) - for k, v in sorted(TRANSFORMATIONS.items()))) - sys.stderr.write('\n') - sys.exit(1) - filters = args.filter - else: - filters = ['default'] - - while True: - # no port given on command line -> ask user now - if args.port is None or args.port == '-': - try: - args.port = ask_for_port() - except KeyboardInterrupt: - sys.stderr.write('\n') - parser.error('user aborted and port is not given') - else: - if not args.port: - parser.error('port is not given') - try: - serial_instance = serial.serial_for_url( - args.port, - args.baudrate, - parity=args.parity, - rtscts=args.rtscts, - xonxoff=args.xonxoff, - do_not_open=True) - - if not hasattr(serial_instance, 'cancel_read'): - # enable timeout for alive flag polling if cancel_read is not available - serial_instance.timeout = 1 - - if args.dtr is not None: - if not args.quiet: - sys.stderr.write('--- forcing DTR {}\n'.format('active' if args.dtr else 'inactive')) - serial_instance.dtr = args.dtr - if args.rts is not None: - if not args.quiet: - sys.stderr.write('--- forcing RTS {}\n'.format('active' if args.rts else 'inactive')) - serial_instance.rts = args.rts - - serial_instance.open() - except serial.SerialException as e: - sys.stderr.write('could not open port {}: {}\n'.format(repr(args.port), e)) - if args.develop: - raise - if not args.ask: - sys.exit(1) - else: - args.port = '-' - else: - break - - miniterm = Miniterm( - serial_instance, - echo=args.echo, - eol=args.eol.lower(), - filters=filters) - miniterm.exit_character = unichr(args.exit_char) - miniterm.menu_character = unichr(args.menu_char) - miniterm.raw = args.raw - miniterm.set_rx_encoding(args.serial_port_encoding) - miniterm.set_tx_encoding(args.serial_port_encoding) - - if not args.quiet: - sys.stderr.write('--- Miniterm on {p.name} {p.baudrate},{p.bytesize},{p.parity},{p.stopbits} ---\n'.format( - p=miniterm.serial)) - sys.stderr.write('--- Quit: {} | Menu: {} | Help: {} followed by {} ---\n'.format( - key_description(miniterm.exit_character), - key_description(miniterm.menu_character), - key_description(miniterm.menu_character), - key_description('\x08'))) - - miniterm.start() - try: - miniterm.join(True) - except KeyboardInterrupt: - pass - if not args.quiet: - sys.stderr.write("\n--- exit ---\n") - miniterm.join() - miniterm.close() - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -if __name__ == '__main__': - main() diff --git a/mFIZ/scripts/mFIZ_extern/serial/urlhandler/protocol_alt.py b/mFIZ/scripts/mFIZ_extern/serial/urlhandler/protocol_alt.py deleted file mode 100644 index c14a87e..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/urlhandler/protocol_alt.py +++ /dev/null @@ -1,55 +0,0 @@ -#! python -# -# This module implements a special URL handler that allows selecting an -# alternate implementation provided by some backends. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause -# -# URL format: alt://port[?option[=value][&option[=value]]] -# options: -# - class=X used class named X instead of Serial -# -# example: -# use poll based implementation on Posix (Linux): -# python -m serial.tools.miniterm alt:///dev/ttyUSB0?class=PosixPollSerial - -try: - import urlparse -except ImportError: - import urllib.parse as urlparse - -import serial - - -def serial_class_for_url(url): - """extract host and port from an URL string""" - parts = urlparse.urlsplit(url) - if parts.scheme != 'alt': - raise serial.SerialException( - 'expected a string in the form "alt://port[?option[=value][&option[=value]]]": ' - 'not starting with alt:// ({!r})'.format(parts.scheme)) - class_name = 'Serial' - try: - for option, values in urlparse.parse_qs(parts.query, True).items(): - if option == 'class': - class_name = values[0] - else: - raise ValueError('unknown option: {!r}'.format(option)) - except ValueError as e: - raise serial.SerialException( - 'expected a string in the form ' - '"alt://port[?option[=value][&option[=value]]]": {!r}'.format(e)) - if not hasattr(serial, class_name): - raise ValueError('unknown class: {!r}'.format(class_name)) - cls = getattr(serial, class_name) - if not issubclass(cls, serial.Serial): - raise ValueError('class {!r} is not an instance of Serial'.format(class_name)) - return (''.join([parts.netloc, parts.path]), cls) - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -if __name__ == '__main__': - s = serial.serial_for_url('alt:///dev/ttyS0?class=PosixPollSerial') - print(s) diff --git a/mFIZ/scripts/mFIZ_extern/serial/urlhandler/protocol_hwgrep.py b/mFIZ/scripts/mFIZ_extern/serial/urlhandler/protocol_hwgrep.py deleted file mode 100644 index 49bbebe..0000000 --- a/mFIZ/scripts/mFIZ_extern/serial/urlhandler/protocol_hwgrep.py +++ /dev/null @@ -1,89 +0,0 @@ -#! python -# -# This module implements a special URL handler that uses the port listing to -# find ports by searching the string descriptions. -# -# This file is part of pySerial. https://github.com/pyserial/pyserial -# (C) 2011-2015 Chris Liechti -# -# SPDX-License-Identifier: BSD-3-Clause -# -# URL format: hwgrep://&