blob: 87733b73f20bb68f197204addd54f61c9a7ad82b [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)"""
Chris Liechti12a439f2015-08-20 23:01:53 +020028 if isinstance(b, memoryview):
29 b = b.tobytes()
Chris Liechtif99cd5c2015-08-13 22:54:16 +020030 x = 0
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020031 while True:
Chris Liechtif99cd5c2015-08-13 22:54:16 +020032 a = b[x:x+1]
33 x += 1
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020034 if a:
35 yield a
36 else:
37 break
38
cliechti38077122013-10-16 02:57:27 +000039# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
40# so a simple ``bytes(sequence)`` doesn't work for all versions
cliechti32c10332009-08-05 13:23:43 +000041def to_bytes(seq):
42 """convert a sequence to a bytes type"""
cliechti38077122013-10-16 02:57:27 +000043 if isinstance(seq, bytes):
44 return seq
45 elif isinstance(seq, bytearray):
46 return bytes(seq)
47 elif isinstance(seq, memoryview):
48 return seq.tobytes()
49 else:
50 b = bytearray()
51 for item in seq:
Chris Liechti07447732015-08-05 00:39:12 +020052 # this one handles int and bytes in Python 2.7
53 # add conversion in case of Python 3.x
54 if isinstance(item, bytes):
55 item = ord(item)
56 b.append(item)
cliechti38077122013-10-16 02:57:27 +000057 return bytes(b)
cliechti32c10332009-08-05 13:23:43 +000058
59# create control bytes
60XON = to_bytes([17])
61XOFF = to_bytes([19])
cliechti4a567a02009-07-27 22:09:31 +000062
cliechti8e99b6f2010-07-21 15:46:39 +000063CR = to_bytes([13])
64LF = to_bytes([10])
65
cliechtia3a811f2009-07-29 21:59:03 +000066
cliechti0d6029a2008-06-21 01:28:46 +000067PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
cliechti58b481c2009-02-16 20:42:32 +000068STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
cliechti14b274a2009-02-07 00:27:05 +000069FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
cliechtid6bf52c2003-10-01 02:28:12 +000070
71PARITY_NAMES = {
cliechti4a567a02009-07-27 22:09:31 +000072 PARITY_NONE: 'None',
73 PARITY_EVEN: 'Even',
74 PARITY_ODD: 'Odd',
75 PARITY_MARK: 'Mark',
76 PARITY_SPACE: 'Space',
cliechtid6bf52c2003-10-01 02:28:12 +000077}
78
cliechti1dbe4b62002-02-14 02:49:25 +000079
cliechti4a567a02009-07-27 22:09:31 +000080class SerialException(IOError):
cliechtid6bf52c2003-10-01 02:28:12 +000081 """Base class for serial port related exceptions."""
cliechti7fe54d52002-03-03 20:11:47 +000082
cliechtid6bf52c2003-10-01 02:28:12 +000083
cliechti62611612004-04-20 01:55:43 +000084class SerialTimeoutException(SerialException):
85 """Write timeouts give an exception"""
86
cliechti4a567a02009-07-27 22:09:31 +000087
cliechti4b20ec62012-08-16 01:04:44 +000088writeTimeoutError = SerialTimeoutException('Write timeout')
89portNotOpenError = SerialException('Attempting to use a port that is not open')
cliechti62611612004-04-20 01:55:43 +000090
cliechtif81362e2009-07-25 03:44:33 +000091
Chris Liechtief6b7b42015-08-06 22:19:26 +020092class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +000093 """\
94 Serial port base class. Provides __init__ function and properties to
95 get/set port settings.
96 """
cliechti14b274a2009-02-07 00:27:05 +000097
cliechtidfec0c82009-07-21 01:35:41 +000098 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +000099 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
100 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
101 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
102 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +0000103 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
cliechti14b274a2009-02-07 00:27:05 +0000104 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
cliechti6ffdb8f2009-07-22 00:48:57 +0000105 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +0000106
cliechtid6bf52c2003-10-01 02:28:12 +0000107 def __init__(self,
cliechti14b274a2009-02-07 00:27:05 +0000108 port = None, # number of device, numbering starts at
109 # zero. if everything fails, the user
110 # can specify a device string, note
111 # that this isn't portable anymore
112 # port will be opened if one is specified
cliechtidfec0c82009-07-21 01:35:41 +0000113 baudrate=9600, # baud rate
114 bytesize=EIGHTBITS, # number of data bits
cliechti14b274a2009-02-07 00:27:05 +0000115 parity=PARITY_NONE, # enable parity checking
cliechtidfec0c82009-07-21 01:35:41 +0000116 stopbits=STOPBITS_ONE, # number of stop bits
cliechti14b274a2009-02-07 00:27:05 +0000117 timeout=None, # set a timeout value, None to wait forever
cliechti74308e42010-07-21 14:03:59 +0000118 xonxoff=False, # enable software flow control
119 rtscts=False, # enable RTS/CTS flow control
cliechti14b274a2009-02-07 00:27:05 +0000120 writeTimeout=None, # set a timeout for writes
cliechti58a2aee2010-05-20 23:37:57 +0000121 dsrdtr=False, # None: use rtscts setting, dsrdtr override if True or False
cliechti14b274a2009-02-07 00:27:05 +0000122 interCharTimeout=None # Inter-character timeout, None to disable
cliechtid6bf52c2003-10-01 02:28:12 +0000123 ):
cliechti7d448562014-08-03 21:57:45 +0000124 """\
125 Initialize comm port object. If a port is given, then the port will be
126 opened immediately. Otherwise a Serial port object in closed state
127 is returned.
128 """
cliechtid6bf52c2003-10-01 02:28:12 +0000129
130 self._isOpen = False
cliechti4a567a02009-07-27 22:09:31 +0000131 self._port = None # correct value is assigned below through properties
132 self._baudrate = None # correct value is assigned below through properties
133 self._bytesize = None # correct value is assigned below through properties
134 self._parity = None # correct value is assigned below through properties
135 self._stopbits = None # correct value is assigned below through properties
136 self._timeout = None # correct value is assigned below through properties
137 self._writeTimeout = None # correct value is assigned below through properties
138 self._xonxoff = None # correct value is assigned below through properties
139 self._rtscts = None # correct value is assigned below through properties
140 self._dsrdtr = None # correct value is assigned below through properties
141 self._interCharTimeout = None # correct value is assigned below through properties
Chris Liechti33f0ec52015-08-06 16:37:21 +0200142 self._rs485_mode = None # disabled by default
Chris Liechtief1fe252015-08-27 23:25:21 +0200143 self._rts_state = True
144 self._dtr_state = True
145 self._break_state = False
cliechti14b274a2009-02-07 00:27:05 +0000146
147 # assign values using get/set methods using the properties feature
cliechtid6bf52c2003-10-01 02:28:12 +0000148 self.port = port
149 self.baudrate = baudrate
150 self.bytesize = bytesize
151 self.parity = parity
152 self.stopbits = stopbits
153 self.timeout = timeout
cliechti62611612004-04-20 01:55:43 +0000154 self.writeTimeout = writeTimeout
cliechtid6bf52c2003-10-01 02:28:12 +0000155 self.xonxoff = xonxoff
156 self.rtscts = rtscts
cliechtif46e0a82005-05-19 15:24:57 +0000157 self.dsrdtr = dsrdtr
cliechti679bfa62008-06-20 23:58:15 +0000158 self.interCharTimeout = interCharTimeout
cliechti14b274a2009-02-07 00:27:05 +0000159
cliechtid6bf52c2003-10-01 02:28:12 +0000160 if port is not None:
161 self.open()
162
163 def isOpen(self):
164 """Check if the port is opened."""
165 return self._isOpen
166
cliechtid6bf52c2003-10-01 02:28:12 +0000167
168 # - - - - - - - - - - - - - - - - - - - - - - - -
169
Chris Liechti779b1a22015-08-04 14:54:22 +0200170 @property
171 def port(self):
172 """\
173 Get the current port setting. The value that was passed on init or using
174 setPort() is passed back. See also the attribute portstr which contains
175 the name of the port as a string.
176 """
177 return self._port
178
179 @port.setter
180 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000181 """\
182 Change the port. The attribute portstr is set to a string that
183 contains the name of the port.
184 """
cliechti14b274a2009-02-07 00:27:05 +0000185
cliechtid6bf52c2003-10-01 02:28:12 +0000186 was_open = self._isOpen
187 if was_open: self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200188 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000189 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000190 self.name = self.portstr
cliechtid6bf52c2003-10-01 02:28:12 +0000191 if was_open: self.open()
cliechti14b274a2009-02-07 00:27:05 +0000192
cliechtid6bf52c2003-10-01 02:28:12 +0000193
Chris Liechti779b1a22015-08-04 14:54:22 +0200194 @property
195 def baudrate(self):
196 """Get the current baud rate setting."""
197 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000198
Chris Liechti779b1a22015-08-04 14:54:22 +0200199 @baudrate.setter
200 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000201 """\
202 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000203 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000204 accepted and the exception is raised when the port is opened.
205 """
cliechti107db8d2004-01-15 01:20:23 +0000206 try:
cliechtie30868d2013-10-16 15:35:11 +0000207 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000208 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000209 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
cliechti107db8d2004-01-15 01:20:23 +0000210 else:
cliechtie30868d2013-10-16 15:35:11 +0000211 if b <= 0:
212 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
213 self._baudrate = b
cliechti107db8d2004-01-15 01:20:23 +0000214 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000215
cliechti14b274a2009-02-07 00:27:05 +0000216
Chris Liechti779b1a22015-08-04 14:54:22 +0200217 @property
218 def bytesize(self):
219 """Get the current byte size setting."""
220 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000221
Chris Liechti779b1a22015-08-04 14:54:22 +0200222 @bytesize.setter
223 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000224 """Change byte size."""
cliechti93db61b2006-08-26 19:16:18 +0000225 if bytesize not in self.BYTESIZES: raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000226 self._bytesize = bytesize
227 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000228
cliechtid6bf52c2003-10-01 02:28:12 +0000229
230
Chris Liechti779b1a22015-08-04 14:54:22 +0200231 @property
232 def parity(self):
233 """Get the current parity setting."""
234 return self._parity
235
236 @parity.setter
237 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000238 """Change parity setting."""
cliechti93db61b2006-08-26 19:16:18 +0000239 if parity not in self.PARITIES: raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000240 self._parity = parity
241 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000242
cliechtid6bf52c2003-10-01 02:28:12 +0000243
244
Chris Liechti779b1a22015-08-04 14:54:22 +0200245 @property
246 def stopbits(self):
247 """Get the current stop bits setting."""
248 return self._stopbits
249
250 @stopbits.setter
251 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000252 """Change stop bits size."""
253 if stopbits not in self.STOPBITS: raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000254 self._stopbits = stopbits
255 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000256
cliechti14b274a2009-02-07 00:27:05 +0000257
Chris Liechti779b1a22015-08-04 14:54:22 +0200258 @property
259 def timeout(self):
260 """Get the current timeout setting."""
261 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000262
Chris Liechti779b1a22015-08-04 14:54:22 +0200263 @timeout.setter
264 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000265 """Change timeout setting."""
266 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000267 try:
cliechti14b274a2009-02-07 00:27:05 +0000268 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000269 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000270 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti2750b832009-07-28 00:13:52 +0000271 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000272 self._timeout = timeout
273 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000274
Chris Liechti779b1a22015-08-04 14:54:22 +0200275
276 @property
277 def writeTimeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000278 """Get the current timeout setting."""
Chris Liechti779b1a22015-08-04 14:54:22 +0200279 return self._writeTimeout
cliechti14b274a2009-02-07 00:27:05 +0000280
Chris Liechti779b1a22015-08-04 14:54:22 +0200281 @writeTimeout.setter
282 def writeTimeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000283 """Change timeout setting."""
284 if timeout is not None:
cliechti93db61b2006-08-26 19:16:18 +0000285 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000286 try:
287 timeout + 1 #test if it's a number, will throw a TypeError if not...
288 except TypeError:
289 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000290
cliechti62611612004-04-20 01:55:43 +0000291 self._writeTimeout = timeout
292 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000293
cliechti14b274a2009-02-07 00:27:05 +0000294
Chris Liechti779b1a22015-08-04 14:54:22 +0200295 @property
296 def xonxoff(self):
297 """Get the current XON/XOFF setting."""
298 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000299
Chris Liechti779b1a22015-08-04 14:54:22 +0200300 @xonxoff.setter
301 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000302 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000303 self._xonxoff = xonxoff
304 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000305
cliechti14b274a2009-02-07 00:27:05 +0000306
Chris Liechti779b1a22015-08-04 14:54:22 +0200307 @property
308 def rtscts(self):
309 """Get the current RTS/CTS flow control setting."""
310 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000311
Chris Liechti779b1a22015-08-04 14:54:22 +0200312 @rtscts.setter
313 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000314 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000315 self._rtscts = rtscts
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 dsrdtr(self):
321 """Get the current DSR/DTR flow control setting."""
322 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000323
Chris Liechti779b1a22015-08-04 14:54:22 +0200324 @dsrdtr.setter
325 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000326 """Change DsrDtr flow control setting."""
327 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000328 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000329 self._dsrdtr = self._rtscts
330 else:
cliechti14b274a2009-02-07 00:27:05 +0000331 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000332 self._dsrdtr = dsrdtr
333 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000334
cliechti14b274a2009-02-07 00:27:05 +0000335
Chris Liechti779b1a22015-08-04 14:54:22 +0200336 @property
337 def interCharTimeout(self):
338 """Get the current inter-character timeout setting."""
339 return self._interCharTimeout
cliechti679bfa62008-06-20 23:58:15 +0000340
Chris Liechti779b1a22015-08-04 14:54:22 +0200341 @interCharTimeout.setter
342 def interCharTimeout(self, interCharTimeout):
cliechti679bfa62008-06-20 23:58:15 +0000343 """Change inter-character timeout setting."""
344 if interCharTimeout is not None:
345 if interCharTimeout < 0: raise ValueError("Not a valid timeout: %r" % interCharTimeout)
346 try:
cliechti14b274a2009-02-07 00:27:05 +0000347 interCharTimeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti679bfa62008-06-20 23:58:15 +0000348 except TypeError:
349 raise ValueError("Not a valid timeout: %r" % interCharTimeout)
cliechti14b274a2009-02-07 00:27:05 +0000350
cliechti679bfa62008-06-20 23:58:15 +0000351 self._interCharTimeout = interCharTimeout
352 if self._isOpen: self._reconfigurePort()
cliechti14b274a2009-02-07 00:27:05 +0000353
cliechti679bfa62008-06-20 23:58:15 +0000354
cliechti4065dce2009-08-10 00:55:46 +0000355 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200356 # functions useful for RS-485 adapters
357
358 @property
359 def rs485_mode(self):
360 """\
361 Enable RS485 mode and apply new settings, set to None to disable.
362 See serial.rs485.RS485Settings for more info about the value.
363 """
364 return self._rs485_mode
365
366 @rs485_mode.setter
367 def rs485_mode(self, rs485_settings):
368 self._rs485_mode = rs485_settings
369 if self._isOpen: self._reconfigurePort()
370
371 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000372
373 _SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
374 'dsrdtr', 'rtscts', 'timeout', 'writeTimeout', 'interCharTimeout')
375
376 def getSettingsDict(self):
cliechti7d448562014-08-03 21:57:45 +0000377 """\
378 Get current port settings as a dictionary. For use with
379 applySettingsDict.
380 """
cliechti4065dce2009-08-10 00:55:46 +0000381 return dict([(key, getattr(self, '_'+key)) for key in self._SETTINGS])
382
383 def applySettingsDict(self, d):
cliechti7d448562014-08-03 21:57:45 +0000384 """\
385 apply stored settings from a dictionary returned from
cliechti4065dce2009-08-10 00:55:46 +0000386 getSettingsDict. it's allowed to delete keys from the dictionary. these
cliechti7d448562014-08-03 21:57:45 +0000387 values will simply left unchanged.
388 """
cliechti4065dce2009-08-10 00:55:46 +0000389 for key in self._SETTINGS:
Chris Liechtib74be012015-08-04 16:36:01 +0200390 if key in d and d[key] != getattr(self, '_'+key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000391 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000392
cliechtid6bf52c2003-10-01 02:28:12 +0000393 # - - - - - - - - - - - - - - - - - - - - - - - -
394
395 def __repr__(self):
396 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000397 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 +0000398 self.__class__.__name__,
399 id(self),
400 self._isOpen,
401 self.portstr,
402 self.baudrate,
403 self.bytesize,
404 self.parity,
405 self.stopbits,
406 self.timeout,
407 self.xonxoff,
408 self.rtscts,
cliechtif46e0a82005-05-19 15:24:57 +0000409 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000410 )
411
cliechti4a567a02009-07-27 22:09:31 +0000412
413 # - - - - - - - - - - - - - - - - - - - - - - - -
414 # compatibility with io library
415
416 def readable(self): return True
417 def writable(self): return True
418 def seekable(self): return False
419 def readinto(self, b):
420 data = self.read(len(b))
421 n = len(data)
422 try:
423 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200424 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000425 import array
426 if not isinstance(b, array.array):
427 raise err
428 b[:n] = array.array('b', data)
429 return n
cliechtif81362e2009-07-25 03:44:33 +0000430
Chris Liechti70b89232015-08-04 03:00:52 +0200431 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200432 # context manager
433
434 def __enter__(self):
435 return self
436
437 def __exit__(self, *args, **kwargs):
438 self.close()
439
440 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechtief1fe252015-08-27 23:25:21 +0200441
442 def send_break(self, duration=0.25):
443 """\
444 Send break condition. Timed, returns to idle state after given
445 duration.
446 """
447 if not self._isOpen: raise portNotOpenError
448 self.break_condition = True
449 time.sleep(duration)
450 self.break_condition = False
451
452 # - - - - - - - - - - - - - - - - - - - - - - - -
453 # backwards compatibility / deprecated functions
454
455 def flushInput(self):
456 self.reset_input_buffer()
457
458 def flushOutput(self):
459 self.reset_output_buffer()
460
461 def inWaiting(self):
462 return self.in_waiting
463
464 def sendBreak(self, duration=0.25):
465 self.send_break(duration)
466
467 def setRTS(self, value=1):
468 self.rts = value
469
470 def setDTR(self, value=1):
471 self.dtr = value
472
473 def getCTS(self):
474 return self.cts
475
476 def getDSR(self):
477 return self.dsr
478
479 def getRI(self):
480 return self.ri
481
482 def getCD(self):
483 return self.cd
484
485 @property
486 def rts(self):
487 return self._rts_state
488 @rts.setter
489 def rts(self, value):
490 self._rts_state = value
491 if self._isOpen:
492 self._update_rts_state()
493
494 @property
495 def dtr(self):
496 return self._dtr_state
497 @dtr.setter
498 def dtr(self, value):
499 self._dtr_state = value
500 if self._isOpen:
501 self._update_dtr_state()
502
503 @property
504 def break_condition(self):
505 return self._break_state
506 @break_condition.setter
507 def break_condition(self, value):
508 self._break_state = value
509 if self._isOpen:
510 self._update_break_state()
511
512 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200513 # additional functionality
514
515 def read_until(self, terminator=LF, size=None):
516 """\
517 Read until a termination sequence is found ('\n' by default), the size
518 is exceeded or until timeout occurs.
519 """
520 lenterm = len(terminator)
521 line = bytearray()
522 while True:
523 c = self.read(1)
524 if c:
525 line += c
526 if line[-lenterm:] == terminator:
527 break
528 if size is not None and len(line) >= size:
529 break
530 else:
531 break
532 return bytes(line)
533
534
535 def iread_until(self, *args, **kwargs):
536 """\
537 Read lines, implemented as generator. It will raise StopIteration on
538 timeout (empty read).
539 """
540 while True:
541 line = self.read_until(*args, **kwargs)
542 if not line: break
543 yield line
cliechtif81362e2009-07-25 03:44:33 +0000544
Chris Liechti779b1a22015-08-04 14:54:22 +0200545
546# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000547if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000548 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000549 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200550 sys.stdout.write('port name: %s\n' % s.name)
551 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
552 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
553 sys.stdout.write('parities: %s\n' % s.PARITIES)
554 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000555 sys.stdout.write('%s\n' % s)