From 5b6169d84afc45c1f979e4fb27df86fc1eb1d994 Mon Sep 17 00:00:00 2001 From: cliechti Date: Tue, 12 Feb 2002 23:24:41 +0000 Subject: initial split from pybsl, jython support git-svn-id: http://svn.code.sf.net/p/pyserial/code/branches/avendor@3 f19166aa-fa4f-0410-85c2-fa1106f25c8a --- pyserial/LICENSE.txt | 61 +++++++ pyserial/MANIFEST | 7 + pyserial/README.txt | 103 ++++++++++++ pyserial/serial/__init__.py | 21 +++ pyserial/serial/serialjava.py | 187 +++++++++++++++++++++ pyserial/serial/serialposix.py | 363 +++++++++++++++++++++++++++++++++++++++++ pyserial/serial/serialwin32.py | 304 ++++++++++++++++++++++++++++++++++ pyserial/setup.py | 13 ++ 8 files changed, 1059 insertions(+) create mode 100644 pyserial/LICENSE.txt create mode 100644 pyserial/MANIFEST create mode 100644 pyserial/README.txt create mode 100644 pyserial/serial/__init__.py create mode 100644 pyserial/serial/serialjava.py create mode 100644 pyserial/serial/serialposix.py create mode 100644 pyserial/serial/serialwin32.py create mode 100644 pyserial/setup.py diff --git a/pyserial/LICENSE.txt b/pyserial/LICENSE.txt new file mode 100644 index 0000000..72f0b89 --- /dev/null +++ b/pyserial/LICENSE.txt @@ -0,0 +1,61 @@ +Copyright (c) 2001 Chris Liechti ; +All Rights Reserved. + +This is the Python license. In short, you can use this product in +commercial and non-commercial applications, modify it, redistribute it. +A notification to the author when you use and/or modify it is welcome. + + +TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING THIS SOFTWARE +=================================================================== + +LICENSE AGREEMENT +----------------- + +1. This LICENSE AGREEMENT is between the copyright holder of this +product, and the Individual or Organization ("Licensee") accessing +and otherwise using this product in source or binary form and its +associated documentation. + +2. Subject to the terms and conditions of this License Agreement, +the copyright holder hereby grants Licensee a nonexclusive, +royalty-free, world-wide license to reproduce, analyze, test, +perform and/or display publicly, prepare derivative works, distribute, +and otherwise use this product alone or in any derivative version, +provided, however, that copyright holders License Agreement and +copyright holders notice of copyright are retained in this product +alone or in any derivative version prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates this product or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to this product. + +4. The copyright holder is making this product available to Licensee on +an "AS IS" basis. THE COPYRIGHT HOLDER MAKES NO REPRESENTATIONS OR +WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, +THE COPYRIGHT HOLDER MAKES NO AND DISCLAIMS ANY REPRESENTATION OR +WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR +THAT THE USE OF THIS PRODUCT WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. THE COPYRIGHT HOLDER SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER +USERS OF THIS PRODUCT FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL +DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE +USING THIS PRODUCT, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE +POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between the +copyright holder and Licensee. This License Agreement does not grant +permission to use trademarks or trade names from the copyright holder +in a trademark sense to endorse or promote products or services of +Licensee, or any third party. + +8. By copying, installing or otherwise using this product, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + diff --git a/pyserial/MANIFEST b/pyserial/MANIFEST new file mode 100644 index 0000000..6b348f5 --- /dev/null +++ b/pyserial/MANIFEST @@ -0,0 +1,7 @@ +README.txt +LICENSE.txt +setup.py +serial\__init__.py +serial\serialjava.py +serial\serialposix.py +serial\serialwin32.py diff --git a/pyserial/README.txt b/pyserial/README.txt new file mode 100644 index 0000000..213b7c5 --- /dev/null +++ b/pyserial/README.txt @@ -0,0 +1,103 @@ +pySerial +-------- +This module capsulates the access for the serial port. It provides backends +for stadard Python running on Windows, Linux, BSD (possibly any POSIX +compilant system) and Jython. The module named "serial" automaticaly selects +the appropriate backed. + +It is released under a free software license, see LICENSE.txt for more +details. + +(C) 2001-2002 Chris Liechti + + +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 can be specified if access through numbering is inappropriate +- support for diffrent bytesizes, stopbits, parity and flow control + with RTS/CTS and/or xon/xoff +- working with or without receive timeout +- file like API with "read" and "write" +- The files in this package are 100% pure Python. + They depend on non standard but common packages on Windows (win32all) and + Jython (JavaComm). POSIX (Linux, BSD) uses only modules from the standard + python distribution) +- 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. + + +Requirements +------------ +- Python 2.0 or newer (1.5.2 untested) +- win32all extensions on Windows +- "Java Communications" (JavaComm) extension for Java/Jython + + +Installation +------------ +Extract files from the archive, open a shell/console in that directory and +let Disutils do the rest: "python setup.py install" + +The files get installed in the "Lib/site-packages" directory in newer +Python versions. + + +Short introduction +------------------ +import serial +#open port 0 at 9600,8,N,1, no timeout +ser = serial.Serial(0) +ser.write("hello") #write a string +ser.close() + +#open 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) +ser.close() + +Parameters for the Serial class +------------------------------- +ser = serial.Serial( + port, #number of device, numbering starts at + #zero. if everything fails, the user + #can specify a device string, note + #that this isn't portable anymore + baudrate=9600, #baudrate + bytesize=EIGHTBITS, #number of databits + parity=PARITY_NONE, #enable parity checking + stopbits=STOPBITS_ONE, #number of stopbits + timeout=None, #set a timeout value, None for waiting forever + xonxoff=0, #enable software flow control + rtscts=0, #enable RTS/CTS flow control +) + +Constants +--------- +parity: + serial.PARITY_NONE + serial.PARITY_EVEN + serial.PARITY_ODD +stopbits: + serial.STOPBITS_ONE + serial.STOPBITS_TWO +bytesize: + serial.FIVEBITS + serial.SIXBITS + serial.SEVENBITS + serial.EIGHTBITS + + +References +---------- +- Python: http://www.python.org +- Jython: http://www.jython.org +- win32all: http://starship.python.net/crew/mhammond/ + and http://www.activestate.com/Products/ActivePython/win32all.html +- Java@IBM http://www-106.ibm.com/developerworks/java/jdk/ + (JavaComm links are on the download page for the respecive platform jdk) +- Java@SUN http://java.sun.com/products/ diff --git a/pyserial/serial/__init__.py b/pyserial/serial/__init__.py new file mode 100644 index 0000000..b5d9c91 --- /dev/null +++ b/pyserial/serial/__init__.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +#portable serial port access with python +#this is a wrapper module for different platform implementations +# +# (C)2001 Chris Liechti +# this is distributed under a free software license, see license.txt + +import sys, os, string +VERSION = string.split("$Revision: 1.1.1.1 $")[1] #extract CVS version + +#chose an implementation, depending on os +if os.name == 'nt': #sys.platform == 'win32': + from serialwin32 import * +elif os.name == 'posix': + from serialposix import * +elif os.name == 'java': + from serialjava import * +else: + raise "Sorry no implementation for your platform available." + +#no "mac" implementation. someone want's to write it? i have no access to a mac. diff --git a/pyserial/serial/serialjava.py b/pyserial/serial/serialjava.py new file mode 100644 index 0000000..f7601ec --- /dev/null +++ b/pyserial/serial/serialjava.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python +#module for serial IO for Jython and JavaComm +#see serial.py +# +#(C) 2002 Chris Liechti +# this is distributed under a free software license, see license.txt + +import sys, os, string, javax.comm + +VERSION = string.split("$Revision: 1.1.1.1 $")[1] #extract CVS version + +PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = (0,1,2,3,4) +STOPBITS_ONE, STOPBITS_TWO, STOPBITS_ONE_HALVE = (1, 2, 3) +FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5,6,7,8) + + +portNotOpenError = ValueError('port not open') + +def device(portnumber): + enum = javax.comm.CommPortIdentifier.getPortIdentifiers() + ports = [] + while enum.hasMoreElements(): + el = enum.nextElement() + if el.getPortType() == javax.comm.CommPortIdentifier.PORT_SERIAL: + ports.append(el) + return ports[portnumber] + +class Serial: + def __init__(self, + port, #number of device, numbering starts at + #zero. if everything fails, the user + #can specify a device string, note + #that this isn't portable anymore + baudrate=9600, #baudrate + bytesize=EIGHTBITS, #number of databits + parity=PARITY_NONE, #enable parity checking + stopbits=STOPBITS_ONE, #number of stopbits + timeout=None, #set a timeout value, None for waiting forever + xonxoff=0, #enable software flow control + rtscts=0, #enable RTS/CTS flow control + ): + + if type(port) == type(''): #strings are taken directly + portId = javax.comm.CommPortIdentifier.getPortIdentifier(port) + else: + portId = device(port) #numbers are transformed to a comportid obj + self.portstr = portId.getName() + + self.sPort = portId.open("python serial module", 10) + self.instream = self.sPort.getInputStream() + self.outstream = self.sPort.getOutputStream() + self.sPort.enableReceiveTimeout(30) + if bytesize == FIVEBITS: + databits = javax.comm.SerialPort.DATABITS_5 + elif bytesize == SIXBITS: + databits = javax.comm.SerialPort.DATABITS_6 + elif bytesize == SEVENBITS: + databits = javax.comm.SerialPort.DATABITS_7 + elif bytesize == EIGHTBITS: + databits = javax.comm.SerialPort.DATABITS_8 + else: + raise ValueError, "unsupported bytesize" + + if stopbits == STOPBITS_ONE: + jstopbits = javax.comm.SerialPort.STOPBITS_1 + elif stopbits == STOPBITS_ONE_HALVE: + jstopbits = javax.comm.SerialPort.STOPBITS_1_5 + elif stopbits == STOPBITS_TWO: + jstopbits = javax.comm.SerialPort.STOPBITS_2 + else: + raise ValueError, "unsupported number of stopbits" + + if parity == PARITY_NONE: + jparity = javax.comm.SerialPort.PARITY_NONE + elif parity == PARITY_EVEN: + jparity = javax.comm.SerialPort.PARITY_EVEN + elif parity == PARITY_ODD: + jparity = javax.comm.SerialPort.PARITY_ODD + elif parity == PARITY_MARK: + jparity = javax.comm.SerialPort.PARITY_MARK + elif parity == PARITY_SPACE: + jparity = javax.comm.SerialPort.PARITY_SPACE + else: + raise ValueError, "unsupported parity type" + + jflowin = jflowout = 0 + if rtscts: + jflowin = jflowin | javax.comm.SerialPort.FLOWCONTROL_RTSCTS_IN + jflowout = jflowout | javax.comm.SerialPort.FLOWCONTROL_RTSCTS_OUT + if xonxoff: + jflowin = jflowin | javax.comm.SerialPort.FLOWCONTROL_XONXOFF_IN + jflowout = jflowout | javax.comm.SerialPort.FLOWCONTROL_XONXOFF_OUT + + self.sPort.setSerialPortParams(baudrate, databits, jstopbits, jparity) + self.sPort.setFlowControlMode(jflowin | jflowout) + + self.timeout = timeout + if timeout: + self.sPort.enableReceiveTimeout(timeout*1000) + else: + self.sPort.disableReceiveTimeout() + + + def close(self): + if self.sPort: + self.instream.close() + self.outstream.close() + self.sPort.close() + self.sPort = None + + def inWaiting(self): + if not self.sPort: raise portNotOpenError + return self.instream.available() + + def write(self, data): + if not self.sPort: raise portNotOpenError + self.outstream.write(data) + + def read(self, size=1): + if not self.sPort: raise portNotOpenError + res = '' + while len(res) < size: + x = self.instream.read() + if x == -1: + if self.timeout: + break + else: + res = res + chr(x) + return res + + def flushInput(self): + if not self.sPort: raise portNotOpenError + self.instream.skip(self.instream.available()) + + def flushOutput(self): + if not self.sPort: raise portNotOpenError + self.outstream.flush() + + def sendBreak(self): + if not self.sPort: raise portNotOpenError + self.sPort.sendBreak() + + def getDSR(self): + if not self.sPort: raise portNotOpenError + self.sPort.isDSR() + + def getCD(self): + if not self.sPort: raise portNotOpenError + self.sPort.isCD() + + def getRI(self): + if not self.sPort: raise portNotOpenError + self.sPort.isRI() + + def getCTS(self): + if not self.sPort: raise portNotOpenError + self.sPort.isCTS() + + def setDTR(self,on=1): + if not self.sPort: raise portNotOpenError + self.sPort.setDTR(on) + + def setRTS(self,on=1): + if not self.sPort: raise portNotOpenError + self.sPort.setRTS(on) + +if __name__ == '__main__': + s = Serial(0, + baudrate=19200, #baudrate + bytesize=EIGHTBITS, #number of databits + parity=PARITY_EVEN, #enable parity checking + stopbits=STOPBITS_ONE, #number of stopbits + timeout=3, #set a timeout value, None for waiting forever + xonxoff=0, #enable software flow control + rtscts=0, #enable RTS/CTS flow control + ) + s.setRTS(1) + s.setDTR(1) + s.flushInput() + s.flushOutput() + s.write('hello') + print repr(s.read(5)) + print s.inWaiting() + del s + + + diff --git a/pyserial/serial/serialposix.py b/pyserial/serial/serialposix.py new file mode 100644 index 0000000..8d58542 --- /dev/null +++ b/pyserial/serial/serialposix.py @@ -0,0 +1,363 @@ +#!/usr/bin/env python +#module for serial IO for POSIX compatible systems, like Linux +#see serial.py +# +#(C) 2001 Chris Liechti +# this is distributed under a free software license, see license.txt +# +#parts based on code from Grant B. Edwards : +# ftp://ftp.visi.com/users/grante/python/PosixSerial.py +# references: http://www.easysw.com/~mike/serial/serial.html + +import sys, os, fcntl, termios, struct, string, select + +VERSION = string.split("$Revision: 1.1.1.1 $")[1] #extract CVS version + +PARITY_NONE, PARITY_EVEN, PARITY_ODD = range(3) +STOPBITS_ONE, STOPBITS_TWO = (1, 2) +FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5,6,7,8) + +if (sys.hexversion < 0x020100f0): + import TERMIOS +else: + TERMIOS = termios + +if (sys.hexversion < 0x020200f0): + import FCNTL +else: + FCNTL = fcntl + +#try to detect the os so that a device can be selected... +plat = string.lower(sys.platform) + +if plat[:5] == 'linux': #Linux (confirmed) + def device(port): + return '/dev/ttyS%d' % port + +elif plat == 'openbsd3': #BSD (confirmed) + def device(port): + return '/dev/ttyp%d' % port + +elif plat[:3] == 'bsd' or \ + plat[:6] == 'netbsd' or \ + plat[:7] == 'freebsd' or \ + plat[:7] == 'openbsd' or \ + plat[:6] == 'darwin': #BSD (confirmed for freebsd4: cuaa%d) + def device(port): + return '/dev/cuaa%d' % port + +elif plat[:4] == 'irix': #IRIX® (not tested) + def device(port): + return '/dev/ttyf%d' % port + +elif plat[:2] == 'hp': #HP-UX (not tested) + def device(port): + return '/dev/tty%dp0' % (port+1) + +elif plat[:5] == 'sunos': #Solaris®/SunOS® (not tested) + def device(port): + return '/dev/tty%c' % (ord('a')+port) + +elif plat[:3] == 'dgux': #Digital UNIX® (not tested) + def device(port): + return '/dev/tty0%d' % (port+1) + +else: + #platform detection has failed... + info = "sys.platform = %r\nos.name = %r\nserialposix.py version = %s" % (sys.platform, os.name, VERSION) + print """send this information to the author of this module: + +%s + +also add the device name of the serial port and where the +counting starts for the first serial port. +e.g. 'first serial port: /dev/ttyS0' +and with a bit luck you can get this module running... +""" + raise Exception, "this module does not run on this platform, sorry." + +#whats up with "aix", "beos", "sco", .... +#they should work, just need to know the device names. +#"cygwin" has a POSIX emulation but does not seem to have a /dev/ttyxx structure? + + +# construct dictionaries for baud rate lookups +baudEnumToInt = {} +baudIntToEnum = {} +for rate in (0,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 + ): + try: + i = eval('TERMIOS.B'+str(rate)) + baudEnumToInt[i]=rate + baudIntToEnum[rate] = i + except: + pass + +if hasattr(TERMIOS, 'TIOCMGET'): + TIOCMGET = TERMIOS.TIOCMGET + TIOCMBIS = TERMIOS.TIOCMBIS + TIOCMBIC = TERMIOS.TIOCMBIC + TIOCMSET = TERMIOS.TIOCMSET + + TIOCM_LE = TERMIOS.TIOCM_LE + TIOCM_DTR = TERMIOS.TIOCM_DTR + TIOCM_RTS = TERMIOS.TIOCM_RTS + TIOCM_ST = TERMIOS.TIOCM_ST + TIOCM_SR = TERMIOS.TIOCM_SR + TIOCM_CTS = TERMIOS.TIOCM_CTS + TIOCM_CAR = TERMIOS.TIOCM_CAR + TIOCM_RNG = TERMIOS.TIOCM_RNG + TIOCM_DSR = TERMIOS.TIOCM_DSR + TIOCM_CD = TERMIOS.TIOCM_CD + TIOCM_RI = TERMIOS.TIOCM_RI + TIOCM_OUT1 = TERMIOS.TIOCM_OUT1 + TIOCM_OUT2 = TERMIOS.TIOCM_OUT2 +else: #workaround for older python versions + TIOCMGET = 0x5415 + TIOCMBIS = 0x5416 + TIOCMBIC = 0x5417 + TIOCMSET = 0x5418 + + TIOCM_LE = 0x001 + TIOCM_DTR = 0x002 + TIOCM_RTS = 0x004 + TIOCM_ST = 0x008 + TIOCM_SR = 0x010 + TIOCM_CTS = 0x020 + TIOCM_CAR = 0x040 + TIOCM_RNG = 0x080 + TIOCM_DSR = 0x100 + TIOCM_CD = TIOCM_CAR + TIOCM_RI = TIOCM_RNG + TIOCM_OUT1 = 0x2000 + TIOCM_OUT2 = 0x4000 + +TIOCM_zero_str = struct.pack('I', 0) +TIOCM_RTS_str = struct.pack('I', TIOCM_RTS) +TIOCM_DTR_str = struct.pack('I', TIOCM_DTR) + +portNotOpenError = ValueError('port not open') + +class Serial: + def __init__(self, + port, #number of device, numbering starts at + #zero. if everything fails, the user + #can specify a device string, note + #that this isn't portable anymore + baudrate=9600, #baudrate + bytesize=EIGHTBITS, #number of databits + parity=PARITY_NONE, #enable parity checking + stopbits=STOPBITS_ONE, #number of stopbits + timeout=None, #set a timeout value, None for waiting forever + xonxoff=0, #enable software flow control + rtscts=0, #enable RTS/CTS flow control + ): + self.fd = None + self.timeout = timeout + vmin = vtime = 0 #timeout is done via select + #open + if type(port) == type(''): #strings are taken directly + self.portstr = port + else: + self.portstr = device(port) #numbers are transformed to a os dependant string + self.fd = os.open(self.portstr, os.O_RDWR|os.O_NOCTTY|os.O_NONBLOCK) + fcntl.fcntl(self.fd, FCNTL.F_SETFL, 0) #set blocking + self.__tcgetattr() #read current settings + #set up raw mode / no echo / binary + self.cflag = self.cflag | (TERMIOS.CLOCAL|TERMIOS.CREAD) + self.lflag = self.lflag & ~(TERMIOS.ICANON|TERMIOS.ECHO|TERMIOS.ECHOE|TERMIOS.ECHOK|TERMIOS.ECHONL| + TERMIOS.ECHOCTL|TERMIOS.ECHOPRT|TERMIOS.ECHOKE|TERMIOS.ISIG|TERMIOS.IEXTEN) + self.oflag = self.oflag & ~(TERMIOS.OPOST) + if hasattr(TERMIOS, 'IUCLC'): + self.iflag = self.iflag & ~(TERMIOS.INLCR|TERMIOS.IGNCR|TERMIOS.ICRNL|TERMIOS.IUCLC|TERMIOS.IGNBRK) + else: + self.iflag = self.iflag & ~(TERMIOS.INLCR|TERMIOS.IGNCR|TERMIOS.ICRNL|TERMIOS.IGNBRK) + #setup baudrate + try: + self.ispeed = self.ospeed = baudIntToEnum[baudrate] + except: + raise ValueError,'invalid baud rate: %s' % baudrate + #setup char len + self.cflag = self.cflag & ~TERMIOS.CSIZE + if bytesize == 8: + self.cflag = self.cflag | TERMIOS.CS8 + elif bytesize == 7: + self.cflag = self.cflag | TERMIOS.CS7 + elif bytesize == 6: + self.cflag = self.cflag | TERMIOS.CS6 + elif bytesize == 5: + self.cflag = self.cflag | TERMIOS.CS5 + else: + raise ValueError,'invalid char len: '+str(clen) + #setup stopbits + if stopbits == STOPBITS_ONE: + self.cflag = self.cflag & ~(TERMIOS.CSTOPB) + elif stopbits == STOPBITS_TWO: + self.cflag = self.cflag | (TERMIOS.CSTOPB) + else: + raise ValueError,'invalid stopit specification:'+str(stopbits) + #setup parity + self.iflag = self.iflag & ~(TERMIOS.INPCK|TERMIOS.ISTRIP) + if parity == PARITY_NONE: + self.cflag = self.cflag & ~(TERMIOS.PARENB|TERMIOS.PARODD) + elif parity == PARITY_EVEN: + self.cflag = self.cflag & ~(TERMIOS.PARODD) + self.cflag = self.cflag | (TERMIOS.PARENB) + elif parity == PARITY_ODD: + self.cflag = self.cflag | (TERMIOS.PARENB|TERMIOS.PARODD) + else: + raise ValueError,'invalid parity: '+str(par) + #setup flow control + #xonxoff + if hasattr(TERMIOS, 'IXANY'): + if xonxoff: + self.iflag = self.iflag | (TERMIOS.IXON|TERMIOS.IXOFF|TERMIOS.IXANY) + else: + self.iflag = self.iflag & ~(TERMIOS.IXON|TERMIOS.IXOFF|TERMIOS.IXANY) + else: + if xonxoff: + self.iflag = self.iflag | (TERMIOS.IXON|TERMIOS.IXOFF) + else: + self.iflag = self.iflag & ~(TERMIOS.IXON|TERMIOS.IXOFF) + #rtscts + if hasattr(TERMIOS, 'CRTSCTS'): + if rtscts: + self.cflag = self.cflag | (TERMIOS.CRTSCTS) + else: + self.cflag = self.cflag & ~(TERMIOS.CRTSCTS) + #buffer + #vmin "minimal number of characters to be read. = for non blocking" + if vmin<0 or vmin>255: + raise ValueError,'invalid vmin: '+str(vmin) + self.cc[TERMIOS.VMIN] = vmin + #vtime + if vtime<0 or vtime>255: + raise ValueError,'invalid vtime: '+str(vtime) + self.cc[TERMIOS.VTIME] = vtime + #activate settings + self.__tcsetattr() + + def __tcsetattr(self): + termios.tcsetattr(self.fd, TERMIOS.TCSANOW, [self.iflag,self.oflag,self.cflag,self.lflag,self.ispeed,self.ospeed,self.cc]) + + def __tcgetattr(self): + self.iflag,self.oflag,self.cflag,self.lflag,self.ispeed,self.ospeed,self.cc = termios.tcgetattr(self.fd) + + def close(self): + if self.fd: + os.close(self.fd) + self.fd = None + + def inWaiting(self): + s = fcntl.ioctl(self.fd, TERMIOS.FIONREAD, TIOCM_zero_str) + return struct.unpack('I',s)[0] + + def write(self, data): + if not self.fd: raise portNotOpenError + t = len(data) + d = data + while t>0: + n = os.write(self.fd, d) + d = d[n:] + t = t - n + + def read(self, size=1): + if not self.fd: raise portNotOpenError + read = '' + imp = None + if size > 0: + while len(read) < size: + if self.timeout: + #print "\tread(): size",size, "have", len(read) #debug + ready,_,_ = select.select([self.fd],[],[], self.timeout) + if not ready: + break #timeout + for fd in ready: + if fd is self.fd: + inp = os.read(self.fd, size-len(read)) + else: + inp = os.read(self.fd, size-len(read)) + if not inp and self.timeout: break #early abort on timeout + read = read + inp + return read + + def flushInput(self): + if not self.fd: + raise portNotOpenError + termios.tcflush(self.fd, TERMIOS.TCIFLUSH) + + def flushOutput(self): + if not self.fd: + raise portNotOpenError + termios.tcflush(self.fd, TERMIOS.TCOFLUSH) + + def sendBreak(self): + if not self.fd: + raise portNotOpenError + termios.tcsendbreak(self.fd, 0) + + def drainOutput(self): + if not self.fd: raise portNotOpenError + termios.tcdrain(self.fd) + + def nonblocking(self): + if not self.fd: + raise portNotOpenError + fcntl.fcntl(self.fd, FCNTL.F_SETFL, FCNTL.O_NONBLOCK) + + def getDSR(self): + if not self.fd: raise portNotOpenError + s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) + return struct.unpack('I',s)[0] & TIOCM_DSR + + def getCD(self): + if not self.fd: raise portNotOpenError + s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) + return struct.unpack('I',s)[0] & TIOCM_CD + + def getRI(self): + if not self.fd: raise portNotOpenError + s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) + return struct.unpack('I',s)[0] & TIOCM_RI + + def getCTS(self): + if not self.fd: raise portNotOpenError + s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) + return struct.unpack('I',s)[0] & TIOCM_CTS + + def setDTR(self,on=1): + if not self.fd: raise portNotOpenError + if on: + fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_DTR_str) + else: + fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_DTR_str) + + def setRTS(self,on=1): + if not self.fd: raise portNotOpenError + if on: + fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_RTS_str) + else: + fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_RTS_str) + +if __name__ == '__main__': + s = Serial(0, + baudrate=19200, #baudrate + bytesize=EIGHTBITS, #number of databits + parity=PARITY_EVEN, #enable parity checking + stopbits=STOPBITS_ONE, #number of stopbits + timeout=3, #set a timeout value, None for waiting forever + xonxoff=0, #enable software flow control + rtscts=0, #enable RTS/CTS flow control + ) + s.setRTS(1) + s.setDTR(1) + s.flushInput() + s.flushOutput() + s.write('hello') + print repr(s.read(5)) + print s.inWaiting() + del s + + diff --git a/pyserial/serial/serialwin32.py b/pyserial/serial/serialwin32.py new file mode 100644 index 0000000..c780069 --- /dev/null +++ b/pyserial/serial/serialwin32.py @@ -0,0 +1,304 @@ +#! python +#serial driver for win32 +#see serial.py +# +#(C) 2001 Chris Liechti +# this is distributed under a free software license, see license.txt + +import win32file # The base COM port and file IO functions. +import win32event # We use events and the WaitFor[Single|Multiple]Objects functions. +import win32con # constants. +import sys, string + +VERSION = string.split("$Revision: 1.1.1.1 $")[1] #extract CVS version + +PARITY_NONE, PARITY_EVEN, PARITY_ODD = range(3) +STOPBITS_ONE, STOPBITS_TWO = (1, 2) +FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5,6,7,8) + +portNotOpenError = ValueError('port not open') + +class Serial: + def __init__(self, + port, #number of device, numbering starts at + #zero. if everything fails, the user + #can specify a device string, note + #that this isn't portable anymore + baudrate=9600, #baudrate + bytesize=EIGHTBITS, #number of databits + parity=PARITY_NONE, #enable parity checking + stopbits=STOPBITS_ONE, #number of stopbits + timeout=None, #set a timeout value, None for waiting forever + xonxoff=0, #enable software flow control + rtscts=0, #enable RTS/CTS flow control + ): + """initialize comm port""" + + self.timeout = timeout + + if type(port) == type(''): #strings are taken directly + self.portstr = port + else: + self.portstr = 'COM%d' % (port+1) #numbers are transformed to a string + #self.portstr = '\\\\.\\COM%d' % (port+1) #WIN NT format?? + + self.hComPort = win32file.CreateFile(self.portstr, + win32con.GENERIC_READ | win32con.GENERIC_WRITE, + 0, # exclusive access + None, # no security + win32con.OPEN_EXISTING, + win32con.FILE_ATTRIBUTE_NORMAL | win32con.FILE_FLAG_OVERLAPPED, + None) + # Setup a 4k buffer + win32file.SetupComm(self.hComPort, 4096, 4096) + + #Save original timeout values: + self.orgTimeouts = win32file.GetCommTimeouts(self.hComPort) + + #Set Windows timeout values + #timeouts is a tuple with the following items: + #(ReadIntervalTimeout,ReadTotalTimeoutMultiplier, + # ReadTotalTimeoutConstant,WriteTotalTimeoutMultiplier, + # WriteTotalTimeoutConstant) + if timeout: + timeouts = (timeout*1000, 0, timeout*1000, 0, 0) + else: + #timeouts = (win32con.MAXDWORD, 1, 0, 1, 0) + timeouts = (win32con.MAXDWORD, 0, 0, 0, 1000) + win32file.SetCommTimeouts(self.hComPort, timeouts) + + #win32file.SetCommMask(self.hComPort, win32file.EV_RXCHAR | win32file.EV_TXEMPTY | + # win32file.EV_RXFLAG | win32file.EV_ERR) + win32file.SetCommMask(self.hComPort, + win32file.EV_RXCHAR | win32file.EV_RXFLAG | win32file.EV_ERR) + #win32file.SetCommMask(self.hComPort, win32file.EV_ERR) + + # Setup the connection info. + # Get state and modify it: + comDCB = win32file.GetCommState(self.hComPort) + comDCB.BaudRate = baudrate + + if bytesize == FIVEBITS: + comDCB.ByteSize = 5 + elif bytesize == SIXBITS: + comDCB.ByteSize = 6 + elif bytesize == SEVENBITS: + comDCB.ByteSize = 7 + elif bytesize == EIGHTBITS: + comDCB.ByteSize = 8 + + if parity == PARITY_NONE: + comDCB.Parity = win32file.NOPARITY + comDCB.fParity = 0 # Dis/Enable Parity Check + elif parity == PARITY_EVEN: + comDCB.Parity = win32file.EVENPARITY + comDCB.fParity = 1 # Dis/Enable Parity Check + elif parity == PARITY_ODD: + comDCB.Parity = win32file.ODDPARITY + comDCB.fParity = 1 # Dis/Enable Parity Check + + if stopbits == STOPBITS_ONE: + comDCB.StopBits = win32file.ONESTOPBIT + elif stopbits == STOPBITS_TWO: + comDCB.StopBits = win32file.TWOSTOPBITS + comDCB.fBinary = 1 # Enable Binary Transmission + # Char. w/ Parity-Err are replaced with 0xff (if fErrorChar is set to TRUE) + if rtscts: + comDCB.fRtsControl = win32file.RTS_CONTROL_HANDSHAKE + comDCB.fDtrControl = win32file.DTR_CONTROL_HANDSHAKE + else: + comDCB.fRtsControl = win32file.RTS_CONTROL_ENABLE + comDCB.fDtrControl = win32file.DTR_CONTROL_ENABLE + comDCB.fOutxCtsFlow = rtscts + comDCB.fOutxDsrFlow = rtscts + comDCB.fOutX = xonxoff + comDCB.fInX = xonxoff + comDCB.fNull = 0 + comDCB.fErrorChar = 0 + comDCB.fAbortOnError = 0 + + win32file.SetCommState(self.hComPort, comDCB) + + # Clear buffers: + # Remove anything that was there + win32file.PurgeComm(self.hComPort, + win32file.PURGE_TXCLEAR | win32file.PURGE_TXABORT | + win32file.PURGE_RXCLEAR | win32file.PURGE_RXABORT) + + #print win32file.ClearCommError(self.hComPort) #flags, comState = + + self.overlapped = win32file.OVERLAPPED() + self.overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None) + + def __del__(self): + self.close() + + def close(self): + """close port""" + if self.hComPort: + #Wait until data is transmitted, but not too long... (Timeout-Time) + #while 1: + # flags, comState = win32file.ClearCommError(hComPort) + # if comState.cbOutQue <= 0 or calcTimeout(startTime) > timeout: + # break + + self.setRTS(0) + self.setDTR(0) + #Clear buffers: + win32file.PurgeComm(self.hComPort, + win32file.PURGE_TXCLEAR | win32file.PURGE_TXABORT | + win32file.PURGE_RXCLEAR | win32file.PURGE_RXABORT) + #Restore original timeout values: + win32file.SetCommTimeouts(self.hComPort, self.orgTimeouts) + #Close COM-Port: + win32file.CloseHandle(self.hComPort) + self.hComPort = None + + def inWaiting(self): + """returns the number of bytes waiting to be read""" + flags, comstat = win32file.ClearCommError(self.hComPort) + return comstat.cbInQue + + def _read(self, size=1): + flags, comstat = win32file.ClearCommError( self.hComPort ) + #print "1:",comstat.cbInQue, + if comstat.cbInQue < size: + rc, mask = win32file.WaitCommEvent(self.hComPort, self.overlapped) + if rc == 0: # Character already ready! + win32event.SetEvent(self.overlapped.hEvent) + + rc = win32event.WaitForSingleObject(self.overlapped.hEvent, win32event.INFINITE) + flags, comstat = win32file.ClearCommError( self.hComPort ) + #print "2:",comstat.cbInQue, + + rc, data = win32file.ReadFile(self.hComPort, size, self.overlapped) + win32event.WaitForSingleObject(self.overlapped.hEvent, win32event.INFINITE) + print "read %r" % str(data) + return str(data) + + def work_read(self,num=1): + "read num bytes from serial port" + if not self.hComPort: raise portNotOpenError + flags, comstat = win32file.ClearCommError( self.hComPort ) + #print "1:",comstat.cbInQue, + if comstat.cbInQue < num: + rc, mask = win32file.WaitCommEvent(self.hComPort, self.overlapped) + if rc == 0: # Character already ready! + win32event.SetEvent(self.overlapped.hEvent) + + if self.timeout: + rc = win32event.WaitForSingleObject(self.overlapped.hEvent, self.timeout*1000) + else: + rc = win32event.WaitForSingleObject(self.overlapped.hEvent, win32event.INFINITE) + flags, comstat = win32file.ClearCommError( self.hComPort ) + #print "2:",comstat.cbInQue, + + #rc, data = win32file.ReadFile(self.hComPort, comstat.cbInQue, self.overlapped) + rc, data = win32file.ReadFile(self.hComPort, num, self.overlapped) + if self.timeout: + win32event.WaitForSingleObject(self.overlapped.hEvent, self.timeout*1000) + else: + win32event.WaitForSingleObject(self.overlapped.hEvent, win32event.INFINITE) + + #old: hr, data = win32file.ReadFile(self.hComPort, num) + #print '.%s.' % str(data) + #print "read() soll %d ist %d" % (num, len(str(data))), repr(data) + return str(data) + + def read(self, size=1): + "read num bytes from serial port" + if not self.hComPort: raise portNotOpenError + #print "read %d" %size ####debug + read = '' + if size > 0: + while len(read) < size: + flags, comstat = win32file.ClearCommError( self.hComPort ) + #print "1:",comstat.cbInQue, + #self.overlapped = win32file.OVERLAPPED() + #self.overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None) + #win32event.ResetEvent(self.overlapped.hEvent) +## if comstat.cbInQue < size: +## #print "read