_win32serialport.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Serial port support for Windows.
  5. Requires PySerial and pywin32.
  6. """
  7. from __future__ import division, absolute_import
  8. # system imports
  9. from serial import PARITY_NONE
  10. from serial import STOPBITS_ONE
  11. from serial import EIGHTBITS
  12. import win32file, win32event
  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__(self, protocol, deviceNameOrPortNumber, reactor,
  21. baudrate = 9600, bytesize = EIGHTBITS, parity = PARITY_NONE,
  22. stopbits = STOPBITS_ONE, xonxoff = 0, rtscts = 0):
  23. self._serial = self._serialFactory(
  24. deviceNameOrPortNumber, baudrate=baudrate, bytesize=bytesize,
  25. parity=parity, stopbits=stopbits, timeout=None,
  26. xonxoff=xonxoff, rtscts=rtscts)
  27. self.flushInput()
  28. self.flushOutput()
  29. self.reactor = reactor
  30. self.protocol = protocol
  31. self.outQueue = []
  32. self.closed = 0
  33. self.closedNotifies = 0
  34. self.writeInProgress = 0
  35. self.protocol = protocol
  36. self._overlappedRead = win32file.OVERLAPPED()
  37. self._overlappedRead.hEvent = win32event.CreateEvent(None, 1, 0, None)
  38. self._overlappedWrite = win32file.OVERLAPPED()
  39. self._overlappedWrite.hEvent = win32event.CreateEvent(None, 0, 0, None)
  40. self.reactor.addEvent(self._overlappedRead.hEvent, self, 'serialReadEvent')
  41. self.reactor.addEvent(self._overlappedWrite.hEvent, self, 'serialWriteEvent')
  42. self.protocol.makeConnection(self)
  43. self._finishPortSetup()
  44. def _finishPortSetup(self):
  45. """
  46. Finish setting up the serial port.
  47. This is a separate method to facilitate testing.
  48. """
  49. flags, comstat = win32file.ClearCommError(self._serial.hComPort)
  50. rc, self.read_buf = win32file.ReadFile(self._serial.hComPort,
  51. win32file.AllocateReadBuffer(1),
  52. self._overlappedRead)
  53. def serialReadEvent(self):
  54. #get that character we set up
  55. n = win32file.GetOverlappedResult(self._serial.hComPort, self._overlappedRead, 0)
  56. if n:
  57. first = str(self.read_buf[:n])
  58. #now we should get everything that is already in the buffer
  59. flags, comstat = win32file.ClearCommError(self._serial.hComPort)
  60. if comstat.cbInQue:
  61. win32event.ResetEvent(self._overlappedRead.hEvent)
  62. rc, buf = win32file.ReadFile(self._serial.hComPort,
  63. win32file.AllocateReadBuffer(comstat.cbInQue),
  64. self._overlappedRead)
  65. n = win32file.GetOverlappedResult(self._serial.hComPort, self._overlappedRead, 1)
  66. #handle all the received data:
  67. self.protocol.dataReceived(first + str(buf[:n]))
  68. else:
  69. #handle all the received data:
  70. self.protocol.dataReceived(first)
  71. #set up next one
  72. win32event.ResetEvent(self._overlappedRead.hEvent)
  73. rc, self.read_buf = win32file.ReadFile(self._serial.hComPort,
  74. win32file.AllocateReadBuffer(1),
  75. self._overlappedRead)
  76. def write(self, data):
  77. if data:
  78. if self.writeInProgress:
  79. self.outQueue.append(data)
  80. else:
  81. self.writeInProgress = 1
  82. win32file.WriteFile(self._serial.hComPort, data, self._overlappedWrite)
  83. def serialWriteEvent(self):
  84. try:
  85. dataToWrite = self.outQueue.pop(0)
  86. except IndexError:
  87. self.writeInProgress = 0
  88. return
  89. else:
  90. win32file.WriteFile(self._serial.hComPort, dataToWrite, self._overlappedWrite)
  91. def connectionLost(self, reason):
  92. """
  93. Called when the serial port disconnects.
  94. Will call C{connectionLost} on the protocol that is handling the
  95. serial data.
  96. """
  97. self.reactor.removeEvent(self._overlappedRead.hEvent)
  98. self.reactor.removeEvent(self._overlappedWrite.hEvent)
  99. abstract.FileDescriptor.connectionLost(self, reason)
  100. self._serial.close()
  101. self.protocol.connectionLost(reason)