blob: f23f024a989a844e96fa3d3a3723444bf2eec27e [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
cliechtic323f1f2010-07-22 00:14:26 +00008
cliechti38077122013-10-16 02:57:27 +00009# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)``
10# isn't returning the contents (very unfortunate). Therefore we need special
11# cases and test for it. Ensure that there is a ``memoryview`` object for older
12# Python versions. This is easier than making every test dependent on its
13# existence.
14try:
15 memoryview
16except (NameError, AttributeError):
17 # implementation does not matter as we do not realy use it.
18 # it just must not inherit from something else we might care for.
Chris Liechti70b89232015-08-04 03:00:52 +020019 class memoryview(object):
cliechti38077122013-10-16 02:57:27 +000020 pass
21
22
23# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
24# so a simple ``bytes(sequence)`` doesn't work for all versions
cliechti32c10332009-08-05 13:23:43 +000025def to_bytes(seq):
26 """convert a sequence to a bytes type"""
cliechti38077122013-10-16 02:57:27 +000027 if isinstance(seq, bytes):
28 return seq
29 elif isinstance(seq, bytearray):
30 return bytes(seq)
31 elif isinstance(seq, memoryview):
32 return seq.tobytes()
33 else:
34 b = bytearray()
35 for item in seq:
Chris Liechti07447732015-08-05 00:39:12 +020036 # this one handles int and bytes in Python 2.7
37 # add conversion in case of Python 3.x
38 if isinstance(item, bytes):
39 item = ord(item)
40 b.append(item)
cliechti38077122013-10-16 02:57:27 +000041 return bytes(b)
cliechti32c10332009-08-05 13:23:43 +000042
43# create control bytes
44XON = to_bytes([17])
45XOFF = to_bytes([19])
cliechti4a567a02009-07-27 22:09:31 +000046
cliechti8e99b6f2010-07-21 15:46:39 +000047CR = to_bytes([13])
48LF = to_bytes([10])
49
cliechtia3a811f2009-07-29 21:59:03 +000050
cliechti0d6029a2008-06-21 01:28:46 +000051PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
cliechti58b481c2009-02-16 20:42:32 +000052STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
cliechti14b274a2009-02-07 00:27:05 +000053FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
cliechtid6bf52c2003-10-01 02:28:12 +000054
55PARITY_NAMES = {
cliechti4a567a02009-07-27 22:09:31 +000056 PARITY_NONE: 'None',
57 PARITY_EVEN: 'Even',
58 PARITY_ODD: 'Odd',
59 PARITY_MARK: 'Mark',
60 PARITY_SPACE: 'Space',
cliechtid6bf52c2003-10-01 02:28:12 +000061}
62
cliechti1dbe4b62002-02-14 02:49:25 +000063
cliechti4a567a02009-07-27 22:09:31 +000064class SerialException(IOError):
cliechtid6bf52c2003-10-01 02:28:12 +000065 """Base class for serial port related exceptions."""
cliechti7fe54d52002-03-03 20:11:47 +000066
cliechtid6bf52c2003-10-01 02:28:12 +000067
cliechti62611612004-04-20 01:55:43 +000068class SerialTimeoutException(SerialException):
69 """Write timeouts give an exception"""
70
cliechti4a567a02009-07-27 22:09:31 +000071
cliechti4b20ec62012-08-16 01:04:44 +000072writeTimeoutError = SerialTimeoutException('Write timeout')
73portNotOpenError = SerialException('Attempting to use a port that is not open')
cliechti62611612004-04-20 01:55:43 +000074
cliechtif81362e2009-07-25 03:44:33 +000075
cliechtif81362e2009-07-25 03:44:33 +000076class SerialBase(object):
cliechti7d448562014-08-03 21:57:45 +000077 """\
78 Serial port base class. Provides __init__ function and properties to
79 get/set port settings.
80 """
cliechti14b274a2009-02-07 00:27:05 +000081
cliechtidfec0c82009-07-21 01:35:41 +000082 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +000083 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
84 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
85 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
86 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +000087 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
cliechti14b274a2009-02-07 00:27:05 +000088 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
cliechti6ffdb8f2009-07-22 00:48:57 +000089 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +000090
cliechtid6bf52c2003-10-01 02:28:12 +000091 def __init__(self,
cliechti14b274a2009-02-07 00:27:05 +000092 port = None, # number of device, numbering starts at
93 # zero. if everything fails, the user
94 # can specify a device string, note
95 # that this isn't portable anymore
96 # port will be opened if one is specified
cliechtidfec0c82009-07-21 01:35:41 +000097 baudrate=9600, # baud rate
98 bytesize=EIGHTBITS, # number of data bits
cliechti14b274a2009-02-07 00:27:05 +000099 parity=PARITY_NONE, # enable parity checking
cliechtidfec0c82009-07-21 01:35:41 +0000100 stopbits=STOPBITS_ONE, # number of stop bits
cliechti14b274a2009-02-07 00:27:05 +0000101 timeout=None, # set a timeout value, None to wait forever
cliechti74308e42010-07-21 14:03:59 +0000102 xonxoff=False, # enable software flow control
103 rtscts=False, # enable RTS/CTS flow control
cliechti14b274a2009-02-07 00:27:05 +0000104 writeTimeout=None, # set a timeout for writes
cliechti58a2aee2010-05-20 23:37:57 +0000105 dsrdtr=False, # None: use rtscts setting, dsrdtr override if True or False
cliechti14b274a2009-02-07 00:27:05 +0000106 interCharTimeout=None # Inter-character timeout, None to disable
cliechtid6bf52c2003-10-01 02:28:12 +0000107 ):
cliechti7d448562014-08-03 21:57:45 +0000108 """\
109 Initialize comm port object. If a port is given, then the port will be
110 opened immediately. Otherwise a Serial port object in closed state
111 is returned.
112 """
cliechtid6bf52c2003-10-01 02:28:12 +0000113
114 self._isOpen = False
cliechti4a567a02009-07-27 22:09:31 +0000115 self._port = None # correct value is assigned below through properties
116 self._baudrate = None # correct value is assigned below through properties
117 self._bytesize = None # correct value is assigned below through properties
118 self._parity = None # correct value is assigned below through properties
119 self._stopbits = None # correct value is assigned below through properties
120 self._timeout = None # correct value is assigned below through properties
121 self._writeTimeout = None # correct value is assigned below through properties
122 self._xonxoff = None # correct value is assigned below through properties
123 self._rtscts = None # correct value is assigned below through properties
124 self._dsrdtr = None # correct value is assigned below through properties
125 self._interCharTimeout = None # correct value is assigned below through properties
Chris Liechti33f0ec52015-08-06 16:37:21 +0200126 self._rs485_mode = None # disabled by default
cliechti14b274a2009-02-07 00:27:05 +0000127
128 # assign values using get/set methods using the properties feature
cliechtid6bf52c2003-10-01 02:28:12 +0000129 self.port = port
130 self.baudrate = baudrate
131 self.bytesize = bytesize
132 self.parity = parity
133 self.stopbits = stopbits
134 self.timeout = timeout
cliechti62611612004-04-20 01:55:43 +0000135 self.writeTimeout = writeTimeout
cliechtid6bf52c2003-10-01 02:28:12 +0000136 self.xonxoff = xonxoff
137 self.rtscts = rtscts
cliechtif46e0a82005-05-19 15:24:57 +0000138 self.dsrdtr = dsrdtr
cliechti679bfa62008-06-20 23:58:15 +0000139 self.interCharTimeout = interCharTimeout
cliechti14b274a2009-02-07 00:27:05 +0000140
cliechtid6bf52c2003-10-01 02:28:12 +0000141 if port is not None:
142 self.open()
143
144 def isOpen(self):
145 """Check if the port is opened."""
146 return self._isOpen
147
cliechtid6bf52c2003-10-01 02:28:12 +0000148
149 # - - - - - - - - - - - - - - - - - - - - - - - -
150
Chris Liechti779b1a22015-08-04 14:54:22 +0200151 @property
152 def port(self):
153 """\
154 Get the current port setting. The value that was passed on init or using
155 setPort() is passed back. See also the attribute portstr which contains
156 the name of the port as a string.
157 """
158 return self._port
159
160 @port.setter
161 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000162 """\
163 Change the port. The attribute portstr is set to a string that
164 contains the name of the port.
165 """
cliechti14b274a2009-02-07 00:27:05 +0000166
cliechtid6bf52c2003-10-01 02:28:12 +0000167 was_open = self._isOpen
168 if was_open: self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200169 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000170 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000171 self.name = self.portstr
cliechtid6bf52c2003-10-01 02:28:12 +0000172 if was_open: self.open()
cliechti14b274a2009-02-07 00:27:05 +0000173
cliechtid6bf52c2003-10-01 02:28:12 +0000174
Chris Liechti779b1a22015-08-04 14:54:22 +0200175 @property
176 def baudrate(self):
177 """Get the current baud rate setting."""
178 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000179
Chris Liechti779b1a22015-08-04 14:54:22 +0200180 @baudrate.setter
181 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000182 """\
183 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000184 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000185 accepted and the exception is raised when the port is opened.
186 """
cliechti107db8d2004-01-15 01:20:23 +0000187 try:
cliechtie30868d2013-10-16 15:35:11 +0000188 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000189 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000190 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
cliechti107db8d2004-01-15 01:20:23 +0000191 else:
cliechtie30868d2013-10-16 15:35:11 +0000192 if b <= 0:
193 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
194 self._baudrate = b
cliechti107db8d2004-01-15 01:20:23 +0000195 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000196
cliechti14b274a2009-02-07 00:27:05 +0000197
Chris Liechti779b1a22015-08-04 14:54:22 +0200198 @property
199 def bytesize(self):
200 """Get the current byte size setting."""
201 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000202
Chris Liechti779b1a22015-08-04 14:54:22 +0200203 @bytesize.setter
204 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000205 """Change byte size."""
cliechti93db61b2006-08-26 19:16:18 +0000206 if bytesize not in self.BYTESIZES: raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000207 self._bytesize = bytesize
208 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000209
cliechtid6bf52c2003-10-01 02:28:12 +0000210
211
Chris Liechti779b1a22015-08-04 14:54:22 +0200212 @property
213 def parity(self):
214 """Get the current parity setting."""
215 return self._parity
216
217 @parity.setter
218 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000219 """Change parity setting."""
cliechti93db61b2006-08-26 19:16:18 +0000220 if parity not in self.PARITIES: raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000221 self._parity = parity
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 stopbits(self):
228 """Get the current stop bits setting."""
229 return self._stopbits
230
231 @stopbits.setter
232 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000233 """Change stop bits size."""
234 if stopbits not in self.STOPBITS: raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000235 self._stopbits = stopbits
236 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000237
cliechti14b274a2009-02-07 00:27:05 +0000238
Chris Liechti779b1a22015-08-04 14:54:22 +0200239 @property
240 def timeout(self):
241 """Get the current timeout setting."""
242 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000243
Chris Liechti779b1a22015-08-04 14:54:22 +0200244 @timeout.setter
245 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000246 """Change timeout setting."""
247 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000248 try:
cliechti14b274a2009-02-07 00:27:05 +0000249 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000250 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000251 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti2750b832009-07-28 00:13:52 +0000252 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000253 self._timeout = timeout
254 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000255
Chris Liechti779b1a22015-08-04 14:54:22 +0200256
257 @property
258 def writeTimeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000259 """Get the current timeout setting."""
Chris Liechti779b1a22015-08-04 14:54:22 +0200260 return self._writeTimeout
cliechti14b274a2009-02-07 00:27:05 +0000261
Chris Liechti779b1a22015-08-04 14:54:22 +0200262 @writeTimeout.setter
263 def writeTimeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000264 """Change timeout setting."""
265 if timeout is not None:
cliechti93db61b2006-08-26 19:16:18 +0000266 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000267 try:
268 timeout + 1 #test if it's a number, will throw a TypeError if not...
269 except TypeError:
270 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000271
cliechti62611612004-04-20 01:55:43 +0000272 self._writeTimeout = timeout
273 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000274
cliechti14b274a2009-02-07 00:27:05 +0000275
Chris Liechti779b1a22015-08-04 14:54:22 +0200276 @property
277 def xonxoff(self):
278 """Get the current XON/XOFF setting."""
279 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000280
Chris Liechti779b1a22015-08-04 14:54:22 +0200281 @xonxoff.setter
282 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000283 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000284 self._xonxoff = xonxoff
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 rtscts(self):
290 """Get the current RTS/CTS flow control setting."""
291 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000292
Chris Liechti779b1a22015-08-04 14:54:22 +0200293 @rtscts.setter
294 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000295 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000296 self._rtscts = rtscts
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 dsrdtr(self):
302 """Get the current DSR/DTR flow control setting."""
303 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000304
Chris Liechti779b1a22015-08-04 14:54:22 +0200305 @dsrdtr.setter
306 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000307 """Change DsrDtr flow control setting."""
308 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000309 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000310 self._dsrdtr = self._rtscts
311 else:
cliechti14b274a2009-02-07 00:27:05 +0000312 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000313 self._dsrdtr = dsrdtr
314 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000315
cliechti14b274a2009-02-07 00:27:05 +0000316
Chris Liechti779b1a22015-08-04 14:54:22 +0200317 @property
318 def interCharTimeout(self):
319 """Get the current inter-character timeout setting."""
320 return self._interCharTimeout
cliechti679bfa62008-06-20 23:58:15 +0000321
Chris Liechti779b1a22015-08-04 14:54:22 +0200322 @interCharTimeout.setter
323 def interCharTimeout(self, interCharTimeout):
cliechti679bfa62008-06-20 23:58:15 +0000324 """Change inter-character timeout setting."""
325 if interCharTimeout is not None:
326 if interCharTimeout < 0: raise ValueError("Not a valid timeout: %r" % interCharTimeout)
327 try:
cliechti14b274a2009-02-07 00:27:05 +0000328 interCharTimeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti679bfa62008-06-20 23:58:15 +0000329 except TypeError:
330 raise ValueError("Not a valid timeout: %r" % interCharTimeout)
cliechti14b274a2009-02-07 00:27:05 +0000331
cliechti679bfa62008-06-20 23:58:15 +0000332 self._interCharTimeout = interCharTimeout
333 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000334
cliechti679bfa62008-06-20 23:58:15 +0000335
cliechti4065dce2009-08-10 00:55:46 +0000336 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200337 # functions useful for RS-485 adapters
338
339 @property
340 def rs485_mode(self):
341 """\
342 Enable RS485 mode and apply new settings, set to None to disable.
343 See serial.rs485.RS485Settings for more info about the value.
344 """
345 return self._rs485_mode
346
347 @rs485_mode.setter
348 def rs485_mode(self, rs485_settings):
349 self._rs485_mode = rs485_settings
350 if self._isOpen: self._reconfigurePort()
351
352 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000353
354 _SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
355 'dsrdtr', 'rtscts', 'timeout', 'writeTimeout', 'interCharTimeout')
356
357 def getSettingsDict(self):
cliechti7d448562014-08-03 21:57:45 +0000358 """\
359 Get current port settings as a dictionary. For use with
360 applySettingsDict.
361 """
cliechti4065dce2009-08-10 00:55:46 +0000362 return dict([(key, getattr(self, '_'+key)) for key in self._SETTINGS])
363
364 def applySettingsDict(self, d):
cliechti7d448562014-08-03 21:57:45 +0000365 """\
366 apply stored settings from a dictionary returned from
cliechti4065dce2009-08-10 00:55:46 +0000367 getSettingsDict. it's allowed to delete keys from the dictionary. these
cliechti7d448562014-08-03 21:57:45 +0000368 values will simply left unchanged.
369 """
cliechti4065dce2009-08-10 00:55:46 +0000370 for key in self._SETTINGS:
Chris Liechtib74be012015-08-04 16:36:01 +0200371 if key in d and d[key] != getattr(self, '_'+key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000372 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000373
cliechtid6bf52c2003-10-01 02:28:12 +0000374 # - - - - - - - - - - - - - - - - - - - - - - - -
375
376 def __repr__(self):
377 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000378 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 +0000379 self.__class__.__name__,
380 id(self),
381 self._isOpen,
382 self.portstr,
383 self.baudrate,
384 self.bytesize,
385 self.parity,
386 self.stopbits,
387 self.timeout,
388 self.xonxoff,
389 self.rtscts,
cliechtif46e0a82005-05-19 15:24:57 +0000390 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000391 )
392
cliechti4a567a02009-07-27 22:09:31 +0000393
394 # - - - - - - - - - - - - - - - - - - - - - - - -
395 # compatibility with io library
396
397 def readable(self): return True
398 def writable(self): return True
399 def seekable(self): return False
400 def readinto(self, b):
401 data = self.read(len(b))
402 n = len(data)
403 try:
404 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200405 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000406 import array
407 if not isinstance(b, array.array):
408 raise err
409 b[:n] = array.array('b', data)
410 return n
cliechtif81362e2009-07-25 03:44:33 +0000411
Chris Liechti70b89232015-08-04 03:00:52 +0200412 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200413 # context manager
414
415 def __enter__(self):
416 return self
417
418 def __exit__(self, *args, **kwargs):
419 self.close()
420
421 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200422 # additional functionality
423
424 def read_until(self, terminator=LF, size=None):
425 """\
426 Read until a termination sequence is found ('\n' by default), the size
427 is exceeded or until timeout occurs.
428 """
429 lenterm = len(terminator)
430 line = bytearray()
431 while True:
432 c = self.read(1)
433 if c:
434 line += c
435 if line[-lenterm:] == terminator:
436 break
437 if size is not None and len(line) >= size:
438 break
439 else:
440 break
441 return bytes(line)
442
443
444 def iread_until(self, *args, **kwargs):
445 """\
446 Read lines, implemented as generator. It will raise StopIteration on
447 timeout (empty read).
448 """
449 while True:
450 line = self.read_until(*args, **kwargs)
451 if not line: break
452 yield line
cliechtif81362e2009-07-25 03:44:33 +0000453
Chris Liechti779b1a22015-08-04 14:54:22 +0200454
455# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000456if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000457 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000458 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200459 sys.stdout.write('port name: %s\n' % s.name)
460 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
461 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
462 sys.stdout.write('parities: %s\n' % s.PARITIES)
463 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000464 sys.stdout.write('%s\n' % s)