blob: 77484317e3c68530217106d6b38c822620cd23a2 [file] [log] [blame]
cliechtid6bf52c2003-10-01 02:28:12 +00001#! python
cliechtid6bf52c2003-10-01 02:28:12 +00002#
Chris Liechti3e02f702015-12-16 23:06:04 +01003# Base class and support functions used by various backends.
4#
5# This file is part of pySerial. https://github.com/pyserial/pyserial
Chris Liechti68340d72015-08-03 14:15:48 +02006# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
Chris Liechtifbdd8a02015-08-09 02:37:45 +02007#
8# SPDX-License-Identifier: BSD-3-Clause
cliechtid6bf52c2003-10-01 02:28:12 +00009
Chris Liechtief6b7b42015-08-06 22:19:26 +020010import io
Chris Liechticf29a352015-10-23 22:03:40 +020011import time
cliechtic323f1f2010-07-22 00:14:26 +000012
cliechti38077122013-10-16 02:57:27 +000013# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)``
14# isn't returning the contents (very unfortunate). Therefore we need special
15# cases and test for it. Ensure that there is a ``memoryview`` object for older
16# Python versions. This is easier than making every test dependent on its
17# existence.
18try:
19 memoryview
20except (NameError, AttributeError):
21 # implementation does not matter as we do not realy use it.
22 # it just must not inherit from something else we might care for.
Chris Liechti409e10b2016-02-10 22:40:34 +010023 class memoryview(object): # pylint: disable=redefined-builtin,invalid-name
cliechti38077122013-10-16 02:57:27 +000024 pass
25
Chris Liechti4a790ad2015-09-09 17:12:52 +020026try:
27 unicode
28except (NameError, AttributeError):
Chris Liechti409e10b2016-02-10 22:40:34 +010029 unicode = str # for Python 3, pylint: disable=redefined-builtin,invalid-name
Chris Liechti4a790ad2015-09-09 17:12:52 +020030
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 Liechtief6b7b42015-08-06 22:19:26 +0200107class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +0000108 """\
109 Serial port base class. Provides __init__ function and properties to
110 get/set port settings.
111 """
cliechti14b274a2009-02-07 00:27:05 +0000112
cliechtidfec0c82009-07-21 01:35:41 +0000113 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +0000114 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
115 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
116 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
117 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +0000118 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
Chris Liechticf29a352015-10-23 22:03:40 +0200119 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
120 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +0000121
cliechtid6bf52c2003-10-01 02:28:12 +0000122 def __init__(self,
Chris Liechtid6bcaaf2016-02-01 22:55:26 +0100123 port=None,
124 baudrate=9600,
125 bytesize=EIGHTBITS,
126 parity=PARITY_NONE,
127 stopbits=STOPBITS_ONE,
128 timeout=None,
129 xonxoff=False,
130 rtscts=False,
131 write_timeout=None,
132 dsrdtr=False,
133 inter_byte_timeout=None,
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100134 **kwargs):
cliechti7d448562014-08-03 21:57:45 +0000135 """\
Chris Liechtid6bcaaf2016-02-01 22:55:26 +0100136 Initialize comm port object. If a "port" is given, then the port will be
cliechti7d448562014-08-03 21:57:45 +0000137 opened immediately. Otherwise a Serial port object in closed state
138 is returned.
139 """
cliechtid6bf52c2003-10-01 02:28:12 +0000140
Chris Liechti033f17c2015-08-30 21:28:04 +0200141 self.is_open = False
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100142 self.portstr = None
143 self.name = None
Chris Liechtic14bba82016-01-02 23:23:11 +0100144 # correct values are assigned below through properties
145 self._port = None
146 self._baudrate = None
147 self._bytesize = None
148 self._parity = None
149 self._stopbits = None
150 self._timeout = None
151 self._write_timeout = None
152 self._xonxoff = None
153 self._rtscts = None
154 self._dsrdtr = None
155 self._inter_byte_timeout = None
Chris Liechti033f17c2015-08-30 21:28:04 +0200156 self._rs485_mode = None # disabled by default
Chris Liechtif7534c82016-05-07 23:35:54 +0200157 self._rts_state = True
158 self._dtr_state = True
Chris Liechtief1fe252015-08-27 23:25:21 +0200159 self._break_state = False
cliechti14b274a2009-02-07 00:27:05 +0000160
161 # assign values using get/set methods using the properties feature
Chris Liechti033f17c2015-08-30 21:28:04 +0200162 self.port = port
cliechtid6bf52c2003-10-01 02:28:12 +0000163 self.baudrate = baudrate
164 self.bytesize = bytesize
Chris Liechti033f17c2015-08-30 21:28:04 +0200165 self.parity = parity
cliechtid6bf52c2003-10-01 02:28:12 +0000166 self.stopbits = stopbits
Chris Liechti033f17c2015-08-30 21:28:04 +0200167 self.timeout = timeout
Chris Liechti518b0d32015-08-30 02:20:39 +0200168 self.write_timeout = write_timeout
Chris Liechti033f17c2015-08-30 21:28:04 +0200169 self.xonxoff = xonxoff
170 self.rtscts = rtscts
171 self.dsrdtr = dsrdtr
Chris Liechtib5331752015-10-24 01:34:11 +0200172 self.inter_byte_timeout = inter_byte_timeout
Chris Liechtic14bba82016-01-02 23:23:11 +0100173 # watch for backward compatible kwargs
174 if 'writeTimeout' in kwargs:
175 self.write_timeout = kwargs.pop('writeTimeout')
176 if 'interCharTimeout' in kwargs:
177 self.inter_byte_timeout = kwargs.pop('interCharTimeout')
178 if kwargs:
Chris Liechti984c5c52016-02-15 23:48:45 +0100179 raise ValueError('unexpected keyword arguments: {!r}'.format(kwargs))
cliechti14b274a2009-02-07 00:27:05 +0000180
cliechtid6bf52c2003-10-01 02:28:12 +0000181 if port is not None:
182 self.open()
183
cliechtid6bf52c2003-10-01 02:28:12 +0000184 # - - - - - - - - - - - - - - - - - - - - - - - -
185
Chris Liechtia51b0bc2015-12-10 21:14:45 +0100186 # to be implemented by subclasses:
187 # def open(self):
188 # def close(self):
Chris Liechti5e763ca2015-12-09 13:01:26 +0100189
190 # - - - - - - - - - - - - - - - - - - - - - - - -
191
Chris Liechti779b1a22015-08-04 14:54:22 +0200192 @property
193 def port(self):
194 """\
195 Get the current port setting. The value that was passed on init or using
Chris Liechtibf9e3182016-04-22 21:31:09 +0200196 setPort() is passed back.
Chris Liechti779b1a22015-08-04 14:54:22 +0200197 """
198 return self._port
199
200 @port.setter
201 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000202 """\
Chris Liechtibf9e3182016-04-22 21:31:09 +0200203 Change the port.
cliechti7d448562014-08-03 21:57:45 +0000204 """
Chris Liechtif41b4592016-05-11 15:11:27 +0200205 if port is not None and not isinstance(port, basestring):
Chris Liechtibf9e3182016-04-22 21:31:09 +0200206 raise ValueError('"port" must be None or a string, not {}'.format(type(port)))
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200207 was_open = self.is_open
208 if was_open:
209 self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200210 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000211 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000212 self.name = self.portstr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200213 if was_open:
214 self.open()
cliechti14b274a2009-02-07 00:27:05 +0000215
Chris Liechti779b1a22015-08-04 14:54:22 +0200216 @property
217 def baudrate(self):
218 """Get the current baud rate setting."""
219 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000220
Chris Liechti779b1a22015-08-04 14:54:22 +0200221 @baudrate.setter
222 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000223 """\
224 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000225 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000226 accepted and the exception is raised when the port is opened.
227 """
cliechti107db8d2004-01-15 01:20:23 +0000228 try:
cliechtie30868d2013-10-16 15:35:11 +0000229 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000230 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100231 raise ValueError("Not a valid baudrate: {!r}".format(baudrate))
cliechti107db8d2004-01-15 01:20:23 +0000232 else:
cliechtie30868d2013-10-16 15:35:11 +0000233 if b <= 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100234 raise ValueError("Not a valid baudrate: {!r}".format(baudrate))
cliechtie30868d2013-10-16 15:35:11 +0000235 self._baudrate = b
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200236 if self.is_open:
237 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000238
Chris Liechti779b1a22015-08-04 14:54:22 +0200239 @property
240 def bytesize(self):
241 """Get the current byte size setting."""
242 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000243
Chris Liechti779b1a22015-08-04 14:54:22 +0200244 @bytesize.setter
245 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000246 """Change byte size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200247 if bytesize not in self.BYTESIZES:
Chris Liechti984c5c52016-02-15 23:48:45 +0100248 raise ValueError("Not a valid byte size: {!r}".format(bytesize))
cliechtid6bf52c2003-10-01 02:28:12 +0000249 self._bytesize = bytesize
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200250 if self.is_open:
251 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000252
Chris Liechti779b1a22015-08-04 14:54:22 +0200253 @property
254 def parity(self):
255 """Get the current parity setting."""
256 return self._parity
257
258 @parity.setter
259 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000260 """Change parity setting."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200261 if parity not in self.PARITIES:
Chris Liechti984c5c52016-02-15 23:48:45 +0100262 raise ValueError("Not a valid parity: {!r}".format(parity))
cliechtid6bf52c2003-10-01 02:28:12 +0000263 self._parity = parity
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200264 if self.is_open:
265 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000266
Chris Liechti779b1a22015-08-04 14:54:22 +0200267 @property
268 def stopbits(self):
269 """Get the current stop bits setting."""
270 return self._stopbits
271
272 @stopbits.setter
273 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000274 """Change stop bits size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200275 if stopbits not in self.STOPBITS:
Chris Liechti984c5c52016-02-15 23:48:45 +0100276 raise ValueError("Not a valid stop bit size: {!r}".format(stopbits))
cliechtid6bf52c2003-10-01 02:28:12 +0000277 self._stopbits = stopbits
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200278 if self.is_open:
279 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000280
Chris Liechti779b1a22015-08-04 14:54:22 +0200281 @property
282 def timeout(self):
283 """Get the current timeout setting."""
284 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000285
Chris Liechti779b1a22015-08-04 14:54:22 +0200286 @timeout.setter
287 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000288 """Change timeout setting."""
289 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000290 try:
cliechti14b274a2009-02-07 00:27:05 +0000291 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000292 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100293 raise ValueError("Not a valid timeout: {!r}".format(timeout))
Chris Liechticf29a352015-10-23 22:03:40 +0200294 if timeout < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100295 raise ValueError("Not a valid timeout: {!r}".format(timeout))
cliechtid6bf52c2003-10-01 02:28:12 +0000296 self._timeout = timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200297 if self.is_open:
298 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000299
Chris Liechti779b1a22015-08-04 14:54:22 +0200300 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200301 def write_timeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000302 """Get the current timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200303 return self._write_timeout
cliechti14b274a2009-02-07 00:27:05 +0000304
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200305 @write_timeout.setter
306 def write_timeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000307 """Change timeout setting."""
308 if timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200309 if timeout < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100310 raise ValueError("Not a valid timeout: {!r}".format(timeout))
cliechti62611612004-04-20 01:55:43 +0000311 try:
Chris Liechti033f17c2015-08-30 21:28:04 +0200312 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti62611612004-04-20 01:55:43 +0000313 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100314 raise ValueError("Not a valid timeout: {!r}".format(timeout))
cliechti14b274a2009-02-07 00:27:05 +0000315
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200316 self._write_timeout = timeout
317 if self.is_open:
318 self._reconfigure_port()
319
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200320 @property
Chris Liechti518b0d32015-08-30 02:20:39 +0200321 def inter_byte_timeout(self):
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200322 """Get the current inter-character timeout setting."""
Chris Liechti96242372015-09-02 02:49:49 +0200323 return self._inter_byte_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200324
Chris Liechti518b0d32015-08-30 02:20:39 +0200325 @inter_byte_timeout.setter
326 def inter_byte_timeout(self, ic_timeout):
327 """Change inter-byte timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200328 if ic_timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200329 if ic_timeout < 0:
Chris Liechti984c5c52016-02-15 23:48:45 +0100330 raise ValueError("Not a valid timeout: {!r}".format(ic_timeout))
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200331 try:
332 ic_timeout + 1 # test if it's a number, will throw a TypeError if not...
333 except TypeError:
Chris Liechti984c5c52016-02-15 23:48:45 +0100334 raise ValueError("Not a valid timeout: {!r}".format(ic_timeout))
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200335
Chris Liechti518b0d32015-08-30 02:20:39 +0200336 self._inter_byte_timeout = ic_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200337 if self.is_open:
338 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000339
Chris Liechti779b1a22015-08-04 14:54:22 +0200340 @property
341 def xonxoff(self):
342 """Get the current XON/XOFF setting."""
343 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000344
Chris Liechti779b1a22015-08-04 14:54:22 +0200345 @xonxoff.setter
346 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000347 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000348 self._xonxoff = xonxoff
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200349 if self.is_open:
350 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000351
Chris Liechti779b1a22015-08-04 14:54:22 +0200352 @property
353 def rtscts(self):
354 """Get the current RTS/CTS flow control setting."""
355 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000356
Chris Liechti779b1a22015-08-04 14:54:22 +0200357 @rtscts.setter
358 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000359 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000360 self._rtscts = rtscts
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200361 if self.is_open:
362 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000363
Chris Liechti779b1a22015-08-04 14:54:22 +0200364 @property
365 def dsrdtr(self):
366 """Get the current DSR/DTR flow control setting."""
367 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000368
Chris Liechti779b1a22015-08-04 14:54:22 +0200369 @dsrdtr.setter
370 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000371 """Change DsrDtr flow control setting."""
372 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000373 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000374 self._dsrdtr = self._rtscts
375 else:
cliechti14b274a2009-02-07 00:27:05 +0000376 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000377 self._dsrdtr = dsrdtr
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
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200382 def rts(self):
383 return self._rts_state
cliechti679bfa62008-06-20 23:58:15 +0000384
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200385 @rts.setter
386 def rts(self, value):
387 self._rts_state = value
388 if self.is_open:
389 self._update_rts_state()
cliechti14b274a2009-02-07 00:27:05 +0000390
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200391 @property
392 def dtr(self):
393 return self._dtr_state
cliechti14b274a2009-02-07 00:27:05 +0000394
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200395 @dtr.setter
396 def dtr(self, value):
397 self._dtr_state = value
398 if self.is_open:
399 self._update_dtr_state()
400
401 @property
402 def break_condition(self):
403 return self._break_state
404
405 @break_condition.setter
406 def break_condition(self, value):
407 self._break_state = value
408 if self.is_open:
409 self._update_break_state()
cliechti679bfa62008-06-20 23:58:15 +0000410
cliechti4065dce2009-08-10 00:55:46 +0000411 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200412 # functions useful for RS-485 adapters
413
414 @property
415 def rs485_mode(self):
416 """\
417 Enable RS485 mode and apply new settings, set to None to disable.
418 See serial.rs485.RS485Settings for more info about the value.
419 """
420 return self._rs485_mode
421
422 @rs485_mode.setter
423 def rs485_mode(self, rs485_settings):
424 self._rs485_mode = rs485_settings
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200425 if self.is_open:
426 self._reconfigure_port()
Chris Liechti33f0ec52015-08-06 16:37:21 +0200427
428 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000429
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200430 _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
Chris Liechti033f17c2015-08-30 21:28:04 +0200431 'dsrdtr', 'rtscts', 'timeout', 'write_timeout',
Chris Liechti1c3249f2015-09-01 02:31:36 +0200432 'inter_byte_timeout')
cliechti4065dce2009-08-10 00:55:46 +0000433
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200434 def get_settings(self):
cliechti7d448562014-08-03 21:57:45 +0000435 """\
436 Get current port settings as a dictionary. For use with
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200437 apply_settings().
cliechti7d448562014-08-03 21:57:45 +0000438 """
Chris Liechti033f17c2015-08-30 21:28:04 +0200439 return dict([(key, getattr(self, '_' + key)) for key in self._SAVED_SETTINGS])
cliechti4065dce2009-08-10 00:55:46 +0000440
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200441 def apply_settings(self, d):
cliechti7d448562014-08-03 21:57:45 +0000442 """\
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200443 Apply stored settings from a dictionary returned from
444 get_settings(). It's allowed to delete keys from the dictionary. These
cliechti7d448562014-08-03 21:57:45 +0000445 values will simply left unchanged.
446 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200447 for key in self._SAVED_SETTINGS:
Chris Liechti033f17c2015-08-30 21:28:04 +0200448 if key in d and d[key] != getattr(self, '_' + key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000449 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000450
cliechtid6bf52c2003-10-01 02:28:12 +0000451 # - - - - - - - - - - - - - - - - - - - - - - - -
452
453 def __repr__(self):
454 """String representation of the current port settings and its state."""
Chris Liechti984c5c52016-02-15 23:48:45 +0100455 return '{name}<id=0x{id:x}, open={p.is_open}>(port={p.portstr!r}, ' \
456 'baudrate={p.baudrate!r}, bytesize={p.bytesize!r}, parity={p.parity!r}, ' \
457 'stopbits={p.stopbits!r}, timeout={p.timeout!r}, xonxoff={p.xonxoff!r}, ' \
458 'rtscts={p.rtscts!r}, dsrdtr={p.dsrdtr!r})'.format(
459 name=self.__class__.__name__, id=id(self), p=self)
cliechtid6bf52c2003-10-01 02:28:12 +0000460
cliechti4a567a02009-07-27 22:09:31 +0000461 # - - - - - - - - - - - - - - - - - - - - - - - -
462 # compatibility with io library
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100463 # pylint: disable=invalid-name,missing-docstring
cliechti4a567a02009-07-27 22:09:31 +0000464
Chris Liechti033f17c2015-08-30 21:28:04 +0200465 def readable(self):
466 return True
467
468 def writable(self):
469 return True
470
471 def seekable(self):
472 return False
473
cliechti4a567a02009-07-27 22:09:31 +0000474 def readinto(self, b):
475 data = self.read(len(b))
476 n = len(data)
477 try:
478 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200479 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000480 import array
481 if not isinstance(b, array.array):
482 raise err
483 b[:n] = array.array('b', data)
484 return n
cliechtif81362e2009-07-25 03:44:33 +0000485
Chris Liechti70b89232015-08-04 03:00:52 +0200486 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200487 # context manager
488
489 def __enter__(self):
490 return self
491
492 def __exit__(self, *args, **kwargs):
493 self.close()
494
495 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechtief1fe252015-08-27 23:25:21 +0200496
497 def send_break(self, duration=0.25):
498 """\
499 Send break condition. Timed, returns to idle state after given
500 duration.
501 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200502 if not self.is_open:
503 raise portNotOpenError
Chris Liechtief1fe252015-08-27 23:25:21 +0200504 self.break_condition = True
505 time.sleep(duration)
506 self.break_condition = False
507
508 # - - - - - - - - - - - - - - - - - - - - - - - -
509 # backwards compatibility / deprecated functions
510
511 def flushInput(self):
512 self.reset_input_buffer()
513
514 def flushOutput(self):
515 self.reset_output_buffer()
516
517 def inWaiting(self):
518 return self.in_waiting
519
520 def sendBreak(self, duration=0.25):
521 self.send_break(duration)
522
523 def setRTS(self, value=1):
524 self.rts = value
525
526 def setDTR(self, value=1):
527 self.dtr = value
528
529 def getCTS(self):
530 return self.cts
531
532 def getDSR(self):
533 return self.dsr
534
535 def getRI(self):
536 return self.ri
537
538 def getCD(self):
539 return self.cd
540
Chris Liechti0eba2a62016-04-06 02:55:51 +0200541 def setPort(self, port):
542 self.port = port
543
Chris Liechtief1fe252015-08-27 23:25:21 +0200544 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200545 def writeTimeout(self):
546 return self.write_timeout
547
548 @writeTimeout.setter
549 def writeTimeout(self, timeout):
550 self.write_timeout = timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200551
552 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200553 def interCharTimeout(self):
Chris Liechti96242372015-09-02 02:49:49 +0200554 return self.inter_byte_timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200555
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200556 @interCharTimeout.setter
557 def interCharTimeout(self, interCharTimeout):
Chris Liechti96242372015-09-02 02:49:49 +0200558 self.inter_byte_timeout = interCharTimeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200559
560 def getSettingsDict(self):
561 return self.get_settings()
562
563 def applySettingsDict(self, d):
564 self.apply_settings(d)
565
566 def isOpen(self):
Chris Liechti16843852015-09-22 23:24:35 +0200567 return self.is_open
Chris Liechtief1fe252015-08-27 23:25:21 +0200568
569 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200570 # additional functionality
571
David Howlett240f8fc2015-10-28 12:32:09 +0000572 def read_all(self):
Chris Liechti03cb8ed2015-10-30 23:37:24 +0100573 """\
574 Read all bytes currently available in the buffer of the OS.
575 """
David Howlett240f8fc2015-10-28 12:32:09 +0000576 return self.read(self.in_waiting)
577
Chris Liechti70b89232015-08-04 03:00:52 +0200578 def read_until(self, terminator=LF, size=None):
579 """\
580 Read until a termination sequence is found ('\n' by default), the size
581 is exceeded or until timeout occurs.
582 """
583 lenterm = len(terminator)
584 line = bytearray()
585 while True:
586 c = self.read(1)
587 if c:
588 line += c
589 if line[-lenterm:] == terminator:
590 break
591 if size is not None and len(line) >= size:
592 break
593 else:
594 break
595 return bytes(line)
596
Chris Liechti70b89232015-08-04 03:00:52 +0200597 def iread_until(self, *args, **kwargs):
598 """\
599 Read lines, implemented as generator. It will raise StopIteration on
600 timeout (empty read).
601 """
602 while True:
603 line = self.read_until(*args, **kwargs)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200604 if not line:
605 break
Chris Liechti70b89232015-08-04 03:00:52 +0200606 yield line
cliechtif81362e2009-07-25 03:44:33 +0000607
Chris Liechti779b1a22015-08-04 14:54:22 +0200608
609# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000610if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000611 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000612 s = SerialBase()
Chris Liechti984c5c52016-02-15 23:48:45 +0100613 sys.stdout.write('port name: {}\n'.format(s.name))
614 sys.stdout.write('baud rates: {}\n'.format(s.BAUDRATES))
615 sys.stdout.write('byte sizes: {}\n'.format(s.BYTESIZES))
616 sys.stdout.write('parities: {}\n'.format(s.PARITIES))
617 sys.stdout.write('stop bits: {}\n'.format(s.STOPBITS))
618 sys.stdout.write('{}\n'.format(s))