blob: cd9937b155c2cef498843968a395ec47de7d7414 [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 Liechtia51b0bc2015-12-10 21:14:45 +0100174 # to be implemented by subclasses:
175 # def open(self):
176 # def close(self):
Chris Liechti5e763ca2015-12-09 13:01:26 +0100177
178 # - - - - - - - - - - - - - - - - - - - - - - - -
179
Chris Liechti779b1a22015-08-04 14:54:22 +0200180 @property
181 def port(self):
182 """\
183 Get the current port setting. The value that was passed on init or using
184 setPort() is passed back. See also the attribute portstr which contains
185 the name of the port as a string.
186 """
187 return self._port
188
189 @port.setter
190 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000191 """\
192 Change the port. The attribute portstr is set to a string that
193 contains the name of the port.
194 """
cliechti14b274a2009-02-07 00:27:05 +0000195
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200196 was_open = self.is_open
197 if was_open:
198 self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200199 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000200 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000201 self.name = self.portstr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200202 if was_open:
203 self.open()
cliechti14b274a2009-02-07 00:27:05 +0000204
cliechtid6bf52c2003-10-01 02:28:12 +0000205
Chris Liechti779b1a22015-08-04 14:54:22 +0200206 @property
207 def baudrate(self):
208 """Get the current baud rate setting."""
209 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000210
Chris Liechti779b1a22015-08-04 14:54:22 +0200211 @baudrate.setter
212 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000213 """\
214 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000215 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000216 accepted and the exception is raised when the port is opened.
217 """
cliechti107db8d2004-01-15 01:20:23 +0000218 try:
cliechtie30868d2013-10-16 15:35:11 +0000219 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000220 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000221 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
cliechti107db8d2004-01-15 01:20:23 +0000222 else:
cliechtie30868d2013-10-16 15:35:11 +0000223 if b <= 0:
224 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
225 self._baudrate = b
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200226 if self.is_open:
227 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000228
cliechti14b274a2009-02-07 00:27:05 +0000229
Chris Liechti779b1a22015-08-04 14:54:22 +0200230 @property
231 def bytesize(self):
232 """Get the current byte size setting."""
233 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000234
Chris Liechti779b1a22015-08-04 14:54:22 +0200235 @bytesize.setter
236 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000237 """Change byte size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200238 if bytesize not in self.BYTESIZES:
239 raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000240 self._bytesize = bytesize
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200241 if self.is_open:
242 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000243
cliechtid6bf52c2003-10-01 02:28:12 +0000244
245
Chris Liechti779b1a22015-08-04 14:54:22 +0200246 @property
247 def parity(self):
248 """Get the current parity setting."""
249 return self._parity
250
251 @parity.setter
252 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000253 """Change parity setting."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200254 if parity not in self.PARITIES:
255 raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000256 self._parity = parity
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200257 if self.is_open:
258 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000259
cliechtid6bf52c2003-10-01 02:28:12 +0000260
261
Chris Liechti779b1a22015-08-04 14:54:22 +0200262 @property
263 def stopbits(self):
264 """Get the current stop bits setting."""
265 return self._stopbits
266
267 @stopbits.setter
268 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000269 """Change stop bits size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200270 if stopbits not in self.STOPBITS:
271 raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000272 self._stopbits = stopbits
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200273 if self.is_open:
274 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000275
cliechti14b274a2009-02-07 00:27:05 +0000276
Chris Liechti779b1a22015-08-04 14:54:22 +0200277 @property
278 def timeout(self):
279 """Get the current timeout setting."""
280 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000281
Chris Liechti779b1a22015-08-04 14:54:22 +0200282 @timeout.setter
283 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000284 """Change timeout setting."""
285 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000286 try:
cliechti14b274a2009-02-07 00:27:05 +0000287 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000288 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000289 raise ValueError("Not a valid timeout: %r" % (timeout,))
Chris Liechticf29a352015-10-23 22:03:40 +0200290 if timeout < 0:
291 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000292 self._timeout = timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200293 if self.is_open:
294 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000295
Chris Liechti779b1a22015-08-04 14:54:22 +0200296
297 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200298 def write_timeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000299 """Get the current timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200300 return self._write_timeout
cliechti14b274a2009-02-07 00:27:05 +0000301
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200302 @write_timeout.setter
303 def write_timeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000304 """Change timeout setting."""
305 if timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200306 if timeout < 0:
307 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000308 try:
Chris Liechti033f17c2015-08-30 21:28:04 +0200309 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti62611612004-04-20 01:55:43 +0000310 except TypeError:
311 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000312
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200313 self._write_timeout = timeout
314 if self.is_open:
315 self._reconfigure_port()
316
317
318 @property
Chris Liechti518b0d32015-08-30 02:20:39 +0200319 def inter_byte_timeout(self):
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200320 """Get the current inter-character timeout setting."""
Chris Liechti96242372015-09-02 02:49:49 +0200321 return self._inter_byte_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200322
Chris Liechti518b0d32015-08-30 02:20:39 +0200323 @inter_byte_timeout.setter
324 def inter_byte_timeout(self, ic_timeout):
325 """Change inter-byte timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200326 if ic_timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200327 if ic_timeout < 0:
328 raise ValueError("Not a valid timeout: %r" % ic_timeout)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200329 try:
330 ic_timeout + 1 # test if it's a number, will throw a TypeError if not...
331 except TypeError:
332 raise ValueError("Not a valid timeout: %r" % ic_timeout)
333
Chris Liechti518b0d32015-08-30 02:20:39 +0200334 self._inter_byte_timeout = ic_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200335 if self.is_open:
336 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000337
cliechti14b274a2009-02-07 00:27:05 +0000338
Chris Liechti779b1a22015-08-04 14:54:22 +0200339 @property
340 def xonxoff(self):
341 """Get the current XON/XOFF setting."""
342 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000343
Chris Liechti779b1a22015-08-04 14:54:22 +0200344 @xonxoff.setter
345 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000346 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000347 self._xonxoff = xonxoff
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200348 if self.is_open:
349 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000350
cliechti14b274a2009-02-07 00:27:05 +0000351
Chris Liechti779b1a22015-08-04 14:54:22 +0200352 @property
353 def rtscts(self):
354 """Get the current RTS/CTS flow control setting."""
355 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000356
Chris Liechti779b1a22015-08-04 14:54:22 +0200357 @rtscts.setter
358 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000359 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000360 self._rtscts = rtscts
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200361 if self.is_open:
362 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000363
cliechti14b274a2009-02-07 00:27:05 +0000364
Chris Liechti779b1a22015-08-04 14:54:22 +0200365 @property
366 def dsrdtr(self):
367 """Get the current DSR/DTR flow control setting."""
368 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000369
Chris Liechti779b1a22015-08-04 14:54:22 +0200370 @dsrdtr.setter
371 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000372 """Change DsrDtr flow control setting."""
373 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000374 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000375 self._dsrdtr = self._rtscts
376 else:
cliechti14b274a2009-02-07 00:27:05 +0000377 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000378 self._dsrdtr = dsrdtr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200379 if self.is_open:
380 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000381
cliechti14b274a2009-02-07 00:27:05 +0000382
Chris Liechti779b1a22015-08-04 14:54:22 +0200383 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200384 def rts(self):
385 return self._rts_state
cliechti679bfa62008-06-20 23:58:15 +0000386
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200387 @rts.setter
388 def rts(self, value):
389 self._rts_state = value
390 if self.is_open:
391 self._update_rts_state()
cliechti14b274a2009-02-07 00:27:05 +0000392
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200393 @property
394 def dtr(self):
395 return self._dtr_state
cliechti14b274a2009-02-07 00:27:05 +0000396
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200397 @dtr.setter
398 def dtr(self, value):
399 self._dtr_state = value
400 if self.is_open:
401 self._update_dtr_state()
402
403 @property
404 def break_condition(self):
405 return self._break_state
406
407 @break_condition.setter
408 def break_condition(self, value):
409 self._break_state = value
410 if self.is_open:
411 self._update_break_state()
cliechti679bfa62008-06-20 23:58:15 +0000412
cliechti4065dce2009-08-10 00:55:46 +0000413 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200414 # functions useful for RS-485 adapters
415
416 @property
417 def rs485_mode(self):
418 """\
419 Enable RS485 mode and apply new settings, set to None to disable.
420 See serial.rs485.RS485Settings for more info about the value.
421 """
422 return self._rs485_mode
423
424 @rs485_mode.setter
425 def rs485_mode(self, rs485_settings):
426 self._rs485_mode = rs485_settings
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200427 if self.is_open:
428 self._reconfigure_port()
Chris Liechti33f0ec52015-08-06 16:37:21 +0200429
430 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000431
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200432 _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
Chris Liechti033f17c2015-08-30 21:28:04 +0200433 'dsrdtr', 'rtscts', 'timeout', 'write_timeout',
Chris Liechti1c3249f2015-09-01 02:31:36 +0200434 'inter_byte_timeout')
cliechti4065dce2009-08-10 00:55:46 +0000435
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200436 def get_settings(self):
cliechti7d448562014-08-03 21:57:45 +0000437 """\
438 Get current port settings as a dictionary. For use with
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200439 apply_settings().
cliechti7d448562014-08-03 21:57:45 +0000440 """
Chris Liechti033f17c2015-08-30 21:28:04 +0200441 return dict([(key, getattr(self, '_' + key)) for key in self._SAVED_SETTINGS])
cliechti4065dce2009-08-10 00:55:46 +0000442
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200443 def apply_settings(self, d):
cliechti7d448562014-08-03 21:57:45 +0000444 """\
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200445 Apply stored settings from a dictionary returned from
446 get_settings(). It's allowed to delete keys from the dictionary. These
cliechti7d448562014-08-03 21:57:45 +0000447 values will simply left unchanged.
448 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200449 for key in self._SAVED_SETTINGS:
Chris Liechti033f17c2015-08-30 21:28:04 +0200450 if key in d and d[key] != getattr(self, '_' + key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000451 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000452
cliechtid6bf52c2003-10-01 02:28:12 +0000453 # - - - - - - - - - - - - - - - - - - - - - - - -
454
455 def __repr__(self):
456 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000457 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 +0200458 self.__class__.__name__,
459 id(self),
460 self.is_open,
461 self.portstr,
462 self.baudrate,
463 self.bytesize,
464 self.parity,
465 self.stopbits,
466 self.timeout,
467 self.xonxoff,
468 self.rtscts,
469 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000470 )
471
cliechti4a567a02009-07-27 22:09:31 +0000472 # - - - - - - - - - - - - - - - - - - - - - - - -
473 # compatibility with io library
474
Chris Liechti033f17c2015-08-30 21:28:04 +0200475 def readable(self):
476 return True
477
478 def writable(self):
479 return True
480
481 def seekable(self):
482 return False
483
cliechti4a567a02009-07-27 22:09:31 +0000484 def readinto(self, b):
485 data = self.read(len(b))
486 n = len(data)
487 try:
488 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200489 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000490 import array
491 if not isinstance(b, array.array):
492 raise err
493 b[:n] = array.array('b', data)
494 return n
cliechtif81362e2009-07-25 03:44:33 +0000495
Chris Liechti70b89232015-08-04 03:00:52 +0200496 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200497 # context manager
498
499 def __enter__(self):
500 return self
501
502 def __exit__(self, *args, **kwargs):
503 self.close()
504
505 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechtief1fe252015-08-27 23:25:21 +0200506
507 def send_break(self, duration=0.25):
508 """\
509 Send break condition. Timed, returns to idle state after given
510 duration.
511 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200512 if not self.is_open:
513 raise portNotOpenError
Chris Liechtief1fe252015-08-27 23:25:21 +0200514 self.break_condition = True
515 time.sleep(duration)
516 self.break_condition = False
517
518 # - - - - - - - - - - - - - - - - - - - - - - - -
519 # backwards compatibility / deprecated functions
520
521 def flushInput(self):
522 self.reset_input_buffer()
523
524 def flushOutput(self):
525 self.reset_output_buffer()
526
527 def inWaiting(self):
528 return self.in_waiting
529
530 def sendBreak(self, duration=0.25):
531 self.send_break(duration)
532
533 def setRTS(self, value=1):
534 self.rts = value
535
536 def setDTR(self, value=1):
537 self.dtr = value
538
539 def getCTS(self):
540 return self.cts
541
542 def getDSR(self):
543 return self.dsr
544
545 def getRI(self):
546 return self.ri
547
548 def getCD(self):
549 return self.cd
550
551 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200552 def writeTimeout(self):
553 return self.write_timeout
554
555 @writeTimeout.setter
556 def writeTimeout(self, timeout):
557 self.write_timeout = timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200558
559 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200560 def interCharTimeout(self):
Chris Liechti96242372015-09-02 02:49:49 +0200561 return self.inter_byte_timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200562
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200563 @interCharTimeout.setter
564 def interCharTimeout(self, interCharTimeout):
Chris Liechti96242372015-09-02 02:49:49 +0200565 self.inter_byte_timeout = interCharTimeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200566
567 def getSettingsDict(self):
568 return self.get_settings()
569
570 def applySettingsDict(self, d):
571 self.apply_settings(d)
572
573 def isOpen(self):
Chris Liechti16843852015-09-22 23:24:35 +0200574 return self.is_open
Chris Liechtief1fe252015-08-27 23:25:21 +0200575
576 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200577 # additional functionality
578
David Howlett240f8fc2015-10-28 12:32:09 +0000579 def read_all(self):
Chris Liechti03cb8ed2015-10-30 23:37:24 +0100580 """\
581 Read all bytes currently available in the buffer of the OS.
582 """
David Howlett240f8fc2015-10-28 12:32:09 +0000583 return self.read(self.in_waiting)
584
Chris Liechti70b89232015-08-04 03:00:52 +0200585 def read_until(self, terminator=LF, size=None):
586 """\
587 Read until a termination sequence is found ('\n' by default), the size
588 is exceeded or until timeout occurs.
589 """
590 lenterm = len(terminator)
591 line = bytearray()
592 while True:
593 c = self.read(1)
594 if c:
595 line += c
596 if line[-lenterm:] == terminator:
597 break
598 if size is not None and len(line) >= size:
599 break
600 else:
601 break
602 return bytes(line)
603
Chris Liechti70b89232015-08-04 03:00:52 +0200604 def iread_until(self, *args, **kwargs):
605 """\
606 Read lines, implemented as generator. It will raise StopIteration on
607 timeout (empty read).
608 """
609 while True:
610 line = self.read_until(*args, **kwargs)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200611 if not line:
612 break
Chris Liechti70b89232015-08-04 03:00:52 +0200613 yield line
cliechtif81362e2009-07-25 03:44:33 +0000614
Chris Liechti779b1a22015-08-04 14:54:22 +0200615
616# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000617if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000618 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000619 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200620 sys.stdout.write('port name: %s\n' % s.name)
621 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
622 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
623 sys.stdout.write('parities: %s\n' % s.PARITIES)
624 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000625 sys.stdout.write('%s\n' % s)