summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/test_rawio.py57
-rw-r--r--serial/serialcli.py21
-rw-r--r--serial/serialjava.py21
-rw-r--r--serial/serialposix.py23
-rw-r--r--serial/serialutil.py107
-rw-r--r--serial/serialwin32.py19
-rw-r--r--setup.py6
7 files changed, 223 insertions, 31 deletions
diff --git a/examples/test_rawio.py b/examples/test_rawio.py
new file mode 100644
index 0000000..674934f
--- /dev/null
+++ b/examples/test_rawio.py
@@ -0,0 +1,57 @@
+##! /usr/bin/env python
+# Python Serial Port Extension for Win32, Linux, BSD, Jython
+# see __init__.py
+#
+# (C) 2001-2008 Chris Liechti <cliechti@gmx.net>
+# this is distributed under a free software license, see license.txt
+
+"""\
+Some tests for the serial module.
+Part of pyserial (http://pyserial.sf.net) (C)2001-2009 cliechti@gmx.net
+
+Intended to be run on different platforms, to ensure portability of
+the code.
+
+This modules contains test for RawSerial. This only works on Python 2.6+ with
+the io library.
+
+For all these tests a simple hardware is required.
+Loopback HW adapter:
+Shortcut these pin pairs:
+ TX <-> RX
+ RTS <-> CTS
+ DTR <-> DSR
+
+On a 9 pole DSUB these are the pins (2-3) (4-6) (7-8)
+"""
+
+import unittest, threading, time
+import serial
+
+# on which port should the tests be performed:
+PORT=0
+
+class Test_RawSerial(unittest.TestCase):
+
+ def setUp(self):
+ self.s = serial.RawSerial(PORT)
+
+ def tearDown(self):
+ self.s.close()
+
+ def test_hello(self):
+ self.s.write(bytes("hello"))
+ hello = self.s.read(5)
+ #~ print hello
+ self.failUnlessEqual(hello, bytes("hello"))
+
+
+if __name__ == '__main__':
+ import sys
+ sys.stdout.write(__doc__)
+ if len(sys.argv) > 1:
+ PORT = sys.argv[1]
+ sys.stdout.write("Testing port: %r\n" % PORT)
+ sys.argv[1:] = ['-v']
+ # When this module is executed from the command-line, it runs all its tests
+ unittest.main()
diff --git a/serial/serialcli.py b/serial/serialcli.py
index 6961bf6..5360cb3 100644
--- a/serial/serialcli.py
+++ b/serial/serialcli.py
@@ -21,7 +21,7 @@ sab = System.Array[System.Byte]
def as_byte_array(string):
return sab([ord(x) for x in string])
-class Serial(SerialBase):
+class IronSerial(SerialBase):
"""Serial port implemenation for .NET/Mono."""
BAUDRATES = (50,75,110,134,150,200,300,600,1200,1800,2400,4800,9600,
@@ -145,7 +145,7 @@ class Serial(SerialBase):
if not self._port_handle: raise portNotOpenError
return self._port_handle.BytesToRead
- def read(self, size=1):
+ def _read(self, size=1):
"""Read size bytes from the serial port. If a timeout is set it may
return less characters as requested. With no timeout it will block
until the requested number of bytes is read."""
@@ -162,7 +162,7 @@ class Serial(SerialBase):
size -= 1
return ''.join(data)
- def write(self, data):
+ def _write(self, data):
"""Output the given string over the serial port."""
if not self._port_handle: raise portNotOpenError
if not isinstance(data, str):
@@ -173,6 +173,7 @@ class Serial(SerialBase):
self._port_handle.Write(as_byte_array(data), 0, len(data))
except System.TimeoutException, e:
raise writeTimeoutError
+ return len(data)
def flushInput(self):
"""Clear input buffer, discarding all that is in the buffer."""
@@ -230,6 +231,20 @@ class Serial(SerialBase):
return self._port_handle.CDHolding
# - - platform specific - - - -
+ # none
+
+
+# assemble Serial class with the platform specifc implementation and the base
+# for file-like behavior
+class Serial(IronSerial, FileLike):
+ pass
+
+# for Python 2.6 and newer, that provide the new I/O library, implement a
+# RawSerial object that plays nice with it.
+if support_io_module:
+ class RawSerial(IronSerial, RawSerialBase):
+ pass
+
#Nur Testfunktion!!
if __name__ == '__main__':
diff --git a/serial/serialjava.py b/serial/serialjava.py
index 2dbaad6..d7e68c4 100644
--- a/serial/serialjava.py
+++ b/serial/serialjava.py
@@ -46,7 +46,8 @@ def device(portnumber):
ports.append(el)
return ports[portnumber].getName()
-class Serial(SerialBase):
+
+class JavaSerial(SerialBase):
"""Serial port class, implemented with Java Communications API and
thus usable with jython and the appropriate java extension."""
@@ -144,7 +145,7 @@ class Serial(SerialBase):
if not self.sPort: raise portNotOpenError
return self._instream.available()
- def read(self, size=1):
+ def _read(self, size=1):
"""Read size bytes from the serial port. If a timeout is set it may
return less characters as requested. With no timeout it will block
until the requested number of bytes is read."""
@@ -160,10 +161,11 @@ class Serial(SerialBase):
read = read + chr(x)
return read
- def write(self, data):
+ def _write(self, data):
"""Output the given string over the serial port."""
if not self.sPort: raise portNotOpenError
self._outstream.write(data)
+ return len(data)
def flushInput(self):
"""Clear input buffer, discarding all that is in the buffer."""
@@ -190,7 +192,7 @@ class Serial(SerialBase):
"""Set terminal status line: Request To Send"""
if not self.sPort: raise portNotOpenError
self.sPort.setRTS(level)
-
+
def setDTR(self, level=1):
"""Set terminal status line: Data Terminal Ready"""
if not self.sPort: raise portNotOpenError
@@ -217,6 +219,17 @@ class Serial(SerialBase):
self.sPort.isCD()
+# assemble Serial class with the platform specifc implementation and the base
+# for file-like behavior
+class Serial(JaveSerial, FileLike):
+ pass
+
+# for Python 2.6 and newer, that provide the new I/O library, implement a
+# RawSerial object that plays nice with it.
+if support_io_module:
+ class RawSerial(JavaSerial, RawSerialBase):
+ pass
+
if __name__ == '__main__':
s = Serial(0,
diff --git a/serial/serialposix.py b/serial/serialposix.py
index 0b87090..2a989fd 100644
--- a/serial/serialposix.py
+++ b/serial/serialposix.py
@@ -265,7 +265,7 @@ TIOCSBRK = hasattr(TERMIOS, 'TIOCSBRK') and TERMIOS.TIOCSBRK or 0x5427
TIOCCBRK = hasattr(TERMIOS, 'TIOCCBRK') and TERMIOS.TIOCCBRK or 0x5428
-class Serial(SerialBase):
+class PosixSerial(SerialBase):
"""Serial port class POSIX implementation. Serial port configuration is
done with termios and fcntl. Runs on Linux and many other Un*x like
systems."""
@@ -273,9 +273,9 @@ class Serial(SerialBase):
def open(self):
"""Open port with current settings. This may throw a SerialException
if the port cannot be opened."""
+ self.fd = None
if self._port is None:
raise SerialException("Port must be configured before it can be used.")
- self.fd = None
# open
try:
self.fd = os.open(self.portstr, os.O_RDWR|os.O_NOCTTY|os.O_NONBLOCK)
@@ -434,7 +434,7 @@ class Serial(SerialBase):
s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str)
return struct.unpack('I',s)[0]
- def read(self, size=1):
+ def _read(self, size=1):
"""Read size bytes from the serial port. If a timeout is set it may
return less characters as requested. With no timeout it will block
until the requested number of bytes is read."""
@@ -453,9 +453,10 @@ class Serial(SerialBase):
break # early abort on timeout
return read
- def write(self, data):
+ def _write(self, data):
"""Output the given string over the serial port."""
if self.fd is None: raise portNotOpenError
+ #~ if not isinstance(port, basestring):
if not isinstance(data, str):
raise TypeError('expected str, got %s' % type(data))
t = len(data)
@@ -476,6 +477,7 @@ class Serial(SerialBase):
except OSError,v:
if v.errno != errno.EAGAIN:
raise
+ return len(data)
def flush(self):
"""Flush of file like objects. In this case, wait until all data
@@ -568,6 +570,19 @@ class Serial(SerialBase):
if self.fd is None: raise portNotOpenError
return self.fd
+
+# assemble Serial class with the platform specifc implementation and the base
+# for file-like behavior
+class Serial(PosixSerial, FileLike):
+ pass
+
+# for Python 2.6 and newer, that provide the new I/O library, implement a
+# RawSerial object that plays nice with it.
+if support_io_module:
+ class RawSerial(PosixSerial, RawSerialBase):
+ pass
+
+
if __name__ == '__main__':
s = Serial(0,
baudrate=19200, # baud rate
diff --git a/serial/serialutil.py b/serial/serialutil.py
index 71bafbf..da9a936 100644
--- a/serial/serialutil.py
+++ b/serial/serialutil.py
@@ -24,13 +24,14 @@ XOFF = chr(19)
class SerialException(Exception):
"""Base class for serial port related exceptions."""
-portNotOpenError = SerialException('Port not open')
+portNotOpenError = ValueError('Attempting to use a port that is not open')
class SerialTimeoutException(SerialException):
"""Write timeouts give an exception"""
writeTimeoutError = SerialTimeoutException("Write timeout")
+
class FileLike(object):
"""An abstract file like class.
@@ -45,8 +46,31 @@ class FileLike(object):
refuses to work (it raises an exception in this case)!
"""
- def read(self, size): raise NotImplementedError
- def write(self, s): raise NotImplementedError
+ def __init__(self):
+ self.closed = True
+
+ def close(self):
+ self.closed = True
+
+ # so that ports are closed when objects are discarded
+ def __del__(self):
+ """Destructor. Calls close()."""
+ # The try/except block is in case this is called at program
+ # exit time, when it's possible that globals have already been
+ # deleted, and then the close() call might fail. Since
+ # there's nothing we can do about such failures and they annoy
+ # the end users, we suppress the traceback.
+ try:
+ self.close()
+ except:
+ pass
+
+ # read and write directly use the platform dependent implementation
+ def read(self, size=1):
+ return self._read(size)
+
+ def write(self, data):
+ return self._write(data)
def readline(self, size=None, eol='\n'):
"""read a line which is terminated with end-of-line (eol) character
@@ -101,15 +125,32 @@ class FileLike(object):
def __iter__(self):
return self
+ # other functions of file-likes - not used by pySerial
+
+ #~ readinto(b)
+
+ def seek(self, pos, whence=0):
+ raise IOError("file is not seekable")
-class SerialBase(FileLike):
+ def tell(self):
+ raise IOError("file is not seekable")
+
+ def truncate(self, n=None):
+ raise IOError("file is not seekable")
+
+ def isatty(self):
+ return False
+
+
+class SerialBase(object):
"""Serial port base class. Provides __init__ function and properties to
get/set port settings."""
# default values, may be overridden in subclasses that do not support all values
- BAUDRATES = (50,75,110,134,150,200,300,600,1200,1800,2400,4800,9600,
- 19200,38400,57600,115200,230400,460800,500000,576000,921600,
- 1000000,1152000,1500000,2000000,2500000,3000000,3500000,4000000)
+ BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
+ 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
+ 3000000, 3500000, 4000000)
BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
@@ -194,13 +235,14 @@ class SerialBase(FileLike):
was_open = self._isOpen
if was_open: self.close()
if port is not None:
- if type(port) in [type(''), type(u'')]: # strings are taken directly
+ if isinstance(port, basestring):
self.portstr = port
else:
self.portstr = self.makeDeviceName(port)
else:
self.portstr = None
self._port = port
+ self.name = self.portstr
if was_open: self.open()
def getPort(self):
@@ -384,11 +426,48 @@ class SerialBase(FileLike):
self.dsrdtr,
)
+# for Python 2.6 and newer, that provide the new I/O library, implement a
+# RawSerial object that plays nice with it.
+try:
+ import io
+except ImportError:
+ support_io_module = False
+else:
+ support_io_module = True
+
+ class RawSerialBase(io.RawIOBase):
+ def readable(self): return True
+ def writable(self): return True
+ def readinto(self, b):
+ data = self._read(len(b))
+ n = len(data)
+ try:
+ b[:n] = data
+ except TypeError, err:
+ import array
+ if not isinstance(b, array.array):
+ raise err
+ b[:n] = array.array(b'b', data)
+ return n
+
+ def write(self, b):
+ if self.closed:
+ raise ValueError("write to closed file")
+ if isinstance(b, unicode):
+ raise TypeError("can't write unicode to binary stream")
+ n = len(b)
+ if n == 0:
+ return 0
+ self._write(b)
+
+
+
if __name__ == '__main__':
+ import sys
s = SerialBase()
- sys.stdio.write('port name: %s\n' % s.portstr)
- sys.stdio.write('baud rates: %s\n' % s.getSupportedBaudrates())
- sys.stdio.write('byte sizes: %s\n' % s.getSupportedByteSizes())
- sys.stdio.write('parities: %s\n' % s.getSupportedParities())
- sys.stdio.write('stop bits: %s\n' % s.getSupportedStopbits())
- sys.stdio.write('%s\n' % s)
+ sys.stdout.write('port name: %s\n' % s.portstr)
+ sys.stdout.write('baud rates: %s\n' % s.getSupportedBaudrates())
+ sys.stdout.write('byte sizes: %s\n' % s.getSupportedByteSizes())
+ sys.stdout.write('parities: %s\n' % s.getSupportedParities())
+ sys.stdout.write('stop bits: %s\n' % s.getSupportedStopbits())
+ sys.stdout.write('%s\n' % s)
diff --git a/serial/serialwin32.py b/serial/serialwin32.py
index 8c881b5..7df6236 100644
--- a/serial/serialwin32.py
+++ b/serial/serialwin32.py
@@ -17,7 +17,7 @@ def device(portnum):
"""Turn a port number into a device name"""
return 'COM%d' % (portnum+1) #numbers are transformed to a string
-class Serial(SerialBase):
+class Win32Serial(SerialBase):
"""Serial port implementation for Win32 based on ctypes."""
BAUDRATES = (50,75,110,134,150,200,300,600,1200,1800,2400,4800,9600,
@@ -196,7 +196,7 @@ class Serial(SerialBase):
raise SerialException('call to ClearCommError failed')
return comstat.cbInQue
- def read(self, size=1):
+ def _read(self, size=1):
"""Read size bytes from the serial port. If a timeout is set it may
return less characters as requested. With no timeout it will block
until the requested number of bytes is read."""
@@ -231,7 +231,7 @@ class Serial(SerialBase):
read = ''
return read
- def write(self, data):
+ def _write(self, data):
"""Output the given string over the serial port."""
if not self.hComPort: raise portNotOpenError
if not isinstance(data, str):
@@ -247,6 +247,7 @@ class Serial(SerialBase):
err = win32.GetOverlappedResult(self.hComPort, self._overlappedWrite, ctypes.byref(n), True)
if n.value != len(data):
raise writeTimeoutError
+ return n.value
def flushInput(self):
@@ -339,6 +340,18 @@ class Serial(SerialBase):
raise SerialException('call to ClearCommError failed')
return comstat.cbOutQue
+# assemble Serial class with the platform specifc implementation and the base
+# for file-like behavior
+class Serial(Win32Serial, FileLike):
+ pass
+
+# for Python 2.6 and newer, that provide the new I/O library, implement a
+# RawSerial object that plays nice with it.
+if support_io_module:
+ class RawSerial(Win32Serial, RawSerialBase):
+ pass
+
+
# Nur Testfunktion!!
if __name__ == '__main__':
diff --git a/setup.py b/setup.py
index f9c41ef..4198f32 100644
--- a/setup.py
+++ b/setup.py
@@ -14,9 +14,9 @@ except ImportError:
raise ImportError("build_py_2to3 not found in distutils - it is required for Python 3.x")
from distutils.command.build_py import build_py
-if sys.version < '2.2.3':
- # distutils that old can't cope with the "classifiers" or
- # "download_url" keywords and True/False constants are missing
+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.2.3 are no longer"
"supported - check http://pyserial.sf.net for older "
"releases or upgrade your Python installation.")