blob: 23ee98c2d103cbbfd4af51883654759cf7d3f530 [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#
cliechtia9a093e2010-01-02 03:05:08 +00007# (C) 2001-2010 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:
cliechtia9a093e2010-01-02 03:05:08 +0000200 # 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:
cliechtia9a093e2010-01-02 03:05:08 +0000298 raise SerialException("Can only operate on a valid file descriptor")
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
cliechtia9a093e2010-01-02 03:05:08 +0000434 # select based implementation, proved to work on many systems
435 def read(self, size=1):
436 """Read size bytes from the serial port. If a timeout is set it may
437 return less characters as requested. With no timeout it will block
438 until the requested number of bytes is read."""
439 if self.fd is None: raise portNotOpenError
440 read = bytearray()
441 while len(read) < size:
442 ready,_,_ = select.select([self.fd],[],[], self._timeout)
443 # If select was used with a timeout, and the timeout occurs, it
444 # returns with empty lists -> thus abort read operation.
445 # For timeout == 0 (non-blocking operation) also abort when there
446 # is nothing to read.
447 if not ready:
448 break # timeout
449 buf = os.read(self.fd, size-len(read))
450 # read should always return some data as select reported it was
451 # ready to read when we get to this point.
452 if not buf:
453 # Disconnected devices, at least on Linux, show the
454 # behavior that they are always ready to read immediately
455 # but reading returns nothing.
456 raise SerialException('device reports readiness to read but returned no data (device disconnected?)')
457 read.extend(buf)
458 return bytes(read)
cliechti89b4af12002-02-12 23:24:41 +0000459
cliechti4a567a02009-07-27 22:09:31 +0000460 def write(self, data):
cliechtid6bf52c2003-10-01 02:28:12 +0000461 """Output the given string over the serial port."""
cliechtic6178262004-03-22 22:04:52 +0000462 if self.fd is None: raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000463 t = len(data)
464 d = data
cliechti3cf46d62009-08-07 00:19:57 +0000465 if self._writeTimeout is not None and self._writeTimeout > 0:
466 timeout = time.time() + self._writeTimeout
467 else:
468 timeout = None
cliechtic6178262004-03-22 22:04:52 +0000469 while t > 0:
cliechti5d4d0bd2004-11-13 03:27:39 +0000470 try:
cliechti5d4d0bd2004-11-13 03:27:39 +0000471 n = os.write(self.fd, d)
cliechti3cf46d62009-08-07 00:19:57 +0000472 if timeout:
473 # when timeout is set, use select to wait for being ready
474 # with the time left as timeout
475 timeleft = timeout - time.time()
476 if timeleft < 0:
477 raise writeTimeoutError
478 _, ready, _ = select.select([], [self.fd], [], timeleft)
cliechti5d4d0bd2004-11-13 03:27:39 +0000479 if not ready:
480 raise writeTimeoutError
481 d = d[n:]
482 t = t - n
cliechti4a567a02009-07-27 22:09:31 +0000483 except OSError, v:
cliechti5d4d0bd2004-11-13 03:27:39 +0000484 if v.errno != errno.EAGAIN:
cliechti65722c92009-08-07 00:48:53 +0000485 raise SerialException('write failed: %s' % (v,))
cliechtif81362e2009-07-25 03:44:33 +0000486 return len(data)
cliechtid6bf52c2003-10-01 02:28:12 +0000487
cliechtia30a8a02003-10-05 12:28:13 +0000488 def flush(self):
489 """Flush of file like objects. In this case, wait until all data
490 is written."""
491 self.drainOutput()
492
cliechti89b4af12002-02-12 23:24:41 +0000493 def flushInput(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000494 """Clear input buffer, discarding all that is in the buffer."""
cliechtic6178262004-03-22 22:04:52 +0000495 if self.fd is None:
cliechti89b4af12002-02-12 23:24:41 +0000496 raise portNotOpenError
497 termios.tcflush(self.fd, TERMIOS.TCIFLUSH)
498
499 def flushOutput(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000500 """Clear output buffer, aborting the current output and
501 discarding all that is in the buffer."""
cliechtic6178262004-03-22 22:04:52 +0000502 if self.fd is None:
cliechti89b4af12002-02-12 23:24:41 +0000503 raise portNotOpenError
504 termios.tcflush(self.fd, TERMIOS.TCOFLUSH)
505
cliechtiaaa04602006-02-05 23:02:46 +0000506 def sendBreak(self, duration=0.25):
cliechti997b63c2008-06-21 00:09:31 +0000507 """Send break condition. Timed, returns to idle state after given duration."""
cliechtic6178262004-03-22 22:04:52 +0000508 if self.fd is None:
cliechti89b4af12002-02-12 23:24:41 +0000509 raise portNotOpenError
cliechtiaaa04602006-02-05 23:02:46 +0000510 termios.tcsendbreak(self.fd, int(duration/0.25))
cliechti89b4af12002-02-12 23:24:41 +0000511
cliechti997b63c2008-06-21 00:09:31 +0000512 def setBreak(self, level=1):
cliechtidfec0c82009-07-21 01:35:41 +0000513 """Set break: Controls TXD. When active, no transmitting is possible."""
cliechti997b63c2008-06-21 00:09:31 +0000514 if self.fd is None: raise portNotOpenError
515 if level:
516 fcntl.ioctl(self.fd, TIOCSBRK)
517 else:
518 fcntl.ioctl(self.fd, TIOCCBRK)
519
cliechti93db61b2006-08-26 19:16:18 +0000520 def setRTS(self, level=1):
cliechtid6bf52c2003-10-01 02:28:12 +0000521 """Set terminal status line: Request To Send"""
cliechtic6178262004-03-22 22:04:52 +0000522 if self.fd is None: raise portNotOpenError
cliechtib2f5fc82006-10-20 00:09:07 +0000523 if level:
cliechtid6bf52c2003-10-01 02:28:12 +0000524 fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_RTS_str)
525 else:
526 fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_RTS_str)
527
cliechti93db61b2006-08-26 19:16:18 +0000528 def setDTR(self, level=1):
cliechtid6bf52c2003-10-01 02:28:12 +0000529 """Set terminal status line: Data Terminal Ready"""
cliechtic6178262004-03-22 22:04:52 +0000530 if self.fd is None: raise portNotOpenError
cliechtib2f5fc82006-10-20 00:09:07 +0000531 if level:
cliechtid6bf52c2003-10-01 02:28:12 +0000532 fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_DTR_str)
533 else:
534 fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_DTR_str)
535
536 def getCTS(self):
537 """Read terminal status line: Clear To Send"""
cliechtic6178262004-03-22 22:04:52 +0000538 if self.fd is None: raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000539 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
540 return struct.unpack('I',s)[0] & TIOCM_CTS != 0
541
542 def getDSR(self):
543 """Read terminal status line: Data Set Ready"""
cliechtic6178262004-03-22 22:04:52 +0000544 if self.fd is None: raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000545 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
546 return struct.unpack('I',s)[0] & TIOCM_DSR != 0
547
cliechtid6bf52c2003-10-01 02:28:12 +0000548 def getRI(self):
549 """Read terminal status line: Ring Indicator"""
cliechtic6178262004-03-22 22:04:52 +0000550 if self.fd is None: raise portNotOpenError
cliechti89b4af12002-02-12 23:24:41 +0000551 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
cliechtid6bf52c2003-10-01 02:28:12 +0000552 return struct.unpack('I',s)[0] & TIOCM_RI != 0
cliechti89b4af12002-02-12 23:24:41 +0000553
554 def getCD(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000555 """Read terminal status line: Carrier Detect"""
cliechtic6178262004-03-22 22:04:52 +0000556 if self.fd is None: raise portNotOpenError
cliechti89b4af12002-02-12 23:24:41 +0000557 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
cliechtid6bf52c2003-10-01 02:28:12 +0000558 return struct.unpack('I',s)[0] & TIOCM_CD != 0
cliechti89b4af12002-02-12 23:24:41 +0000559
cliechtia30a8a02003-10-05 12:28:13 +0000560 # - - platform specific - - - -
561
562 def drainOutput(self):
563 """internal - not portable!"""
cliechtic6178262004-03-22 22:04:52 +0000564 if self.fd is None: raise portNotOpenError
cliechtia30a8a02003-10-05 12:28:13 +0000565 termios.tcdrain(self.fd)
566
567 def nonblocking(self):
568 """internal - not portable!"""
cliechtic6178262004-03-22 22:04:52 +0000569 if self.fd is None:
cliechtia30a8a02003-10-05 12:28:13 +0000570 raise portNotOpenError
571 fcntl.fcntl(self.fd, FCNTL.F_SETFL, FCNTL.O_NONBLOCK)
572
cliechti8753bbc2005-01-15 20:32:51 +0000573 def fileno(self):
cliechtifab09872009-02-07 00:25:44 +0000574 """For easier use of the serial port instance with select.
cliechti8753bbc2005-01-15 20:32:51 +0000575 WARNING: this function is not portable to different platforms!"""
576 if self.fd is None: raise portNotOpenError
577 return self.fd
cliechti89b4af12002-02-12 23:24:41 +0000578
cliechti57e48a62009-08-03 22:29:58 +0000579 def flowControl(self, enable):
580 """manually control flow - when hardware or software flow control is
581 enabled"""
582 if enable:
583 termios.tcflow(self.fd, TERMIOS.TCION)
584 else:
585 termios.tcflow(self.fd, TERMIOS.TCIOFF)
586
cliechtif81362e2009-07-25 03:44:33 +0000587
588# assemble Serial class with the platform specifc implementation and the base
cliechti4a567a02009-07-27 22:09:31 +0000589# for file-like behavior. for Python 2.6 and newer, that provide the new I/O
590# library, derrive from io.RawIOBase
591try:
592 import io
593except ImportError:
594 # classic version with our own file-like emulation
595 class Serial(PosixSerial, FileLike):
596 pass
597else:
598 # io library present
599 class Serial(PosixSerial, io.RawIOBase):
cliechtif81362e2009-07-25 03:44:33 +0000600 pass
601
cliechtia9a093e2010-01-02 03:05:08 +0000602class PosixPollSerial(Serial):
603 """poll based read implementation. not all systems support poll properly.
604 however this one has better handling of errors, such as a device
605 disconnecting while it's in use (e.g. USB-serial unplugged)"""
606
607 def read(self, size=1):
608 """Read size bytes from the serial port. If a timeout is set it may
609 return less characters as requested. With no timeout it will block
610 until the requested number of bytes is read."""
611 if self.fd is None: raise portNotOpenError
612 read = bytearray()
613 poll = select.poll()
614 poll.register(self.fd, select.POLLIN|select.POLLERR|select.POLLHUP|select.POLLNVAL)
615 if size > 0:
616 while len(read) < size:
617 # print "\tread(): size",size, "have", len(read) #debug
618 # wait until device becomes ready to read (or something fails)
619 for fd, event in poll.poll(self._timeout):
620 if event & (select.POLLERR|select.POLLHUP|select.POLLNVAL):
621 raise SerialException('device reports error (poll)')
622 # we don't care if it is select.POLLIN or timeout, that's
623 # handled below
624 buf = os.read(self.fd, size - len(read))
625 read.extend(buf)
626 if ((self._timeout is not None and self._timeout >= 0) or
627 (self._interCharTimeout is not None and self._interCharTimeout > 0)) and not buf:
628 break # early abort on timeout
629 return bytes(read)
630
cliechtif81362e2009-07-25 03:44:33 +0000631
cliechti89b4af12002-02-12 23:24:41 +0000632if __name__ == '__main__':
633 s = Serial(0,
cliechti53c9fd42009-07-23 23:51:51 +0000634 baudrate=19200, # baud rate
635 bytesize=EIGHTBITS, # number of data bits
cliechti3172d3d2009-07-21 22:33:40 +0000636 parity=PARITY_EVEN, # enable parity checking
cliechti53c9fd42009-07-23 23:51:51 +0000637 stopbits=STOPBITS_ONE, # number of stop bits
cliechti3172d3d2009-07-21 22:33:40 +0000638 timeout=3, # set a timeout value, None for waiting forever
639 xonxoff=0, # enable software flow control
640 rtscts=0, # enable RTS/CTS flow control
cliechti89b4af12002-02-12 23:24:41 +0000641 )
642 s.setRTS(1)
643 s.setDTR(1)
644 s.flushInput()
645 s.flushOutput()
646 s.write('hello')
cliechti109486b2009-08-02 00:00:11 +0000647 sys.stdout.write('%r\n' % s.read(5))
648 sys.stdout.write('%s\n' % s.inWaiting())
cliechti89b4af12002-02-12 23:24:41 +0000649 del s
cliechti4569bac2007-11-08 21:57:19 +0000650