blob: db35063251a456c9265d20da86f72792150e4a92 [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
cliechti761fd6e2008-06-24 11:32:43 +000010import System
cliechti0d6029a2008-06-21 01:28:46 +000011import System.IO.Ports
cliechti39cfb7b2011-08-22 00:30:07 +000012from serial.serialutil import *
cliechti0d6029a2008-06-21 01:28:46 +000013
cliechti761fd6e2008-06-24 11:32:43 +000014# must invoke function with byte array, make a helper to convert strings
15# to byte arrays
16sab = System.Array[System.Byte]
Chris Liechtiba45c522016-02-06 23:53:23 +010017
18
cliechti761fd6e2008-06-24 11:32:43 +000019def as_byte_array(string):
cliechti4a567a02009-07-27 22:09:31 +000020 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 +000021
Chris Liechticb6ce1b2016-02-02 01:53:56 +010022
Chris Liechtief6b7b42015-08-06 22:19:26 +020023class Serial(SerialBase):
cliechti771278b2013-10-17 03:19:00 +000024 """Serial port implementation for .NET/Mono."""
cliechti0d6029a2008-06-21 01:28:46 +000025
cliechti4a567a02009-07-27 22:09:31 +000026 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
Chris Liechticb6ce1b2016-02-02 01:53:56 +010027 9600, 19200, 38400, 57600, 115200)
cliechti0d6029a2008-06-21 01:28:46 +000028
29 def open(self):
cliechti00df9702014-08-04 10:12:48 +000030 """\
31 Open port with current settings. This may throw a SerialException
32 if the port cannot be opened.
33 """
cliechti0d6029a2008-06-21 01:28:46 +000034 if self._port is None:
35 raise SerialException("Port must be configured before it can be used.")
Chris Liechti6ed12e02015-09-18 21:23:42 +020036 if self.is_open:
cliechti8f69e702011-03-19 00:22:32 +000037 raise SerialException("Port is already open.")
cliechti0d6029a2008-06-21 01:28:46 +000038 try:
39 self._port_handle = System.IO.Ports.SerialPort(self.portstr)
Chris Liechti6ed12e02015-09-18 21:23:42 +020040 except Exception as msg:
cliechtiff0c3792008-06-22 01:01:21 +000041 self._port_handle = None
cliechti0d6029a2008-06-21 01:28:46 +000042 raise SerialException("could not open port %s: %s" % (self.portstr, msg))
43
Chris Liechtifc3b4992016-01-22 02:19:59 +010044 # if RTS and/or DTR are not set before open, they default to True
45 if self._rts_state is None:
46 self._rts_state = True
47 if self._dtr_state is None:
48 self._dtr_state = True
49
cliechti0d6029a2008-06-21 01:28:46 +000050 self._reconfigurePort()
51 self._port_handle.Open()
Chris Liechti6ed12e02015-09-18 21:23:42 +020052 self.is_open = True
53 if not self._dsrdtr:
54 self._update_dtr_state()
cliechti761fd6e2008-06-24 11:32:43 +000055 if not self._rtscts:
Chris Liechti6ed12e02015-09-18 21:23:42 +020056 self._update_rts_state()
57 self.reset_input_buffer()
cliechti0d6029a2008-06-21 01:28:46 +000058
59 def _reconfigurePort(self):
cliechtiff0c3792008-06-22 01:01:21 +000060 """Set communication parameters on opened port."""
cliechti0d6029a2008-06-21 01:28:46 +000061 if not self._port_handle:
62 raise SerialException("Can only operate on a valid port handle")
cliechti58b481c2009-02-16 20:42:32 +000063
cliechtiedfba4e2009-02-07 00:29:47 +000064 #~ self._port_handle.ReceivedBytesThreshold = 1
cliechti58b481c2009-02-16 20:42:32 +000065
cliechti0d6029a2008-06-21 01:28:46 +000066 if self._timeout is None:
67 self._port_handle.ReadTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
68 else:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010069 self._port_handle.ReadTimeout = int(self._timeout * 1000)
cliechti58b481c2009-02-16 20:42:32 +000070
cliechti0d6029a2008-06-21 01:28:46 +000071 # if self._timeout != 0 and self._interCharTimeout is not None:
72 # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
cliechti58b481c2009-02-16 20:42:32 +000073
Chris Liechti6ed12e02015-09-18 21:23:42 +020074 if self._write_timeout is None:
cliechtiff0c3792008-06-22 01:01:21 +000075 self._port_handle.WriteTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
cliechti0d6029a2008-06-21 01:28:46 +000076 else:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010077 self._port_handle.WriteTimeout = int(self._write_timeout * 1000)
cliechti0d6029a2008-06-21 01:28:46 +000078
79 # Setup the connection info.
cliechtic53a8ca2008-06-24 11:57:32 +000080 try:
81 self._port_handle.BaudRate = self._baudrate
Chris Liechti6ed12e02015-09-18 21:23:42 +020082 except IOError as e:
cliechtic53a8ca2008-06-24 11:57:32 +000083 # catch errors from illegal baudrate settings
84 raise ValueError(str(e))
cliechti0d6029a2008-06-21 01:28:46 +000085
86 if self._bytesize == FIVEBITS:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010087 self._port_handle.DataBits = 5
cliechti0d6029a2008-06-21 01:28:46 +000088 elif self._bytesize == SIXBITS:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010089 self._port_handle.DataBits = 6
cliechti0d6029a2008-06-21 01:28:46 +000090 elif self._bytesize == SEVENBITS:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010091 self._port_handle.DataBits = 7
cliechti0d6029a2008-06-21 01:28:46 +000092 elif self._bytesize == EIGHTBITS:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010093 self._port_handle.DataBits = 8
cliechti0d6029a2008-06-21 01:28:46 +000094 else:
95 raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
96
97 if self._parity == PARITY_NONE:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010098 self._port_handle.Parity = getattr(System.IO.Ports.Parity, 'None') # reserved keyword in Py3k
cliechti0d6029a2008-06-21 01:28:46 +000099 elif self._parity == PARITY_EVEN:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100100 self._port_handle.Parity = System.IO.Ports.Parity.Even
cliechti0d6029a2008-06-21 01:28:46 +0000101 elif self._parity == PARITY_ODD:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100102 self._port_handle.Parity = System.IO.Ports.Parity.Odd
cliechti0d6029a2008-06-21 01:28:46 +0000103 elif self._parity == PARITY_MARK:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100104 self._port_handle.Parity = System.IO.Ports.Parity.Mark
cliechti0d6029a2008-06-21 01:28:46 +0000105 elif self._parity == PARITY_SPACE:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100106 self._port_handle.Parity = System.IO.Ports.Parity.Space
cliechti0d6029a2008-06-21 01:28:46 +0000107 else:
108 raise ValueError("Unsupported parity mode: %r" % self._parity)
109
110 if self._stopbits == STOPBITS_ONE:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100111 self._port_handle.StopBits = System.IO.Ports.StopBits.One
cliechti58b481c2009-02-16 20:42:32 +0000112 elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100113 self._port_handle.StopBits = System.IO.Ports.StopBits.OnePointFive
cliechti0d6029a2008-06-21 01:28:46 +0000114 elif self._stopbits == STOPBITS_TWO:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100115 self._port_handle.StopBits = System.IO.Ports.StopBits.Two
cliechti0d6029a2008-06-21 01:28:46 +0000116 else:
117 raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
cliechti58b481c2009-02-16 20:42:32 +0000118
cliechti0d6029a2008-06-21 01:28:46 +0000119 if self._rtscts and self._xonxoff:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100120 self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff
cliechti0d6029a2008-06-21 01:28:46 +0000121 elif self._rtscts:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100122 self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSend
cliechti0d6029a2008-06-21 01:28:46 +0000123 elif self._xonxoff:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100124 self._port_handle.Handshake = System.IO.Ports.Handshake.XOnXOff
cliechti0d6029a2008-06-21 01:28:46 +0000125 else:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100126 self._port_handle.Handshake = getattr(System.IO.Ports.Handshake, 'None') # reserved keyword in Py3k
cliechti0d6029a2008-06-21 01:28:46 +0000127
128 #~ def __del__(self):
129 #~ self.close()
130
131 def close(self):
132 """Close port"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200133 if self.is_open:
cliechti0d6029a2008-06-21 01:28:46 +0000134 if self._port_handle:
135 try:
cliechtiff0c3792008-06-22 01:01:21 +0000136 self._port_handle.Close()
cliechti0d6029a2008-06-21 01:28:46 +0000137 except System.IO.Ports.InvalidOperationException:
138 # ignore errors. can happen for unplugged USB serial devices
139 pass
140 self._port_handle = None
Chris Liechti6ed12e02015-09-18 21:23:42 +0200141 self.is_open = False
cliechti0d6029a2008-06-21 01:28:46 +0000142
143 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti58b481c2009-02-16 20:42:32 +0000144
Chris Liechti6ed12e02015-09-18 21:23:42 +0200145 @property
146 def in_waiting(self):
cliechti0d6029a2008-06-21 01:28:46 +0000147 """Return the number of characters currently in the input buffer."""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200148 if not self._port_handle:
149 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000150 return self._port_handle.BytesToRead
151
cliechti4a567a02009-07-27 22:09:31 +0000152 def read(self, size=1):
cliechti00df9702014-08-04 10:12:48 +0000153 """\
154 Read size bytes from the serial port. If a timeout is set it may
155 return less characters as requested. With no timeout it will block
156 until the requested number of bytes is read.
157 """
Chris Liechti6ed12e02015-09-18 21:23:42 +0200158 if not self._port_handle:
159 raise portNotOpenError
cliechti4a567a02009-07-27 22:09:31 +0000160 # must use single byte reads as this is the only way to read
161 # without applying encodings
162 data = bytearray()
cliechti0d6029a2008-06-21 01:28:46 +0000163 while size:
cliechtiff0c3792008-06-22 01:01:21 +0000164 try:
cliechti4a567a02009-07-27 22:09:31 +0000165 data.append(self._port_handle.ReadByte())
Chris Liechti6c63da62016-01-25 21:39:32 +0100166 except System.TimeoutException:
cliechtiff0c3792008-06-22 01:01:21 +0000167 break
168 else:
169 size -= 1
cliechti4a567a02009-07-27 22:09:31 +0000170 return bytes(data)
cliechti0d6029a2008-06-21 01:28:46 +0000171
cliechti4a567a02009-07-27 22:09:31 +0000172 def write(self, data):
cliechti0d6029a2008-06-21 01:28:46 +0000173 """Output the given string over the serial port."""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200174 if not self._port_handle:
175 raise portNotOpenError
cliechti00df9702014-08-04 10:12:48 +0000176 #~ if not isinstance(data, (bytes, bytearray)):
177 #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
cliechtiff0c3792008-06-22 01:01:21 +0000178 try:
cliechti761fd6e2008-06-24 11:32:43 +0000179 # must call overloaded method with byte array argument
180 # as this is the only one not applying encodings
181 self._port_handle.Write(as_byte_array(data), 0, len(data))
Chris Liechti6c63da62016-01-25 21:39:32 +0100182 except System.TimeoutException:
cliechtiff0c3792008-06-22 01:01:21 +0000183 raise writeTimeoutError
cliechtif81362e2009-07-25 03:44:33 +0000184 return len(data)
cliechti0d6029a2008-06-21 01:28:46 +0000185
Chris Liechti6ed12e02015-09-18 21:23:42 +0200186 def reset_input_buffer(self):
cliechti0d6029a2008-06-21 01:28:46 +0000187 """Clear input buffer, discarding all that is in the buffer."""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200188 if not self._port_handle:
189 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000190 self._port_handle.DiscardInBuffer()
191
Chris Liechti6ed12e02015-09-18 21:23:42 +0200192 def reset_output_buffer(self):
cliechti00df9702014-08-04 10:12:48 +0000193 """\
194 Clear output buffer, aborting the current output and
195 discarding all that is in the buffer.
196 """
Chris Liechti6ed12e02015-09-18 21:23:42 +0200197 if not self._port_handle:
198 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000199 self._port_handle.DiscardOutBuffer()
200
Chris Liechti6ed12e02015-09-18 21:23:42 +0200201 def _update_break_state(self):
cliechti00df9702014-08-04 10:12:48 +0000202 """
203 Set break: Controls TXD. When active, to transmitting is possible.
204 """
Chris Liechti6ed12e02015-09-18 21:23:42 +0200205 if not self._port_handle:
206 raise portNotOpenError
207 self._port_handle.BreakState = bool(self._break_state)
cliechti0d6029a2008-06-21 01:28:46 +0000208
Chris Liechti6ed12e02015-09-18 21:23:42 +0200209 def _update_rts_state(self):
cliechti0d6029a2008-06-21 01:28:46 +0000210 """Set terminal status line: Request To Send"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200211 if not self._port_handle:
212 raise portNotOpenError
213 self._port_handle.RtsEnable = bool(self._rts_state)
cliechti0d6029a2008-06-21 01:28:46 +0000214
Chris Liechti6ed12e02015-09-18 21:23:42 +0200215 def _update_dtr_state(self):
cliechti0d6029a2008-06-21 01:28:46 +0000216 """Set terminal status line: Data Terminal Ready"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200217 if not self._port_handle:
218 raise portNotOpenError
219 self._port_handle.DtrEnable = bool(self._dtr_state)
cliechti0d6029a2008-06-21 01:28:46 +0000220
Chris Liechti6ed12e02015-09-18 21:23:42 +0200221 @property
222 def cts(self):
cliechti0d6029a2008-06-21 01:28:46 +0000223 """Read terminal status line: Clear To Send"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200224 if not self._port_handle:
225 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000226 return self._port_handle.CtsHolding
227
Chris Liechti6ed12e02015-09-18 21:23:42 +0200228 @property
229 def dsr(self):
cliechti0d6029a2008-06-21 01:28:46 +0000230 """Read terminal status line: Data Set Ready"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200231 if not self._port_handle:
232 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000233 return self._port_handle.DsrHolding
234
Chris Liechti6ed12e02015-09-18 21:23:42 +0200235 @property
236 def ri(self):
cliechtiff0c3792008-06-22 01:01:21 +0000237 """Read terminal status line: Ring Indicator"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200238 if not self._port_handle:
239 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000240 #~ return self._port_handle.XXX
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100241 return False # XXX an error would be better
cliechti0d6029a2008-06-21 01:28:46 +0000242
Chris Liechti6ed12e02015-09-18 21:23:42 +0200243 @property
244 def cd(self):
cliechti0d6029a2008-06-21 01:28:46 +0000245 """Read terminal status line: Carrier Detect"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200246 if not self._port_handle:
247 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000248 return self._port_handle.CDHolding
249
250 # - - platform specific - - - -
cliechtif81362e2009-07-25 03:44:33 +0000251 # none