blob: 1ccfabb46fd4b088be8a9a53fac5ec91e15b8222 [file] [log] [blame]
cliechtid6bf52c2003-10-01 02:28:12 +00001#! python
cliechtic54b2c82008-06-21 01:59:08 +00002# Python Serial Port Extension for Win32, Linux, BSD, Jython
3# see __init__.py
cliechtid6bf52c2003-10-01 02:28:12 +00004#
Chris Liechti68340d72015-08-03 14:15:48 +02005# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
Chris Liechtifbdd8a02015-08-09 02:37:45 +02006#
7# SPDX-License-Identifier: BSD-3-Clause
cliechtid6bf52c2003-10-01 02:28:12 +00008
Chris Liechtief6b7b42015-08-06 22:19:26 +02009import io
cliechtic323f1f2010-07-22 00:14:26 +000010
cliechti38077122013-10-16 02:57:27 +000011# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)``
12# isn't returning the contents (very unfortunate). Therefore we need special
13# cases and test for it. Ensure that there is a ``memoryview`` object for older
14# Python versions. This is easier than making every test dependent on its
15# existence.
16try:
17 memoryview
18except (NameError, AttributeError):
19 # implementation does not matter as we do not realy use it.
20 # it just must not inherit from something else we might care for.
Chris Liechti70b89232015-08-04 03:00:52 +020021 class memoryview(object):
cliechti38077122013-10-16 02:57:27 +000022 pass
23
Chris Liechti4a790ad2015-09-09 17:12:52 +020024try:
25 unicode
26except (NameError, AttributeError):
27 unicode = str # for Python 3
28
cliechti38077122013-10-16 02:57:27 +000029
Chris Liechtif99cd5c2015-08-13 22:54:16 +020030# "for byte in data" fails for python3 as it returns ints instead of bytes
31def iterbytes(b):
32 """Iterate over bytes, returning bytes instead of ints (python3)"""
Chris Liechti12a439f2015-08-20 23:01:53 +020033 if isinstance(b, memoryview):
34 b = b.tobytes()
Chris Liechtif99cd5c2015-08-13 22:54:16 +020035 x = 0
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020036 while True:
Chris Liechti033f17c2015-08-30 21:28:04 +020037 a = b[x:x + 1]
Chris Liechtif99cd5c2015-08-13 22:54:16 +020038 x += 1
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020039 if a:
40 yield a
41 else:
42 break
43
Chris Liechti033f17c2015-08-30 21:28:04 +020044
cliechti38077122013-10-16 02:57:27 +000045# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
46# so a simple ``bytes(sequence)`` doesn't work for all versions
cliechti32c10332009-08-05 13:23:43 +000047def to_bytes(seq):
48 """convert a sequence to a bytes type"""
cliechti38077122013-10-16 02:57:27 +000049 if isinstance(seq, bytes):
50 return seq
51 elif isinstance(seq, bytearray):
52 return bytes(seq)
53 elif isinstance(seq, memoryview):
54 return seq.tobytes()
Chris Liechti4a790ad2015-09-09 17:12:52 +020055 elif isinstance(seq, unicode):
56 raise TypeError('unicode strings are not supported, please encode to bytes: %r' % (seq,))
cliechti38077122013-10-16 02:57:27 +000057 else:
58 b = bytearray()
59 for item in seq:
Chris Liechti07447732015-08-05 00:39:12 +020060 # this one handles int and bytes in Python 2.7
61 # add conversion in case of Python 3.x
62 if isinstance(item, bytes):
63 item = ord(item)
64 b.append(item)
cliechti38077122013-10-16 02:57:27 +000065 return bytes(b)
cliechti32c10332009-08-05 13:23:43 +000066
67# create control bytes
68XON = to_bytes([17])
69XOFF = to_bytes([19])
cliechti4a567a02009-07-27 22:09:31 +000070
cliechti8e99b6f2010-07-21 15:46:39 +000071CR = to_bytes([13])
72LF = to_bytes([10])
73
cliechtia3a811f2009-07-29 21:59:03 +000074
cliechti0d6029a2008-06-21 01:28:46 +000075PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
cliechti58b481c2009-02-16 20:42:32 +000076STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
cliechti14b274a2009-02-07 00:27:05 +000077FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
cliechtid6bf52c2003-10-01 02:28:12 +000078
79PARITY_NAMES = {
Chris Liechti033f17c2015-08-30 21:28:04 +020080 PARITY_NONE: 'None',
81 PARITY_EVEN: 'Even',
82 PARITY_ODD: 'Odd',
83 PARITY_MARK: 'Mark',
cliechti4a567a02009-07-27 22:09:31 +000084 PARITY_SPACE: 'Space',
cliechtid6bf52c2003-10-01 02:28:12 +000085}
86
cliechti1dbe4b62002-02-14 02:49:25 +000087
cliechti4a567a02009-07-27 22:09:31 +000088class SerialException(IOError):
cliechtid6bf52c2003-10-01 02:28:12 +000089 """Base class for serial port related exceptions."""
cliechti7fe54d52002-03-03 20:11:47 +000090
cliechtid6bf52c2003-10-01 02:28:12 +000091
cliechti62611612004-04-20 01:55:43 +000092class SerialTimeoutException(SerialException):
93 """Write timeouts give an exception"""
94
cliechti4a567a02009-07-27 22:09:31 +000095
cliechti4b20ec62012-08-16 01:04:44 +000096writeTimeoutError = SerialTimeoutException('Write timeout')
97portNotOpenError = SerialException('Attempting to use a port that is not open')
cliechti62611612004-04-20 01:55:43 +000098
cliechtif81362e2009-07-25 03:44:33 +000099
Chris Liechtief6b7b42015-08-06 22:19:26 +0200100class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +0000101 """\
102 Serial port base class. Provides __init__ function and properties to
103 get/set port settings.
104 """
cliechti14b274a2009-02-07 00:27:05 +0000105
cliechtidfec0c82009-07-21 01:35:41 +0000106 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +0000107 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
108 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
109 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
110 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +0000111 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
cliechti14b274a2009-02-07 00:27:05 +0000112 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
cliechti6ffdb8f2009-07-22 00:48:57 +0000113 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +0000114
cliechtid6bf52c2003-10-01 02:28:12 +0000115 def __init__(self,
Chris Liechti033f17c2015-08-30 21:28:04 +0200116 port=None, # number of device, numbering starts at
cliechti14b274a2009-02-07 00:27:05 +0000117 # zero. if everything fails, the user
118 # can specify a device string, note
119 # that this isn't portable anymore
120 # port will be opened if one is specified
cliechtidfec0c82009-07-21 01:35:41 +0000121 baudrate=9600, # baud rate
122 bytesize=EIGHTBITS, # number of data bits
cliechti14b274a2009-02-07 00:27:05 +0000123 parity=PARITY_NONE, # enable parity checking
Chris Liechti033f17c2015-08-30 21:28:04 +0200124 stopbits=STOPBITS_ONE, # number of stop bits
cliechti14b274a2009-02-07 00:27:05 +0000125 timeout=None, # set a timeout value, None to wait forever
cliechti74308e42010-07-21 14:03:59 +0000126 xonxoff=False, # enable software flow control
127 rtscts=False, # enable RTS/CTS flow control
Chris Liechti518b0d32015-08-30 02:20:39 +0200128 write_timeout=None, # set a timeout for writes
cliechti58a2aee2010-05-20 23:37:57 +0000129 dsrdtr=False, # None: use rtscts setting, dsrdtr override if True or False
Chris Liechti033f17c2015-08-30 21:28:04 +0200130 inter_byte_timeout=None # Inter-character timeout, None to disable
cliechtid6bf52c2003-10-01 02:28:12 +0000131 ):
cliechti7d448562014-08-03 21:57:45 +0000132 """\
133 Initialize comm port object. If a port is given, then the port will be
134 opened immediately. Otherwise a Serial port object in closed state
135 is returned.
136 """
cliechtid6bf52c2003-10-01 02:28:12 +0000137
Chris Liechti033f17c2015-08-30 21:28:04 +0200138 self.is_open = False
139 self._port = None # correct value is assigned below through properties
140 self._baudrate = None # correct value is assigned below through properties
141 self._bytesize = None # correct value is assigned below through properties
142 self._parity = None # correct value is assigned below through properties
143 self._stopbits = None # correct value is assigned below through properties
144 self._timeout = None # correct value is assigned below through properties
145 self._write_timeout = None # correct value is assigned below through properties
146 self._xonxoff = None # correct value is assigned below through properties
147 self._rtscts = None # correct value is assigned below through properties
148 self._dsrdtr = None # correct value is assigned below through properties
149 self._inter_byte_timeout = None # correct value is assigned below through properties
150 self._rs485_mode = None # disabled by default
Chris Liechtief1fe252015-08-27 23:25:21 +0200151 self._rts_state = True
152 self._dtr_state = True
153 self._break_state = False
cliechti14b274a2009-02-07 00:27:05 +0000154
155 # assign values using get/set methods using the properties feature
Chris Liechti033f17c2015-08-30 21:28:04 +0200156 self.port = port
cliechtid6bf52c2003-10-01 02:28:12 +0000157 self.baudrate = baudrate
158 self.bytesize = bytesize
Chris Liechti033f17c2015-08-30 21:28:04 +0200159 self.parity = parity
cliechtid6bf52c2003-10-01 02:28:12 +0000160 self.stopbits = stopbits
Chris Liechti033f17c2015-08-30 21:28:04 +0200161 self.timeout = timeout
Chris Liechti518b0d32015-08-30 02:20:39 +0200162 self.write_timeout = write_timeout
Chris Liechti033f17c2015-08-30 21:28:04 +0200163 self.xonxoff = xonxoff
164 self.rtscts = rtscts
165 self.dsrdtr = dsrdtr
Chris Liechti518b0d32015-08-30 02:20:39 +0200166 self.inter_character_timeout = inter_byte_timeout
cliechti14b274a2009-02-07 00:27:05 +0000167
cliechtid6bf52c2003-10-01 02:28:12 +0000168 if port is not None:
169 self.open()
170
cliechtid6bf52c2003-10-01 02:28:12 +0000171 # - - - - - - - - - - - - - - - - - - - - - - - -
172
Chris Liechti779b1a22015-08-04 14:54:22 +0200173 @property
174 def port(self):
175 """\
176 Get the current port setting. The value that was passed on init or using
177 setPort() is passed back. See also the attribute portstr which contains
178 the name of the port as a string.
179 """
180 return self._port
181
182 @port.setter
183 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000184 """\
185 Change the port. The attribute portstr is set to a string that
186 contains the name of the port.
187 """
cliechti14b274a2009-02-07 00:27:05 +0000188
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200189 was_open = self.is_open
190 if was_open:
191 self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200192 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000193 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000194 self.name = self.portstr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200195 if was_open:
196 self.open()
cliechti14b274a2009-02-07 00:27:05 +0000197
cliechtid6bf52c2003-10-01 02:28:12 +0000198
Chris Liechti779b1a22015-08-04 14:54:22 +0200199 @property
200 def baudrate(self):
201 """Get the current baud rate setting."""
202 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000203
Chris Liechti779b1a22015-08-04 14:54:22 +0200204 @baudrate.setter
205 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000206 """\
207 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000208 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000209 accepted and the exception is raised when the port is opened.
210 """
cliechti107db8d2004-01-15 01:20:23 +0000211 try:
cliechtie30868d2013-10-16 15:35:11 +0000212 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000213 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000214 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
cliechti107db8d2004-01-15 01:20:23 +0000215 else:
cliechtie30868d2013-10-16 15:35:11 +0000216 if b <= 0:
217 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
218 self._baudrate = b
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200219 if self.is_open:
220 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000221
cliechti14b274a2009-02-07 00:27:05 +0000222
Chris Liechti779b1a22015-08-04 14:54:22 +0200223 @property
224 def bytesize(self):
225 """Get the current byte size setting."""
226 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000227
Chris Liechti779b1a22015-08-04 14:54:22 +0200228 @bytesize.setter
229 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000230 """Change byte size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200231 if bytesize not in self.BYTESIZES:
232 raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000233 self._bytesize = bytesize
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200234 if self.is_open:
235 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000236
cliechtid6bf52c2003-10-01 02:28:12 +0000237
238
Chris Liechti779b1a22015-08-04 14:54:22 +0200239 @property
240 def parity(self):
241 """Get the current parity setting."""
242 return self._parity
243
244 @parity.setter
245 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000246 """Change parity setting."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200247 if parity not in self.PARITIES:
248 raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000249 self._parity = parity
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200250 if self.is_open:
251 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000252
cliechtid6bf52c2003-10-01 02:28:12 +0000253
254
Chris Liechti779b1a22015-08-04 14:54:22 +0200255 @property
256 def stopbits(self):
257 """Get the current stop bits setting."""
258 return self._stopbits
259
260 @stopbits.setter
261 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000262 """Change stop bits size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200263 if stopbits not in self.STOPBITS:
264 raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000265 self._stopbits = stopbits
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200266 if self.is_open:
267 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000268
cliechti14b274a2009-02-07 00:27:05 +0000269
Chris Liechti779b1a22015-08-04 14:54:22 +0200270 @property
271 def timeout(self):
272 """Get the current timeout setting."""
273 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000274
Chris Liechti779b1a22015-08-04 14:54:22 +0200275 @timeout.setter
276 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000277 """Change timeout setting."""
278 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000279 try:
cliechti14b274a2009-02-07 00:27:05 +0000280 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000281 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000282 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti2750b832009-07-28 00:13:52 +0000283 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000284 self._timeout = timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200285 if self.is_open:
286 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000287
Chris Liechti779b1a22015-08-04 14:54:22 +0200288
289 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200290 def write_timeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000291 """Get the current timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200292 return self._write_timeout
cliechti14b274a2009-02-07 00:27:05 +0000293
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200294 @write_timeout.setter
295 def write_timeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000296 """Change timeout setting."""
297 if timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200298 if timeout < 0:
299 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000300 try:
Chris Liechti033f17c2015-08-30 21:28:04 +0200301 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti62611612004-04-20 01:55:43 +0000302 except TypeError:
303 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000304
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200305 self._write_timeout = timeout
306 if self.is_open:
307 self._reconfigure_port()
308
309
310 @property
Chris Liechti518b0d32015-08-30 02:20:39 +0200311 def inter_byte_timeout(self):
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200312 """Get the current inter-character timeout setting."""
Chris Liechti96242372015-09-02 02:49:49 +0200313 return self._inter_byte_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200314
Chris Liechti518b0d32015-08-30 02:20:39 +0200315 @inter_byte_timeout.setter
316 def inter_byte_timeout(self, ic_timeout):
317 """Change inter-byte timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200318 if ic_timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200319 if ic_timeout < 0:
320 raise ValueError("Not a valid timeout: %r" % ic_timeout)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200321 try:
322 ic_timeout + 1 # test if it's a number, will throw a TypeError if not...
323 except TypeError:
324 raise ValueError("Not a valid timeout: %r" % ic_timeout)
325
Chris Liechti518b0d32015-08-30 02:20:39 +0200326 self._inter_byte_timeout = ic_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200327 if self.is_open:
328 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000329
cliechti14b274a2009-02-07 00:27:05 +0000330
Chris Liechti779b1a22015-08-04 14:54:22 +0200331 @property
332 def xonxoff(self):
333 """Get the current XON/XOFF setting."""
334 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000335
Chris Liechti779b1a22015-08-04 14:54:22 +0200336 @xonxoff.setter
337 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000338 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000339 self._xonxoff = xonxoff
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200340 if self.is_open:
341 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000342
cliechti14b274a2009-02-07 00:27:05 +0000343
Chris Liechti779b1a22015-08-04 14:54:22 +0200344 @property
345 def rtscts(self):
346 """Get the current RTS/CTS flow control setting."""
347 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000348
Chris Liechti779b1a22015-08-04 14:54:22 +0200349 @rtscts.setter
350 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000351 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000352 self._rtscts = rtscts
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200353 if self.is_open:
354 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000355
cliechti14b274a2009-02-07 00:27:05 +0000356
Chris Liechti779b1a22015-08-04 14:54:22 +0200357 @property
358 def dsrdtr(self):
359 """Get the current DSR/DTR flow control setting."""
360 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000361
Chris Liechti779b1a22015-08-04 14:54:22 +0200362 @dsrdtr.setter
363 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000364 """Change DsrDtr flow control setting."""
365 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000366 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000367 self._dsrdtr = self._rtscts
368 else:
cliechti14b274a2009-02-07 00:27:05 +0000369 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000370 self._dsrdtr = dsrdtr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200371 if self.is_open:
372 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000373
cliechti14b274a2009-02-07 00:27:05 +0000374
Chris Liechti779b1a22015-08-04 14:54:22 +0200375 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200376 def rts(self):
377 return self._rts_state
cliechti679bfa62008-06-20 23:58:15 +0000378
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200379 @rts.setter
380 def rts(self, value):
381 self._rts_state = value
382 if self.is_open:
383 self._update_rts_state()
cliechti14b274a2009-02-07 00:27:05 +0000384
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200385 @property
386 def dtr(self):
387 return self._dtr_state
cliechti14b274a2009-02-07 00:27:05 +0000388
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200389 @dtr.setter
390 def dtr(self, value):
391 self._dtr_state = value
392 if self.is_open:
393 self._update_dtr_state()
394
395 @property
396 def break_condition(self):
397 return self._break_state
398
399 @break_condition.setter
400 def break_condition(self, value):
401 self._break_state = value
402 if self.is_open:
403 self._update_break_state()
cliechti679bfa62008-06-20 23:58:15 +0000404
cliechti4065dce2009-08-10 00:55:46 +0000405 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200406 # functions useful for RS-485 adapters
407
408 @property
409 def rs485_mode(self):
410 """\
411 Enable RS485 mode and apply new settings, set to None to disable.
412 See serial.rs485.RS485Settings for more info about the value.
413 """
414 return self._rs485_mode
415
416 @rs485_mode.setter
417 def rs485_mode(self, rs485_settings):
418 self._rs485_mode = rs485_settings
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200419 if self.is_open:
420 self._reconfigure_port()
Chris Liechti33f0ec52015-08-06 16:37:21 +0200421
422 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000423
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200424 _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
Chris Liechti033f17c2015-08-30 21:28:04 +0200425 'dsrdtr', 'rtscts', 'timeout', 'write_timeout',
Chris Liechti1c3249f2015-09-01 02:31:36 +0200426 'inter_byte_timeout')
cliechti4065dce2009-08-10 00:55:46 +0000427
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200428 def get_settings(self):
cliechti7d448562014-08-03 21:57:45 +0000429 """\
430 Get current port settings as a dictionary. For use with
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200431 apply_settings().
cliechti7d448562014-08-03 21:57:45 +0000432 """
Chris Liechti033f17c2015-08-30 21:28:04 +0200433 return dict([(key, getattr(self, '_' + key)) for key in self._SAVED_SETTINGS])
cliechti4065dce2009-08-10 00:55:46 +0000434
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200435 def apply_settings(self, d):
cliechti7d448562014-08-03 21:57:45 +0000436 """\
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200437 Apply stored settings from a dictionary returned from
438 get_settings(). It's allowed to delete keys from the dictionary. These
cliechti7d448562014-08-03 21:57:45 +0000439 values will simply left unchanged.
440 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200441 for key in self._SAVED_SETTINGS:
Chris Liechti033f17c2015-08-30 21:28:04 +0200442 if key in d and d[key] != getattr(self, '_' + key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000443 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000444
cliechtid6bf52c2003-10-01 02:28:12 +0000445 # - - - - - - - - - - - - - - - - - - - - - - - -
446
447 def __repr__(self):
448 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000449 return "%s<id=0x%x, open=%s>(port=%r, baudrate=%r, bytesize=%r, parity=%r, stopbits=%r, timeout=%r, xonxoff=%r, rtscts=%r, dsrdtr=%r)" % (
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200450 self.__class__.__name__,
451 id(self),
452 self.is_open,
453 self.portstr,
454 self.baudrate,
455 self.bytesize,
456 self.parity,
457 self.stopbits,
458 self.timeout,
459 self.xonxoff,
460 self.rtscts,
461 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000462 )
463
cliechti4a567a02009-07-27 22:09:31 +0000464
465 # - - - - - - - - - - - - - - - - - - - - - - - -
466 # compatibility with io library
467
Chris Liechti033f17c2015-08-30 21:28:04 +0200468 def readable(self):
469 return True
470
471 def writable(self):
472 return True
473
474 def seekable(self):
475 return False
476
cliechti4a567a02009-07-27 22:09:31 +0000477 def readinto(self, b):
478 data = self.read(len(b))
479 n = len(data)
480 try:
481 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200482 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000483 import array
484 if not isinstance(b, array.array):
485 raise err
486 b[:n] = array.array('b', data)
487 return n
cliechtif81362e2009-07-25 03:44:33 +0000488
Chris Liechti70b89232015-08-04 03:00:52 +0200489 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200490 # context manager
491
492 def __enter__(self):
493 return self
494
495 def __exit__(self, *args, **kwargs):
496 self.close()
497
498 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechtief1fe252015-08-27 23:25:21 +0200499
500 def send_break(self, duration=0.25):
501 """\
502 Send break condition. Timed, returns to idle state after given
503 duration.
504 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200505 if not self.is_open:
506 raise portNotOpenError
Chris Liechtief1fe252015-08-27 23:25:21 +0200507 self.break_condition = True
508 time.sleep(duration)
509 self.break_condition = False
510
511 # - - - - - - - - - - - - - - - - - - - - - - - -
512 # backwards compatibility / deprecated functions
513
514 def flushInput(self):
515 self.reset_input_buffer()
516
517 def flushOutput(self):
518 self.reset_output_buffer()
519
520 def inWaiting(self):
521 return self.in_waiting
522
523 def sendBreak(self, duration=0.25):
524 self.send_break(duration)
525
526 def setRTS(self, value=1):
527 self.rts = value
528
529 def setDTR(self, value=1):
530 self.dtr = value
531
532 def getCTS(self):
533 return self.cts
534
535 def getDSR(self):
536 return self.dsr
537
538 def getRI(self):
539 return self.ri
540
541 def getCD(self):
542 return self.cd
543
544 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200545 def writeTimeout(self):
546 return self.write_timeout
547
548 @writeTimeout.setter
549 def writeTimeout(self, timeout):
550 self.write_timeout = timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200551
552 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200553 def interCharTimeout(self):
Chris Liechti96242372015-09-02 02:49:49 +0200554 return self.inter_byte_timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200555
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200556 @interCharTimeout.setter
557 def interCharTimeout(self, interCharTimeout):
Chris Liechti96242372015-09-02 02:49:49 +0200558 self.inter_byte_timeout = interCharTimeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200559
560 def getSettingsDict(self):
561 return self.get_settings()
562
563 def applySettingsDict(self, d):
564 self.apply_settings(d)
565
566 def isOpen(self):
567 return self._is_open
Chris Liechtief1fe252015-08-27 23:25:21 +0200568
569 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200570 # additional functionality
571
572 def read_until(self, terminator=LF, size=None):
573 """\
574 Read until a termination sequence is found ('\n' by default), the size
575 is exceeded or until timeout occurs.
576 """
577 lenterm = len(terminator)
578 line = bytearray()
579 while True:
580 c = self.read(1)
581 if c:
582 line += c
583 if line[-lenterm:] == terminator:
584 break
585 if size is not None and len(line) >= size:
586 break
587 else:
588 break
589 return bytes(line)
590
Chris Liechti70b89232015-08-04 03:00:52 +0200591 def iread_until(self, *args, **kwargs):
592 """\
593 Read lines, implemented as generator. It will raise StopIteration on
594 timeout (empty read).
595 """
596 while True:
597 line = self.read_until(*args, **kwargs)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200598 if not line:
599 break
Chris Liechti70b89232015-08-04 03:00:52 +0200600 yield line
cliechtif81362e2009-07-25 03:44:33 +0000601
Chris Liechti779b1a22015-08-04 14:54:22 +0200602
603# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000604if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000605 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000606 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200607 sys.stdout.write('port name: %s\n' % s.name)
608 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
609 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
610 sys.stdout.write('parities: %s\n' % s.PARITIES)
611 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000612 sys.stdout.write('%s\n' % s)