_win32serialport.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. # -*- test-case-name: twisted.internet.test.test_win32serialport -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. Serial port support for Windows.
  6. Requires PySerial and pywin32.
  7. """
  8. import win32event
  9. import win32file
  10. # system imports
  11. from serial import EIGHTBITS, PARITY_NONE, STOPBITS_ONE
  12. from serial.serialutil import to_bytes
  13. # twisted imports
  14. from twisted.internet import abstract
  15. # sibling imports
  16. from twisted.internet.serialport import BaseSerialPort
  17. class SerialPort(BaseSerialPort, abstract.FileDescriptor):
  18. """A serial device, acting as a transport, that uses a win32 event."""
  19. connected = 1
  20. def __init__(
  21. self,
  22. protocol,
  23. deviceNameOrPortNumber,
  24. reactor,
  25. baudrate=9600,
  26. bytesize=EIGHTBITS,
  27. parity=PARITY_NONE,
  28. stopbits=STOPBITS_ONE,
  29. xonxoff=0,
  30. rtscts=0,
  31. ):
  32. self._serial = self._serialFactory(
  33. deviceNameOrPortNumber,
  34. baudrate=baudrate,
  35. bytesize=bytesize,
  36. parity=parity,
  37. stopbits=stopbits,
  38. timeout=None,
  39. xonxoff=xonxoff,
  40. rtscts=rtscts,
  41. )
  42. self.flushInput()
  43. self.flushOutput()
  44. self.reactor = reactor
  45. self.protocol = protocol
  46. self.outQueue = []
  47. self.closed = 0
  48. self.closedNotifies = 0
  49. self.writeInProgress = 0
  50. self.protocol = protocol
  51. self._overlappedRead = win32file.OVERLAPPED()
  52. self._overlappedRead.hEvent = win32event.CreateEvent(None, 1, 0, None)
  53. self._overlappedWrite = win32file.OVERLAPPED()
  54. self._overlappedWrite.hEvent = win32event.CreateEvent(None, 0, 0, None)
  55. self.reactor.addEvent(self._overlappedRead.hEvent, self, "serialReadEvent")
  56. self.reactor.addEvent(self._overlappedWrite.hEvent, self, "serialWriteEvent")
  57. self.protocol.makeConnection(self)
  58. self._finishPortSetup()
  59. def _finishPortSetup(self):
  60. """
  61. Finish setting up the serial port.
  62. This is a separate method to facilitate testing.
  63. """
  64. flags, comstat = self._clearCommError()
  65. rc, self.read_buf = win32file.ReadFile(
  66. self._serial._port_handle,
  67. win32file.AllocateReadBuffer(1),
  68. self._overlappedRead,
  69. )
  70. def _clearCommError(self):
  71. return win32file.ClearCommError(self._serial._port_handle)
  72. def serialReadEvent(self):
  73. # get that character we set up
  74. n = win32file.GetOverlappedResult(
  75. self._serial._port_handle, self._overlappedRead, 0
  76. )
  77. first = to_bytes(self.read_buf[:n])
  78. # now we should get everything that is already in the buffer
  79. flags, comstat = self._clearCommError()
  80. if comstat.cbInQue:
  81. win32event.ResetEvent(self._overlappedRead.hEvent)
  82. rc, buf = win32file.ReadFile(
  83. self._serial._port_handle,
  84. win32file.AllocateReadBuffer(comstat.cbInQue),
  85. self._overlappedRead,
  86. )
  87. n = win32file.GetOverlappedResult(
  88. self._serial._port_handle, self._overlappedRead, 1
  89. )
  90. # handle all the received data:
  91. self.protocol.dataReceived(first + to_bytes(buf[:n]))
  92. else:
  93. # handle all the received data:
  94. self.protocol.dataReceived(first)
  95. # set up next one
  96. win32event.ResetEvent(self._overlappedRead.hEvent)
  97. rc, self.read_buf = win32file.ReadFile(
  98. self._serial._port_handle,
  99. win32file.AllocateReadBuffer(1),
  100. self._overlappedRead,
  101. )
  102. def write(self, data):
  103. if data:
  104. if self.writeInProgress:
  105. self.outQueue.append(data)
  106. else:
  107. self.writeInProgress = 1
  108. win32file.WriteFile(
  109. self._serial._port_handle, data, self._overlappedWrite
  110. )
  111. def serialWriteEvent(self):
  112. try:
  113. dataToWrite = self.outQueue.pop(0)
  114. except IndexError:
  115. self.writeInProgress = 0
  116. return
  117. else:
  118. win32file.WriteFile(
  119. self._serial._port_handle, dataToWrite, self._overlappedWrite
  120. )
  121. def connectionLost(self, reason):
  122. """
  123. Called when the serial port disconnects.
  124. Will call C{connectionLost} on the protocol that is handling the
  125. serial data.
  126. """
  127. self.reactor.removeEvent(self._overlappedRead.hEvent)
  128. self.reactor.removeEvent(self._overlappedWrite.hEvent)
  129. abstract.FileDescriptor.connectionLost(self, reason)
  130. self._serial.close()
  131. self.protocol.connectionLost(reason)