blob: 2ed278776dfdeb303111594a9b0939fe222e67e3 [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):
Chris Liechtia83408a2016-05-23 22:18:43 +020021 # implementation does not matter as we do not really use it.
cliechti38077122013-10-16 02:57:27 +000022 # 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
Chris Liechtibf9e3182016-04-22 21:31:09 +020031try:
Chris Liechtif41b4592016-05-11 15:11:27 +020032 basestring
Chris Liechtibf9e3182016-04-22 21:31:09 +020033except (NameError, AttributeError):
Chris Liechtif41b4592016-05-11 15:11:27 +020034 basestring = (str,) # for Python 3, pylint: disable=redefined-builtin,invalid-name
Chris Liechtibf9e3182016-04-22 21:31:09 +020035
cliechti38077122013-10-16 02:57:27 +000036
Chris Liechtif99cd5c2015-08-13 22:54:16 +020037# "for byte in data" fails for python3 as it returns ints instead of bytes
38def iterbytes(b):
39 """Iterate over bytes, returning bytes instead of ints (python3)"""
Chris Liechti12a439f2015-08-20 23:01:53 +020040 if isinstance(b, memoryview):
41 b = b.tobytes()
Chris Liechti9eaa40c2016-02-12 23:32:59 +010042 i = 0
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020043 while True:
Chris Liechti9eaa40c2016-02-12 23:32:59 +010044 a = b[i:i + 1]
45 i += 1
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020046 if a:
47 yield a
48 else:
49 break
50
Chris Liechti033f17c2015-08-30 21:28:04 +020051
cliechti38077122013-10-16 02:57:27 +000052# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
53# so a simple ``bytes(sequence)`` doesn't work for all versions
cliechti32c10332009-08-05 13:23:43 +000054def to_bytes(seq):
55 """convert a sequence to a bytes type"""
cliechti38077122013-10-16 02:57:27 +000056 if isinstance(seq, bytes):
57 return seq
58 elif isinstance(seq, bytearray):
59 return bytes(seq)
60 elif isinstance(seq, memoryview):
61 return seq.tobytes()
Chris Liechti4a790ad2015-09-09 17:12:52 +020062 elif isinstance(seq, unicode):
Chris Liechti984c5c52016-02-15 23:48:45 +010063 raise TypeError('unicode strings are not supported, please encode to bytes: {!r}'.format(seq))
cliechti38077122013-10-16 02:57:27 +000064 else:
65 b = bytearray()
66 for item in seq:
Chris Liechti07447732015-08-05 00:39:12 +020067 # this one handles int and bytes in Python 2.7
68 # add conversion in case of Python 3.x
69 if isinstance(item, bytes):
70 item = ord(item)
71 b.append(item)
cliechti38077122013-10-16 02:57:27 +000072 return bytes(b)
cliechti32c10332009-08-05 13:23:43 +000073
74# create control bytes
Chris Liechticf29a352015-10-23 22:03:40 +020075XON = to_bytes([17])
cliechti32c10332009-08-05 13:23:43 +000076XOFF = to_bytes([19])
cliechti4a567a02009-07-27 22:09:31 +000077
cliechti8e99b6f2010-07-21 15:46:39 +000078CR = to_bytes([13])
79LF = to_bytes([10])
80
cliechtia3a811f2009-07-29 21:59:03 +000081
cliechti0d6029a2008-06-21 01:28:46 +000082PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
cliechti58b481c2009-02-16 20:42:32 +000083STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
cliechti14b274a2009-02-07 00:27:05 +000084FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
cliechtid6bf52c2003-10-01 02:28:12 +000085
86PARITY_NAMES = {
Chris Liechti033f17c2015-08-30 21:28:04 +020087 PARITY_NONE: 'None',
88 PARITY_EVEN: 'Even',
89 PARITY_ODD: 'Odd',
90 PARITY_MARK: 'Mark',
cliechti4a567a02009-07-27 22:09:31 +000091 PARITY_SPACE: 'Space',
cliechtid6bf52c2003-10-01 02:28:12 +000092}
93
cliechti1dbe4b62002-02-14 02:49:25 +000094
cliechti4a567a02009-07-27 22:09:31 +000095class SerialException(IOError):
cliechtid6bf52c2003-10-01 02:28:12 +000096 """Base class for serial port related exceptions."""
cliechti7fe54d52002-03-03 20:11:47 +000097
cliechtid6bf52c2003-10-01 02:28:12 +000098
cliechti62611612004-04-20 01:55:43 +000099class SerialTimeoutException(SerialException):
100 """Write timeouts give an exception"""
101
cliechti4a567a02009-07-27 22:09:31 +0000102
cliechti4b20ec62012-08-16 01:04:44 +0000103writeTimeoutError = SerialTimeoutException('Write timeout')
104portNotOpenError = SerialException('Attempting to use a port that is not open')
cliechti62611612004-04-20 01:55:43 +0000105
cliechtif81362e2009-07-25 03:44:33 +0000106
Chris Liechti935a2622016-08-30 23:39:15 +0200107class Timeout(object):
108 """\
109 Timeout implementation with time.time(). This is compatible with all
110 Python versions but has issues if the clock is adjusted while the
111 timeout is running.
112 """
113 def __init__(self, duration):
114 """Initialize a timeout with given duration"""
115 self.is_infinite = (duration is None)
116 self.is_non_blocking = (duration == 0)
117 if duration is not None:
118 self.target_time = time.time() + duration
119 else:
120 self.target_time = None
121
122 def expired(self):
123 """Return a boolean if the timeout has expired"""
124 return self.target_time is not None and time.time() > self.target_time
125
126 def time_left(self):
127 """Return how many seconds are left until the timeout expires"""
128 if self.is_non_blocking:
129 return 0
130 elif self.is_infinite:
131 return None
132 else:
133 return max(0, self.target_time - time.time())
134
Chris Liechtif0197252016-09-01 19:48:03 +0200135 def restart(self, duration):
136 self.target_time = time.time() + duration
137
Chris Liechti935a2622016-08-30 23:39:15 +0200138
Chris Liechtief6b7b42015-08-06 22:19:26 +0200139class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +0000140 """\
141 Serial port base class. Provides __init__ function and properties to
142 get/set port settings.
143 """
cliechti14b274a2009-02-07 00:27:05 +0000144
cliechtidfec0c82009-07-21 01:35:41 +0000145 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +0000146 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
147 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
148 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
149 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +0000150 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
Chris Liechticf29a352015-10-23 22:03:40 +0200151 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
152 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +0000153
cliechtid6bf52c2003-10-01 02:28:12 +0000154 def __init__(self,
Chris Liechtid6bcaaf2016-02-01 22:55:26 +0100155 port=None,
156 baudrate=9600,
157 bytesize=EIGHTBITS,
158 parity=PARITY_NONE,
159 stopbits=STOPBITS_ONE,
160 timeout=None,
161 xonxoff=False,
162 rtscts=False,
163 write_timeout=None,
164 dsrdtr=False,
165 inter_byte_timeout=None,
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100166 **kwargs):
cliechti7d448562014-08-03 21:57:45 +0000167 """\
Chris Liechtid6bcaaf2016-02-01 22:55:26 +0100168 Initialize comm port object. If a "port" is given, then the port will be
cliechti7d448562014-08-03 21:57:45 +0000169 opened immediately. Otherwise a Serial port object in closed state
170 is returned.
171 """
cliechtid6bf52c2003-10-01 02:28:12 +0000172
Chris Liechti033f17c2015-08-30 21:28:04 +0200173 self.is_open = False
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100174 self.portstr = None
175 self.name = None
Chris Liechtic14bba82016-01-02 23:23:11 +0100176 # correct values are assigned below through properties
177 self._port = None
178 self._baudrate = None
179 self._bytesize = None
180 self._parity = None
181 self._stopbits = None
182 self._timeout = None
183 self._write_timeout = None
184 self._xonxoff = None
185 self._rtscts = None
186 self._dsrdtr = None
187 self._inter_byte_timeout = None
Chris Liechti033f17c2015-08-30 21:28:04 +0200188 self._rs485_mode = None # disabled by default
Chris Liechtif7534c82016-05-07 23:35:54 +0200189 self._rts_state = True
190 self._dtr_state = True
Chris Liechtief1fe252015-08-27 23:25:21 +0200191 self._break_state = False
cliechti14b274a2009-02-07 00:27:05 +0000192
193 # assign values using get/set methods using the properties feature
Chris Liechti033f17c2015-08-30 21:28:04 +0200194 self.port = port
cliechtid6bf52c2003-10-01 02:28:12 +0000195 self.baudrate = baudrate
196 self.bytesize = bytesize
Chris Liechti033f17c2015-08-30 21:28:04 +0200197 self.parity = parity
cliechtid6bf52c2003-10-01 02:28:12 +0000198 self.stopbits = stopbits
Chris Liechti033f17c2015-08-30 21:28:04 +0200199 self.timeout = timeout
Chris Liechti518b0d32015-08-30 02:20:39 +0200200 self.write_timeout = write_timeout
Chris Liechti033f17c2015-08-30 21:28:04 +0200201 self.xonxoff = xonxoff
202 self.rtscts = rtscts
203 self.dsrdtr = dsrdtr
Chris Liechtib5331752015-10-24 01:34:11 +0200204 self.inter_byte_timeout = inter_byte_timeout
Chris Liechtic14bba82016-01-02 23:23:11 +0100205 # watch for backward compatible kwargs
206 if 'writeTimeout' in kwargs:
207 self.write_timeout = kwargs.pop('writeTimeout')
208 if 'interCharTimeout' in kwargs:
209 self.inter_byte_timeout = kwargs.pop('interCharTimeout')
210 if kwargs:
Chris Liechti984c5c52016-02-15 23:48:45 +0100211 raise ValueError('unexpected keyword arguments: {!r}'.format(kwargs))
cliechti14b274a2009-02-07 00:27:05 +0000212
cliechtid6bf52c2003-10-01 02:28:12 +0000213 if port is not None:
214 self.open()
215
cliechtid6bf52c2003-10-01 02:28:12 +0000216 # - - - - - - - - - - - - - - - - - - - - - - - -
217
Chris Liechtia51b0bc2015-12-10 21:14:45 +0100218 # to be implemented by subclasses:
219 # def open(self):
220 # def close(self):
Chris Liechti5e763ca2015-12-09 13:01:26 +0100221
222 # - - - - - - - - - - - - - - - - - - - - - - - -
223
Chris Liechti779b1a22015-08-04 14:54:22 +0200224 @property
225 def port(self):
226 """\
227 Get the current port setting. The value that was passed on init or using
Chris Liechtibf9e3182016-04-22 21:31:09 +0200228 setPort() is passed back.
Chris Liechti779b1a22015-08-04 14:54:22 +0200229 """
230 return self._port
231
232 @port.setter
233 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000234 """\
Chris Liechtibf9e3182016-04-22 21:31:09 +0200235 Change the port.
cliechti7d448562014-08-03 21:57:45 +0000236 """
Chris Liechtif41b4592016-05-11 15:11:27 +0200237 if port is not None and not isinstance(port, basestring):
Chris Liechtibf9e3182016-04-22 21:31:09 +0200238 raise ValueError('"port" must be None or a string, not {}'.format(type(port)))
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200239 was_open = self.is_open
240 if was_open:
241 self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200242 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000243 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000244 self.name = self.portstr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200245 if was_open:
246 self.open()
cliechti14b274a2009-02-07 00:27:05 +0000247
Chris Liechti779b1a22015-08-04 14:54:22 +0200248 @property
249 def baudrate(self):
250 """Get the current baud rate setting."""
251 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000252
Chris Liechti779b1a22015-08-04 14:54:22 +0200253 @baudrate.setter
254 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000255 """\
256 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000257 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000258 accepted and the exception is raised when the port is opened.
259 """
cliechti107db8d2004-01-15 01:20:23 +0000260 try:
cliechtie30868d2013-10-16 15:35:11 +0000261 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000262 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100263 raise ValueError("Not a valid baudrate: {!r}".format(baudrate))
cliechti107db8d2004-01-15 01:20:23 +0000264 else:
Chris Liechtia83408a2016-05-23 22:18:43 +0200265 if b < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100266 raise ValueError("Not a valid baudrate: {!r}".format(baudrate))
cliechtie30868d2013-10-16 15:35:11 +0000267 self._baudrate = b
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200268 if self.is_open:
269 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000270
Chris Liechti779b1a22015-08-04 14:54:22 +0200271 @property
272 def bytesize(self):
273 """Get the current byte size setting."""
274 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000275
Chris Liechti779b1a22015-08-04 14:54:22 +0200276 @bytesize.setter
277 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000278 """Change byte size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200279 if bytesize not in self.BYTESIZES:
Chris Liechti984c5c52016-02-15 23:48:45 +0100280 raise ValueError("Not a valid byte size: {!r}".format(bytesize))
cliechtid6bf52c2003-10-01 02:28:12 +0000281 self._bytesize = bytesize
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200282 if self.is_open:
283 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000284
Chris Liechti779b1a22015-08-04 14:54:22 +0200285 @property
286 def parity(self):
287 """Get the current parity setting."""
288 return self._parity
289
290 @parity.setter
291 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000292 """Change parity setting."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200293 if parity not in self.PARITIES:
Chris Liechti984c5c52016-02-15 23:48:45 +0100294 raise ValueError("Not a valid parity: {!r}".format(parity))
cliechtid6bf52c2003-10-01 02:28:12 +0000295 self._parity = parity
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200296 if self.is_open:
297 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000298
Chris Liechti779b1a22015-08-04 14:54:22 +0200299 @property
300 def stopbits(self):
301 """Get the current stop bits setting."""
302 return self._stopbits
303
304 @stopbits.setter
305 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000306 """Change stop bits size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200307 if stopbits not in self.STOPBITS:
Chris Liechti984c5c52016-02-15 23:48:45 +0100308 raise ValueError("Not a valid stop bit size: {!r}".format(stopbits))
cliechtid6bf52c2003-10-01 02:28:12 +0000309 self._stopbits = stopbits
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200310 if self.is_open:
311 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000312
Chris Liechti779b1a22015-08-04 14:54:22 +0200313 @property
314 def timeout(self):
315 """Get the current timeout setting."""
316 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000317
Chris Liechti779b1a22015-08-04 14:54:22 +0200318 @timeout.setter
319 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000320 """Change timeout setting."""
321 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000322 try:
cliechti14b274a2009-02-07 00:27:05 +0000323 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000324 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100325 raise ValueError("Not a valid timeout: {!r}".format(timeout))
Chris Liechticf29a352015-10-23 22:03:40 +0200326 if timeout < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100327 raise ValueError("Not a valid timeout: {!r}".format(timeout))
cliechtid6bf52c2003-10-01 02:28:12 +0000328 self._timeout = timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200329 if self.is_open:
330 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000331
Chris Liechti779b1a22015-08-04 14:54:22 +0200332 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200333 def write_timeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000334 """Get the current timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200335 return self._write_timeout
cliechti14b274a2009-02-07 00:27:05 +0000336
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200337 @write_timeout.setter
338 def write_timeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000339 """Change timeout setting."""
340 if timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200341 if timeout < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100342 raise ValueError("Not a valid timeout: {!r}".format(timeout))
cliechti62611612004-04-20 01:55:43 +0000343 try:
Chris Liechti033f17c2015-08-30 21:28:04 +0200344 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti62611612004-04-20 01:55:43 +0000345 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100346 raise ValueError("Not a valid timeout: {!r}".format(timeout))
cliechti14b274a2009-02-07 00:27:05 +0000347
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200348 self._write_timeout = timeout
349 if self.is_open:
350 self._reconfigure_port()
351
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200352 @property
Chris Liechti518b0d32015-08-30 02:20:39 +0200353 def inter_byte_timeout(self):
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200354 """Get the current inter-character timeout setting."""
Chris Liechti96242372015-09-02 02:49:49 +0200355 return self._inter_byte_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200356
Chris Liechti518b0d32015-08-30 02:20:39 +0200357 @inter_byte_timeout.setter
358 def inter_byte_timeout(self, ic_timeout):
359 """Change inter-byte timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200360 if ic_timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200361 if ic_timeout < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100362 raise ValueError("Not a valid timeout: {!r}".format(ic_timeout))
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200363 try:
364 ic_timeout + 1 # test if it's a number, will throw a TypeError if not...
365 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100366 raise ValueError("Not a valid timeout: {!r}".format(ic_timeout))
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200367
Chris Liechti518b0d32015-08-30 02:20:39 +0200368 self._inter_byte_timeout = ic_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200369 if self.is_open:
370 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000371
Chris Liechti779b1a22015-08-04 14:54:22 +0200372 @property
373 def xonxoff(self):
374 """Get the current XON/XOFF setting."""
375 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000376
Chris Liechti779b1a22015-08-04 14:54:22 +0200377 @xonxoff.setter
378 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000379 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000380 self._xonxoff = xonxoff
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200381 if self.is_open:
382 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000383
Chris Liechti779b1a22015-08-04 14:54:22 +0200384 @property
385 def rtscts(self):
386 """Get the current RTS/CTS flow control setting."""
387 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000388
Chris Liechti779b1a22015-08-04 14:54:22 +0200389 @rtscts.setter
390 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000391 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000392 self._rtscts = rtscts
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200393 if self.is_open:
394 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000395
Chris Liechti779b1a22015-08-04 14:54:22 +0200396 @property
397 def dsrdtr(self):
398 """Get the current DSR/DTR flow control setting."""
399 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000400
Chris Liechti779b1a22015-08-04 14:54:22 +0200401 @dsrdtr.setter
402 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000403 """Change DsrDtr flow control setting."""
404 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000405 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000406 self._dsrdtr = self._rtscts
407 else:
cliechti14b274a2009-02-07 00:27:05 +0000408 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000409 self._dsrdtr = dsrdtr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200410 if self.is_open:
411 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000412
Chris Liechti779b1a22015-08-04 14:54:22 +0200413 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200414 def rts(self):
415 return self._rts_state
cliechti679bfa62008-06-20 23:58:15 +0000416
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200417 @rts.setter
418 def rts(self, value):
419 self._rts_state = value
420 if self.is_open:
421 self._update_rts_state()
cliechti14b274a2009-02-07 00:27:05 +0000422
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200423 @property
424 def dtr(self):
425 return self._dtr_state
cliechti14b274a2009-02-07 00:27:05 +0000426
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200427 @dtr.setter
428 def dtr(self, value):
429 self._dtr_state = value
430 if self.is_open:
431 self._update_dtr_state()
432
433 @property
434 def break_condition(self):
435 return self._break_state
436
437 @break_condition.setter
438 def break_condition(self, value):
439 self._break_state = value
440 if self.is_open:
441 self._update_break_state()
cliechti679bfa62008-06-20 23:58:15 +0000442
cliechti4065dce2009-08-10 00:55:46 +0000443 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200444 # functions useful for RS-485 adapters
445
446 @property
447 def rs485_mode(self):
448 """\
449 Enable RS485 mode and apply new settings, set to None to disable.
450 See serial.rs485.RS485Settings for more info about the value.
451 """
452 return self._rs485_mode
453
454 @rs485_mode.setter
455 def rs485_mode(self, rs485_settings):
456 self._rs485_mode = rs485_settings
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200457 if self.is_open:
458 self._reconfigure_port()
Chris Liechti33f0ec52015-08-06 16:37:21 +0200459
460 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000461
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200462 _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
Chris Liechti033f17c2015-08-30 21:28:04 +0200463 'dsrdtr', 'rtscts', 'timeout', 'write_timeout',
Chris Liechti1c3249f2015-09-01 02:31:36 +0200464 'inter_byte_timeout')
cliechti4065dce2009-08-10 00:55:46 +0000465
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200466 def get_settings(self):
cliechti7d448562014-08-03 21:57:45 +0000467 """\
468 Get current port settings as a dictionary. For use with
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200469 apply_settings().
cliechti7d448562014-08-03 21:57:45 +0000470 """
Chris Liechti033f17c2015-08-30 21:28:04 +0200471 return dict([(key, getattr(self, '_' + key)) for key in self._SAVED_SETTINGS])
cliechti4065dce2009-08-10 00:55:46 +0000472
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200473 def apply_settings(self, d):
cliechti7d448562014-08-03 21:57:45 +0000474 """\
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200475 Apply stored settings from a dictionary returned from
476 get_settings(). It's allowed to delete keys from the dictionary. These
cliechti7d448562014-08-03 21:57:45 +0000477 values will simply left unchanged.
478 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200479 for key in self._SAVED_SETTINGS:
Chris Liechti033f17c2015-08-30 21:28:04 +0200480 if key in d and d[key] != getattr(self, '_' + key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000481 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000482
cliechtid6bf52c2003-10-01 02:28:12 +0000483 # - - - - - - - - - - - - - - - - - - - - - - - -
484
485 def __repr__(self):
486 """String representation of the current port settings and its state."""
Chris Liechti984c5c52016-02-15 23:48:45 +0100487 return '{name}<id=0x{id:x}, open={p.is_open}>(port={p.portstr!r}, ' \
488 'baudrate={p.baudrate!r}, bytesize={p.bytesize!r}, parity={p.parity!r}, ' \
489 'stopbits={p.stopbits!r}, timeout={p.timeout!r}, xonxoff={p.xonxoff!r}, ' \
490 'rtscts={p.rtscts!r}, dsrdtr={p.dsrdtr!r})'.format(
491 name=self.__class__.__name__, id=id(self), p=self)
cliechtid6bf52c2003-10-01 02:28:12 +0000492
cliechti4a567a02009-07-27 22:09:31 +0000493 # - - - - - - - - - - - - - - - - - - - - - - - -
494 # compatibility with io library
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100495 # pylint: disable=invalid-name,missing-docstring
cliechti4a567a02009-07-27 22:09:31 +0000496
Chris Liechti033f17c2015-08-30 21:28:04 +0200497 def readable(self):
498 return True
499
500 def writable(self):
501 return True
502
503 def seekable(self):
504 return False
505
cliechti4a567a02009-07-27 22:09:31 +0000506 def readinto(self, b):
507 data = self.read(len(b))
508 n = len(data)
509 try:
510 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200511 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000512 import array
513 if not isinstance(b, array.array):
514 raise err
515 b[:n] = array.array('b', data)
516 return n
cliechtif81362e2009-07-25 03:44:33 +0000517
Chris Liechti70b89232015-08-04 03:00:52 +0200518 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200519 # context manager
520
521 def __enter__(self):
522 return self
523
524 def __exit__(self, *args, **kwargs):
525 self.close()
526
527 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechtief1fe252015-08-27 23:25:21 +0200528
529 def send_break(self, duration=0.25):
530 """\
531 Send break condition. Timed, returns to idle state after given
532 duration.
533 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200534 if not self.is_open:
535 raise portNotOpenError
Chris Liechtief1fe252015-08-27 23:25:21 +0200536 self.break_condition = True
537 time.sleep(duration)
538 self.break_condition = False
539
540 # - - - - - - - - - - - - - - - - - - - - - - - -
541 # backwards compatibility / deprecated functions
542
543 def flushInput(self):
544 self.reset_input_buffer()
545
546 def flushOutput(self):
547 self.reset_output_buffer()
548
549 def inWaiting(self):
550 return self.in_waiting
551
552 def sendBreak(self, duration=0.25):
553 self.send_break(duration)
554
555 def setRTS(self, value=1):
556 self.rts = value
557
558 def setDTR(self, value=1):
559 self.dtr = value
560
561 def getCTS(self):
562 return self.cts
563
564 def getDSR(self):
565 return self.dsr
566
567 def getRI(self):
568 return self.ri
569
570 def getCD(self):
571 return self.cd
572
Chris Liechti0eba2a62016-04-06 02:55:51 +0200573 def setPort(self, port):
574 self.port = port
575
Chris Liechtief1fe252015-08-27 23:25:21 +0200576 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200577 def writeTimeout(self):
578 return self.write_timeout
579
580 @writeTimeout.setter
581 def writeTimeout(self, timeout):
582 self.write_timeout = timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200583
584 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200585 def interCharTimeout(self):
Chris Liechti96242372015-09-02 02:49:49 +0200586 return self.inter_byte_timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200587
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200588 @interCharTimeout.setter
589 def interCharTimeout(self, interCharTimeout):
Chris Liechti96242372015-09-02 02:49:49 +0200590 self.inter_byte_timeout = interCharTimeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200591
592 def getSettingsDict(self):
593 return self.get_settings()
594
595 def applySettingsDict(self, d):
596 self.apply_settings(d)
597
598 def isOpen(self):
Chris Liechti16843852015-09-22 23:24:35 +0200599 return self.is_open
Chris Liechtief1fe252015-08-27 23:25:21 +0200600
601 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200602 # additional functionality
603
David Howlett240f8fc2015-10-28 12:32:09 +0000604 def read_all(self):
Chris Liechti03cb8ed2015-10-30 23:37:24 +0100605 """\
606 Read all bytes currently available in the buffer of the OS.
607 """
David Howlett240f8fc2015-10-28 12:32:09 +0000608 return self.read(self.in_waiting)
609
Chris Liechti70b89232015-08-04 03:00:52 +0200610 def read_until(self, terminator=LF, size=None):
611 """\
612 Read until a termination sequence is found ('\n' by default), the size
613 is exceeded or until timeout occurs.
614 """
615 lenterm = len(terminator)
616 line = bytearray()
617 while True:
618 c = self.read(1)
619 if c:
620 line += c
621 if line[-lenterm:] == terminator:
622 break
623 if size is not None and len(line) >= size:
624 break
625 else:
626 break
627 return bytes(line)
628
Chris Liechti70b89232015-08-04 03:00:52 +0200629 def iread_until(self, *args, **kwargs):
630 """\
631 Read lines, implemented as generator. It will raise StopIteration on
632 timeout (empty read).
633 """
634 while True:
635 line = self.read_until(*args, **kwargs)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200636 if not line:
637 break
Chris Liechti70b89232015-08-04 03:00:52 +0200638 yield line
cliechtif81362e2009-07-25 03:44:33 +0000639
Chris Liechti779b1a22015-08-04 14:54:22 +0200640
641# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000642if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000643 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000644 s = SerialBase()
Chris Liechti984c5c52016-02-15 23:48:45 +0100645 sys.stdout.write('port name: {}\n'.format(s.name))
646 sys.stdout.write('baud rates: {}\n'.format(s.BAUDRATES))
647 sys.stdout.write('byte sizes: {}\n'.format(s.BYTESIZES))
648 sys.stdout.write('parities: {}\n'.format(s.PARITIES))
649 sys.stdout.write('stop bits: {}\n'.format(s.STOPBITS))
650 sys.stdout.write('{}\n'.format(s))