blob: 0b2b9a3e6be2b1fdab4b787c802239ae2f96fd0c [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
135
Chris Liechtief6b7b42015-08-06 22:19:26 +0200136class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +0000137 """\
138 Serial port base class. Provides __init__ function and properties to
139 get/set port settings.
140 """
cliechti14b274a2009-02-07 00:27:05 +0000141
cliechtidfec0c82009-07-21 01:35:41 +0000142 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +0000143 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
144 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
145 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
146 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +0000147 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
Chris Liechticf29a352015-10-23 22:03:40 +0200148 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
149 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +0000150
cliechtid6bf52c2003-10-01 02:28:12 +0000151 def __init__(self,
Chris Liechtid6bcaaf2016-02-01 22:55:26 +0100152 port=None,
153 baudrate=9600,
154 bytesize=EIGHTBITS,
155 parity=PARITY_NONE,
156 stopbits=STOPBITS_ONE,
157 timeout=None,
158 xonxoff=False,
159 rtscts=False,
160 write_timeout=None,
161 dsrdtr=False,
162 inter_byte_timeout=None,
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100163 **kwargs):
cliechti7d448562014-08-03 21:57:45 +0000164 """\
Chris Liechtid6bcaaf2016-02-01 22:55:26 +0100165 Initialize comm port object. If a "port" is given, then the port will be
cliechti7d448562014-08-03 21:57:45 +0000166 opened immediately. Otherwise a Serial port object in closed state
167 is returned.
168 """
cliechtid6bf52c2003-10-01 02:28:12 +0000169
Chris Liechti033f17c2015-08-30 21:28:04 +0200170 self.is_open = False
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100171 self.portstr = None
172 self.name = None
Chris Liechtic14bba82016-01-02 23:23:11 +0100173 # correct values are assigned below through properties
174 self._port = None
175 self._baudrate = None
176 self._bytesize = None
177 self._parity = None
178 self._stopbits = None
179 self._timeout = None
180 self._write_timeout = None
181 self._xonxoff = None
182 self._rtscts = None
183 self._dsrdtr = None
184 self._inter_byte_timeout = None
Chris Liechti033f17c2015-08-30 21:28:04 +0200185 self._rs485_mode = None # disabled by default
Chris Liechtif7534c82016-05-07 23:35:54 +0200186 self._rts_state = True
187 self._dtr_state = True
Chris Liechtief1fe252015-08-27 23:25:21 +0200188 self._break_state = False
cliechti14b274a2009-02-07 00:27:05 +0000189
190 # assign values using get/set methods using the properties feature
Chris Liechti033f17c2015-08-30 21:28:04 +0200191 self.port = port
cliechtid6bf52c2003-10-01 02:28:12 +0000192 self.baudrate = baudrate
193 self.bytesize = bytesize
Chris Liechti033f17c2015-08-30 21:28:04 +0200194 self.parity = parity
cliechtid6bf52c2003-10-01 02:28:12 +0000195 self.stopbits = stopbits
Chris Liechti033f17c2015-08-30 21:28:04 +0200196 self.timeout = timeout
Chris Liechti518b0d32015-08-30 02:20:39 +0200197 self.write_timeout = write_timeout
Chris Liechti033f17c2015-08-30 21:28:04 +0200198 self.xonxoff = xonxoff
199 self.rtscts = rtscts
200 self.dsrdtr = dsrdtr
Chris Liechtib5331752015-10-24 01:34:11 +0200201 self.inter_byte_timeout = inter_byte_timeout
Chris Liechtic14bba82016-01-02 23:23:11 +0100202 # watch for backward compatible kwargs
203 if 'writeTimeout' in kwargs:
204 self.write_timeout = kwargs.pop('writeTimeout')
205 if 'interCharTimeout' in kwargs:
206 self.inter_byte_timeout = kwargs.pop('interCharTimeout')
207 if kwargs:
Chris Liechti984c5c52016-02-15 23:48:45 +0100208 raise ValueError('unexpected keyword arguments: {!r}'.format(kwargs))
cliechti14b274a2009-02-07 00:27:05 +0000209
cliechtid6bf52c2003-10-01 02:28:12 +0000210 if port is not None:
211 self.open()
212
cliechtid6bf52c2003-10-01 02:28:12 +0000213 # - - - - - - - - - - - - - - - - - - - - - - - -
214
Chris Liechtia51b0bc2015-12-10 21:14:45 +0100215 # to be implemented by subclasses:
216 # def open(self):
217 # def close(self):
Chris Liechti5e763ca2015-12-09 13:01:26 +0100218
219 # - - - - - - - - - - - - - - - - - - - - - - - -
220
Chris Liechti779b1a22015-08-04 14:54:22 +0200221 @property
222 def port(self):
223 """\
224 Get the current port setting. The value that was passed on init or using
Chris Liechtibf9e3182016-04-22 21:31:09 +0200225 setPort() is passed back.
Chris Liechti779b1a22015-08-04 14:54:22 +0200226 """
227 return self._port
228
229 @port.setter
230 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000231 """\
Chris Liechtibf9e3182016-04-22 21:31:09 +0200232 Change the port.
cliechti7d448562014-08-03 21:57:45 +0000233 """
Chris Liechtif41b4592016-05-11 15:11:27 +0200234 if port is not None and not isinstance(port, basestring):
Chris Liechtibf9e3182016-04-22 21:31:09 +0200235 raise ValueError('"port" must be None or a string, not {}'.format(type(port)))
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200236 was_open = self.is_open
237 if was_open:
238 self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200239 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000240 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000241 self.name = self.portstr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200242 if was_open:
243 self.open()
cliechti14b274a2009-02-07 00:27:05 +0000244
Chris Liechti779b1a22015-08-04 14:54:22 +0200245 @property
246 def baudrate(self):
247 """Get the current baud rate setting."""
248 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000249
Chris Liechti779b1a22015-08-04 14:54:22 +0200250 @baudrate.setter
251 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000252 """\
253 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000254 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000255 accepted and the exception is raised when the port is opened.
256 """
cliechti107db8d2004-01-15 01:20:23 +0000257 try:
cliechtie30868d2013-10-16 15:35:11 +0000258 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000259 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100260 raise ValueError("Not a valid baudrate: {!r}".format(baudrate))
cliechti107db8d2004-01-15 01:20:23 +0000261 else:
Chris Liechtia83408a2016-05-23 22:18:43 +0200262 if b < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100263 raise ValueError("Not a valid baudrate: {!r}".format(baudrate))
cliechtie30868d2013-10-16 15:35:11 +0000264 self._baudrate = b
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200265 if self.is_open:
266 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000267
Chris Liechti779b1a22015-08-04 14:54:22 +0200268 @property
269 def bytesize(self):
270 """Get the current byte size setting."""
271 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000272
Chris Liechti779b1a22015-08-04 14:54:22 +0200273 @bytesize.setter
274 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000275 """Change byte size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200276 if bytesize not in self.BYTESIZES:
Chris Liechti984c5c52016-02-15 23:48:45 +0100277 raise ValueError("Not a valid byte size: {!r}".format(bytesize))
cliechtid6bf52c2003-10-01 02:28:12 +0000278 self._bytesize = bytesize
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200279 if self.is_open:
280 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000281
Chris Liechti779b1a22015-08-04 14:54:22 +0200282 @property
283 def parity(self):
284 """Get the current parity setting."""
285 return self._parity
286
287 @parity.setter
288 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000289 """Change parity setting."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200290 if parity not in self.PARITIES:
Chris Liechti984c5c52016-02-15 23:48:45 +0100291 raise ValueError("Not a valid parity: {!r}".format(parity))
cliechtid6bf52c2003-10-01 02:28:12 +0000292 self._parity = parity
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
297 def stopbits(self):
298 """Get the current stop bits setting."""
299 return self._stopbits
300
301 @stopbits.setter
302 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000303 """Change stop bits size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200304 if stopbits not in self.STOPBITS:
Chris Liechti984c5c52016-02-15 23:48:45 +0100305 raise ValueError("Not a valid stop bit size: {!r}".format(stopbits))
cliechtid6bf52c2003-10-01 02:28:12 +0000306 self._stopbits = stopbits
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200307 if self.is_open:
308 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000309
Chris Liechti779b1a22015-08-04 14:54:22 +0200310 @property
311 def timeout(self):
312 """Get the current timeout setting."""
313 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000314
Chris Liechti779b1a22015-08-04 14:54:22 +0200315 @timeout.setter
316 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000317 """Change timeout setting."""
318 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000319 try:
cliechti14b274a2009-02-07 00:27:05 +0000320 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000321 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100322 raise ValueError("Not a valid timeout: {!r}".format(timeout))
Chris Liechticf29a352015-10-23 22:03:40 +0200323 if timeout < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100324 raise ValueError("Not a valid timeout: {!r}".format(timeout))
cliechtid6bf52c2003-10-01 02:28:12 +0000325 self._timeout = timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200326 if self.is_open:
327 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000328
Chris Liechti779b1a22015-08-04 14:54:22 +0200329 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200330 def write_timeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000331 """Get the current timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200332 return self._write_timeout
cliechti14b274a2009-02-07 00:27:05 +0000333
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200334 @write_timeout.setter
335 def write_timeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000336 """Change timeout setting."""
337 if timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200338 if timeout < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100339 raise ValueError("Not a valid timeout: {!r}".format(timeout))
cliechti62611612004-04-20 01:55:43 +0000340 try:
Chris Liechti033f17c2015-08-30 21:28:04 +0200341 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti62611612004-04-20 01:55:43 +0000342 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100343 raise ValueError("Not a valid timeout: {!r}".format(timeout))
cliechti14b274a2009-02-07 00:27:05 +0000344
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200345 self._write_timeout = timeout
346 if self.is_open:
347 self._reconfigure_port()
348
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200349 @property
Chris Liechti518b0d32015-08-30 02:20:39 +0200350 def inter_byte_timeout(self):
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200351 """Get the current inter-character timeout setting."""
Chris Liechti96242372015-09-02 02:49:49 +0200352 return self._inter_byte_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200353
Chris Liechti518b0d32015-08-30 02:20:39 +0200354 @inter_byte_timeout.setter
355 def inter_byte_timeout(self, ic_timeout):
356 """Change inter-byte timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200357 if ic_timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200358 if ic_timeout < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100359 raise ValueError("Not a valid timeout: {!r}".format(ic_timeout))
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200360 try:
361 ic_timeout + 1 # test if it's a number, will throw a TypeError if not...
362 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100363 raise ValueError("Not a valid timeout: {!r}".format(ic_timeout))
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200364
Chris Liechti518b0d32015-08-30 02:20:39 +0200365 self._inter_byte_timeout = ic_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200366 if self.is_open:
367 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000368
Chris Liechti779b1a22015-08-04 14:54:22 +0200369 @property
370 def xonxoff(self):
371 """Get the current XON/XOFF setting."""
372 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000373
Chris Liechti779b1a22015-08-04 14:54:22 +0200374 @xonxoff.setter
375 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000376 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000377 self._xonxoff = xonxoff
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200378 if self.is_open:
379 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000380
Chris Liechti779b1a22015-08-04 14:54:22 +0200381 @property
382 def rtscts(self):
383 """Get the current RTS/CTS flow control setting."""
384 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000385
Chris Liechti779b1a22015-08-04 14:54:22 +0200386 @rtscts.setter
387 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000388 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000389 self._rtscts = rtscts
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200390 if self.is_open:
391 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000392
Chris Liechti779b1a22015-08-04 14:54:22 +0200393 @property
394 def dsrdtr(self):
395 """Get the current DSR/DTR flow control setting."""
396 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000397
Chris Liechti779b1a22015-08-04 14:54:22 +0200398 @dsrdtr.setter
399 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000400 """Change DsrDtr flow control setting."""
401 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000402 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000403 self._dsrdtr = self._rtscts
404 else:
cliechti14b274a2009-02-07 00:27:05 +0000405 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000406 self._dsrdtr = dsrdtr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200407 if self.is_open:
408 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000409
Chris Liechti779b1a22015-08-04 14:54:22 +0200410 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200411 def rts(self):
412 return self._rts_state
cliechti679bfa62008-06-20 23:58:15 +0000413
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200414 @rts.setter
415 def rts(self, value):
416 self._rts_state = value
417 if self.is_open:
418 self._update_rts_state()
cliechti14b274a2009-02-07 00:27:05 +0000419
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200420 @property
421 def dtr(self):
422 return self._dtr_state
cliechti14b274a2009-02-07 00:27:05 +0000423
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200424 @dtr.setter
425 def dtr(self, value):
426 self._dtr_state = value
427 if self.is_open:
428 self._update_dtr_state()
429
430 @property
431 def break_condition(self):
432 return self._break_state
433
434 @break_condition.setter
435 def break_condition(self, value):
436 self._break_state = value
437 if self.is_open:
438 self._update_break_state()
cliechti679bfa62008-06-20 23:58:15 +0000439
cliechti4065dce2009-08-10 00:55:46 +0000440 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200441 # functions useful for RS-485 adapters
442
443 @property
444 def rs485_mode(self):
445 """\
446 Enable RS485 mode and apply new settings, set to None to disable.
447 See serial.rs485.RS485Settings for more info about the value.
448 """
449 return self._rs485_mode
450
451 @rs485_mode.setter
452 def rs485_mode(self, rs485_settings):
453 self._rs485_mode = rs485_settings
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200454 if self.is_open:
455 self._reconfigure_port()
Chris Liechti33f0ec52015-08-06 16:37:21 +0200456
457 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000458
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200459 _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
Chris Liechti033f17c2015-08-30 21:28:04 +0200460 'dsrdtr', 'rtscts', 'timeout', 'write_timeout',
Chris Liechti1c3249f2015-09-01 02:31:36 +0200461 'inter_byte_timeout')
cliechti4065dce2009-08-10 00:55:46 +0000462
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200463 def get_settings(self):
cliechti7d448562014-08-03 21:57:45 +0000464 """\
465 Get current port settings as a dictionary. For use with
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200466 apply_settings().
cliechti7d448562014-08-03 21:57:45 +0000467 """
Chris Liechti033f17c2015-08-30 21:28:04 +0200468 return dict([(key, getattr(self, '_' + key)) for key in self._SAVED_SETTINGS])
cliechti4065dce2009-08-10 00:55:46 +0000469
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200470 def apply_settings(self, d):
cliechti7d448562014-08-03 21:57:45 +0000471 """\
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200472 Apply stored settings from a dictionary returned from
473 get_settings(). It's allowed to delete keys from the dictionary. These
cliechti7d448562014-08-03 21:57:45 +0000474 values will simply left unchanged.
475 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200476 for key in self._SAVED_SETTINGS:
Chris Liechti033f17c2015-08-30 21:28:04 +0200477 if key in d and d[key] != getattr(self, '_' + key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000478 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000479
cliechtid6bf52c2003-10-01 02:28:12 +0000480 # - - - - - - - - - - - - - - - - - - - - - - - -
481
482 def __repr__(self):
483 """String representation of the current port settings and its state."""
Chris Liechti984c5c52016-02-15 23:48:45 +0100484 return '{name}<id=0x{id:x}, open={p.is_open}>(port={p.portstr!r}, ' \
485 'baudrate={p.baudrate!r}, bytesize={p.bytesize!r}, parity={p.parity!r}, ' \
486 'stopbits={p.stopbits!r}, timeout={p.timeout!r}, xonxoff={p.xonxoff!r}, ' \
487 'rtscts={p.rtscts!r}, dsrdtr={p.dsrdtr!r})'.format(
488 name=self.__class__.__name__, id=id(self), p=self)
cliechtid6bf52c2003-10-01 02:28:12 +0000489
cliechti4a567a02009-07-27 22:09:31 +0000490 # - - - - - - - - - - - - - - - - - - - - - - - -
491 # compatibility with io library
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100492 # pylint: disable=invalid-name,missing-docstring
cliechti4a567a02009-07-27 22:09:31 +0000493
Chris Liechti033f17c2015-08-30 21:28:04 +0200494 def readable(self):
495 return True
496
497 def writable(self):
498 return True
499
500 def seekable(self):
501 return False
502
cliechti4a567a02009-07-27 22:09:31 +0000503 def readinto(self, b):
504 data = self.read(len(b))
505 n = len(data)
506 try:
507 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200508 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000509 import array
510 if not isinstance(b, array.array):
511 raise err
512 b[:n] = array.array('b', data)
513 return n
cliechtif81362e2009-07-25 03:44:33 +0000514
Chris Liechti70b89232015-08-04 03:00:52 +0200515 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200516 # context manager
517
518 def __enter__(self):
519 return self
520
521 def __exit__(self, *args, **kwargs):
522 self.close()
523
524 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechtief1fe252015-08-27 23:25:21 +0200525
526 def send_break(self, duration=0.25):
527 """\
528 Send break condition. Timed, returns to idle state after given
529 duration.
530 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200531 if not self.is_open:
532 raise portNotOpenError
Chris Liechtief1fe252015-08-27 23:25:21 +0200533 self.break_condition = True
534 time.sleep(duration)
535 self.break_condition = False
536
537 # - - - - - - - - - - - - - - - - - - - - - - - -
538 # backwards compatibility / deprecated functions
539
540 def flushInput(self):
541 self.reset_input_buffer()
542
543 def flushOutput(self):
544 self.reset_output_buffer()
545
546 def inWaiting(self):
547 return self.in_waiting
548
549 def sendBreak(self, duration=0.25):
550 self.send_break(duration)
551
552 def setRTS(self, value=1):
553 self.rts = value
554
555 def setDTR(self, value=1):
556 self.dtr = value
557
558 def getCTS(self):
559 return self.cts
560
561 def getDSR(self):
562 return self.dsr
563
564 def getRI(self):
565 return self.ri
566
567 def getCD(self):
568 return self.cd
569
Chris Liechti0eba2a62016-04-06 02:55:51 +0200570 def setPort(self, port):
571 self.port = port
572
Chris Liechtief1fe252015-08-27 23:25:21 +0200573 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200574 def writeTimeout(self):
575 return self.write_timeout
576
577 @writeTimeout.setter
578 def writeTimeout(self, timeout):
579 self.write_timeout = timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200580
581 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200582 def interCharTimeout(self):
Chris Liechti96242372015-09-02 02:49:49 +0200583 return self.inter_byte_timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200584
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200585 @interCharTimeout.setter
586 def interCharTimeout(self, interCharTimeout):
Chris Liechti96242372015-09-02 02:49:49 +0200587 self.inter_byte_timeout = interCharTimeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200588
589 def getSettingsDict(self):
590 return self.get_settings()
591
592 def applySettingsDict(self, d):
593 self.apply_settings(d)
594
595 def isOpen(self):
Chris Liechti16843852015-09-22 23:24:35 +0200596 return self.is_open
Chris Liechtief1fe252015-08-27 23:25:21 +0200597
598 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200599 # additional functionality
600
David Howlett240f8fc2015-10-28 12:32:09 +0000601 def read_all(self):
Chris Liechti03cb8ed2015-10-30 23:37:24 +0100602 """\
603 Read all bytes currently available in the buffer of the OS.
604 """
David Howlett240f8fc2015-10-28 12:32:09 +0000605 return self.read(self.in_waiting)
606
Chris Liechti70b89232015-08-04 03:00:52 +0200607 def read_until(self, terminator=LF, size=None):
608 """\
609 Read until a termination sequence is found ('\n' by default), the size
610 is exceeded or until timeout occurs.
611 """
612 lenterm = len(terminator)
613 line = bytearray()
614 while True:
615 c = self.read(1)
616 if c:
617 line += c
618 if line[-lenterm:] == terminator:
619 break
620 if size is not None and len(line) >= size:
621 break
622 else:
623 break
624 return bytes(line)
625
Chris Liechti70b89232015-08-04 03:00:52 +0200626 def iread_until(self, *args, **kwargs):
627 """\
628 Read lines, implemented as generator. It will raise StopIteration on
629 timeout (empty read).
630 """
631 while True:
632 line = self.read_until(*args, **kwargs)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200633 if not line:
634 break
Chris Liechti70b89232015-08-04 03:00:52 +0200635 yield line
cliechtif81362e2009-07-25 03:44:33 +0000636
Chris Liechti779b1a22015-08-04 14:54:22 +0200637
638# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000639if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000640 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000641 s = SerialBase()
Chris Liechti984c5c52016-02-15 23:48:45 +0100642 sys.stdout.write('port name: {}\n'.format(s.name))
643 sys.stdout.write('baud rates: {}\n'.format(s.BAUDRATES))
644 sys.stdout.write('byte sizes: {}\n'.format(s.BYTESIZES))
645 sys.stdout.write('parities: {}\n'.format(s.PARITIES))
646 sys.stdout.write('stop bits: {}\n'.format(s.STOPBITS))
647 sys.stdout.write('{}\n'.format(s))