blob: 3474d9300b4b7dbe2eb2ce7b2676d94bf4fad215 [file] [log] [blame]
cliechtid6bf52c2003-10-01 02:28:12 +00001#! python
cliechtid6bf52c2003-10-01 02:28:12 +00002#
Chris Liechti3e02f702015-12-16 23:06:04 +01003# Base class and support functions used by various backends.
4#
5# This file is part of pySerial. https://github.com/pyserial/pyserial
Chris Liechti68340d72015-08-03 14:15:48 +02006# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
Chris Liechtifbdd8a02015-08-09 02:37:45 +02007#
8# SPDX-License-Identifier: BSD-3-Clause
cliechtid6bf52c2003-10-01 02:28:12 +00009
Chris Liechtief6b7b42015-08-06 22:19:26 +020010import io
Chris Liechticf29a352015-10-23 22:03:40 +020011import time
cliechtic323f1f2010-07-22 00:14:26 +000012
cliechti38077122013-10-16 02:57:27 +000013# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)``
14# isn't returning the contents (very unfortunate). Therefore we need special
15# cases and test for it. Ensure that there is a ``memoryview`` object for older
16# Python versions. This is easier than making every test dependent on its
17# existence.
18try:
19 memoryview
20except (NameError, AttributeError):
21 # implementation does not matter as we do not realy use it.
22 # it just must not inherit from something else we might care for.
Chris Liechti409e10b2016-02-10 22:40:34 +010023 class memoryview(object): # pylint: disable=redefined-builtin,invalid-name
cliechti38077122013-10-16 02:57:27 +000024 pass
25
Chris Liechti4a790ad2015-09-09 17:12:52 +020026try:
27 unicode
28except (NameError, AttributeError):
Chris Liechti409e10b2016-02-10 22:40:34 +010029 unicode = str # for Python 3, pylint: disable=redefined-builtin,invalid-name
Chris Liechti4a790ad2015-09-09 17:12:52 +020030
cliechti38077122013-10-16 02:57:27 +000031
Chris Liechtif99cd5c2015-08-13 22:54:16 +020032# "for byte in data" fails for python3 as it returns ints instead of bytes
33def iterbytes(b):
34 """Iterate over bytes, returning bytes instead of ints (python3)"""
Chris Liechti12a439f2015-08-20 23:01:53 +020035 if isinstance(b, memoryview):
36 b = b.tobytes()
Chris Liechti9eaa40c2016-02-12 23:32:59 +010037 i = 0
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020038 while True:
Chris Liechti9eaa40c2016-02-12 23:32:59 +010039 a = b[i:i + 1]
40 i += 1
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020041 if a:
42 yield a
43 else:
44 break
45
Chris Liechti033f17c2015-08-30 21:28:04 +020046
cliechti38077122013-10-16 02:57:27 +000047# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
48# so a simple ``bytes(sequence)`` doesn't work for all versions
cliechti32c10332009-08-05 13:23:43 +000049def to_bytes(seq):
50 """convert a sequence to a bytes type"""
cliechti38077122013-10-16 02:57:27 +000051 if isinstance(seq, bytes):
52 return seq
53 elif isinstance(seq, bytearray):
54 return bytes(seq)
55 elif isinstance(seq, memoryview):
56 return seq.tobytes()
Chris Liechti4a790ad2015-09-09 17:12:52 +020057 elif isinstance(seq, unicode):
58 raise TypeError('unicode strings are not supported, please encode to bytes: %r' % (seq,))
cliechti38077122013-10-16 02:57:27 +000059 else:
60 b = bytearray()
61 for item in seq:
Chris Liechti07447732015-08-05 00:39:12 +020062 # this one handles int and bytes in Python 2.7
63 # add conversion in case of Python 3.x
64 if isinstance(item, bytes):
65 item = ord(item)
66 b.append(item)
cliechti38077122013-10-16 02:57:27 +000067 return bytes(b)
cliechti32c10332009-08-05 13:23:43 +000068
69# create control bytes
Chris Liechticf29a352015-10-23 22:03:40 +020070XON = to_bytes([17])
cliechti32c10332009-08-05 13:23:43 +000071XOFF = to_bytes([19])
cliechti4a567a02009-07-27 22:09:31 +000072
cliechti8e99b6f2010-07-21 15:46:39 +000073CR = to_bytes([13])
74LF = to_bytes([10])
75
cliechtia3a811f2009-07-29 21:59:03 +000076
cliechti0d6029a2008-06-21 01:28:46 +000077PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
cliechti58b481c2009-02-16 20:42:32 +000078STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
cliechti14b274a2009-02-07 00:27:05 +000079FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
cliechtid6bf52c2003-10-01 02:28:12 +000080
81PARITY_NAMES = {
Chris Liechti033f17c2015-08-30 21:28:04 +020082 PARITY_NONE: 'None',
83 PARITY_EVEN: 'Even',
84 PARITY_ODD: 'Odd',
85 PARITY_MARK: 'Mark',
cliechti4a567a02009-07-27 22:09:31 +000086 PARITY_SPACE: 'Space',
cliechtid6bf52c2003-10-01 02:28:12 +000087}
88
cliechti1dbe4b62002-02-14 02:49:25 +000089
cliechti4a567a02009-07-27 22:09:31 +000090class SerialException(IOError):
cliechtid6bf52c2003-10-01 02:28:12 +000091 """Base class for serial port related exceptions."""
cliechti7fe54d52002-03-03 20:11:47 +000092
cliechtid6bf52c2003-10-01 02:28:12 +000093
cliechti62611612004-04-20 01:55:43 +000094class SerialTimeoutException(SerialException):
95 """Write timeouts give an exception"""
96
cliechti4a567a02009-07-27 22:09:31 +000097
cliechti4b20ec62012-08-16 01:04:44 +000098writeTimeoutError = SerialTimeoutException('Write timeout')
99portNotOpenError = SerialException('Attempting to use a port that is not open')
cliechti62611612004-04-20 01:55:43 +0000100
cliechtif81362e2009-07-25 03:44:33 +0000101
Chris Liechtief6b7b42015-08-06 22:19:26 +0200102class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +0000103 """\
104 Serial port base class. Provides __init__ function and properties to
105 get/set port settings.
106 """
cliechti14b274a2009-02-07 00:27:05 +0000107
cliechtidfec0c82009-07-21 01:35:41 +0000108 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +0000109 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
110 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
111 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
112 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +0000113 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
Chris Liechticf29a352015-10-23 22:03:40 +0200114 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
115 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +0000116
cliechtid6bf52c2003-10-01 02:28:12 +0000117 def __init__(self,
Chris Liechtid6bcaaf2016-02-01 22:55:26 +0100118 port=None,
119 baudrate=9600,
120 bytesize=EIGHTBITS,
121 parity=PARITY_NONE,
122 stopbits=STOPBITS_ONE,
123 timeout=None,
124 xonxoff=False,
125 rtscts=False,
126 write_timeout=None,
127 dsrdtr=False,
128 inter_byte_timeout=None,
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100129 **kwargs):
cliechti7d448562014-08-03 21:57:45 +0000130 """\
Chris Liechtid6bcaaf2016-02-01 22:55:26 +0100131 Initialize comm port object. If a "port" is given, then the port will be
cliechti7d448562014-08-03 21:57:45 +0000132 opened immediately. Otherwise a Serial port object in closed state
133 is returned.
134 """
cliechtid6bf52c2003-10-01 02:28:12 +0000135
Chris Liechti033f17c2015-08-30 21:28:04 +0200136 self.is_open = False
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100137 self.portstr = None
138 self.name = None
Chris Liechtic14bba82016-01-02 23:23:11 +0100139 # correct values are assigned below through properties
140 self._port = None
141 self._baudrate = None
142 self._bytesize = None
143 self._parity = None
144 self._stopbits = None
145 self._timeout = None
146 self._write_timeout = None
147 self._xonxoff = None
148 self._rtscts = None
149 self._dsrdtr = None
150 self._inter_byte_timeout = None
Chris Liechti033f17c2015-08-30 21:28:04 +0200151 self._rs485_mode = None # disabled by default
Chris Liechti4cf65392016-01-21 23:57:02 +0100152 self._rts_state = None
153 self._dtr_state = None
Chris Liechtief1fe252015-08-27 23:25:21 +0200154 self._break_state = False
cliechti14b274a2009-02-07 00:27:05 +0000155
156 # assign values using get/set methods using the properties feature
Chris Liechti033f17c2015-08-30 21:28:04 +0200157 self.port = port
cliechtid6bf52c2003-10-01 02:28:12 +0000158 self.baudrate = baudrate
159 self.bytesize = bytesize
Chris Liechti033f17c2015-08-30 21:28:04 +0200160 self.parity = parity
cliechtid6bf52c2003-10-01 02:28:12 +0000161 self.stopbits = stopbits
Chris Liechti033f17c2015-08-30 21:28:04 +0200162 self.timeout = timeout
Chris Liechti518b0d32015-08-30 02:20:39 +0200163 self.write_timeout = write_timeout
Chris Liechti033f17c2015-08-30 21:28:04 +0200164 self.xonxoff = xonxoff
165 self.rtscts = rtscts
166 self.dsrdtr = dsrdtr
Chris Liechtib5331752015-10-24 01:34:11 +0200167 self.inter_byte_timeout = inter_byte_timeout
Chris Liechtic14bba82016-01-02 23:23:11 +0100168 # watch for backward compatible kwargs
169 if 'writeTimeout' in kwargs:
170 self.write_timeout = kwargs.pop('writeTimeout')
171 if 'interCharTimeout' in kwargs:
172 self.inter_byte_timeout = kwargs.pop('interCharTimeout')
173 if kwargs:
174 raise ValueError('unexpected keyword arguments: %r' % (kwargs,))
cliechti14b274a2009-02-07 00:27:05 +0000175
cliechtid6bf52c2003-10-01 02:28:12 +0000176 if port is not None:
177 self.open()
178
cliechtid6bf52c2003-10-01 02:28:12 +0000179 # - - - - - - - - - - - - - - - - - - - - - - - -
180
Chris Liechtia51b0bc2015-12-10 21:14:45 +0100181 # to be implemented by subclasses:
182 # def open(self):
183 # def close(self):
Chris Liechti5e763ca2015-12-09 13:01:26 +0100184
185 # - - - - - - - - - - - - - - - - - - - - - - - -
186
Chris Liechti779b1a22015-08-04 14:54:22 +0200187 @property
188 def port(self):
189 """\
190 Get the current port setting. The value that was passed on init or using
191 setPort() is passed back. See also the attribute portstr which contains
192 the name of the port as a string.
193 """
194 return self._port
195
196 @port.setter
197 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000198 """\
199 Change the port. The attribute portstr is set to a string that
200 contains the name of the port.
201 """
cliechti14b274a2009-02-07 00:27:05 +0000202
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200203 was_open = self.is_open
204 if was_open:
205 self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200206 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000207 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000208 self.name = self.portstr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200209 if was_open:
210 self.open()
cliechti14b274a2009-02-07 00:27:05 +0000211
Chris Liechti779b1a22015-08-04 14:54:22 +0200212 @property
213 def baudrate(self):
214 """Get the current baud rate setting."""
215 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000216
Chris Liechti779b1a22015-08-04 14:54:22 +0200217 @baudrate.setter
218 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000219 """\
220 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000221 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000222 accepted and the exception is raised when the port is opened.
223 """
cliechti107db8d2004-01-15 01:20:23 +0000224 try:
cliechtie30868d2013-10-16 15:35:11 +0000225 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000226 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000227 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
cliechti107db8d2004-01-15 01:20:23 +0000228 else:
cliechtie30868d2013-10-16 15:35:11 +0000229 if b <= 0:
230 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
231 self._baudrate = b
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200232 if self.is_open:
233 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000234
Chris Liechti779b1a22015-08-04 14:54:22 +0200235 @property
236 def bytesize(self):
237 """Get the current byte size setting."""
238 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000239
Chris Liechti779b1a22015-08-04 14:54:22 +0200240 @bytesize.setter
241 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000242 """Change byte size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200243 if bytesize not in self.BYTESIZES:
244 raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000245 self._bytesize = bytesize
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200246 if self.is_open:
247 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000248
Chris Liechti779b1a22015-08-04 14:54:22 +0200249 @property
250 def parity(self):
251 """Get the current parity setting."""
252 return self._parity
253
254 @parity.setter
255 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000256 """Change parity setting."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200257 if parity not in self.PARITIES:
258 raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000259 self._parity = parity
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200260 if self.is_open:
261 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000262
Chris Liechti779b1a22015-08-04 14:54:22 +0200263 @property
264 def stopbits(self):
265 """Get the current stop bits setting."""
266 return self._stopbits
267
268 @stopbits.setter
269 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000270 """Change stop bits size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200271 if stopbits not in self.STOPBITS:
272 raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000273 self._stopbits = stopbits
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200274 if self.is_open:
275 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000276
Chris Liechti779b1a22015-08-04 14:54:22 +0200277 @property
278 def timeout(self):
279 """Get the current timeout setting."""
280 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000281
Chris Liechti779b1a22015-08-04 14:54:22 +0200282 @timeout.setter
283 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000284 """Change timeout setting."""
285 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000286 try:
cliechti14b274a2009-02-07 00:27:05 +0000287 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000288 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000289 raise ValueError("Not a valid timeout: %r" % (timeout,))
Chris Liechticf29a352015-10-23 22:03:40 +0200290 if timeout < 0:
291 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000292 self._timeout = timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200293 if self.is_open:
294 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000295
Chris Liechti779b1a22015-08-04 14:54:22 +0200296 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200297 def write_timeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000298 """Get the current timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200299 return self._write_timeout
cliechti14b274a2009-02-07 00:27:05 +0000300
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200301 @write_timeout.setter
302 def write_timeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000303 """Change timeout setting."""
304 if timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200305 if timeout < 0:
306 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000307 try:
Chris Liechti033f17c2015-08-30 21:28:04 +0200308 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti62611612004-04-20 01:55:43 +0000309 except TypeError:
310 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000311
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200312 self._write_timeout = timeout
313 if self.is_open:
314 self._reconfigure_port()
315
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200316 @property
Chris Liechti518b0d32015-08-30 02:20:39 +0200317 def inter_byte_timeout(self):
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200318 """Get the current inter-character timeout setting."""
Chris Liechti96242372015-09-02 02:49:49 +0200319 return self._inter_byte_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200320
Chris Liechti518b0d32015-08-30 02:20:39 +0200321 @inter_byte_timeout.setter
322 def inter_byte_timeout(self, ic_timeout):
323 """Change inter-byte timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200324 if ic_timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200325 if ic_timeout < 0:
326 raise ValueError("Not a valid timeout: %r" % ic_timeout)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200327 try:
328 ic_timeout + 1 # test if it's a number, will throw a TypeError if not...
329 except TypeError:
330 raise ValueError("Not a valid timeout: %r" % ic_timeout)
331
Chris Liechti518b0d32015-08-30 02:20:39 +0200332 self._inter_byte_timeout = ic_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200333 if self.is_open:
334 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000335
Chris Liechti779b1a22015-08-04 14:54:22 +0200336 @property
337 def xonxoff(self):
338 """Get the current XON/XOFF setting."""
339 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000340
Chris Liechti779b1a22015-08-04 14:54:22 +0200341 @xonxoff.setter
342 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000343 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000344 self._xonxoff = xonxoff
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200345 if self.is_open:
346 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000347
Chris Liechti779b1a22015-08-04 14:54:22 +0200348 @property
349 def rtscts(self):
350 """Get the current RTS/CTS flow control setting."""
351 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000352
Chris Liechti779b1a22015-08-04 14:54:22 +0200353 @rtscts.setter
354 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000355 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000356 self._rtscts = rtscts
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200357 if self.is_open:
358 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000359
Chris Liechti779b1a22015-08-04 14:54:22 +0200360 @property
361 def dsrdtr(self):
362 """Get the current DSR/DTR flow control setting."""
363 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000364
Chris Liechti779b1a22015-08-04 14:54:22 +0200365 @dsrdtr.setter
366 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000367 """Change DsrDtr flow control setting."""
368 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000369 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000370 self._dsrdtr = self._rtscts
371 else:
cliechti14b274a2009-02-07 00:27:05 +0000372 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000373 self._dsrdtr = dsrdtr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200374 if self.is_open:
375 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000376
Chris Liechti779b1a22015-08-04 14:54:22 +0200377 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200378 def rts(self):
379 return self._rts_state
cliechti679bfa62008-06-20 23:58:15 +0000380
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200381 @rts.setter
382 def rts(self, value):
383 self._rts_state = value
384 if self.is_open:
385 self._update_rts_state()
cliechti14b274a2009-02-07 00:27:05 +0000386
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200387 @property
388 def dtr(self):
389 return self._dtr_state
cliechti14b274a2009-02-07 00:27:05 +0000390
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200391 @dtr.setter
392 def dtr(self, value):
393 self._dtr_state = value
394 if self.is_open:
395 self._update_dtr_state()
396
397 @property
398 def break_condition(self):
399 return self._break_state
400
401 @break_condition.setter
402 def break_condition(self, value):
403 self._break_state = value
404 if self.is_open:
405 self._update_break_state()
cliechti679bfa62008-06-20 23:58:15 +0000406
cliechti4065dce2009-08-10 00:55:46 +0000407 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200408 # functions useful for RS-485 adapters
409
410 @property
411 def rs485_mode(self):
412 """\
413 Enable RS485 mode and apply new settings, set to None to disable.
414 See serial.rs485.RS485Settings for more info about the value.
415 """
416 return self._rs485_mode
417
418 @rs485_mode.setter
419 def rs485_mode(self, rs485_settings):
420 self._rs485_mode = rs485_settings
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200421 if self.is_open:
422 self._reconfigure_port()
Chris Liechti33f0ec52015-08-06 16:37:21 +0200423
424 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000425
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200426 _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
Chris Liechti033f17c2015-08-30 21:28:04 +0200427 'dsrdtr', 'rtscts', 'timeout', 'write_timeout',
Chris Liechti1c3249f2015-09-01 02:31:36 +0200428 'inter_byte_timeout')
cliechti4065dce2009-08-10 00:55:46 +0000429
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200430 def get_settings(self):
cliechti7d448562014-08-03 21:57:45 +0000431 """\
432 Get current port settings as a dictionary. For use with
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200433 apply_settings().
cliechti7d448562014-08-03 21:57:45 +0000434 """
Chris Liechti033f17c2015-08-30 21:28:04 +0200435 return dict([(key, getattr(self, '_' + key)) for key in self._SAVED_SETTINGS])
cliechti4065dce2009-08-10 00:55:46 +0000436
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200437 def apply_settings(self, d):
cliechti7d448562014-08-03 21:57:45 +0000438 """\
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200439 Apply stored settings from a dictionary returned from
440 get_settings(). It's allowed to delete keys from the dictionary. These
cliechti7d448562014-08-03 21:57:45 +0000441 values will simply left unchanged.
442 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200443 for key in self._SAVED_SETTINGS:
Chris Liechti033f17c2015-08-30 21:28:04 +0200444 if key in d and d[key] != getattr(self, '_' + key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000445 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000446
cliechtid6bf52c2003-10-01 02:28:12 +0000447 # - - - - - - - - - - - - - - - - - - - - - - - -
448
449 def __repr__(self):
450 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000451 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 +0200452 self.__class__.__name__,
453 id(self),
454 self.is_open,
455 self.portstr,
456 self.baudrate,
457 self.bytesize,
458 self.parity,
459 self.stopbits,
460 self.timeout,
461 self.xonxoff,
462 self.rtscts,
463 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000464 )
465
cliechti4a567a02009-07-27 22:09:31 +0000466 # - - - - - - - - - - - - - - - - - - - - - - - -
467 # compatibility with io library
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100468 # pylint: disable=invalid-name,missing-docstring
cliechti4a567a02009-07-27 22:09:31 +0000469
Chris Liechti033f17c2015-08-30 21:28:04 +0200470 def readable(self):
471 return True
472
473 def writable(self):
474 return True
475
476 def seekable(self):
477 return False
478
cliechti4a567a02009-07-27 22:09:31 +0000479 def readinto(self, b):
480 data = self.read(len(b))
481 n = len(data)
482 try:
483 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200484 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000485 import array
486 if not isinstance(b, array.array):
487 raise err
488 b[:n] = array.array('b', data)
489 return n
cliechtif81362e2009-07-25 03:44:33 +0000490
Chris Liechti70b89232015-08-04 03:00:52 +0200491 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200492 # context manager
493
494 def __enter__(self):
495 return self
496
497 def __exit__(self, *args, **kwargs):
498 self.close()
499
500 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechtief1fe252015-08-27 23:25:21 +0200501
502 def send_break(self, duration=0.25):
503 """\
504 Send break condition. Timed, returns to idle state after given
505 duration.
506 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200507 if not self.is_open:
508 raise portNotOpenError
Chris Liechtief1fe252015-08-27 23:25:21 +0200509 self.break_condition = True
510 time.sleep(duration)
511 self.break_condition = False
512
513 # - - - - - - - - - - - - - - - - - - - - - - - -
514 # backwards compatibility / deprecated functions
515
516 def flushInput(self):
517 self.reset_input_buffer()
518
519 def flushOutput(self):
520 self.reset_output_buffer()
521
522 def inWaiting(self):
523 return self.in_waiting
524
525 def sendBreak(self, duration=0.25):
526 self.send_break(duration)
527
528 def setRTS(self, value=1):
529 self.rts = value
530
531 def setDTR(self, value=1):
532 self.dtr = value
533
534 def getCTS(self):
535 return self.cts
536
537 def getDSR(self):
538 return self.dsr
539
540 def getRI(self):
541 return self.ri
542
543 def getCD(self):
544 return self.cd
545
546 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200547 def writeTimeout(self):
548 return self.write_timeout
549
550 @writeTimeout.setter
551 def writeTimeout(self, timeout):
552 self.write_timeout = timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200553
554 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200555 def interCharTimeout(self):
Chris Liechti96242372015-09-02 02:49:49 +0200556 return self.inter_byte_timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200557
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200558 @interCharTimeout.setter
559 def interCharTimeout(self, interCharTimeout):
Chris Liechti96242372015-09-02 02:49:49 +0200560 self.inter_byte_timeout = interCharTimeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200561
562 def getSettingsDict(self):
563 return self.get_settings()
564
565 def applySettingsDict(self, d):
566 self.apply_settings(d)
567
568 def isOpen(self):
Chris Liechti16843852015-09-22 23:24:35 +0200569 return self.is_open
Chris Liechtief1fe252015-08-27 23:25:21 +0200570
571 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200572 # additional functionality
573
David Howlett240f8fc2015-10-28 12:32:09 +0000574 def read_all(self):
Chris Liechti03cb8ed2015-10-30 23:37:24 +0100575 """\
576 Read all bytes currently available in the buffer of the OS.
577 """
David Howlett240f8fc2015-10-28 12:32:09 +0000578 return self.read(self.in_waiting)
579
Chris Liechti70b89232015-08-04 03:00:52 +0200580 def read_until(self, terminator=LF, size=None):
581 """\
582 Read until a termination sequence is found ('\n' by default), the size
583 is exceeded or until timeout occurs.
584 """
585 lenterm = len(terminator)
586 line = bytearray()
587 while True:
588 c = self.read(1)
589 if c:
590 line += c
591 if line[-lenterm:] == terminator:
592 break
593 if size is not None and len(line) >= size:
594 break
595 else:
596 break
597 return bytes(line)
598
Chris Liechti70b89232015-08-04 03:00:52 +0200599 def iread_until(self, *args, **kwargs):
600 """\
601 Read lines, implemented as generator. It will raise StopIteration on
602 timeout (empty read).
603 """
604 while True:
605 line = self.read_until(*args, **kwargs)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200606 if not line:
607 break
Chris Liechti70b89232015-08-04 03:00:52 +0200608 yield line
cliechtif81362e2009-07-25 03:44:33 +0000609
Chris Liechti779b1a22015-08-04 14:54:22 +0200610
611# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000612if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000613 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000614 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200615 sys.stdout.write('port name: %s\n' % s.name)
616 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
617 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
618 sys.stdout.write('parities: %s\n' % s.PARITIES)
619 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000620 sys.stdout.write('%s\n' % s)