blob: e20196d48ad635c772fc47db03f10965e3a8ead6 [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)"""
28 x = 0
29 a = True
30 while a:
31 a = b[x:x+1]
32 x += 1
33 yield a
34
cliechti38077122013-10-16 02:57:27 +000035# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
36# so a simple ``bytes(sequence)`` doesn't work for all versions
cliechti32c10332009-08-05 13:23:43 +000037def to_bytes(seq):
38 """convert a sequence to a bytes type"""
cliechti38077122013-10-16 02:57:27 +000039 if isinstance(seq, bytes):
40 return seq
41 elif isinstance(seq, bytearray):
42 return bytes(seq)
43 elif isinstance(seq, memoryview):
44 return seq.tobytes()
45 else:
46 b = bytearray()
47 for item in seq:
Chris Liechti07447732015-08-05 00:39:12 +020048 # this one handles int and bytes in Python 2.7
49 # add conversion in case of Python 3.x
50 if isinstance(item, bytes):
51 item = ord(item)
52 b.append(item)
cliechti38077122013-10-16 02:57:27 +000053 return bytes(b)
cliechti32c10332009-08-05 13:23:43 +000054
55# create control bytes
56XON = to_bytes([17])
57XOFF = to_bytes([19])
cliechti4a567a02009-07-27 22:09:31 +000058
cliechti8e99b6f2010-07-21 15:46:39 +000059CR = to_bytes([13])
60LF = to_bytes([10])
61
cliechtia3a811f2009-07-29 21:59:03 +000062
cliechti0d6029a2008-06-21 01:28:46 +000063PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
cliechti58b481c2009-02-16 20:42:32 +000064STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
cliechti14b274a2009-02-07 00:27:05 +000065FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
cliechtid6bf52c2003-10-01 02:28:12 +000066
67PARITY_NAMES = {
cliechti4a567a02009-07-27 22:09:31 +000068 PARITY_NONE: 'None',
69 PARITY_EVEN: 'Even',
70 PARITY_ODD: 'Odd',
71 PARITY_MARK: 'Mark',
72 PARITY_SPACE: 'Space',
cliechtid6bf52c2003-10-01 02:28:12 +000073}
74
cliechti1dbe4b62002-02-14 02:49:25 +000075
cliechti4a567a02009-07-27 22:09:31 +000076class SerialException(IOError):
cliechtid6bf52c2003-10-01 02:28:12 +000077 """Base class for serial port related exceptions."""
cliechti7fe54d52002-03-03 20:11:47 +000078
cliechtid6bf52c2003-10-01 02:28:12 +000079
cliechti62611612004-04-20 01:55:43 +000080class SerialTimeoutException(SerialException):
81 """Write timeouts give an exception"""
82
cliechti4a567a02009-07-27 22:09:31 +000083
cliechti4b20ec62012-08-16 01:04:44 +000084writeTimeoutError = SerialTimeoutException('Write timeout')
85portNotOpenError = SerialException('Attempting to use a port that is not open')
cliechti62611612004-04-20 01:55:43 +000086
cliechtif81362e2009-07-25 03:44:33 +000087
Chris Liechtief6b7b42015-08-06 22:19:26 +020088class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +000089 """\
90 Serial port base class. Provides __init__ function and properties to
91 get/set port settings.
92 """
cliechti14b274a2009-02-07 00:27:05 +000093
cliechtidfec0c82009-07-21 01:35:41 +000094 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +000095 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
96 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
97 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
98 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +000099 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
cliechti14b274a2009-02-07 00:27:05 +0000100 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
cliechti6ffdb8f2009-07-22 00:48:57 +0000101 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +0000102
cliechtid6bf52c2003-10-01 02:28:12 +0000103 def __init__(self,
cliechti14b274a2009-02-07 00:27:05 +0000104 port = None, # number of device, numbering starts at
105 # zero. if everything fails, the user
106 # can specify a device string, note
107 # that this isn't portable anymore
108 # port will be opened if one is specified
cliechtidfec0c82009-07-21 01:35:41 +0000109 baudrate=9600, # baud rate
110 bytesize=EIGHTBITS, # number of data bits
cliechti14b274a2009-02-07 00:27:05 +0000111 parity=PARITY_NONE, # enable parity checking
cliechtidfec0c82009-07-21 01:35:41 +0000112 stopbits=STOPBITS_ONE, # number of stop bits
cliechti14b274a2009-02-07 00:27:05 +0000113 timeout=None, # set a timeout value, None to wait forever
cliechti74308e42010-07-21 14:03:59 +0000114 xonxoff=False, # enable software flow control
115 rtscts=False, # enable RTS/CTS flow control
cliechti14b274a2009-02-07 00:27:05 +0000116 writeTimeout=None, # set a timeout for writes
cliechti58a2aee2010-05-20 23:37:57 +0000117 dsrdtr=False, # None: use rtscts setting, dsrdtr override if True or False
cliechti14b274a2009-02-07 00:27:05 +0000118 interCharTimeout=None # Inter-character timeout, None to disable
cliechtid6bf52c2003-10-01 02:28:12 +0000119 ):
cliechti7d448562014-08-03 21:57:45 +0000120 """\
121 Initialize comm port object. If a port is given, then the port will be
122 opened immediately. Otherwise a Serial port object in closed state
123 is returned.
124 """
cliechtid6bf52c2003-10-01 02:28:12 +0000125
126 self._isOpen = False
cliechti4a567a02009-07-27 22:09:31 +0000127 self._port = None # correct value is assigned below through properties
128 self._baudrate = None # correct value is assigned below through properties
129 self._bytesize = None # correct value is assigned below through properties
130 self._parity = None # correct value is assigned below through properties
131 self._stopbits = None # correct value is assigned below through properties
132 self._timeout = None # correct value is assigned below through properties
133 self._writeTimeout = None # correct value is assigned below through properties
134 self._xonxoff = None # correct value is assigned below through properties
135 self._rtscts = None # correct value is assigned below through properties
136 self._dsrdtr = None # correct value is assigned below through properties
137 self._interCharTimeout = None # correct value is assigned below through properties
Chris Liechti33f0ec52015-08-06 16:37:21 +0200138 self._rs485_mode = None # disabled by default
cliechti14b274a2009-02-07 00:27:05 +0000139
140 # assign values using get/set methods using the properties feature
cliechtid6bf52c2003-10-01 02:28:12 +0000141 self.port = port
142 self.baudrate = baudrate
143 self.bytesize = bytesize
144 self.parity = parity
145 self.stopbits = stopbits
146 self.timeout = timeout
cliechti62611612004-04-20 01:55:43 +0000147 self.writeTimeout = writeTimeout
cliechtid6bf52c2003-10-01 02:28:12 +0000148 self.xonxoff = xonxoff
149 self.rtscts = rtscts
cliechtif46e0a82005-05-19 15:24:57 +0000150 self.dsrdtr = dsrdtr
cliechti679bfa62008-06-20 23:58:15 +0000151 self.interCharTimeout = interCharTimeout
cliechti14b274a2009-02-07 00:27:05 +0000152
cliechtid6bf52c2003-10-01 02:28:12 +0000153 if port is not None:
154 self.open()
155
156 def isOpen(self):
157 """Check if the port is opened."""
158 return self._isOpen
159
cliechtid6bf52c2003-10-01 02:28:12 +0000160
161 # - - - - - - - - - - - - - - - - - - - - - - - -
162
Chris Liechti779b1a22015-08-04 14:54:22 +0200163 @property
164 def port(self):
165 """\
166 Get the current port setting. The value that was passed on init or using
167 setPort() is passed back. See also the attribute portstr which contains
168 the name of the port as a string.
169 """
170 return self._port
171
172 @port.setter
173 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000174 """\
175 Change the port. The attribute portstr is set to a string that
176 contains the name of the port.
177 """
cliechti14b274a2009-02-07 00:27:05 +0000178
cliechtid6bf52c2003-10-01 02:28:12 +0000179 was_open = self._isOpen
180 if was_open: self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200181 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000182 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000183 self.name = self.portstr
cliechtid6bf52c2003-10-01 02:28:12 +0000184 if was_open: self.open()
cliechti14b274a2009-02-07 00:27:05 +0000185
cliechtid6bf52c2003-10-01 02:28:12 +0000186
Chris Liechti779b1a22015-08-04 14:54:22 +0200187 @property
188 def baudrate(self):
189 """Get the current baud rate setting."""
190 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000191
Chris Liechti779b1a22015-08-04 14:54:22 +0200192 @baudrate.setter
193 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000194 """\
195 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000196 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000197 accepted and the exception is raised when the port is opened.
198 """
cliechti107db8d2004-01-15 01:20:23 +0000199 try:
cliechtie30868d2013-10-16 15:35:11 +0000200 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000201 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000202 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
cliechti107db8d2004-01-15 01:20:23 +0000203 else:
cliechtie30868d2013-10-16 15:35:11 +0000204 if b <= 0:
205 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
206 self._baudrate = b
cliechti107db8d2004-01-15 01:20:23 +0000207 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000208
cliechti14b274a2009-02-07 00:27:05 +0000209
Chris Liechti779b1a22015-08-04 14:54:22 +0200210 @property
211 def bytesize(self):
212 """Get the current byte size setting."""
213 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000214
Chris Liechti779b1a22015-08-04 14:54:22 +0200215 @bytesize.setter
216 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000217 """Change byte size."""
cliechti93db61b2006-08-26 19:16:18 +0000218 if bytesize not in self.BYTESIZES: raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000219 self._bytesize = bytesize
220 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000221
cliechtid6bf52c2003-10-01 02:28:12 +0000222
223
Chris Liechti779b1a22015-08-04 14:54:22 +0200224 @property
225 def parity(self):
226 """Get the current parity setting."""
227 return self._parity
228
229 @parity.setter
230 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000231 """Change parity setting."""
cliechti93db61b2006-08-26 19:16:18 +0000232 if parity not in self.PARITIES: raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000233 self._parity = parity
234 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000235
cliechtid6bf52c2003-10-01 02:28:12 +0000236
237
Chris Liechti779b1a22015-08-04 14:54:22 +0200238 @property
239 def stopbits(self):
240 """Get the current stop bits setting."""
241 return self._stopbits
242
243 @stopbits.setter
244 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000245 """Change stop bits size."""
246 if stopbits not in self.STOPBITS: raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000247 self._stopbits = stopbits
248 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000249
cliechti14b274a2009-02-07 00:27:05 +0000250
Chris Liechti779b1a22015-08-04 14:54:22 +0200251 @property
252 def timeout(self):
253 """Get the current timeout setting."""
254 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000255
Chris Liechti779b1a22015-08-04 14:54:22 +0200256 @timeout.setter
257 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000258 """Change timeout setting."""
259 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000260 try:
cliechti14b274a2009-02-07 00:27:05 +0000261 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000262 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000263 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti2750b832009-07-28 00:13:52 +0000264 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000265 self._timeout = timeout
266 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000267
Chris Liechti779b1a22015-08-04 14:54:22 +0200268
269 @property
270 def writeTimeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000271 """Get the current timeout setting."""
Chris Liechti779b1a22015-08-04 14:54:22 +0200272 return self._writeTimeout
cliechti14b274a2009-02-07 00:27:05 +0000273
Chris Liechti779b1a22015-08-04 14:54:22 +0200274 @writeTimeout.setter
275 def writeTimeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000276 """Change timeout setting."""
277 if timeout is not None:
cliechti93db61b2006-08-26 19:16:18 +0000278 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000279 try:
280 timeout + 1 #test if it's a number, will throw a TypeError if not...
281 except TypeError:
282 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000283
cliechti62611612004-04-20 01:55:43 +0000284 self._writeTimeout = timeout
285 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000286
cliechti14b274a2009-02-07 00:27:05 +0000287
Chris Liechti779b1a22015-08-04 14:54:22 +0200288 @property
289 def xonxoff(self):
290 """Get the current XON/XOFF setting."""
291 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000292
Chris Liechti779b1a22015-08-04 14:54:22 +0200293 @xonxoff.setter
294 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000295 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000296 self._xonxoff = xonxoff
297 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000298
cliechti14b274a2009-02-07 00:27:05 +0000299
Chris Liechti779b1a22015-08-04 14:54:22 +0200300 @property
301 def rtscts(self):
302 """Get the current RTS/CTS flow control setting."""
303 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000304
Chris Liechti779b1a22015-08-04 14:54:22 +0200305 @rtscts.setter
306 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000307 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000308 self._rtscts = rtscts
309 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000310
cliechti14b274a2009-02-07 00:27:05 +0000311
Chris Liechti779b1a22015-08-04 14:54:22 +0200312 @property
313 def dsrdtr(self):
314 """Get the current DSR/DTR flow control setting."""
315 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000316
Chris Liechti779b1a22015-08-04 14:54:22 +0200317 @dsrdtr.setter
318 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000319 """Change DsrDtr flow control setting."""
320 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000321 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000322 self._dsrdtr = self._rtscts
323 else:
cliechti14b274a2009-02-07 00:27:05 +0000324 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000325 self._dsrdtr = dsrdtr
326 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000327
cliechti14b274a2009-02-07 00:27:05 +0000328
Chris Liechti779b1a22015-08-04 14:54:22 +0200329 @property
330 def interCharTimeout(self):
331 """Get the current inter-character timeout setting."""
332 return self._interCharTimeout
cliechti679bfa62008-06-20 23:58:15 +0000333
Chris Liechti779b1a22015-08-04 14:54:22 +0200334 @interCharTimeout.setter
335 def interCharTimeout(self, interCharTimeout):
cliechti679bfa62008-06-20 23:58:15 +0000336 """Change inter-character timeout setting."""
337 if interCharTimeout is not None:
338 if interCharTimeout < 0: raise ValueError("Not a valid timeout: %r" % interCharTimeout)
339 try:
cliechti14b274a2009-02-07 00:27:05 +0000340 interCharTimeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti679bfa62008-06-20 23:58:15 +0000341 except TypeError:
342 raise ValueError("Not a valid timeout: %r" % interCharTimeout)
cliechti14b274a2009-02-07 00:27:05 +0000343
cliechti679bfa62008-06-20 23:58:15 +0000344 self._interCharTimeout = interCharTimeout
345 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000346
cliechti679bfa62008-06-20 23:58:15 +0000347
cliechti4065dce2009-08-10 00:55:46 +0000348 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200349 # functions useful for RS-485 adapters
350
351 @property
352 def rs485_mode(self):
353 """\
354 Enable RS485 mode and apply new settings, set to None to disable.
355 See serial.rs485.RS485Settings for more info about the value.
356 """
357 return self._rs485_mode
358
359 @rs485_mode.setter
360 def rs485_mode(self, rs485_settings):
361 self._rs485_mode = rs485_settings
362 if self._isOpen: self._reconfigurePort()
363
364 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000365
366 _SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
367 'dsrdtr', 'rtscts', 'timeout', 'writeTimeout', 'interCharTimeout')
368
369 def getSettingsDict(self):
cliechti7d448562014-08-03 21:57:45 +0000370 """\
371 Get current port settings as a dictionary. For use with
372 applySettingsDict.
373 """
cliechti4065dce2009-08-10 00:55:46 +0000374 return dict([(key, getattr(self, '_'+key)) for key in self._SETTINGS])
375
376 def applySettingsDict(self, d):
cliechti7d448562014-08-03 21:57:45 +0000377 """\
378 apply stored settings from a dictionary returned from
cliechti4065dce2009-08-10 00:55:46 +0000379 getSettingsDict. it's allowed to delete keys from the dictionary. these
cliechti7d448562014-08-03 21:57:45 +0000380 values will simply left unchanged.
381 """
cliechti4065dce2009-08-10 00:55:46 +0000382 for key in self._SETTINGS:
Chris Liechtib74be012015-08-04 16:36:01 +0200383 if key in d and d[key] != getattr(self, '_'+key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000384 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000385
cliechtid6bf52c2003-10-01 02:28:12 +0000386 # - - - - - - - - - - - - - - - - - - - - - - - -
387
388 def __repr__(self):
389 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000390 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 +0000391 self.__class__.__name__,
392 id(self),
393 self._isOpen,
394 self.portstr,
395 self.baudrate,
396 self.bytesize,
397 self.parity,
398 self.stopbits,
399 self.timeout,
400 self.xonxoff,
401 self.rtscts,
cliechtif46e0a82005-05-19 15:24:57 +0000402 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000403 )
404
cliechti4a567a02009-07-27 22:09:31 +0000405
406 # - - - - - - - - - - - - - - - - - - - - - - - -
407 # compatibility with io library
408
409 def readable(self): return True
410 def writable(self): return True
411 def seekable(self): return False
412 def readinto(self, b):
413 data = self.read(len(b))
414 n = len(data)
415 try:
416 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200417 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000418 import array
419 if not isinstance(b, array.array):
420 raise err
421 b[:n] = array.array('b', data)
422 return n
cliechtif81362e2009-07-25 03:44:33 +0000423
Chris Liechti70b89232015-08-04 03:00:52 +0200424 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200425 # context manager
426
427 def __enter__(self):
428 return self
429
430 def __exit__(self, *args, **kwargs):
431 self.close()
432
433 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200434 # additional functionality
435
436 def read_until(self, terminator=LF, size=None):
437 """\
438 Read until a termination sequence is found ('\n' by default), the size
439 is exceeded or until timeout occurs.
440 """
441 lenterm = len(terminator)
442 line = bytearray()
443 while True:
444 c = self.read(1)
445 if c:
446 line += c
447 if line[-lenterm:] == terminator:
448 break
449 if size is not None and len(line) >= size:
450 break
451 else:
452 break
453 return bytes(line)
454
455
456 def iread_until(self, *args, **kwargs):
457 """\
458 Read lines, implemented as generator. It will raise StopIteration on
459 timeout (empty read).
460 """
461 while True:
462 line = self.read_until(*args, **kwargs)
463 if not line: break
464 yield line
cliechtif81362e2009-07-25 03:44:33 +0000465
Chris Liechti779b1a22015-08-04 14:54:22 +0200466
467# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000468if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000469 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000470 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200471 sys.stdout.write('port name: %s\n' % s.name)
472 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
473 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
474 sys.stdout.write('parities: %s\n' % s.PARITIES)
475 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000476 sys.stdout.write('%s\n' % s)