serialcli.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #! python
  2. # 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
  5. #
  6. # (C) 2008 Chris Liechti <cliechti@gmx.net>
  7. # this is distributed under a free software license, see license.txt
  8. import clr
  9. import System
  10. import System.IO.Ports
  11. from serial.serialutil import *
  12. def device(portnum):
  13. """Turn a port number into a device name"""
  14. return System.IO.Ports.SerialPort.GetPortNames()[portnum]
  15. # must invoke function with byte array, make a helper to convert strings
  16. # to byte arrays
  17. sab = System.Array[System.Byte]
  18. def as_byte_array(string):
  19. return sab([ord(x) for x in string]) # XXX will require adaption when run with a 3.x compatible IronPython
  20. class IronSerial(SerialBase):
  21. """Serial port implementation for .NET/Mono."""
  22. BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
  23. 9600, 19200, 38400, 57600, 115200)
  24. def open(self):
  25. """Open port with current settings. This may throw a SerialException
  26. if the port cannot be opened."""
  27. if self._port is None:
  28. raise SerialException("Port must be configured before it can be used.")
  29. if self._isOpen:
  30. raise SerialException("Port is already open.")
  31. try:
  32. self._port_handle = System.IO.Ports.SerialPort(self.portstr)
  33. except Exception, msg:
  34. self._port_handle = None
  35. raise SerialException("could not open port %s: %s" % (self.portstr, msg))
  36. self._reconfigurePort()
  37. self._port_handle.Open()
  38. self._isOpen = True
  39. if not self._rtscts:
  40. self.setRTS(True)
  41. self.setDTR(True)
  42. self.flushInput()
  43. self.flushOutput()
  44. def _reconfigurePort(self):
  45. """Set communication parameters on opened port."""
  46. if not self._port_handle:
  47. raise SerialException("Can only operate on a valid port handle")
  48. #~ self._port_handle.ReceivedBytesThreshold = 1
  49. if self._timeout is None:
  50. self._port_handle.ReadTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
  51. else:
  52. self._port_handle.ReadTimeout = int(self._timeout*1000)
  53. # if self._timeout != 0 and self._interCharTimeout is not None:
  54. # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
  55. if self._writeTimeout is None:
  56. self._port_handle.WriteTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
  57. else:
  58. self._port_handle.WriteTimeout = int(self._writeTimeout*1000)
  59. # Setup the connection info.
  60. try:
  61. self._port_handle.BaudRate = self._baudrate
  62. except IOError, e:
  63. # catch errors from illegal baudrate settings
  64. raise ValueError(str(e))
  65. if self._bytesize == FIVEBITS:
  66. self._port_handle.DataBits = 5
  67. elif self._bytesize == SIXBITS:
  68. self._port_handle.DataBits = 6
  69. elif self._bytesize == SEVENBITS:
  70. self._port_handle.DataBits = 7
  71. elif self._bytesize == EIGHTBITS:
  72. self._port_handle.DataBits = 8
  73. else:
  74. raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
  75. if self._parity == PARITY_NONE:
  76. self._port_handle.Parity = getattr(System.IO.Ports.Parity, 'None') # reserved keyword in Py3k
  77. elif self._parity == PARITY_EVEN:
  78. self._port_handle.Parity = System.IO.Ports.Parity.Even
  79. elif self._parity == PARITY_ODD:
  80. self._port_handle.Parity = System.IO.Ports.Parity.Odd
  81. elif self._parity == PARITY_MARK:
  82. self._port_handle.Parity = System.IO.Ports.Parity.Mark
  83. elif self._parity == PARITY_SPACE:
  84. self._port_handle.Parity = System.IO.Ports.Parity.Space
  85. else:
  86. raise ValueError("Unsupported parity mode: %r" % self._parity)
  87. if self._stopbits == STOPBITS_ONE:
  88. self._port_handle.StopBits = System.IO.Ports.StopBits.One
  89. elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
  90. self._port_handle.StopBits = System.IO.Ports.StopBits.OnePointFive
  91. elif self._stopbits == STOPBITS_TWO:
  92. self._port_handle.StopBits = System.IO.Ports.StopBits.Two
  93. else:
  94. raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
  95. if self._rtscts and self._xonxoff:
  96. self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff
  97. elif self._rtscts:
  98. self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSend
  99. elif self._xonxoff:
  100. self._port_handle.Handshake = System.IO.Ports.Handshake.XOnXOff
  101. else:
  102. self._port_handle.Handshake = getattr(System.IO.Ports.Handshake, 'None') # reserved keyword in Py3k
  103. #~ def __del__(self):
  104. #~ self.close()
  105. def close(self):
  106. """Close port"""
  107. if self._isOpen:
  108. if self._port_handle:
  109. try:
  110. self._port_handle.Close()
  111. except System.IO.Ports.InvalidOperationException:
  112. # ignore errors. can happen for unplugged USB serial devices
  113. pass
  114. self._port_handle = None
  115. self._isOpen = False
  116. def makeDeviceName(self, port):
  117. try:
  118. return device(port)
  119. except TypeError, e:
  120. raise SerialException(str(e))
  121. # - - - - - - - - - - - - - - - - - - - - - - - -
  122. def inWaiting(self):
  123. """Return the number of characters currently in the input buffer."""
  124. if not self._port_handle: raise portNotOpenError
  125. return self._port_handle.BytesToRead
  126. def read(self, size=1):
  127. """Read size bytes from the serial port. If a timeout is set it may
  128. return less characters as requested. With no timeout it will block
  129. until the requested number of bytes is read."""
  130. if not self._port_handle: raise portNotOpenError
  131. # must use single byte reads as this is the only way to read
  132. # without applying encodings
  133. data = bytearray()
  134. while size:
  135. try:
  136. data.append(self._port_handle.ReadByte())
  137. except System.TimeoutException, e:
  138. break
  139. else:
  140. size -= 1
  141. return bytes(data)
  142. def write(self, data):
  143. """Output the given string over the serial port."""
  144. if not self._port_handle: raise portNotOpenError
  145. if not isinstance(data, (bytes, bytearray)):
  146. raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
  147. try:
  148. # must call overloaded method with byte array argument
  149. # as this is the only one not applying encodings
  150. self._port_handle.Write(as_byte_array(data), 0, len(data))
  151. except System.TimeoutException, e:
  152. raise writeTimeoutError
  153. return len(data)
  154. def flushInput(self):
  155. """Clear input buffer, discarding all that is in the buffer."""
  156. if not self._port_handle: raise portNotOpenError
  157. self._port_handle.DiscardInBuffer()
  158. def flushOutput(self):
  159. """Clear output buffer, aborting the current output and
  160. discarding all that is in the buffer."""
  161. if not self._port_handle: raise portNotOpenError
  162. self._port_handle.DiscardOutBuffer()
  163. def sendBreak(self, duration=0.25):
  164. """Send break condition. Timed, returns to idle state after given duration."""
  165. if not self._port_handle: raise portNotOpenError
  166. import time
  167. self._port_handle.BreakState = True
  168. time.sleep(duration)
  169. self._port_handle.BreakState = False
  170. def setBreak(self, level=True):
  171. """Set break: Controls TXD. When active, to transmitting is possible."""
  172. if not self._port_handle: raise portNotOpenError
  173. self._port_handle.BreakState = bool(level)
  174. def setRTS(self, level=True):
  175. """Set terminal status line: Request To Send"""
  176. if not self._port_handle: raise portNotOpenError
  177. self._port_handle.RtsEnable = bool(level)
  178. def setDTR(self, level=True):
  179. """Set terminal status line: Data Terminal Ready"""
  180. if not self._port_handle: raise portNotOpenError
  181. self._port_handle.DtrEnable = bool(level)
  182. def getCTS(self):
  183. """Read terminal status line: Clear To Send"""
  184. if not self._port_handle: raise portNotOpenError
  185. return self._port_handle.CtsHolding
  186. def getDSR(self):
  187. """Read terminal status line: Data Set Ready"""
  188. if not self._port_handle: raise portNotOpenError
  189. return self._port_handle.DsrHolding
  190. def getRI(self):
  191. """Read terminal status line: Ring Indicator"""
  192. if not self._port_handle: raise portNotOpenError
  193. #~ return self._port_handle.XXX
  194. return False #XXX an error would be better
  195. def getCD(self):
  196. """Read terminal status line: Carrier Detect"""
  197. if not self._port_handle: raise portNotOpenError
  198. return self._port_handle.CDHolding
  199. # - - platform specific - - - -
  200. # none
  201. # assemble Serial class with the platform specific implementation and the base
  202. # for file-like behavior. for Python 2.6 and newer, that provide the new I/O
  203. # library, derive from io.RawIOBase
  204. try:
  205. import io
  206. except ImportError:
  207. # classic version with our own file-like emulation
  208. class Serial(IronSerial, FileLike):
  209. pass
  210. else:
  211. # io library present
  212. class Serial(IronSerial, io.RawIOBase):
  213. pass
  214. # Nur Testfunktion!!
  215. if __name__ == '__main__':
  216. import sys
  217. s = Serial(0)
  218. sys.stdio.write('%s\n' % s)
  219. s = Serial()
  220. sys.stdio.write('%s\n' % s)
  221. s.baudrate = 19200
  222. s.databits = 7
  223. s.close()
  224. s.port = 0
  225. s.open()
  226. sys.stdio.write('%s\n' % s)