blob: 5e3597b4f32df07eba6023c2d2844cf82c063483 [file] [log] [blame]
cliechtid6bf52c2003-10-01 02:28:12 +00001#! python
cliechtic54b2c82008-06-21 01:59:08 +00002# Python Serial Port Extension for Win32, Linux, BSD, Jython
3# see __init__.py
cliechtid6bf52c2003-10-01 02:28:12 +00004#
Chris Liechti68340d72015-08-03 14:15:48 +02005# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
Chris Liechtifbdd8a02015-08-09 02:37:45 +02006#
7# SPDX-License-Identifier: BSD-3-Clause
cliechtid6bf52c2003-10-01 02:28:12 +00008
Chris Liechtief6b7b42015-08-06 22:19:26 +02009import io
cliechtic323f1f2010-07-22 00:14:26 +000010
cliechti38077122013-10-16 02:57:27 +000011# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)``
12# isn't returning the contents (very unfortunate). Therefore we need special
13# cases and test for it. Ensure that there is a ``memoryview`` object for older
14# Python versions. This is easier than making every test dependent on its
15# existence.
16try:
17 memoryview
18except (NameError, AttributeError):
19 # implementation does not matter as we do not realy use it.
20 # it just must not inherit from something else we might care for.
Chris Liechti70b89232015-08-04 03:00:52 +020021 class memoryview(object):
cliechti38077122013-10-16 02:57:27 +000022 pass
23
24
Chris Liechtif99cd5c2015-08-13 22:54:16 +020025# "for byte in data" fails for python3 as it returns ints instead of bytes
26def iterbytes(b):
27 """Iterate over bytes, returning bytes instead of ints (python3)"""
Chris Liechti12a439f2015-08-20 23:01:53 +020028 if isinstance(b, memoryview):
29 b = b.tobytes()
Chris Liechtif99cd5c2015-08-13 22:54:16 +020030 x = 0
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020031 while True:
Chris Liechtif99cd5c2015-08-13 22:54:16 +020032 a = b[x:x+1]
33 x += 1
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020034 if a:
35 yield a
36 else:
37 break
38
cliechti38077122013-10-16 02:57:27 +000039# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
40# so a simple ``bytes(sequence)`` doesn't work for all versions
cliechti32c10332009-08-05 13:23:43 +000041def to_bytes(seq):
42 """convert a sequence to a bytes type"""
cliechti38077122013-10-16 02:57:27 +000043 if isinstance(seq, bytes):
44 return seq
45 elif isinstance(seq, bytearray):
46 return bytes(seq)
47 elif isinstance(seq, memoryview):
48 return seq.tobytes()
49 else:
50 b = bytearray()
51 for item in seq:
Chris Liechti07447732015-08-05 00:39:12 +020052 # this one handles int and bytes in Python 2.7
53 # add conversion in case of Python 3.x
54 if isinstance(item, bytes):
55 item = ord(item)
56 b.append(item)
cliechti38077122013-10-16 02:57:27 +000057 return bytes(b)
cliechti32c10332009-08-05 13:23:43 +000058
59# create control bytes
60XON = to_bytes([17])
61XOFF = to_bytes([19])
cliechti4a567a02009-07-27 22:09:31 +000062
cliechti8e99b6f2010-07-21 15:46:39 +000063CR = to_bytes([13])
64LF = to_bytes([10])
65
cliechtia3a811f2009-07-29 21:59:03 +000066
cliechti0d6029a2008-06-21 01:28:46 +000067PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
cliechti58b481c2009-02-16 20:42:32 +000068STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
cliechti14b274a2009-02-07 00:27:05 +000069FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
cliechtid6bf52c2003-10-01 02:28:12 +000070
71PARITY_NAMES = {
cliechti4a567a02009-07-27 22:09:31 +000072 PARITY_NONE: 'None',
73 PARITY_EVEN: 'Even',
74 PARITY_ODD: 'Odd',
75 PARITY_MARK: 'Mark',
76 PARITY_SPACE: 'Space',
cliechtid6bf52c2003-10-01 02:28:12 +000077}
78
cliechti1dbe4b62002-02-14 02:49:25 +000079
cliechti4a567a02009-07-27 22:09:31 +000080class SerialException(IOError):
cliechtid6bf52c2003-10-01 02:28:12 +000081 """Base class for serial port related exceptions."""
cliechti7fe54d52002-03-03 20:11:47 +000082
cliechtid6bf52c2003-10-01 02:28:12 +000083
cliechti62611612004-04-20 01:55:43 +000084class SerialTimeoutException(SerialException):
85 """Write timeouts give an exception"""
86
cliechti4a567a02009-07-27 22:09:31 +000087
cliechti4b20ec62012-08-16 01:04:44 +000088writeTimeoutError = SerialTimeoutException('Write timeout')
89portNotOpenError = SerialException('Attempting to use a port that is not open')
cliechti62611612004-04-20 01:55:43 +000090
cliechtif81362e2009-07-25 03:44:33 +000091
Chris Liechtief6b7b42015-08-06 22:19:26 +020092class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +000093 """\
94 Serial port base class. Provides __init__ function and properties to
95 get/set port settings.
96 """
cliechti14b274a2009-02-07 00:27:05 +000097
cliechtidfec0c82009-07-21 01:35:41 +000098 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +000099 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
100 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
101 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
102 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +0000103 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
cliechti14b274a2009-02-07 00:27:05 +0000104 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
cliechti6ffdb8f2009-07-22 00:48:57 +0000105 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +0000106
cliechtid6bf52c2003-10-01 02:28:12 +0000107 def __init__(self,
cliechti14b274a2009-02-07 00:27:05 +0000108 port = None, # number of device, numbering starts at
109 # zero. if everything fails, the user
110 # can specify a device string, note
111 # that this isn't portable anymore
112 # port will be opened if one is specified
cliechtidfec0c82009-07-21 01:35:41 +0000113 baudrate=9600, # baud rate
114 bytesize=EIGHTBITS, # number of data bits
cliechti14b274a2009-02-07 00:27:05 +0000115 parity=PARITY_NONE, # enable parity checking
cliechtidfec0c82009-07-21 01:35:41 +0000116 stopbits=STOPBITS_ONE, # number of stop bits
cliechti14b274a2009-02-07 00:27:05 +0000117 timeout=None, # set a timeout value, None to wait forever
cliechti74308e42010-07-21 14:03:59 +0000118 xonxoff=False, # enable software flow control
119 rtscts=False, # enable RTS/CTS flow control
cliechti14b274a2009-02-07 00:27:05 +0000120 writeTimeout=None, # set a timeout for writes
cliechti58a2aee2010-05-20 23:37:57 +0000121 dsrdtr=False, # None: use rtscts setting, dsrdtr override if True or False
cliechti14b274a2009-02-07 00:27:05 +0000122 interCharTimeout=None # Inter-character timeout, None to disable
cliechtid6bf52c2003-10-01 02:28:12 +0000123 ):
cliechti7d448562014-08-03 21:57:45 +0000124 """\
125 Initialize comm port object. If a port is given, then the port will be
126 opened immediately. Otherwise a Serial port object in closed state
127 is returned.
128 """
cliechtid6bf52c2003-10-01 02:28:12 +0000129
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200130 self.is_open = False
cliechti4a567a02009-07-27 22:09:31 +0000131 self._port = None # correct value is assigned below through properties
132 self._baudrate = None # correct value is assigned below through properties
133 self._bytesize = None # correct value is assigned below through properties
134 self._parity = None # correct value is assigned below through properties
135 self._stopbits = None # correct value is assigned below through properties
136 self._timeout = None # correct value is assigned below through properties
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200137 self._write_timeout = None # correct value is assigned below through properties
cliechti4a567a02009-07-27 22:09:31 +0000138 self._xonxoff = None # correct value is assigned below through properties
139 self._rtscts = None # correct value is assigned below through properties
140 self._dsrdtr = None # correct value is assigned below through properties
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200141 self._inter_character_timeout = None # correct value is assigned below through properties
Chris Liechti33f0ec52015-08-06 16:37:21 +0200142 self._rs485_mode = None # disabled by default
Chris Liechtief1fe252015-08-27 23:25:21 +0200143 self._rts_state = True
144 self._dtr_state = True
145 self._break_state = False
cliechti14b274a2009-02-07 00:27:05 +0000146
147 # assign values using get/set methods using the properties feature
cliechtid6bf52c2003-10-01 02:28:12 +0000148 self.port = port
149 self.baudrate = baudrate
150 self.bytesize = bytesize
151 self.parity = parity
152 self.stopbits = stopbits
153 self.timeout = timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200154 self.write_timeout = writeTimeout
cliechtid6bf52c2003-10-01 02:28:12 +0000155 self.xonxoff = xonxoff
156 self.rtscts = rtscts
cliechtif46e0a82005-05-19 15:24:57 +0000157 self.dsrdtr = dsrdtr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200158 self.inter_character_timeout = interCharTimeout
cliechti14b274a2009-02-07 00:27:05 +0000159
cliechtid6bf52c2003-10-01 02:28:12 +0000160 if port is not None:
161 self.open()
162
cliechtid6bf52c2003-10-01 02:28:12 +0000163 # - - - - - - - - - - - - - - - - - - - - - - - -
164
Chris Liechti779b1a22015-08-04 14:54:22 +0200165 @property
166 def port(self):
167 """\
168 Get the current port setting. The value that was passed on init or using
169 setPort() is passed back. See also the attribute portstr which contains
170 the name of the port as a string.
171 """
172 return self._port
173
174 @port.setter
175 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000176 """\
177 Change the port. The attribute portstr is set to a string that
178 contains the name of the port.
179 """
cliechti14b274a2009-02-07 00:27:05 +0000180
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200181 was_open = self.is_open
182 if was_open:
183 self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200184 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000185 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000186 self.name = self.portstr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200187 if was_open:
188 self.open()
cliechti14b274a2009-02-07 00:27:05 +0000189
cliechtid6bf52c2003-10-01 02:28:12 +0000190
Chris Liechti779b1a22015-08-04 14:54:22 +0200191 @property
192 def baudrate(self):
193 """Get the current baud rate setting."""
194 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000195
Chris Liechti779b1a22015-08-04 14:54:22 +0200196 @baudrate.setter
197 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000198 """\
199 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000200 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000201 accepted and the exception is raised when the port is opened.
202 """
cliechti107db8d2004-01-15 01:20:23 +0000203 try:
cliechtie30868d2013-10-16 15:35:11 +0000204 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000205 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000206 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
cliechti107db8d2004-01-15 01:20:23 +0000207 else:
cliechtie30868d2013-10-16 15:35:11 +0000208 if b <= 0:
209 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
210 self._baudrate = b
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200211 if self.is_open:
212 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000213
cliechti14b274a2009-02-07 00:27:05 +0000214
Chris Liechti779b1a22015-08-04 14:54:22 +0200215 @property
216 def bytesize(self):
217 """Get the current byte size setting."""
218 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000219
Chris Liechti779b1a22015-08-04 14:54:22 +0200220 @bytesize.setter
221 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000222 """Change byte size."""
cliechti93db61b2006-08-26 19:16:18 +0000223 if bytesize not in self.BYTESIZES: raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000224 self._bytesize = bytesize
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200225 if self.is_open:
226 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000227
cliechtid6bf52c2003-10-01 02:28:12 +0000228
229
Chris Liechti779b1a22015-08-04 14:54:22 +0200230 @property
231 def parity(self):
232 """Get the current parity setting."""
233 return self._parity
234
235 @parity.setter
236 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000237 """Change parity setting."""
cliechti93db61b2006-08-26 19:16:18 +0000238 if parity not in self.PARITIES: raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000239 self._parity = parity
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200240 if self.is_open:
241 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000242
cliechtid6bf52c2003-10-01 02:28:12 +0000243
244
Chris Liechti779b1a22015-08-04 14:54:22 +0200245 @property
246 def stopbits(self):
247 """Get the current stop bits setting."""
248 return self._stopbits
249
250 @stopbits.setter
251 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000252 """Change stop bits size."""
253 if stopbits not in self.STOPBITS: raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000254 self._stopbits = stopbits
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200255 if self.is_open:
256 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000257
cliechti14b274a2009-02-07 00:27:05 +0000258
Chris Liechti779b1a22015-08-04 14:54:22 +0200259 @property
260 def timeout(self):
261 """Get the current timeout setting."""
262 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000263
Chris Liechti779b1a22015-08-04 14:54:22 +0200264 @timeout.setter
265 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000266 """Change timeout setting."""
267 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000268 try:
cliechti14b274a2009-02-07 00:27:05 +0000269 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000270 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000271 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti2750b832009-07-28 00:13:52 +0000272 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000273 self._timeout = timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200274 if self.is_open:
275 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000276
Chris Liechti779b1a22015-08-04 14:54:22 +0200277
278 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200279 def write_timeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000280 """Get the current timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200281 return self._write_timeout
cliechti14b274a2009-02-07 00:27:05 +0000282
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200283 @write_timeout.setter
284 def write_timeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000285 """Change timeout setting."""
286 if timeout is not None:
cliechti93db61b2006-08-26 19:16:18 +0000287 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000288 try:
289 timeout + 1 #test if it's a number, will throw a TypeError if not...
290 except TypeError:
291 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000292
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200293 self._write_timeout = timeout
294 if self.is_open:
295 self._reconfigure_port()
296
297
298 @property
299 def inter_character_timeout(self):
300 """Get the current inter-character timeout setting."""
301 return self._interCharTimeout
302
303 @inter_character_timeout.setter
304 def inter_character_timeout(self, ic_timeout):
305 """Change inter-character timeout setting."""
306 if ic_timeout is not None:
307 if ic_timeout < 0: raise ValueError("Not a valid timeout: %r" % ic_timeout)
308 try:
309 ic_timeout + 1 # test if it's a number, will throw a TypeError if not...
310 except TypeError:
311 raise ValueError("Not a valid timeout: %r" % ic_timeout)
312
313 self._interCharTimeout = ic_timeout
314 if self.is_open:
315 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000316
cliechti14b274a2009-02-07 00:27:05 +0000317
Chris Liechti779b1a22015-08-04 14:54:22 +0200318 @property
319 def xonxoff(self):
320 """Get the current XON/XOFF setting."""
321 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000322
Chris Liechti779b1a22015-08-04 14:54:22 +0200323 @xonxoff.setter
324 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000325 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000326 self._xonxoff = xonxoff
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200327 if self.is_open:
328 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000329
cliechti14b274a2009-02-07 00:27:05 +0000330
Chris Liechti779b1a22015-08-04 14:54:22 +0200331 @property
332 def rtscts(self):
333 """Get the current RTS/CTS flow control setting."""
334 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000335
Chris Liechti779b1a22015-08-04 14:54:22 +0200336 @rtscts.setter
337 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000338 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000339 self._rtscts = rtscts
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200340 if self.is_open:
341 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000342
cliechti14b274a2009-02-07 00:27:05 +0000343
Chris Liechti779b1a22015-08-04 14:54:22 +0200344 @property
345 def dsrdtr(self):
346 """Get the current DSR/DTR flow control setting."""
347 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000348
Chris Liechti779b1a22015-08-04 14:54:22 +0200349 @dsrdtr.setter
350 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000351 """Change DsrDtr flow control setting."""
352 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000353 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000354 self._dsrdtr = self._rtscts
355 else:
cliechti14b274a2009-02-07 00:27:05 +0000356 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000357 self._dsrdtr = dsrdtr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200358 if self.is_open:
359 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000360
cliechti14b274a2009-02-07 00:27:05 +0000361
Chris Liechti779b1a22015-08-04 14:54:22 +0200362 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200363 def rts(self):
364 return self._rts_state
cliechti679bfa62008-06-20 23:58:15 +0000365
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200366 @rts.setter
367 def rts(self, value):
368 self._rts_state = value
369 if self.is_open:
370 self._update_rts_state()
cliechti14b274a2009-02-07 00:27:05 +0000371
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200372 @property
373 def dtr(self):
374 return self._dtr_state
cliechti14b274a2009-02-07 00:27:05 +0000375
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200376 @dtr.setter
377 def dtr(self, value):
378 self._dtr_state = value
379 if self.is_open:
380 self._update_dtr_state()
381
382 @property
383 def break_condition(self):
384 return self._break_state
385
386 @break_condition.setter
387 def break_condition(self, value):
388 self._break_state = value
389 if self.is_open:
390 self._update_break_state()
cliechti679bfa62008-06-20 23:58:15 +0000391
cliechti4065dce2009-08-10 00:55:46 +0000392 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200393 # functions useful for RS-485 adapters
394
395 @property
396 def rs485_mode(self):
397 """\
398 Enable RS485 mode and apply new settings, set to None to disable.
399 See serial.rs485.RS485Settings for more info about the value.
400 """
401 return self._rs485_mode
402
403 @rs485_mode.setter
404 def rs485_mode(self, rs485_settings):
405 self._rs485_mode = rs485_settings
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200406 if self.is_open:
407 self._reconfigure_port()
Chris Liechti33f0ec52015-08-06 16:37:21 +0200408
409 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000410
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200411 _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
412 'dsrdtr', 'rtscts', 'timeout', 'write_timeout', 'inter_character_timeout')
cliechti4065dce2009-08-10 00:55:46 +0000413
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200414 def get_settings(self):
cliechti7d448562014-08-03 21:57:45 +0000415 """\
416 Get current port settings as a dictionary. For use with
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200417 apply_settings().
cliechti7d448562014-08-03 21:57:45 +0000418 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200419 return dict([(key, getattr(self, '_'+key)) for key in self._SAVED_SETTINGS])
cliechti4065dce2009-08-10 00:55:46 +0000420
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200421 def apply_settings(self, d):
cliechti7d448562014-08-03 21:57:45 +0000422 """\
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200423 Apply stored settings from a dictionary returned from
424 get_settings(). It's allowed to delete keys from the dictionary. These
cliechti7d448562014-08-03 21:57:45 +0000425 values will simply left unchanged.
426 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200427 for key in self._SAVED_SETTINGS:
Chris Liechtib74be012015-08-04 16:36:01 +0200428 if key in d and d[key] != getattr(self, '_'+key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000429 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000430
cliechtid6bf52c2003-10-01 02:28:12 +0000431 # - - - - - - - - - - - - - - - - - - - - - - - -
432
433 def __repr__(self):
434 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000435 return "%s<id=0x%x, open=%s>(port=%r, baudrate=%r, bytesize=%r, parity=%r, stopbits=%r, timeout=%r, xonxoff=%r, rtscts=%r, dsrdtr=%r)" % (
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200436 self.__class__.__name__,
437 id(self),
438 self.is_open,
439 self.portstr,
440 self.baudrate,
441 self.bytesize,
442 self.parity,
443 self.stopbits,
444 self.timeout,
445 self.xonxoff,
446 self.rtscts,
447 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000448 )
449
cliechti4a567a02009-07-27 22:09:31 +0000450
451 # - - - - - - - - - - - - - - - - - - - - - - - -
452 # compatibility with io library
453
454 def readable(self): return True
455 def writable(self): return True
456 def seekable(self): return False
457 def readinto(self, b):
458 data = self.read(len(b))
459 n = len(data)
460 try:
461 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200462 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000463 import array
464 if not isinstance(b, array.array):
465 raise err
466 b[:n] = array.array('b', data)
467 return n
cliechtif81362e2009-07-25 03:44:33 +0000468
Chris Liechti70b89232015-08-04 03:00:52 +0200469 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200470 # context manager
471
472 def __enter__(self):
473 return self
474
475 def __exit__(self, *args, **kwargs):
476 self.close()
477
478 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechtief1fe252015-08-27 23:25:21 +0200479
480 def send_break(self, duration=0.25):
481 """\
482 Send break condition. Timed, returns to idle state after given
483 duration.
484 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200485 if not self.is_open:
486 raise portNotOpenError
Chris Liechtief1fe252015-08-27 23:25:21 +0200487 self.break_condition = True
488 time.sleep(duration)
489 self.break_condition = False
490
491 # - - - - - - - - - - - - - - - - - - - - - - - -
492 # backwards compatibility / deprecated functions
493
494 def flushInput(self):
495 self.reset_input_buffer()
496
497 def flushOutput(self):
498 self.reset_output_buffer()
499
500 def inWaiting(self):
501 return self.in_waiting
502
503 def sendBreak(self, duration=0.25):
504 self.send_break(duration)
505
506 def setRTS(self, value=1):
507 self.rts = value
508
509 def setDTR(self, value=1):
510 self.dtr = value
511
512 def getCTS(self):
513 return self.cts
514
515 def getDSR(self):
516 return self.dsr
517
518 def getRI(self):
519 return self.ri
520
521 def getCD(self):
522 return self.cd
523
524 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200525 def writeTimeout(self):
526 return self.write_timeout
527
528 @writeTimeout.setter
529 def writeTimeout(self, timeout):
530 self.write_timeout = timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200531
532 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200533 def interCharTimeout(self):
534 return self.inter_character_timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200535
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200536 @interCharTimeout.setter
537 def interCharTimeout(self, interCharTimeout):
538 self.inter_character_timeout = interCharTimeout
539
540 def getSettingsDict(self):
541 return self.get_settings()
542
543 def applySettingsDict(self, d):
544 self.apply_settings(d)
545
546 def isOpen(self):
547 return self._is_open
Chris Liechtief1fe252015-08-27 23:25:21 +0200548
549 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200550 # additional functionality
551
552 def read_until(self, terminator=LF, size=None):
553 """\
554 Read until a termination sequence is found ('\n' by default), the size
555 is exceeded or until timeout occurs.
556 """
557 lenterm = len(terminator)
558 line = bytearray()
559 while True:
560 c = self.read(1)
561 if c:
562 line += c
563 if line[-lenterm:] == terminator:
564 break
565 if size is not None and len(line) >= size:
566 break
567 else:
568 break
569 return bytes(line)
570
571
572 def iread_until(self, *args, **kwargs):
573 """\
574 Read lines, implemented as generator. It will raise StopIteration on
575 timeout (empty read).
576 """
577 while True:
578 line = self.read_until(*args, **kwargs)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200579 if not line:
580 break
Chris Liechti70b89232015-08-04 03:00:52 +0200581 yield line
cliechtif81362e2009-07-25 03:44:33 +0000582
Chris Liechti779b1a22015-08-04 14:54:22 +0200583
584# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000585if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000586 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000587 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200588 sys.stdout.write('port name: %s\n' % s.name)
589 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
590 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
591 sys.stdout.write('parities: %s\n' % s.PARITIES)
592 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000593 sys.stdout.write('%s\n' % s)