blob: 29bd2cbfda8946fc25df0225c9d711d807551bc7 [file] [log] [blame]
cliechti0d6029a2008-06-21 01:28:46 +00001#! python
cliechtiff0c3792008-06-22 01:01:21 +00002# Python Serial Port Extension for Win32, Linux, BSD, Jython and .NET/Mono
3# serial driver for .NET/Mono (IronPython), .NET >= 2
4# see __init__.py
cliechti0d6029a2008-06-21 01:28:46 +00005#
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 clr
11import System
cliechti0d6029a2008-06-21 01:28:46 +000012import System.IO.Ports
cliechti39cfb7b2011-08-22 00:30:07 +000013from serial.serialutil import *
cliechti0d6029a2008-06-21 01:28:46 +000014
cliechti4a567a02009-07-27 22:09:31 +000015
Chris Liechti6ed12e02015-09-18 21:23:42 +020016#~ def device(portnum):
17 #~ """Turn a port number into a device name"""
18 #~ return System.IO.Ports.SerialPort.GetPortNames()[portnum]
cliechti0d6029a2008-06-21 01:28:46 +000019
cliechti4a567a02009-07-27 22:09:31 +000020
cliechti761fd6e2008-06-24 11:32:43 +000021# must invoke function with byte array, make a helper to convert strings
22# to byte arrays
23sab = System.Array[System.Byte]
24def as_byte_array(string):
cliechti4a567a02009-07-27 22:09:31 +000025 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 +000026
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,
31 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
48 self._reconfigurePort()
49 self._port_handle.Open()
Chris Liechti6ed12e02015-09-18 21:23:42 +020050 self.is_open = True
51 if not self._dsrdtr:
52 self._update_dtr_state()
cliechti761fd6e2008-06-24 11:32:43 +000053 if not self._rtscts:
Chris Liechti6ed12e02015-09-18 21:23:42 +020054 self._update_rts_state()
55 self.reset_input_buffer()
cliechti0d6029a2008-06-21 01:28:46 +000056
57 def _reconfigurePort(self):
cliechtiff0c3792008-06-22 01:01:21 +000058 """Set communication parameters on opened port."""
cliechti0d6029a2008-06-21 01:28:46 +000059 if not self._port_handle:
60 raise SerialException("Can only operate on a valid port handle")
cliechti58b481c2009-02-16 20:42:32 +000061
cliechtiedfba4e2009-02-07 00:29:47 +000062 #~ self._port_handle.ReceivedBytesThreshold = 1
cliechti58b481c2009-02-16 20:42:32 +000063
cliechti0d6029a2008-06-21 01:28:46 +000064 if self._timeout is None:
65 self._port_handle.ReadTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
66 else:
67 self._port_handle.ReadTimeout = int(self._timeout*1000)
cliechti58b481c2009-02-16 20:42:32 +000068
cliechti0d6029a2008-06-21 01:28:46 +000069 # if self._timeout != 0 and self._interCharTimeout is not None:
70 # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
cliechti58b481c2009-02-16 20:42:32 +000071
Chris Liechti6ed12e02015-09-18 21:23:42 +020072 if self._write_timeout is None:
cliechtiff0c3792008-06-22 01:01:21 +000073 self._port_handle.WriteTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
cliechti0d6029a2008-06-21 01:28:46 +000074 else:
Chris Liechti6ed12e02015-09-18 21:23:42 +020075 self._port_handle.WriteTimeout = int(self._write_timeout*1000)
cliechti0d6029a2008-06-21 01:28:46 +000076
77
78 # Setup the connection info.
cliechtic53a8ca2008-06-24 11:57:32 +000079 try:
80 self._port_handle.BaudRate = self._baudrate
Chris Liechti6ed12e02015-09-18 21:23:42 +020081 except IOError as e:
cliechtic53a8ca2008-06-24 11:57:32 +000082 # catch errors from illegal baudrate settings
83 raise ValueError(str(e))
cliechti0d6029a2008-06-21 01:28:46 +000084
85 if self._bytesize == FIVEBITS:
86 self._port_handle.DataBits = 5
87 elif self._bytesize == SIXBITS:
88 self._port_handle.DataBits = 6
89 elif self._bytesize == SEVENBITS:
90 self._port_handle.DataBits = 7
91 elif self._bytesize == EIGHTBITS:
92 self._port_handle.DataBits = 8
93 else:
94 raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
95
96 if self._parity == PARITY_NONE:
cliechti91d247d2009-07-25 00:42:57 +000097 self._port_handle.Parity = getattr(System.IO.Ports.Parity, 'None') # reserved keyword in Py3k
cliechti0d6029a2008-06-21 01:28:46 +000098 elif self._parity == PARITY_EVEN:
99 self._port_handle.Parity = System.IO.Ports.Parity.Even
100 elif self._parity == PARITY_ODD:
101 self._port_handle.Parity = System.IO.Ports.Parity.Odd
102 elif self._parity == PARITY_MARK:
103 self._port_handle.Parity = System.IO.Ports.Parity.Mark
104 elif self._parity == PARITY_SPACE:
105 self._port_handle.Parity = System.IO.Ports.Parity.Space
106 else:
107 raise ValueError("Unsupported parity mode: %r" % self._parity)
108
109 if self._stopbits == STOPBITS_ONE:
110 self._port_handle.StopBits = System.IO.Ports.StopBits.One
cliechti58b481c2009-02-16 20:42:32 +0000111 elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
112 self._port_handle.StopBits = System.IO.Ports.StopBits.OnePointFive
cliechti0d6029a2008-06-21 01:28:46 +0000113 elif self._stopbits == STOPBITS_TWO:
114 self._port_handle.StopBits = System.IO.Ports.StopBits.Two
115 else:
116 raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
cliechti58b481c2009-02-16 20:42:32 +0000117
cliechti0d6029a2008-06-21 01:28:46 +0000118 if self._rtscts and self._xonxoff:
119 self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff
120 elif self._rtscts:
121 self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSend
122 elif self._xonxoff:
123 self._port_handle.Handshake = System.IO.Ports.Handshake.XOnXOff
124 else:
cliechti91d247d2009-07-25 00:42:57 +0000125 self._port_handle.Handshake = getattr(System.IO.Ports.Handshake, 'None') # reserved keyword in Py3k
cliechti0d6029a2008-06-21 01:28:46 +0000126
127 #~ def __del__(self):
128 #~ self.close()
129
130 def close(self):
131 """Close port"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200132 if self.is_open:
cliechti0d6029a2008-06-21 01:28:46 +0000133 if self._port_handle:
134 try:
cliechtiff0c3792008-06-22 01:01:21 +0000135 self._port_handle.Close()
cliechti0d6029a2008-06-21 01:28:46 +0000136 except System.IO.Ports.InvalidOperationException:
137 # ignore errors. can happen for unplugged USB serial devices
138 pass
139 self._port_handle = None
Chris Liechti6ed12e02015-09-18 21:23:42 +0200140 self.is_open = False
cliechti0d6029a2008-06-21 01:28:46 +0000141
142 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti58b481c2009-02-16 20:42:32 +0000143
Chris Liechti6ed12e02015-09-18 21:23:42 +0200144 @property
145 def in_waiting(self):
cliechti0d6029a2008-06-21 01:28:46 +0000146 """Return the number of characters currently in the input buffer."""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200147 if not self._port_handle:
148 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000149 return self._port_handle.BytesToRead
150
cliechti4a567a02009-07-27 22:09:31 +0000151 def read(self, size=1):
cliechti00df9702014-08-04 10:12:48 +0000152 """\
153 Read size bytes from the serial port. If a timeout is set it may
154 return less characters as requested. With no timeout it will block
155 until the requested number of bytes is read.
156 """
Chris Liechti6ed12e02015-09-18 21:23:42 +0200157 if not self._port_handle:
158 raise portNotOpenError
cliechti4a567a02009-07-27 22:09:31 +0000159 # must use single byte reads as this is the only way to read
160 # without applying encodings
161 data = bytearray()
cliechti0d6029a2008-06-21 01:28:46 +0000162 while size:
cliechtiff0c3792008-06-22 01:01:21 +0000163 try:
cliechti4a567a02009-07-27 22:09:31 +0000164 data.append(self._port_handle.ReadByte())
Chris Liechti6ed12e02015-09-18 21:23:42 +0200165 except System.TimeoutException as e:
cliechtiff0c3792008-06-22 01:01:21 +0000166 break
167 else:
168 size -= 1
cliechti4a567a02009-07-27 22:09:31 +0000169 return bytes(data)
cliechti0d6029a2008-06-21 01:28:46 +0000170
cliechti4a567a02009-07-27 22:09:31 +0000171 def write(self, data):
cliechti0d6029a2008-06-21 01:28:46 +0000172 """Output the given string over the serial port."""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200173 if not self._port_handle:
174 raise portNotOpenError
cliechti00df9702014-08-04 10:12:48 +0000175 #~ if not isinstance(data, (bytes, bytearray)):
176 #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
cliechtiff0c3792008-06-22 01:01:21 +0000177 try:
cliechti761fd6e2008-06-24 11:32:43 +0000178 # must call overloaded method with byte array argument
179 # as this is the only one not applying encodings
180 self._port_handle.Write(as_byte_array(data), 0, len(data))
Chris Liechti6ed12e02015-09-18 21:23:42 +0200181 except System.TimeoutException as e:
cliechtiff0c3792008-06-22 01:01:21 +0000182 raise writeTimeoutError
cliechtif81362e2009-07-25 03:44:33 +0000183 return len(data)
cliechti0d6029a2008-06-21 01:28:46 +0000184
Chris Liechti6ed12e02015-09-18 21:23:42 +0200185 def reset_input_buffer(self):
cliechti0d6029a2008-06-21 01:28:46 +0000186 """Clear input buffer, discarding all that is in the buffer."""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200187 if not self._port_handle:
188 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000189 self._port_handle.DiscardInBuffer()
190
Chris Liechti6ed12e02015-09-18 21:23:42 +0200191 def reset_output_buffer(self):
cliechti00df9702014-08-04 10:12:48 +0000192 """\
193 Clear output buffer, aborting the current output and
194 discarding all that is in the buffer.
195 """
Chris Liechti6ed12e02015-09-18 21:23:42 +0200196 if not self._port_handle:
197 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000198 self._port_handle.DiscardOutBuffer()
199
Chris Liechti6ed12e02015-09-18 21:23:42 +0200200 def _update_break_state(self):
cliechti00df9702014-08-04 10:12:48 +0000201 """
202 Set break: Controls TXD. When active, to transmitting is possible.
203 """
Chris Liechti6ed12e02015-09-18 21:23:42 +0200204 if not self._port_handle:
205 raise portNotOpenError
206 self._port_handle.BreakState = bool(self._break_state)
cliechti0d6029a2008-06-21 01:28:46 +0000207
Chris Liechti6ed12e02015-09-18 21:23:42 +0200208 def _update_rts_state(self):
cliechti0d6029a2008-06-21 01:28:46 +0000209 """Set terminal status line: Request To Send"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200210 if not self._port_handle:
211 raise portNotOpenError
212 self._port_handle.RtsEnable = bool(self._rts_state)
cliechti0d6029a2008-06-21 01:28:46 +0000213
Chris Liechti6ed12e02015-09-18 21:23:42 +0200214 def _update_dtr_state(self):
cliechti0d6029a2008-06-21 01:28:46 +0000215 """Set terminal status line: Data Terminal Ready"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200216 if not self._port_handle:
217 raise portNotOpenError
218 self._port_handle.DtrEnable = bool(self._dtr_state)
cliechti0d6029a2008-06-21 01:28:46 +0000219
Chris Liechti6ed12e02015-09-18 21:23:42 +0200220 @property
221 def cts(self):
cliechti0d6029a2008-06-21 01:28:46 +0000222 """Read terminal status line: Clear To Send"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200223 if not self._port_handle:
224 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000225 return self._port_handle.CtsHolding
226
Chris Liechti6ed12e02015-09-18 21:23:42 +0200227 @property
228 def dsr(self):
cliechti0d6029a2008-06-21 01:28:46 +0000229 """Read terminal status line: Data Set Ready"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200230 if not self._port_handle:
231 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000232 return self._port_handle.DsrHolding
233
Chris Liechti6ed12e02015-09-18 21:23:42 +0200234 @property
235 def ri(self):
cliechtiff0c3792008-06-22 01:01:21 +0000236 """Read terminal status line: Ring Indicator"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200237 if not self._port_handle:
238 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000239 #~ return self._port_handle.XXX
cliechtiff0c3792008-06-22 01:01:21 +0000240 return False #XXX an error would be better
cliechti0d6029a2008-06-21 01:28:46 +0000241
Chris Liechti6ed12e02015-09-18 21:23:42 +0200242 @property
243 def cd(self):
cliechti0d6029a2008-06-21 01:28:46 +0000244 """Read terminal status line: Carrier Detect"""
Chris Liechti6ed12e02015-09-18 21:23:42 +0200245 if not self._port_handle:
246 raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000247 return self._port_handle.CDHolding
248
249 # - - platform specific - - - -
cliechtif81362e2009-07-25 03:44:33 +0000250 # none
251
252
cliechti4a567a02009-07-27 22:09:31 +0000253# Nur Testfunktion!!
cliechti0d6029a2008-06-21 01:28:46 +0000254if __name__ == '__main__':
cliechti7aaead32009-07-23 14:02:41 +0000255 import sys
256
cliechti0d6029a2008-06-21 01:28:46 +0000257 s = Serial(0)
cliechti7aaead32009-07-23 14:02:41 +0000258 sys.stdio.write('%s\n' % s)
259
cliechti0d6029a2008-06-21 01:28:46 +0000260 s = Serial()
cliechti7aaead32009-07-23 14:02:41 +0000261 sys.stdio.write('%s\n' % s)
262
263
cliechti0d6029a2008-06-21 01:28:46 +0000264 s.baudrate = 19200
265 s.databits = 7
266 s.close()
267 s.port = 0
268 s.open()
cliechti7aaead32009-07-23 14:02:41 +0000269 sys.stdio.write('%s\n' % s)
cliechti0d6029a2008-06-21 01:28:46 +0000270