blob: 4d2c7e0c8dff5a59bba4024bfa73103b5c5ad765 [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>
cliechtid6bf52c2003-10-01 02:28:12 +00006# this is distributed under a free software license, see license.txt
7
Chris Liechtief6b7b42015-08-06 22:19:26 +02008import io
cliechtic323f1f2010-07-22 00:14:26 +00009
cliechti38077122013-10-16 02:57:27 +000010# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)``
11# isn't returning the contents (very unfortunate). Therefore we need special
12# cases and test for it. Ensure that there is a ``memoryview`` object for older
13# Python versions. This is easier than making every test dependent on its
14# existence.
15try:
16 memoryview
17except (NameError, AttributeError):
18 # implementation does not matter as we do not realy use it.
19 # it just must not inherit from something else we might care for.
Chris Liechti70b89232015-08-04 03:00:52 +020020 class memoryview(object):
cliechti38077122013-10-16 02:57:27 +000021 pass
22
23
24# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
25# so a simple ``bytes(sequence)`` doesn't work for all versions
cliechti32c10332009-08-05 13:23:43 +000026def to_bytes(seq):
27 """convert a sequence to a bytes type"""
cliechti38077122013-10-16 02:57:27 +000028 if isinstance(seq, bytes):
29 return seq
30 elif isinstance(seq, bytearray):
31 return bytes(seq)
32 elif isinstance(seq, memoryview):
33 return seq.tobytes()
34 else:
35 b = bytearray()
36 for item in seq:
Chris Liechti07447732015-08-05 00:39:12 +020037 # this one handles int and bytes in Python 2.7
38 # add conversion in case of Python 3.x
39 if isinstance(item, bytes):
40 item = ord(item)
41 b.append(item)
cliechti38077122013-10-16 02:57:27 +000042 return bytes(b)
cliechti32c10332009-08-05 13:23:43 +000043
44# create control bytes
45XON = to_bytes([17])
46XOFF = to_bytes([19])
cliechti4a567a02009-07-27 22:09:31 +000047
cliechti8e99b6f2010-07-21 15:46:39 +000048CR = to_bytes([13])
49LF = to_bytes([10])
50
cliechtia3a811f2009-07-29 21:59:03 +000051
cliechti0d6029a2008-06-21 01:28:46 +000052PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
cliechti58b481c2009-02-16 20:42:32 +000053STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
cliechti14b274a2009-02-07 00:27:05 +000054FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
cliechtid6bf52c2003-10-01 02:28:12 +000055
56PARITY_NAMES = {
cliechti4a567a02009-07-27 22:09:31 +000057 PARITY_NONE: 'None',
58 PARITY_EVEN: 'Even',
59 PARITY_ODD: 'Odd',
60 PARITY_MARK: 'Mark',
61 PARITY_SPACE: 'Space',
cliechtid6bf52c2003-10-01 02:28:12 +000062}
63
cliechti1dbe4b62002-02-14 02:49:25 +000064
cliechti4a567a02009-07-27 22:09:31 +000065class SerialException(IOError):
cliechtid6bf52c2003-10-01 02:28:12 +000066 """Base class for serial port related exceptions."""
cliechti7fe54d52002-03-03 20:11:47 +000067
cliechtid6bf52c2003-10-01 02:28:12 +000068
cliechti62611612004-04-20 01:55:43 +000069class SerialTimeoutException(SerialException):
70 """Write timeouts give an exception"""
71
cliechti4a567a02009-07-27 22:09:31 +000072
cliechti4b20ec62012-08-16 01:04:44 +000073writeTimeoutError = SerialTimeoutException('Write timeout')
74portNotOpenError = SerialException('Attempting to use a port that is not open')
cliechti62611612004-04-20 01:55:43 +000075
cliechtif81362e2009-07-25 03:44:33 +000076
Chris Liechtief6b7b42015-08-06 22:19:26 +020077class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +000078 """\
79 Serial port base class. Provides __init__ function and properties to
80 get/set port settings.
81 """
cliechti14b274a2009-02-07 00:27:05 +000082
cliechtidfec0c82009-07-21 01:35:41 +000083 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +000084 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
85 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
86 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
87 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +000088 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
cliechti14b274a2009-02-07 00:27:05 +000089 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
cliechti6ffdb8f2009-07-22 00:48:57 +000090 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +000091
cliechtid6bf52c2003-10-01 02:28:12 +000092 def __init__(self,
cliechti14b274a2009-02-07 00:27:05 +000093 port = None, # number of device, numbering starts at
94 # zero. if everything fails, the user
95 # can specify a device string, note
96 # that this isn't portable anymore
97 # port will be opened if one is specified
cliechtidfec0c82009-07-21 01:35:41 +000098 baudrate=9600, # baud rate
99 bytesize=EIGHTBITS, # number of data bits
cliechti14b274a2009-02-07 00:27:05 +0000100 parity=PARITY_NONE, # enable parity checking
cliechtidfec0c82009-07-21 01:35:41 +0000101 stopbits=STOPBITS_ONE, # number of stop bits
cliechti14b274a2009-02-07 00:27:05 +0000102 timeout=None, # set a timeout value, None to wait forever
cliechti74308e42010-07-21 14:03:59 +0000103 xonxoff=False, # enable software flow control
104 rtscts=False, # enable RTS/CTS flow control
cliechti14b274a2009-02-07 00:27:05 +0000105 writeTimeout=None, # set a timeout for writes
cliechti58a2aee2010-05-20 23:37:57 +0000106 dsrdtr=False, # None: use rtscts setting, dsrdtr override if True or False
cliechti14b274a2009-02-07 00:27:05 +0000107 interCharTimeout=None # Inter-character timeout, None to disable
cliechtid6bf52c2003-10-01 02:28:12 +0000108 ):
cliechti7d448562014-08-03 21:57:45 +0000109 """\
110 Initialize comm port object. If a port is given, then the port will be
111 opened immediately. Otherwise a Serial port object in closed state
112 is returned.
113 """
cliechtid6bf52c2003-10-01 02:28:12 +0000114
115 self._isOpen = False
cliechti4a567a02009-07-27 22:09:31 +0000116 self._port = None # correct value is assigned below through properties
117 self._baudrate = None # correct value is assigned below through properties
118 self._bytesize = None # correct value is assigned below through properties
119 self._parity = None # correct value is assigned below through properties
120 self._stopbits = None # correct value is assigned below through properties
121 self._timeout = None # correct value is assigned below through properties
122 self._writeTimeout = None # correct value is assigned below through properties
123 self._xonxoff = None # correct value is assigned below through properties
124 self._rtscts = None # correct value is assigned below through properties
125 self._dsrdtr = None # correct value is assigned below through properties
126 self._interCharTimeout = None # correct value is assigned below through properties
Chris Liechti33f0ec52015-08-06 16:37:21 +0200127 self._rs485_mode = None # disabled by default
cliechti14b274a2009-02-07 00:27:05 +0000128
129 # assign values using get/set methods using the properties feature
cliechtid6bf52c2003-10-01 02:28:12 +0000130 self.port = port
131 self.baudrate = baudrate
132 self.bytesize = bytesize
133 self.parity = parity
134 self.stopbits = stopbits
135 self.timeout = timeout
cliechti62611612004-04-20 01:55:43 +0000136 self.writeTimeout = writeTimeout
cliechtid6bf52c2003-10-01 02:28:12 +0000137 self.xonxoff = xonxoff
138 self.rtscts = rtscts
cliechtif46e0a82005-05-19 15:24:57 +0000139 self.dsrdtr = dsrdtr
cliechti679bfa62008-06-20 23:58:15 +0000140 self.interCharTimeout = interCharTimeout
cliechti14b274a2009-02-07 00:27:05 +0000141
cliechtid6bf52c2003-10-01 02:28:12 +0000142 if port is not None:
143 self.open()
144
145 def isOpen(self):
146 """Check if the port is opened."""
147 return self._isOpen
148
cliechtid6bf52c2003-10-01 02:28:12 +0000149
150 # - - - - - - - - - - - - - - - - - - - - - - - -
151
Chris Liechti779b1a22015-08-04 14:54:22 +0200152 @property
153 def port(self):
154 """\
155 Get the current port setting. The value that was passed on init or using
156 setPort() is passed back. See also the attribute portstr which contains
157 the name of the port as a string.
158 """
159 return self._port
160
161 @port.setter
162 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000163 """\
164 Change the port. The attribute portstr is set to a string that
165 contains the name of the port.
166 """
cliechti14b274a2009-02-07 00:27:05 +0000167
cliechtid6bf52c2003-10-01 02:28:12 +0000168 was_open = self._isOpen
169 if was_open: self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200170 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000171 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000172 self.name = self.portstr
cliechtid6bf52c2003-10-01 02:28:12 +0000173 if was_open: self.open()
cliechti14b274a2009-02-07 00:27:05 +0000174
cliechtid6bf52c2003-10-01 02:28:12 +0000175
Chris Liechti779b1a22015-08-04 14:54:22 +0200176 @property
177 def baudrate(self):
178 """Get the current baud rate setting."""
179 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000180
Chris Liechti779b1a22015-08-04 14:54:22 +0200181 @baudrate.setter
182 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000183 """\
184 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000185 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000186 accepted and the exception is raised when the port is opened.
187 """
cliechti107db8d2004-01-15 01:20:23 +0000188 try:
cliechtie30868d2013-10-16 15:35:11 +0000189 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000190 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000191 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
cliechti107db8d2004-01-15 01:20:23 +0000192 else:
cliechtie30868d2013-10-16 15:35:11 +0000193 if b <= 0:
194 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
195 self._baudrate = b
cliechti107db8d2004-01-15 01:20:23 +0000196 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000197
cliechti14b274a2009-02-07 00:27:05 +0000198
Chris Liechti779b1a22015-08-04 14:54:22 +0200199 @property
200 def bytesize(self):
201 """Get the current byte size setting."""
202 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000203
Chris Liechti779b1a22015-08-04 14:54:22 +0200204 @bytesize.setter
205 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000206 """Change byte size."""
cliechti93db61b2006-08-26 19:16:18 +0000207 if bytesize not in self.BYTESIZES: raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000208 self._bytesize = bytesize
209 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000210
cliechtid6bf52c2003-10-01 02:28:12 +0000211
212
Chris Liechti779b1a22015-08-04 14:54:22 +0200213 @property
214 def parity(self):
215 """Get the current parity setting."""
216 return self._parity
217
218 @parity.setter
219 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000220 """Change parity setting."""
cliechti93db61b2006-08-26 19:16:18 +0000221 if parity not in self.PARITIES: raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000222 self._parity = parity
223 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000224
cliechtid6bf52c2003-10-01 02:28:12 +0000225
226
Chris Liechti779b1a22015-08-04 14:54:22 +0200227 @property
228 def stopbits(self):
229 """Get the current stop bits setting."""
230 return self._stopbits
231
232 @stopbits.setter
233 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000234 """Change stop bits size."""
235 if stopbits not in self.STOPBITS: raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000236 self._stopbits = stopbits
237 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000238
cliechti14b274a2009-02-07 00:27:05 +0000239
Chris Liechti779b1a22015-08-04 14:54:22 +0200240 @property
241 def timeout(self):
242 """Get the current timeout setting."""
243 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000244
Chris Liechti779b1a22015-08-04 14:54:22 +0200245 @timeout.setter
246 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000247 """Change timeout setting."""
248 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000249 try:
cliechti14b274a2009-02-07 00:27:05 +0000250 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000251 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000252 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti2750b832009-07-28 00:13:52 +0000253 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000254 self._timeout = timeout
255 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000256
Chris Liechti779b1a22015-08-04 14:54:22 +0200257
258 @property
259 def writeTimeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000260 """Get the current timeout setting."""
Chris Liechti779b1a22015-08-04 14:54:22 +0200261 return self._writeTimeout
cliechti14b274a2009-02-07 00:27:05 +0000262
Chris Liechti779b1a22015-08-04 14:54:22 +0200263 @writeTimeout.setter
264 def writeTimeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000265 """Change timeout setting."""
266 if timeout is not None:
cliechti93db61b2006-08-26 19:16:18 +0000267 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000268 try:
269 timeout + 1 #test if it's a number, will throw a TypeError if not...
270 except TypeError:
271 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000272
cliechti62611612004-04-20 01:55:43 +0000273 self._writeTimeout = timeout
274 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000275
cliechti14b274a2009-02-07 00:27:05 +0000276
Chris Liechti779b1a22015-08-04 14:54:22 +0200277 @property
278 def xonxoff(self):
279 """Get the current XON/XOFF setting."""
280 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000281
Chris Liechti779b1a22015-08-04 14:54:22 +0200282 @xonxoff.setter
283 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000284 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000285 self._xonxoff = xonxoff
286 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000287
cliechti14b274a2009-02-07 00:27:05 +0000288
Chris Liechti779b1a22015-08-04 14:54:22 +0200289 @property
290 def rtscts(self):
291 """Get the current RTS/CTS flow control setting."""
292 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000293
Chris Liechti779b1a22015-08-04 14:54:22 +0200294 @rtscts.setter
295 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000296 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000297 self._rtscts = rtscts
298 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000299
cliechti14b274a2009-02-07 00:27:05 +0000300
Chris Liechti779b1a22015-08-04 14:54:22 +0200301 @property
302 def dsrdtr(self):
303 """Get the current DSR/DTR flow control setting."""
304 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000305
Chris Liechti779b1a22015-08-04 14:54:22 +0200306 @dsrdtr.setter
307 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000308 """Change DsrDtr flow control setting."""
309 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000310 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000311 self._dsrdtr = self._rtscts
312 else:
cliechti14b274a2009-02-07 00:27:05 +0000313 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000314 self._dsrdtr = dsrdtr
315 if self._isOpen: self._reconfigurePort()
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 interCharTimeout(self):
320 """Get the current inter-character timeout setting."""
321 return self._interCharTimeout
cliechti679bfa62008-06-20 23:58:15 +0000322
Chris Liechti779b1a22015-08-04 14:54:22 +0200323 @interCharTimeout.setter
324 def interCharTimeout(self, interCharTimeout):
cliechti679bfa62008-06-20 23:58:15 +0000325 """Change inter-character timeout setting."""
326 if interCharTimeout is not None:
327 if interCharTimeout < 0: raise ValueError("Not a valid timeout: %r" % interCharTimeout)
328 try:
cliechti14b274a2009-02-07 00:27:05 +0000329 interCharTimeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti679bfa62008-06-20 23:58:15 +0000330 except TypeError:
331 raise ValueError("Not a valid timeout: %r" % interCharTimeout)
cliechti14b274a2009-02-07 00:27:05 +0000332
cliechti679bfa62008-06-20 23:58:15 +0000333 self._interCharTimeout = interCharTimeout
334 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000335
cliechti679bfa62008-06-20 23:58:15 +0000336
cliechti4065dce2009-08-10 00:55:46 +0000337 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200338 # functions useful for RS-485 adapters
339
340 @property
341 def rs485_mode(self):
342 """\
343 Enable RS485 mode and apply new settings, set to None to disable.
344 See serial.rs485.RS485Settings for more info about the value.
345 """
346 return self._rs485_mode
347
348 @rs485_mode.setter
349 def rs485_mode(self, rs485_settings):
350 self._rs485_mode = rs485_settings
351 if self._isOpen: self._reconfigurePort()
352
353 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000354
355 _SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
356 'dsrdtr', 'rtscts', 'timeout', 'writeTimeout', 'interCharTimeout')
357
358 def getSettingsDict(self):
cliechti7d448562014-08-03 21:57:45 +0000359 """\
360 Get current port settings as a dictionary. For use with
361 applySettingsDict.
362 """
cliechti4065dce2009-08-10 00:55:46 +0000363 return dict([(key, getattr(self, '_'+key)) for key in self._SETTINGS])
364
365 def applySettingsDict(self, d):
cliechti7d448562014-08-03 21:57:45 +0000366 """\
367 apply stored settings from a dictionary returned from
cliechti4065dce2009-08-10 00:55:46 +0000368 getSettingsDict. it's allowed to delete keys from the dictionary. these
cliechti7d448562014-08-03 21:57:45 +0000369 values will simply left unchanged.
370 """
cliechti4065dce2009-08-10 00:55:46 +0000371 for key in self._SETTINGS:
Chris Liechtib74be012015-08-04 16:36:01 +0200372 if key in d and d[key] != getattr(self, '_'+key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000373 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000374
cliechtid6bf52c2003-10-01 02:28:12 +0000375 # - - - - - - - - - - - - - - - - - - - - - - - -
376
377 def __repr__(self):
378 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000379 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 +0000380 self.__class__.__name__,
381 id(self),
382 self._isOpen,
383 self.portstr,
384 self.baudrate,
385 self.bytesize,
386 self.parity,
387 self.stopbits,
388 self.timeout,
389 self.xonxoff,
390 self.rtscts,
cliechtif46e0a82005-05-19 15:24:57 +0000391 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000392 )
393
cliechti4a567a02009-07-27 22:09:31 +0000394
395 # - - - - - - - - - - - - - - - - - - - - - - - -
396 # compatibility with io library
397
398 def readable(self): return True
399 def writable(self): return True
400 def seekable(self): return False
401 def readinto(self, b):
402 data = self.read(len(b))
403 n = len(data)
404 try:
405 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200406 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000407 import array
408 if not isinstance(b, array.array):
409 raise err
410 b[:n] = array.array('b', data)
411 return n
cliechtif81362e2009-07-25 03:44:33 +0000412
Chris Liechti70b89232015-08-04 03:00:52 +0200413 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200414 # context manager
415
416 def __enter__(self):
417 return self
418
419 def __exit__(self, *args, **kwargs):
420 self.close()
421
422 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200423 # additional functionality
424
425 def read_until(self, terminator=LF, size=None):
426 """\
427 Read until a termination sequence is found ('\n' by default), the size
428 is exceeded or until timeout occurs.
429 """
430 lenterm = len(terminator)
431 line = bytearray()
432 while True:
433 c = self.read(1)
434 if c:
435 line += c
436 if line[-lenterm:] == terminator:
437 break
438 if size is not None and len(line) >= size:
439 break
440 else:
441 break
442 return bytes(line)
443
444
445 def iread_until(self, *args, **kwargs):
446 """\
447 Read lines, implemented as generator. It will raise StopIteration on
448 timeout (empty read).
449 """
450 while True:
451 line = self.read_until(*args, **kwargs)
452 if not line: break
453 yield line
cliechtif81362e2009-07-25 03:44:33 +0000454
Chris Liechti779b1a22015-08-04 14:54:22 +0200455
456# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000457if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000458 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000459 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200460 sys.stdout.write('port name: %s\n' % s.name)
461 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
462 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
463 sys.stdout.write('parities: %s\n' % s.PARITIES)
464 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000465 sys.stdout.write('%s\n' % s)