blob: 1873a00def52905ae3394a9120cd3ed983b90dad [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
cliechti4a567a02009-07-27 22:09:31 +000014
Chris Liechti6ed12e02015-09-18 21:23:42 +020015#~ def device(portnum):
16 #~ """Turn a port number into a device name"""
17 #~ return System.IO.Ports.SerialPort.GetPortNames()[portnum]
cliechti0d6029a2008-06-21 01:28:46 +000018
cliechti4a567a02009-07-27 22:09:31 +000019
cliechti761fd6e2008-06-24 11:32:43 +000020# must invoke function with byte array, make a helper to convert strings
21# to byte arrays
22sab = System.Array[System.Byte]
23def as_byte_array(string):
cliechti4a567a02009-07-27 22:09:31 +000024 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 +000025
Chris Liechticb6ce1b2016-02-02 01:53:56 +010026
Chris Liechtief6b7b42015-08-06 22:19:26 +020027class Serial(SerialBase):
cliechti771278b2013-10-17 03:19:00 +000028 """Serial port implementation for .NET/Mono."""
cliechti0d6029a2008-06-21 01:28:46 +000029
cliechti4a567a02009-07-27 22:09:31 +000030 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
Chris Liechticb6ce1b2016-02-02 01:53:56 +010031 9600, 19200, 38400, 57600, 115200)
cliechti0d6029a2008-06-21 01:28:46 +000032
33 def open(self):
cliechti00df9702014-08-04 10:12:48 +000034 """\
35 Open port with current settings. This may throw a SerialException
36 if the port cannot be opened.
37 """
cliechti0d6029a2008-06-21 01:28:46 +000038 if self._port is None:
39 raise SerialException("Port must be configured before it can be used.")
Chris Liechti6ed12e02015-09-18 21:23:42 +020040 if self.is_open:
cliechti8f69e702011-03-19 00:22:32 +000041 raise SerialException("Port is already open.")
cliechti0d6029a2008-06-21 01:28:46 +000042 try:
43 self._port_handle = System.IO.Ports.SerialPort(self.portstr)
Chris Liechti6ed12e02015-09-18 21:23:42 +020044 except Exception as msg:
cliechtiff0c3792008-06-22 01:01:21 +000045 self._port_handle = None
cliechti0d6029a2008-06-21 01:28:46 +000046 raise SerialException("could not open port %s: %s" % (self.portstr, msg))
47
Chris Liechtifc3b4992016-01-22 02:19:59 +010048 # if RTS and/or DTR are not set before open, they default to True
49 if self._rts_state is None:
50 self._rts_state = True
51 if self._dtr_state is None:
52 self._dtr_state = True
53
cliechti0d6029a2008-06-21 01:28:46 +000054 self._reconfigurePort()
55 self._port_handle.Open()
Chris Liechti6ed12e02015-09-18 21:23:42 +020056 self.is_open = True
57 if not self._dsrdtr:
58 self._update_dtr_state()
cliechti761fd6e2008-06-24 11:32:43 +000059 if not self._rtscts:
Chris Liechti6ed12e02015-09-18 21:23:42 +020060 self._update_rts_state()
61 self.reset_input_buffer()
cliechti0d6029a2008-06-21 01:28:46 +000062
63 def _reconfigurePort(self):
cliechtiff0c3792008-06-22 01:01:21 +000064 """Set communication parameters on opened port."""
cliechti0d6029a2008-06-21 01:28:46 +000065 if not self._port_handle:
66 raise SerialException("Can only operate on a valid port handle")
cliechti58b481c2009-02-16 20:42:32 +000067
cliechtiedfba4e2009-02-07 00:29:47 +000068 #~ self._port_handle.ReceivedBytesThreshold = 1
cliechti58b481c2009-02-16 20:42:32 +000069
cliechti0d6029a2008-06-21 01:28:46 +000070 if self._timeout is None:
71 self._port_handle.ReadTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
72 else:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010073 self._port_handle.ReadTimeout = int(self._timeout * 1000)
cliechti58b481c2009-02-16 20:42:32 +000074
cliechti0d6029a2008-06-21 01:28:46 +000075 # if self._timeout != 0 and self._interCharTimeout is not None:
76 # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
cliechti58b481c2009-02-16 20:42:32 +000077
Chris Liechti6ed12e02015-09-18 21:23:42 +020078 if self._write_timeout is None:
cliechtiff0c3792008-06-22 01:01:21 +000079 self._port_handle.WriteTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
cliechti0d6029a2008-06-21 01:28:46 +000080 else:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010081 self._port_handle.WriteTimeout = int(self._write_timeout * 1000)
cliechti0d6029a2008-06-21 01:28:46 +000082
83 # Setup the connection info.
cliechtic53a8ca2008-06-24 11:57:32 +000084 try:
85 self._port_handle.BaudRate = self._baudrate
Chris Liechti6ed12e02015-09-18 21:23:42 +020086 except IOError as e:
cliechtic53a8ca2008-06-24 11:57:32 +000087 # catch errors from illegal baudrate settings
88 raise ValueError(str(e))
cliechti0d6029a2008-06-21 01:28:46 +000089
90 if self._bytesize == FIVEBITS:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010091 self._port_handle.DataBits = 5
cliechti0d6029a2008-06-21 01:28:46 +000092 elif self._bytesize == SIXBITS:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010093 self._port_handle.DataBits = 6
cliechti0d6029a2008-06-21 01:28:46 +000094 elif self._bytesize == SEVENBITS:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010095 self._port_handle.DataBits = 7
cliechti0d6029a2008-06-21 01:28:46 +000096 elif self._bytesize == EIGHTBITS:
Chris Liechticb6ce1b2016-02-02 01:53:56 +010097 self._port_handle.DataBits = 8
cliechti0d6029a2008-06-21 01:28:46 +000098 else:
99 raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
100
101 if self._parity == PARITY_NONE:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100102 self._port_handle.Parity = getattr(System.IO.Ports.Parity, 'None') # reserved keyword in Py3k
cliechti0d6029a2008-06-21 01:28:46 +0000103 elif self._parity == PARITY_EVEN:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100104 self._port_handle.Parity = System.IO.Ports.Parity.Even
cliechti0d6029a2008-06-21 01:28:46 +0000105 elif self._parity == PARITY_ODD:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100106 self._port_handle.Parity = System.IO.Ports.Parity.Odd
cliechti0d6029a2008-06-21 01:28:46 +0000107 elif self._parity == PARITY_MARK:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100108 self._port_handle.Parity = System.IO.Ports.Parity.Mark
cliechti0d6029a2008-06-21 01:28:46 +0000109 elif self._parity == PARITY_SPACE:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100110 self._port_handle.Parity = System.IO.Ports.Parity.Space
cliechti0d6029a2008-06-21 01:28:46 +0000111 else:
112 raise ValueError("Unsupported parity mode: %r" % self._parity)
113
114 if self._stopbits == STOPBITS_ONE:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100115 self._port_handle.StopBits = System.IO.Ports.StopBits.One
cliechti58b481c2009-02-16 20:42:32 +0000116 elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100117 self._port_handle.StopBits = System.IO.Ports.StopBits.OnePointFive
cliechti0d6029a2008-06-21 01:28:46 +0000118 elif self._stopbits == STOPBITS_TWO:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100119 self._port_handle.StopBits = System.IO.Ports.StopBits.Two
cliechti0d6029a2008-06-21 01:28:46 +0000120 else:
121 raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
cliechti58b481c2009-02-16 20:42:32 +0000122
cliechti0d6029a2008-06-21 01:28:46 +0000123 if self._rtscts and self._xonxoff:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100124 self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff
cliechti0d6029a2008-06-21 01:28:46 +0000125 elif self._rtscts:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100126 self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSend
cliechti0d6029a2008-06-21 01:28:46 +0000127 elif self._xonxoff:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100128 self._port_handle.Handshake = System.IO.Ports.Handshake.XOnXOff
cliechti0d6029a2008-06-21 01:28:46 +0000129 else:
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100130 self._port_handle.Handshake = getattr(System.IO.Ports.Handshake, 'None') # reserved keyword in Py3k
cliechti0d6029a2008-06-21 01:28:46 +0000131
132 #~ def __del__(self):
133 #~ self.close()
134
135 def close(self):
136 """Close port"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200137 if self.is_open:
cliechti0d6029a2008-06-21 01:28:46 +0000138 if self._port_handle:
139 try:
cliechtiff0c3792008-06-22 01:01:21 +0000140 self._port_handle.Close()
cliechti0d6029a2008-06-21 01:28:46 +0000141 except System.IO.Ports.InvalidOperationException:
142 # ignore errors. can happen for unplugged USB serial devices
143 pass
144 self._port_handle = None
Chris Liechti6ed12e02015-09-18 21:23:42 +0200145 self.is_open = False
cliechti0d6029a2008-06-21 01:28:46 +0000146
147 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti58b481c2009-02-16 20:42:32 +0000148
Chris Liechti6ed12e02015-09-18 21:23:42 +0200149 @property
150 def in_waiting(self):
cliechti0d6029a2008-06-21 01:28:46 +0000151 """Return the number of characters currently in the input buffer."""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200152 if not self._port_handle:
153 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000154 return self._port_handle.BytesToRead
155
cliechti4a567a02009-07-27 22:09:31 +0000156 def read(self, size=1):
cliechti00df9702014-08-04 10:12:48 +0000157 """\
158 Read size bytes from the serial port. If a timeout is set it may
159 return less characters as requested. With no timeout it will block
160 until the requested number of bytes is read.
161 """
Chris Liechti6ed12e02015-09-18 21:23:42 +0200162 if not self._port_handle:
163 raise portNotOpenError
cliechti4a567a02009-07-27 22:09:31 +0000164 # must use single byte reads as this is the only way to read
165 # without applying encodings
166 data = bytearray()
cliechti0d6029a2008-06-21 01:28:46 +0000167 while size:
cliechtiff0c3792008-06-22 01:01:21 +0000168 try:
cliechti4a567a02009-07-27 22:09:31 +0000169 data.append(self._port_handle.ReadByte())
Chris Liechti6c63da62016-01-25 21:39:32 +0100170 except System.TimeoutException:
cliechtiff0c3792008-06-22 01:01:21 +0000171 break
172 else:
173 size -= 1
cliechti4a567a02009-07-27 22:09:31 +0000174 return bytes(data)
cliechti0d6029a2008-06-21 01:28:46 +0000175
cliechti4a567a02009-07-27 22:09:31 +0000176 def write(self, data):
cliechti0d6029a2008-06-21 01:28:46 +0000177 """Output the given string over the serial port."""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200178 if not self._port_handle:
179 raise portNotOpenError
cliechti00df9702014-08-04 10:12:48 +0000180 #~ if not isinstance(data, (bytes, bytearray)):
181 #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
cliechtiff0c3792008-06-22 01:01:21 +0000182 try:
cliechti761fd6e2008-06-24 11:32:43 +0000183 # must call overloaded method with byte array argument
184 # as this is the only one not applying encodings
185 self._port_handle.Write(as_byte_array(data), 0, len(data))
Chris Liechti6c63da62016-01-25 21:39:32 +0100186 except System.TimeoutException:
cliechtiff0c3792008-06-22 01:01:21 +0000187 raise writeTimeoutError
cliechtif81362e2009-07-25 03:44:33 +0000188 return len(data)
cliechti0d6029a2008-06-21 01:28:46 +0000189
Chris Liechti6ed12e02015-09-18 21:23:42 +0200190 def reset_input_buffer(self):
cliechti0d6029a2008-06-21 01:28:46 +0000191 """Clear input buffer, discarding all that is in the buffer."""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200192 if not self._port_handle:
193 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000194 self._port_handle.DiscardInBuffer()
195
Chris Liechti6ed12e02015-09-18 21:23:42 +0200196 def reset_output_buffer(self):
cliechti00df9702014-08-04 10:12:48 +0000197 """\
198 Clear output buffer, aborting the current output and
199 discarding all that is in the buffer.
200 """
Chris Liechti6ed12e02015-09-18 21:23:42 +0200201 if not self._port_handle:
202 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000203 self._port_handle.DiscardOutBuffer()
204
Chris Liechti6ed12e02015-09-18 21:23:42 +0200205 def _update_break_state(self):
cliechti00df9702014-08-04 10:12:48 +0000206 """
207 Set break: Controls TXD. When active, to transmitting is possible.
208 """
Chris Liechti6ed12e02015-09-18 21:23:42 +0200209 if not self._port_handle:
210 raise portNotOpenError
211 self._port_handle.BreakState = bool(self._break_state)
cliechti0d6029a2008-06-21 01:28:46 +0000212
Chris Liechti6ed12e02015-09-18 21:23:42 +0200213 def _update_rts_state(self):
cliechti0d6029a2008-06-21 01:28:46 +0000214 """Set terminal status line: Request To Send"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200215 if not self._port_handle:
216 raise portNotOpenError
217 self._port_handle.RtsEnable = bool(self._rts_state)
cliechti0d6029a2008-06-21 01:28:46 +0000218
Chris Liechti6ed12e02015-09-18 21:23:42 +0200219 def _update_dtr_state(self):
cliechti0d6029a2008-06-21 01:28:46 +0000220 """Set terminal status line: Data Terminal Ready"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200221 if not self._port_handle:
222 raise portNotOpenError
223 self._port_handle.DtrEnable = bool(self._dtr_state)
cliechti0d6029a2008-06-21 01:28:46 +0000224
Chris Liechti6ed12e02015-09-18 21:23:42 +0200225 @property
226 def cts(self):
cliechti0d6029a2008-06-21 01:28:46 +0000227 """Read terminal status line: Clear To Send"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200228 if not self._port_handle:
229 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000230 return self._port_handle.CtsHolding
231
Chris Liechti6ed12e02015-09-18 21:23:42 +0200232 @property
233 def dsr(self):
cliechti0d6029a2008-06-21 01:28:46 +0000234 """Read terminal status line: Data Set Ready"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200235 if not self._port_handle:
236 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000237 return self._port_handle.DsrHolding
238
Chris Liechti6ed12e02015-09-18 21:23:42 +0200239 @property
240 def ri(self):
cliechtiff0c3792008-06-22 01:01:21 +0000241 """Read terminal status line: Ring Indicator"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200242 if not self._port_handle:
243 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000244 #~ return self._port_handle.XXX
Chris Liechticb6ce1b2016-02-02 01:53:56 +0100245 return False # XXX an error would be better
cliechti0d6029a2008-06-21 01:28:46 +0000246
Chris Liechti6ed12e02015-09-18 21:23:42 +0200247 @property
248 def cd(self):
cliechti0d6029a2008-06-21 01:28:46 +0000249 """Read terminal status line: Carrier Detect"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200250 if not self._port_handle:
251 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000252 return self._port_handle.CDHolding
253
254 # - - platform specific - - - -
cliechtif81362e2009-07-25 03:44:33 +0000255 # none