blob: 9bd223fe357fc016dee03be818cf576a79b1aeb8 [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
130 self._isOpen = 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
137 self._writeTimeout = None # correct value is assigned below through properties
138 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
141 self._interCharTimeout = None # correct value is assigned below through properties
Chris Liechti33f0ec52015-08-06 16:37:21 +0200142 self._rs485_mode = None # disabled by default
cliechti14b274a2009-02-07 00:27:05 +0000143
144 # assign values using get/set methods using the properties feature
cliechtid6bf52c2003-10-01 02:28:12 +0000145 self.port = port
146 self.baudrate = baudrate
147 self.bytesize = bytesize
148 self.parity = parity
149 self.stopbits = stopbits
150 self.timeout = timeout
cliechti62611612004-04-20 01:55:43 +0000151 self.writeTimeout = writeTimeout
cliechtid6bf52c2003-10-01 02:28:12 +0000152 self.xonxoff = xonxoff
153 self.rtscts = rtscts
cliechtif46e0a82005-05-19 15:24:57 +0000154 self.dsrdtr = dsrdtr
cliechti679bfa62008-06-20 23:58:15 +0000155 self.interCharTimeout = interCharTimeout
cliechti14b274a2009-02-07 00:27:05 +0000156
cliechtid6bf52c2003-10-01 02:28:12 +0000157 if port is not None:
158 self.open()
159
160 def isOpen(self):
161 """Check if the port is opened."""
162 return self._isOpen
163
cliechtid6bf52c2003-10-01 02:28:12 +0000164
165 # - - - - - - - - - - - - - - - - - - - - - - - -
166
Chris Liechti779b1a22015-08-04 14:54:22 +0200167 @property
168 def port(self):
169 """\
170 Get the current port setting. The value that was passed on init or using
171 setPort() is passed back. See also the attribute portstr which contains
172 the name of the port as a string.
173 """
174 return self._port
175
176 @port.setter
177 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000178 """\
179 Change the port. The attribute portstr is set to a string that
180 contains the name of the port.
181 """
cliechti14b274a2009-02-07 00:27:05 +0000182
cliechtid6bf52c2003-10-01 02:28:12 +0000183 was_open = self._isOpen
184 if was_open: self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200185 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000186 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000187 self.name = self.portstr
cliechtid6bf52c2003-10-01 02:28:12 +0000188 if was_open: 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
cliechti107db8d2004-01-15 01:20:23 +0000211 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000212
cliechti14b274a2009-02-07 00:27:05 +0000213
Chris Liechti779b1a22015-08-04 14:54:22 +0200214 @property
215 def bytesize(self):
216 """Get the current byte size setting."""
217 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000218
Chris Liechti779b1a22015-08-04 14:54:22 +0200219 @bytesize.setter
220 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000221 """Change byte size."""
cliechti93db61b2006-08-26 19:16:18 +0000222 if bytesize not in self.BYTESIZES: raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000223 self._bytesize = bytesize
224 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000225
cliechtid6bf52c2003-10-01 02:28:12 +0000226
227
Chris Liechti779b1a22015-08-04 14:54:22 +0200228 @property
229 def parity(self):
230 """Get the current parity setting."""
231 return self._parity
232
233 @parity.setter
234 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000235 """Change parity setting."""
cliechti93db61b2006-08-26 19:16:18 +0000236 if parity not in self.PARITIES: raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000237 self._parity = parity
238 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000239
cliechtid6bf52c2003-10-01 02:28:12 +0000240
241
Chris Liechti779b1a22015-08-04 14:54:22 +0200242 @property
243 def stopbits(self):
244 """Get the current stop bits setting."""
245 return self._stopbits
246
247 @stopbits.setter
248 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000249 """Change stop bits size."""
250 if stopbits not in self.STOPBITS: raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000251 self._stopbits = stopbits
252 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000253
cliechti14b274a2009-02-07 00:27:05 +0000254
Chris Liechti779b1a22015-08-04 14:54:22 +0200255 @property
256 def timeout(self):
257 """Get the current timeout setting."""
258 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000259
Chris Liechti779b1a22015-08-04 14:54:22 +0200260 @timeout.setter
261 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000262 """Change timeout setting."""
263 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000264 try:
cliechti14b274a2009-02-07 00:27:05 +0000265 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000266 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000267 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti2750b832009-07-28 00:13:52 +0000268 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000269 self._timeout = timeout
270 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000271
Chris Liechti779b1a22015-08-04 14:54:22 +0200272
273 @property
274 def writeTimeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000275 """Get the current timeout setting."""
Chris Liechti779b1a22015-08-04 14:54:22 +0200276 return self._writeTimeout
cliechti14b274a2009-02-07 00:27:05 +0000277
Chris Liechti779b1a22015-08-04 14:54:22 +0200278 @writeTimeout.setter
279 def writeTimeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000280 """Change timeout setting."""
281 if timeout is not None:
cliechti93db61b2006-08-26 19:16:18 +0000282 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000283 try:
284 timeout + 1 #test if it's a number, will throw a TypeError if not...
285 except TypeError:
286 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000287
cliechti62611612004-04-20 01:55:43 +0000288 self._writeTimeout = timeout
289 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000290
cliechti14b274a2009-02-07 00:27:05 +0000291
Chris Liechti779b1a22015-08-04 14:54:22 +0200292 @property
293 def xonxoff(self):
294 """Get the current XON/XOFF setting."""
295 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000296
Chris Liechti779b1a22015-08-04 14:54:22 +0200297 @xonxoff.setter
298 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000299 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000300 self._xonxoff = xonxoff
301 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000302
cliechti14b274a2009-02-07 00:27:05 +0000303
Chris Liechti779b1a22015-08-04 14:54:22 +0200304 @property
305 def rtscts(self):
306 """Get the current RTS/CTS flow control setting."""
307 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000308
Chris Liechti779b1a22015-08-04 14:54:22 +0200309 @rtscts.setter
310 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000311 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000312 self._rtscts = rtscts
313 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000314
cliechti14b274a2009-02-07 00:27:05 +0000315
Chris Liechti779b1a22015-08-04 14:54:22 +0200316 @property
317 def dsrdtr(self):
318 """Get the current DSR/DTR flow control setting."""
319 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000320
Chris Liechti779b1a22015-08-04 14:54:22 +0200321 @dsrdtr.setter
322 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000323 """Change DsrDtr flow control setting."""
324 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000325 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000326 self._dsrdtr = self._rtscts
327 else:
cliechti14b274a2009-02-07 00:27:05 +0000328 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000329 self._dsrdtr = dsrdtr
330 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000331
cliechti14b274a2009-02-07 00:27:05 +0000332
Chris Liechti779b1a22015-08-04 14:54:22 +0200333 @property
334 def interCharTimeout(self):
335 """Get the current inter-character timeout setting."""
336 return self._interCharTimeout
cliechti679bfa62008-06-20 23:58:15 +0000337
Chris Liechti779b1a22015-08-04 14:54:22 +0200338 @interCharTimeout.setter
339 def interCharTimeout(self, interCharTimeout):
cliechti679bfa62008-06-20 23:58:15 +0000340 """Change inter-character timeout setting."""
341 if interCharTimeout is not None:
342 if interCharTimeout < 0: raise ValueError("Not a valid timeout: %r" % interCharTimeout)
343 try:
cliechti14b274a2009-02-07 00:27:05 +0000344 interCharTimeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti679bfa62008-06-20 23:58:15 +0000345 except TypeError:
346 raise ValueError("Not a valid timeout: %r" % interCharTimeout)
cliechti14b274a2009-02-07 00:27:05 +0000347
cliechti679bfa62008-06-20 23:58:15 +0000348 self._interCharTimeout = interCharTimeout
349 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000350
cliechti679bfa62008-06-20 23:58:15 +0000351
cliechti4065dce2009-08-10 00:55:46 +0000352 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200353 # functions useful for RS-485 adapters
354
355 @property
356 def rs485_mode(self):
357 """\
358 Enable RS485 mode and apply new settings, set to None to disable.
359 See serial.rs485.RS485Settings for more info about the value.
360 """
361 return self._rs485_mode
362
363 @rs485_mode.setter
364 def rs485_mode(self, rs485_settings):
365 self._rs485_mode = rs485_settings
366 if self._isOpen: self._reconfigurePort()
367
368 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000369
370 _SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
371 'dsrdtr', 'rtscts', 'timeout', 'writeTimeout', 'interCharTimeout')
372
373 def getSettingsDict(self):
cliechti7d448562014-08-03 21:57:45 +0000374 """\
375 Get current port settings as a dictionary. For use with
376 applySettingsDict.
377 """
cliechti4065dce2009-08-10 00:55:46 +0000378 return dict([(key, getattr(self, '_'+key)) for key in self._SETTINGS])
379
380 def applySettingsDict(self, d):
cliechti7d448562014-08-03 21:57:45 +0000381 """\
382 apply stored settings from a dictionary returned from
cliechti4065dce2009-08-10 00:55:46 +0000383 getSettingsDict. it's allowed to delete keys from the dictionary. these
cliechti7d448562014-08-03 21:57:45 +0000384 values will simply left unchanged.
385 """
cliechti4065dce2009-08-10 00:55:46 +0000386 for key in self._SETTINGS:
Chris Liechtib74be012015-08-04 16:36:01 +0200387 if key in d and d[key] != getattr(self, '_'+key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000388 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000389
cliechtid6bf52c2003-10-01 02:28:12 +0000390 # - - - - - - - - - - - - - - - - - - - - - - - -
391
392 def __repr__(self):
393 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000394 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)" % (
cliechtid6bf52c2003-10-01 02:28:12 +0000395 self.__class__.__name__,
396 id(self),
397 self._isOpen,
398 self.portstr,
399 self.baudrate,
400 self.bytesize,
401 self.parity,
402 self.stopbits,
403 self.timeout,
404 self.xonxoff,
405 self.rtscts,
cliechtif46e0a82005-05-19 15:24:57 +0000406 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000407 )
408
cliechti4a567a02009-07-27 22:09:31 +0000409
410 # - - - - - - - - - - - - - - - - - - - - - - - -
411 # compatibility with io library
412
413 def readable(self): return True
414 def writable(self): return True
415 def seekable(self): return False
416 def readinto(self, b):
417 data = self.read(len(b))
418 n = len(data)
419 try:
420 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200421 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000422 import array
423 if not isinstance(b, array.array):
424 raise err
425 b[:n] = array.array('b', data)
426 return n
cliechtif81362e2009-07-25 03:44:33 +0000427
Chris Liechti70b89232015-08-04 03:00:52 +0200428 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200429 # context manager
430
431 def __enter__(self):
432 return self
433
434 def __exit__(self, *args, **kwargs):
435 self.close()
436
437 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200438 # additional functionality
439
440 def read_until(self, terminator=LF, size=None):
441 """\
442 Read until a termination sequence is found ('\n' by default), the size
443 is exceeded or until timeout occurs.
444 """
445 lenterm = len(terminator)
446 line = bytearray()
447 while True:
448 c = self.read(1)
449 if c:
450 line += c
451 if line[-lenterm:] == terminator:
452 break
453 if size is not None and len(line) >= size:
454 break
455 else:
456 break
457 return bytes(line)
458
459
460 def iread_until(self, *args, **kwargs):
461 """\
462 Read lines, implemented as generator. It will raise StopIteration on
463 timeout (empty read).
464 """
465 while True:
466 line = self.read_until(*args, **kwargs)
467 if not line: break
468 yield line
cliechtif81362e2009-07-25 03:44:33 +0000469
Chris Liechti779b1a22015-08-04 14:54:22 +0200470
471# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000472if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000473 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000474 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200475 sys.stdout.write('port name: %s\n' % s.name)
476 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
477 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
478 sys.stdout.write('parities: %s\n' % s.PARITIES)
479 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000480 sys.stdout.write('%s\n' % s)