2 # Python Serial Port Extension for Win32, Linux, BSD, Jython and .NET/Mono
3 # serial driver for .NET/Mono (IronPython), .NET >= 2
6 # (C) 2008 Chris Liechti <cliechti@gmx.net>
7 # this is distributed under a free software license, see license.txt
11 import System
.IO
.Ports
12 from serial
.serialutil
import *
16 """Turn a port number into a device name"""
17 return System
.IO
.Ports
.SerialPort
.GetPortNames()[portnum
]
20 # must invoke function with byte array, make a helper to convert strings
22 sab
= System
.Array
[System
.Byte
]
23 def as_byte_array(string
):
24 return sab([ord(x
) for x
in string
]) # XXX will require adaption when run with a 3.x compatible IronPython
26 class IronSerial(SerialBase
):
27 """Serial port implementation for .NET/Mono."""
29 BAUDRATES
= (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
30 9600, 19200, 38400, 57600, 115200)
33 """Open port with current settings. This may throw a SerialException
34 if the port cannot be opened."""
35 if self
._port
is None:
36 raise SerialException("Port must be configured before it can be used.")
38 raise SerialException("Port is already open.")
40 self
._port
_handle
= System
.IO
.Ports
.SerialPort(self
.portstr
)
41 except Exception, msg
:
42 self
._port
_handle
= None
43 raise SerialException("could not open port %s: %s" % (self
.portstr
, msg
))
45 self
._reconfigurePort
()
46 self
._port
_handle
.Open()
54 def _reconfigurePort(self
):
55 """Set communication parameters on opened port."""
56 if not self
._port
_handle
:
57 raise SerialException("Can only operate on a valid port handle")
59 #~ self._port_handle.ReceivedBytesThreshold = 1
61 if self
._timeout
is None:
62 self
._port
_handle
.ReadTimeout
= System
.IO
.Ports
.SerialPort
.InfiniteTimeout
64 self
._port
_handle
.ReadTimeout
= int(self
._timeout
*1000)
66 # if self._timeout != 0 and self._interCharTimeout is not None:
67 # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
69 if self
._writeTimeout
is None:
70 self
._port
_handle
.WriteTimeout
= System
.IO
.Ports
.SerialPort
.InfiniteTimeout
72 self
._port
_handle
.WriteTimeout
= int(self
._writeTimeout
*1000)
75 # Setup the connection info.
77 self
._port
_handle
.BaudRate
= self
._baudrate
79 # catch errors from illegal baudrate settings
80 raise ValueError(str(e
))
82 if self
._bytesize
== FIVEBITS
:
83 self
._port
_handle
.DataBits
= 5
84 elif self
._bytesize
== SIXBITS
:
85 self
._port
_handle
.DataBits
= 6
86 elif self
._bytesize
== SEVENBITS
:
87 self
._port
_handle
.DataBits
= 7
88 elif self
._bytesize
== EIGHTBITS
:
89 self
._port
_handle
.DataBits
= 8
91 raise ValueError("Unsupported number of data bits: %r" % self
._bytesize
)
93 if self
._parity
== PARITY_NONE
:
94 self
._port
_handle
.Parity
= getattr(System
.IO
.Ports
.Parity
, 'None') # reserved keyword in Py3k
95 elif self
._parity
== PARITY_EVEN
:
96 self
._port
_handle
.Parity
= System
.IO
.Ports
.Parity
.Even
97 elif self
._parity
== PARITY_ODD
:
98 self
._port
_handle
.Parity
= System
.IO
.Ports
.Parity
.Odd
99 elif self
._parity
== PARITY_MARK
:
100 self
._port
_handle
.Parity
= System
.IO
.Ports
.Parity
.Mark
101 elif self
._parity
== PARITY_SPACE
:
102 self
._port
_handle
.Parity
= System
.IO
.Ports
.Parity
.Space
104 raise ValueError("Unsupported parity mode: %r" % self
._parity
)
106 if self
._stopbits
== STOPBITS_ONE
:
107 self
._port
_handle
.StopBits
= System
.IO
.Ports
.StopBits
.One
108 elif self
._stopbits
== STOPBITS_ONE_POINT_FIVE
:
109 self
._port
_handle
.StopBits
= System
.IO
.Ports
.StopBits
.OnePointFive
110 elif self
._stopbits
== STOPBITS_TWO
:
111 self
._port
_handle
.StopBits
= System
.IO
.Ports
.StopBits
.Two
113 raise ValueError("Unsupported number of stop bits: %r" % self
._stopbits
)
115 if self
._rtscts
and self
._xonxoff
:
116 self
._port
_handle
.Handshake
= System
.IO
.Ports
.Handshake
.RequestToSendXOnXOff
118 self
._port
_handle
.Handshake
= System
.IO
.Ports
.Handshake
.RequestToSend
120 self
._port
_handle
.Handshake
= System
.IO
.Ports
.Handshake
.XOnXOff
122 self
._port
_handle
.Handshake
= getattr(System
.IO
.Ports
.Handshake
, 'None') # reserved keyword in Py3k
124 #~ def __del__(self):
130 if self
._port
_handle
:
132 self
._port
_handle
.Close()
133 except System
.IO
.Ports
.InvalidOperationException
:
134 # ignore errors. can happen for unplugged USB serial devices
136 self
._port
_handle
= None
139 def makeDeviceName(self
, port
):
143 raise SerialException(str(e
))
145 # - - - - - - - - - - - - - - - - - - - - - - - -
148 """Return the number of characters currently in the input buffer."""
149 if not self
._port
_handle
: raise portNotOpenError
150 return self
._port
_handle
.BytesToRead
152 def read(self
, size
=1):
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 if not self
._port
_handle
: raise portNotOpenError
157 # must use single byte reads as this is the only way to read
158 # without applying encodings
162 data
.append(self
._port
_handle
.ReadByte())
163 except System
.TimeoutException
, e
:
169 def write(self
, data
):
170 """Output the given string over the serial port."""
171 if not self
._port
_handle
: raise portNotOpenError
172 if not isinstance(data
, (bytes
, bytearray
)):
173 raise TypeError('expected %s or bytearray, got %s' % (bytes
, type(data
)))
175 # must call overloaded method with byte array argument
176 # as this is the only one not applying encodings
177 self
._port
_handle
.Write(as_byte_array(data
), 0, len(data
))
178 except System
.TimeoutException
, e
:
179 raise writeTimeoutError
182 def flushInput(self
):
183 """Clear input buffer, discarding all that is in the buffer."""
184 if not self
._port
_handle
: raise portNotOpenError
185 self
._port
_handle
.DiscardInBuffer()
187 def flushOutput(self
):
188 """Clear output buffer, aborting the current output and
189 discarding all that is in the buffer."""
190 if not self
._port
_handle
: raise portNotOpenError
191 self
._port
_handle
.DiscardOutBuffer()
193 def sendBreak(self
, duration
=0.25):
194 """Send break condition. Timed, returns to idle state after given duration."""
195 if not self
._port
_handle
: raise portNotOpenError
197 self
._port
_handle
.BreakState
= True
199 self
._port
_handle
.BreakState
= False
201 def setBreak(self
, level
=True):
202 """Set break: Controls TXD. When active, to transmitting is possible."""
203 if not self
._port
_handle
: raise portNotOpenError
204 self
._port
_handle
.BreakState
= bool(level
)
206 def setRTS(self
, level
=True):
207 """Set terminal status line: Request To Send"""
208 if not self
._port
_handle
: raise portNotOpenError
209 self
._port
_handle
.RtsEnable
= bool(level
)
211 def setDTR(self
, level
=True):
212 """Set terminal status line: Data Terminal Ready"""
213 if not self
._port
_handle
: raise portNotOpenError
214 self
._port
_handle
.DtrEnable
= bool(level
)
217 """Read terminal status line: Clear To Send"""
218 if not self
._port
_handle
: raise portNotOpenError
219 return self
._port
_handle
.CtsHolding
222 """Read terminal status line: Data Set Ready"""
223 if not self
._port
_handle
: raise portNotOpenError
224 return self
._port
_handle
.DsrHolding
227 """Read terminal status line: Ring Indicator"""
228 if not self
._port
_handle
: raise portNotOpenError
229 #~ return self._port_handle.XXX
230 return False #XXX an error would be better
233 """Read terminal status line: Carrier Detect"""
234 if not self
._port
_handle
: raise portNotOpenError
235 return self
._port
_handle
.CDHolding
237 # - - platform specific - - - -
241 # assemble Serial class with the platform specific implementation and the base
242 # for file-like behavior. for Python 2.6 and newer, that provide the new I/O
243 # library, derive from io.RawIOBase
247 # classic version with our own file-like emulation
248 class Serial(IronSerial
, FileLike
):
252 class Serial(IronSerial
, io
.RawIOBase
):
257 if __name__
== '__main__':
261 sys
.stdio
.write('%s\n' % s
)
264 sys
.stdio
.write('%s\n' % s
)
272 sys
.stdio
.write('%s\n' % s
)