blob: a71bd37c6c0dd08d330b56c5a5d21132d3300f70 [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
25# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
26# so a simple ``bytes(sequence)`` doesn't work for all versions
cliechti32c10332009-08-05 13:23:43 +000027def to_bytes(seq):
28 """convert a sequence to a bytes type"""
cliechti38077122013-10-16 02:57:27 +000029 if isinstance(seq, bytes):
30 return seq
31 elif isinstance(seq, bytearray):
32 return bytes(seq)
33 elif isinstance(seq, memoryview):
34 return seq.tobytes()
35 else:
36 b = bytearray()
37 for item in seq:
Chris Liechti07447732015-08-05 00:39:12 +020038 # this one handles int and bytes in Python 2.7
39 # add conversion in case of Python 3.x
40 if isinstance(item, bytes):
41 item = ord(item)
42 b.append(item)
cliechti38077122013-10-16 02:57:27 +000043 return bytes(b)
cliechti32c10332009-08-05 13:23:43 +000044
45# create control bytes
46XON = to_bytes([17])
47XOFF = to_bytes([19])
cliechti4a567a02009-07-27 22:09:31 +000048
cliechti8e99b6f2010-07-21 15:46:39 +000049CR = to_bytes([13])
50LF = to_bytes([10])
51
cliechtia3a811f2009-07-29 21:59:03 +000052
cliechti0d6029a2008-06-21 01:28:46 +000053PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
cliechti58b481c2009-02-16 20:42:32 +000054STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
cliechti14b274a2009-02-07 00:27:05 +000055FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
cliechtid6bf52c2003-10-01 02:28:12 +000056
57PARITY_NAMES = {
cliechti4a567a02009-07-27 22:09:31 +000058 PARITY_NONE: 'None',
59 PARITY_EVEN: 'Even',
60 PARITY_ODD: 'Odd',
61 PARITY_MARK: 'Mark',
62 PARITY_SPACE: 'Space',
cliechtid6bf52c2003-10-01 02:28:12 +000063}
64
cliechti1dbe4b62002-02-14 02:49:25 +000065
cliechti4a567a02009-07-27 22:09:31 +000066class SerialException(IOError):
cliechtid6bf52c2003-10-01 02:28:12 +000067 """Base class for serial port related exceptions."""
cliechti7fe54d52002-03-03 20:11:47 +000068
cliechtid6bf52c2003-10-01 02:28:12 +000069
cliechti62611612004-04-20 01:55:43 +000070class SerialTimeoutException(SerialException):
71 """Write timeouts give an exception"""
72
cliechti4a567a02009-07-27 22:09:31 +000073
cliechti4b20ec62012-08-16 01:04:44 +000074writeTimeoutError = SerialTimeoutException('Write timeout')
75portNotOpenError = SerialException('Attempting to use a port that is not open')
cliechti62611612004-04-20 01:55:43 +000076
cliechtif81362e2009-07-25 03:44:33 +000077
Chris Liechtief6b7b42015-08-06 22:19:26 +020078class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +000079 """\
80 Serial port base class. Provides __init__ function and properties to
81 get/set port settings.
82 """
cliechti14b274a2009-02-07 00:27:05 +000083
cliechtidfec0c82009-07-21 01:35:41 +000084 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +000085 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
86 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
87 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
88 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +000089 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
cliechti14b274a2009-02-07 00:27:05 +000090 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
cliechti6ffdb8f2009-07-22 00:48:57 +000091 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +000092
cliechtid6bf52c2003-10-01 02:28:12 +000093 def __init__(self,
cliechti14b274a2009-02-07 00:27:05 +000094 port = None, # number of device, numbering starts at
95 # zero. if everything fails, the user
96 # can specify a device string, note
97 # that this isn't portable anymore
98 # port will be opened if one is specified
cliechtidfec0c82009-07-21 01:35:41 +000099 baudrate=9600, # baud rate
100 bytesize=EIGHTBITS, # number of data bits
cliechti14b274a2009-02-07 00:27:05 +0000101 parity=PARITY_NONE, # enable parity checking
cliechtidfec0c82009-07-21 01:35:41 +0000102 stopbits=STOPBITS_ONE, # number of stop bits
cliechti14b274a2009-02-07 00:27:05 +0000103 timeout=None, # set a timeout value, None to wait forever
cliechti74308e42010-07-21 14:03:59 +0000104 xonxoff=False, # enable software flow control
105 rtscts=False, # enable RTS/CTS flow control
cliechti14b274a2009-02-07 00:27:05 +0000106 writeTimeout=None, # set a timeout for writes
cliechti58a2aee2010-05-20 23:37:57 +0000107 dsrdtr=False, # None: use rtscts setting, dsrdtr override if True or False
cliechti14b274a2009-02-07 00:27:05 +0000108 interCharTimeout=None # Inter-character timeout, None to disable
cliechtid6bf52c2003-10-01 02:28:12 +0000109 ):
cliechti7d448562014-08-03 21:57:45 +0000110 """\
111 Initialize comm port object. If a port is given, then the port will be
112 opened immediately. Otherwise a Serial port object in closed state
113 is returned.
114 """
cliechtid6bf52c2003-10-01 02:28:12 +0000115
116 self._isOpen = False
cliechti4a567a02009-07-27 22:09:31 +0000117 self._port = None # correct value is assigned below through properties
118 self._baudrate = None # correct value is assigned below through properties
119 self._bytesize = None # correct value is assigned below through properties
120 self._parity = None # correct value is assigned below through properties
121 self._stopbits = None # correct value is assigned below through properties
122 self._timeout = None # correct value is assigned below through properties
123 self._writeTimeout = None # correct value is assigned below through properties
124 self._xonxoff = None # correct value is assigned below through properties
125 self._rtscts = None # correct value is assigned below through properties
126 self._dsrdtr = None # correct value is assigned below through properties
127 self._interCharTimeout = None # correct value is assigned below through properties
Chris Liechti33f0ec52015-08-06 16:37:21 +0200128 self._rs485_mode = None # disabled by default
cliechti14b274a2009-02-07 00:27:05 +0000129
130 # assign values using get/set methods using the properties feature
cliechtid6bf52c2003-10-01 02:28:12 +0000131 self.port = port
132 self.baudrate = baudrate
133 self.bytesize = bytesize
134 self.parity = parity
135 self.stopbits = stopbits
136 self.timeout = timeout
cliechti62611612004-04-20 01:55:43 +0000137 self.writeTimeout = writeTimeout
cliechtid6bf52c2003-10-01 02:28:12 +0000138 self.xonxoff = xonxoff
139 self.rtscts = rtscts
cliechtif46e0a82005-05-19 15:24:57 +0000140 self.dsrdtr = dsrdtr
cliechti679bfa62008-06-20 23:58:15 +0000141 self.interCharTimeout = interCharTimeout
cliechti14b274a2009-02-07 00:27:05 +0000142
cliechtid6bf52c2003-10-01 02:28:12 +0000143 if port is not None:
144 self.open()
145
146 def isOpen(self):
147 """Check if the port is opened."""
148 return self._isOpen
149
cliechtid6bf52c2003-10-01 02:28:12 +0000150
151 # - - - - - - - - - - - - - - - - - - - - - - - -
152
Chris Liechti779b1a22015-08-04 14:54:22 +0200153 @property
154 def port(self):
155 """\
156 Get the current port setting. The value that was passed on init or using
157 setPort() is passed back. See also the attribute portstr which contains
158 the name of the port as a string.
159 """
160 return self._port
161
162 @port.setter
163 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000164 """\
165 Change the port. The attribute portstr is set to a string that
166 contains the name of the port.
167 """
cliechti14b274a2009-02-07 00:27:05 +0000168
cliechtid6bf52c2003-10-01 02:28:12 +0000169 was_open = self._isOpen
170 if was_open: self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200171 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000172 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000173 self.name = self.portstr
cliechtid6bf52c2003-10-01 02:28:12 +0000174 if was_open: self.open()
cliechti14b274a2009-02-07 00:27:05 +0000175
cliechtid6bf52c2003-10-01 02:28:12 +0000176
Chris Liechti779b1a22015-08-04 14:54:22 +0200177 @property
178 def baudrate(self):
179 """Get the current baud rate setting."""
180 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000181
Chris Liechti779b1a22015-08-04 14:54:22 +0200182 @baudrate.setter
183 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000184 """\
185 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000186 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000187 accepted and the exception is raised when the port is opened.
188 """
cliechti107db8d2004-01-15 01:20:23 +0000189 try:
cliechtie30868d2013-10-16 15:35:11 +0000190 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000191 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000192 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
cliechti107db8d2004-01-15 01:20:23 +0000193 else:
cliechtie30868d2013-10-16 15:35:11 +0000194 if b <= 0:
195 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
196 self._baudrate = b
cliechti107db8d2004-01-15 01:20:23 +0000197 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000198
cliechti14b274a2009-02-07 00:27:05 +0000199
Chris Liechti779b1a22015-08-04 14:54:22 +0200200 @property
201 def bytesize(self):
202 """Get the current byte size setting."""
203 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000204
Chris Liechti779b1a22015-08-04 14:54:22 +0200205 @bytesize.setter
206 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000207 """Change byte size."""
cliechti93db61b2006-08-26 19:16:18 +0000208 if bytesize not in self.BYTESIZES: raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000209 self._bytesize = bytesize
210 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000211
cliechtid6bf52c2003-10-01 02:28:12 +0000212
213
Chris Liechti779b1a22015-08-04 14:54:22 +0200214 @property
215 def parity(self):
216 """Get the current parity setting."""
217 return self._parity
218
219 @parity.setter
220 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000221 """Change parity setting."""
cliechti93db61b2006-08-26 19:16:18 +0000222 if parity not in self.PARITIES: raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000223 self._parity = parity
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 stopbits(self):
230 """Get the current stop bits setting."""
231 return self._stopbits
232
233 @stopbits.setter
234 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000235 """Change stop bits size."""
236 if stopbits not in self.STOPBITS: raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000237 self._stopbits = stopbits
238 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000239
cliechti14b274a2009-02-07 00:27:05 +0000240
Chris Liechti779b1a22015-08-04 14:54:22 +0200241 @property
242 def timeout(self):
243 """Get the current timeout setting."""
244 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000245
Chris Liechti779b1a22015-08-04 14:54:22 +0200246 @timeout.setter
247 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000248 """Change timeout setting."""
249 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000250 try:
cliechti14b274a2009-02-07 00:27:05 +0000251 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000252 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000253 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti2750b832009-07-28 00:13:52 +0000254 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000255 self._timeout = timeout
256 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000257
Chris Liechti779b1a22015-08-04 14:54:22 +0200258
259 @property
260 def writeTimeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000261 """Get the current timeout setting."""
Chris Liechti779b1a22015-08-04 14:54:22 +0200262 return self._writeTimeout
cliechti14b274a2009-02-07 00:27:05 +0000263
Chris Liechti779b1a22015-08-04 14:54:22 +0200264 @writeTimeout.setter
265 def writeTimeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000266 """Change timeout setting."""
267 if timeout is not None:
cliechti93db61b2006-08-26 19:16:18 +0000268 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000269 try:
270 timeout + 1 #test if it's a number, will throw a TypeError if not...
271 except TypeError:
272 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000273
cliechti62611612004-04-20 01:55:43 +0000274 self._writeTimeout = timeout
275 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000276
cliechti14b274a2009-02-07 00:27:05 +0000277
Chris Liechti779b1a22015-08-04 14:54:22 +0200278 @property
279 def xonxoff(self):
280 """Get the current XON/XOFF setting."""
281 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000282
Chris Liechti779b1a22015-08-04 14:54:22 +0200283 @xonxoff.setter
284 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000285 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000286 self._xonxoff = xonxoff
287 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000288
cliechti14b274a2009-02-07 00:27:05 +0000289
Chris Liechti779b1a22015-08-04 14:54:22 +0200290 @property
291 def rtscts(self):
292 """Get the current RTS/CTS flow control setting."""
293 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000294
Chris Liechti779b1a22015-08-04 14:54:22 +0200295 @rtscts.setter
296 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000297 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000298 self._rtscts = rtscts
299 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000300
cliechti14b274a2009-02-07 00:27:05 +0000301
Chris Liechti779b1a22015-08-04 14:54:22 +0200302 @property
303 def dsrdtr(self):
304 """Get the current DSR/DTR flow control setting."""
305 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000306
Chris Liechti779b1a22015-08-04 14:54:22 +0200307 @dsrdtr.setter
308 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000309 """Change DsrDtr flow control setting."""
310 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000311 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000312 self._dsrdtr = self._rtscts
313 else:
cliechti14b274a2009-02-07 00:27:05 +0000314 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000315 self._dsrdtr = dsrdtr
316 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000317
cliechti14b274a2009-02-07 00:27:05 +0000318
Chris Liechti779b1a22015-08-04 14:54:22 +0200319 @property
320 def interCharTimeout(self):
321 """Get the current inter-character timeout setting."""
322 return self._interCharTimeout
cliechti679bfa62008-06-20 23:58:15 +0000323
Chris Liechti779b1a22015-08-04 14:54:22 +0200324 @interCharTimeout.setter
325 def interCharTimeout(self, interCharTimeout):
cliechti679bfa62008-06-20 23:58:15 +0000326 """Change inter-character timeout setting."""
327 if interCharTimeout is not None:
328 if interCharTimeout < 0: raise ValueError("Not a valid timeout: %r" % interCharTimeout)
329 try:
cliechti14b274a2009-02-07 00:27:05 +0000330 interCharTimeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti679bfa62008-06-20 23:58:15 +0000331 except TypeError:
332 raise ValueError("Not a valid timeout: %r" % interCharTimeout)
cliechti14b274a2009-02-07 00:27:05 +0000333
cliechti679bfa62008-06-20 23:58:15 +0000334 self._interCharTimeout = interCharTimeout
335 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000336
cliechti679bfa62008-06-20 23:58:15 +0000337
cliechti4065dce2009-08-10 00:55:46 +0000338 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200339 # functions useful for RS-485 adapters
340
341 @property
342 def rs485_mode(self):
343 """\
344 Enable RS485 mode and apply new settings, set to None to disable.
345 See serial.rs485.RS485Settings for more info about the value.
346 """
347 return self._rs485_mode
348
349 @rs485_mode.setter
350 def rs485_mode(self, rs485_settings):
351 self._rs485_mode = rs485_settings
352 if self._isOpen: self._reconfigurePort()
353
354 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000355
356 _SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
357 'dsrdtr', 'rtscts', 'timeout', 'writeTimeout', 'interCharTimeout')
358
359 def getSettingsDict(self):
cliechti7d448562014-08-03 21:57:45 +0000360 """\
361 Get current port settings as a dictionary. For use with
362 applySettingsDict.
363 """
cliechti4065dce2009-08-10 00:55:46 +0000364 return dict([(key, getattr(self, '_'+key)) for key in self._SETTINGS])
365
366 def applySettingsDict(self, d):
cliechti7d448562014-08-03 21:57:45 +0000367 """\
368 apply stored settings from a dictionary returned from
cliechti4065dce2009-08-10 00:55:46 +0000369 getSettingsDict. it's allowed to delete keys from the dictionary. these
cliechti7d448562014-08-03 21:57:45 +0000370 values will simply left unchanged.
371 """
cliechti4065dce2009-08-10 00:55:46 +0000372 for key in self._SETTINGS:
Chris Liechtib74be012015-08-04 16:36:01 +0200373 if key in d and d[key] != getattr(self, '_'+key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000374 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000375
cliechtid6bf52c2003-10-01 02:28:12 +0000376 # - - - - - - - - - - - - - - - - - - - - - - - -
377
378 def __repr__(self):
379 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000380 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 +0000381 self.__class__.__name__,
382 id(self),
383 self._isOpen,
384 self.portstr,
385 self.baudrate,
386 self.bytesize,
387 self.parity,
388 self.stopbits,
389 self.timeout,
390 self.xonxoff,
391 self.rtscts,
cliechtif46e0a82005-05-19 15:24:57 +0000392 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000393 )
394
cliechti4a567a02009-07-27 22:09:31 +0000395
396 # - - - - - - - - - - - - - - - - - - - - - - - -
397 # compatibility with io library
398
399 def readable(self): return True
400 def writable(self): return True
401 def seekable(self): return False
402 def readinto(self, b):
403 data = self.read(len(b))
404 n = len(data)
405 try:
406 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200407 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000408 import array
409 if not isinstance(b, array.array):
410 raise err
411 b[:n] = array.array('b', data)
412 return n
cliechtif81362e2009-07-25 03:44:33 +0000413
Chris Liechti70b89232015-08-04 03:00:52 +0200414 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200415 # context manager
416
417 def __enter__(self):
418 return self
419
420 def __exit__(self, *args, **kwargs):
421 self.close()
422
423 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200424 # additional functionality
425
426 def read_until(self, terminator=LF, size=None):
427 """\
428 Read until a termination sequence is found ('\n' by default), the size
429 is exceeded or until timeout occurs.
430 """
431 lenterm = len(terminator)
432 line = bytearray()
433 while True:
434 c = self.read(1)
435 if c:
436 line += c
437 if line[-lenterm:] == terminator:
438 break
439 if size is not None and len(line) >= size:
440 break
441 else:
442 break
443 return bytes(line)
444
445
446 def iread_until(self, *args, **kwargs):
447 """\
448 Read lines, implemented as generator. It will raise StopIteration on
449 timeout (empty read).
450 """
451 while True:
452 line = self.read_until(*args, **kwargs)
453 if not line: break
454 yield line
cliechtif81362e2009-07-25 03:44:33 +0000455
Chris Liechti779b1a22015-08-04 14:54:22 +0200456
457# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000458if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000459 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000460 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200461 sys.stdout.write('port name: %s\n' % s.name)
462 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
463 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
464 sys.stdout.write('parities: %s\n' % s.PARITIES)
465 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000466 sys.stdout.write('%s\n' % s)