pyserial-2.6/0000755000175000017500000000000011654115151012547 5ustar lchlch00000000000000pyserial-2.6/CHANGES.txt0000644000175000017500000003260411654113646014374 0ustar lchlch00000000000000======================== pySerial Release Notes ======================== Version 1.0 13 Feb 2002 --------------------------- - First public release. - Split from the pybsl application (see http://mspgcc.sourceforge.net) New Features: - Added Jython support Version 1.1 14 Feb 2002 --------------------------- Bugfixes: - Win32, when not specifying a timeout - Typos in the Docs New Features: - added ``serialutil`` which provides a base class for the ``Serial`` objects. - ``readline``, ``readlines``, ``writelines`` and ``flush`` are now supported see README.txt for deatils. Version 1.11 14 Feb 2002 --------------------------- Same as 1.1 but added missing files. Version 1.12 18 Feb 2002 --------------------------- Removed unneded constants to fix RH7.x problems. Version 1.13 09 Apr 2002 --------------------------- Added alternate way for enabling rtscts (CNEW_RTSCTS is tried too) If port opening fails, a ``SerialException`` is raised on all platforms Version 1.14 29 May 2002 --------------------------- Added examples to archive Added non-blocking mode for ``timeout=0`` (tnx Mat Martineau) Bugfixes: - win32 does now return the remaining characters on timeout Version 1.15 04 Jun 2002 --------------------------- Bugfixes (win32): - removed debug messages - compatibility to win9x improved Version 1.16 02 Jul 2002 --------------------------- Added implementation of RI and corrected RTS/CTS on Win32 Version 1.17 03 Jul 2002 --------------------------- Silly mix of two versions in win32 code corrected Version 1.18 06 Dec 2002 --------------------------- Bugfixes (general): - remove the mapping of flush to the destructive flushOutput as this is not the expected behaviour. - readline: EOL character for lines can be chosen idea by John Florian. Bugfixes (posix): - cygwin port numbering fixed - test each and every constant for it's existence in termios module, use default if not existent (fix for Bug item #640214) - wrong exception on nonexistent ports with /dev file. bug report by Louis Cordier Bugfixes (win32): - RTS/CTS handling as suggested in Bug #635072 - bugfix of timeouts brought up by Markus Hoffrogge Version 1.19 19 Mar 2003 --------------------------- Bugfixes (posix): - removed ``dgux`` entry which actually had a wrong comment and is probably not in use anywhere. Bugfixes (win32): - added ``int()`` conversion, [Bug 702120] - remove code to set control lines in close method of win32 version. [Bug 669625] Version 1.20 28 Aug 2003 --------------------------- - Added ``serial.device()`` for all platforms Bugfixes (win32): - don't recreate overlapped structures and events on each read/write. - don't set unneeded event masks. - dont use DOS device names for ports > 9. - remove send timeout (its not used in the linux impl. anyway). Version 1.21 30 Sep 2003 --------------------------- Bugfixes (win32): - name for COM10 was not built correctly, found by Norm Davis. Bugfixes (examples): - small change in ``miniterm.py`` that should mage it run on cygwin, [Bug 809904] submitted by Rolf Campbell. Version 2.0b1 1 Oct 2003 --------------------------- Transition to the Python 2.0 series: - New implementation only supports Python 2.2+, backwards compatibility should be maintained almost everywhere. The OS handles (like the ``hComPort`` or ``fd`` attribute) were prefixed with an underscore. The different names stay, as anyone that uses one of these has to write platform specific code anyway. - Common base class ``serialutil.SerialBase`` for all implementations. - ``PARITY_NONE``, ``PARITY_EVEN``, ``PARITY_ODD`` constants changed and all these constants moved to ``serialutil.py`` (still available as ``serial.PARITY_NONE`` etc. and they should be used that way) - Added ``serial.PARITY_NAMES`` (implemented in ``serialutil.PARITY_NAMES``). This dictionary can be used to convert parity constants to meaningful strings. - Each Serial class and instance has a list of supported values: ``BAUDRATES``, ``BYTESIZES``, ``PARITIES``, ``STOPBITS``Ggg (i.e. ``serial.Serial.BAUDRATES or s = serial.Serial; s.BAUDRATES``) these values can be used to fill in value sin GUI dialogs etc. - Creating a ``Serial()`` object without port spec returns an unconfigured, closed port. Useful if a GUI dialog should take a port and configure it. - New methods for ``serial.Serial`` instances: ``open()``, ``isOpen()`` - A port can be opened and closed as many times as desired. - Instances of ``serial.Serial`` have ``baudrate``, ``bytesize``, ``timeout`` etc. attributes implemented as properties, all can be set while the port is opened. It will then be reconfigured. - Improved ``__doc__``'s. - New ``test_advanced.py`` for the property setting/getting testing. - Small bugfix on posix with get* methods (return value should be true a boolean). - added a ``__repr__`` that returns a meaningful string will all the serial setting, easy for debugging. - The serialposix module does not throw an exception on unsupported platforms, the message is still printed. The idea that it may still work even if the platform itself s not known, it simply tries to do the posix stuff anyway (It's likely that opening ports by number fails, but by name it should work). Version 2.0b2 4 Oct 2003 --------------------------- - Added serial port configuration dialog for wxPython to the examples. - Added terminal application for wxPython with wxGlade design file to the examples. - Jython support is currently broken as Jython does not have a Python 2.2 compatible release out yet Version 2.0 6 Nov 2003 --------------------------- - Fixes ``setup.py`` for older distutils Version 2.1 28 Jul 2004 --------------------------- Bugfixes: - Fix XON/XOFF values [Bug 975250] Bugfixes (posix): - ``fd == 0`` fix from Vsevolod Lobko - netbsd fixes from Erik Lindgren - Dynamicaly lookup baudrates and some cleanups Bugfixes (examples): - CRLF handling of ``miniterm.py`` should be more consistent on Win32 and others. Added LF only command line option - Multithreading fixes to ``wxTerminal.py`` (helps with wxGTK) - Small change for wxPython 2.5 in ``wxSerialConfigDialog.py`` [Bug 994856] New Features: - Implement write timeouts (``writeTimeout`` parameter) Version 2.2 31 Jul 2005 --------------------------- Bugfixes: - [Bug 1014227]: property broken - [Bug 1105687]: ``serial_tcp_example.py``: ``--localport`` option - [Bug 1106313]: device (port) strings cannot be unicode Bugfixes (posix): - [Patch 1043436] Fix for [Bug 1043420] (OSError: EAGAIN) - [Patch 1102700] ``fileno()`` added - ensure disabled PARMRK Bugfixes (win32): - [Patch 983106]: keep RTS/CTS state on port setting changes New Features: - ``dsrdtr`` setting to enable/disable DSR/DTR flow control independently from the ``rtscts`` setting. (Currenly Win32 only, ignored on other platforms) Version 2.3 19 Jun 2008 --------------------------- New Features: - iterator interface. ``for line in Serial(...): ...`` is now possible Suggested by Bernhard Bender - ``sendBreak()`` accepts a ``duration`` argument. Default duration increased. - win32 handles \\.\COMx format automatically for com ports of higher number (COM10 is internally translated to \\.\COM10 etc.) - miniterm.py has a new feature to send a file (upload) and configurable special characters for exit and upload. Refactored internals to class based structure (upload and class refactoring by Colin D Bennett) Bugfixes: - [Bug 1451535] TCP/serial redirect example "--help" - update VERSION variable - update wxSerialConfigDialog.py and wxTerminal.py compatibility with wxPython 2.8 (Peleg) - Check for string in write function. Using unicode causes errors, this helps catching errors early (Tom Lynn) Bugfixes (posix): - [Bug 1554183] setRTS/setDTR reference to non existing local "on" - [Bug 1513653] file descriptor not closed when exception is thrown - FreeBSD now uses cuadX instead of cuaaX (Patrick Phalen) Bugfixes (win32): - [Bug 1520357] Handle leak - [Bug 1679013] Ignore exception raised by SetCommTimeout() in close(). - [Bug 1938118] process hang forever under XP Version 2.4 6 Jul 2008 --------------------------- New Features: - [Patch 1616790] pyserial: Add inter-character timeout feature - [Patch 1924805] add a setBreak function - Add mark/space parity - Add .NET/Mono backend (IronPython) Bugfixes (posix): - [Bug 1783159] Arbitrary baud rates (Linux/Posix) Bugfixes (win32): - [Patch 1561423] Add mark/space parity, Win32 - [Bug 2000771] serial port CANNOT be specified by number on windows - examples/scanwin32.py does no longer return \\.\ names - fix \\.\ handling for some cases Bugfixes (jython): - The Jython backend tries javax.comm and gnu.io (Seo Sanghyeon) Version 2.5-rc1 2009-07-30 --------------------------- New Features: - Python 3.x support (through 2to3) - compatible with Python io library (Python 2.6+) - Support for Win32 is now written on the top of ctypes (bundled with Python 2.5+) instead of pywin32 (patch by Giovanni Bajo). - 1.5 stop bits (STOPBITS_ONE_POINT_FIVE, implemented on all platforms) - miniterm application extended (CTRL+T -> menu) - miniterm.py is now installed as "script" - add scanlinux.py example - add port_publisher example - experimental RFC-2217 server support (examples/rfc2217_server.py) - add ``getSettingsDict`` and ``applySettingsDict`` serial object methods - use a ``poll`` based implementation on Posix, instead of a ``select`` based, provides better error handling [removed again in later releases]. Bugfixes: - Improve and fix tcp_serial_redirector example. - [Bug 2603052] 5-bit mode (needs 1.5 stop bits in some cases) Bugfixes (posix): - [Bug 2810169] Propagate exceptions raised in serialposix _reconfigure - [Bug 2562610] setting non standard baud rates on Darwin (Emmanuel Blot) Bugfixes (win32): - [Bug 2469098] parity PARITY_MARK, PARITY_SPACE isn't supported on win32 - [SF 2446218] outWaiting implemented - [Bug 2392892] scanwin32.py better exception handling - [Bug 2505422] scanwin32.py Vista 64bit compatibility Version 2.5-rc2 2010-01-02 --------------------------- New Features: - Documentation update, now written with Sphinx/ReST - Updated miniterm.py example - experimental RFC-2217 client support (serial.rfc2217.Serial, see docs) - add ``loop://`` device for testing. - add ``serial.serial_for_url`` factory function (support for native ports and ``rfc2217``, ``socket`` and ``loop`` URLs) - add new example: ``rfc2217_server.py`` - tests live in their own directory now (no longer in examples) Bugfixes: - [Bug 2915810] Fix for suboption parsing in rfc2217 - Packaging bug (missed some files) Bugfixes (posix): - improve write timeout behavior - [Bug 2836297] move Linux specific constants to not break other platforms - ``poll`` based implementation for ``read`` is in a separate class ``PosixPollSerial``, as it is not supported well on all platforms (the default ``Serial`` class uses select). - changed error handling in ``read`` so that disconnected devices are detected. Bugfixes (win32): - [Bug 2886763] hComPort doesn't get initialized for Serial(port=None) Version 2.5 2010-07-22 --------------------------- New Features: - [Bug 2976262] dsrdtr should default to False ``dsrdtr`` parameter default value changed from ``None`` (follow ``rtscts`` setting) to ``False``. This means ``rtscts=True`` enables hardware flow control on RTS/CTS but no longer also on DTR/DSR. This change mostly affects Win32 as on other platforms, that setting was ignored anyway. - Improved xreadlines, it is now a generator function that yields lines as they are received (previously it called readlines which would only return all lines read after a read-timeout). However xreadlines is deprecated an not available when the io module is used. Use ``for line in Serial(...):`` instead. Bugfixes: - [Bug 2925854] test.py produces exception with python 3.1 - [Bug 3029812] 2.5rc2 readline(s) doesn't work Bugfixes (posix): - [BUG 3006606] Nonblocking error - Unix platform Bugfixes (win32): - [Bug 2998169] Memory corruption at faster transmission speeds. (bug introduced in 2.5-rc1) Version 2.6 2011-11-02 --------------------------- New Features: - Moved some of the examples to serial.tools so that they can be used with ``python -m`` - serial port enumeration now included as ``serial.tools.list_ports`` - URL handers for ``serial_for_url`` are now imported dynamically. This allows to add protocols w/o editing files. The list ``serial.protocol_handler_packages`` can be used to add or remove user packages with protocol handlers (see docs for details). - new URL type: hwgrep:// uses list_ports module to search for ports by their description - serveral internal changes to improve Python 3.x compatibility (setup.py, use of absolute imports and more) Bugfixes: - [Bug 3093882] calling open() on an already open port now raises an exception - [Bug 3245627] connection-lost let rfc2217 hangs in closed loop - [Patch 3147043] readlines() to support multi-character eol Bugfixes (posix): - [Patch 3316943] Avoid unneeded termios.tcsetattr calls in serialposix.py - [Patch 2912349] Serial Scan as a Module with Mac Support Bugfixes (win32): - [Bug 3057499] writeTimeoutError when write Timeout is 0 - [Bug 3414327] Character out of range in list_ports_windows - [Patch 3036175] Windows 98 Support fix - [Patch 3054352] RTS automatic toggle, for RS485 functionality. - Fix type definitions for 64 bit Windows compatibility pyserial-2.6/README.txt0000644000175000017500000000232511620304016014240 0ustar lchlch00000000000000========== pySerial ========== Overview ======== This module encapsulates the access for the serial port. It provides backends for Python running on Windows, Linux, BSD (possibly any POSIX compliant system), Jython and IronPython (.NET and Mono). The module named "serial" automatically selects the appropriate backend. - Project Homepage: http://pyserial.sourceforge.net - Project page on SourceForge: http://sourceforge.net/projects/pyserial/ - SVN repository: http://sourceforge.net/svn/?group_id=46487 - Download Page: http://sourceforge.net/project/showfiles.php?group_id=46487 BSD license, (C) 2001-2011 Chris Liechti Documentation ============= For API documentation, usage and examples see files in the "documentation" directory. The ".rst" files can be read in any text editor or being converted to HTML or PDF using Sphinx. An online HTML version is at http://pyserial.sourceforge.net. Examples ======== Examples and unit tests are in the directory "examples". Installation ============ Detailed information can be found in "documentation/pyserial.rst". The usual setup.py for Python libraries is used for the source distribution. Windows installers are also available (see download link above). pyserial-2.6/MANIFEST.in0000644000175000017500000000171011421701370014300 0ustar lchlch00000000000000include README.txt include LICENSE.txt include CHANGES.txt include MANIFEST.in include setup.py include examples/enhancedserial.py include examples/miniterm.py include examples/port_publisher.py include examples/port_publisher.sh include examples/rfc2217_server.py include examples/scan.py include examples/scanlinux.py include examples/scanwin32.py include examples/setup-miniterm-py2exe.py include examples/setup-rfc2217_server-py2exe.py include examples/setup-wxTerminal-py2exe.py include examples/tcp_serial_redirect.py include examples/wxSerialConfigDialog.py include examples/wxSerialConfigDialog.wxg include examples/wxTerminal.py include examples/wxTerminal.wxg include test/run_all_tests.py include test/test.py include test/test_advanced.py include test/test_high_load.py include test/test_io_lib.py include test/test_readline.py include documentation/*.rst include documentation/pyserial.png include documentation/conf.py include documentation/Makefile pyserial-2.6/examples/0000755000175000017500000000000011654115151014365 5ustar lchlch00000000000000pyserial-2.6/examples/setup-miniterm-py2exe.py0000644000175000017500000000114111534046605021134 0ustar lchlch00000000000000# setup script for py2exe to create the miniterm.exe # $Id: setup-miniterm-py2exe.py,v 1.1 2005-09-21 19:51:19 cliechti Exp $ from distutils.core import setup import glob, sys, py2exe, os sys.path.append('..') sys.argv.extend("py2exe --bundle 1".split()) import serial.tools.miniterm setup( name = 'miniterm', zipfile = None, options = {"py2exe": { 'dist_dir': 'bin', 'excludes': ['serialjava', 'serialposix', 'serialcli'], 'compressed': 1, } }, console = [ #~ "miniterm.py", serial.tools.miniterm.__file__ ], ) pyserial-2.6/examples/port_publisher.sh0000644000175000017500000000203611231743646017772 0ustar lchlch00000000000000#! /bin/sh # daemon starter script # based on skeleton from Debian GNU/Linux # cliechti at gmx.net PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/local/bin/port_publisher.py NAME=port_publisher DESC="serial port avahi device publisher" test -f $DAEMON || exit 0 set -e case "$1" in start) echo -n "Starting $DESC: " $DAEMON --daemon --pidfile /var/run/$NAME.pid echo "$NAME." ;; stop) echo -n "Stopping $DESC: " start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid # \ --exec $DAEMON echo "$NAME." ;; restart|force-reload) echo -n "Restarting $DESC: " start-stop-daemon --stop --quiet --pidfile \ /var/run/$NAME.pid # --exec $DAEMON sleep 1 $DAEMON --daemon --pidfile /var/run/$NAME.pid echo "$NAME." ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|restart|force-reload}" >&2 exit 1 ;; esac exit 0 pyserial-2.6/examples/wxTerminal.wxg0000644000175000017500000001301511026531632017245 0ustar lchlch00000000000000 Serial Terminal 1 546, 383 wxVERTICAL wxEXPAND 0 ID_CLEAR ID_SAVEAS --- --- ID_SETTINGS ID_TERM --- ID_EXIT Terminal Settings wxVERTICAL wxEXPAND 0 wxVERTICAL wxALL 4 wxALL 4 0 0 0 CR only LF only CR+LF wxALL|wxALIGN_RIGHT 4 wxHORIZONTAL 0 1 0 pyserial-2.6/examples/enhancedserial.py0000644000175000017500000000417111026531632017706 0ustar lchlch00000000000000#!/usr/bin/env python """Enhanced Serial Port class part of pyserial (http://pyserial.sf.net) (C)2002 cliechti@gmx.net another implementation of the readline and readlines method. this one should be more efficient because a bunch of characters are read on each access, but the drawback is that a timeout must be specified to make it work (enforced by the class __init__). this class could be enhanced with a read_until() method and more like found in the telnetlib. """ from serial import Serial class EnhancedSerial(Serial): def __init__(self, *args, **kwargs): #ensure that a reasonable timeout is set timeout = kwargs.get('timeout',0.1) if timeout < 0.01: timeout = 0.1 kwargs['timeout'] = timeout Serial.__init__(self, *args, **kwargs) self.buf = '' def readline(self, maxsize=None, timeout=1): """maxsize is ignored, timeout in seconds is the max time that is way for a complete line""" tries = 0 while 1: self.buf += self.read(512) pos = self.buf.find('\n') if pos >= 0: line, self.buf = self.buf[:pos+1], self.buf[pos+1:] return line tries += 1 if tries * self.timeout > timeout: break line, self.buf = self.buf, '' return line def readlines(self, sizehint=None, timeout=1): """read all lines that are available. abort after timout when no more data arrives.""" lines = [] while 1: line = self.readline(timeout=timeout) if line: lines.append(line) if not line or line[-1:] != '\n': break return lines if __name__=='__main__': #do some simple tests with a Loopback HW (see test.py for details) PORT = 0 #test, only with Loopback HW (shortcut RX/TX pins (3+4 on DSUB 9 and 25) ) s = EnhancedSerial(PORT) #write out some test data lines s.write('\n'.join("hello how are you".split())) #and read them back print s.readlines() #this one should print an empty list print s.readlines(timeout=0.4) pyserial-2.6/examples/scanwin32.py0000644000175000017500000001763411237073002016554 0ustar lchlch00000000000000import ctypes import re def ValidHandle(value): if value == 0: raise ctypes.WinError() return value NULL = 0 HDEVINFO = ctypes.c_int BOOL = ctypes.c_int CHAR = ctypes.c_char PCTSTR = ctypes.c_char_p HWND = ctypes.c_uint DWORD = ctypes.c_ulong PDWORD = ctypes.POINTER(DWORD) ULONG = ctypes.c_ulong ULONG_PTR = ctypes.POINTER(ULONG) #~ PBYTE = ctypes.c_char_p PBYTE = ctypes.c_void_p class GUID(ctypes.Structure): _fields_ = [ ('Data1', ctypes.c_ulong), ('Data2', ctypes.c_ushort), ('Data3', ctypes.c_ushort), ('Data4', ctypes.c_ubyte*8), ] def __str__(self): return "{%08x-%04x-%04x-%s-%s}" % ( self.Data1, self.Data2, self.Data3, ''.join(["%02x" % d for d in self.Data4[:2]]), ''.join(["%02x" % 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:%s DevInst:%s" % (self.ClassGuid, self.DevInst) PSP_DEVINFO_DATA = ctypes.POINTER(SP_DEVINFO_DATA) class SP_DEVICE_INTERFACE_DATA(ctypes.Structure): _fields_ = [ ('cbSize', DWORD), ('InterfaceClassGuid', GUID), ('Flags', DWORD), ('Reserved', ULONG_PTR), ] def __str__(self): return "InterfaceClassGuid:%s Flags:%s" % (self.InterfaceClassGuid, self.Flags) PSP_DEVICE_INTERFACE_DATA = ctypes.POINTER(SP_DEVICE_INTERFACE_DATA) PSP_DEVICE_INTERFACE_DETAIL_DATA = ctypes.c_void_p class dummy(ctypes.Structure): _fields_=[("d1", DWORD), ("d2", CHAR)] _pack_ = 1 SIZEOF_SP_DEVICE_INTERFACE_DETAIL_DATA_A = ctypes.sizeof(dummy) SetupDiDestroyDeviceInfoList = ctypes.windll.setupapi.SetupDiDestroyDeviceInfoList SetupDiDestroyDeviceInfoList.argtypes = [HDEVINFO] SetupDiDestroyDeviceInfoList.restype = BOOL SetupDiGetClassDevs = ctypes.windll.setupapi.SetupDiGetClassDevsA SetupDiGetClassDevs.argtypes = [ctypes.POINTER(GUID), PCTSTR, HWND, DWORD] SetupDiGetClassDevs.restype = ValidHandle # HDEVINFO SetupDiEnumDeviceInterfaces = ctypes.windll.setupapi.SetupDiEnumDeviceInterfaces SetupDiEnumDeviceInterfaces.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, ctypes.POINTER(GUID), DWORD, PSP_DEVICE_INTERFACE_DATA] SetupDiEnumDeviceInterfaces.restype = BOOL SetupDiGetDeviceInterfaceDetail = ctypes.windll.setupapi.SetupDiGetDeviceInterfaceDetailA SetupDiGetDeviceInterfaceDetail.argtypes = [HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA, DWORD, PDWORD, PSP_DEVINFO_DATA] SetupDiGetDeviceInterfaceDetail.restype = BOOL SetupDiGetDeviceRegistryProperty = ctypes.windll.setupapi.SetupDiGetDeviceRegistryPropertyA SetupDiGetDeviceRegistryProperty.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD] SetupDiGetDeviceRegistryProperty.restype = BOOL GUID_CLASS_COMPORT = GUID(0x86e0d1e0L, 0x8089, 0x11d0, (ctypes.c_ubyte*8)(0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73)) DIGCF_PRESENT = 2 DIGCF_DEVICEINTERFACE = 16 INVALID_HANDLE_VALUE = 0 ERROR_INSUFFICIENT_BUFFER = 122 SPDRP_HARDWAREID = 1 SPDRP_FRIENDLYNAME = 12 SPDRP_LOCATION_INFORMATION = 13 ERROR_NO_MORE_ITEMS = 259 def comports(available_only=True): """This generator scans the device registry for com ports and yields (order, port, desc, hwid). If available_only is true only return currently existing ports. Order is a helper to get sorted lists. it can be ignored otherwise.""" flags = DIGCF_DEVICEINTERFACE if available_only: flags |= DIGCF_PRESENT g_hdi = SetupDiGetClassDevs(ctypes.byref(GUID_CLASS_COMPORT), None, NULL, flags); #~ for i in range(256): for dwIndex in range(256): did = SP_DEVICE_INTERFACE_DATA() did.cbSize = ctypes.sizeof(did) if not SetupDiEnumDeviceInterfaces( g_hdi, None, ctypes.byref(GUID_CLASS_COMPORT), dwIndex, ctypes.byref(did) ): if ctypes.GetLastError() != ERROR_NO_MORE_ITEMS: raise ctypes.WinError() break dwNeeded = DWORD() # get the size if not SetupDiGetDeviceInterfaceDetail( g_hdi, ctypes.byref(did), None, 0, ctypes.byref(dwNeeded), None ): # Ignore ERROR_INSUFFICIENT_BUFFER if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: raise ctypes.WinError() # allocate buffer class SP_DEVICE_INTERFACE_DETAIL_DATA_A(ctypes.Structure): _fields_ = [ ('cbSize', DWORD), ('DevicePath', CHAR*(dwNeeded.value - ctypes.sizeof(DWORD))), ] def __str__(self): return "DevicePath:%s" % (self.DevicePath,) idd = SP_DEVICE_INTERFACE_DETAIL_DATA_A() idd.cbSize = SIZEOF_SP_DEVICE_INTERFACE_DETAIL_DATA_A devinfo = SP_DEVINFO_DATA() devinfo.cbSize = ctypes.sizeof(devinfo) if not SetupDiGetDeviceInterfaceDetail( g_hdi, ctypes.byref(did), ctypes.byref(idd), dwNeeded, None, ctypes.byref(devinfo) ): raise ctypes.WinError() # hardware ID szHardwareID = ctypes.create_string_buffer(250) 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() # friendly name szFriendlyName = ctypes.create_string_buffer(1024) if not SetupDiGetDeviceRegistryProperty( g_hdi, ctypes.byref(devinfo), SPDRP_FRIENDLYNAME, None, ctypes.byref(szFriendlyName), ctypes.sizeof(szFriendlyName) - 1, None ): # Ignore ERROR_INSUFFICIENT_BUFFER if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: #~ raise ctypes.WinError() # not getting friendly name for com0com devices, try something else szFriendlyName = ctypes.create_string_buffer(1024) if SetupDiGetDeviceRegistryProperty( g_hdi, ctypes.byref(devinfo), SPDRP_LOCATION_INFORMATION, None, ctypes.byref(szFriendlyName), ctypes.sizeof(szFriendlyName) - 1, None ): port_name = "\\\\.\\" + szFriendlyName.value order = None else: port_name = szFriendlyName.value order = None else: try: m = re.search(r"\((.*?(\d+))\)", szFriendlyName.value) #~ print szFriendlyName.value, m.groups() port_name = m.group(1) order = int(m.group(2)) except AttributeError, msg: port_name = szFriendlyName.value order = None yield order, port_name, szFriendlyName.value, szHardwareID.value SetupDiDestroyDeviceInfoList(g_hdi) if __name__ == '__main__': import serial print "-"*78 print "Serial ports" print "-"*78 for order, port, desc, hwid in sorted(comports()): print "%-10s: %s (%s) ->" % (port, desc, hwid), try: serial.Serial(port) # test open except serial.serialutil.SerialException: print "can't be openend" else: print "Ready" print # list of all ports the system knows print "-"*78 print "All serial ports (registry)" print "-"*78 for order, port, desc, hwid in sorted(comports(False)): print "%-10s: %s (%s)" % (port, desc, hwid) pyserial-2.6/examples/rfc2217_server.py0000644000175000017500000001503511535035477017431 0ustar lchlch00000000000000#!/usr/bin/env python # (C) 2009 Chris Liechti # redirect data from a TCP/IP connection to a serial port and vice versa # using RFC 2217 import sys import os import threading import time import socket import serial import serial.rfc2217 import logging class Redirector: def __init__(self, serial_instance, socket, debug=None): self.serial = serial_instance self.socket = socket self._write_lock = threading.Lock() self.rfc2217 = serial.rfc2217.PortManager( self.serial, self, logger = (debug and logging.getLogger('rfc2217.server')) ) self.log = logging.getLogger('redirector') def statusline_poller(self): self.log.debug('status line poll thread started') while self.alive: time.sleep(1) self.rfc2217.check_modem_lines() self.log.debug('status line poll thread terminated') def shortcut(self): """connect the serial port to the TCP port by copying everything from one side to the other""" self.alive = True self.thread_read = threading.Thread(target=self.reader) self.thread_read.setDaemon(True) self.thread_read.setName('serial->socket') self.thread_read.start() self.thread_poll = threading.Thread(target=self.statusline_poller) self.thread_poll.setDaemon(True) self.thread_poll.setName('status line poll') self.thread_poll.start() self.writer() def reader(self): """loop forever and copy serial->socket""" self.log.debug('reader thread started') while self.alive: try: data = self.serial.read(1) # read one, blocking n = self.serial.inWaiting() # look if there is more if n: data = data + self.serial.read(n) # and get as much as possible if data: # escape outgoing data when needed (Telnet IAC (0xff) character) data = serial.to_bytes(self.rfc2217.escape(data)) self._write_lock.acquire() try: self.socket.sendall(data) # send it over TCP finally: self._write_lock.release() except socket.error, msg: self.log.error('%s' % (msg,)) # probably got disconnected break self.alive = False self.log.debug('reader thread terminated') def write(self, data): """thread safe socket write with no data escaping. used to send telnet stuff""" self._write_lock.acquire() try: self.socket.sendall(data) finally: self._write_lock.release() def writer(self): """loop forever and copy socket->serial""" while self.alive: try: data = self.socket.recv(1024) if not data: break self.serial.write(serial.to_bytes(self.rfc2217.filter(data))) except socket.error, msg: self.log.error('%s' % (msg,)) # probably got disconnected break self.stop() def stop(self): """Stop copying""" self.log.debug('stopping') if self.alive: self.alive = False self.thread_read.join() self.thread_poll.join() if __name__ == '__main__': import optparse parser = optparse.OptionParser( usage = "%prog [options] port", description = "RFC 2217 Serial to Network (TCP/IP) redirector.", epilog = """\ NOTE: no security measures are implemented. Anyone can remotely connect to this service over the network. Only one connection at once is supported. When the connection is terminated it waits for the next connect. """) parser.add_option("-p", "--localport", dest = "local_port", action = "store", type = 'int', help = "local TCP port", default = 2217 ) parser.add_option("-v", "--verbose", dest = "verbosity", action = "count", help = "print more diagnostic messages (option can be given multiple times)", default = 0 ) (options, args) = parser.parse_args() if len(args) != 1: parser.error('serial port name required as argument') if options.verbosity > 3: options.verbosity = 3 level = ( logging.WARNING, logging.INFO, logging.DEBUG, logging.NOTSET, )[options.verbosity] logging.basicConfig(level=logging.INFO) logging.getLogger('root').setLevel(logging.INFO) logging.getLogger('rfc2217').setLevel(level) # connect to serial port ser = serial.Serial() ser.port = args[0] ser.timeout = 3 # required so that the reader thread can exit logging.info("RFC 2217 TCP/IP to Serial redirector - type Ctrl-C / BREAK to quit") try: ser.open() except serial.SerialException, e: logging.error("Could not open serial port %s: %s" % (ser.portstr, e)) sys.exit(1) logging.info("Serving serial port: %s" % (ser.portstr,)) settings = ser.getSettingsDict() # reset control line as no _remote_ "terminal" has been connected yet ser.setDTR(False) ser.setRTS(False) srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) srv.bind( ('', options.local_port) ) srv.listen(1) logging.info("TCP/IP port: %s" % (options.local_port,)) while True: try: connection, addr = srv.accept() logging.info('Connected by %s:%s' % (addr[0], addr[1])) connection.setsockopt( socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) ser.setRTS(True) ser.setDTR(True) # enter network <-> serial loop r = Redirector( ser, connection, options.verbosity > 0 ) try: r.shortcut() finally: logging.info('Disconnected') r.stop() connection.close() ser.setDTR(False) ser.setRTS(False) # Restore port settings (may have been changed by RFC 2217 capable # client) ser.applySettingsDict(settings) except KeyboardInterrupt: break except socket.error, msg: logging.error('%s' % (msg,)) logging.info('--- exit ---') pyserial-2.6/examples/wxTerminal.py0000644000175000017500000003233311026531632017074 0ustar lchlch00000000000000#!/usr/bin/env python # generated by wxGlade 0.3.1 on Fri Oct 03 23:23:45 2003 #from wxPython.wx import * import wx import wxSerialConfigDialog import serial import threading #---------------------------------------------------------------------- # Create an own event type, so that GUI updates can be delegated # this is required as on some platforms only the main thread can # access the GUI without crashing. wxMutexGuiEnter/wxMutexGuiLeave # could be used too, but an event is more elegant. SERIALRX = wx.NewEventType() # bind to serial data receive events EVT_SERIALRX = wx.PyEventBinder(SERIALRX, 0) class SerialRxEvent(wx.PyCommandEvent): eventType = SERIALRX def __init__(self, windowID, data): wx.PyCommandEvent.__init__(self, self.eventType, windowID) self.data = data def Clone(self): self.__class__(self.GetId(), self.data) #---------------------------------------------------------------------- ID_CLEAR = wx.NewId() ID_SAVEAS = wx.NewId() ID_SETTINGS = wx.NewId() ID_TERM = wx.NewId() ID_EXIT = wx.NewId() NEWLINE_CR = 0 NEWLINE_LF = 1 NEWLINE_CRLF = 2 class TerminalSetup: """Placeholder for various terminal settings. Used to pass the options to the TerminalSettingsDialog.""" def __init__(self): self.echo = False self.unprintable = False self.newline = NEWLINE_CRLF class TerminalSettingsDialog(wx.Dialog): """Simple dialog with common terminal settings like echo, newline mode.""" def __init__(self, *args, **kwds): self.settings = kwds['settings'] del kwds['settings'] # begin wxGlade: TerminalSettingsDialog.__init__ kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) self.checkbox_echo = wx.CheckBox(self, -1, "Local Echo") self.checkbox_unprintable = wx.CheckBox(self, -1, "Show unprintable characters") self.radio_box_newline = wx.RadioBox(self, -1, "Newline Handling", choices=["CR only", "LF only", "CR+LF"], majorDimension=0, style=wx.RA_SPECIFY_ROWS) self.button_ok = wx.Button(self, -1, "OK") self.button_cancel = wx.Button(self, -1, "Cancel") self.__set_properties() self.__do_layout() # end wxGlade self.__attach_events() self.checkbox_echo.SetValue(self.settings.echo) self.checkbox_unprintable.SetValue(self.settings.unprintable) self.radio_box_newline.SetSelection(self.settings.newline) def __set_properties(self): # begin wxGlade: TerminalSettingsDialog.__set_properties self.SetTitle("Terminal Settings") self.radio_box_newline.SetSelection(0) self.button_ok.SetDefault() # end wxGlade def __do_layout(self): # begin wxGlade: TerminalSettingsDialog.__do_layout sizer_2 = wx.BoxSizer(wx.VERTICAL) sizer_3 = wx.BoxSizer(wx.HORIZONTAL) sizer_4 = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Input/Output"), wx.VERTICAL) sizer_4.Add(self.checkbox_echo, 0, wx.ALL, 4) sizer_4.Add(self.checkbox_unprintable, 0, wx.ALL, 4) sizer_4.Add(self.radio_box_newline, 0, 0, 0) sizer_2.Add(sizer_4, 0, wx.EXPAND, 0) sizer_3.Add(self.button_ok, 0, 0, 0) sizer_3.Add(self.button_cancel, 0, 0, 0) sizer_2.Add(sizer_3, 0, wx.ALL|wx.ALIGN_RIGHT, 4) self.SetAutoLayout(1) self.SetSizer(sizer_2) sizer_2.Fit(self) sizer_2.SetSizeHints(self) self.Layout() # end wxGlade def __attach_events(self): self.Bind(wx.EVT_BUTTON, self.OnOK, id = self.button_ok.GetId()) self.Bind(wx.EVT_BUTTON, self.OnCancel, id = self.button_cancel.GetId()) def OnOK(self, events): """Update data wil new values and close dialog.""" self.settings.echo = self.checkbox_echo.GetValue() self.settings.unprintable = self.checkbox_unprintable.GetValue() self.settings.newline = self.radio_box_newline.GetSelection() self.EndModal(wx.ID_OK) def OnCancel(self, events): """Do not update data but close dialog.""" self.EndModal(wx.ID_CANCEL) # end of class TerminalSettingsDialog class TerminalFrame(wx.Frame): """Simple terminal program for wxPython""" def __init__(self, *args, **kwds): self.serial = serial.Serial() self.serial.timeout = 0.5 #make sure that the alive event can be checked from time to time self.settings = TerminalSetup() #placeholder for the settings self.thread = None self.alive = threading.Event() # begin wxGlade: TerminalFrame.__init__ kwds["style"] = wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, *args, **kwds) self.text_ctrl_output = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.TE_READONLY) # Menu Bar self.frame_terminal_menubar = wx.MenuBar() self.SetMenuBar(self.frame_terminal_menubar) wxglade_tmp_menu = wx.Menu() wxglade_tmp_menu.Append(ID_CLEAR, "&Clear", "", wx.ITEM_NORMAL) wxglade_tmp_menu.Append(ID_SAVEAS, "&Save Text As...", "", wx.ITEM_NORMAL) wxglade_tmp_menu.AppendSeparator() wxglade_tmp_menu.Append(ID_SETTINGS, "&Port Settings...", "", wx.ITEM_NORMAL) wxglade_tmp_menu.Append(ID_TERM, "&Terminal Settings...", "", wx.ITEM_NORMAL) wxglade_tmp_menu.AppendSeparator() wxglade_tmp_menu.Append(ID_EXIT, "&Exit", "", wx.ITEM_NORMAL) self.frame_terminal_menubar.Append(wxglade_tmp_menu, "&File") # Menu Bar end self.__set_properties() self.__do_layout() # end wxGlade self.__attach_events() #register events self.OnPortSettings(None) #call setup dialog on startup, opens port if not self.alive.isSet(): self.Close() def StartThread(self): """Start the receiver thread""" self.thread = threading.Thread(target=self.ComPortThread) self.thread.setDaemon(1) self.alive.set() self.thread.start() def StopThread(self): """Stop the receiver thread, wait util it's finished.""" if self.thread is not None: self.alive.clear() #clear alive event for thread self.thread.join() #wait until thread has finished self.thread = None def __set_properties(self): # begin wxGlade: TerminalFrame.__set_properties self.SetTitle("Serial Terminal") self.SetSize((546, 383)) # end wxGlade def __do_layout(self): # begin wxGlade: TerminalFrame.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) sizer_1.Add(self.text_ctrl_output, 1, wx.EXPAND, 0) self.SetAutoLayout(1) self.SetSizer(sizer_1) self.Layout() # end wxGlade def __attach_events(self): #register events at the controls self.Bind(wx.EVT_MENU, self.OnClear, id = ID_CLEAR) self.Bind(wx.EVT_MENU, self.OnSaveAs, id = ID_SAVEAS) self.Bind(wx.EVT_MENU, self.OnExit, id = ID_EXIT) self.Bind(wx.EVT_MENU, self.OnPortSettings, id = ID_SETTINGS) self.Bind(wx.EVT_MENU, self.OnTermSettings, id = ID_TERM) self.text_ctrl_output.Bind(wx.EVT_CHAR, self.OnKey) self.Bind(EVT_SERIALRX, self.OnSerialRead) self.Bind(wx.EVT_CLOSE, self.OnClose) def OnExit(self, event): """Menu point Exit""" self.Close() def OnClose(self, event): """Called on application shutdown.""" self.StopThread() #stop reader thread self.serial.close() #cleanup self.Destroy() #close windows, exit app def OnSaveAs(self, event): """Save contents of output window.""" filename = None dlg = wx.FileDialog(None, "Save Text As...", ".", "", "Text File|*.txt|All Files|*", wx.SAVE) if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetPath() dlg.Destroy() if filename is not None: f = file(filename, 'w') text = self.text_ctrl_output.GetValue() if type(text) == unicode: text = text.encode("latin1") #hm, is that a good asumption? f.write(text) f.close() def OnClear(self, event): """Clear contents of output window.""" self.text_ctrl_output.Clear() def OnPortSettings(self, event=None): """Show the portsettings dialog. The reader thread is stopped for the settings change.""" if event is not None: #will be none when called on startup self.StopThread() self.serial.close() ok = False while not ok: dialog_serial_cfg = wxSerialConfigDialog.SerialConfigDialog(None, -1, "", show=wxSerialConfigDialog.SHOW_BAUDRATE|wxSerialConfigDialog.SHOW_FORMAT|wxSerialConfigDialog.SHOW_FLOW, serial=self.serial ) result = dialog_serial_cfg.ShowModal() dialog_serial_cfg.Destroy() #open port if not called on startup, open it on startup and OK too if result == wx.ID_OK or event is not None: try: self.serial.open() except serial.SerialException, e: dlg = wx.MessageDialog(None, str(e), "Serial Port Error", wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() else: self.StartThread() self.SetTitle("Serial Terminal on %s [%s, %s%s%s%s%s]" % ( self.serial.portstr, self.serial.baudrate, self.serial.bytesize, self.serial.parity, self.serial.stopbits, self.serial.rtscts and ' RTS/CTS' or '', self.serial.xonxoff and ' Xon/Xoff' or '', ) ) ok = True else: #on startup, dialog aborted self.alive.clear() ok = True def OnTermSettings(self, event): """Menu point Terminal Settings. Show the settings dialog with the current terminal settings""" dialog = TerminalSettingsDialog(None, -1, "", settings=self.settings) result = dialog.ShowModal() dialog.Destroy() def OnKey(self, event): """Key event handler. if the key is in the ASCII range, write it to the serial port. Newline handling and local echo is also done here.""" code = event.GetKeyCode() if code < 256: #is it printable? if code == 13: #is it a newline? (check for CR which is the RETURN key) if self.settings.echo: #do echo if needed self.text_ctrl_output.AppendText('\n') if self.settings.newline == NEWLINE_CR: self.serial.write('\r') #send CR elif self.settings.newline == NEWLINE_LF: self.serial.write('\n') #send LF elif self.settings.newline == NEWLINE_CRLF: self.serial.write('\r\n') #send CR+LF else: char = chr(code) if self.settings.echo: #do echo if needed self.text_ctrl_output.WriteText(char) self.serial.write(char) #send the charcater else: print "Extra Key:", code def OnSerialRead(self, event): """Handle input from the serial port.""" text = event.data if self.settings.unprintable: text = ''.join([(c >= ' ') and c or '<%d>' % ord(c) for c in text]) self.text_ctrl_output.AppendText(text) def ComPortThread(self): """Thread that handles the incomming traffic. Does the basic input transformation (newlines) and generates an SerialRxEvent""" while self.alive.isSet(): #loop while alive event is true text = self.serial.read(1) #read one, with timout if text: #check if not timeout n = self.serial.inWaiting() #look if there is more to read if n: text = text + self.serial.read(n) #get it #newline transformation if self.settings.newline == NEWLINE_CR: text = text.replace('\r', '\n') elif self.settings.newline == NEWLINE_LF: pass elif self.settings.newline == NEWLINE_CRLF: text = text.replace('\r\n', '\n') event = SerialRxEvent(self.GetId(), text) self.GetEventHandler().AddPendingEvent(event) #~ self.OnSerialRead(text) #output text in window # end of class TerminalFrame class MyApp(wx.App): def OnInit(self): wx.InitAllImageHandlers() frame_terminal = TerminalFrame(None, -1, "") self.SetTopWindow(frame_terminal) frame_terminal.Show(1) return 1 # end of class MyApp if __name__ == "__main__": app = MyApp(0) app.MainLoop() pyserial-2.6/examples/port_publisher.py0000644000175000017500000004206211317535560020012 0ustar lchlch00000000000000#! /usr/bin/env python """\ Multi-port serial<->TCP/IP forwarder. - RFC 2217 - check existence of serial port periodically - start/stop forwarders - each forwarder creates a server socket and opens the serial port - serial ports are opened only once. network connect/disconnect does not influence serial port - only one client per connection """ import sys, os, time import traceback import socket import select import serial import serial.rfc2217 import avahi import dbus class ZeroconfService: """\ A simple class to publish a network service with zeroconf using avahi. """ def __init__(self, name, port, stype="_http._tcp", domain="", host="", text=""): self.name = name self.stype = stype self.domain = domain self.host = host self.port = port self.text = text self.group = None def publish(self): bus = dbus.SystemBus() server = dbus.Interface( bus.get_object( avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER ), avahi.DBUS_INTERFACE_SERVER ) g = dbus.Interface( bus.get_object( avahi.DBUS_NAME, server.EntryGroupNew() ), avahi.DBUS_INTERFACE_ENTRY_GROUP ) g.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, dbus.UInt32(0), self.name, self.stype, self.domain, self.host, dbus.UInt16(self.port), self.text) g.Commit() self.group = g def unpublish(self): if self.group is not None: self.group.Reset() self.group = None def __str__(self): return "%r @ %s:%s (%s)" % (self.name, self.host, self.port, self.stype) class Forwarder(ZeroconfService): """\ Single port serial<->TCP/IP forarder that depends on an external select loop. - Buffers for serial -> network and network -> serial - RFC 2217 state - Zeroconf publish/unpublish on open/close. """ def __init__(self, device, name, network_port, on_close=None): ZeroconfService.__init__(self, name, network_port, stype='_serial_port._tcp') self.alive = False self.network_port = network_port self.on_close = on_close self.device = device self.serial = serial.Serial() self.serial.port = device self.serial.baudrate = 115200 self.serial.timeout = 0 self.socket = None self.server_socket = None self.rfc2217 = None # instantiate later, when connecting def __del__(self): try: if self.alive: self.close() except: pass # XXX errors on shutdown def open(self): """open serial port, start network server and publish service""" self.buffer_net2ser = '' self.buffer_ser2net = '' # open serial port try: self.serial.open() self.serial.setRTS(False) except Exception, msg: self.handle_serial_error(msg) self.serial_settings_backup = self.serial.getSettingsDict() # start the socket server self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_socket.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, self.server_socket.getsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR ) | 1 ) self.server_socket.setblocking(0) try: self.server_socket.bind( ('', self.network_port) ) self.server_socket.listen(1) except socket.error, msg: self.handle_server_error() #~ raise if not options.quiet: print "%s: Waiting for connection on %s..." % (self.device, self.network_port) # zeroconfig self.publish() # now we are ready self.alive = True def close(self): """Close all resources and unpublish service""" if not options.quiet: print "%s: closing..." % (self.device, ) self.alive = False self.unpublish() if self.server_socket: self.server_socket.close() if self.socket: self.handle_disconnect() self.serial.close() if self.on_close is not None: # ensure it is only called once callback = self.on_close self.on_close = None callback(self) def write(self, data): """the write method is used by serial.rfc2217.PortManager. it has to write to the network.""" self.buffer_ser2net += data def update_select_maps(self, read_map, write_map, error_map): """Update dictionaries for select call. insert fd->callback mapping""" if self.alive: # always handle serial port reads read_map[self.serial] = self.handle_serial_read error_map[self.serial] = self.handle_serial_error # handle serial port writes if buffer is not empty if self.buffer_net2ser: write_map[self.serial] = self.handle_serial_write # handle network if self.socket is not None: # handle socket if connected # only read from network if the internal buffer is not # already filled. the TCP flow control will hold back data if len(self.buffer_net2ser) < 2048: read_map[self.socket] = self.handle_socket_read # only check for write readiness when there is data if self.buffer_ser2net: write_map[self.socket] = self.handle_socket_write error_map[self.socket] = self.handle_socket_error else: # no connection, ensure clear buffer self.buffer_ser2net = '' # check the server socket read_map[self.server_socket] = self.handle_connect error_map[self.server_socket] = self.handle_server_error def handle_serial_read(self): """Reading from serial port""" try: data = os.read(self.serial.fileno(), 1024) if data: # store data in buffer if there is a client connected if self.socket is not None: # escape outgoing data when needed (Telnet IAC (0xff) character) if self.rfc2217: data = serial.to_bytes(self.rfc2217.escape(data)) self.buffer_ser2net += data else: self.handle_serial_error() except Exception, msg: self.handle_serial_error(msg) def handle_serial_write(self): """Writing to serial port""" try: # write a chunk n = os.write(self.serial.fileno(), self.buffer_net2ser) # and see how large that chunk was, remove that from buffer self.buffer_net2ser = self.buffer_net2ser[n:] except Exception, msg: self.handle_serial_error(msg) def handle_serial_error(self, error=None): """Serial port error""" # terminate connection self.close() def handle_socket_read(self): """Read from socket""" try: # read a chunk from the serial port data = self.socket.recv(1024) if data: # Process RFC 2217 stuff when enabled if self.rfc2217: data = serial.to_bytes(self.rfc2217.filter(data)) # add data to buffer self.buffer_net2ser += data else: # empty read indicates disconnection self.handle_disconnect() except socket.error: self.handle_socket_error() def handle_socket_write(self): """Write to socket""" try: # write a chunk count = self.socket.send(self.buffer_ser2net) # and remove the sent data from the buffer self.buffer_ser2net = self.buffer_ser2net[count:] except socket.error: self.handle_socket_error() def handle_socket_error(self): """Socket connection fails""" self.handle_disconnect() def handle_connect(self): """Server socket gets a connection""" # accept a connection in any case, close connection # below if already busy connection, addr = self.server_socket.accept() if self.socket is None: self.socket = connection self.socket.setblocking(0) self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) if not options.quiet: print '%s: Connected by %s:%s' % (self.device, addr[0], addr[1]) self.serial.setRTS(True) self.serial.setDTR(True) self.rfc2217 = serial.rfc2217.PortManager(self.serial, self) else: # reject connection if there is already one connection.close() if not options.quiet: print '%s: Rejecting connect from %s:%s' % (self.device, addr[0], addr[1]) def handle_server_error(self): """Socket server fails""" self.close() def handle_disconnect(self): """Socket gets disconnected""" # signal disconnected terminal with control lines try: self.serial.setRTS(False) self.serial.setDTR(False) finally: # restore original port configuration in case it was changed self.serial.applySettingsDict(self.serial_settings_backup) # stop RFC 2217 state machine self.rfc2217 = None # clear send buffer self.buffer_ser2net = '' # close network connection if self.socket is not None: self.socket.close() self.socket = None if not options.quiet: print '%s: Disconnected' % self.device def test(): service = ZeroconfService(name="TestService", port=3000) service.publish() raw_input("Press any key to unpublish the service ") service.unpublish() if __name__ == '__main__': import optparse parser = optparse.OptionParser(usage="""\ %prog [options] Announce the existence of devices using zeroconf and provide a TCP/IP <-> serial port gateway (implements RFC 2217). Note that the TCP/IP server is not protected. Everyone can connect to it! If running as daemon, write to syslog. Otherwise write to stdout. """) parser.add_option("-q", "--quiet", dest="quiet", action="store_true", help="suppress non error messages", default=False) parser.add_option("-o", "--logfile", dest="log_file", help="write messages file instead of stdout", default=None, metavar="FILE") parser.add_option("-d", "--daemon", dest="daemonize", action="store_true", help="start as daemon", default=False) parser.add_option("", "--pidfile", dest="pid_file", help="specify a name for the PID file", default=None, metavar="FILE") (options, args) = parser.parse_args() # redirect output if specified if options.log_file is not None: class WriteFlushed: def __init__(self, fileobj): self.fileobj = fileobj def write(self, s): self.fileobj.write(s) self.fileobj.flush() def close(self): self.fileobj.close() sys.stdout = sys.stderr = WriteFlushed(open(options.log_file, 'a')) # atexit.register(lambda: sys.stdout.close()) if options.daemonize: # if running as daemon is requested, do the fork magic # options.quiet = True import pwd # do the UNIX double-fork magic, see Stevens' "Advanced # Programming in the UNIX Environment" for details (ISBN 0201563177) try: pid = os.fork() if pid > 0: # exit first parent sys.exit(0) except OSError, e: sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1) # decouple from parent environment os.chdir("/") # don't prevent unmounting.... os.setsid() os.umask(0) # do second fork try: pid = os.fork() if pid > 0: # exit from second parent, print eventual PID before # print "Daemon PID %d" % pid if options.pid_file is not None: open(options.pid_file,'w').write("%d"%pid) sys.exit(0) except OSError, e: sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1) if options.log_file is None: import syslog syslog.openlog("serial port publisher") # redirect output to syslog class WriteToSysLog: def __init__(self): self.buffer = '' def write(self, s): self.buffer += s if '\n' in self.buffer: output, self.buffer = self.buffer.split('\n', 1) syslog.syslog(output) def flush(self): syslog.syslog(self.buffer) self.buffer = '' def close(self): self.flush() sys.stdout = sys.stderr = WriteToSysLog() # ensure the that the daemon runs a normal user, if run as root #if os.getuid() == 0: # name, passwd, uid, gid, desc, home, shell = pwd.getpwnam('someuser') # os.setgid(gid) # set group first # os.setuid(uid) # set user # keep the published stuff in a dictionary published = {} # prepare list of device names (hard coded) device_list = ['/dev/ttyUSB%d' % p for p in range(8)] # get a nice hostname hostname = socket.gethostname() def unpublish(forwarder): """when forwarders die, we need to unregister them""" try: del published[forwarder.device] except KeyError: pass else: if not options.quiet: print "unpublish: %s" % (forwarder) alive = True next_check = 0 # main loop while alive: try: # if it is time, check for serial port devices now = time.time() if now > next_check: next_check = now + 5 # check each device for device in device_list: # if it appeared if os.path.exists(device): if device not in published: num = int(device[-1]) published[device] = Forwarder( device, "%s on %s" % (device, hostname), 7000+num, on_close=unpublish ) if not options.quiet: print "publish: %s" % (published[device]) published[device].open() else: # or when it disappeared if device in published: if not options.quiet: print "unpublish: %s" % (published[device]) published[device].close() try: del published[device] except KeyError: pass # select_start = time.time() read_map = {} write_map = {} error_map = {} for publisher in published.values(): publisher.update_select_maps(read_map, write_map, error_map) try: readers, writers, errors = select.select( read_map.keys(), write_map.keys(), error_map.keys(), 5 ) except select.error, err: if err[0] != EINTR: raise # select_end = time.time() # print "select used %.3f s" % (select_end - select_start) for reader in readers: read_map[reader]() for writer in writers: write_map[writer]() for error in errors: error_map[error]() # print "operation used %.3f s" % (time.time() - select_end) except KeyboardInterrupt: alive = False except SystemExit: raise except: #~ raise traceback.print_exc() pyserial-2.6/examples/tcp_serial_redirect.py0000644000175000017500000002444211237673136020764 0ustar lchlch00000000000000#!/usr/bin/env python # (C) 2002-2009 Chris Liechti # redirect data from a TCP/IP connection to a serial port and vice versa # requires Python 2.2 'cause socket.sendall is used import sys import os import time import threading import socket import codecs import serial try: True except NameError: True = 1 False = 0 class Redirector: def __init__(self, serial_instance, socket, ser_newline=None, net_newline=None, spy=False): self.serial = serial_instance self.socket = socket self.ser_newline = ser_newline self.net_newline = net_newline self.spy = spy self._write_lock = threading.Lock() def shortcut(self): """connect the serial port to the TCP port by copying everything from one side to the other""" self.alive = True self.thread_read = threading.Thread(target=self.reader) self.thread_read.setDaemon(True) self.thread_read.setName('serial->socket') self.thread_read.start() self.writer() def reader(self): """loop forever and copy serial->socket""" while self.alive: try: data = self.serial.read(1) # read one, blocking n = self.serial.inWaiting() # look if there is more if n: data = data + self.serial.read(n) # and get as much as possible if data: # the spy shows what's on the serial port, so log it before converting newlines if self.spy: sys.stdout.write(codecs.escape_encode(data)[0]) sys.stdout.flush() if self.ser_newline and self.net_newline: # do the newline conversion # XXX fails for CR+LF in input when it is cut in half at the begin or end of the string data = net_newline.join(data.split(ser_newline)) # escape outgoing data when needed (Telnet IAC (0xff) character) self._write_lock.acquire() try: self.socket.sendall(data) # send it over TCP finally: self._write_lock.release() except socket.error, msg: sys.stderr.write('ERROR: %s\n' % msg) # probably got disconnected break self.alive = False def write(self, data): """thread safe socket write with no data escaping. used to send telnet stuff""" self._write_lock.acquire() try: self.socket.sendall(data) finally: self._write_lock.release() def writer(self): """loop forever and copy socket->serial""" while self.alive: try: data = self.socket.recv(1024) if not data: break if self.ser_newline and self.net_newline: # do the newline conversion # XXX fails for CR+LF in input when it is cut in half at the begin or end of the string data = ser_newline.join(data.split(net_newline)) self.serial.write(data) # get a bunch of bytes and send them # the spy shows what's on the serial port, so log it after converting newlines if self.spy: sys.stdout.write(codecs.escape_encode(data)[0]) sys.stdout.flush() except socket.error, msg: sys.stderr.write('ERROR: %s\n' % msg) # probably got disconnected break self.alive = False self.thread_read.join() def stop(self): """Stop copying""" if self.alive: self.alive = False self.thread_read.join() if __name__ == '__main__': import optparse parser = optparse.OptionParser( usage = "%prog [options] [port [baudrate]]", description = "Simple Serial to Network (TCP/IP) redirector.", epilog = """\ NOTE: no security measures are implemented. Anyone can remotely connect to this service over the network. Only one connection at once is supported. When the connection is terminated it waits for the next connect. """) parser.add_option("-q", "--quiet", dest = "quiet", action = "store_true", help = "suppress non error messages", default = False ) parser.add_option("--spy", dest = "spy", action = "store_true", help = "peek at the communication and print all data to the console", default = False ) group = optparse.OptionGroup(parser, "Serial Port", "Serial port settings" ) parser.add_option_group(group) group.add_option("-p", "--port", dest = "port", help = "port, a number (default 0) or a device name", default = None ) group.add_option("-b", "--baud", dest = "baudrate", action = "store", type = 'int', help = "set baud rate, default: %default", default = 9600 ) group.add_option("", "--parity", dest = "parity", action = "store", help = "set parity, one of [N, E, O], default=%default", default = 'N' ) group.add_option("--rtscts", dest = "rtscts", action = "store_true", help = "enable RTS/CTS flow control (default off)", default = False ) group.add_option("--xonxoff", dest = "xonxoff", action = "store_true", help = "enable software flow control (default off)", default = False ) group.add_option("--rts", dest = "rts_state", action = "store", type = 'int', help = "set initial RTS line state (possible values: 0, 1)", default = None ) group.add_option("--dtr", dest = "dtr_state", action = "store", type = 'int', help = "set initial DTR line state (possible values: 0, 1)", default = None ) group = optparse.OptionGroup(parser, "Network settings", "Network configuration." ) parser.add_option_group(group) group.add_option("-P", "--localport", dest = "local_port", action = "store", type = 'int', help = "local TCP port", default = 7777 ) group = optparse.OptionGroup(parser, "Newline Settings", "Convert newlines between network and serial port. Conversion is normally disabled and can be enabled by --convert." ) parser.add_option_group(group) group.add_option("-c", "--convert", dest = "convert", action = "store_true", help = "enable newline conversion (default off)", default = False ) group.add_option("--net-nl", dest = "net_newline", action = "store", help = "type of newlines that are expected on the network (default: %default)", default = "LF" ) group.add_option("--ser-nl", dest = "ser_newline", action = "store", help = "type of newlines that are expected on the serial port (default: %default)", default = "CR+LF" ) (options, args) = parser.parse_args() # get port and baud rate from command line arguments or the option switches port = options.port baudrate = options.baudrate if args: if options.port is not None: parser.error("no arguments are allowed, options only when --port is given") port = args.pop(0) if args: try: baudrate = int(args[0]) except ValueError: parser.error("baud rate must be a number, not %r" % args[0]) args.pop(0) if args: parser.error("too many arguments") else: if port is None: port = 0 # check newline modes for network connection mode = options.net_newline.upper() if mode == 'CR': net_newline = '\r' elif mode == 'LF': net_newline = '\n' elif mode == 'CR+LF' or mode == 'CRLF': net_newline = '\r\n' else: parser.error("Invalid value for --net-nl. Valid are 'CR', 'LF' and 'CR+LF'/'CRLF'.") # check newline modes for serial connection mode = options.ser_newline.upper() if mode == 'CR': ser_newline = '\r' elif mode == 'LF': ser_newline = '\n' elif mode == 'CR+LF' or mode == 'CRLF': ser_newline = '\r\n' else: parser.error("Invalid value for --ser-nl. Valid are 'CR', 'LF' and 'CR+LF'/'CRLF'.") # connect to serial port ser = serial.Serial() ser.port = port ser.baudrate = baudrate ser.parity = options.parity ser.rtscts = options.rtscts ser.xonxoff = options.xonxoff ser.timeout = 1 # required so that the reader thread can exit if not options.quiet: sys.stderr.write("--- TCP/IP to Serial redirector --- type Ctrl-C / BREAK to quit\n") sys.stderr.write("--- %s %s,%s,%s,%s ---\n" % (ser.portstr, ser.baudrate, 8, ser.parity, 1)) try: ser.open() except serial.SerialException, e: sys.stderr.write("Could not open serial port %s: %s\n" % (ser.portstr, e)) sys.exit(1) if options.rts_state is not None: ser.setRTS(options.rts_state) if options.dtr_state is not None: ser.setDTR(options.dtr_state) srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) srv.bind( ('', options.local_port) ) srv.listen(1) while True: try: sys.stderr.write("Waiting for connection on %s...\n" % options.local_port) connection, addr = srv.accept() sys.stderr.write('Connected by %s\n' % (addr,)) # enter network <-> serial loop r = Redirector( ser, connection, options.convert and ser_newline or None, options.convert and net_newline or None, options.spy, ) r.shortcut() if options.spy: sys.stdout.write('\n') sys.stderr.write('Disconnected\n') connection.close() except KeyboardInterrupt: break except socket.error, msg: sys.stderr.write('ERROR: %s\n' % msg) sys.stderr.write('\n--- exit ---\n') pyserial-2.6/examples/scan.py0000644000175000017500000000137211231441475015670 0ustar lchlch00000000000000#! /usr/bin/env python """\ Scan for serial ports. Part of pySerial (http://pyserial.sf.net) (C) 2002-2003 The scan function of this module tries to open each port number from 0 to 255 and it builds a list of those ports where this was successful. """ import serial def scan(): """scan for available ports. return a list of tuples (num, name)""" available = [] for i in range(256): try: s = serial.Serial(i) available.append( (i, s.portstr)) s.close() # explicit close 'cause of delayed GC in java except serial.SerialException: pass return available if __name__=='__main__': print "Found ports:" for n,s in scan(): print "(%d) %s" % (n,s) pyserial-2.6/examples/setup-wxTerminal-py2exe.py0000644000175000017500000000162511240117763021447 0ustar lchlch00000000000000# This is a setup.py example script for the use with py2exe from distutils.core import setup import py2exe import sys, os #this script is only useful for py2exe so just run that distutils command. #that allows to run it with a simple double click. sys.argv.append('py2exe') #get an icon from somewhere.. the python installation should have one: icon = os.path.join(os.path.dirname(sys.executable), 'py.ico') setup( options = {'py2exe': { 'excludes': ['javax.comm'], 'optimize': 2, 'dist_dir': 'dist', } }, name = "wxTerminal", windows = [ { 'script': "wxTerminal.py", 'icon_resources': [(0x0004, icon)] }, ], zipfile = "stuff.lib", description = "Simple serial terminal application", version = "0.1", author = "Chris Liechti", author_email = "cliechti@gmx.net", url = "http://pyserial.sf.net", ) pyserial-2.6/examples/setup-rfc2217_server-py2exe.py0000644000175000017500000000100611237073002021753 0ustar lchlch00000000000000# setup script for py2exe to create the miniterm.exe # $Id: setup-rfc2217_server-py2exe.py 320 2009-08-07 18:22:49Z cliechti $ from distutils.core import setup import glob, sys, py2exe, os sys.path.append('..') sys.argv.extend("py2exe --bundle 1".split()) setup( name='rfc2217_server', zipfile=None, options = {"py2exe": { 'dist_dir': 'bin', 'excludes': ['javax.comm'], 'compressed': 1, } }, console = [ "rfc2217_server.py", ], ) pyserial-2.6/examples/wxSerialConfigDialog.py0000644000175000017500000002700311026531632021004 0ustar lchlch00000000000000#!/usr/bin/env python # generated by wxGlade 0.3.1 on Thu Oct 02 23:25:44 2003 #from wxPython.wx import * import wx import serial SHOW_BAUDRATE = 1<<0 SHOW_FORMAT = 1<<1 SHOW_FLOW = 1<<2 SHOW_TIMEOUT = 1<<3 SHOW_ALL = SHOW_BAUDRATE|SHOW_FORMAT|SHOW_FLOW|SHOW_TIMEOUT try: enumerate except NameError: def enumerate(sequence): return zip(range(len(sequence)), sequence) class SerialConfigDialog(wx.Dialog): """Serial Port confiuration dialog, to be used with pyserial 2.0+ When instantiating a class of this dialog, then the "serial" keyword argument is mandatory. It is a reference to a serial.Serial instance. the optional "show" keyword argument can be used to show/hide different settings. The default is SHOW_ALL which coresponds to SHOW_BAUDRATE|SHOW_FORMAT|SHOW_FLOW|SHOW_TIMEOUT. All constants can be found in ths module (not the class).""" def __init__(self, *args, **kwds): #grab the serial keyword and remove it from the dict self.serial = kwds['serial'] del kwds['serial'] self.show = SHOW_ALL if kwds.has_key('show'): self.show = kwds['show'] del kwds['show'] # begin wxGlade: SerialConfigDialog.__init__ # end wxGlade kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) self.label_2 = wx.StaticText(self, -1, "Port") self.combo_box_port = wx.ComboBox(self, -1, choices=["dummy1", "dummy2", "dummy3", "dummy4", "dummy5"], style=wx.CB_DROPDOWN) if self.show & SHOW_BAUDRATE: self.label_1 = wx.StaticText(self, -1, "Baudrate") self.choice_baudrate = wx.Choice(self, -1, choices=["choice 1"]) if self.show & SHOW_FORMAT: self.label_3 = wx.StaticText(self, -1, "Data Bits") self.choice_databits = wx.Choice(self, -1, choices=["choice 1"]) self.label_4 = wx.StaticText(self, -1, "Stop Bits") self.choice_stopbits = wx.Choice(self, -1, choices=["choice 1"]) self.label_5 = wx.StaticText(self, -1, "Parity") self.choice_parity = wx.Choice(self, -1, choices=["choice 1"]) if self.show & SHOW_TIMEOUT: self.checkbox_timeout = wx.CheckBox(self, -1, "Use Timeout") self.text_ctrl_timeout = wx.TextCtrl(self, -1, "") self.label_6 = wx.StaticText(self, -1, "seconds") if self.show & SHOW_FLOW: self.checkbox_rtscts = wx.CheckBox(self, -1, "RTS/CTS") self.checkbox_xonxoff = wx.CheckBox(self, -1, "Xon/Xoff") self.button_ok = wx.Button(self, -1, "OK") self.button_cancel = wx.Button(self, -1, "Cancel") self.__set_properties() self.__do_layout() #fill in ports and select current setting index = 0 self.combo_box_port.Clear() for n in range(4): portname = serial.device(n) self.combo_box_port.Append(portname) if self.serial.portstr == portname: index = n if self.serial.portstr is not None: self.combo_box_port.SetValue(str(self.serial.portstr)) else: self.combo_box_port.SetSelection(index) if self.show & SHOW_BAUDRATE: #fill in badrates and select current setting self.choice_baudrate.Clear() for n, baudrate in enumerate(self.serial.BAUDRATES): self.choice_baudrate.Append(str(baudrate)) if self.serial.baudrate == baudrate: index = n self.choice_baudrate.SetSelection(index) if self.show & SHOW_FORMAT: #fill in databits and select current setting self.choice_databits.Clear() for n, bytesize in enumerate(self.serial.BYTESIZES): self.choice_databits.Append(str(bytesize)) if self.serial.bytesize == bytesize: index = n self.choice_databits.SetSelection(index) #fill in stopbits and select current setting self.choice_stopbits.Clear() for n, stopbits in enumerate(self.serial.STOPBITS): self.choice_stopbits.Append(str(stopbits)) if self.serial.stopbits == stopbits: index = n self.choice_stopbits.SetSelection(index) #fill in parities and select current setting self.choice_parity.Clear() for n, parity in enumerate(self.serial.PARITIES): self.choice_parity.Append(str(serial.PARITY_NAMES[parity])) if self.serial.parity == parity: index = n self.choice_parity.SetSelection(index) if self.show & SHOW_TIMEOUT: #set the timeout mode and value if self.serial.timeout is None: self.checkbox_timeout.SetValue(False) self.text_ctrl_timeout.Enable(False) else: self.checkbox_timeout.SetValue(True) self.text_ctrl_timeout.Enable(True) self.text_ctrl_timeout.SetValue(str(self.serial.timeout)) if self.show & SHOW_FLOW: #set the rtscts mode self.checkbox_rtscts.SetValue(self.serial.rtscts) #set the rtscts mode self.checkbox_xonxoff.SetValue(self.serial.xonxoff) #attach the event handlers self.__attach_events() def __set_properties(self): # begin wxGlade: SerialConfigDialog.__set_properties # end wxGlade self.SetTitle("Serial Port Configuration") if self.show & SHOW_TIMEOUT: self.text_ctrl_timeout.Enable(0) self.button_ok.SetDefault() def __do_layout(self): # begin wxGlade: SerialConfigDialog.__do_layout # end wxGlade sizer_2 = wx.BoxSizer(wx.VERTICAL) sizer_3 = wx.BoxSizer(wx.HORIZONTAL) sizer_basics = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Basics"), wx.VERTICAL) sizer_5 = wx.BoxSizer(wx.HORIZONTAL) sizer_5.Add(self.label_2, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_5.Add(self.combo_box_port, 1, 0, 0) sizer_basics.Add(sizer_5, 0, wx.RIGHT|wx.EXPAND, 0) if self.show & SHOW_BAUDRATE: sizer_baudrate = wx.BoxSizer(wx.HORIZONTAL) sizer_baudrate.Add(self.label_1, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_baudrate.Add(self.choice_baudrate, 1, wx.ALIGN_RIGHT, 0) sizer_basics.Add(sizer_baudrate, 0, wx.EXPAND, 0) sizer_2.Add(sizer_basics, 0, wx.EXPAND, 0) if self.show & SHOW_FORMAT: sizer_8 = wx.BoxSizer(wx.HORIZONTAL) sizer_7 = wx.BoxSizer(wx.HORIZONTAL) sizer_6 = wx.BoxSizer(wx.HORIZONTAL) sizer_format = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Data Format"), wx.VERTICAL) sizer_6.Add(self.label_3, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_6.Add(self.choice_databits, 1, wx.ALIGN_RIGHT, 0) sizer_format.Add(sizer_6, 0, wx.EXPAND, 0) sizer_7.Add(self.label_4, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_7.Add(self.choice_stopbits, 1, wx.ALIGN_RIGHT, 0) sizer_format.Add(sizer_7, 0, wx.EXPAND, 0) sizer_8.Add(self.label_5, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_8.Add(self.choice_parity, 1, wx.ALIGN_RIGHT, 0) sizer_format.Add(sizer_8, 0, wx.EXPAND, 0) sizer_2.Add(sizer_format, 0, wx.EXPAND, 0) if self.show & SHOW_TIMEOUT: sizer_timeout = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Timeout"), wx.HORIZONTAL) sizer_timeout.Add(self.checkbox_timeout, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_timeout.Add(self.text_ctrl_timeout, 0, 0, 0) sizer_timeout.Add(self.label_6, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_2.Add(sizer_timeout, 0, 0, 0) if self.show & SHOW_FLOW: sizer_flow = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Flow Control"), wx.HORIZONTAL) sizer_flow.Add(self.checkbox_rtscts, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_flow.Add(self.checkbox_xonxoff, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_flow.Add((10,10), 1, wx.EXPAND, 0) sizer_2.Add(sizer_flow, 0, wx.EXPAND, 0) sizer_3.Add(self.button_ok, 0, 0, 0) sizer_3.Add(self.button_cancel, 0, 0, 0) sizer_2.Add(sizer_3, 0, wx.ALL|wx.ALIGN_RIGHT, 4) self.SetAutoLayout(1) self.SetSizer(sizer_2) sizer_2.Fit(self) sizer_2.SetSizeHints(self) self.Layout() def __attach_events(self): wx.EVT_BUTTON(self, self.button_ok.GetId(), self.OnOK) wx.EVT_BUTTON(self, self.button_cancel.GetId(), self.OnCancel) if self.show & SHOW_TIMEOUT: wx.EVT_CHECKBOX(self, self.checkbox_timeout.GetId(), self.OnTimeout) def OnOK(self, events): success = True self.serial.port = str(self.combo_box_port.GetValue()) if self.show & SHOW_BAUDRATE: self.serial.baudrate = self.serial.BAUDRATES[self.choice_baudrate.GetSelection()] if self.show & SHOW_FORMAT: self.serial.bytesize = self.serial.BYTESIZES[self.choice_databits.GetSelection()] self.serial.stopbits = self.serial.STOPBITS[self.choice_stopbits.GetSelection()] self.serial.parity = self.serial.PARITIES[self.choice_parity.GetSelection()] if self.show & SHOW_FLOW: self.serial.rtscts = self.checkbox_rtscts.GetValue() self.serial.xonxoff = self.checkbox_xonxoff.GetValue() if self.show & SHOW_TIMEOUT: if self.checkbox_timeout.GetValue(): try: self.serial.timeout = float(self.text_ctrl_timeout.GetValue()) except ValueError: dlg = wx.MessageDialog(self, 'Timeout must be a numeric value', 'Value Error', wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() success = False else: self.serial.timeout = None if success: self.EndModal(wx.ID_OK) def OnCancel(self, events): self.EndModal(wx.ID_CANCEL) def OnTimeout(self, events): if self.checkbox_timeout.GetValue(): self.text_ctrl_timeout.Enable(True) else: self.text_ctrl_timeout.Enable(False) # end of class SerialConfigDialog class MyApp(wx.App): """Test code""" def OnInit(self): wx.InitAllImageHandlers() ser = serial.Serial() print ser #loop until cancel is pressed, old values are used as start for the next run #show the different views, one after the other #value are kept. for flags in (SHOW_BAUDRATE, SHOW_FLOW, SHOW_FORMAT, SHOW_TIMEOUT, SHOW_ALL): dialog_serial_cfg = SerialConfigDialog(None, -1, "", serial=ser, show=flags) self.SetTopWindow(dialog_serial_cfg) result = dialog_serial_cfg.ShowModal() print ser if result != wx.ID_OK: break #the user can play around with the values, CANCEL aborts the loop while 1: dialog_serial_cfg = SerialConfigDialog(None, -1, "", serial=ser) self.SetTopWindow(dialog_serial_cfg) result = dialog_serial_cfg.ShowModal() print ser if result != wx.ID_OK: break return 0 # end of class MyApp if __name__ == "__main__": app = MyApp(0) app.MainLoop() pyserial-2.6/examples/scanlinux.py0000644000175000017500000000074111534047016016746 0ustar lchlch00000000000000#! /usr/bin/env python """\ Scan for serial ports. Linux specific variant that also includes USB/Serial adapters. Part of pySerial (http://pyserial.sf.net) (C) 2009 """ import serial import glob def scan(): """scan for available ports. return a list of device names.""" return glob.glob('/dev/ttyS*') + glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*') if __name__=='__main__': print "Found ports:" for name in scan(): print name pyserial-2.6/examples/wxSerialConfigDialog.wxg0000644000175000017500000003234311026531632021164 0ustar lchlch00000000000000 Serial Port Configuration wxVERTICAL wxEXPAND 0 wxVERTICAL wxRIGHT|wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 1 0 0 dummy1 dummy2 dummy3 dummy4 dummy5 wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 1 wxALIGN_RIGHT 0 0 choice 1 wxEXPAND 0 wxVERTICAL wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 1 wxALIGN_RIGHT 0 0 choice 1 wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 1 wxALIGN_RIGHT 0 0 choice 1 wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 1 wxALIGN_RIGHT 0 0 choice 1 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 0 1 wxALL|wxALIGN_CENTER_VERTICAL 4 1 wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 wxALL|wxALIGN_CENTER_VERTICAL 4 wxEXPAND 0 10 10 wxALL|wxALIGN_RIGHT 4 wxHORIZONTAL 0 1 0 pyserial-2.6/setup.py0000644000175000017500000000621711624326574014301 0ustar lchlch00000000000000# setup.py for pySerial # # Windows installer: # "python setup.py bdist_wininst" # # Direct install (all systems): # "python setup.py install" # # For Python 3.x use the corresponding Python executable, # e.g. "python3 setup.py ..." import sys from distutils.core import setup if sys.version_info >= (3, 0): try: from distutils.command.build_py import build_py_2to3 as build_py from distutils.command.build_scripts import build_scripts_2to3 as build_scripts except ImportError: raise ImportError("build_py_2to3 not found in distutils - it is required for Python 3.x") suffix = "-py3k" else: from distutils.command.build_py import build_py from distutils.command.build_scripts import build_scripts suffix = "" if sys.version < '2.3': # distutils that old can't cope with the "classifiers" or "download_url" # keywords and True/False constants and basestring are missing raise ValueError("Sorry Python versions older than 2.3 are no longer" "supported - check http://pyserial.sf.net for older " "releases or upgrade your Python installation.") # importing version does not work with Python 3 as files have not yet been # converted. #~ import serial #~ version = serial.VERSION import re, os version = re.search( "VERSION.*'(.+)'", open(os.path.join('serial', '__init__.py')).read()).group(1) setup( name = "pyserial" + suffix, description = "Python Serial Port Extension", version = version, author = "Chris Liechti", author_email = "cliechti@gmx.net", url = "http://pyserial.sourceforge.net/", packages = ['serial', 'serial.tools', 'serial.urlhandler'], license = "Python", long_description = "Python Serial Port Extension for Win32, Linux, BSD, Jython, IronPython", classifiers = [ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Intended Audience :: End Users/Desktop', 'License :: OSI Approved :: Python Software Foundation License', 'Natural Language :: English', 'Operating System :: POSIX', 'Operating System :: Microsoft :: Windows', #~ 'Operating System :: Microsoft :: Windows :: Windows CE', # could work due to new ctypes impl. someone needs to confirm that 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.3', 'Programming Language :: Python :: 2.4', 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.0', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', 'Topic :: Communications', 'Topic :: Software Development :: Libraries', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Terminals :: Serial', ], platforms = 'any', cmdclass = {'build_py': build_py, 'build_scripts': build_scripts}, scripts = ['serial/tools/miniterm.py'], ) pyserial-2.6/documentation/0000755000175000017500000000000011654115151015420 5ustar lchlch00000000000000pyserial-2.6/documentation/shortintro.rst0000644000175000017500000000643111616664326020404 0ustar lchlch00000000000000==================== Short introduction ==================== Opening serial ports ==================== Open port 0 at "9600,8,N,1", no timeout:: >>> import serial >>> ser = serial.Serial(0) # open first serial port >>> print ser.portstr # check which port was really used >>> ser.write("hello") # write a string >>> ser.close() # close port Open named port at "19200,8,N,1", 1s timeout:: >>> ser = serial.Serial('/dev/ttyS1', 19200, timeout=1) >>> x = ser.read() # read one byte >>> s = ser.read(10) # read up to ten bytes (timeout) >>> line = ser.readline() # read a '\n' terminated line >>> ser.close() Open second port at "38400,8,E,1", non blocking HW handshaking:: >>> ser = serial.Serial(1, 38400, timeout=0, ... parity=serial.PARITY_EVEN, rtscts=1) >>> s = ser.read(100) # read up to one hundred bytes ... # or as much is in the buffer Configuring ports later ======================= Get a Serial instance and configure/open it later:: >>> ser = serial.Serial() >>> ser.baudrate = 19200 >>> ser.port = 0 >>> ser Serial(port='COM1', baudrate=19200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=0, rtscts=0) >>> ser.open() >>> ser.isOpen() True >>> ser.close() >>> ser.isOpen() False Readline ======== Be carefully when using :meth:`readline`. Do specify a timeout when opening the serial port otherwise it could block forever if no newline character is received. Also note that :meth:`readlines` only works with a timeout. :meth:`readlines` depends on having a timeout and interprets that as EOF (end of file). It raises an exception if the port is not opened correctly. Do also have a look at the example files in the examples directory in the source distribution or online. .. note:: The ``eol`` parameter for :meth:`readline` is no longer supported when pySerial is run with newer Python versions (V2.6+) where the module :mod:`io` is available. EOL --- To specify the EOL character for :meth:`readline` or to use universal newline mode, it is advised to use io.TextIOWrapper_:: import serial import io ser = serial.serial_for_url('loop://', timeout=1) sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser)) sio.write(unicode("hello\n")) sio.flush() # it is buffering. required to get the data out *now* hello = sio.readline() print hello == unicode("hello\n") .. _io.TextIOWrapper: http://docs.python.org/library/io.html#io.TextIOWrapper Testing ports ============= Listing ports ------------- ``python -m serial.tools.list_ports`` will print a list of available ports. It is also possible to add a regexp as first argument and the list will only include entries that matched. .. note:: The enumeration may not work on all operating systems. It may be incomplete, list unavailable ports or may lack detailed descriptions of the ports. .. versionadded: 2.6 Accessing ports --------------- pySerial includes a small terminal console based terminal program called :ref:`miniterm`. It ca be started with ``python -m serial.tools.miniterm `` (use option ``-h`` to get a listing of all options). pyserial-2.6/documentation/index.rst0000644000175000017500000000172311463326246017273 0ustar lchlch00000000000000.. pySerial documentation master file Welcome to pySerial's documentation =================================== This module encapsulates the access for the serial port. It provides backends for Python running on Windows, Linux, BSD (possibly any POSIX compliant system), Jython and IronPython (.NET and Mono). The module named "serial" automatically selects the appropriate backend. Other pages (online) - `project page on SourceForge`_ - `SVN repository`_ - `Download Page`_ with releases - This page, when viewed online, is at http://pyserial.sf.net. .. _`project page on SourceForge`: http://sourceforge.net/projects/pyserial/ .. _`SVN repository`: http://sourceforge.net/svn/?group_id=46487 .. _`Download Page`: http://pypi.python.org/pypi/pyserial Contents: .. toctree:: :maxdepth: 2 pyserial shortintro examples pyserial_api pyparallel appendix Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` pyserial-2.6/documentation/pyserial.rst0000644000175000017500000000733311421576003020007 0ustar lchlch00000000000000========== pySerial ========== Overview ======== This module encapsulates the access for the serial port. It provides backends for Python running on Windows, Linux, BSD (possibly any POSIX compliant system), Jython and IronPython (.NET and Mono). The module named "serial" automatically selects the appropriate backend. It is released under a free software license, see LICENSE_ for more details. Copyright (C) 2001-2010 Chris Liechti Other pages (online) - `project page on SourceForge`_ - `SVN repository`_ - `Download Page`_ with releases - This page, when viewed online is at http://pyserial.sf.net. .. _LICENSE: appendix.html#license .. _`project page on SourceForge`: http://sourceforge.net/projects/pyserial/ .. _`SVN repository`: http://sourceforge.net/svn/?group_id=46487 .. _`Download Page`: http://sourceforge.net/project/showfiles.php?group_id=46487 Features ======== - Same class based interface on all supported platforms. - Access to the port settings through Python properties. - Support for different byte sizes, stop bits, parity and flow control with RTS/CTS and/or Xon/Xoff. - Working with or without receive timeout. - File like API with "read" and "write" ("readline" etc. also supported). - The files in this package are 100% pure Python. - The port is set up for binary transmission. No NULL byte stripping, CR-LF translation etc. (which are many times enabled for POSIX.) This makes this module universally useful. - Compatible with :mod:`io` library (Python 2.6+) - RFC 2217 client (experimental), server provided in the examples. Requirements ============ - Python 2.3 or newer, including Python 3.x - ctypes extensions on Windows (is in standard library since Python 2.5+) - "Java Communications" (JavaComm) or compatible extension for Java/Jython Installation ============ pyserial -------- This installs a package that can be used from Python (``import serial``). To install the module for all users on the system, administrator rights (root) is required.. From source (tar.gz or checkout) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Download the archive from http://pypi.python.org/pypi/pyserial. Unpack the archive, enter the ``pyserial-x.y`` directory and run:: python setup.py install For Python 3.x:: python3 setup.py install From PyPI ~~~~~~~~~ Alternatively it can be installed from PyPI, either manually downloading the files and installing as described above or using:: pip pyserial or:: easy_install -U pyserial Packages ~~~~~~~~ There are also packaged versions for some Linux distributions and Windows: Debian/Ubuntu A package is available under the name "python-serial". Note that some distributions package an older version of pySerial. Windows There is also a Windows installer for end users. It is located in the PyPi_. Developers may be interested to get the source archive, because it contains examples and the readme. .. _PyPi: http://pypi.python.org/pypi/pyserial References ========== * Python: http://www.python.org/ * Jython: http://www.jython.org/ * Java@IBM: http://www-106.ibm.com/developerworks/java/jdk/ (JavaComm links are on the download page for the respective platform JDK) * Java@SUN: http://java.sun.com/products/ * IronPython: http://www.codeplex.com/IronPython * setuptools: http://peak.telecommunity.com/DevCenter/setuptools Older Versions ============== Older versions are still available on the `Download Page`_. pySerial 1.21 is compatible with Python 2.0 on Windows, Linux and several un*x like systems, MacOSX and Jython. On windows releases older than 2.5 will depend on pywin32_ (previously known as win32all) .. _`Download Page`: http://sourceforge.net/project/showfiles.php?group_id=46487 .. _pywin32: http://pypi.python.org/pypi/pywin32 pyserial-2.6/documentation/pyparallel.rst0000644000175000017500000001032611234410446020320 0ustar lchlch00000000000000============ pyParallel ============ .. note:: This module is in development (since years ;-) Overview ======== This module encapsulates the access for the parallel port. It provides backends for Python running on Windows and Linux. Other platforms are possible too but not yet integrated. This module is still under development. But it may be useful for developers. Copyright (C) 2001-2003 Chris Liechti Here is the `project page on SourceForge`_ and here is the `SVN repository`_. .. _`project page on SourceForge`: http://sourceforge.net/projects/pyserial/ .. _`SVN repository`: http://sourceforge.net/svn/?group_id=46487 Features -------- * same class based interface on all supported platforms * port numbering starts at zero, no need to know the port name in the user program * port string (device name) can be specified if access through numbering is inappropriate Requirements ------------ * Python 2.2 or newer * "Java Communications" (JavaComm) extension for Java/Jython Installation ------------ Extract files from the archive, open a shell/console in that directory and let Distutils do the rest: ``python setup.py install`` The files get installed in the "Lib/site-packages" directory in newer Python versions. The windows version needs a compiled extension and the giveio.sys driver for Windows NT/2k/XP. The extension module can be compiled with Distutils with either MSVC or GCC/mingw32. It is released under a free software license, see LICENSE.txt for more details. Short introduction ================== :: >>> import parallel >>> p = parallel.Parallel() # open LPT1 >>> p.setData(0x55) Examples -------- Please look in the SVN Repository. There is an example directory where you can find a simple terminal and more. http://pyserial.svn.sourceforge.net/viewvc/pyserial/trunk/pyparallel/examples/ API === .. module:: parallel .. class:: Parallel .. method:: __init__(port) Open given parallel port. .. method:: setData(value) Apply the given byte to the data pins of the parallel port. .. method:: setDataStrobe(level) Set the "data strobe" line to the given state. .. method:: setAutoFeed(level) Set "auto feed" line to given state. .. method:: setInitOut(level) Set "initialize" line to given state. .. method: setSelect(level) Set "select" line to given state. .. method:getInError() Set "Error" line to given state. .. method:: getInSelected() Read level of "select" line. .. method:: getInPaperOut() Read level of "paper out" line. .. method:: getInAcknowledge() Read level of "Acknowledge" line. .. method: getInBusy() Read level of "busy" line. .. module:: parallel.parallelutil .. class:: BitaccessMeta This mix-in class adds a few properties that allow easier bit access to the data lines. (D0 .. D7) e.g. p.D0 refers to the first bit of the data lines. .. class:: VirtualParallelPort This class provides a virtual parallel port implementation, useful for tests and simulations without real hardware. Notes ===== Linux ----- 1. The :manpage:`lp(4)` module must be unloaded, ``rmmod lp``. ``lp`` claims exclusive access to the port and other programs won't be able to use it. 2. The :manpage:`ppdev(4)` module needs to be loaded, ``modprobe ppdev``. When ``udev`` is in use, (default with 2.6 kernels) this will create a ``/dev/parport0``. 3. The user needs to have write permissions to ``/dev/parport0``. Many distributions have an ``lp`` group that owns the device; the simplest is to add the user account to this group. Simply changing permissions on the device is not the best strategy as they will be reverted to their defaults next time the driver is loaded. Windows ------- The giveio driver must be installed as the module needs direct access to the hardware. This also means that USB parallel port adapters won't be supported. Misc ==== References ---------- * Python: http://www.python.org/ * Jython: http://www.jython.org/ * Java@IBM: http://www-106.ibm.com/developerworks/java/jdk/ (JavaComm links are on the download page for the respective platform JDK) * Java@SUN: http://java.sun.com/products/ pyserial-2.6/documentation/pyserial.png0000644000175000017500000001561211234410446017762 0ustar lchlch00000000000000‰PNG  IHDRÎpVßOÁsBIT|dˆtEXtSoftwarewww.inkscape.org›î<IDATxœíw¸EÕÇ?ç&R BH¨ÑФ„ª€TA^}1*R|x%‚‚_Š‚¤( ‚H‘W‘¥7©HÔPB JHB œ÷3¿ÜßÝìÎÌ–{ɽû}ž}öÞ9gf÷·ggæÌ)¢ª$!"+ƒ€îXj‘J5jt_Ìf¹cšªNMVfÁ‘¾À:ÀŠ]ÕÃ5–L^PÕ Žˆ ÖÚZÓ·5k,&ªê€Þ"ÒX—ŽB3˜Ì>¤Fžƒ¾@l¹ÒX¦´ëŠÈLU-@/` W±7IªúIWö¶FÅ "Ò¬Úty6ðho`e: ÍëªúRö¯FÅnàx^Dæk¸Ëý•Û€Mug“º¸5j,ÉF“‚ó¾¦é§kÔèÁp2ñ~Ó¥m@¿¦ ³º¶K5j,1h–~IÕó‚®ìIK:ÈF½gS£FÔ‚S£FÔ‚S£FÔ‚S£FÔ‚S£FôXÁÃHÙ]DV©˜÷r"ÒcŸmO@îÅø2¦¦kšò7˜¡œïè Ìf¸ãƒ¦¿g¨je{L"2ø °BÓµ7€ãTõš‚<Û€јkÆt¹8EUŸ(Ñ×A˜½ÔšØsjlPûÎKRªÚ˜ <×UøìÜôÿ3ªúv¡È2t­Õô|Ìôáqà w~LU§åe$"# Øý'q-ðUU—ƒß2Àÿ{¦¦ª—æìß à;À‘À<´=“€Ë€ËUõÍ*‹ÈÊÀ ÿgÉœ4|Ü\ \—GˆDä/؈™†k€U5jCXDÎÆdKU—£_?¾, Ì^^Á¾ª`¿›4ý<ûʺ²NW¶±°6*ÏNPÕ³¨IÁœÆ±²ªsËÐ>Œ.Ç\àF`­Èþ¯ïp¿Ó#ùlOûÔ4íøJŽg:ÖÑÌ~¬K[ féÿ}à=÷¯˜w³¬tÁi3€ý"ïá=|æ›Eð¸'ПU#ûr¢«?øT«_Â%ù6sïÁü<®Ï‚Ó5?Ë׉È"Ò+P÷ìᦡ7p‰sfJ…ˆlìèá?I#æÚÎmýTà]`WU}%DS#ªú8ðlr¾ï7,Šî(8 (™PÕ+=U6Žó”ŸèÃòöÃæêç¨êÄHš¨ê8La³°KÕü—tå@ WÕK² EäÓÀD OF•€‘NÈšé¶ÄîYx[o}ê ˆÜì|Æ'8"²扸 æ;u]ˆwmo``kìwS¨Ìõ¶Ó÷þ…™ØnR7‰ _ɵ¿ðoà^U½'Gÿ‡ûaÚ³Û4 æ‘½€+TõàØ¶2xu[å@Ö1X/p/x<ôJÐÜ ùvŽgù*¶%åü4¥ñÀÖüG¤Ðÿ X7‚~¦ÙKÒß ‰ ßx'…þ* _ýáîwl¦œ™õÌ]÷\_¯zÝ_pÛ³YÊs/kxü°©þ^º¯}r<Ë›Ý"Jl­u•+ŸŒ­…Žnw×>Fxx÷su¯w/ñ°iŒOžÍò®].v¾Üë®Ý!´³1eËX`'àkÀ3ŽþWú1­å,àÀÀ·šúôßÚe]º«à|ˆ©gUÈ3y¸Ÿóô»øZ îÁ9”ÓÝ"Ú@lSµñ‚¯–(ûŽ+»ÈÃû«®Îõ)e <ÄCÿcWçÜlŒbÛyè¯puŽLy©_sB‘©yîwôŸÏÈé@[í(Gûûª§UÊ]a˜¬—ªöUÕÁª:ÈÕ±ó9Ø—© (?ûzga)L‘ðwÚ#ž¤a<ö²äÁ“î¼qJÙîî|’ªNN”5ÚYÏÃ{ w¾8¥ì‚D4líÎç7_T‹sQ¢NVûŸ`;úÍô3±ç)غg¸uÙæÀ«ªz[‚~p 3ã3m7®W®pi•àLRÕ)ª:S»óªú±ªNVÕ¿«ê±ªº!ðEl>^»ˆÈšY…ªúðÛ€­<åó0KÍٷƽL)kÄôJSÚ4Ô¬i¦C 4”i&Dóu:‹~éjÿ}÷/K¢ßЫúø.D«'J“Ó€ª^©†O.Ѧ‡êü[LÅYªútº°Ñ.mĹÁOuš­fìáξ6sçƒRÊIÔICCsxhóEi~ž>íâcØhýŸ úe°i$˜Ýá"PÓøMÖ‘mô«`÷?‡ìûo<Ï'3ÊK¡kœÁ療™Õmw|Dc òžô-1‡~û2/›¸ÞŸvë„)Ø”éàRLØ>¶õð]xÖÑ_ŒM6ǦiŠiË2û™¾‹M·~ŠºÛbö|êúæÓlm@{ôÿc±éÓ.À}D¬?0E†b#îÁ˜åù>´+~ä¡ý7¦¶/µ¾I[ã´Jp–+q+`_™"í¾Á0f\™—÷ž%˜KŸE„‹e|1‹ªdßöà=Õ’}~Ø<‚~Lh“ôkDДñLï– ÿ¡¾$ýå@oÀ+pOgN«6@ûjÄÆ §íû0ãÊ"X^Ugøÿ Ó&Åb¼ªn®æmó[Øb{Œªþ*£ÎrÀvØ‚x*öRD¹?¸ßë0lÄlzt©Fú9¹œI‡›`üOà_Ü­/¿Ž ñÛÀýšÃ÷ɹ‚|±^nQÕxêïŠ æyªúØv<ü:l€VnÃÛ’ôR\pÖÂ?§8 8šŽQN}øYÁ¾4ã~wÞHUýÓ$å†ûPÅš¥ÑOÅ6‹Ò¿œV‚þIò­U:u}Ó*å@YÁÉí¼Ö„ÕCÔüzΈä÷šªÞ\¢? LĦ^E?5:¢¡¡ìV‚S¶Ý%hgFÖ;‹8ýÿ%ú²jé€!"²N<{86Æ”-E´œA,©SµµJоSIUçŠÈ÷ Æ òØ®¿[yèÿàꕸ¾"ð¶ñºRÎgxE¨Ý%uÄÙ+/s/¾³ª-Š¿ ì)ëŒ|Byý¦‘õ÷sçËTõÕDÙ÷ÜùÓúmÜù×)e¿IÔIÖîÜAÕ­¶¿tI¢NVûÑn0Ú ŸŠE/ê Ïâù1F¬SÐ*Á9@Dˆ­,"ëa_þO•l·jÁ錅g^ÁYÑßI)SwöýάÊiöƒ'êøè?N)››¨“E?ŸôÜL1íw€ó4]xB#½[‹ •1.‘CEdé¬ "2LD.À|QÒ,‡óà9U-b%ëœE;ãÁ£î+8·ºóÑ"’|ÁNpç—=ô»óÁ)eßHÔICÃ@óÍèèD¬önÙÍôý€šêÄb_w¾'M!´Ú‘m Tãjl‘y;¦{ŸQÿÆ1¦À¼¶o€g´{tŽ6sΚFœ× Ú×}s€?bVÞO4õó‹ú~´kÄ~‹ ì¦îoue™î͘_Õ4Lûx*fÊ¿ íë£;ñnæhgaŽyëºwñAGŸË vƒØ+þ] #Ï®>"3 òW ð=±jÁqížéøŸY}Ìv-Ù¿Xìêý¦Ø¨”¤Ø4‚~¯Œö#ᵚA‹°*6=6Æ P@ ”WpZµÚ•˜‹iñ¢6òHú¿$±B ¼(Æßƈȹª:ÝWYUŸuÊ“#±©Ê@Ì9î4"®›ª>áŒ(¥£*÷20UÕ›]žoÒ´J¤¨ª^&"ã°©]cô.UÍ»&ØÌI—=!<ÔOTµ¦ˆl†ß ´tØ!OÛg`±áÆªê ¡ú=Îúz<0SË¿^1ÿÖÑÝ9 !˜Šóç%èC#NÕxgbë¿ãEıÇCD†`.À3«š4tWÁY€åº9¢à­Ö,:H^¨ê{Ølàmà—"r|gµµ$ƼSA_ØU£swœYX˜¥³+àõR À¦wÆj#›xÆâ'l‚YÞNÄ”%ïоo1ÇŸ,£öv@wÀö?†a w”Ýï‘­ß­±wé=ÌïÊ2š/ç˳°&¦=œüÍYS,6èj·‚qLºw§=ÁP̱ ²q–Ì Ëô¥ØK;‰ö—7¶½ùX†²õ#ïg'ÒSûe³1uøMâ÷KáÖ>ƒçòdGš]‚wÚ»5H7‹Î8X üq¢Cö`:üsœ i«q|9RpÊoŸ´54§Ð$]—.)8ŠíÊ{ûëáùÕˆ¾^‚lj­à»Uy€”"‚ÓŠ5Nž`„WbÓ™² ‡”¤Å*„ÃK¹ðXkaß÷‹H0œoKQ<çоá*Fz^ž2øAÅü ¡‚eŠ/"c°èôUÀ7 j„bìZQ;£€‡]‚¥2ȲÃË„‹”¹gdõ±n YÖ‘*äW‹¥àˆÈj˜dø£ÏçäUë¤Í*6©°­¡ÀŸ\øÚ¢."yíÞv >“Ã,!U•ÈÊùÙeh…à ‹¨ó_øóJ6p'ð9,Ìê̼ü$õ“¹;O â#àÀg5;,ÑNÄM;§±¯1£Ï¢hô”y3MkÆ‘"RåËÞ¯B^…Ð uô"Ò¦‰¤¹ ¸iÀáóoªjßrU} xJDÇ¢æônÔœªbfbž“Ýñ¦;&Ok8É“/0`'c°ŽÎ&ü;}…r~öëa÷‹¼‚Ó ûÀ=—“. !ÏÜNG+§¶ˆN¦o`=LƒáÃ!I¡i†ªÞ("«b¹.(ÔËŽ¸‹Qö˜–ó( í-½ ü¢Iϳ-Ô(›ÍØ­DŸ Û¯g¸ à ´Ñ­FœV™Ü¬é)[ÕSðˆª^j@U§«ê?´DÊD‡çUõá’BaÁ«  U=‹QÖ™Èúˆ¥!ïhÓ@•‚Óò§U‚3ÜSm®¯°1xY"¿„穌멩 ›PÖÕ"Bª Y‚ó>fñž…õs´zÞe”!•`qœÐèsàê lï´aU $8Ypðš‡.”ÓÔ‡XV€ Dd– ' çcf2YqVqÑhbŠÅÖe^·Yh•àø`ÖW·ÃDä˜*;ÀÚ£þ—ÅÔ@yªà¸ÏgM~‘§,„™Ÿãg²µ‚Õ‚í¡ß;¦‘ˆ)±7kxW U‚“}ÞiÀ|ÑeÚ€sEä=¹MDN‘Ý ìE4#ôâãÚ:_DŽ‘½Dd§Œ†{±|nÞE¦\Sèü5P¾õM#׿½¤g>Ñ'áÓPöØ'ôÂý2‚ÇŠ˜ñç°`ÓDäz}3/Ba^—qmœ Ü„) >‘—Dä9Öù¥‡àuVK»(";’=Eº$LjQ"Ò U•†)8Áqʘ¬ìy>p¾{ê±#N(¯Ìåä[°‚„î<*"Wç\—MÕ soØËRý¼ˆl ñ ÎI?Dd€ˆl#"G&}Aü¶¶è ì†}@ÒpKBò?õú‘-|IøFœ–GWj•àx7œJök„§PilCð‘6MUeVHØhÒ'8;ˆÈk"ò6yË¡94£þånî†à›fÝÒüªÞ¥lÉ˧¾ß¾å4[ÕŸÚU½(3y8ð  ‘B•) C6\¡Ñv ,œkÈ4g>_ºÓ!"md/ì?Á¦ÊI\—Q稂oÄ鱂5 SÕ_cɆŠÎá×F¬=ªúÿ(¯*5È}ªêË´V%¶!Ûb¼ª¦­9^Ȩ?”¸œž¾ß¼¬›Ii´Jp¢ºó]‰ÜkHÁjÀŸuÊf˜Åwž€yjú°b <ã*âßôêæŒë¾UÌt-Ֆѡǎ8¹"oºiÛZØÔ­Èœ~gñ-JóŒ/¿¾ŽYú¨êUÝTþöU N§F/M ˆàøØbÇgVÓrå@«æþÑÕ"xž-"bæù»a*âXSŽcfÿi ÎLlÑ•ªþ;²½EàÖ Ë¥O`íŠøx᤬—Qü¦ª>™Bs°¿‡í†"ò)U}ÅSÇ—be¦§¬KЪ§p^UýPUoVÕïªêØ t<~“€\*ï4$ª7ã=`U=»ŒÐ4µã{æ{bÓÆþ˜fðQOÝÑ"2¢dbàf‹ÈÁ"²‘ˆŒ‘½EäzLZ‡dòuŽ€¾í=Vp*‹´¯ª/©ê™Ø(Ze-J}#ÎÉZ]põå媪³TuŽª^ƒ-ÊoɨÛ¸ID†G´[f1íœu€Ë°ˆBÿnÀöÒÊò ­9{¬àTžÐ ûªeYøü;ªŒ8êûŠBb^ï,¾‚E¶IúÀøˆ …‚ƒˆÈŠˆI‰D$kÚÊ„×åÙ ’è6‚ã²aÊ2ô™©ÇxmÆ"dj´È‚ØÙ·ù"ç %Ÿ!Õ”'{Ñy&ü½Éøz?B>[Žî&8£åY6N¾—ã8Ï—1/B#N–IËUX„Ò,("ÛzÊ‹ Î ÒÅ"kºz?–è(7eÖ)^>·Ðü‹ˆŒ‘‰ÈñY‘cšhŽÆüA|Èšòøge Pº÷„FœTm£3³¿<@{®gG>·à¸<£ŸÏK—{fX˜‡¦j§¤åA‘^"²¹ˆléŒR; eÔÑE¬ÈôðsÖ³wÒq^>³¬ÝßM]šë÷ôj'áÇd²ÕÑ¡éÈQ"2‹>Ó8f²hò«'›TõÕ >¡Ççæ}p Ù ýQX çñ)eEö|v"üƒ­7ÞÀ3o Íã Lõ>Sr¤­#bQzîL\}”×Çl¯Æöõ6pÇ–´›<-‘ß?RÕ÷#î#ÊNèëîƒÏœ"˼cWà-¹€Xì‚opðrƒTÌ†Ú üjëΑTõ¦”²éÚLÁQÕ×Eän:¦žLbSÒçY"È`aü·P€q˜‹Å žpX ~¾Œvû²¨àÄlWl„ÊÖ†…ÛFD¶ÑD@ý²(3UóÜÁçáçûê.‹Å,¾ûѾKœÐ¼™ýg!htšK“Þ*”¥!$À—ʳ¢ˆæ Ët!þ ÖUõÚÐ8øî+mSxŸ/# ‡%Î2‚ót¸J&|#Î?É6,Åb°ù¾öeî% Y.Ðsðï5…ö‹þøvÛ³¢„F Žˆô¾à©r…ªž–/YSd€5]È©f¼LŽU¨*”òB”œ{)~s™ÖÑîù6áiM æcœˆã¨ÖµàbOYV_^WÕ‰>¦îëþcO•áן$r?Êíeó± ñyñ+üaˆ;Œ:Îêû÷ÚÉBå²…ÇÙ(_€t²©ê]ØB¯Ìj –g44WoŒU…º? ¨×f\qGU¯.È(N}^ÎÎ/Ë+3 YÉ‹,´Uõ]lújF•´éÚ‰À]yÛÊÀo*âÓ…òã4å 9{ ±ù]NËÁ»/¶À{6ÿÉØCœó>†»{ù!pö‚ÇlàæzÚ›M…þˆYo´ÓK’õ£8=g_›·7çÙù„@¢(׿d2¨é)õ–”Íy‰>ŽËû~$ø®‰­5_Kôa°JÆ} ÜŠÍ@òäú3]¦ÏM}éG訥yF ¸â:úvX´ÆõšŽ¾Ø—¿ùø¹ª†Â$%ù ðYׯ(lÁ·4¦Fž<<Ž­nÑŠƒW¸öÓîcò‰k÷à]M¨Èsð\³0.Ôߦt+Tõ‘šaØh¾*öAz*ë÷pu?‹ Ûø"ïF_q}X§Æ½β|ö›7m˜àÍMsr®ÃB}^SyÛÿT 85jtw$§åžt5j,‰¨§F¨§F¨§F¨§F¨§F¨§F¨§FH N-H5j¤£-ùO³ƒOŒÇ_=Ͳ1§Ž,VˆŒ$_£F“‰æØ{3’‚ÓK”T£FvŒ c€™mX°ƒæokˆÈºÎ°F é-"ëÒ1ÓùlàmQÕF~Ç-èíe.Íe6‹Atø5º}±f#ÍUÕÙâœt‘¡˜M­Y«QcQ,À<`§,XÓlªËáR£FwÀTàç‚$gáE ¶=SÁ H¯FXð–YÀ´4ïÔÿ¯Ê¦AÙ ™nIEND®B`‚pyserial-2.6/documentation/pyserial_api.rst0000644000175000017500000007067211625552111020646 0ustar lchlch00000000000000============== pySerial API ============== .. module:: serial Classes ======= Native ports ------------ .. class:: Serial .. method:: __init__(port=None, baudrate=9600, bytesize=EIGHTBITS, parity=PARITY_NONE, stopbits=STOPBITS_ONE, timeout=None, xonxoff=False, rtscts=False, writeTimeout=None, dsrdtr=False, interCharTimeout=None) :param port: Device name or port number number or :const:`None`. :param baudrate: Baud rate such as 9600 or 115200 etc. :param bytesize: Number of data bits. Possible values: :const:`FIVEBITS`, :const:`SIXBITS`, :const:`SEVENBITS`, :const:`EIGHTBITS` :param parity: Enable parity checking. Possible values: :const:`PARITY_NONE`, :const:`PARITY_EVEN`, :const:`PARITY_ODD` :const:`PARITY_MARK`, :const:`PARITY_SPACE` :param stopbits: Number of stop bits. Possible values: :const:`STOPBITS_ONE`, :const:`STOPBITS_ONE_POINT_FIVE`, :const:`STOPBITS_TWO` :param timeout: Set a read timeout value. :param xonxoff: Enable software flow control. :param rtscts: Enable hardware (RTS/CTS) flow control. :param dsrdtr: Enable hardware (DSR/DTR) flow control. :param writeTimeout: Set a write timeout value. :param interCharTimeout: Inter-character timeout, :const:`None` to disable (default). :exception ValueError: Will be raised when parameter are out of range, e.g. baud rate, data bits. :exception SerialException: In case the device can not be found or can not be configured. The port is immediately opened on object creation, when a *port* is given. It is not opened when *port* is :const:`None` and a successive call to :meth:`open` will be needed. Possible values for the parameter *port*: - Number: number of device, numbering starts at zero. - Device name: depending on operating system. e.g. ``/dev/ttyUSB0`` on GNU/Linux or ``COM3`` on Windows. The parameter *baudrate* can be one of the standard values: 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200. These are well supported on all platforms. Standard values above 115200 such as: 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000 also work on many platforms. Non-standard values are also supported on some platforms (GNU/Linux, MAC OSX >= Tiger, Windows). Though, even on these platforms some serial ports may reject non-standard values. Possible values for the parameter *timeout*: - ``timeout = None``: wait forever - ``timeout = 0``: non-blocking mode (return immediately on read) - ``timeout = x``: set timeout to ``x`` seconds (float allowed) Writes are blocking by default, unless *writeTimeout* is set. For possible values refer to the list for *timeout* above. Note that enabling both flow control methods (*xonxoff* and *rtscts*) together may not be supported. It is common to use one of the methods at once, not both. *dsrdtr* is not supported by all platforms (silently ignored). Setting it to ``None`` has the effect that its state follows *rtscts*. Also consider using the function :func:`serial_for_url` instead of creating Serial instances directly. .. versionchanged:: 2.5 *dsrdtr* now defaults to ``False`` (instead of *None*) .. method:: open() Open port. .. method:: close() Close port immediately. .. method:: __del__() Destructor, close port when serial port instance is freed. The following methods may raise :exc:`ValueError` when applied to a closed port. .. method:: read(size=1) :param size: Number of bytes to read. :return: Bytes read from the port. 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. .. versionchanged:: 2.5 Returns an instance of :class:`bytes` when available (Python 2.6 and newer) and :class:`str` otherwise. .. method:: write(data) :param data: Data to send. :return: Number of bytes written. :exception SerialTimeoutException: In case a write timeout is configured for the port and the time is exceeded. Write the string *data* to the port. .. versionchanged:: 2.5 Accepts instances of :class:`bytes` and :class:`bytearray` when available (Python 2.6 and newer) and :class:`str` otherwise. .. versionchanged:: 2.5 Write returned ``None`` in previous versions. .. method:: inWaiting() Return the number of chars in the receive buffer. .. method:: flush() Flush of file like objects. In this case, wait until all data is written. .. method:: flushInput() Flush input buffer, discarding all it's contents. .. method:: flushOutput() Clear output buffer, aborting the current output and discarding all that is in the buffer. .. method:: sendBreak(duration=0.25) :param duration: Time (float) to activate the BREAK condition. Send break condition. Timed, returns to idle state after given duration. .. method:: setBreak(level=True) :param level: when true activate BREAK condition, else disable. Set break: Controls TXD. When active, no transmitting is possible. .. method:: setRTS(level=True) :param level: Set control line to logic level. Set RTS line to specified logic level. .. method:: setDTR(level=True) :param level: Set control line to logic level. Set DTR line to specified logic level. .. method:: getCTS() :return: Current state (boolean) Return the state of the CTS line. .. method:: getDSR() :return: Current state (boolean) Return the state of the DSR line. .. method:: getRI() :return: Current state (boolean) Return the state of the RI line. .. method:: getCD() :return: Current state (boolean) Return the state of the CD line Read-only attributes: .. attribute:: name Device name. This is always the device name even if the port was opened by a number. (Read Only). .. versionadded:: 2.5 .. attribute:: portstr :deprecated: use :attr:`name` instead New values can be assigned to the following attributes (properties), the port will be reconfigured, even if it's opened at that time: .. attribute:: port Read or write port. When the port is already open, it will be closed and reopened with the new setting. .. attribute:: baudrate Read or write current baud rate setting. .. attribute:: bytesize Read or write current data byte size setting. .. attribute:: parity Read or write current parity setting. .. attribute:: stopbits Read or write current stop bit width setting. .. attribute:: timeout Read or write current read timeout setting. .. attribute:: writeTimeout Read or write current write timeout setting. .. attribute:: xonxoff Read or write current software flow control rate setting. .. attribute:: rtscts Read or write current hardware flow control setting. .. attribute:: dsrdtr Read or write current hardware flow control setting. .. attribute:: interCharTimeout Read or write current inter character timeout setting. The following constants are also provided: .. attribute:: BAUDRATES A list of valid baud rates. The list may be incomplete such that higher baud rates may be supported by the device and that values in between the standard baud rates are supported. (Read Only). .. attribute:: BYTESIZES A list of valid byte sizes for the device (Read Only). .. attribute:: PARITIES A list of valid parities for the device (Read Only). .. attribute:: STOPBITS A list of valid stop bit widths for the device (Read Only). The following methods are for compatibility with the :mod:`io` library. .. method:: readable() :return: True .. versionadded:: 2.5 .. method:: writable() :return: True .. versionadded:: 2.5 .. method:: seekable() :return: False .. versionadded:: 2.5 .. method:: readinto(b) :param b: bytearray or array instance :return: Number of byte read Read up to len(b) bytes into :class:`bytearray` *b* and return the number of bytes read. .. versionadded:: 2.5 The port settings can be read and written as dictionary. .. method:: getSettingsDict() :return: a dictionary with current port settings. Get a dictionary with port settings. This is useful to backup the current settings so that a later point in time they can be restored using :meth:`applySettingsDict`. Note that control lines (RTS/DTR) are part of the settings. .. versionadded:: 2.5 .. method:: applySettingsDict(d) :param d: a dictionary with port settings. Applies a dictionary that was created by :meth:`getSettingsDict`. Only changes are applied and when a key is missing it means that the setting stays unchanged. Note that control lines (RTS/DTR) are not changed. .. versionadded:: 2.5 Platform specific methods. .. warning:: Programs using the following methods are not portable to other platforms! .. method:: nonblocking() :platform: Unix Configure the device for nonblocking operation. This can be useful if the port is used with :mod:`select`. .. method:: fileno() :platform: Unix :return: File descriptor. Return file descriptor number for the port that is opened by this object. It is useful when serial ports are used with :mod:`select`. .. method:: setXON(level=True) :platform: Windows :param level: Set flow control state. Set software flow control state. .. note:: For systems that provide the :py:mod:`io` library (Python 2.6 and newer), the class :class:`Serial` will derive from :py:class:`io.RawIOBase`. For all others from :class:`FileLike`. Implementation detail: some attributes and functions are provided by the class :class:`SerialBase` and some by the platform specific class and others by the base class mentioned above. .. class:: FileLike An abstract file like class. It is used as base class for :class:`Serial` when no :py:mod:`io` module is available. This class implements :meth:`readline` and :meth:`readlines` based on :meth:`read` and :meth:`writelines` based on :meth:`write`. Note that when the serial port was opened with no timeout, that :meth:`readline` blocks until it sees a newline (or the specified size is reached) and that :meth:`readlines` would never return and therefore refuses to work (it raises an exception in this case)! .. method:: writelines(sequence) Write a list of strings to the port. The following three methods are overridden in :class:`Serial`. .. method:: flush() Flush of file like objects. It's a no-op in this class, may be overridden. .. method:: read() Raises NotImplementedError, needs to be overridden by subclass. .. method:: write(data) Raises NotImplementedError, needs to be overridden by subclass. The following functions are implemented for compatibility with other file-like objects, however serial ports are not seekable. .. method:: seek(pos, whence=0) :exception IOError: always, as method is not supported on serial port .. versionadded:: 2.5 .. method:: tell() :exception IOError: always, as method is not supported on serial port .. versionadded:: 2.5 .. method:: truncate(self, n=None) :exception IOError: always, as method is not supported on serial port .. versionadded:: 2.5 .. method:: isatty() :exception IOError: always, as method is not supported on serial port .. versionadded:: 2.5 To be able to use the file like object as iterator for e.g. ``for line in Serial(0): ...`` usage: .. method:: next() Return the next line by calling :meth:`readline`. .. method:: __iter__() Returns self. Other high level access functions. .. method:: readline(size=None, eol='\\n') :param size: Max number of bytes to read, ``None`` -> no limit. :param eol: The end of line character. Read a line which is terminated with end-of-line (*eol*) character (``\n`` by default) or until timeout. .. method:: readlines(sizehint=None, eol='\\n') :param sizehint: Ignored parameter. :param eol: The end of line character. Read a list of lines, until timeout. *sizehint* is ignored and only present for API compatibility with built-in File objects. Note that this function only returns on a timeout. .. method:: xreadlines(sizehint=None) Read lines, implemented as generator. Unlike *readlines* (that only returns on a timeout) is this function yielding lines as they are received. .. deprecated:: 2.5 Use ``for line in Serial(...): ...`` instead. This method is not available in Python 2.6 and newer where the :mod:`io` library is available and pySerial bases on it. .. versionchanged:: 2.5 Implement as generator. :rfc:`2217` Network ports ------------------------- .. warning:: This implementation is currently in an experimental state. Use at your own risk. .. class:: rfc2217.Serial This implements a :rfc:`2217` compatible client. Port names are URLs_ in the form: ``rfc2217://:[/