blob: ddd0cdf6cf41ee6e652dd1d94460d5a29c891c71 [file] [log] [blame]
cliechti0d6029a2008-06-21 01:28:46 +00001#! python
cliechti0d6029a2008-06-21 01:28:46 +00002#
Chris Liechti3e02f702015-12-16 23:06:04 +01003# Backend for .NET/Mono (IronPython), .NET >= 2
4#
5# This file is part of pySerial. https://github.com/pyserial/pyserial
Chris Liechtic2b26792015-09-22 23:16:07 +02006# (C) 2008-2015 Chris Liechti <cliechti@gmx.net>
Chris Liechtifbdd8a02015-08-09 02:37:45 +02007#
8# SPDX-License-Identifier: BSD-3-Clause
cliechti0d6029a2008-06-21 01:28:46 +00009
Kurt McKee057387c2018-02-07 22:10:38 -060010from __future__ import absolute_import
11
cliechti761fd6e2008-06-24 11:32:43 +000012import System
cliechti0d6029a2008-06-21 01:28:46 +000013import System.IO.Ports
cliechti39cfb7b2011-08-22 00:30:07 +000014from serial.serialutil import *
cliechti0d6029a2008-06-21 01:28:46 +000015
cliechti761fd6e2008-06-24 11:32:43 +000016# must invoke function with byte array, make a helper to convert strings
17# to byte arrays
18sab = System.Array[System.Byte]
Chris Liechtiba45c522016-02-06 23:53:23 +010019
20
cliechti761fd6e2008-06-24 11:32:43 +000021def as_byte_array(string):
cliechti4a567a02009-07-27 22:09:31 +000022 return sab([ord(x) for x in string]) # XXX will require adaption when run with a 3.x compatible IronPython
cliechti761fd6e2008-06-24 11:32:43 +000023
Chris Liechticb6ce1b2016-02-02 01:53:56 +010024
Chris Liechtief6b7b42015-08-06 22:19:26 +020025class Serial(SerialBase):
cliechti771278b2013-10-17 03:19:00 +000026 """Serial port implementation for .NET/Mono."""
cliechti0d6029a2008-06-21 01:28:46 +000027
cliechti4a567a02009-07-27 22:09:31 +000028 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
Chris Liechticb6ce1b2016-02-02 01:53:56 +010029 9600, 19200, 38400, 57600, 115200)
cliechti0d6029a2008-06-21 01:28:46 +000030
31 def open(self):
cliechti00df9702014-08-04 10:12:48 +000032 """\
33 Open port with current settings. This may throw a SerialException
34 if the port cannot be opened.
35 """
cliechti0d6029a2008-06-21 01:28:46 +000036 if self._port is None:
37 raise SerialException("Port must be configured before it can be used.")
Chris Liechti6ed12e02015-09-18 21:23:42 +020038 if self.is_open:
cliechti8f69e702011-03-19 00:22:32 +000039 raise SerialException("Port is already open.")
cliechti0d6029a2008-06-21 01:28:46 +000040 try:
41 self._port_handle = System.IO.Ports.SerialPort(self.portstr)
Chris Liechti6ed12e02015-09-18 21:23:42 +020042 except Exception as msg:
cliechtiff0c3792008-06-22 01:01:21 +000043 self._port_handle = None
cliechti0d6029a2008-06-21 01:28:46 +000044 raise SerialException("could not open port %s: %s" % (self.portstr, msg))
45
Chris Liechtifc3b4992016-01-22 02:19:59 +010046 # if RTS and/or DTR are not set before open, they default to True
47 if self._rts_state is None:
48 self._rts_state = True
49 if self._dtr_state is None:
50 self._dtr_state = True
51
Chris Liechti5d772fc2016-06-10 00:08:06 +020052 self._reconfigure_port()
cliechti0d6029a2008-06-21 01:28:46 +000053 self._port_handle.Open()
Chris Liechti6ed12e02015-09-18 21:23:42 +020054 self.is_open = True
55 if not self._dsrdtr:
56 self._update_dtr_state()
cliechti761fd6e2008-06-24 11:32:43 +000057 if not self._rtscts:
Chris Liechti6ed12e02015-09-18 21:23:42 +020058 self._update_rts_state()
59 self.reset_input_buffer()
cliechti0d6029a2008-06-21 01:28:46 +000060
Chris Liechti5d772fc2016-06-10 00:08:06 +020061 def _reconfigure_port(self):
cliechtiff0c3792008-06-22 01:01:21 +000062 """Set communication parameters on opened port."""
cliechti0d6029a2008-06-21 01:28:46 +000063 if not self._port_handle:
64 raise SerialException("Can only operate on a valid port handle")
cliechti58b481c2009-02-16 20:42:32 +000065
cliechtiedfba4e2009-02-07 00:29:47 +000066 #~ self._port_handle.ReceivedBytesThreshold = 1
cliechti58b481c2009-02-16 20:42:32 +000067
cliechti0d6029a2008-06-21 01:28:46 +000068 if self._timeout is None:
69 self._port_handle.ReadTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
70 else:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010071 self._port_handle.ReadTimeout = int(self._timeout * 1000)
cliechti58b481c2009-02-16 20:42:32 +000072
cliechti0d6029a2008-06-21 01:28:46 +000073 # if self._timeout != 0 and self._interCharTimeout is not None:
74 # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
cliechti58b481c2009-02-16 20:42:32 +000075
Chris Liechti6ed12e02015-09-18 21:23:42 +020076 if self._write_timeout is None:
cliechtiff0c3792008-06-22 01:01:21 +000077 self._port_handle.WriteTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
cliechti0d6029a2008-06-21 01:28:46 +000078 else:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010079 self._port_handle.WriteTimeout = int(self._write_timeout * 1000)
cliechti0d6029a2008-06-21 01:28:46 +000080
81 # Setup the connection info.
cliechtic53a8ca2008-06-24 11:57:32 +000082 try:
83 self._port_handle.BaudRate = self._baudrate
Chris Liechti6ed12e02015-09-18 21:23:42 +020084 except IOError as e:
cliechtic53a8ca2008-06-24 11:57:32 +000085 # catch errors from illegal baudrate settings
86 raise ValueError(str(e))
cliechti0d6029a2008-06-21 01:28:46 +000087
88 if self._bytesize == FIVEBITS:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010089 self._port_handle.DataBits = 5
cliechti0d6029a2008-06-21 01:28:46 +000090 elif self._bytesize == SIXBITS:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010091 self._port_handle.DataBits = 6
cliechti0d6029a2008-06-21 01:28:46 +000092 elif self._bytesize == SEVENBITS:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010093 self._port_handle.DataBits = 7
cliechti0d6029a2008-06-21 01:28:46 +000094 elif self._bytesize == EIGHTBITS:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010095 self._port_handle.DataBits = 8
cliechti0d6029a2008-06-21 01:28:46 +000096 else:
97 raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
98
99 if self._parity == PARITY_NONE:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100100 self._port_handle.Parity = getattr(System.IO.Ports.Parity, 'None') # reserved keyword in Py3k
cliechti0d6029a2008-06-21 01:28:46 +0000101 elif self._parity == PARITY_EVEN:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100102 self._port_handle.Parity = System.IO.Ports.Parity.Even
cliechti0d6029a2008-06-21 01:28:46 +0000103 elif self._parity == PARITY_ODD:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100104 self._port_handle.Parity = System.IO.Ports.Parity.Odd
cliechti0d6029a2008-06-21 01:28:46 +0000105 elif self._parity == PARITY_MARK:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100106 self._port_handle.Parity = System.IO.Ports.Parity.Mark
cliechti0d6029a2008-06-21 01:28:46 +0000107 elif self._parity == PARITY_SPACE:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100108 self._port_handle.Parity = System.IO.Ports.Parity.Space
cliechti0d6029a2008-06-21 01:28:46 +0000109 else:
110 raise ValueError("Unsupported parity mode: %r" % self._parity)
111
112 if self._stopbits == STOPBITS_ONE:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100113 self._port_handle.StopBits = System.IO.Ports.StopBits.One
cliechti58b481c2009-02-16 20:42:32 +0000114 elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100115 self._port_handle.StopBits = System.IO.Ports.StopBits.OnePointFive
cliechti0d6029a2008-06-21 01:28:46 +0000116 elif self._stopbits == STOPBITS_TWO:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100117 self._port_handle.StopBits = System.IO.Ports.StopBits.Two
cliechti0d6029a2008-06-21 01:28:46 +0000118 else:
119 raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
cliechti58b481c2009-02-16 20:42:32 +0000120
cliechti0d6029a2008-06-21 01:28:46 +0000121 if self._rtscts and self._xonxoff:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100122 self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff
cliechti0d6029a2008-06-21 01:28:46 +0000123 elif self._rtscts:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100124 self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSend
cliechti0d6029a2008-06-21 01:28:46 +0000125 elif self._xonxoff:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100126 self._port_handle.Handshake = System.IO.Ports.Handshake.XOnXOff
cliechti0d6029a2008-06-21 01:28:46 +0000127 else:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100128 self._port_handle.Handshake = getattr(System.IO.Ports.Handshake, 'None') # reserved keyword in Py3k
cliechti0d6029a2008-06-21 01:28:46 +0000129
130 #~ def __del__(self):
131 #~ self.close()
132
133 def close(self):
134 """Close port"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200135 if self.is_open:
cliechti0d6029a2008-06-21 01:28:46 +0000136 if self._port_handle:
137 try:
cliechtiff0c3792008-06-22 01:01:21 +0000138 self._port_handle.Close()
cliechti0d6029a2008-06-21 01:28:46 +0000139 except System.IO.Ports.InvalidOperationException:
140 # ignore errors. can happen for unplugged USB serial devices
141 pass
142 self._port_handle = None
Chris Liechti6ed12e02015-09-18 21:23:42 +0200143 self.is_open = False
cliechti0d6029a2008-06-21 01:28:46 +0000144
145 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti58b481c2009-02-16 20:42:32 +0000146
Chris Liechti6ed12e02015-09-18 21:23:42 +0200147 @property
148 def in_waiting(self):
cliechti0d6029a2008-06-21 01:28:46 +0000149 """Return the number of characters currently in the input buffer."""
Chris Liechtiacac2362016-03-29 22:37:48 +0200150 if not self.is_open:
Chris Liechti6ed12e02015-09-18 21:23:42 +0200151 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000152 return self._port_handle.BytesToRead
153
cliechti4a567a02009-07-27 22:09:31 +0000154 def read(self, size=1):
cliechti00df9702014-08-04 10:12:48 +0000155 """\
156 Read size bytes from the serial port. If a timeout is set it may
157 return less characters as requested. With no timeout it will block
158 until the requested number of bytes is read.
159 """
Chris Liechtiacac2362016-03-29 22:37:48 +0200160 if not self.is_open:
Chris Liechti6ed12e02015-09-18 21:23:42 +0200161 raise portNotOpenError
cliechti4a567a02009-07-27 22:09:31 +0000162 # must use single byte reads as this is the only way to read
163 # without applying encodings
164 data = bytearray()
cliechti0d6029a2008-06-21 01:28:46 +0000165 while size:
cliechtiff0c3792008-06-22 01:01:21 +0000166 try:
cliechti4a567a02009-07-27 22:09:31 +0000167 data.append(self._port_handle.ReadByte())
Chris Liechti6c63da62016-01-25 21:39:32 +0100168 except System.TimeoutException:
cliechtiff0c3792008-06-22 01:01:21 +0000169 break
170 else:
171 size -= 1
cliechti4a567a02009-07-27 22:09:31 +0000172 return bytes(data)
cliechti0d6029a2008-06-21 01:28:46 +0000173
cliechti4a567a02009-07-27 22:09:31 +0000174 def write(self, data):
cliechti0d6029a2008-06-21 01:28:46 +0000175 """Output the given string over the serial port."""
Chris Liechtiacac2362016-03-29 22:37:48 +0200176 if not self.is_open:
Chris Liechti6ed12e02015-09-18 21:23:42 +0200177 raise portNotOpenError
cliechti00df9702014-08-04 10:12:48 +0000178 #~ if not isinstance(data, (bytes, bytearray)):
179 #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
cliechtiff0c3792008-06-22 01:01:21 +0000180 try:
cliechti761fd6e2008-06-24 11:32:43 +0000181 # must call overloaded method with byte array argument
182 # as this is the only one not applying encodings
183 self._port_handle.Write(as_byte_array(data), 0, len(data))
Chris Liechti6c63da62016-01-25 21:39:32 +0100184 except System.TimeoutException:
cliechtiff0c3792008-06-22 01:01:21 +0000185 raise writeTimeoutError
cliechtif81362e2009-07-25 03:44:33 +0000186 return len(data)
cliechti0d6029a2008-06-21 01:28:46 +0000187
Chris Liechti6ed12e02015-09-18 21:23:42 +0200188 def reset_input_buffer(self):
cliechti0d6029a2008-06-21 01:28:46 +0000189 """Clear input buffer, discarding all that is in the buffer."""
Chris Liechtiacac2362016-03-29 22:37:48 +0200190 if not self.is_open:
Chris Liechti6ed12e02015-09-18 21:23:42 +0200191 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000192 self._port_handle.DiscardInBuffer()
193
Chris Liechti6ed12e02015-09-18 21:23:42 +0200194 def reset_output_buffer(self):
cliechti00df9702014-08-04 10:12:48 +0000195 """\
196 Clear output buffer, aborting the current output and
197 discarding all that is in the buffer.
198 """
Chris Liechtiacac2362016-03-29 22:37:48 +0200199 if not self.is_open:
Chris Liechti6ed12e02015-09-18 21:23:42 +0200200 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000201 self._port_handle.DiscardOutBuffer()
202
Chris Liechti6ed12e02015-09-18 21:23:42 +0200203 def _update_break_state(self):
cliechti00df9702014-08-04 10:12:48 +0000204 """
205 Set break: Controls TXD. When active, to transmitting is possible.
206 """
Chris Liechtiacac2362016-03-29 22:37:48 +0200207 if not self.is_open:
Chris Liechti6ed12e02015-09-18 21:23:42 +0200208 raise portNotOpenError
209 self._port_handle.BreakState = bool(self._break_state)
cliechti0d6029a2008-06-21 01:28:46 +0000210
Chris Liechti6ed12e02015-09-18 21:23:42 +0200211 def _update_rts_state(self):
cliechti0d6029a2008-06-21 01:28:46 +0000212 """Set terminal status line: Request To Send"""
Chris Liechtiacac2362016-03-29 22:37:48 +0200213 if not self.is_open:
Chris Liechti6ed12e02015-09-18 21:23:42 +0200214 raise portNotOpenError
215 self._port_handle.RtsEnable = bool(self._rts_state)
cliechti0d6029a2008-06-21 01:28:46 +0000216
Chris Liechti6ed12e02015-09-18 21:23:42 +0200217 def _update_dtr_state(self):
cliechti0d6029a2008-06-21 01:28:46 +0000218 """Set terminal status line: Data Terminal Ready"""
Chris Liechtiacac2362016-03-29 22:37:48 +0200219 if not self.is_open:
Chris Liechti6ed12e02015-09-18 21:23:42 +0200220 raise portNotOpenError
221 self._port_handle.DtrEnable = bool(self._dtr_state)
cliechti0d6029a2008-06-21 01:28:46 +0000222
Chris Liechti6ed12e02015-09-18 21:23:42 +0200223 @property
224 def cts(self):
cliechti0d6029a2008-06-21 01:28:46 +0000225 """Read terminal status line: Clear To Send"""
Chris Liechtiacac2362016-03-29 22:37:48 +0200226 if not self.is_open:
Chris Liechti6ed12e02015-09-18 21:23:42 +0200227 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000228 return self._port_handle.CtsHolding
229
Chris Liechti6ed12e02015-09-18 21:23:42 +0200230 @property
231 def dsr(self):
cliechti0d6029a2008-06-21 01:28:46 +0000232 """Read terminal status line: Data Set Ready"""
Chris Liechtiacac2362016-03-29 22:37:48 +0200233 if not self.is_open:
Chris Liechti6ed12e02015-09-18 21:23:42 +0200234 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000235 return self._port_handle.DsrHolding
236
Chris Liechti6ed12e02015-09-18 21:23:42 +0200237 @property
238 def ri(self):
cliechtiff0c3792008-06-22 01:01:21 +0000239 """Read terminal status line: Ring Indicator"""
Chris Liechtiacac2362016-03-29 22:37:48 +0200240 if not self.is_open:
Chris Liechti6ed12e02015-09-18 21:23:42 +0200241 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000242 #~ return self._port_handle.XXX
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100243 return False # XXX an error would be better
cliechti0d6029a2008-06-21 01:28:46 +0000244
Chris Liechti6ed12e02015-09-18 21:23:42 +0200245 @property
246 def cd(self):
cliechti0d6029a2008-06-21 01:28:46 +0000247 """Read terminal status line: Carrier Detect"""
Chris Liechtiacac2362016-03-29 22:37:48 +0200248 if not self.is_open:
Chris Liechti6ed12e02015-09-18 21:23:42 +0200249 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000250 return self._port_handle.CDHolding
251
252 # - - platform specific - - - -
cliechtif81362e2009-07-25 03:44:33 +0000253 # none