blob: e847a6a685ca330c7b0043c841b951e5276f9e43 [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 Liechti06ed4a52016-09-03 23:53:12 +02006# (C) 2001-2016 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
Kurt McKee057387c2018-02-07 22:10:38 -060010from __future__ import absolute_import
11
Chris Liechtief6b7b42015-08-06 22:19:26 +020012import io
Chris Liechticf29a352015-10-23 22:03:40 +020013import time
cliechtic323f1f2010-07-22 00:14:26 +000014
cliechti38077122013-10-16 02:57:27 +000015# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)``
16# isn't returning the contents (very unfortunate). Therefore we need special
17# cases and test for it. Ensure that there is a ``memoryview`` object for older
18# Python versions. This is easier than making every test dependent on its
19# existence.
20try:
21 memoryview
22except (NameError, AttributeError):
Chris Liechtia83408a2016-05-23 22:18:43 +020023 # implementation does not matter as we do not really use it.
cliechti38077122013-10-16 02:57:27 +000024 # it just must not inherit from something else we might care for.
Chris Liechti409e10b2016-02-10 22:40:34 +010025 class memoryview(object): # pylint: disable=redefined-builtin,invalid-name
cliechti38077122013-10-16 02:57:27 +000026 pass
27
Chris Liechti4a790ad2015-09-09 17:12:52 +020028try:
29 unicode
30except (NameError, AttributeError):
Chris Liechti409e10b2016-02-10 22:40:34 +010031 unicode = str # for Python 3, pylint: disable=redefined-builtin,invalid-name
Chris Liechti4a790ad2015-09-09 17:12:52 +020032
Chris Liechtibf9e3182016-04-22 21:31:09 +020033try:
Chris Liechtif41b4592016-05-11 15:11:27 +020034 basestring
Chris Liechtibf9e3182016-04-22 21:31:09 +020035except (NameError, AttributeError):
Chris Liechtif41b4592016-05-11 15:11:27 +020036 basestring = (str,) # for Python 3, pylint: disable=redefined-builtin,invalid-name
Chris Liechtibf9e3182016-04-22 21:31:09 +020037
cliechti38077122013-10-16 02:57:27 +000038
Chris Liechtif99cd5c2015-08-13 22:54:16 +020039# "for byte in data" fails for python3 as it returns ints instead of bytes
40def iterbytes(b):
41 """Iterate over bytes, returning bytes instead of ints (python3)"""
Chris Liechti12a439f2015-08-20 23:01:53 +020042 if isinstance(b, memoryview):
43 b = b.tobytes()
Chris Liechti9eaa40c2016-02-12 23:32:59 +010044 i = 0
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020045 while True:
Chris Liechti9eaa40c2016-02-12 23:32:59 +010046 a = b[i:i + 1]
47 i += 1
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020048 if a:
49 yield a
50 else:
51 break
52
Chris Liechti033f17c2015-08-30 21:28:04 +020053
cliechti38077122013-10-16 02:57:27 +000054# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
55# so a simple ``bytes(sequence)`` doesn't work for all versions
cliechti32c10332009-08-05 13:23:43 +000056def to_bytes(seq):
57 """convert a sequence to a bytes type"""
cliechti38077122013-10-16 02:57:27 +000058 if isinstance(seq, bytes):
59 return seq
60 elif isinstance(seq, bytearray):
61 return bytes(seq)
62 elif isinstance(seq, memoryview):
63 return seq.tobytes()
Chris Liechti4a790ad2015-09-09 17:12:52 +020064 elif isinstance(seq, unicode):
Chris Liechti984c5c52016-02-15 23:48:45 +010065 raise TypeError('unicode strings are not supported, please encode to bytes: {!r}'.format(seq))
cliechti38077122013-10-16 02:57:27 +000066 else:
Chris Liechti143ff762016-09-14 18:01:45 +020067 # handle list of integers and bytes (one or more items) for Python 2 and 3
68 return bytes(bytearray(seq))
69
cliechti32c10332009-08-05 13:23:43 +000070
71# create control bytes
Chris Liechticf29a352015-10-23 22:03:40 +020072XON = to_bytes([17])
cliechti32c10332009-08-05 13:23:43 +000073XOFF = to_bytes([19])
cliechti4a567a02009-07-27 22:09:31 +000074
cliechti8e99b6f2010-07-21 15:46:39 +000075CR = to_bytes([13])
76LF = to_bytes([10])
77
cliechtia3a811f2009-07-29 21:59:03 +000078
cliechti0d6029a2008-06-21 01:28:46 +000079PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
cliechti58b481c2009-02-16 20:42:32 +000080STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
cliechti14b274a2009-02-07 00:27:05 +000081FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
cliechtid6bf52c2003-10-01 02:28:12 +000082
83PARITY_NAMES = {
Chris Liechti033f17c2015-08-30 21:28:04 +020084 PARITY_NONE: 'None',
85 PARITY_EVEN: 'Even',
86 PARITY_ODD: 'Odd',
87 PARITY_MARK: 'Mark',
cliechti4a567a02009-07-27 22:09:31 +000088 PARITY_SPACE: 'Space',
cliechtid6bf52c2003-10-01 02:28:12 +000089}
90
cliechti1dbe4b62002-02-14 02:49:25 +000091
cliechti4a567a02009-07-27 22:09:31 +000092class SerialException(IOError):
cliechtid6bf52c2003-10-01 02:28:12 +000093 """Base class for serial port related exceptions."""
cliechti7fe54d52002-03-03 20:11:47 +000094
cliechtid6bf52c2003-10-01 02:28:12 +000095
cliechti62611612004-04-20 01:55:43 +000096class SerialTimeoutException(SerialException):
97 """Write timeouts give an exception"""
98
cliechti4a567a02009-07-27 22:09:31 +000099
cliechti4b20ec62012-08-16 01:04:44 +0000100writeTimeoutError = SerialTimeoutException('Write timeout')
101portNotOpenError = SerialException('Attempting to use a port that is not open')
cliechti62611612004-04-20 01:55:43 +0000102
cliechtif81362e2009-07-25 03:44:33 +0000103
Chris Liechti935a2622016-08-30 23:39:15 +0200104class Timeout(object):
105 """\
Chris Liechti514f76c2016-09-02 22:32:37 +0200106 Abstraction for timeout operations. Using time.monotonic() if available
107 or time.time() in all other cases.
Chris Liechti06ed4a52016-09-03 23:53:12 +0200108
109 The class can also be initialized with 0 or None, in order to support
110 non-blocking and fully blocking I/O operations. The attributes
111 is_non_blocking and is_infinite are set accordingly.
Chris Liechti935a2622016-08-30 23:39:15 +0200112 """
Chris Liechti514f76c2016-09-02 22:32:37 +0200113 if hasattr(time, 'monotonic'):
114 # Timeout implementation with time.monotonic(). This function is only
115 # supported by Python 3.3 and above. It returns a time in seconds
116 # (float) just as time.time(), but is not affected by system clock
117 # adjustments.
118 TIME = time.monotonic
119 else:
120 # Timeout implementation with time.time(). This is compatible with all
121 # Python versions but has issues if the clock is adjusted while the
122 # timeout is running.
123 TIME = time.time
124
Chris Liechti935a2622016-08-30 23:39:15 +0200125 def __init__(self, duration):
126 """Initialize a timeout with given duration"""
127 self.is_infinite = (duration is None)
128 self.is_non_blocking = (duration == 0)
Chris Liechti03513322016-09-04 23:35:53 +0200129 self.duration = duration
Chris Liechti935a2622016-08-30 23:39:15 +0200130 if duration is not None:
Chris Liechti514f76c2016-09-02 22:32:37 +0200131 self.target_time = self.TIME() + duration
Chris Liechti935a2622016-08-30 23:39:15 +0200132 else:
133 self.target_time = None
134
135 def expired(self):
Chris Liechti06ed4a52016-09-03 23:53:12 +0200136 """Return a boolean, telling if the timeout has expired"""
Chris Liechti03513322016-09-04 23:35:53 +0200137 return self.target_time is not None and self.time_left() <= 0
Chris Liechti935a2622016-08-30 23:39:15 +0200138
139 def time_left(self):
140 """Return how many seconds are left until the timeout expires"""
141 if self.is_non_blocking:
142 return 0
143 elif self.is_infinite:
144 return None
145 else:
Chris Liechti03513322016-09-04 23:35:53 +0200146 delta = self.target_time - self.TIME()
147 if delta > self.duration:
148 # clock jumped, recalculate
149 self.target_time = self.TIME() + self.duration
150 return self.duration
151 else:
152 return max(0, delta)
Chris Liechti935a2622016-08-30 23:39:15 +0200153
Chris Liechtif0197252016-09-01 19:48:03 +0200154 def restart(self, duration):
Chris Liechti06ed4a52016-09-03 23:53:12 +0200155 """\
156 Restart a timeout, only supported if a timeout was already set up
157 before.
158 """
Chris Liechti03513322016-09-04 23:35:53 +0200159 self.duration = duration
Chris Liechti514f76c2016-09-02 22:32:37 +0200160 self.target_time = self.TIME() + duration
Chris Liechtif0197252016-09-01 19:48:03 +0200161
Chris Liechti935a2622016-08-30 23:39:15 +0200162
Chris Liechtief6b7b42015-08-06 22:19:26 +0200163class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +0000164 """\
165 Serial port base class. Provides __init__ function and properties to
166 get/set port settings.
167 """
cliechti14b274a2009-02-07 00:27:05 +0000168
cliechtidfec0c82009-07-21 01:35:41 +0000169 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +0000170 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
171 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
172 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
173 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +0000174 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
Chris Liechticf29a352015-10-23 22:03:40 +0200175 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
176 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +0000177
cliechtid6bf52c2003-10-01 02:28:12 +0000178 def __init__(self,
Chris Liechtid6bcaaf2016-02-01 22:55:26 +0100179 port=None,
180 baudrate=9600,
181 bytesize=EIGHTBITS,
182 parity=PARITY_NONE,
183 stopbits=STOPBITS_ONE,
184 timeout=None,
185 xonxoff=False,
186 rtscts=False,
187 write_timeout=None,
188 dsrdtr=False,
189 inter_byte_timeout=None,
Rob Gaddi636cc642017-02-24 11:39:46 -0800190 exclusive=None,
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100191 **kwargs):
cliechti7d448562014-08-03 21:57:45 +0000192 """\
Chris Liechtid6bcaaf2016-02-01 22:55:26 +0100193 Initialize comm port object. If a "port" is given, then the port will be
cliechti7d448562014-08-03 21:57:45 +0000194 opened immediately. Otherwise a Serial port object in closed state
195 is returned.
196 """
cliechtid6bf52c2003-10-01 02:28:12 +0000197
Chris Liechti033f17c2015-08-30 21:28:04 +0200198 self.is_open = False
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100199 self.portstr = None
200 self.name = None
Chris Liechtic14bba82016-01-02 23:23:11 +0100201 # correct values are assigned below through properties
202 self._port = None
203 self._baudrate = None
204 self._bytesize = None
205 self._parity = None
206 self._stopbits = None
207 self._timeout = None
208 self._write_timeout = None
209 self._xonxoff = None
210 self._rtscts = None
211 self._dsrdtr = None
212 self._inter_byte_timeout = None
Chris Liechti033f17c2015-08-30 21:28:04 +0200213 self._rs485_mode = None # disabled by default
Chris Liechtif7534c82016-05-07 23:35:54 +0200214 self._rts_state = True
215 self._dtr_state = True
Chris Liechtief1fe252015-08-27 23:25:21 +0200216 self._break_state = False
Rob Gaddi636cc642017-02-24 11:39:46 -0800217 self._exclusive = None
cliechti14b274a2009-02-07 00:27:05 +0000218
219 # assign values using get/set methods using the properties feature
Chris Liechti033f17c2015-08-30 21:28:04 +0200220 self.port = port
cliechtid6bf52c2003-10-01 02:28:12 +0000221 self.baudrate = baudrate
222 self.bytesize = bytesize
Chris Liechti033f17c2015-08-30 21:28:04 +0200223 self.parity = parity
cliechtid6bf52c2003-10-01 02:28:12 +0000224 self.stopbits = stopbits
Chris Liechti033f17c2015-08-30 21:28:04 +0200225 self.timeout = timeout
Chris Liechti518b0d32015-08-30 02:20:39 +0200226 self.write_timeout = write_timeout
Chris Liechti033f17c2015-08-30 21:28:04 +0200227 self.xonxoff = xonxoff
228 self.rtscts = rtscts
229 self.dsrdtr = dsrdtr
Chris Liechtib5331752015-10-24 01:34:11 +0200230 self.inter_byte_timeout = inter_byte_timeout
Rob Gaddi636cc642017-02-24 11:39:46 -0800231 self.exclusive = exclusive
Chris Liechti1c4bc812017-03-08 02:44:04 +0100232
Chris Liechtic14bba82016-01-02 23:23:11 +0100233 # watch for backward compatible kwargs
234 if 'writeTimeout' in kwargs:
235 self.write_timeout = kwargs.pop('writeTimeout')
236 if 'interCharTimeout' in kwargs:
237 self.inter_byte_timeout = kwargs.pop('interCharTimeout')
238 if kwargs:
Chris Liechti984c5c52016-02-15 23:48:45 +0100239 raise ValueError('unexpected keyword arguments: {!r}'.format(kwargs))
cliechti14b274a2009-02-07 00:27:05 +0000240
cliechtid6bf52c2003-10-01 02:28:12 +0000241 if port is not None:
242 self.open()
243
cliechtid6bf52c2003-10-01 02:28:12 +0000244 # - - - - - - - - - - - - - - - - - - - - - - - -
245
Chris Liechtia51b0bc2015-12-10 21:14:45 +0100246 # to be implemented by subclasses:
247 # def open(self):
248 # def close(self):
Chris Liechti5e763ca2015-12-09 13:01:26 +0100249
250 # - - - - - - - - - - - - - - - - - - - - - - - -
251
Chris Liechti779b1a22015-08-04 14:54:22 +0200252 @property
253 def port(self):
254 """\
255 Get the current port setting. The value that was passed on init or using
Chris Liechtibf9e3182016-04-22 21:31:09 +0200256 setPort() is passed back.
Chris Liechti779b1a22015-08-04 14:54:22 +0200257 """
258 return self._port
259
260 @port.setter
261 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000262 """\
Chris Liechtibf9e3182016-04-22 21:31:09 +0200263 Change the port.
cliechti7d448562014-08-03 21:57:45 +0000264 """
Chris Liechtif41b4592016-05-11 15:11:27 +0200265 if port is not None and not isinstance(port, basestring):
Chris Liechtibf9e3182016-04-22 21:31:09 +0200266 raise ValueError('"port" must be None or a string, not {}'.format(type(port)))
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200267 was_open = self.is_open
268 if was_open:
269 self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200270 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000271 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000272 self.name = self.portstr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200273 if was_open:
274 self.open()
cliechti14b274a2009-02-07 00:27:05 +0000275
Chris Liechti779b1a22015-08-04 14:54:22 +0200276 @property
277 def baudrate(self):
278 """Get the current baud rate setting."""
279 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000280
Chris Liechti779b1a22015-08-04 14:54:22 +0200281 @baudrate.setter
282 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000283 """\
284 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000285 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000286 accepted and the exception is raised when the port is opened.
287 """
cliechti107db8d2004-01-15 01:20:23 +0000288 try:
cliechtie30868d2013-10-16 15:35:11 +0000289 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000290 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100291 raise ValueError("Not a valid baudrate: {!r}".format(baudrate))
cliechti107db8d2004-01-15 01:20:23 +0000292 else:
Chris Liechtia83408a2016-05-23 22:18:43 +0200293 if b < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100294 raise ValueError("Not a valid baudrate: {!r}".format(baudrate))
cliechtie30868d2013-10-16 15:35:11 +0000295 self._baudrate = b
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 bytesize(self):
301 """Get the current byte size setting."""
302 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000303
Chris Liechti779b1a22015-08-04 14:54:22 +0200304 @bytesize.setter
305 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000306 """Change byte size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200307 if bytesize not in self.BYTESIZES:
Chris Liechti984c5c52016-02-15 23:48:45 +0100308 raise ValueError("Not a valid byte size: {!r}".format(bytesize))
cliechtid6bf52c2003-10-01 02:28:12 +0000309 self._bytesize = bytesize
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
Rob Gaddi636cc642017-02-24 11:39:46 -0800314 def exclusive(self):
315 """Get the current exclusive access setting."""
316 return self._exclusive
Chris Liechti1c4bc812017-03-08 02:44:04 +0100317
Rob Gaddi636cc642017-02-24 11:39:46 -0800318 @exclusive.setter
319 def exclusive(self, exclusive):
320 """Change the exclusive access setting."""
321 self._exclusive = exclusive
322 if self.is_open:
323 self._reconfigure_port()
324
325 @property
Chris Liechti779b1a22015-08-04 14:54:22 +0200326 def parity(self):
327 """Get the current parity setting."""
328 return self._parity
329
330 @parity.setter
331 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000332 """Change parity setting."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200333 if parity not in self.PARITIES:
Chris Liechti984c5c52016-02-15 23:48:45 +0100334 raise ValueError("Not a valid parity: {!r}".format(parity))
cliechtid6bf52c2003-10-01 02:28:12 +0000335 self._parity = parity
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200336 if self.is_open:
337 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000338
Chris Liechti779b1a22015-08-04 14:54:22 +0200339 @property
340 def stopbits(self):
341 """Get the current stop bits setting."""
342 return self._stopbits
343
344 @stopbits.setter
345 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000346 """Change stop bits size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200347 if stopbits not in self.STOPBITS:
Chris Liechti984c5c52016-02-15 23:48:45 +0100348 raise ValueError("Not a valid stop bit size: {!r}".format(stopbits))
cliechtid6bf52c2003-10-01 02:28:12 +0000349 self._stopbits = stopbits
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200350 if self.is_open:
351 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000352
Chris Liechti779b1a22015-08-04 14:54:22 +0200353 @property
354 def timeout(self):
355 """Get the current timeout setting."""
356 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000357
Chris Liechti779b1a22015-08-04 14:54:22 +0200358 @timeout.setter
359 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000360 """Change timeout setting."""
361 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000362 try:
cliechti14b274a2009-02-07 00:27:05 +0000363 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000364 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100365 raise ValueError("Not a valid timeout: {!r}".format(timeout))
Chris Liechticf29a352015-10-23 22:03:40 +0200366 if timeout < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100367 raise ValueError("Not a valid timeout: {!r}".format(timeout))
cliechtid6bf52c2003-10-01 02:28:12 +0000368 self._timeout = 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
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200373 def write_timeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000374 """Get the current timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200375 return self._write_timeout
cliechti14b274a2009-02-07 00:27:05 +0000376
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200377 @write_timeout.setter
378 def write_timeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000379 """Change timeout setting."""
380 if timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200381 if timeout < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100382 raise ValueError("Not a valid timeout: {!r}".format(timeout))
cliechti62611612004-04-20 01:55:43 +0000383 try:
Chris Liechti033f17c2015-08-30 21:28:04 +0200384 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti62611612004-04-20 01:55:43 +0000385 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100386 raise ValueError("Not a valid timeout: {!r}".format(timeout))
cliechti14b274a2009-02-07 00:27:05 +0000387
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200388 self._write_timeout = timeout
389 if self.is_open:
390 self._reconfigure_port()
391
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200392 @property
Chris Liechti518b0d32015-08-30 02:20:39 +0200393 def inter_byte_timeout(self):
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200394 """Get the current inter-character timeout setting."""
Chris Liechti96242372015-09-02 02:49:49 +0200395 return self._inter_byte_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200396
Chris Liechti518b0d32015-08-30 02:20:39 +0200397 @inter_byte_timeout.setter
398 def inter_byte_timeout(self, ic_timeout):
399 """Change inter-byte timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200400 if ic_timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200401 if ic_timeout < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100402 raise ValueError("Not a valid timeout: {!r}".format(ic_timeout))
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200403 try:
404 ic_timeout + 1 # test if it's a number, will throw a TypeError if not...
405 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100406 raise ValueError("Not a valid timeout: {!r}".format(ic_timeout))
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200407
Chris Liechti518b0d32015-08-30 02:20:39 +0200408 self._inter_byte_timeout = ic_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200409 if self.is_open:
410 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000411
Chris Liechti779b1a22015-08-04 14:54:22 +0200412 @property
413 def xonxoff(self):
414 """Get the current XON/XOFF setting."""
415 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000416
Chris Liechti779b1a22015-08-04 14:54:22 +0200417 @xonxoff.setter
418 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000419 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000420 self._xonxoff = xonxoff
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200421 if self.is_open:
422 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000423
Chris Liechti779b1a22015-08-04 14:54:22 +0200424 @property
425 def rtscts(self):
426 """Get the current RTS/CTS flow control setting."""
427 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000428
Chris Liechti779b1a22015-08-04 14:54:22 +0200429 @rtscts.setter
430 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000431 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000432 self._rtscts = rtscts
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200433 if self.is_open:
434 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000435
Chris Liechti779b1a22015-08-04 14:54:22 +0200436 @property
437 def dsrdtr(self):
438 """Get the current DSR/DTR flow control setting."""
439 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000440
Chris Liechti779b1a22015-08-04 14:54:22 +0200441 @dsrdtr.setter
442 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000443 """Change DsrDtr flow control setting."""
444 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000445 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000446 self._dsrdtr = self._rtscts
447 else:
cliechti14b274a2009-02-07 00:27:05 +0000448 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000449 self._dsrdtr = dsrdtr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200450 if self.is_open:
451 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000452
Chris Liechti779b1a22015-08-04 14:54:22 +0200453 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200454 def rts(self):
455 return self._rts_state
cliechti679bfa62008-06-20 23:58:15 +0000456
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200457 @rts.setter
458 def rts(self, value):
459 self._rts_state = value
460 if self.is_open:
461 self._update_rts_state()
cliechti14b274a2009-02-07 00:27:05 +0000462
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200463 @property
464 def dtr(self):
465 return self._dtr_state
cliechti14b274a2009-02-07 00:27:05 +0000466
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200467 @dtr.setter
468 def dtr(self, value):
469 self._dtr_state = value
470 if self.is_open:
471 self._update_dtr_state()
472
473 @property
474 def break_condition(self):
475 return self._break_state
476
477 @break_condition.setter
478 def break_condition(self, value):
479 self._break_state = value
480 if self.is_open:
481 self._update_break_state()
cliechti679bfa62008-06-20 23:58:15 +0000482
cliechti4065dce2009-08-10 00:55:46 +0000483 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200484 # functions useful for RS-485 adapters
485
486 @property
487 def rs485_mode(self):
488 """\
489 Enable RS485 mode and apply new settings, set to None to disable.
490 See serial.rs485.RS485Settings for more info about the value.
491 """
492 return self._rs485_mode
493
494 @rs485_mode.setter
495 def rs485_mode(self, rs485_settings):
496 self._rs485_mode = rs485_settings
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200497 if self.is_open:
498 self._reconfigure_port()
Chris Liechti33f0ec52015-08-06 16:37:21 +0200499
500 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000501
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200502 _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
Chris Liechti033f17c2015-08-30 21:28:04 +0200503 'dsrdtr', 'rtscts', 'timeout', 'write_timeout',
Chris Liechti1c3249f2015-09-01 02:31:36 +0200504 'inter_byte_timeout')
cliechti4065dce2009-08-10 00:55:46 +0000505
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200506 def get_settings(self):
cliechti7d448562014-08-03 21:57:45 +0000507 """\
508 Get current port settings as a dictionary. For use with
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200509 apply_settings().
cliechti7d448562014-08-03 21:57:45 +0000510 """
Chris Liechti033f17c2015-08-30 21:28:04 +0200511 return dict([(key, getattr(self, '_' + key)) for key in self._SAVED_SETTINGS])
cliechti4065dce2009-08-10 00:55:46 +0000512
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200513 def apply_settings(self, d):
cliechti7d448562014-08-03 21:57:45 +0000514 """\
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200515 Apply stored settings from a dictionary returned from
516 get_settings(). It's allowed to delete keys from the dictionary. These
cliechti7d448562014-08-03 21:57:45 +0000517 values will simply left unchanged.
518 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200519 for key in self._SAVED_SETTINGS:
Chris Liechti033f17c2015-08-30 21:28:04 +0200520 if key in d and d[key] != getattr(self, '_' + key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000521 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000522
cliechtid6bf52c2003-10-01 02:28:12 +0000523 # - - - - - - - - - - - - - - - - - - - - - - - -
524
525 def __repr__(self):
526 """String representation of the current port settings and its state."""
Chris Liechti984c5c52016-02-15 23:48:45 +0100527 return '{name}<id=0x{id:x}, open={p.is_open}>(port={p.portstr!r}, ' \
528 'baudrate={p.baudrate!r}, bytesize={p.bytesize!r}, parity={p.parity!r}, ' \
529 'stopbits={p.stopbits!r}, timeout={p.timeout!r}, xonxoff={p.xonxoff!r}, ' \
530 'rtscts={p.rtscts!r}, dsrdtr={p.dsrdtr!r})'.format(
531 name=self.__class__.__name__, id=id(self), p=self)
cliechtid6bf52c2003-10-01 02:28:12 +0000532
cliechti4a567a02009-07-27 22:09:31 +0000533 # - - - - - - - - - - - - - - - - - - - - - - - -
534 # compatibility with io library
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100535 # pylint: disable=invalid-name,missing-docstring
cliechti4a567a02009-07-27 22:09:31 +0000536
Chris Liechti033f17c2015-08-30 21:28:04 +0200537 def readable(self):
538 return True
539
540 def writable(self):
541 return True
542
543 def seekable(self):
544 return False
545
cliechti4a567a02009-07-27 22:09:31 +0000546 def readinto(self, b):
547 data = self.read(len(b))
548 n = len(data)
549 try:
550 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200551 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000552 import array
553 if not isinstance(b, array.array):
554 raise err
555 b[:n] = array.array('b', data)
556 return n
cliechtif81362e2009-07-25 03:44:33 +0000557
Chris Liechti70b89232015-08-04 03:00:52 +0200558 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200559 # context manager
560
561 def __enter__(self):
Guillaume Galeazzi48a5ce12017-06-28 16:21:46 +0200562 if not self.is_open:
563 self.open()
Chris Liechti779b1a22015-08-04 14:54:22 +0200564 return self
565
566 def __exit__(self, *args, **kwargs):
567 self.close()
568
569 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechtief1fe252015-08-27 23:25:21 +0200570
571 def send_break(self, duration=0.25):
572 """\
573 Send break condition. Timed, returns to idle state after given
574 duration.
575 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200576 if not self.is_open:
577 raise portNotOpenError
Chris Liechtief1fe252015-08-27 23:25:21 +0200578 self.break_condition = True
579 time.sleep(duration)
580 self.break_condition = False
581
582 # - - - - - - - - - - - - - - - - - - - - - - - -
583 # backwards compatibility / deprecated functions
584
585 def flushInput(self):
586 self.reset_input_buffer()
587
588 def flushOutput(self):
589 self.reset_output_buffer()
590
591 def inWaiting(self):
592 return self.in_waiting
593
594 def sendBreak(self, duration=0.25):
595 self.send_break(duration)
596
597 def setRTS(self, value=1):
598 self.rts = value
599
600 def setDTR(self, value=1):
601 self.dtr = value
602
603 def getCTS(self):
604 return self.cts
605
606 def getDSR(self):
607 return self.dsr
608
609 def getRI(self):
610 return self.ri
611
612 def getCD(self):
613 return self.cd
614
Chris Liechti0eba2a62016-04-06 02:55:51 +0200615 def setPort(self, port):
616 self.port = port
617
Chris Liechtief1fe252015-08-27 23:25:21 +0200618 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200619 def writeTimeout(self):
620 return self.write_timeout
621
622 @writeTimeout.setter
623 def writeTimeout(self, timeout):
624 self.write_timeout = timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200625
626 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200627 def interCharTimeout(self):
Chris Liechti96242372015-09-02 02:49:49 +0200628 return self.inter_byte_timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200629
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200630 @interCharTimeout.setter
631 def interCharTimeout(self, interCharTimeout):
Chris Liechti96242372015-09-02 02:49:49 +0200632 self.inter_byte_timeout = interCharTimeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200633
634 def getSettingsDict(self):
635 return self.get_settings()
636
637 def applySettingsDict(self, d):
638 self.apply_settings(d)
639
640 def isOpen(self):
Chris Liechti16843852015-09-22 23:24:35 +0200641 return self.is_open
Chris Liechtief1fe252015-08-27 23:25:21 +0200642
643 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200644 # additional functionality
645
David Howlett240f8fc2015-10-28 12:32:09 +0000646 def read_all(self):
Chris Liechti03cb8ed2015-10-30 23:37:24 +0100647 """\
648 Read all bytes currently available in the buffer of the OS.
649 """
David Howlett240f8fc2015-10-28 12:32:09 +0000650 return self.read(self.in_waiting)
651
Chris Liechti70b89232015-08-04 03:00:52 +0200652 def read_until(self, terminator=LF, size=None):
653 """\
654 Read until a termination sequence is found ('\n' by default), the size
655 is exceeded or until timeout occurs.
656 """
657 lenterm = len(terminator)
658 line = bytearray()
Chris Liechti6f03c0b2016-12-22 23:51:34 +0100659 timeout = Timeout(self._timeout)
Chris Liechti70b89232015-08-04 03:00:52 +0200660 while True:
661 c = self.read(1)
662 if c:
663 line += c
664 if line[-lenterm:] == terminator:
665 break
666 if size is not None and len(line) >= size:
667 break
668 else:
669 break
Chris Liechti6f03c0b2016-12-22 23:51:34 +0100670 if timeout.expired():
671 break
Chris Liechti70b89232015-08-04 03:00:52 +0200672 return bytes(line)
673
Chris Liechti70b89232015-08-04 03:00:52 +0200674 def iread_until(self, *args, **kwargs):
675 """\
676 Read lines, implemented as generator. It will raise StopIteration on
677 timeout (empty read).
678 """
679 while True:
680 line = self.read_until(*args, **kwargs)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200681 if not line:
682 break
Chris Liechti70b89232015-08-04 03:00:52 +0200683 yield line
cliechtif81362e2009-07-25 03:44:33 +0000684
Chris Liechti779b1a22015-08-04 14:54:22 +0200685
686# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000687if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000688 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000689 s = SerialBase()
Chris Liechti984c5c52016-02-15 23:48:45 +0100690 sys.stdout.write('port name: {}\n'.format(s.name))
691 sys.stdout.write('baud rates: {}\n'.format(s.BAUDRATES))
692 sys.stdout.write('byte sizes: {}\n'.format(s.BYTESIZES))
693 sys.stdout.write('parities: {}\n'.format(s.PARITIES))
694 sys.stdout.write('stop bits: {}\n'.format(s.STOPBITS))
695 sys.stdout.write('{}\n'.format(s))