1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 Serial port support for Windows.
7 Requires PySerial and pywin32.
12 from serial import PARITY_NONE, PARITY_EVEN, PARITY_ODD
13 from serial import STOPBITS_ONE, STOPBITS_TWO
14 from serial import FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS
15 import win32file, win32event
18 from twisted.internet import abstract
21 from serialport import BaseSerialPort
24 class SerialPort(BaseSerialPort, abstract.FileDescriptor):
25 """A serial device, acting as a transport, that uses a win32 event."""
29 def __init__(self, protocol, deviceNameOrPortNumber, reactor,
30 baudrate = 9600, bytesize = EIGHTBITS, parity = PARITY_NONE,
31 stopbits = STOPBITS_ONE, xonxoff = 0, rtscts = 0):
32 self._serial = self._serialFactory(
33 deviceNameOrPortNumber, baudrate=baudrate, bytesize=bytesize,
34 parity=parity, stopbits=stopbits, timeout=None,
35 xonxoff=xonxoff, rtscts=rtscts)
38 self.reactor = reactor
39 self.protocol = protocol
42 self.closedNotifies = 0
43 self.writeInProgress = 0
45 self.protocol = protocol
46 self._overlappedRead = win32file.OVERLAPPED()
47 self._overlappedRead.hEvent = win32event.CreateEvent(None, 1, 0, None)
48 self._overlappedWrite = win32file.OVERLAPPED()
49 self._overlappedWrite.hEvent = win32event.CreateEvent(None, 0, 0, None)
51 self.reactor.addEvent(self._overlappedRead.hEvent, self, 'serialReadEvent')
52 self.reactor.addEvent(self._overlappedWrite.hEvent, self, 'serialWriteEvent')
54 self.protocol.makeConnection(self)
55 self._finishPortSetup()
58 def _finishPortSetup(self):
60 Finish setting up the serial port.
62 This is a separate method to facilitate testing.
64 flags, comstat = win32file.ClearCommError(self._serial.hComPort)
65 rc, self.read_buf = win32file.ReadFile(self._serial.hComPort,
66 win32file.AllocateReadBuffer(1),
70 def serialReadEvent(self):
71 #get that character we set up
72 n = win32file.GetOverlappedResult(self._serial.hComPort, self._overlappedRead, 0)
74 first = str(self.read_buf[:n])
75 #now we should get everything that is already in the buffer
76 flags, comstat = win32file.ClearCommError(self._serial.hComPort)
78 win32event.ResetEvent(self._overlappedRead.hEvent)
79 rc, buf = win32file.ReadFile(self._serial.hComPort,
80 win32file.AllocateReadBuffer(comstat.cbInQue),
82 n = win32file.GetOverlappedResult(self._serial.hComPort, self._overlappedRead, 1)
83 #handle all the received data:
84 self.protocol.dataReceived(first + str(buf[:n]))
86 #handle all the received data:
87 self.protocol.dataReceived(first)
90 win32event.ResetEvent(self._overlappedRead.hEvent)
91 rc, self.read_buf = win32file.ReadFile(self._serial.hComPort,
92 win32file.AllocateReadBuffer(1),
96 def write(self, data):
98 if self.writeInProgress:
99 self.outQueue.append(data)
101 self.writeInProgress = 1
102 win32file.WriteFile(self._serial.hComPort, data, self._overlappedWrite)
105 def serialWriteEvent(self):
107 dataToWrite = self.outQueue.pop(0)
109 self.writeInProgress = 0
112 win32file.WriteFile(self._serial.hComPort, dataToWrite, self._overlappedWrite)
115 def connectionLost(self, reason):
117 Called when the serial port disconnects.
119 Will call C{connectionLost} on the protocol that is handling the
122 self.reactor.removeEvent(self._overlappedRead.hEvent)
123 self.reactor.removeEvent(self._overlappedWrite.hEvent)
124 abstract.FileDescriptor.connectionLost(self, reason)
126 self.protocol.connectionLost(reason)