summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcliechti <cliechti@f19166aa-fa4f-0410-85c2-fa1106f25c8a>2004-04-20 01:55:43 +0000
committercliechti <cliechti@f19166aa-fa4f-0410-85c2-fa1106f25c8a>2004-04-20 01:55:43 +0000
commit626116161311f6ade383f4f603c8250e12cc8321 (patch)
tree5bd1d3e86abc7aed0e87f20237db31cdaeccc9cc
parent6ac115b52dfbc2bc71538445b9d1c11fad7251c4 (diff)
downloadpyserial-git-626116161311f6ade383f4f603c8250e12cc8321.tar.gz
- implement write timeouts + tests
- added XON/XOFF constants
-rw-r--r--pyserial/CHANGES.txt8
-rw-r--r--pyserial/examples/test.py26
-rw-r--r--pyserial/examples/test_advanced.py3
-rw-r--r--pyserial/serial/.cvsignore1
-rw-r--r--pyserial/serial/serialposix.py19
-rw-r--r--pyserial/serial/serialutil.py34
-rw-r--r--pyserial/serial/serialwin32.py16
7 files changed, 91 insertions, 16 deletions
diff --git a/pyserial/CHANGES.txt b/pyserial/CHANGES.txt
index 3b8c4b1..fa8c257 100644
--- a/pyserial/CHANGES.txt
+++ b/pyserial/CHANGES.txt
@@ -28,8 +28,8 @@ Version 1.13 09 Apr 2002
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)
+ Added examples to archive
+ Added non-blocking mode for timeout=0 (tnx Mat Martineau)
Bugfixes:
- win32 does now return the remaining characters on timeout
@@ -137,4 +137,6 @@ Version 2.0 6 Nov 2003
Version 2.1 XXXXXXXXXXX
Bugfixes (posix):
- - fd == 0 fix from Vsevolod Lobko
+ - fd == 0 fix from Vsevolod Lobko
+ New Features:
+ - implement write timeouts ('writeTimeout' parameter)
diff --git a/pyserial/examples/test.py b/pyserial/examples/test.py
index 9713145..96bd3ee 100644
--- a/pyserial/examples/test.py
+++ b/pyserial/examples/test.py
@@ -95,7 +95,7 @@ class Test1_Forever(unittest.TestCase):
character is sent after some time to stop the test, this is done
through the SendEvent class and the Loopback HW."""
def setUp(self):
- self.s = serial.Serial(PORT,timeout=None)
+ self.s = serial.Serial(PORT, timeout=None)
self.event = SendEvent(self.s)
def tearDown(self):
self.event.stop()
@@ -105,7 +105,7 @@ class Test1_Forever(unittest.TestCase):
"""no timeout: after port open, the input buffer must be empty (read).
a character is sent after some time to terminate the test (SendEvent)."""
c = self.s.read(1)
- if not (self.event.isSet() and c =='E'):
+ if not (self.event.isSet() and c == 'E'):
self.fail("expected marker")
class Test2_Forever(unittest.TestCase):
@@ -155,6 +155,28 @@ class Test0_DataWires(unittest.TestCase):
"""Test RI"""
self.failUnless(self.s.getRI()==0, "RI -> 0")
+class Test_MoreTimeouts(unittest.TestCase):
+ """Test with timeouts"""
+ def setUp(self):
+ self.s = serial.Serial() #create an closed serial port
+
+ def tearDown(self):
+ self.s.close()
+
+ def test_WriteTimeout(self):
+ """Test write() timeout."""
+ #use xonxoff setting and the loopback adapter to switch traffic on hold
+ self.s.port = PORT
+ self.s.writeTimeout = 1
+ self.s.xonxoff = 1
+ self.s.open()
+ self.s.write(serial.XOFF)
+ time.sleep(0.1) #some systems need a little delay so that they can react on XOFF
+ t1 = time.time()
+ self.failUnlessRaises(serial.SerialTimeoutException, self.s.write, "timeout please"*100)
+ t2 = time.time()
+ self.failUnless( 1 <= (t2-t1) < 2, "Timeout not in the given intervall (%s)" % (t2-t1))
+
if __name__ == '__main__':
import sys
print __doc__
diff --git a/pyserial/examples/test_advanced.py b/pyserial/examples/test_advanced.py
index 8d65b16..a966c2f 100644
--- a/pyserial/examples/test_advanced.py
+++ b/pyserial/examples/test_advanced.py
@@ -67,7 +67,7 @@ class Test_ChangeAttributes(unittest.TestCase):
#test internals
self.failUnlessEqual(self.s._baudrate, baudrate)
#test illegal values
- for illegal_value in (-300, -1, 0, 'a', None):
+ for illegal_value in (-300, -1, 'a', None):
self.failUnlessRaises(ValueError, self.s.setBaudrate, illegal_value)
def test_BaudrateSetting2(self):
@@ -155,7 +155,6 @@ class Test_ChangeAttributes(unittest.TestCase):
self.s.close()
self.failUnless(not self.s.isOpen())
-
if __name__ == '__main__':
import sys
print __doc__
diff --git a/pyserial/serial/.cvsignore b/pyserial/serial/.cvsignore
new file mode 100644
index 0000000..7e99e36
--- /dev/null
+++ b/pyserial/serial/.cvsignore
@@ -0,0 +1 @@
+*.pyc \ No newline at end of file
diff --git a/pyserial/serial/serialposix.py b/pyserial/serial/serialposix.py
index 30e1eab..a03622e 100644
--- a/pyserial/serial/serialposix.py
+++ b/pyserial/serial/serialposix.py
@@ -13,7 +13,7 @@
import sys, os, fcntl, termios, struct, select
from serialutil import *
-VERSION = "$Revision: 1.20 $".split()[1] #extract CVS version
+VERSION = "$Revision: 1.21 $".split()[1] #extract CVS version
#Do check the Python version as some constants have moved.
if (sys.hexversion < 0x020100f0):
@@ -144,10 +144,11 @@ class Serial(SerialBase):
except Exception, msg:
self.fd = None
raise SerialException("Could not open port: %s" % msg)
- fcntl.fcntl(self.fd, FCNTL.F_SETFL, 0) #set blocking
+ #~ fcntl.fcntl(self.fd, FCNTL.F_SETFL, 0) #set blocking
self._reconfigurePort()
self._isOpen = True
+ #~ self.flushInput()
def _reconfigurePort(self):
@@ -208,7 +209,7 @@ class Serial(SerialBase):
#xonxoff
if hasattr(TERMIOS, 'IXANY'):
if self._xonxoff:
- iflag |= (TERMIOS.IXON|TERMIOS.IXOFF|TERMIOS.IXANY)
+ iflag |= (TERMIOS.IXON|TERMIOS.IXOFF) #|TERMIOS.IXANY)
else:
iflag &= ~(TERMIOS.IXON|TERMIOS.IXOFF|TERMIOS.IXANY)
else:
@@ -270,12 +271,12 @@ class Serial(SerialBase):
if size > 0:
while len(read) < size:
#print "\tread(): size",size, "have", len(read) #debug
- ready,_,_ = select.select([self.fd],[],[], self.timeout)
+ ready,_,_ = select.select([self.fd],[],[], self._timeout)
if not ready:
break #timeout
buf = os.read(self.fd, size-len(read))
read = read + buf
- if self.timeout >= 0 and not buf:
+ if self._timeout >= 0 and not buf:
break #early abort on timeout
return read
@@ -285,7 +286,15 @@ class Serial(SerialBase):
t = len(data)
d = data
while t > 0:
+ if self._writeTimeout is not None and self._writeTimeout > 0:
+ _,ready,_ = select.select([],[self.fd],[], self._writeTimeout)
+ if not ready:
+ raise writeTimeoutError
n = os.write(self.fd, d)
+ if self._writeTimeout is not None and self._writeTimeout > 0:
+ _,ready,_ = select.select([],[self.fd],[], self._writeTimeout)
+ if not ready:
+ raise writeTimeoutError
d = d[n:]
t = t - n
diff --git a/pyserial/serial/serialutil.py b/pyserial/serial/serialutil.py
index c503568..0d4883b 100644
--- a/pyserial/serial/serialutil.py
+++ b/pyserial/serial/serialutil.py
@@ -15,6 +15,9 @@ PARITY_NAMES = {
PARITY_ODD: 'Odd',
}
+XON = chr(16)
+XOFF = chr(18)
+
#Python < 2.2.3 compatibility
try:
True
@@ -27,6 +30,11 @@ class SerialException(Exception):
portNotOpenError = SerialException('Port not open')
+class SerialTimeoutException(SerialException):
+ """Write timeouts give an exception"""
+
+writeTimeoutError = SerialTimeoutException("Write timeout")
+
class FileLike(object):
"""An abstract file like class.
@@ -113,6 +121,7 @@ class SerialBase(FileLike):
timeout=None, #set a timeout value, None to wait forever
xonxoff=0, #enable software flow control
rtscts=0, #enable RTS/CTS flow control
+ writeTimeout=None, #set a timeout for writes
):
"""Initialize comm port object. If a port is given, then the port will be
opened immediately. Otherwise a Serial port object in closed state
@@ -125,16 +134,18 @@ class SerialBase(FileLike):
self._parity = None #correct value is assigned below trough properties
self._stopbits = None #correct value is assigned below trough properties
self._timeout = None #correct value is assigned below trough properties
+ self._writeTimeout = None #correct value is assigned below trough properties
self._xonxoff = None #correct value is assigned below trough properties
self._rtscts = None #correct value is assigned below trough properties
- #assign values using get/set methods using the properties featrure
+ #assign values using get/set methods using the properties feature
self.port = port
self.baudrate = baudrate
self.bytesize = bytesize
self.parity = parity
self.stopbits = stopbits
self.timeout = timeout
+ self.writeTimeout = writeTimeout
self.xonxoff = xonxoff
self.rtscts = rtscts
@@ -263,7 +274,26 @@ class SerialBase(FileLike):
"""Get the current timeout setting."""
return self._timeout
- timeout = property(getTimeout, setTimeout, "Timeout setting")
+ timeout = property(getTimeout, setTimeout, "Timeout setting for read()")
+
+
+ def setWriteTimeout(self, timeout):
+ """Change timeout setting."""
+ if timeout is not None:
+ if timeout < 0: raise ValueError("Not a valid timeout: %r" % timeout)
+ try:
+ timeout + 1 #test if it's a number, will throw a TypeError if not...
+ except TypeError:
+ raise ValueError("Not a valid timeout: %r" % timeout)
+
+ self._writeTimeout = timeout
+ if self._isOpen: self._reconfigurePort()
+
+ def getWriteTimeout(self):
+ """Get the current timeout setting."""
+ return self._writeTimeout
+
+ writeTimeout = property(getWriteTimeout, setWriteTimeout, "Timeout setting for write()")
def setXonXoff(self, xonxoff):
diff --git a/pyserial/serial/serialwin32.py b/pyserial/serial/serialwin32.py
index fa04029..5a22efd 100644
--- a/pyserial/serial/serialwin32.py
+++ b/pyserial/serial/serialwin32.py
@@ -11,7 +11,7 @@ import win32event # We use events and the WaitFor[Single|Multiple]Objects functi
import win32con # constants.
from serialutil import *
-VERSION = "$Revision: 1.28 $".split()[1] #extract CVS version
+VERSION = "$Revision: 1.29 $".split()[1] #extract CVS version
#from winbase.h. these should realy be in win32con
MS_CTS_ON = 16
@@ -90,6 +90,12 @@ class Serial(SerialBase):
timeouts = (win32con.MAXDWORD, 0, 0, 0, 0)
else:
timeouts = (0, 0, int(self._timeout*1000), 0, 0)
+ if self._writeTimeout is None:
+ pass
+ elif self._writeTimeout == 0:
+ timeouts = timeouts[:-2] + (0, win32con.MAXDWORD)
+ else:
+ timeouts = timeouts[:-2] + (0, int(self._writeTimeout*1000))
win32file.SetCommTimeouts(self.hComPort, timeouts)
win32file.SetCommMask(self.hComPort, win32file.EV_ERR)
@@ -144,6 +150,8 @@ class Serial(SerialBase):
comDCB.fNull = 0
comDCB.fErrorChar = 0
comDCB.fAbortOnError = 0
+ comDCB.XonChar = XON
+ comDCB.XoffChar = XOFF
try:
win32file.SetCommState(self.hComPort, comDCB)
@@ -207,7 +215,11 @@ class Serial(SerialBase):
err, n = win32file.WriteFile(self.hComPort, s, self._overlappedWrite)
if err: #will be ERROR_IO_PENDING:
# Wait for the write to complete.
- win32event.WaitForSingleObject(self._overlappedWrite.hEvent, win32event.INFINITE)
+ #~ win32event.WaitForSingleObject(self._overlappedWrite.hEvent, win32event.INFINITE)
+ n = win32file.GetOverlappedResult(self.hComPort, self._overlappedWrite, 1)
+ if n != len(s):
+ raise writeTimeoutError
+
def flushInput(self):
"""Clear input buffer, discarding all that is in the buffer."""