blob: e2aa6cd049792a734aadaf234c3927be99b3fd45 [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 Liechti518b0d32015-08-30 02:20:39 +0200167 self.inter_character_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 Liechti779b1a22015-08-04 14:54:22 +0200174 @property
175 def port(self):
176 """\
177 Get the current port setting. The value that was passed on init or using
178 setPort() is passed back. See also the attribute portstr which contains
179 the name of the port as a string.
180 """
181 return self._port
182
183 @port.setter
184 def port(self, port):
cliechti7d448562014-08-03 21:57:45 +0000185 """\
186 Change the port. The attribute portstr is set to a string that
187 contains the name of the port.
188 """
cliechti14b274a2009-02-07 00:27:05 +0000189
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200190 was_open = self.is_open
191 if was_open:
192 self.close()
Chris Liechti68340d72015-08-03 14:15:48 +0200193 self.portstr = port
cliechtid6bf52c2003-10-01 02:28:12 +0000194 self._port = port
cliechtif81362e2009-07-25 03:44:33 +0000195 self.name = self.portstr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200196 if was_open:
197 self.open()
cliechti14b274a2009-02-07 00:27:05 +0000198
cliechtid6bf52c2003-10-01 02:28:12 +0000199
Chris Liechti779b1a22015-08-04 14:54:22 +0200200 @property
201 def baudrate(self):
202 """Get the current baud rate setting."""
203 return self._baudrate
cliechtid6bf52c2003-10-01 02:28:12 +0000204
Chris Liechti779b1a22015-08-04 14:54:22 +0200205 @baudrate.setter
206 def baudrate(self, baudrate):
cliechti7d448562014-08-03 21:57:45 +0000207 """\
208 Change baud rate. It raises a ValueError if the port is open and the
cliechti2750b832009-07-28 00:13:52 +0000209 baud rate is not possible. If the port is closed, then the value is
cliechti7d448562014-08-03 21:57:45 +0000210 accepted and the exception is raised when the port is opened.
211 """
cliechti107db8d2004-01-15 01:20:23 +0000212 try:
cliechtie30868d2013-10-16 15:35:11 +0000213 b = int(baudrate)
cliechti107db8d2004-01-15 01:20:23 +0000214 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000215 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
cliechti107db8d2004-01-15 01:20:23 +0000216 else:
cliechtie30868d2013-10-16 15:35:11 +0000217 if b <= 0:
218 raise ValueError("Not a valid baudrate: %r" % (baudrate,))
219 self._baudrate = b
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200220 if self.is_open:
221 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000222
cliechti14b274a2009-02-07 00:27:05 +0000223
Chris Liechti779b1a22015-08-04 14:54:22 +0200224 @property
225 def bytesize(self):
226 """Get the current byte size setting."""
227 return self._bytesize
cliechtid6bf52c2003-10-01 02:28:12 +0000228
Chris Liechti779b1a22015-08-04 14:54:22 +0200229 @bytesize.setter
230 def bytesize(self, bytesize):
cliechtid6bf52c2003-10-01 02:28:12 +0000231 """Change byte size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200232 if bytesize not in self.BYTESIZES:
233 raise ValueError("Not a valid byte size: %r" % (bytesize,))
cliechtid6bf52c2003-10-01 02:28:12 +0000234 self._bytesize = bytesize
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200235 if self.is_open:
236 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000237
cliechtid6bf52c2003-10-01 02:28:12 +0000238
239
Chris Liechti779b1a22015-08-04 14:54:22 +0200240 @property
241 def parity(self):
242 """Get the current parity setting."""
243 return self._parity
244
245 @parity.setter
246 def parity(self, parity):
cliechtid6bf52c2003-10-01 02:28:12 +0000247 """Change parity setting."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200248 if parity not in self.PARITIES:
249 raise ValueError("Not a valid parity: %r" % (parity,))
cliechtid6bf52c2003-10-01 02:28:12 +0000250 self._parity = parity
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200251 if self.is_open:
252 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000253
cliechtid6bf52c2003-10-01 02:28:12 +0000254
255
Chris Liechti779b1a22015-08-04 14:54:22 +0200256 @property
257 def stopbits(self):
258 """Get the current stop bits setting."""
259 return self._stopbits
260
261 @stopbits.setter
262 def stopbits(self, stopbits):
cliechti4a567a02009-07-27 22:09:31 +0000263 """Change stop bits size."""
Chris Liechti033f17c2015-08-30 21:28:04 +0200264 if stopbits not in self.STOPBITS:
265 raise ValueError("Not a valid stop bit size: %r" % (stopbits,))
cliechtid6bf52c2003-10-01 02:28:12 +0000266 self._stopbits = stopbits
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200267 if self.is_open:
268 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000269
cliechti14b274a2009-02-07 00:27:05 +0000270
Chris Liechti779b1a22015-08-04 14:54:22 +0200271 @property
272 def timeout(self):
273 """Get the current timeout setting."""
274 return self._timeout
cliechtid6bf52c2003-10-01 02:28:12 +0000275
Chris Liechti779b1a22015-08-04 14:54:22 +0200276 @timeout.setter
277 def timeout(self, timeout):
cliechtid6bf52c2003-10-01 02:28:12 +0000278 """Change timeout setting."""
279 if timeout is not None:
cliechtid6bf52c2003-10-01 02:28:12 +0000280 try:
cliechti14b274a2009-02-07 00:27:05 +0000281 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechtid6bf52c2003-10-01 02:28:12 +0000282 except TypeError:
cliechti93db61b2006-08-26 19:16:18 +0000283 raise ValueError("Not a valid timeout: %r" % (timeout,))
Chris Liechticf29a352015-10-23 22:03:40 +0200284 if timeout < 0:
285 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechtid6bf52c2003-10-01 02:28:12 +0000286 self._timeout = timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200287 if self.is_open:
288 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000289
Chris Liechti779b1a22015-08-04 14:54:22 +0200290
291 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200292 def write_timeout(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000293 """Get the current timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200294 return self._write_timeout
cliechti14b274a2009-02-07 00:27:05 +0000295
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200296 @write_timeout.setter
297 def write_timeout(self, timeout):
cliechti62611612004-04-20 01:55:43 +0000298 """Change timeout setting."""
299 if timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200300 if timeout < 0:
301 raise ValueError("Not a valid timeout: %r" % (timeout,))
cliechti62611612004-04-20 01:55:43 +0000302 try:
Chris Liechti033f17c2015-08-30 21:28:04 +0200303 timeout + 1 # test if it's a number, will throw a TypeError if not...
cliechti62611612004-04-20 01:55:43 +0000304 except TypeError:
305 raise ValueError("Not a valid timeout: %r" % timeout)
cliechti14b274a2009-02-07 00:27:05 +0000306
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200307 self._write_timeout = timeout
308 if self.is_open:
309 self._reconfigure_port()
310
311
312 @property
Chris Liechti518b0d32015-08-30 02:20:39 +0200313 def inter_byte_timeout(self):
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200314 """Get the current inter-character timeout setting."""
Chris Liechti96242372015-09-02 02:49:49 +0200315 return self._inter_byte_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200316
Chris Liechti518b0d32015-08-30 02:20:39 +0200317 @inter_byte_timeout.setter
318 def inter_byte_timeout(self, ic_timeout):
319 """Change inter-byte timeout setting."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200320 if ic_timeout is not None:
Chris Liechti033f17c2015-08-30 21:28:04 +0200321 if ic_timeout < 0:
322 raise ValueError("Not a valid timeout: %r" % ic_timeout)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200323 try:
324 ic_timeout + 1 # test if it's a number, will throw a TypeError if not...
325 except TypeError:
326 raise ValueError("Not a valid timeout: %r" % ic_timeout)
327
Chris Liechti518b0d32015-08-30 02:20:39 +0200328 self._inter_byte_timeout = ic_timeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200329 if self.is_open:
330 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000331
cliechti14b274a2009-02-07 00:27:05 +0000332
Chris Liechti779b1a22015-08-04 14:54:22 +0200333 @property
334 def xonxoff(self):
335 """Get the current XON/XOFF setting."""
336 return self._xonxoff
cliechtid6bf52c2003-10-01 02:28:12 +0000337
Chris Liechti779b1a22015-08-04 14:54:22 +0200338 @xonxoff.setter
339 def xonxoff(self, xonxoff):
cliechti4a567a02009-07-27 22:09:31 +0000340 """Change XON/XOFF setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000341 self._xonxoff = xonxoff
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200342 if self.is_open:
343 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000344
cliechti14b274a2009-02-07 00:27:05 +0000345
Chris Liechti779b1a22015-08-04 14:54:22 +0200346 @property
347 def rtscts(self):
348 """Get the current RTS/CTS flow control setting."""
349 return self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000350
Chris Liechti779b1a22015-08-04 14:54:22 +0200351 @rtscts.setter
352 def rtscts(self, rtscts):
cliechti4a567a02009-07-27 22:09:31 +0000353 """Change RTS/CTS flow control setting."""
cliechtid6bf52c2003-10-01 02:28:12 +0000354 self._rtscts = rtscts
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200355 if self.is_open:
356 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000357
cliechti14b274a2009-02-07 00:27:05 +0000358
Chris Liechti779b1a22015-08-04 14:54:22 +0200359 @property
360 def dsrdtr(self):
361 """Get the current DSR/DTR flow control setting."""
362 return self._dsrdtr
cliechtid6bf52c2003-10-01 02:28:12 +0000363
Chris Liechti779b1a22015-08-04 14:54:22 +0200364 @dsrdtr.setter
365 def dsrdtr(self, dsrdtr=None):
cliechtif46e0a82005-05-19 15:24:57 +0000366 """Change DsrDtr flow control setting."""
367 if dsrdtr is None:
cliechti14b274a2009-02-07 00:27:05 +0000368 # if not set, keep backwards compatibility and follow rtscts setting
cliechtif46e0a82005-05-19 15:24:57 +0000369 self._dsrdtr = self._rtscts
370 else:
cliechti14b274a2009-02-07 00:27:05 +0000371 # if defined independently, follow its value
cliechtif46e0a82005-05-19 15:24:57 +0000372 self._dsrdtr = dsrdtr
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200373 if self.is_open:
374 self._reconfigure_port()
cliechti14b274a2009-02-07 00:27:05 +0000375
cliechti14b274a2009-02-07 00:27:05 +0000376
Chris Liechti779b1a22015-08-04 14:54:22 +0200377 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200378 def rts(self):
379 return self._rts_state
cliechti679bfa62008-06-20 23:58:15 +0000380
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200381 @rts.setter
382 def rts(self, value):
383 self._rts_state = value
384 if self.is_open:
385 self._update_rts_state()
cliechti14b274a2009-02-07 00:27:05 +0000386
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200387 @property
388 def dtr(self):
389 return self._dtr_state
cliechti14b274a2009-02-07 00:27:05 +0000390
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200391 @dtr.setter
392 def dtr(self, value):
393 self._dtr_state = value
394 if self.is_open:
395 self._update_dtr_state()
396
397 @property
398 def break_condition(self):
399 return self._break_state
400
401 @break_condition.setter
402 def break_condition(self, value):
403 self._break_state = value
404 if self.is_open:
405 self._update_break_state()
cliechti679bfa62008-06-20 23:58:15 +0000406
cliechti4065dce2009-08-10 00:55:46 +0000407 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti33f0ec52015-08-06 16:37:21 +0200408 # functions useful for RS-485 adapters
409
410 @property
411 def rs485_mode(self):
412 """\
413 Enable RS485 mode and apply new settings, set to None to disable.
414 See serial.rs485.RS485Settings for more info about the value.
415 """
416 return self._rs485_mode
417
418 @rs485_mode.setter
419 def rs485_mode(self, rs485_settings):
420 self._rs485_mode = rs485_settings
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200421 if self.is_open:
422 self._reconfigure_port()
Chris Liechti33f0ec52015-08-06 16:37:21 +0200423
424 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti4065dce2009-08-10 00:55:46 +0000425
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200426 _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
Chris Liechti033f17c2015-08-30 21:28:04 +0200427 'dsrdtr', 'rtscts', 'timeout', 'write_timeout',
Chris Liechti1c3249f2015-09-01 02:31:36 +0200428 'inter_byte_timeout')
cliechti4065dce2009-08-10 00:55:46 +0000429
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200430 def get_settings(self):
cliechti7d448562014-08-03 21:57:45 +0000431 """\
432 Get current port settings as a dictionary. For use with
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200433 apply_settings().
cliechti7d448562014-08-03 21:57:45 +0000434 """
Chris Liechti033f17c2015-08-30 21:28:04 +0200435 return dict([(key, getattr(self, '_' + key)) for key in self._SAVED_SETTINGS])
cliechti4065dce2009-08-10 00:55:46 +0000436
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200437 def apply_settings(self, d):
cliechti7d448562014-08-03 21:57:45 +0000438 """\
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200439 Apply stored settings from a dictionary returned from
440 get_settings(). It's allowed to delete keys from the dictionary. These
cliechti7d448562014-08-03 21:57:45 +0000441 values will simply left unchanged.
442 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200443 for key in self._SAVED_SETTINGS:
Chris Liechti033f17c2015-08-30 21:28:04 +0200444 if key in d and d[key] != getattr(self, '_' + key): # check against internal "_" value
cliechti4065dce2009-08-10 00:55:46 +0000445 setattr(self, key, d[key]) # set non "_" value to use properties write function
cliechti679bfa62008-06-20 23:58:15 +0000446
cliechtid6bf52c2003-10-01 02:28:12 +0000447 # - - - - - - - - - - - - - - - - - - - - - - - -
448
449 def __repr__(self):
450 """String representation of the current port settings and its state."""
cliechtif46e0a82005-05-19 15:24:57 +0000451 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 +0200452 self.__class__.__name__,
453 id(self),
454 self.is_open,
455 self.portstr,
456 self.baudrate,
457 self.bytesize,
458 self.parity,
459 self.stopbits,
460 self.timeout,
461 self.xonxoff,
462 self.rtscts,
463 self.dsrdtr,
cliechtid6bf52c2003-10-01 02:28:12 +0000464 )
465
cliechti4a567a02009-07-27 22:09:31 +0000466 # - - - - - - - - - - - - - - - - - - - - - - - -
467 # compatibility with io library
468
Chris Liechti033f17c2015-08-30 21:28:04 +0200469 def readable(self):
470 return True
471
472 def writable(self):
473 return True
474
475 def seekable(self):
476 return False
477
cliechti4a567a02009-07-27 22:09:31 +0000478 def readinto(self, b):
479 data = self.read(len(b))
480 n = len(data)
481 try:
482 b[:n] = data
Chris Liechti68340d72015-08-03 14:15:48 +0200483 except TypeError as err:
cliechti4a567a02009-07-27 22:09:31 +0000484 import array
485 if not isinstance(b, array.array):
486 raise err
487 b[:n] = array.array('b', data)
488 return n
cliechtif81362e2009-07-25 03:44:33 +0000489
Chris Liechti70b89232015-08-04 03:00:52 +0200490 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti779b1a22015-08-04 14:54:22 +0200491 # context manager
492
493 def __enter__(self):
494 return self
495
496 def __exit__(self, *args, **kwargs):
497 self.close()
498
499 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechtief1fe252015-08-27 23:25:21 +0200500
501 def send_break(self, duration=0.25):
502 """\
503 Send break condition. Timed, returns to idle state after given
504 duration.
505 """
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200506 if not self.is_open:
507 raise portNotOpenError
Chris Liechtief1fe252015-08-27 23:25:21 +0200508 self.break_condition = True
509 time.sleep(duration)
510 self.break_condition = False
511
512 # - - - - - - - - - - - - - - - - - - - - - - - -
513 # backwards compatibility / deprecated functions
514
515 def flushInput(self):
516 self.reset_input_buffer()
517
518 def flushOutput(self):
519 self.reset_output_buffer()
520
521 def inWaiting(self):
522 return self.in_waiting
523
524 def sendBreak(self, duration=0.25):
525 self.send_break(duration)
526
527 def setRTS(self, value=1):
528 self.rts = value
529
530 def setDTR(self, value=1):
531 self.dtr = value
532
533 def getCTS(self):
534 return self.cts
535
536 def getDSR(self):
537 return self.dsr
538
539 def getRI(self):
540 return self.ri
541
542 def getCD(self):
543 return self.cd
544
545 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200546 def writeTimeout(self):
547 return self.write_timeout
548
549 @writeTimeout.setter
550 def writeTimeout(self, timeout):
551 self.write_timeout = timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200552
553 @property
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200554 def interCharTimeout(self):
Chris Liechti96242372015-09-02 02:49:49 +0200555 return self.inter_byte_timeout
Chris Liechtief1fe252015-08-27 23:25:21 +0200556
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200557 @interCharTimeout.setter
558 def interCharTimeout(self, interCharTimeout):
Chris Liechti96242372015-09-02 02:49:49 +0200559 self.inter_byte_timeout = interCharTimeout
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200560
561 def getSettingsDict(self):
562 return self.get_settings()
563
564 def applySettingsDict(self, d):
565 self.apply_settings(d)
566
567 def isOpen(self):
Chris Liechti16843852015-09-22 23:24:35 +0200568 return self.is_open
Chris Liechtief1fe252015-08-27 23:25:21 +0200569
570 # - - - - - - - - - - - - - - - - - - - - - - - -
Chris Liechti70b89232015-08-04 03:00:52 +0200571 # additional functionality
572
573 def read_until(self, terminator=LF, size=None):
574 """\
575 Read until a termination sequence is found ('\n' by default), the size
576 is exceeded or until timeout occurs.
577 """
578 lenterm = len(terminator)
579 line = bytearray()
580 while True:
581 c = self.read(1)
582 if c:
583 line += c
584 if line[-lenterm:] == terminator:
585 break
586 if size is not None and len(line) >= size:
587 break
588 else:
589 break
590 return bytes(line)
591
Chris Liechti70b89232015-08-04 03:00:52 +0200592 def iread_until(self, *args, **kwargs):
593 """\
594 Read lines, implemented as generator. It will raise StopIteration on
595 timeout (empty read).
596 """
597 while True:
598 line = self.read_until(*args, **kwargs)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200599 if not line:
600 break
Chris Liechti70b89232015-08-04 03:00:52 +0200601 yield line
cliechtif81362e2009-07-25 03:44:33 +0000602
Chris Liechti779b1a22015-08-04 14:54:22 +0200603
604# - - - - - - - - - - - - - - - - - - - - - - - - -
cliechtid6bf52c2003-10-01 02:28:12 +0000605if __name__ == '__main__':
cliechtif81362e2009-07-25 03:44:33 +0000606 import sys
cliechtid6bf52c2003-10-01 02:28:12 +0000607 s = SerialBase()
Chris Liechti779b1a22015-08-04 14:54:22 +0200608 sys.stdout.write('port name: %s\n' % s.name)
609 sys.stdout.write('baud rates: %s\n' % s.BAUDRATES)
610 sys.stdout.write('byte sizes: %s\n' % s.BYTESIZES)
611 sys.stdout.write('parities: %s\n' % s.PARITIES)
612 sys.stdout.write('stop bits: %s\n' % s.STOPBITS)
cliechtif81362e2009-07-25 03:44:33 +0000613 sys.stdout.write('%s\n' % s)