blob: 38d1dba4404e8cfb11cd40e6039049b2b88e7f69 [file] [log] [blame]
cliechti89b4af12002-02-12 23:24:41 +00001#!/usr/bin/env python
cliechti58b481c2009-02-16 20:42:32 +00002#
cliechtic54b2c82008-06-21 01:59:08 +00003# Python Serial Port Extension for Win32, Linux, BSD, Jython
4# module for serial IO for POSIX compatible systems, like Linux
5# see __init__.py
cliechti89b4af12002-02-12 23:24:41 +00006#
cliechti58b481c2009-02-16 20:42:32 +00007# (C) 2001-2009 Chris Liechti <cliechti@gmx.net>
cliechti89b4af12002-02-12 23:24:41 +00008# this is distributed under a free software license, see license.txt
9#
cliechtic54b2c82008-06-21 01:59:08 +000010# parts based on code from Grant B. Edwards <grante@visi.com>:
cliechti89b4af12002-02-12 23:24:41 +000011# ftp://ftp.visi.com/users/grante/python/PosixSerial.py
cliechti53c9fd42009-07-23 23:51:51 +000012#
cliechti89b4af12002-02-12 23:24:41 +000013# references: http://www.easysw.com/~mike/serial/serial.html
14
cliechti3cf46d62009-08-07 00:19:57 +000015import sys, os, fcntl, termios, struct, select, errno, time
cliechtid6bf52c2003-10-01 02:28:12 +000016from serialutil import *
cliechti89b4af12002-02-12 23:24:41 +000017
cliechti53c9fd42009-07-23 23:51:51 +000018# Do check the Python version as some constants have moved.
cliechti89b4af12002-02-12 23:24:41 +000019if (sys.hexversion < 0x020100f0):
20 import TERMIOS
21else:
22 TERMIOS = termios
23
24if (sys.hexversion < 0x020200f0):
25 import FCNTL
26else:
27 FCNTL = fcntl
28
cliechti3172d3d2009-07-21 22:33:40 +000029# try to detect the OS so that a device can be selected...
cliechti53c9fd42009-07-23 23:51:51 +000030# this code block should supply a device() and set_special_baudrate() function
31# for the platform
cliechtid6bf52c2003-10-01 02:28:12 +000032plat = sys.platform.lower()
cliechti89b4af12002-02-12 23:24:41 +000033
cliechti3172d3d2009-07-21 22:33:40 +000034if plat[:5] == 'linux': # Linux (confirmed)
cliechti53c9fd42009-07-23 23:51:51 +000035
cliechti89b4af12002-02-12 23:24:41 +000036 def device(port):
37 return '/dev/ttyS%d' % port
38
cliechti53c9fd42009-07-23 23:51:51 +000039 ASYNC_SPD_MASK = 0x1030
40 ASYNC_SPD_CUST = 0x0030
41
42 def set_special_baudrate(port, baudrate):
43 import array
44 buf = array.array('i', [0] * 32)
45
46 # get serial_struct
47 FCNTL.ioctl(port.fd, TERMIOS.TIOCGSERIAL, buf)
48
49 # set custom divisor
50 buf[6] = buf[7] / baudrate
51
52 # update flags
53 buf[4] &= ~ASYNC_SPD_MASK
54 buf[4] |= ASYNC_SPD_CUST
55
56 # set serial_struct
57 try:
58 res = FCNTL.ioctl(port.fd, TERMIOS.TIOCSSERIAL, buf)
59 except IOError:
60 raise ValueError('Failed to set custom baud rate: %r' % baudrate)
61
cliechti99220a02009-08-14 00:21:25 +000062 baudrate_constants = {
63 0: 0000000, # hang up
64 50: 0000001,
65 75: 0000002,
66 110: 0000003,
67 134: 0000004,
68 150: 0000005,
69 200: 0000006,
70 300: 0000007,
71 600: 0000010,
72 1200: 0000011,
73 1800: 0000012,
74 2400: 0000013,
75 4800: 0000014,
76 9600: 0000015,
77 19200: 0000016,
78 38400: 0000017,
79 57600: 0010001,
80 115200: 0010002,
81 230400: 0010003,
82 460800: 0010004,
83 500000: 0010005,
84 576000: 0010006,
85 921600: 0010007,
86 1000000: 0010010,
87 1152000: 0010011,
88 1500000: 0010012,
89 2000000: 0010013,
90 2500000: 0010014,
91 3000000: 0010015,
92 3500000: 0010016,
93 4000000: 0010017
94 }
95
cliechti53c9fd42009-07-23 23:51:51 +000096elif plat == 'cygwin': # cygwin/win32 (confirmed)
97
cliechtif281fde2002-06-07 21:53:40 +000098 def device(port):
cliechtif5831e02002-12-05 23:15:27 +000099 return '/dev/com%d' % (port + 1)
cliechtif281fde2002-06-07 21:53:40 +0000100
cliechti53c9fd42009-07-23 23:51:51 +0000101 def set_special_baudrate(port, baudrate):
cliechti99220a02009-08-14 00:21:25 +0000102 raise ValueError("sorry don't know how to handle non standard baud rate on this platform")
cliechti53c9fd42009-07-23 23:51:51 +0000103
cliechti99220a02009-08-14 00:21:25 +0000104 baudrate_constants = {}
cliechti53c9fd42009-07-23 23:51:51 +0000105
cliechti99220a02009-08-14 00:21:25 +0000106elif plat == 'openbsd3': # BSD (confirmed)
cliechti53c9fd42009-07-23 23:51:51 +0000107
cliechti89b4af12002-02-12 23:24:41 +0000108 def device(port):
109 return '/dev/ttyp%d' % port
110
cliechti53c9fd42009-07-23 23:51:51 +0000111 def set_special_baudrate(port, baudrate):
112 raise ValueError("sorry don't know how to handle non standard baud rate on this platform")
113
cliechti99220a02009-08-14 00:21:25 +0000114 baudrate_constants = {}
115
cliechti89b4af12002-02-12 23:24:41 +0000116elif plat[:3] == 'bsd' or \
cliechti89b4af12002-02-12 23:24:41 +0000117 plat[:7] == 'freebsd' or \
cliechti53c9fd42009-07-23 23:51:51 +0000118 plat[:7] == 'openbsd': # BSD (confirmed for freebsd4: cuaa%d)
119
cliechti89b4af12002-02-12 23:24:41 +0000120 def device(port):
cliechtieaa96882008-06-16 22:59:20 +0000121 return '/dev/cuad%d' % port
cliechti89b4af12002-02-12 23:24:41 +0000122
cliechti53c9fd42009-07-23 23:51:51 +0000123 def set_special_baudrate(port, baudrate):
124 raise ValueError("sorry don't know how to handle non standard baud rate on this platform")
125
cliechti99220a02009-08-14 00:21:25 +0000126 baudrate_constants = {}
127
cliechti53c9fd42009-07-23 23:51:51 +0000128elif plat[:6] == 'darwin': # OS X
129
130 version = os.uname()[2].split('.')
131 # Tiger or above can support arbitrary serial speeds
132 if int(version[0]) >= 8:
cliechti53c9fd42009-07-23 23:51:51 +0000133 def set_special_baudrate(port, baudrate):
134 # use IOKit-specific call to set up high speeds
135 import array, fcntl
136 buf = array.array('i', [baudrate])
137 IOSSIOSPEED = 0x80045402 #_IOW('T', 2, speed_t)
138 fcntl.ioctl(port.fd, IOSSIOSPEED, buf, 1)
139 else: # version < 8
140 def set_special_baudrate(port, baudrate):
141 raise ValueError("baud rate not supported")
142
143 def device(port):
144 return '/dev/cuad%d' % port
145
cliechti99220a02009-08-14 00:21:25 +0000146 baudrate_constants = {}
147
cliechti53c9fd42009-07-23 23:51:51 +0000148
cliechti3172d3d2009-07-21 22:33:40 +0000149elif plat[:6] == 'netbsd': # NetBSD 1.6 testing by Erk
cliechti53c9fd42009-07-23 23:51:51 +0000150
cliechti835996a2004-06-02 19:45:07 +0000151 def device(port):
152 return '/dev/dty%02d' % port
153
cliechti53c9fd42009-07-23 23:51:51 +0000154 def set_special_baudrate(port, baudrate):
155 raise ValueError("sorry don't know how to handle non standard baud rate on this platform")
156
cliechti99220a02009-08-14 00:21:25 +0000157 baudrate_constants = {}
158
cliechti3172d3d2009-07-21 22:33:40 +0000159elif plat[:4] == 'irix': # IRIX (partially tested)
cliechti53c9fd42009-07-23 23:51:51 +0000160
cliechti89b4af12002-02-12 23:24:41 +0000161 def device(port):
cliechtie2418e92006-06-05 20:03:17 +0000162 return '/dev/ttyf%d' % (port+1) #XXX different device names depending on flow control
cliechti89b4af12002-02-12 23:24:41 +0000163
cliechti53c9fd42009-07-23 23:51:51 +0000164 def set_special_baudrate(port, baudrate):
165 raise ValueError("sorry don't know how to handle non standard baud rate on this platform")
166
cliechti99220a02009-08-14 00:21:25 +0000167 baudrate_constants = {}
168
cliechti3172d3d2009-07-21 22:33:40 +0000169elif plat[:2] == 'hp': # HP-UX (not tested)
cliechti53c9fd42009-07-23 23:51:51 +0000170
cliechti89b4af12002-02-12 23:24:41 +0000171 def device(port):
172 return '/dev/tty%dp0' % (port+1)
173
cliechti53c9fd42009-07-23 23:51:51 +0000174 def set_special_baudrate(port, baudrate):
175 raise ValueError("sorry don't know how to handle non standard baud rate on this platform")
176
cliechti99220a02009-08-14 00:21:25 +0000177 baudrate_constants = {}
178
cliechti3172d3d2009-07-21 22:33:40 +0000179elif plat[:5] == 'sunos': # Solaris/SunOS (confirmed)
cliechti53c9fd42009-07-23 23:51:51 +0000180
cliechti89b4af12002-02-12 23:24:41 +0000181 def device(port):
182 return '/dev/tty%c' % (ord('a')+port)
cliechti58b481c2009-02-16 20:42:32 +0000183
cliechti53c9fd42009-07-23 23:51:51 +0000184 def set_special_baudrate(port, baudrate):
185 raise ValueError("sorry don't know how to handle non standard baud rate on this platform")
186
cliechti99220a02009-08-14 00:21:25 +0000187 baudrate_constants = {}
188
cliechti3172d3d2009-07-21 22:33:40 +0000189elif plat[:3] == 'aix': # AIX
cliechti53c9fd42009-07-23 23:51:51 +0000190
cliechti40e1b072005-03-12 12:05:26 +0000191 def device(port):
192 return '/dev/tty%d' % (port)
cliechti89b4af12002-02-12 23:24:41 +0000193
cliechti53c9fd42009-07-23 23:51:51 +0000194 def set_special_baudrate(port, baudrate):
195 raise ValueError("sorry don't know how to handle non standard baud rate on this platform")
196
cliechti99220a02009-08-14 00:21:25 +0000197 baudrate_constants = {}
198
cliechti89b4af12002-02-12 23:24:41 +0000199else:
200 #platform detection has failed...
cliechti7aaead32009-07-23 14:02:41 +0000201 sys.stderr.write("""\
202don't know how to number ttys on this system.
cliechti895e8302004-04-20 02:40:28 +0000203! Use an explicit path (eg /dev/ttyS1) or send this information to
204! the author of this module:
cliechti89b4af12002-02-12 23:24:41 +0000205
cliechti895e8302004-04-20 02:40:28 +0000206sys.platform = %r
207os.name = %r
208serialposix.py version = %s
cliechti89b4af12002-02-12 23:24:41 +0000209
210also add the device name of the serial port and where the
211counting starts for the first serial port.
212e.g. 'first serial port: /dev/ttyS0'
213and with a bit luck you can get this module running...
cliechti7aaead32009-07-23 14:02:41 +0000214""" % (sys.platform, os.name, VERSION))
cliechti58b481c2009-02-16 20:42:32 +0000215 # no exception, just continue with a brave attempt to build a device name
216 # even if the device name is not correct for the platform it has chances
cliechti3172d3d2009-07-21 22:33:40 +0000217 # to work using a string with the real device name as port parameter.
cliechtid6bf52c2003-10-01 02:28:12 +0000218 def device(portum):
219 return '/dev/ttyS%d' % portnum
cliechti53c9fd42009-07-23 23:51:51 +0000220 def set_special_baudrate(port, baudrate):
221 raise SerialException("sorry don't know how to handle non standard baud rate on this platform")
cliechti99220a02009-08-14 00:21:25 +0000222 baudrate_constants = {}
cliechtid6bf52c2003-10-01 02:28:12 +0000223 #~ raise Exception, "this module does not run on this platform, sorry."
cliechti89b4af12002-02-12 23:24:41 +0000224
cliechti58b481c2009-02-16 20:42:32 +0000225# whats up with "aix", "beos", ....
226# they should work, just need to know the device names.
cliechti89b4af12002-02-12 23:24:41 +0000227
228
cliechti58b481c2009-02-16 20:42:32 +0000229# load some constants for later use.
230# try to use values from TERMIOS, use defaults from linux otherwise
cliechti8901aef2002-11-19 01:15:05 +0000231TIOCMGET = hasattr(TERMIOS, 'TIOCMGET') and TERMIOS.TIOCMGET or 0x5415
232TIOCMBIS = hasattr(TERMIOS, 'TIOCMBIS') and TERMIOS.TIOCMBIS or 0x5416
233TIOCMBIC = hasattr(TERMIOS, 'TIOCMBIC') and TERMIOS.TIOCMBIC or 0x5417
234TIOCMSET = hasattr(TERMIOS, 'TIOCMSET') and TERMIOS.TIOCMSET or 0x5418
cliechti89b4af12002-02-12 23:24:41 +0000235
cliechti8901aef2002-11-19 01:15:05 +0000236#TIOCM_LE = hasattr(TERMIOS, 'TIOCM_LE') and TERMIOS.TIOCM_LE or 0x001
237TIOCM_DTR = hasattr(TERMIOS, 'TIOCM_DTR') and TERMIOS.TIOCM_DTR or 0x002
238TIOCM_RTS = hasattr(TERMIOS, 'TIOCM_RTS') and TERMIOS.TIOCM_RTS or 0x004
239#TIOCM_ST = hasattr(TERMIOS, 'TIOCM_ST') and TERMIOS.TIOCM_ST or 0x008
240#TIOCM_SR = hasattr(TERMIOS, 'TIOCM_SR') and TERMIOS.TIOCM_SR or 0x010
cliechti89b4af12002-02-12 23:24:41 +0000241
cliechti8901aef2002-11-19 01:15:05 +0000242TIOCM_CTS = hasattr(TERMIOS, 'TIOCM_CTS') and TERMIOS.TIOCM_CTS or 0x020
243TIOCM_CAR = hasattr(TERMIOS, 'TIOCM_CAR') and TERMIOS.TIOCM_CAR or 0x040
244TIOCM_RNG = hasattr(TERMIOS, 'TIOCM_RNG') and TERMIOS.TIOCM_RNG or 0x080
245TIOCM_DSR = hasattr(TERMIOS, 'TIOCM_DSR') and TERMIOS.TIOCM_DSR or 0x100
246TIOCM_CD = hasattr(TERMIOS, 'TIOCM_CD') and TERMIOS.TIOCM_CD or TIOCM_CAR
247TIOCM_RI = hasattr(TERMIOS, 'TIOCM_RI') and TERMIOS.TIOCM_RI or TIOCM_RNG
248#TIOCM_OUT1 = hasattr(TERMIOS, 'TIOCM_OUT1') and TERMIOS.TIOCM_OUT1 or 0x2000
249#TIOCM_OUT2 = hasattr(TERMIOS, 'TIOCM_OUT2') and TERMIOS.TIOCM_OUT2 or 0x4000
cliechtif5831e02002-12-05 23:15:27 +0000250TIOCINQ = hasattr(TERMIOS, 'FIONREAD') and TERMIOS.FIONREAD or 0x541B
cliechti89b4af12002-02-12 23:24:41 +0000251
252TIOCM_zero_str = struct.pack('I', 0)
253TIOCM_RTS_str = struct.pack('I', TIOCM_RTS)
254TIOCM_DTR_str = struct.pack('I', TIOCM_DTR)
255
cliechti997b63c2008-06-21 00:09:31 +0000256TIOCSBRK = hasattr(TERMIOS, 'TIOCSBRK') and TERMIOS.TIOCSBRK or 0x5427
257TIOCCBRK = hasattr(TERMIOS, 'TIOCCBRK') and TERMIOS.TIOCCBRK or 0x5428
258
cliechti89b4af12002-02-12 23:24:41 +0000259
cliechtif81362e2009-07-25 03:44:33 +0000260class PosixSerial(SerialBase):
cliechtid6bf52c2003-10-01 02:28:12 +0000261 """Serial port class POSIX implementation. Serial port configuration is
262 done with termios and fcntl. Runs on Linux and many other Un*x like
263 systems."""
264
265 def open(self):
266 """Open port with current settings. This may throw a SerialException
267 if the port cannot be opened."""
cliechtif81362e2009-07-25 03:44:33 +0000268 self.fd = None
cliechtid6bf52c2003-10-01 02:28:12 +0000269 if self._port is None:
270 raise SerialException("Port must be configured before it can be used.")
cliechti58b481c2009-02-16 20:42:32 +0000271 # open
cliechti4616bf12002-04-08 23:13:14 +0000272 try:
273 self.fd = os.open(self.portstr, os.O_RDWR|os.O_NOCTTY|os.O_NONBLOCK)
274 except Exception, msg:
275 self.fd = None
cliechti93db61b2006-08-26 19:16:18 +0000276 raise SerialException("could not open port %s: %s" % (self._port, msg))
cliechti2750b832009-07-28 00:13:52 +0000277 #~ fcntl.fcntl(self.fd, FCNTL.F_SETFL, 0) # set blocking
cliechti58b481c2009-02-16 20:42:32 +0000278
cliechtib2f5fc82006-10-20 00:09:07 +0000279 try:
280 self._reconfigurePort()
281 except:
cliechti2750b832009-07-28 00:13:52 +0000282 try:
283 os.close(self.fd)
284 except:
285 # ignore any exception when closing the port
286 # also to keep original exception that happened when setting up
287 pass
cliechtib2f5fc82006-10-20 00:09:07 +0000288 self.fd = None
cliechtif0a4f0f2009-07-21 21:12:37 +0000289 raise
cliechtib2f5fc82006-10-20 00:09:07 +0000290 else:
291 self._isOpen = True
cliechti62611612004-04-20 01:55:43 +0000292 #~ self.flushInput()
cliechti58b481c2009-02-16 20:42:32 +0000293
294
cliechtid6bf52c2003-10-01 02:28:12 +0000295 def _reconfigurePort(self):
cliechtib2f5fc82006-10-20 00:09:07 +0000296 """Set communication parameters on opened port."""
cliechtic6178262004-03-22 22:04:52 +0000297 if self.fd is None:
cliechtid6bf52c2003-10-01 02:28:12 +0000298 raise SerialException("Can only operate on a valid port handle")
cliechtie8c45422008-06-20 23:23:14 +0000299 custom_baud = None
cliechti58b481c2009-02-16 20:42:32 +0000300
cliechti2750b832009-07-28 00:13:52 +0000301 vmin = vtime = 0 # timeout is done via select
cliechti679bfa62008-06-20 23:58:15 +0000302 if self._interCharTimeout is not None:
303 vmin = 1
304 vtime = int(self._interCharTimeout * 10)
cliechti6ce7ab12002-11-07 02:15:00 +0000305 try:
cliechtid6bf52c2003-10-01 02:28:12 +0000306 iflag, oflag, cflag, lflag, ispeed, ospeed, cc = termios.tcgetattr(self.fd)
cliechti2750b832009-07-28 00:13:52 +0000307 except termios.error, msg: # if a port is nonexistent but has a /dev file, it'll fail here
cliechtid6bf52c2003-10-01 02:28:12 +0000308 raise SerialException("Could not configure port: %s" % msg)
cliechti58b481c2009-02-16 20:42:32 +0000309 # set up raw mode / no echo / binary
cliechtid6bf52c2003-10-01 02:28:12 +0000310 cflag |= (TERMIOS.CLOCAL|TERMIOS.CREAD)
311 lflag &= ~(TERMIOS.ICANON|TERMIOS.ECHO|TERMIOS.ECHOE|TERMIOS.ECHOK|TERMIOS.ECHONL|
cliechti835996a2004-06-02 19:45:07 +0000312 TERMIOS.ISIG|TERMIOS.IEXTEN) #|TERMIOS.ECHOPRT
cliechti2750b832009-07-28 00:13:52 +0000313 for flag in ('ECHOCTL', 'ECHOKE'): # netbsd workaround for Erk
cliechti835996a2004-06-02 19:45:07 +0000314 if hasattr(TERMIOS, flag):
315 lflag &= ~getattr(TERMIOS, flag)
cliechti58b481c2009-02-16 20:42:32 +0000316
cliechtid6bf52c2003-10-01 02:28:12 +0000317 oflag &= ~(TERMIOS.OPOST)
cliechti895e8302004-04-20 02:40:28 +0000318 iflag &= ~(TERMIOS.INLCR|TERMIOS.IGNCR|TERMIOS.ICRNL|TERMIOS.IGNBRK)
cliechti89b4af12002-02-12 23:24:41 +0000319 if hasattr(TERMIOS, 'IUCLC'):
cliechti895e8302004-04-20 02:40:28 +0000320 iflag &= ~TERMIOS.IUCLC
cliechti3e57b3d2005-08-12 21:04:44 +0000321 if hasattr(TERMIOS, 'PARMRK'):
322 iflag &= ~TERMIOS.PARMRK
cliechti58b481c2009-02-16 20:42:32 +0000323
cliechtif0a4f0f2009-07-21 21:12:37 +0000324 # setup baud rate
cliechti89b4af12002-02-12 23:24:41 +0000325 try:
cliechti2750b832009-07-28 00:13:52 +0000326 ispeed = ospeed = getattr(TERMIOS, 'B%s' % (self._baudrate))
cliechti895e8302004-04-20 02:40:28 +0000327 except AttributeError:
cliechtif1559d02007-11-08 23:43:58 +0000328 try:
329 ispeed = ospeed = baudrate_constants[self._baudrate]
330 except KeyError:
cliechtie8c45422008-06-20 23:23:14 +0000331 #~ raise ValueError('Invalid baud rate: %r' % self._baudrate)
cliechtif0a4f0f2009-07-21 21:12:37 +0000332 # may need custom baud rate, it isn't in our list.
cliechtie8c45422008-06-20 23:23:14 +0000333 ispeed = ospeed = getattr(TERMIOS, 'B38400')
cliechtif0a4f0f2009-07-21 21:12:37 +0000334 try:
335 custom_baud = int(self._baudrate) # store for later
336 except ValueError:
337 raise ValueError('Invalid baud rate: %r' % self._baudrate)
338 else:
339 if custom_baud < 0:
340 raise ValueError('Invalid baud rate: %r' % self._baudrate)
cliechti58b481c2009-02-16 20:42:32 +0000341
342 # setup char len
cliechtid6bf52c2003-10-01 02:28:12 +0000343 cflag &= ~TERMIOS.CSIZE
344 if self._bytesize == 8:
345 cflag |= TERMIOS.CS8
346 elif self._bytesize == 7:
347 cflag |= TERMIOS.CS7
348 elif self._bytesize == 6:
349 cflag |= TERMIOS.CS6
350 elif self._bytesize == 5:
351 cflag |= TERMIOS.CS5
cliechti89b4af12002-02-12 23:24:41 +0000352 else:
cliechtid6bf52c2003-10-01 02:28:12 +0000353 raise ValueError('Invalid char len: %r' % self._bytesize)
cliechti58b481c2009-02-16 20:42:32 +0000354 # setup stopbits
cliechtid6bf52c2003-10-01 02:28:12 +0000355 if self._stopbits == STOPBITS_ONE:
356 cflag &= ~(TERMIOS.CSTOPB)
cliechti58b481c2009-02-16 20:42:32 +0000357 elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
358 cflag |= (TERMIOS.CSTOPB) # XXX same as TWO.. there is no POSIX support for 1.5
cliechtid6bf52c2003-10-01 02:28:12 +0000359 elif self._stopbits == STOPBITS_TWO:
360 cflag |= (TERMIOS.CSTOPB)
cliechti89b4af12002-02-12 23:24:41 +0000361 else:
cliechti3172d3d2009-07-21 22:33:40 +0000362 raise ValueError('Invalid stop bit specification: %r' % self._stopbits)
cliechti58b481c2009-02-16 20:42:32 +0000363 # setup parity
cliechtid6bf52c2003-10-01 02:28:12 +0000364 iflag &= ~(TERMIOS.INPCK|TERMIOS.ISTRIP)
365 if self._parity == PARITY_NONE:
366 cflag &= ~(TERMIOS.PARENB|TERMIOS.PARODD)
367 elif self._parity == PARITY_EVEN:
368 cflag &= ~(TERMIOS.PARODD)
369 cflag |= (TERMIOS.PARENB)
370 elif self._parity == PARITY_ODD:
371 cflag |= (TERMIOS.PARENB|TERMIOS.PARODD)
cliechti89b4af12002-02-12 23:24:41 +0000372 else:
cliechtid6bf52c2003-10-01 02:28:12 +0000373 raise ValueError('Invalid parity: %r' % self._parity)
cliechti58b481c2009-02-16 20:42:32 +0000374 # setup flow control
375 # xonxoff
cliechti89b4af12002-02-12 23:24:41 +0000376 if hasattr(TERMIOS, 'IXANY'):
cliechtid6bf52c2003-10-01 02:28:12 +0000377 if self._xonxoff:
cliechti62611612004-04-20 01:55:43 +0000378 iflag |= (TERMIOS.IXON|TERMIOS.IXOFF) #|TERMIOS.IXANY)
cliechti89b4af12002-02-12 23:24:41 +0000379 else:
cliechtid6bf52c2003-10-01 02:28:12 +0000380 iflag &= ~(TERMIOS.IXON|TERMIOS.IXOFF|TERMIOS.IXANY)
cliechti89b4af12002-02-12 23:24:41 +0000381 else:
cliechtid6bf52c2003-10-01 02:28:12 +0000382 if self._xonxoff:
383 iflag |= (TERMIOS.IXON|TERMIOS.IXOFF)
cliechti89b4af12002-02-12 23:24:41 +0000384 else:
cliechtid6bf52c2003-10-01 02:28:12 +0000385 iflag &= ~(TERMIOS.IXON|TERMIOS.IXOFF)
cliechti58b481c2009-02-16 20:42:32 +0000386 # rtscts
cliechti89b4af12002-02-12 23:24:41 +0000387 if hasattr(TERMIOS, 'CRTSCTS'):
cliechtid6bf52c2003-10-01 02:28:12 +0000388 if self._rtscts:
389 cflag |= (TERMIOS.CRTSCTS)
cliechti89b4af12002-02-12 23:24:41 +0000390 else:
cliechtid6bf52c2003-10-01 02:28:12 +0000391 cflag &= ~(TERMIOS.CRTSCTS)
cliechti2750b832009-07-28 00:13:52 +0000392 elif hasattr(TERMIOS, 'CNEW_RTSCTS'): # try it with alternate constant name
cliechtid6bf52c2003-10-01 02:28:12 +0000393 if self._rtscts:
394 cflag |= (TERMIOS.CNEW_RTSCTS)
cliechtid4743692002-04-08 22:39:53 +0000395 else:
cliechtid6bf52c2003-10-01 02:28:12 +0000396 cflag &= ~(TERMIOS.CNEW_RTSCTS)
cliechti2750b832009-07-28 00:13:52 +0000397 # XXX should there be a warning if setting up rtscts (and xonxoff etc) fails??
cliechti58b481c2009-02-16 20:42:32 +0000398
399 # buffer
400 # vmin "minimal number of characters to be read. = for non blocking"
cliechtid6bf52c2003-10-01 02:28:12 +0000401 if vmin < 0 or vmin > 255:
402 raise ValueError('Invalid vmin: %r ' % vmin)
403 cc[TERMIOS.VMIN] = vmin
cliechti58b481c2009-02-16 20:42:32 +0000404 # vtime
cliechtid6bf52c2003-10-01 02:28:12 +0000405 if vtime < 0 or vtime > 255:
406 raise ValueError('Invalid vtime: %r' % vtime)
407 cc[TERMIOS.VTIME] = vtime
cliechti58b481c2009-02-16 20:42:32 +0000408 # activate settings
cliechtid6bf52c2003-10-01 02:28:12 +0000409 termios.tcsetattr(self.fd, TERMIOS.TCSANOW, [iflag, oflag, cflag, lflag, ispeed, ospeed, cc])
cliechti58b481c2009-02-16 20:42:32 +0000410
cliechtie8c45422008-06-20 23:23:14 +0000411 # apply custom baud rate, if any
412 if custom_baud is not None:
cliechti53c9fd42009-07-23 23:51:51 +0000413 set_special_baudrate(self, custom_baud)
cliechti89b4af12002-02-12 23:24:41 +0000414
415 def close(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000416 """Close port"""
417 if self._isOpen:
cliechtic6178262004-03-22 22:04:52 +0000418 if self.fd is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000419 os.close(self.fd)
420 self.fd = None
421 self._isOpen = False
cliechti89b4af12002-02-12 23:24:41 +0000422
cliechtid6bf52c2003-10-01 02:28:12 +0000423 def makeDeviceName(self, port):
424 return device(port)
425
426 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti95c62212002-03-04 22:17:53 +0000427
cliechti89b4af12002-02-12 23:24:41 +0000428 def inWaiting(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000429 """Return the number of characters currently in the input buffer."""
cliechtif5831e02002-12-05 23:15:27 +0000430 #~ s = fcntl.ioctl(self.fd, TERMIOS.FIONREAD, TIOCM_zero_str)
431 s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str)
cliechti89b4af12002-02-12 23:24:41 +0000432 return struct.unpack('I',s)[0]
433
cliechti4a567a02009-07-27 22:09:31 +0000434 def read(self, size=1):
cliechtid6bf52c2003-10-01 02:28:12 +0000435 """Read size bytes from the serial port. If a timeout is set it may
436 return less characters as requested. With no timeout it will block
437 until the requested number of bytes is read."""
cliechtic6178262004-03-22 22:04:52 +0000438 if self.fd is None: raise portNotOpenError
cliechti4a567a02009-07-27 22:09:31 +0000439 read = bytearray()
cliechti65722c92009-08-07 00:48:53 +0000440 poll = select.poll()
441 poll.register(self.fd, select.POLLIN|select.POLLERR|select.POLLHUP|select.POLLNVAL)
cliechti8d5dbe22002-04-24 20:44:13 +0000442 inp = None
cliechti89b4af12002-02-12 23:24:41 +0000443 if size > 0:
444 while len(read) < size:
cliechti58b481c2009-02-16 20:42:32 +0000445 # print "\tread(): size",size, "have", len(read) #debug
cliechti65722c92009-08-07 00:48:53 +0000446 # wait until device becomes ready to read (or something fails)
447 for fd, event in poll.poll(self._timeout):
448 if event & (select.POLLERR|select.POLLHUP|select.POLLNVAL):
449 raise SerialException('device reports error (poll)')
450 # we don't care if it is select.POLLIN or timeout, that's
451 # handled below
cliechti4a567a02009-07-27 22:09:31 +0000452 buf = os.read(self.fd, size - len(read))
453 read.extend(buf)
cliechti2750b832009-07-28 00:13:52 +0000454 if ((self._timeout is not None and self._timeout >= 0) or
455 (self._interCharTimeout is not None and self._interCharTimeout > 0)) and not buf:
cliechti58b481c2009-02-16 20:42:32 +0000456 break # early abort on timeout
cliechti4a567a02009-07-27 22:09:31 +0000457 return bytes(read)
cliechti89b4af12002-02-12 23:24:41 +0000458
cliechti4a567a02009-07-27 22:09:31 +0000459 def write(self, data):
cliechtid6bf52c2003-10-01 02:28:12 +0000460 """Output the given string over the serial port."""
cliechtic6178262004-03-22 22:04:52 +0000461 if self.fd is None: raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000462 t = len(data)
463 d = data
cliechti3cf46d62009-08-07 00:19:57 +0000464 if self._writeTimeout is not None and self._writeTimeout > 0:
465 timeout = time.time() + self._writeTimeout
466 else:
467 timeout = None
cliechtic6178262004-03-22 22:04:52 +0000468 while t > 0:
cliechti5d4d0bd2004-11-13 03:27:39 +0000469 try:
cliechti5d4d0bd2004-11-13 03:27:39 +0000470 n = os.write(self.fd, d)
cliechti3cf46d62009-08-07 00:19:57 +0000471 if timeout:
472 # when timeout is set, use select to wait for being ready
473 # with the time left as timeout
474 timeleft = timeout - time.time()
475 if timeleft < 0:
476 raise writeTimeoutError
477 _, ready, _ = select.select([], [self.fd], [], timeleft)
cliechti5d4d0bd2004-11-13 03:27:39 +0000478 if not ready:
479 raise writeTimeoutError
480 d = d[n:]
481 t = t - n
cliechti4a567a02009-07-27 22:09:31 +0000482 except OSError, v:
cliechti5d4d0bd2004-11-13 03:27:39 +0000483 if v.errno != errno.EAGAIN:
cliechti65722c92009-08-07 00:48:53 +0000484 raise SerialException('write failed: %s' % (v,))
cliechtif81362e2009-07-25 03:44:33 +0000485 return len(data)
cliechtid6bf52c2003-10-01 02:28:12 +0000486
cliechtia30a8a02003-10-05 12:28:13 +0000487 def flush(self):
488 """Flush of file like objects. In this case, wait until all data
489 is written."""
490 self.drainOutput()
491
cliechti89b4af12002-02-12 23:24:41 +0000492 def flushInput(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000493 """Clear input buffer, discarding all that is in the buffer."""
cliechtic6178262004-03-22 22:04:52 +0000494 if self.fd is None:
cliechti89b4af12002-02-12 23:24:41 +0000495 raise portNotOpenError
496 termios.tcflush(self.fd, TERMIOS.TCIFLUSH)
497
498 def flushOutput(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000499 """Clear output buffer, aborting the current output and
500 discarding all that is in the buffer."""
cliechtic6178262004-03-22 22:04:52 +0000501 if self.fd is None:
cliechti89b4af12002-02-12 23:24:41 +0000502 raise portNotOpenError
503 termios.tcflush(self.fd, TERMIOS.TCOFLUSH)
504
cliechtiaaa04602006-02-05 23:02:46 +0000505 def sendBreak(self, duration=0.25):
cliechti997b63c2008-06-21 00:09:31 +0000506 """Send break condition. Timed, returns to idle state after given duration."""
cliechtic6178262004-03-22 22:04:52 +0000507 if self.fd is None:
cliechti89b4af12002-02-12 23:24:41 +0000508 raise portNotOpenError
cliechtiaaa04602006-02-05 23:02:46 +0000509 termios.tcsendbreak(self.fd, int(duration/0.25))
cliechti89b4af12002-02-12 23:24:41 +0000510
cliechti997b63c2008-06-21 00:09:31 +0000511 def setBreak(self, level=1):
cliechtidfec0c82009-07-21 01:35:41 +0000512 """Set break: Controls TXD. When active, no transmitting is possible."""
cliechti997b63c2008-06-21 00:09:31 +0000513 if self.fd is None: raise portNotOpenError
514 if level:
515 fcntl.ioctl(self.fd, TIOCSBRK)
516 else:
517 fcntl.ioctl(self.fd, TIOCCBRK)
518
cliechti93db61b2006-08-26 19:16:18 +0000519 def setRTS(self, level=1):
cliechtid6bf52c2003-10-01 02:28:12 +0000520 """Set terminal status line: Request To Send"""
cliechtic6178262004-03-22 22:04:52 +0000521 if self.fd is None: raise portNotOpenError
cliechtib2f5fc82006-10-20 00:09:07 +0000522 if level:
cliechtid6bf52c2003-10-01 02:28:12 +0000523 fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_RTS_str)
524 else:
525 fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_RTS_str)
526
cliechti93db61b2006-08-26 19:16:18 +0000527 def setDTR(self, level=1):
cliechtid6bf52c2003-10-01 02:28:12 +0000528 """Set terminal status line: Data Terminal Ready"""
cliechtic6178262004-03-22 22:04:52 +0000529 if self.fd is None: raise portNotOpenError
cliechtib2f5fc82006-10-20 00:09:07 +0000530 if level:
cliechtid6bf52c2003-10-01 02:28:12 +0000531 fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_DTR_str)
532 else:
533 fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_DTR_str)
534
535 def getCTS(self):
536 """Read terminal status line: Clear To Send"""
cliechtic6178262004-03-22 22:04:52 +0000537 if self.fd is None: raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000538 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
539 return struct.unpack('I',s)[0] & TIOCM_CTS != 0
540
541 def getDSR(self):
542 """Read terminal status line: Data Set Ready"""
cliechtic6178262004-03-22 22:04:52 +0000543 if self.fd is None: raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000544 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
545 return struct.unpack('I',s)[0] & TIOCM_DSR != 0
546
cliechtid6bf52c2003-10-01 02:28:12 +0000547 def getRI(self):
548 """Read terminal status line: Ring Indicator"""
cliechtic6178262004-03-22 22:04:52 +0000549 if self.fd is None: raise portNotOpenError
cliechti89b4af12002-02-12 23:24:41 +0000550 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
cliechtid6bf52c2003-10-01 02:28:12 +0000551 return struct.unpack('I',s)[0] & TIOCM_RI != 0
cliechti89b4af12002-02-12 23:24:41 +0000552
553 def getCD(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000554 """Read terminal status line: Carrier Detect"""
cliechtic6178262004-03-22 22:04:52 +0000555 if self.fd is None: raise portNotOpenError
cliechti89b4af12002-02-12 23:24:41 +0000556 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
cliechtid6bf52c2003-10-01 02:28:12 +0000557 return struct.unpack('I',s)[0] & TIOCM_CD != 0
cliechti89b4af12002-02-12 23:24:41 +0000558
cliechtia30a8a02003-10-05 12:28:13 +0000559 # - - platform specific - - - -
560
561 def drainOutput(self):
562 """internal - not portable!"""
cliechtic6178262004-03-22 22:04:52 +0000563 if self.fd is None: raise portNotOpenError
cliechtia30a8a02003-10-05 12:28:13 +0000564 termios.tcdrain(self.fd)
565
566 def nonblocking(self):
567 """internal - not portable!"""
cliechtic6178262004-03-22 22:04:52 +0000568 if self.fd is None:
cliechtia30a8a02003-10-05 12:28:13 +0000569 raise portNotOpenError
570 fcntl.fcntl(self.fd, FCNTL.F_SETFL, FCNTL.O_NONBLOCK)
571
cliechti8753bbc2005-01-15 20:32:51 +0000572 def fileno(self):
cliechtifab09872009-02-07 00:25:44 +0000573 """For easier use of the serial port instance with select.
cliechti8753bbc2005-01-15 20:32:51 +0000574 WARNING: this function is not portable to different platforms!"""
575 if self.fd is None: raise portNotOpenError
576 return self.fd
cliechti89b4af12002-02-12 23:24:41 +0000577
cliechti57e48a62009-08-03 22:29:58 +0000578 def flowControl(self, enable):
579 """manually control flow - when hardware or software flow control is
580 enabled"""
581 if enable:
582 termios.tcflow(self.fd, TERMIOS.TCION)
583 else:
584 termios.tcflow(self.fd, TERMIOS.TCIOFF)
585
cliechtif81362e2009-07-25 03:44:33 +0000586
587# assemble Serial class with the platform specifc implementation and the base
cliechti4a567a02009-07-27 22:09:31 +0000588# for file-like behavior. for Python 2.6 and newer, that provide the new I/O
589# library, derrive from io.RawIOBase
590try:
591 import io
592except ImportError:
593 # classic version with our own file-like emulation
594 class Serial(PosixSerial, FileLike):
595 pass
596else:
597 # io library present
598 class Serial(PosixSerial, io.RawIOBase):
cliechtif81362e2009-07-25 03:44:33 +0000599 pass
600
601
cliechti89b4af12002-02-12 23:24:41 +0000602if __name__ == '__main__':
603 s = Serial(0,
cliechti53c9fd42009-07-23 23:51:51 +0000604 baudrate=19200, # baud rate
605 bytesize=EIGHTBITS, # number of data bits
cliechti3172d3d2009-07-21 22:33:40 +0000606 parity=PARITY_EVEN, # enable parity checking
cliechti53c9fd42009-07-23 23:51:51 +0000607 stopbits=STOPBITS_ONE, # number of stop bits
cliechti3172d3d2009-07-21 22:33:40 +0000608 timeout=3, # set a timeout value, None for waiting forever
609 xonxoff=0, # enable software flow control
610 rtscts=0, # enable RTS/CTS flow control
cliechti89b4af12002-02-12 23:24:41 +0000611 )
612 s.setRTS(1)
613 s.setDTR(1)
614 s.flushInput()
615 s.flushOutput()
616 s.write('hello')
cliechti109486b2009-08-02 00:00:11 +0000617 sys.stdout.write('%r\n' % s.read(5))
618 sys.stdout.write('%s\n' % s.inWaiting())
cliechti89b4af12002-02-12 23:24:41 +0000619 del s
cliechti4569bac2007-11-08 21:57:19 +0000620