blob: a71b6183b1d9050fc51ca2761fabad4d530ff964 [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
Chris Liechticf29a352015-10-23 22:03:40 +020010import time
cliechtic323f1f2010-07-22 00:14:26 +000011
cliechti38077122013-10-16 02:57:27 +000012# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)``
13# isn't returning the contents (very unfortunate). Therefore we need special
14# cases and test for it. Ensure that there is a ``memoryview`` object for older
15# Python versions. This is easier than making every test dependent on its
16# existence.
17try:
18 memoryview
19except (NameError, AttributeError):
20 # implementation does not matter as we do not realy use it.
21 # it just must not inherit from something else we might care for.
Chris Liechti70b89232015-08-04 03:00:52 +020022 class memoryview(object):
cliechti38077122013-10-16 02:57:27 +000023 pass
24
Chris Liechti4a790ad2015-09-09 17:12:52 +020025try:
26 unicode
27except (NameError, AttributeError):
28 unicode = str # for Python 3
29
cliechti38077122013-10-16 02:57:27 +000030
Chris Liechtif99cd5c2015-08-13 22:54:16 +020031# "for byte in data" fails for python3 as it returns ints instead of bytes
32def iterbytes(b):
33 """Iterate over bytes, returning bytes instead of ints (python3)"""
Chris Liechti12a439f2015-08-20 23:01:53 +020034 if isinstance(b, memoryview):
35 b = b.tobytes()
Chris Liechtif99cd5c2015-08-13 22:54:16 +020036 x = 0
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020037 while True:
Chris Liechti033f17c2015-08-30 21:28:04 +020038 a = b[x:x + 1]
Chris Liechtif99cd5c2015-08-13 22:54:16 +020039 x += 1
Chris Liechti5eaaa4e2015-08-17 03:08:55 +020040 if a:
41 yield a
42 else:
43 break
44
Chris Liechti033f17c2015-08-30 21:28:04 +020045
cliechti38077122013-10-16 02:57:27 +000046# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
47# so a simple ``bytes(sequence)`` doesn't work for all versions
cliechti32c10332009-08-05 13:23:43 +000048def to_bytes(seq):
49 """convert a sequence to a bytes type"""
cliechti38077122013-10-16 02:57:27 +000050 if isinstance(seq, bytes):
51 return seq
52 elif isinstance(seq, bytearray):
53 return bytes(seq)
54 elif isinstance(seq, memoryview):
55 return seq.tobytes()
Chris Liechti4a790ad2015-09-09 17:12:52 +020056 elif isinstance(seq, unicode):
57 raise TypeError('unicode strings are not supported, please encode to bytes: %r' % (seq,))
cliechti38077122013-10-16 02:57:27 +000058 else:
59 b = bytearray()
60 for item in seq:
Chris Liechti07447732015-08-05 00:39:12 +020061 # this one handles int and bytes in Python 2.7
62 # add conversion in case of Python 3.x
63 if isinstance(item, bytes):
64 item = ord(item)
65 b.append(item)
cliechti38077122013-10-16 02:57:27 +000066 return bytes(b)
cliechti32c10332009-08-05 13:23:43 +000067
68# create control bytes
Chris Liechticf29a352015-10-23 22:03:40 +020069XON = to_bytes([17])
cliechti32c10332009-08-05 13:23:43 +000070XOFF = to_bytes([19])
cliechti4a567a02009-07-27 22:09:31 +000071
cliechti8e99b6f2010-07-21 15:46:39 +000072CR = to_bytes([13])
73LF = to_bytes([10])
74
cliechtia3a811f2009-07-29 21:59:03 +000075
cliechti0d6029a2008-06-21 01:28:46 +000076PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
cliechti58b481c2009-02-16 20:42:32 +000077STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
cliechti14b274a2009-02-07 00:27:05 +000078FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
cliechtid6bf52c2003-10-01 02:28:12 +000079
80PARITY_NAMES = {
Chris Liechti033f17c2015-08-30 21:28:04 +020081 PARITY_NONE: 'None',
82 PARITY_EVEN: 'Even',
83 PARITY_ODD: 'Odd',
84 PARITY_MARK: 'Mark',
cliechti4a567a02009-07-27 22:09:31 +000085 PARITY_SPACE: 'Space',
cliechtid6bf52c2003-10-01 02:28:12 +000086}
87
cliechti1dbe4b62002-02-14 02:49:25 +000088
cliechti4a567a02009-07-27 22:09:31 +000089class SerialException(IOError):
cliechtid6bf52c2003-10-01 02:28:12 +000090 """Base class for serial port related exceptions."""
cliechti7fe54d52002-03-03 20:11:47 +000091
cliechtid6bf52c2003-10-01 02:28:12 +000092
cliechti62611612004-04-20 01:55:43 +000093class SerialTimeoutException(SerialException):
94 """Write timeouts give an exception"""
95
cliechti4a567a02009-07-27 22:09:31 +000096
cliechti4b20ec62012-08-16 01:04:44 +000097writeTimeoutError = SerialTimeoutException('Write timeout')
98portNotOpenError = SerialException('Attempting to use a port that is not open')
cliechti62611612004-04-20 01:55:43 +000099
cliechtif81362e2009-07-25 03:44:33 +0000100
Chris Liechtief6b7b42015-08-06 22:19:26 +0200101class SerialBase(io.RawIOBase):
cliechti7d448562014-08-03 21:57:45 +0000102 """\
103 Serial port base class. Provides __init__ function and properties to
104 get/set port settings.
105 """
cliechti14b274a2009-02-07 00:27:05 +0000106
cliechtidfec0c82009-07-21 01:35:41 +0000107 # default values, may be overridden in subclasses that do not support all values
cliechtif81362e2009-07-25 03:44:33 +0000108 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
109 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
110 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
111 3000000, 3500000, 4000000)
cliechtid6bf52c2003-10-01 02:28:12 +0000112 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
Chris Liechticf29a352015-10-23 22:03:40 +0200113 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
114 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
cliechti14b274a2009-02-07 00:27:05 +0000115
cliechtid6bf52c2003-10-01 02:28:12 +0000116 def __init__(self,
Chris Liechti033f17c2015-08-30 21:28:04 +0200117 port=None, # number of device, numbering starts at
cliechti14b274a2009-02-07 00:27:05 +0000118 # zero. if everything fails, the user
119 # can specify a device string, note
120 # that this isn't portable anymore
121 # port will be opened if one is specified
cliechtidfec0c82009-07-21 01:35:41 +0000122 baudrate=9600, # baud rate
123 bytesize=EIGHTBITS, # number of data bits
cliechti14b274a2009-02-07 00:27:05 +0000124 parity=PARITY_NONE, # enable parity checking
Chris Liechti033f17c2015-08-30 21:28:04 +0200125 stopbits=STOPBITS_ONE, # number of stop bits
cliechti14b274a2009-02-07 00:27:05 +0000126 timeout=None, # set a timeout value, None to wait forever
cliechti74308e42010-07-21 14:03:59 +0000127 xonxoff=False, # enable software flow control
128 rtscts=False, # enable RTS/CTS flow control
Chris Liechti518b0d32015-08-30 02:20:39 +0200129 write_timeout=None, # set a timeout for writes
cliechti58a2aee2010-05-20 23:37:57 +0000130 dsrdtr=False, # None: use rtscts setting, dsrdtr override if True or False
Chris Liechti033f17c2015-08-30 21:28:04 +0200131 inter_byte_timeout=None # Inter-character timeout, None to disable
cliechtid6bf52c2003-10-01 02:28:12 +0000132 ):
cliechti7d448562014-08-03 21:57:45 +0000133 """\
134 Initialize comm port object. If a port is given, then the port will be
135 opened immediately. Otherwise a Serial port object in closed state
136 is returned.
137 """
cliechtid6bf52c2003-10-01 02:28:12 +0000138
Chris Liechti033f17c2015-08-30 21:28:04 +0200139 self.is_open = False
140 self._port = None # correct value is assigned below through properties
141 self._baudrate = None # correct value is assigned below through properties
142 self._bytesize = None # correct value is assigned below through properties
Chris Liechticf29a352015-10-23 22:03:40 +0200143 self._parity = None # correct value is assigned below through properties
Chris Liechti033f17c2015-08-30 21:28:04 +0200144 self._stopbits = None # correct value is assigned below through properties
145 self._timeout = None # correct value is assigned below through properties
146 self._write_timeout = None # correct value is assigned below through properties
147 self._xonxoff = None # correct value is assigned below through properties
148 self._rtscts = None # correct value is assigned below through properties
149 self._dsrdtr = None # correct value is assigned below through properties
150 self._inter_byte_timeout = None # correct value is assigned below through properties
151 self._rs485_mode = None # disabled by default
Chris Liechtief1fe252015-08-27 23:25:21 +0200152 self._rts_state = True
153 self._dtr_state = True
154 self._break_state = False
cliechti14b274a2009-02-07 00:27:05 +0000155
156 # assign values using get/set methods using the properties feature
Chris Liechti033f17c2015-08-30 21:28:04 +0200157 self.port = port
cliechtid6bf52c2003-10-01 02:28:12 +0000158 self.baudrate = baudrate
159 self.bytesize = bytesize
Chris Liechti033f17c2015-08-30 21:28:04 +0200160 self.parity = parity
cliechtid6bf52c2003-10-01 02:28:12 +0000161 self.stopbits = stopbits
Chris Liechti033f17c2015-08-30 21:28:04 +0200162 self.timeout = timeout
Chris Liechti518b0d32015-08-30 02:20:39 +0200163 self.write_timeout = write_timeout
Chris Liechti033f17c2015-08-30 21:28:04 +0200164 self.xonxoff = xonxoff
165 self.rtscts = rtscts
166 self.dsrdtr = dsrdtr
Chris Liechtib5331752015-10-24 01:34:11 +0200167 self.inter_byte_timeout = inter_byte_timeout
cliechti14b274a2009-02-07 00:27:05 +0000168
cliechtid6bf52c2003-10-01 02:28:12 +0000169 if port is not None:
170 self.open()
171
cliechtid6bf52c2003-10-01 02:28:12 +0000172 # - - - - - - - - - - - - - - - - - - - - - - - -
173
Chris Liechti5e763ca2015-12-09 13:01:26 +0100174 def open(self):
175 """Opens the Port"""
176 raise NotImplementedError("This function must be implemented in the subclass")
177
178 def close(self):
179 """Closes the Port"""
180 raise NotImplementedError("This function must be implemented in the subclass")
181
182 # - - - - - - - - - - - - - - - - - - - - - - - -
183
Chris Liechti779b1a22015-08-04 14:54:22 +0200184 @property
185 def port(self):
186 """\
187 Get the current port setting. The value that was passed on init or using
188 setPort() is passed back. See also the attribute portstr which contains
189 the name of the port as a string.
190 """
191 return self._port
192
193 @port.setter
194 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000195 """\
196 Change the port. The attribute portstr is set to a string that
197 contains the name of the port.
198 """
cliechti14b274a2009-02-07 00:27:05 +0000199
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200200 was_open = self.is_open
201 if was_open:
202 self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200203 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000204 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000205 self.name = self.portstr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200206 if was_open:
207 self.open()
cliechti14b274a2009-02-07 00:27:05 +0000208
cliechtid6bf52c2003-10-01 02:28:12 +0000209
Chris Liechti779b1a22015-08-04 14:54:22 +0200210 @property
211 def baudrate(self):
212 """Get the current baud rate setting."""
213 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000214
Chris Liechti779b1a22015-08-04 14:54:22 +0200215 @baudrate.setter
216 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000217 """\
218 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000219 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000220 accepted and the exception is raised when the port is opened.
221 """
cliechti107db8d2004-01-15 01:20:23 +0000222 try:
cliechtie30868d2013-10-16 15:35:11 +0000223 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000224 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000225 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
cliechti107db8d2004-01-15 01:20:23 +0000226 else:
cliechtie30868d2013-10-16 15:35:11 +0000227 if b <= 0:
228 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
229 self._baudrate = b
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200230 if self.is_open:
231 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000232
cliechti14b274a2009-02-07 00:27:05 +0000233
Chris Liechti779b1a22015-08-04 14:54:22 +0200234 @property
235 def bytesize(self):
236 """Get the current byte size setting."""
237 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000238
Chris Liechti779b1a22015-08-04 14:54:22 +0200239 @bytesize.setter
240 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000241 """Change byte size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200242 if bytesize not in self.BYTESIZES:
243 raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000244 self._bytesize = bytesize
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200245 if self.is_open:
246 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000247
cliechtid6bf52c2003-10-01 02:28:12 +0000248
249
Chris Liechti779b1a22015-08-04 14:54:22 +0200250 @property
251 def parity(self):
252 """Get the current parity setting."""
253 return self._parity
254
255 @parity.setter
256 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000257 """Change parity setting."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200258 if parity not in self.PARITIES:
259 raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000260 self._parity = parity
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200261 if self.is_open:
262 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000263
cliechtid6bf52c2003-10-01 02:28:12 +0000264
265
Chris Liechti779b1a22015-08-04 14:54:22 +0200266 @property
267 def stopbits(self):
268 """Get the current stop bits setting."""
269 return self._stopbits
270
271 @stopbits.setter
272 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000273 """Change stop bits size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200274 if stopbits not in self.STOPBITS:
275 raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000276 self._stopbits = stopbits
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200277 if self.is_open:
278 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000279
cliechti14b274a2009-02-07 00:27:05 +0000280
Chris Liechti779b1a22015-08-04 14:54:22 +0200281 @property
282 def timeout(self):
283 """Get the current timeout setting."""
284 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000285
Chris Liechti779b1a22015-08-04 14:54:22 +0200286 @timeout.setter
287 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000288 """Change timeout setting."""
289 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000290 try:
cliechti14b274a2009-02-07 00:27:05 +0000291 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000292 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000293 raise ValueError("Not a valid timeout: %r" % (timeout,))
Chris Liechticf29a352015-10-23 22:03:40 +0200294 if timeout < 0:
295 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000296 self._timeout = timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200297 if self.is_open:
298 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000299
Chris Liechti779b1a22015-08-04 14:54:22 +0200300
301 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200302 def write_timeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000303 """Get the current timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200304 return self._write_timeout
cliechti14b274a2009-02-07 00:27:05 +0000305
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200306 @write_timeout.setter
307 def write_timeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000308 """Change timeout setting."""
309 if timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200310 if timeout < 0:
311 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000312 try:
Chris Liechti033f17c2015-08-30 21:28:04 +0200313 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti62611612004-04-20 01:55:43 +0000314 except TypeError:
315 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000316
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200317 self._write_timeout = timeout
318 if self.is_open:
319 self._reconfigure_port()
320
321
322 @property
Chris Liechti518b0d32015-08-30 02:20:39 +0200323 def inter_byte_timeout(self):
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200324 """Get the current inter-character timeout setting."""
Chris Liechti96242372015-09-02 02:49:49 +0200325 return self._inter_byte_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200326
Chris Liechti518b0d32015-08-30 02:20:39 +0200327 @inter_byte_timeout.setter
328 def inter_byte_timeout(self, ic_timeout):
329 """Change inter-byte timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200330 if ic_timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200331 if ic_timeout < 0:
332 raise ValueError("Not a valid timeout: %r" % ic_timeout)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200333 try:
334 ic_timeout + 1 # test if it's a number, will throw a TypeError if not...
335 except TypeError:
336 raise ValueError("Not a valid timeout: %r" % ic_timeout)
337
Chris Liechti518b0d32015-08-30 02:20:39 +0200338 self._inter_byte_timeout = ic_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200339 if self.is_open:
340 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000341
cliechti14b274a2009-02-07 00:27:05 +0000342
Chris Liechti779b1a22015-08-04 14:54:22 +0200343 @property
344 def xonxoff(self):
345 """Get the current XON/XOFF setting."""
346 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000347
Chris Liechti779b1a22015-08-04 14:54:22 +0200348 @xonxoff.setter
349 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000350 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000351 self._xonxoff = xonxoff
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200352 if self.is_open:
353 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000354
cliechti14b274a2009-02-07 00:27:05 +0000355
Chris Liechti779b1a22015-08-04 14:54:22 +0200356 @property
357 def rtscts(self):
358 """Get the current RTS/CTS flow control setting."""
359 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000360
Chris Liechti779b1a22015-08-04 14:54:22 +0200361 @rtscts.setter
362 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000363 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000364 self._rtscts = rtscts
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200365 if self.is_open:
366 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000367
cliechti14b274a2009-02-07 00:27:05 +0000368
Chris Liechti779b1a22015-08-04 14:54:22 +0200369 @property
370 def dsrdtr(self):
371 """Get the current DSR/DTR flow control setting."""
372 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000373
Chris Liechti779b1a22015-08-04 14:54:22 +0200374 @dsrdtr.setter
375 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000376 """Change DsrDtr flow control setting."""
377 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000378 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000379 self._dsrdtr = self._rtscts
380 else:
cliechti14b274a2009-02-07 00:27:05 +0000381 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000382 self._dsrdtr = dsrdtr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200383 if self.is_open:
384 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000385
cliechti14b274a2009-02-07 00:27:05 +0000386
Chris Liechti779b1a22015-08-04 14:54:22 +0200387 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200388 def rts(self):
389 return self._rts_state
cliechti679bfa62008-06-20 23:58:15 +0000390
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200391 @rts.setter
392 def rts(self, value):
393 self._rts_state = value
394 if self.is_open:
395 self._update_rts_state()
cliechti14b274a2009-02-07 00:27:05 +0000396
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200397 @property
398 def dtr(self):
399 return self._dtr_state
cliechti14b274a2009-02-07 00:27:05 +0000400
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200401 @dtr.setter
402 def dtr(self, value):
403 self._dtr_state = value
404 if self.is_open:
405 self._update_dtr_state()
406
407 @property
408 def break_condition(self):
409 return self._break_state
410
411 @break_condition.setter
412 def break_condition(self, value):
413 self._break_state = value
414 if self.is_open:
415 self._update_break_state()
cliechti679bfa62008-06-20 23:58:15 +0000416
cliechti4065dce2009-08-10 00:55:46 +0000417 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200418 # functions useful for RS-485 adapters
419
420 @property
421 def rs485_mode(self):
422 """\
423 Enable RS485 mode and apply new settings, set to None to disable.
424 See serial.rs485.RS485Settings for more info about the value.
425 """
426 return self._rs485_mode
427
428 @rs485_mode.setter
429 def rs485_mode(self, rs485_settings):
430 self._rs485_mode = rs485_settings
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200431 if self.is_open:
432 self._reconfigure_port()
Chris Liechti33f0ec52015-08-06 16:37:21 +0200433
434 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000435
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200436 _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
Chris Liechti033f17c2015-08-30 21:28:04 +0200437 'dsrdtr', 'rtscts', 'timeout', 'write_timeout',
Chris Liechti1c3249f2015-09-01 02:31:36 +0200438 'inter_byte_timeout')
cliechti4065dce2009-08-10 00:55:46 +0000439
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200440 def get_settings(self):
cliechti7d448562014-08-03 21:57:45 +0000441 """\
442 Get current port settings as a dictionary. For use with
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200443 apply_settings().
cliechti7d448562014-08-03 21:57:45 +0000444 """
Chris Liechti033f17c2015-08-30 21:28:04 +0200445 return dict([(key, getattr(self, '_' + key)) for key in self._SAVED_SETTINGS])
cliechti4065dce2009-08-10 00:55:46 +0000446
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200447 def apply_settings(self, d):
cliechti7d448562014-08-03 21:57:45 +0000448 """\
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200449 Apply stored settings from a dictionary returned from
450 get_settings(). It's allowed to delete keys from the dictionary. These
cliechti7d448562014-08-03 21:57:45 +0000451 values will simply left unchanged.
452 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200453 for key in self._SAVED_SETTINGS:
Chris Liechti033f17c2015-08-30 21:28:04 +0200454 if key in d and d[key] != getattr(self, '_' + key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000455 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000456
cliechtid6bf52c2003-10-01 02:28:12 +0000457 # - - - - - - - - - - - - - - - - - - - - - - - -
458
459 def __repr__(self):
460 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000461 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 +0200462 self.__class__.__name__,
463 id(self),
464 self.is_open,
465 self.portstr,
466 self.baudrate,
467 self.bytesize,
468 self.parity,
469 self.stopbits,
470 self.timeout,
471 self.xonxoff,
472 self.rtscts,
473 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000474 )
475
cliechti4a567a02009-07-27 22:09:31 +0000476 # - - - - - - - - - - - - - - - - - - - - - - - -
477 # compatibility with io library
478
Chris Liechti033f17c2015-08-30 21:28:04 +0200479 def readable(self):
480 return True
481
482 def writable(self):
483 return True
484
485 def seekable(self):
486 return False
487
cliechti4a567a02009-07-27 22:09:31 +0000488 def readinto(self, b):
489 data = self.read(len(b))
490 n = len(data)
491 try:
492 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200493 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000494 import array
495 if not isinstance(b, array.array):
496 raise err
497 b[:n] = array.array('b', data)
498 return n
cliechtif81362e2009-07-25 03:44:33 +0000499
Chris Liechti70b89232015-08-04 03:00:52 +0200500 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200501 # context manager
502
503 def __enter__(self):
504 return self
505
506 def __exit__(self, *args, **kwargs):
507 self.close()
508
509 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechtief1fe252015-08-27 23:25:21 +0200510
511 def send_break(self, duration=0.25):
512 """\
513 Send break condition. Timed, returns to idle state after given
514 duration.
515 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200516 if not self.is_open:
517 raise portNotOpenError
Chris Liechtief1fe252015-08-27 23:25:21 +0200518 self.break_condition = True
519 time.sleep(duration)
520 self.break_condition = False
521
522 # - - - - - - - - - - - - - - - - - - - - - - - -
523 # backwards compatibility / deprecated functions
524
525 def flushInput(self):
526 self.reset_input_buffer()
527
528 def flushOutput(self):
529 self.reset_output_buffer()
530
531 def inWaiting(self):
532 return self.in_waiting
533
534 def sendBreak(self, duration=0.25):
535 self.send_break(duration)
536
537 def setRTS(self, value=1):
538 self.rts = value
539
540 def setDTR(self, value=1):
541 self.dtr = value
542
543 def getCTS(self):
544 return self.cts
545
546 def getDSR(self):
547 return self.dsr
548
549 def getRI(self):
550 return self.ri
551
552 def getCD(self):
553 return self.cd
554
555 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200556 def writeTimeout(self):
557 return self.write_timeout
558
559 @writeTimeout.setter
560 def writeTimeout(self, timeout):
561 self.write_timeout = timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200562
563 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200564 def interCharTimeout(self):
Chris Liechti96242372015-09-02 02:49:49 +0200565 return self.inter_byte_timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200566
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200567 @interCharTimeout.setter
568 def interCharTimeout(self, interCharTimeout):
Chris Liechti96242372015-09-02 02:49:49 +0200569 self.inter_byte_timeout = interCharTimeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200570
571 def getSettingsDict(self):
572 return self.get_settings()
573
574 def applySettingsDict(self, d):
575 self.apply_settings(d)
576
577 def isOpen(self):
Chris Liechti16843852015-09-22 23:24:35 +0200578 return self.is_open
Chris Liechtief1fe252015-08-27 23:25:21 +0200579
580 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200581 # additional functionality
582
David Howlett240f8fc2015-10-28 12:32:09 +0000583 def read_all(self):
Chris Liechti03cb8ed2015-10-30 23:37:24 +0100584 """\
585 Read all bytes currently available in the buffer of the OS.
586 """
David Howlett240f8fc2015-10-28 12:32:09 +0000587 return self.read(self.in_waiting)
588
Chris Liechti70b89232015-08-04 03:00:52 +0200589 def read_until(self, terminator=LF, size=None):
590 """\
591 Read until a termination sequence is found ('\n' by default), the size
592 is exceeded or until timeout occurs.
593 """
594 lenterm = len(terminator)
595 line = bytearray()
596 while True:
597 c = self.read(1)
598 if c:
599 line += c
600 if line[-lenterm:] == terminator:
601 break
602 if size is not None and len(line) >= size:
603 break
604 else:
605 break
606 return bytes(line)
607
Chris Liechti70b89232015-08-04 03:00:52 +0200608 def iread_until(self, *args, **kwargs):
609 """\
610 Read lines, implemented as generator. It will raise StopIteration on
611 timeout (empty read).
612 """
613 while True:
614 line = self.read_until(*args, **kwargs)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200615 if not line:
616 break
Chris Liechti70b89232015-08-04 03:00:52 +0200617 yield line
cliechtif81362e2009-07-25 03:44:33 +0000618
Chris Liechti779b1a22015-08-04 14:54:22 +0200619
620# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000621if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000622 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000623 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200624 sys.stdout.write('port name: %s\n' % s.name)
625 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
626 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
627 sys.stdout.write('parities: %s\n' % s.PARITIES)
628 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000629 sys.stdout.write('%s\n' % s)