blob: 63f8a930555f684c19a67e9fd9ba8177d1028009 [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
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020029 while True:
Chris Liechtif99cd5c2015-08-13 22:54:16 +020030 a = b[x:x+1]
31 x += 1
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020032 if a:
33 yield a
34 else:
35 break
36
cliechti38077122013-10-16 02:57:27 +000037# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
38# so a simple ``bytes(sequence)`` doesn't work for all versions
cliechti32c10332009-08-05 13:23:43 +000039def to_bytes(seq):
40 """convert a sequence to a bytes type"""
cliechti38077122013-10-16 02:57:27 +000041 if isinstance(seq, bytes):
42 return seq
43 elif isinstance(seq, bytearray):
44 return bytes(seq)
45 elif isinstance(seq, memoryview):
46 return seq.tobytes()
47 else:
48 b = bytearray()
49 for item in seq:
Chris Liechti07447732015-08-05 00:39:12 +020050 # this one handles int and bytes in Python 2.7
51 # add conversion in case of Python 3.x
52 if isinstance(item, bytes):
53 item = ord(item)
54 b.append(item)
cliechti38077122013-10-16 02:57:27 +000055 return bytes(b)
cliechti32c10332009-08-05 13:23:43 +000056
57# create control bytes
58XON = to_bytes([17])
59XOFF = to_bytes([19])
cliechti4a567a02009-07-27 22:09:31 +000060
cliechti8e99b6f2010-07-21 15:46:39 +000061CR = to_bytes([13])
62LF = to_bytes([10])
63
cliechtia3a811f2009-07-29 21:59:03 +000064
cliechti0d6029a2008-06-21 01:28:46 +000065PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
cliechti58b481c2009-02-16 20:42:32 +000066STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
cliechti14b274a2009-02-07 00:27:05 +000067FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
cliechtid6bf52c2003-10-01 02:28:12 +000068
69PARITY_NAMES = {
cliechti4a567a02009-07-27 22:09:31 +000070 PARITY_NONE: 'None',
71 PARITY_EVEN: 'Even',
72 PARITY_ODD: 'Odd',
73 PARITY_MARK: 'Mark',
74 PARITY_SPACE: 'Space',
cliechtid6bf52c2003-10-01 02:28:12 +000075}
76
cliechti1dbe4b62002-02-14 02:49:25 +000077
cliechti4a567a02009-07-27 22:09:31 +000078class SerialException(IOError):
cliechtid6bf52c2003-10-01 02:28:12 +000079 """Base class for serial port related exceptions."""
cliechti7fe54d52002-03-03 20:11:47 +000080
cliechtid6bf52c2003-10-01 02:28:12 +000081
cliechti62611612004-04-20 01:55:43 +000082class SerialTimeoutException(SerialException):
83 """Write timeouts give an exception"""
84
cliechti4a567a02009-07-27 22:09:31 +000085
cliechti4b20ec62012-08-16 01:04:44 +000086writeTimeoutError = SerialTimeoutException('Write timeout')
87portNotOpenError = SerialException('Attempting to use a port that is not open')
cliechti62611612004-04-20 01:55:43 +000088
cliechtif81362e2009-07-25 03:44:33 +000089
Chris Liechtief6b7b42015-08-06 22:19:26 +020090class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +000091 """\
92 Serial port base class. Provides __init__ function and properties to
93 get/set port settings.
94 """
cliechti14b274a2009-02-07 00:27:05 +000095
cliechtidfec0c82009-07-21 01:35:41 +000096 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +000097 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
98 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
99 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
100 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +0000101 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
cliechti14b274a2009-02-07 00:27:05 +0000102 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
cliechti6ffdb8f2009-07-22 00:48:57 +0000103 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +0000104
cliechtid6bf52c2003-10-01 02:28:12 +0000105 def __init__(self,
cliechti14b274a2009-02-07 00:27:05 +0000106 port = None, # number of device, numbering starts at
107 # zero. if everything fails, the user
108 # can specify a device string, note
109 # that this isn't portable anymore
110 # port will be opened if one is specified
cliechtidfec0c82009-07-21 01:35:41 +0000111 baudrate=9600, # baud rate
112 bytesize=EIGHTBITS, # number of data bits
cliechti14b274a2009-02-07 00:27:05 +0000113 parity=PARITY_NONE, # enable parity checking
cliechtidfec0c82009-07-21 01:35:41 +0000114 stopbits=STOPBITS_ONE, # number of stop bits
cliechti14b274a2009-02-07 00:27:05 +0000115 timeout=None, # set a timeout value, None to wait forever
cliechti74308e42010-07-21 14:03:59 +0000116 xonxoff=False, # enable software flow control
117 rtscts=False, # enable RTS/CTS flow control
cliechti14b274a2009-02-07 00:27:05 +0000118 writeTimeout=None, # set a timeout for writes
cliechti58a2aee2010-05-20 23:37:57 +0000119 dsrdtr=False, # None: use rtscts setting, dsrdtr override if True or False
cliechti14b274a2009-02-07 00:27:05 +0000120 interCharTimeout=None # Inter-character timeout, None to disable
cliechtid6bf52c2003-10-01 02:28:12 +0000121 ):
cliechti7d448562014-08-03 21:57:45 +0000122 """\
123 Initialize comm port object. If a port is given, then the port will be
124 opened immediately. Otherwise a Serial port object in closed state
125 is returned.
126 """
cliechtid6bf52c2003-10-01 02:28:12 +0000127
128 self._isOpen = False
cliechti4a567a02009-07-27 22:09:31 +0000129 self._port = None # correct value is assigned below through properties
130 self._baudrate = None # correct value is assigned below through properties
131 self._bytesize = None # correct value is assigned below through properties
132 self._parity = None # correct value is assigned below through properties
133 self._stopbits = None # correct value is assigned below through properties
134 self._timeout = None # correct value is assigned below through properties
135 self._writeTimeout = None # correct value is assigned below through properties
136 self._xonxoff = None # correct value is assigned below through properties
137 self._rtscts = None # correct value is assigned below through properties
138 self._dsrdtr = None # correct value is assigned below through properties
139 self._interCharTimeout = None # correct value is assigned below through properties
Chris Liechti33f0ec52015-08-06 16:37:21 +0200140 self._rs485_mode = None # disabled by default
cliechti14b274a2009-02-07 00:27:05 +0000141
142 # assign values using get/set methods using the properties feature
cliechtid6bf52c2003-10-01 02:28:12 +0000143 self.port = port
144 self.baudrate = baudrate
145 self.bytesize = bytesize
146 self.parity = parity
147 self.stopbits = stopbits
148 self.timeout = timeout
cliechti62611612004-04-20 01:55:43 +0000149 self.writeTimeout = writeTimeout
cliechtid6bf52c2003-10-01 02:28:12 +0000150 self.xonxoff = xonxoff
151 self.rtscts = rtscts
cliechtif46e0a82005-05-19 15:24:57 +0000152 self.dsrdtr = dsrdtr
cliechti679bfa62008-06-20 23:58:15 +0000153 self.interCharTimeout = interCharTimeout
cliechti14b274a2009-02-07 00:27:05 +0000154
cliechtid6bf52c2003-10-01 02:28:12 +0000155 if port is not None:
156 self.open()
157
158 def isOpen(self):
159 """Check if the port is opened."""
160 return self._isOpen
161
cliechtid6bf52c2003-10-01 02:28:12 +0000162
163 # - - - - - - - - - - - - - - - - - - - - - - - -
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
cliechtid6bf52c2003-10-01 02:28:12 +0000181 was_open = self._isOpen
182 if was_open: self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200183 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000184 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000185 self.name = self.portstr
cliechtid6bf52c2003-10-01 02:28:12 +0000186 if was_open: self.open()
cliechti14b274a2009-02-07 00:27:05 +0000187
cliechtid6bf52c2003-10-01 02:28:12 +0000188
Chris Liechti779b1a22015-08-04 14:54:22 +0200189 @property
190 def baudrate(self):
191 """Get the current baud rate setting."""
192 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000193
Chris Liechti779b1a22015-08-04 14:54:22 +0200194 @baudrate.setter
195 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000196 """\
197 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000198 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000199 accepted and the exception is raised when the port is opened.
200 """
cliechti107db8d2004-01-15 01:20:23 +0000201 try:
cliechtie30868d2013-10-16 15:35:11 +0000202 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000203 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000204 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
cliechti107db8d2004-01-15 01:20:23 +0000205 else:
cliechtie30868d2013-10-16 15:35:11 +0000206 if b <= 0:
207 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
208 self._baudrate = b
cliechti107db8d2004-01-15 01:20:23 +0000209 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000210
cliechti14b274a2009-02-07 00:27:05 +0000211
Chris Liechti779b1a22015-08-04 14:54:22 +0200212 @property
213 def bytesize(self):
214 """Get the current byte size setting."""
215 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000216
Chris Liechti779b1a22015-08-04 14:54:22 +0200217 @bytesize.setter
218 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000219 """Change byte size."""
cliechti93db61b2006-08-26 19:16:18 +0000220 if bytesize not in self.BYTESIZES: raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000221 self._bytesize = bytesize
222 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000223
cliechtid6bf52c2003-10-01 02:28:12 +0000224
225
Chris Liechti779b1a22015-08-04 14:54:22 +0200226 @property
227 def parity(self):
228 """Get the current parity setting."""
229 return self._parity
230
231 @parity.setter
232 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000233 """Change parity setting."""
cliechti93db61b2006-08-26 19:16:18 +0000234 if parity not in self.PARITIES: raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000235 self._parity = parity
236 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000237
cliechtid6bf52c2003-10-01 02:28:12 +0000238
239
Chris Liechti779b1a22015-08-04 14:54:22 +0200240 @property
241 def stopbits(self):
242 """Get the current stop bits setting."""
243 return self._stopbits
244
245 @stopbits.setter
246 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000247 """Change stop bits size."""
248 if stopbits not in self.STOPBITS: raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000249 self._stopbits = stopbits
250 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000251
cliechti14b274a2009-02-07 00:27:05 +0000252
Chris Liechti779b1a22015-08-04 14:54:22 +0200253 @property
254 def timeout(self):
255 """Get the current timeout setting."""
256 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000257
Chris Liechti779b1a22015-08-04 14:54:22 +0200258 @timeout.setter
259 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000260 """Change timeout setting."""
261 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000262 try:
cliechti14b274a2009-02-07 00:27:05 +0000263 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000264 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000265 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti2750b832009-07-28 00:13:52 +0000266 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000267 self._timeout = timeout
268 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000269
Chris Liechti779b1a22015-08-04 14:54:22 +0200270
271 @property
272 def writeTimeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000273 """Get the current timeout setting."""
Chris Liechti779b1a22015-08-04 14:54:22 +0200274 return self._writeTimeout
cliechti14b274a2009-02-07 00:27:05 +0000275
Chris Liechti779b1a22015-08-04 14:54:22 +0200276 @writeTimeout.setter
277 def writeTimeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000278 """Change timeout setting."""
279 if timeout is not None:
cliechti93db61b2006-08-26 19:16:18 +0000280 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000281 try:
282 timeout + 1 #test if it's a number, will throw a TypeError if not...
283 except TypeError:
284 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000285
cliechti62611612004-04-20 01:55:43 +0000286 self._writeTimeout = timeout
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 xonxoff(self):
292 """Get the current XON/XOFF setting."""
293 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000294
Chris Liechti779b1a22015-08-04 14:54:22 +0200295 @xonxoff.setter
296 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000297 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000298 self._xonxoff = xonxoff
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 rtscts(self):
304 """Get the current RTS/CTS flow control setting."""
305 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000306
Chris Liechti779b1a22015-08-04 14:54:22 +0200307 @rtscts.setter
308 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000309 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000310 self._rtscts = rtscts
311 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000312
cliechti14b274a2009-02-07 00:27:05 +0000313
Chris Liechti779b1a22015-08-04 14:54:22 +0200314 @property
315 def dsrdtr(self):
316 """Get the current DSR/DTR flow control setting."""
317 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000318
Chris Liechti779b1a22015-08-04 14:54:22 +0200319 @dsrdtr.setter
320 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000321 """Change DsrDtr flow control setting."""
322 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000323 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000324 self._dsrdtr = self._rtscts
325 else:
cliechti14b274a2009-02-07 00:27:05 +0000326 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000327 self._dsrdtr = dsrdtr
328 if self._isOpen: self._reconfigurePort()
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 interCharTimeout(self):
333 """Get the current inter-character timeout setting."""
334 return self._interCharTimeout
cliechti679bfa62008-06-20 23:58:15 +0000335
Chris Liechti779b1a22015-08-04 14:54:22 +0200336 @interCharTimeout.setter
337 def interCharTimeout(self, interCharTimeout):
cliechti679bfa62008-06-20 23:58:15 +0000338 """Change inter-character timeout setting."""
339 if interCharTimeout is not None:
340 if interCharTimeout < 0: raise ValueError("Not a valid timeout: %r" % interCharTimeout)
341 try:
cliechti14b274a2009-02-07 00:27:05 +0000342 interCharTimeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti679bfa62008-06-20 23:58:15 +0000343 except TypeError:
344 raise ValueError("Not a valid timeout: %r" % interCharTimeout)
cliechti14b274a2009-02-07 00:27:05 +0000345
cliechti679bfa62008-06-20 23:58:15 +0000346 self._interCharTimeout = interCharTimeout
347 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000348
cliechti679bfa62008-06-20 23:58:15 +0000349
cliechti4065dce2009-08-10 00:55:46 +0000350 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200351 # functions useful for RS-485 adapters
352
353 @property
354 def rs485_mode(self):
355 """\
356 Enable RS485 mode and apply new settings, set to None to disable.
357 See serial.rs485.RS485Settings for more info about the value.
358 """
359 return self._rs485_mode
360
361 @rs485_mode.setter
362 def rs485_mode(self, rs485_settings):
363 self._rs485_mode = rs485_settings
364 if self._isOpen: self._reconfigurePort()
365
366 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000367
368 _SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
369 'dsrdtr', 'rtscts', 'timeout', 'writeTimeout', 'interCharTimeout')
370
371 def getSettingsDict(self):
cliechti7d448562014-08-03 21:57:45 +0000372 """\
373 Get current port settings as a dictionary. For use with
374 applySettingsDict.
375 """
cliechti4065dce2009-08-10 00:55:46 +0000376 return dict([(key, getattr(self, '_'+key)) for key in self._SETTINGS])
377
378 def applySettingsDict(self, d):
cliechti7d448562014-08-03 21:57:45 +0000379 """\
380 apply stored settings from a dictionary returned from
cliechti4065dce2009-08-10 00:55:46 +0000381 getSettingsDict. it's allowed to delete keys from the dictionary. these
cliechti7d448562014-08-03 21:57:45 +0000382 values will simply left unchanged.
383 """
cliechti4065dce2009-08-10 00:55:46 +0000384 for key in self._SETTINGS:
Chris Liechtib74be012015-08-04 16:36:01 +0200385 if key in d and d[key] != getattr(self, '_'+key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000386 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000387
cliechtid6bf52c2003-10-01 02:28:12 +0000388 # - - - - - - - - - - - - - - - - - - - - - - - -
389
390 def __repr__(self):
391 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000392 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 +0000393 self.__class__.__name__,
394 id(self),
395 self._isOpen,
396 self.portstr,
397 self.baudrate,
398 self.bytesize,
399 self.parity,
400 self.stopbits,
401 self.timeout,
402 self.xonxoff,
403 self.rtscts,
cliechtif46e0a82005-05-19 15:24:57 +0000404 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000405 )
406
cliechti4a567a02009-07-27 22:09:31 +0000407
408 # - - - - - - - - - - - - - - - - - - - - - - - -
409 # compatibility with io library
410
411 def readable(self): return True
412 def writable(self): return True
413 def seekable(self): return False
414 def readinto(self, b):
415 data = self.read(len(b))
416 n = len(data)
417 try:
418 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200419 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000420 import array
421 if not isinstance(b, array.array):
422 raise err
423 b[:n] = array.array('b', data)
424 return n
cliechtif81362e2009-07-25 03:44:33 +0000425
Chris Liechti70b89232015-08-04 03:00:52 +0200426 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200427 # context manager
428
429 def __enter__(self):
430 return self
431
432 def __exit__(self, *args, **kwargs):
433 self.close()
434
435 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200436 # additional functionality
437
438 def read_until(self, terminator=LF, size=None):
439 """\
440 Read until a termination sequence is found ('\n' by default), the size
441 is exceeded or until timeout occurs.
442 """
443 lenterm = len(terminator)
444 line = bytearray()
445 while True:
446 c = self.read(1)
447 if c:
448 line += c
449 if line[-lenterm:] == terminator:
450 break
451 if size is not None and len(line) >= size:
452 break
453 else:
454 break
455 return bytes(line)
456
457
458 def iread_until(self, *args, **kwargs):
459 """\
460 Read lines, implemented as generator. It will raise StopIteration on
461 timeout (empty read).
462 """
463 while True:
464 line = self.read_until(*args, **kwargs)
465 if not line: break
466 yield line
cliechtif81362e2009-07-25 03:44:33 +0000467
Chris Liechti779b1a22015-08-04 14:54:22 +0200468
469# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000470if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000471 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000472 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200473 sys.stdout.write('port name: %s\n' % s.name)
474 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
475 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
476 sys.stdout.write('parities: %s\n' % s.PARITIES)
477 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000478 sys.stdout.write('%s\n' % s)