blob: 9ab38762061bacd3ab9f6331833d039e6cdddaaa [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#
cliechtiff0c3792008-06-22 01:01:21 +00006# (C) 2008 Chris Liechti <cliechti@gmx.net>
cliechti0d6029a2008-06-21 01:28:46 +00007# this is distributed under a free software license, see license.txt
8
cliechti761fd6e2008-06-24 11:32:43 +00009import clr
10import 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
cliechti0d6029a2008-06-21 01:28:46 +000015def device(portnum):
16 """Turn a port number into a device name"""
17 return System.IO.Ports.SerialPort.GetPortNames()[portnum]
18
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
cliechtif81362e2009-07-25 03:44:33 +000026class IronSerial(SerialBase):
cliechti771278b2013-10-17 03:19:00 +000027 """Serial port implementation for .NET/Mono."""
cliechti0d6029a2008-06-21 01:28:46 +000028
cliechti4a567a02009-07-27 22:09:31 +000029 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
30 9600, 19200, 38400, 57600, 115200)
cliechti0d6029a2008-06-21 01:28:46 +000031
32 def open(self):
cliechti00df9702014-08-04 10:12:48 +000033 """\
34 Open port with current settings. This may throw a SerialException
35 if the port cannot be opened.
36 """
cliechti0d6029a2008-06-21 01:28:46 +000037 if self._port is None:
38 raise SerialException("Port must be configured before it can be used.")
cliechti8f69e702011-03-19 00:22:32 +000039 if self._isOpen:
40 raise SerialException("Port is already open.")
cliechti0d6029a2008-06-21 01:28:46 +000041 try:
42 self._port_handle = System.IO.Ports.SerialPort(self.portstr)
43 except Exception, msg:
cliechtiff0c3792008-06-22 01:01:21 +000044 self._port_handle = None
cliechti0d6029a2008-06-21 01:28:46 +000045 raise SerialException("could not open port %s: %s" % (self.portstr, msg))
46
47 self._reconfigurePort()
48 self._port_handle.Open()
49 self._isOpen = True
cliechti761fd6e2008-06-24 11:32:43 +000050 if not self._rtscts:
51 self.setRTS(True)
52 self.setDTR(True)
cliechtiff0c3792008-06-22 01:01:21 +000053 self.flushInput()
54 self.flushOutput()
cliechti0d6029a2008-06-21 01:28:46 +000055
56 def _reconfigurePort(self):
cliechtiff0c3792008-06-22 01:01:21 +000057 """Set communication parameters on opened port."""
cliechti0d6029a2008-06-21 01:28:46 +000058 if not self._port_handle:
59 raise SerialException("Can only operate on a valid port handle")
cliechti58b481c2009-02-16 20:42:32 +000060
cliechtiedfba4e2009-02-07 00:29:47 +000061 #~ self._port_handle.ReceivedBytesThreshold = 1
cliechti58b481c2009-02-16 20:42:32 +000062
cliechti0d6029a2008-06-21 01:28:46 +000063 if self._timeout is None:
64 self._port_handle.ReadTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
65 else:
66 self._port_handle.ReadTimeout = int(self._timeout*1000)
cliechti58b481c2009-02-16 20:42:32 +000067
cliechti0d6029a2008-06-21 01:28:46 +000068 # if self._timeout != 0 and self._interCharTimeout is not None:
69 # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
cliechti58b481c2009-02-16 20:42:32 +000070
cliechti0d6029a2008-06-21 01:28:46 +000071 if self._writeTimeout is None:
cliechtiff0c3792008-06-22 01:01:21 +000072 self._port_handle.WriteTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
cliechti0d6029a2008-06-21 01:28:46 +000073 else:
74 self._port_handle.WriteTimeout = int(self._writeTimeout*1000)
75
76
77 # Setup the connection info.
cliechtic53a8ca2008-06-24 11:57:32 +000078 try:
79 self._port_handle.BaudRate = self._baudrate
80 except IOError, e:
81 # catch errors from illegal baudrate settings
82 raise ValueError(str(e))
cliechti0d6029a2008-06-21 01:28:46 +000083
84 if self._bytesize == FIVEBITS:
85 self._port_handle.DataBits = 5
86 elif self._bytesize == SIXBITS:
87 self._port_handle.DataBits = 6
88 elif self._bytesize == SEVENBITS:
89 self._port_handle.DataBits = 7
90 elif self._bytesize == EIGHTBITS:
91 self._port_handle.DataBits = 8
92 else:
93 raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
94
95 if self._parity == PARITY_NONE:
cliechti91d247d2009-07-25 00:42:57 +000096 self._port_handle.Parity = getattr(System.IO.Ports.Parity, 'None') # reserved keyword in Py3k
cliechti0d6029a2008-06-21 01:28:46 +000097 elif self._parity == PARITY_EVEN:
98 self._port_handle.Parity = System.IO.Ports.Parity.Even
99 elif self._parity == PARITY_ODD:
100 self._port_handle.Parity = System.IO.Ports.Parity.Odd
101 elif self._parity == PARITY_MARK:
102 self._port_handle.Parity = System.IO.Ports.Parity.Mark
103 elif self._parity == PARITY_SPACE:
104 self._port_handle.Parity = System.IO.Ports.Parity.Space
105 else:
106 raise ValueError("Unsupported parity mode: %r" % self._parity)
107
108 if self._stopbits == STOPBITS_ONE:
109 self._port_handle.StopBits = System.IO.Ports.StopBits.One
cliechti58b481c2009-02-16 20:42:32 +0000110 elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
111 self._port_handle.StopBits = System.IO.Ports.StopBits.OnePointFive
cliechti0d6029a2008-06-21 01:28:46 +0000112 elif self._stopbits == STOPBITS_TWO:
113 self._port_handle.StopBits = System.IO.Ports.StopBits.Two
114 else:
115 raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
cliechti58b481c2009-02-16 20:42:32 +0000116
cliechti0d6029a2008-06-21 01:28:46 +0000117 if self._rtscts and self._xonxoff:
118 self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff
119 elif self._rtscts:
120 self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSend
121 elif self._xonxoff:
122 self._port_handle.Handshake = System.IO.Ports.Handshake.XOnXOff
123 else:
cliechti91d247d2009-07-25 00:42:57 +0000124 self._port_handle.Handshake = getattr(System.IO.Ports.Handshake, 'None') # reserved keyword in Py3k
cliechti0d6029a2008-06-21 01:28:46 +0000125
126 #~ def __del__(self):
127 #~ self.close()
128
129 def close(self):
130 """Close port"""
131 if self._isOpen:
132 if self._port_handle:
133 try:
cliechtiff0c3792008-06-22 01:01:21 +0000134 self._port_handle.Close()
cliechti0d6029a2008-06-21 01:28:46 +0000135 except System.IO.Ports.InvalidOperationException:
136 # ignore errors. can happen for unplugged USB serial devices
137 pass
138 self._port_handle = None
139 self._isOpen = False
140
141 def makeDeviceName(self, port):
cliechtic53a8ca2008-06-24 11:57:32 +0000142 try:
143 return device(port)
144 except TypeError, e:
145 raise SerialException(str(e))
cliechti0d6029a2008-06-21 01:28:46 +0000146
147 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti58b481c2009-02-16 20:42:32 +0000148
cliechti0d6029a2008-06-21 01:28:46 +0000149 def inWaiting(self):
150 """Return the number of characters currently in the input buffer."""
151 if not self._port_handle: raise portNotOpenError
152 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 """
cliechti0d6029a2008-06-21 01:28:46 +0000160 if not self._port_handle: raise portNotOpenError
cliechti4a567a02009-07-27 22:09:31 +0000161 # must use single byte reads as this is the only way to read
162 # without applying encodings
163 data = bytearray()
cliechti0d6029a2008-06-21 01:28:46 +0000164 while size:
cliechtiff0c3792008-06-22 01:01:21 +0000165 try:
cliechti4a567a02009-07-27 22:09:31 +0000166 data.append(self._port_handle.ReadByte())
cliechtiff0c3792008-06-22 01:01:21 +0000167 except System.TimeoutException, e:
168 break
169 else:
170 size -= 1
cliechti4a567a02009-07-27 22:09:31 +0000171 return bytes(data)
cliechti0d6029a2008-06-21 01:28:46 +0000172
cliechti4a567a02009-07-27 22:09:31 +0000173 def write(self, data):
cliechti0d6029a2008-06-21 01:28:46 +0000174 """Output the given string over the serial port."""
175 if not self._port_handle: 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))
cliechtiff0c3792008-06-22 01:01:21 +0000182 except System.TimeoutException, e:
183 raise writeTimeoutError
cliechtif81362e2009-07-25 03:44:33 +0000184 return len(data)
cliechti0d6029a2008-06-21 01:28:46 +0000185
186 def flushInput(self):
187 """Clear input buffer, discarding all that is in the buffer."""
188 if not self._port_handle: raise portNotOpenError
189 self._port_handle.DiscardInBuffer()
190
191 def flushOutput(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 """
cliechti0d6029a2008-06-21 01:28:46 +0000196 if not self._port_handle: raise portNotOpenError
197 self._port_handle.DiscardOutBuffer()
198
199 def sendBreak(self, duration=0.25):
cliechti00df9702014-08-04 10:12:48 +0000200 """\
201 Send break condition. Timed, returns to idle state after given
202 duration.
203 """
cliechti0d6029a2008-06-21 01:28:46 +0000204 if not self._port_handle: raise portNotOpenError
205 import time
206 self._port_handle.BreakState = True
207 time.sleep(duration)
208 self._port_handle.BreakState = False
209
cliechtiff0c3792008-06-22 01:01:21 +0000210 def setBreak(self, level=True):
cliechti00df9702014-08-04 10:12:48 +0000211 """
212 Set break: Controls TXD. When active, to transmitting is possible.
213 """
cliechti0d6029a2008-06-21 01:28:46 +0000214 if not self._port_handle: raise portNotOpenError
cliechtiff0c3792008-06-22 01:01:21 +0000215 self._port_handle.BreakState = bool(level)
cliechti0d6029a2008-06-21 01:28:46 +0000216
cliechtiff0c3792008-06-22 01:01:21 +0000217 def setRTS(self, level=True):
cliechti0d6029a2008-06-21 01:28:46 +0000218 """Set terminal status line: Request To Send"""
219 if not self._port_handle: raise portNotOpenError
cliechtiff0c3792008-06-22 01:01:21 +0000220 self._port_handle.RtsEnable = bool(level)
cliechti0d6029a2008-06-21 01:28:46 +0000221
cliechtiff0c3792008-06-22 01:01:21 +0000222 def setDTR(self, level=True):
cliechti0d6029a2008-06-21 01:28:46 +0000223 """Set terminal status line: Data Terminal Ready"""
224 if not self._port_handle: raise portNotOpenError
cliechtiff0c3792008-06-22 01:01:21 +0000225 self._port_handle.DtrEnable = bool(level)
cliechti0d6029a2008-06-21 01:28:46 +0000226
227 def getCTS(self):
228 """Read terminal status line: Clear To Send"""
229 if not self._port_handle: raise portNotOpenError
230 return self._port_handle.CtsHolding
231
232 def getDSR(self):
233 """Read terminal status line: Data Set Ready"""
234 if not self._port_handle: raise portNotOpenError
235 return self._port_handle.DsrHolding
236
cliechtiff0c3792008-06-22 01:01:21 +0000237 def getRI(self):
238 """Read terminal status line: Ring Indicator"""
239 if not self._port_handle: raise portNotOpenError
cliechti0d6029a2008-06-21 01:28:46 +0000240 #~ return self._port_handle.XXX
cliechtiff0c3792008-06-22 01:01:21 +0000241 return False #XXX an error would be better
cliechti0d6029a2008-06-21 01:28:46 +0000242
243 def getCD(self):
244 """Read terminal status line: Carrier Detect"""
245 if not self._port_handle: raise portNotOpenError
246 return self._port_handle.CDHolding
247
248 # - - platform specific - - - -
cliechtif81362e2009-07-25 03:44:33 +0000249 # none
250
251
cliechti4a567a02009-07-27 22:09:31 +0000252# assemble Serial class with the platform specific implementation and the base
253# for file-like behavior. for Python 2.6 and newer, that provide the new I/O
254# library, derive from io.RawIOBase
255try:
256 import io
257except ImportError:
258 # classic version with our own file-like emulation
259 class Serial(IronSerial, FileLike):
260 pass
261else:
262 # io library present
263 class Serial(IronSerial, io.RawIOBase):
cliechtif81362e2009-07-25 03:44:33 +0000264 pass
265
cliechti0d6029a2008-06-21 01:28:46 +0000266
cliechti4a567a02009-07-27 22:09:31 +0000267# Nur Testfunktion!!
cliechti0d6029a2008-06-21 01:28:46 +0000268if __name__ == '__main__':
cliechti7aaead32009-07-23 14:02:41 +0000269 import sys
270
cliechti0d6029a2008-06-21 01:28:46 +0000271 s = Serial(0)
cliechti7aaead32009-07-23 14:02:41 +0000272 sys.stdio.write('%s\n' % s)
273
cliechti0d6029a2008-06-21 01:28:46 +0000274 s = Serial()
cliechti7aaead32009-07-23 14:02:41 +0000275 sys.stdio.write('%s\n' % s)
276
277
cliechti0d6029a2008-06-21 01:28:46 +0000278 s.baudrate = 19200
279 s.databits = 7
280 s.close()
281 s.port = 0
282 s.open()
cliechti7aaead32009-07-23 14:02:41 +0000283 sys.stdio.write('%s\n' % s)
cliechti0d6029a2008-06-21 01:28:46 +0000284