1# Copyright (c) Twisted Matrix Laboratories. 2# See LICENSE for details. 3 4""" 5Serial port support for Windows. 6 7Requires PySerial and pywin32. 8""" 9 10# system imports 11import serial 12from serial import PARITY_NONE, PARITY_EVEN, PARITY_ODD 13from serial import STOPBITS_ONE, STOPBITS_TWO 14from serial import FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS 15import win32file, win32event 16 17# twisted imports 18from twisted.internet import abstract 19 20# sibling imports 21from serialport import BaseSerialPort 22 23 24class SerialPort(BaseSerialPort, abstract.FileDescriptor): 25 """A serial device, acting as a transport, that uses a win32 event.""" 26 27 connected = 1 28 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) 36 self.flushInput() 37 self.flushOutput() 38 self.reactor = reactor 39 self.protocol = protocol 40 self.outQueue = [] 41 self.closed = 0 42 self.closedNotifies = 0 43 self.writeInProgress = 0 44 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) 50 51 self.reactor.addEvent(self._overlappedRead.hEvent, self, 'serialReadEvent') 52 self.reactor.addEvent(self._overlappedWrite.hEvent, self, 'serialWriteEvent') 53 54 self.protocol.makeConnection(self) 55 self._finishPortSetup() 56 57 58 def _finishPortSetup(self): 59 """ 60 Finish setting up the serial port. 61 62 This is a separate method to facilitate testing. 63 """ 64 flags, comstat = win32file.ClearCommError(self._serial.hComPort) 65 rc, self.read_buf = win32file.ReadFile(self._serial.hComPort, 66 win32file.AllocateReadBuffer(1), 67 self._overlappedRead) 68 69 70 def serialReadEvent(self): 71 #get that character we set up 72 n = win32file.GetOverlappedResult(self._serial.hComPort, self._overlappedRead, 0) 73 if n: 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) 77 if comstat.cbInQue: 78 win32event.ResetEvent(self._overlappedRead.hEvent) 79 rc, buf = win32file.ReadFile(self._serial.hComPort, 80 win32file.AllocateReadBuffer(comstat.cbInQue), 81 self._overlappedRead) 82 n = win32file.GetOverlappedResult(self._serial.hComPort, self._overlappedRead, 1) 83 #handle all the received data: 84 self.protocol.dataReceived(first + str(buf[:n])) 85 else: 86 #handle all the received data: 87 self.protocol.dataReceived(first) 88 89 #set up next one 90 win32event.ResetEvent(self._overlappedRead.hEvent) 91 rc, self.read_buf = win32file.ReadFile(self._serial.hComPort, 92 win32file.AllocateReadBuffer(1), 93 self._overlappedRead) 94 95 96 def write(self, data): 97 if data: 98 if self.writeInProgress: 99 self.outQueue.append(data) 100 else: 101 self.writeInProgress = 1 102 win32file.WriteFile(self._serial.hComPort, data, self._overlappedWrite) 103 104 105 def serialWriteEvent(self): 106 try: 107 dataToWrite = self.outQueue.pop(0) 108 except IndexError: 109 self.writeInProgress = 0 110 return 111 else: 112 win32file.WriteFile(self._serial.hComPort, dataToWrite, self._overlappedWrite) 113 114 115 def connectionLost(self, reason): 116 """ 117 Called when the serial port disconnects. 118 119 Will call C{connectionLost} on the protocol that is handling the 120 serial data. 121 """ 122 self.reactor.removeEvent(self._overlappedRead.hEvent) 123 self.reactor.removeEvent(self._overlappedWrite.hEvent) 124 abstract.FileDescriptor.connectionLost(self, reason) 125 self._serial.close() 126 self.protocol.connectionLost(reason) 127