blob: d0a196ec20ae24ed33a8abd00599fbd46885baa2 [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 Liechti033f17c2015-08-30 21:28:04 +020032 a = b[x:x + 1]
Chris Liechtif99cd5c2015-08-13 22:54:16 +020033 x += 1
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020034 if a:
35 yield a
36 else:
37 break
38
Chris Liechti033f17c2015-08-30 21:28:04 +020039
cliechti38077122013-10-16 02:57:27 +000040# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
41# so a simple ``bytes(sequence)`` doesn't work for all versions
cliechti32c10332009-08-05 13:23:43 +000042def to_bytes(seq):
43 """convert a sequence to a bytes type"""
cliechti38077122013-10-16 02:57:27 +000044 if isinstance(seq, bytes):
45 return seq
46 elif isinstance(seq, bytearray):
47 return bytes(seq)
48 elif isinstance(seq, memoryview):
49 return seq.tobytes()
50 else:
51 b = bytearray()
52 for item in seq:
Chris Liechti07447732015-08-05 00:39:12 +020053 # this one handles int and bytes in Python 2.7
54 # add conversion in case of Python 3.x
55 if isinstance(item, bytes):
56 item = ord(item)
57 b.append(item)
cliechti38077122013-10-16 02:57:27 +000058 return bytes(b)
cliechti32c10332009-08-05 13:23:43 +000059
60# create control bytes
61XON = to_bytes([17])
62XOFF = to_bytes([19])
cliechti4a567a02009-07-27 22:09:31 +000063
cliechti8e99b6f2010-07-21 15:46:39 +000064CR = to_bytes([13])
65LF = to_bytes([10])
66
cliechtia3a811f2009-07-29 21:59:03 +000067
cliechti0d6029a2008-06-21 01:28:46 +000068PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
cliechti58b481c2009-02-16 20:42:32 +000069STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
cliechti14b274a2009-02-07 00:27:05 +000070FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
cliechtid6bf52c2003-10-01 02:28:12 +000071
72PARITY_NAMES = {
Chris Liechti033f17c2015-08-30 21:28:04 +020073 PARITY_NONE: 'None',
74 PARITY_EVEN: 'Even',
75 PARITY_ODD: 'Odd',
76 PARITY_MARK: 'Mark',
cliechti4a567a02009-07-27 22:09:31 +000077 PARITY_SPACE: 'Space',
cliechtid6bf52c2003-10-01 02:28:12 +000078}
79
cliechti1dbe4b62002-02-14 02:49:25 +000080
cliechti4a567a02009-07-27 22:09:31 +000081class SerialException(IOError):
cliechtid6bf52c2003-10-01 02:28:12 +000082 """Base class for serial port related exceptions."""
cliechti7fe54d52002-03-03 20:11:47 +000083
cliechtid6bf52c2003-10-01 02:28:12 +000084
cliechti62611612004-04-20 01:55:43 +000085class SerialTimeoutException(SerialException):
86 """Write timeouts give an exception"""
87
cliechti4a567a02009-07-27 22:09:31 +000088
cliechti4b20ec62012-08-16 01:04:44 +000089writeTimeoutError = SerialTimeoutException('Write timeout')
90portNotOpenError = SerialException('Attempting to use a port that is not open')
cliechti62611612004-04-20 01:55:43 +000091
cliechtif81362e2009-07-25 03:44:33 +000092
Chris Liechtief6b7b42015-08-06 22:19:26 +020093class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +000094 """\
95 Serial port base class. Provides __init__ function and properties to
96 get/set port settings.
97 """
cliechti14b274a2009-02-07 00:27:05 +000098
cliechtidfec0c82009-07-21 01:35:41 +000099 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +0000100 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
101 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
102 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
103 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +0000104 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
cliechti14b274a2009-02-07 00:27:05 +0000105 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
cliechti6ffdb8f2009-07-22 00:48:57 +0000106 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +0000107
cliechtid6bf52c2003-10-01 02:28:12 +0000108 def __init__(self,
Chris Liechti033f17c2015-08-30 21:28:04 +0200109 port=None, # number of device, numbering starts at
cliechti14b274a2009-02-07 00:27:05 +0000110 # zero. if everything fails, the user
111 # can specify a device string, note
112 # that this isn't portable anymore
113 # port will be opened if one is specified
cliechtidfec0c82009-07-21 01:35:41 +0000114 baudrate=9600, # baud rate
115 bytesize=EIGHTBITS, # number of data bits
cliechti14b274a2009-02-07 00:27:05 +0000116 parity=PARITY_NONE, # enable parity checking
Chris Liechti033f17c2015-08-30 21:28:04 +0200117 stopbits=STOPBITS_ONE, # number of stop bits
cliechti14b274a2009-02-07 00:27:05 +0000118 timeout=None, # set a timeout value, None to wait forever
cliechti74308e42010-07-21 14:03:59 +0000119 xonxoff=False, # enable software flow control
120 rtscts=False, # enable RTS/CTS flow control
Chris Liechti518b0d32015-08-30 02:20:39 +0200121 write_timeout=None, # set a timeout for writes
cliechti58a2aee2010-05-20 23:37:57 +0000122 dsrdtr=False, # None: use rtscts setting, dsrdtr override if True or False
Chris Liechti033f17c2015-08-30 21:28:04 +0200123 inter_byte_timeout=None # Inter-character timeout, None to disable
cliechtid6bf52c2003-10-01 02:28:12 +0000124 ):
cliechti7d448562014-08-03 21:57:45 +0000125 """\
126 Initialize comm port object. If a port is given, then the port will be
127 opened immediately. Otherwise a Serial port object in closed state
128 is returned.
129 """
cliechtid6bf52c2003-10-01 02:28:12 +0000130
Chris Liechti033f17c2015-08-30 21:28:04 +0200131 self.is_open = False
132 self._port = None # correct value is assigned below through properties
133 self._baudrate = None # correct value is assigned below through properties
134 self._bytesize = None # correct value is assigned below through properties
135 self._parity = None # correct value is assigned below through properties
136 self._stopbits = None # correct value is assigned below through properties
137 self._timeout = None # correct value is assigned below through properties
138 self._write_timeout = None # correct value is assigned below through properties
139 self._xonxoff = None # correct value is assigned below through properties
140 self._rtscts = None # correct value is assigned below through properties
141 self._dsrdtr = None # correct value is assigned below through properties
142 self._inter_byte_timeout = None # correct value is assigned below through properties
143 self._rs485_mode = None # disabled by default
Chris Liechtief1fe252015-08-27 23:25:21 +0200144 self._rts_state = True
145 self._dtr_state = True
146 self._break_state = False
cliechti14b274a2009-02-07 00:27:05 +0000147
148 # assign values using get/set methods using the properties feature
Chris Liechti033f17c2015-08-30 21:28:04 +0200149 self.port = port
cliechtid6bf52c2003-10-01 02:28:12 +0000150 self.baudrate = baudrate
151 self.bytesize = bytesize
Chris Liechti033f17c2015-08-30 21:28:04 +0200152 self.parity = parity
cliechtid6bf52c2003-10-01 02:28:12 +0000153 self.stopbits = stopbits
Chris Liechti033f17c2015-08-30 21:28:04 +0200154 self.timeout = timeout
Chris Liechti518b0d32015-08-30 02:20:39 +0200155 self.write_timeout = write_timeout
Chris Liechti033f17c2015-08-30 21:28:04 +0200156 self.xonxoff = xonxoff
157 self.rtscts = rtscts
158 self.dsrdtr = dsrdtr
Chris Liechti518b0d32015-08-30 02:20:39 +0200159 self.inter_character_timeout = inter_byte_timeout
cliechti14b274a2009-02-07 00:27:05 +0000160
cliechtid6bf52c2003-10-01 02:28:12 +0000161 if port is not None:
162 self.open()
163
cliechtid6bf52c2003-10-01 02:28:12 +0000164 # - - - - - - - - - - - - - - - - - - - - - - - -
165
Chris Liechti779b1a22015-08-04 14:54:22 +0200166 @property
167 def port(self):
168 """\
169 Get the current port setting. The value that was passed on init or using
170 setPort() is passed back. See also the attribute portstr which contains
171 the name of the port as a string.
172 """
173 return self._port
174
175 @port.setter
176 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000177 """\
178 Change the port. The attribute portstr is set to a string that
179 contains the name of the port.
180 """
cliechti14b274a2009-02-07 00:27:05 +0000181
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200182 was_open = self.is_open
183 if was_open:
184 self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200185 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000186 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000187 self.name = self.portstr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200188 if was_open:
189 self.open()
cliechti14b274a2009-02-07 00:27:05 +0000190
cliechtid6bf52c2003-10-01 02:28:12 +0000191
Chris Liechti779b1a22015-08-04 14:54:22 +0200192 @property
193 def baudrate(self):
194 """Get the current baud rate setting."""
195 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000196
Chris Liechti779b1a22015-08-04 14:54:22 +0200197 @baudrate.setter
198 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000199 """\
200 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000201 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000202 accepted and the exception is raised when the port is opened.
203 """
cliechti107db8d2004-01-15 01:20:23 +0000204 try:
cliechtie30868d2013-10-16 15:35:11 +0000205 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000206 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000207 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
cliechti107db8d2004-01-15 01:20:23 +0000208 else:
cliechtie30868d2013-10-16 15:35:11 +0000209 if b <= 0:
210 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
211 self._baudrate = b
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200212 if self.is_open:
213 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000214
cliechti14b274a2009-02-07 00:27:05 +0000215
Chris Liechti779b1a22015-08-04 14:54:22 +0200216 @property
217 def bytesize(self):
218 """Get the current byte size setting."""
219 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000220
Chris Liechti779b1a22015-08-04 14:54:22 +0200221 @bytesize.setter
222 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000223 """Change byte size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200224 if bytesize not in self.BYTESIZES:
225 raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000226 self._bytesize = bytesize
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200227 if self.is_open:
228 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000229
cliechtid6bf52c2003-10-01 02:28:12 +0000230
231
Chris Liechti779b1a22015-08-04 14:54:22 +0200232 @property
233 def parity(self):
234 """Get the current parity setting."""
235 return self._parity
236
237 @parity.setter
238 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000239 """Change parity setting."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200240 if parity not in self.PARITIES:
241 raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000242 self._parity = parity
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200243 if self.is_open:
244 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000245
cliechtid6bf52c2003-10-01 02:28:12 +0000246
247
Chris Liechti779b1a22015-08-04 14:54:22 +0200248 @property
249 def stopbits(self):
250 """Get the current stop bits setting."""
251 return self._stopbits
252
253 @stopbits.setter
254 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000255 """Change stop bits size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200256 if stopbits not in self.STOPBITS:
257 raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000258 self._stopbits = stopbits
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200259 if self.is_open:
260 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000261
cliechti14b274a2009-02-07 00:27:05 +0000262
Chris Liechti779b1a22015-08-04 14:54:22 +0200263 @property
264 def timeout(self):
265 """Get the current timeout setting."""
266 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000267
Chris Liechti779b1a22015-08-04 14:54:22 +0200268 @timeout.setter
269 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000270 """Change timeout setting."""
271 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000272 try:
cliechti14b274a2009-02-07 00:27:05 +0000273 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000274 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000275 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti2750b832009-07-28 00:13:52 +0000276 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000277 self._timeout = timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200278 if self.is_open:
279 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000280
Chris Liechti779b1a22015-08-04 14:54:22 +0200281
282 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200283 def write_timeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000284 """Get the current timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200285 return self._write_timeout
cliechti14b274a2009-02-07 00:27:05 +0000286
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200287 @write_timeout.setter
288 def write_timeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000289 """Change timeout setting."""
290 if timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200291 if timeout < 0:
292 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000293 try:
Chris Liechti033f17c2015-08-30 21:28:04 +0200294 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti62611612004-04-20 01:55:43 +0000295 except TypeError:
296 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000297
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200298 self._write_timeout = timeout
299 if self.is_open:
300 self._reconfigure_port()
301
302
303 @property
Chris Liechti518b0d32015-08-30 02:20:39 +0200304 def inter_byte_timeout(self):
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200305 """Get the current inter-character timeout setting."""
Chris Liechti96242372015-09-02 02:49:49 +0200306 return self._inter_byte_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200307
Chris Liechti518b0d32015-08-30 02:20:39 +0200308 @inter_byte_timeout.setter
309 def inter_byte_timeout(self, ic_timeout):
310 """Change inter-byte timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200311 if ic_timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200312 if ic_timeout < 0:
313 raise ValueError("Not a valid timeout: %r" % ic_timeout)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200314 try:
315 ic_timeout + 1 # test if it's a number, will throw a TypeError if not...
316 except TypeError:
317 raise ValueError("Not a valid timeout: %r" % ic_timeout)
318
Chris Liechti518b0d32015-08-30 02:20:39 +0200319 self._inter_byte_timeout = ic_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200320 if self.is_open:
321 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000322
cliechti14b274a2009-02-07 00:27:05 +0000323
Chris Liechti779b1a22015-08-04 14:54:22 +0200324 @property
325 def xonxoff(self):
326 """Get the current XON/XOFF setting."""
327 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000328
Chris Liechti779b1a22015-08-04 14:54:22 +0200329 @xonxoff.setter
330 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000331 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000332 self._xonxoff = xonxoff
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200333 if self.is_open:
334 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000335
cliechti14b274a2009-02-07 00:27:05 +0000336
Chris Liechti779b1a22015-08-04 14:54:22 +0200337 @property
338 def rtscts(self):
339 """Get the current RTS/CTS flow control setting."""
340 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000341
Chris Liechti779b1a22015-08-04 14:54:22 +0200342 @rtscts.setter
343 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000344 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000345 self._rtscts = rtscts
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200346 if self.is_open:
347 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000348
cliechti14b274a2009-02-07 00:27:05 +0000349
Chris Liechti779b1a22015-08-04 14:54:22 +0200350 @property
351 def dsrdtr(self):
352 """Get the current DSR/DTR flow control setting."""
353 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000354
Chris Liechti779b1a22015-08-04 14:54:22 +0200355 @dsrdtr.setter
356 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000357 """Change DsrDtr flow control setting."""
358 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000359 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000360 self._dsrdtr = self._rtscts
361 else:
cliechti14b274a2009-02-07 00:27:05 +0000362 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000363 self._dsrdtr = dsrdtr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200364 if self.is_open:
365 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000366
cliechti14b274a2009-02-07 00:27:05 +0000367
Chris Liechti779b1a22015-08-04 14:54:22 +0200368 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200369 def rts(self):
370 return self._rts_state
cliechti679bfa62008-06-20 23:58:15 +0000371
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200372 @rts.setter
373 def rts(self, value):
374 self._rts_state = value
375 if self.is_open:
376 self._update_rts_state()
cliechti14b274a2009-02-07 00:27:05 +0000377
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200378 @property
379 def dtr(self):
380 return self._dtr_state
cliechti14b274a2009-02-07 00:27:05 +0000381
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200382 @dtr.setter
383 def dtr(self, value):
384 self._dtr_state = value
385 if self.is_open:
386 self._update_dtr_state()
387
388 @property
389 def break_condition(self):
390 return self._break_state
391
392 @break_condition.setter
393 def break_condition(self, value):
394 self._break_state = value
395 if self.is_open:
396 self._update_break_state()
cliechti679bfa62008-06-20 23:58:15 +0000397
cliechti4065dce2009-08-10 00:55:46 +0000398 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200399 # functions useful for RS-485 adapters
400
401 @property
402 def rs485_mode(self):
403 """\
404 Enable RS485 mode and apply new settings, set to None to disable.
405 See serial.rs485.RS485Settings for more info about the value.
406 """
407 return self._rs485_mode
408
409 @rs485_mode.setter
410 def rs485_mode(self, rs485_settings):
411 self._rs485_mode = rs485_settings
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200412 if self.is_open:
413 self._reconfigure_port()
Chris Liechti33f0ec52015-08-06 16:37:21 +0200414
415 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000416
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200417 _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
Chris Liechti033f17c2015-08-30 21:28:04 +0200418 'dsrdtr', 'rtscts', 'timeout', 'write_timeout',
Chris Liechti1c3249f2015-09-01 02:31:36 +0200419 'inter_byte_timeout')
cliechti4065dce2009-08-10 00:55:46 +0000420
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200421 def get_settings(self):
cliechti7d448562014-08-03 21:57:45 +0000422 """\
423 Get current port settings as a dictionary. For use with
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200424 apply_settings().
cliechti7d448562014-08-03 21:57:45 +0000425 """
Chris Liechti033f17c2015-08-30 21:28:04 +0200426 return dict([(key, getattr(self, '_' + key)) for key in self._SAVED_SETTINGS])
cliechti4065dce2009-08-10 00:55:46 +0000427
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200428 def apply_settings(self, d):
cliechti7d448562014-08-03 21:57:45 +0000429 """\
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200430 Apply stored settings from a dictionary returned from
431 get_settings(). It's allowed to delete keys from the dictionary. These
cliechti7d448562014-08-03 21:57:45 +0000432 values will simply left unchanged.
433 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200434 for key in self._SAVED_SETTINGS:
Chris Liechti033f17c2015-08-30 21:28:04 +0200435 if key in d and d[key] != getattr(self, '_' + key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000436 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000437
cliechtid6bf52c2003-10-01 02:28:12 +0000438 # - - - - - - - - - - - - - - - - - - - - - - - -
439
440 def __repr__(self):
441 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000442 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)" % (
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200443 self.__class__.__name__,
444 id(self),
445 self.is_open,
446 self.portstr,
447 self.baudrate,
448 self.bytesize,
449 self.parity,
450 self.stopbits,
451 self.timeout,
452 self.xonxoff,
453 self.rtscts,
454 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000455 )
456
cliechti4a567a02009-07-27 22:09:31 +0000457
458 # - - - - - - - - - - - - - - - - - - - - - - - -
459 # compatibility with io library
460
Chris Liechti033f17c2015-08-30 21:28:04 +0200461 def readable(self):
462 return True
463
464 def writable(self):
465 return True
466
467 def seekable(self):
468 return False
469
cliechti4a567a02009-07-27 22:09:31 +0000470 def readinto(self, b):
471 data = self.read(len(b))
472 n = len(data)
473 try:
474 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200475 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000476 import array
477 if not isinstance(b, array.array):
478 raise err
479 b[:n] = array.array('b', data)
480 return n
cliechtif81362e2009-07-25 03:44:33 +0000481
Chris Liechti70b89232015-08-04 03:00:52 +0200482 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200483 # context manager
484
485 def __enter__(self):
486 return self
487
488 def __exit__(self, *args, **kwargs):
489 self.close()
490
491 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechtief1fe252015-08-27 23:25:21 +0200492
493 def send_break(self, duration=0.25):
494 """\
495 Send break condition. Timed, returns to idle state after given
496 duration.
497 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200498 if not self.is_open:
499 raise portNotOpenError
Chris Liechtief1fe252015-08-27 23:25:21 +0200500 self.break_condition = True
501 time.sleep(duration)
502 self.break_condition = False
503
504 # - - - - - - - - - - - - - - - - - - - - - - - -
505 # backwards compatibility / deprecated functions
506
507 def flushInput(self):
508 self.reset_input_buffer()
509
510 def flushOutput(self):
511 self.reset_output_buffer()
512
513 def inWaiting(self):
514 return self.in_waiting
515
516 def sendBreak(self, duration=0.25):
517 self.send_break(duration)
518
519 def setRTS(self, value=1):
520 self.rts = value
521
522 def setDTR(self, value=1):
523 self.dtr = value
524
525 def getCTS(self):
526 return self.cts
527
528 def getDSR(self):
529 return self.dsr
530
531 def getRI(self):
532 return self.ri
533
534 def getCD(self):
535 return self.cd
536
537 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200538 def writeTimeout(self):
539 return self.write_timeout
540
541 @writeTimeout.setter
542 def writeTimeout(self, timeout):
543 self.write_timeout = timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200544
545 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200546 def interCharTimeout(self):
Chris Liechti96242372015-09-02 02:49:49 +0200547 return self.inter_byte_timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200548
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200549 @interCharTimeout.setter
550 def interCharTimeout(self, interCharTimeout):
Chris Liechti96242372015-09-02 02:49:49 +0200551 self.inter_byte_timeout = interCharTimeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200552
553 def getSettingsDict(self):
554 return self.get_settings()
555
556 def applySettingsDict(self, d):
557 self.apply_settings(d)
558
559 def isOpen(self):
560 return self._is_open
Chris Liechtief1fe252015-08-27 23:25:21 +0200561
562 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200563 # additional functionality
564
565 def read_until(self, terminator=LF, size=None):
566 """\
567 Read until a termination sequence is found ('\n' by default), the size
568 is exceeded or until timeout occurs.
569 """
570 lenterm = len(terminator)
571 line = bytearray()
572 while True:
573 c = self.read(1)
574 if c:
575 line += c
576 if line[-lenterm:] == terminator:
577 break
578 if size is not None and len(line) >= size:
579 break
580 else:
581 break
582 return bytes(line)
583
Chris Liechti70b89232015-08-04 03:00:52 +0200584 def iread_until(self, *args, **kwargs):
585 """\
586 Read lines, implemented as generator. It will raise StopIteration on
587 timeout (empty read).
588 """
589 while True:
590 line = self.read_until(*args, **kwargs)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200591 if not line:
592 break
Chris Liechti70b89232015-08-04 03:00:52 +0200593 yield line
cliechtif81362e2009-07-25 03:44:33 +0000594
Chris Liechti779b1a22015-08-04 14:54:22 +0200595
596# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000597if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000598 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000599 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200600 sys.stdout.write('port name: %s\n' % s.name)
601 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
602 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
603 sys.stdout.write('parities: %s\n' % s.PARITIES)
604 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000605 sys.stdout.write('%s\n' % s)