2
#Python Serial Port Extension for Win32, Linux, BSD, Jython
3
#serial driver for win32
2
# Python Serial Port Extension for Win32, Linux, BSD, Jython
3
# serial driver for win32
6
#(C) 2001-2003 Chris Liechti <cliechti@gmx.net>
6
# (C) 2001-2009 Chris Liechti <cliechti@gmx.net>
7
7
# this is distributed under a free software license, see license.txt
9
import win32file # The base COM port and file IO functions.
10
import win32event # We use events and the WaitFor[Single|Multiple]Objects functions.
11
import win32con # constants.
9
# Initial patch to use ctypes by Giovanni Bajo <rasky@develer.com>
12
14
from serialutil import *
14
VERSION = "$Revision: 1.40 $".split()[1] #extract CVS version
16
#from winbase.h. these should realy be in win32con
22
17
def device(portnum):
23
18
"""Turn a port number into a device name"""
24
return 'COM%d' % (portnum+1) #numbers are transformed to a string
26
class Serial(SerialBase):
27
"""Serial port implemenation for Win32. This implemenatation requires a
28
win32all installation."""
30
BAUDRATES = (50,75,110,134,150,200,300,600,1200,1800,2400,4800,9600,
31
19200,38400,57600,115200)
19
return 'COM%d' % (portnum+1) # numbers are transformed to a string
22
class Win32Serial(SerialBase):
23
"""Serial port implementation for Win32 based on ctypes."""
25
BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
26
9600, 19200, 38400, 57600, 115200)
28
def __init__(self, *args, **kwargs):
30
SerialBase.__init__(self, *args, **kwargs)
34
33
"""Open port with current settings. This may throw a SerialException
35
34
if the port cannot be opened."""
36
35
if self._port is None:
37
36
raise SerialException("Port must be configured before it can be used.")
37
# the "\\.\COMx" format is required for devices other than COM1-COM8
38
# not all versions of windows seem to support this properly
39
# so that the first few ports are used with the DOS device name
40
self.hComPort = win32file.CreateFile(self.makeDeviceName(self.portstr),
41
win32con.GENERIC_READ | win32con.GENERIC_WRITE,
44
win32con.OPEN_EXISTING,
45
win32con.FILE_FLAG_OVERLAPPED,
47
except Exception, msg:
48
self.hComPort = None #'cause __del__ is called anyway
49
raise SerialException("could not open port %s: %s" % (self.portstr, msg))
42
if port.upper().startswith('COM') and int(port[3:]) > 8:
43
port = '\\\\.\\' + port
45
# for like COMnotanumber
47
self.hComPort = win32.CreateFile(port,
48
win32.GENERIC_READ | win32.GENERIC_WRITE,
52
win32.FILE_ATTRIBUTE_NORMAL | win32.FILE_FLAG_OVERLAPPED,
54
if self.hComPort == win32.INVALID_HANDLE_VALUE:
55
self.hComPort = None # 'cause __del__ is called anyway
56
raise SerialException("could not open port %s: %s" % (self.portstr, ctypes.WinError()))
50
58
# Setup a 4k buffer
51
win32file.SetupComm(self.hComPort, 4096, 4096)
53
#Save original timeout values:
54
self._orgTimeouts = win32file.GetCommTimeouts(self.hComPort)
56
self._rtsState = win32file.RTS_CONTROL_ENABLE
57
self._dtrState = win32file.DTR_CONTROL_ENABLE
59
win32.SetupComm(self.hComPort, 4096, 4096)
61
# Save original timeout values:
62
self._orgTimeouts = win32.COMMTIMEOUTS()
63
win32.GetCommTimeouts(self.hComPort, ctypes.byref(self._orgTimeouts))
65
self._rtsState = win32.RTS_CONTROL_ENABLE
66
self._dtrState = win32.DTR_CONTROL_ENABLE
59
68
self._reconfigurePort()
62
71
# Remove anything that was there
63
win32file.PurgeComm(self.hComPort,
64
win32file.PURGE_TXCLEAR | win32file.PURGE_TXABORT |
65
win32file.PURGE_RXCLEAR | win32file.PURGE_RXABORT)
72
win32.PurgeComm(self.hComPort,
73
win32.PURGE_TXCLEAR | win32.PURGE_TXABORT |
74
win32.PURGE_RXCLEAR | win32.PURGE_RXABORT)
67
self._overlappedRead = win32file.OVERLAPPED()
68
self._overlappedRead.hEvent = win32event.CreateEvent(None, 1, 0, None)
69
self._overlappedWrite = win32file.OVERLAPPED()
70
#~ self._overlappedWrite.hEvent = win32event.CreateEvent(None, 1, 0, None)
71
self._overlappedWrite.hEvent = win32event.CreateEvent(None, 0, 0, None)
76
self._overlappedRead = win32.OVERLAPPED()
77
self._overlappedRead.hEvent = win32.CreateEvent(None, 1, 0, None)
78
self._overlappedWrite = win32.OVERLAPPED()
79
#~ self._overlappedWrite.hEvent = win32.CreateEvent(None, 1, 0, None)
80
self._overlappedWrite.hEvent = win32.CreateEvent(None, 0, 0, None)
72
81
self._isOpen = True
74
83
def _reconfigurePort(self):
75
"""Set commuication parameters on opened port."""
84
"""Set communication parameters on opened port."""
76
85
if not self.hComPort:
77
86
raise SerialException("Can only operate on a valid port handle")
79
#Set Windows timeout values
80
#timeouts is a tuple with the following items:
81
#(ReadIntervalTimeout,ReadTotalTimeoutMultiplier,
82
# ReadTotalTimeoutConstant,WriteTotalTimeoutMultiplier,
83
# WriteTotalTimeoutConstant)
88
# Set Windows timeout values
89
# timeouts is a tuple with the following items:
90
# (ReadIntervalTimeout,ReadTotalTimeoutMultiplier,
91
# ReadTotalTimeoutConstant,WriteTotalTimeoutMultiplier,
92
# WriteTotalTimeoutConstant)
84
93
if self._timeout is None:
85
94
timeouts = (0, 0, 0, 0, 0)
86
95
elif self._timeout == 0:
87
timeouts = (win32con.MAXDWORD, 0, 0, 0, 0)
96
timeouts = (win32.MAXDWORD, 0, 0, 0, 0)
89
98
timeouts = (0, 0, int(self._timeout*1000), 0, 0)
99
if self._timeout != 0 and self._interCharTimeout is not None:
100
timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
90
102
if self._writeTimeout is None:
92
104
elif self._writeTimeout == 0:
93
timeouts = timeouts[:-2] + (0, win32con.MAXDWORD)
105
timeouts = timeouts[:-2] + (0, win32.MAXDWORD)
95
107
timeouts = timeouts[:-2] + (0, int(self._writeTimeout*1000))
96
win32file.SetCommTimeouts(self.hComPort, timeouts)
108
win32.SetCommTimeouts(self.hComPort, ctypes.byref(win32.COMMTIMEOUTS(*timeouts)))
98
win32file.SetCommMask(self.hComPort, win32file.EV_ERR)
110
win32.SetCommMask(self.hComPort, win32.EV_ERR)
100
112
# Setup the connection info.
101
113
# Get state and modify it:
102
comDCB = win32file.GetCommState(self.hComPort)
115
win32.GetCommState(self.hComPort, ctypes.byref(comDCB))
103
116
comDCB.BaudRate = self._baudrate
105
118
if self._bytesize == FIVEBITS:
114
127
raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
116
129
if self._parity == PARITY_NONE:
117
comDCB.Parity = win32file.NOPARITY
118
comDCB.fParity = 0 # Dis/Enable Parity Check
130
comDCB.Parity = win32.NOPARITY
131
comDCB.fParity = 0 # Disable Parity Check
119
132
elif self._parity == PARITY_EVEN:
120
comDCB.Parity = win32file.EVENPARITY
121
comDCB.fParity = 1 # Dis/Enable Parity Check
133
comDCB.Parity = win32.EVENPARITY
134
comDCB.fParity = 1 # Enable Parity Check
122
135
elif self._parity == PARITY_ODD:
123
comDCB.Parity = win32file.ODDPARITY
124
comDCB.fParity = 1 # Dis/Enable Parity Check
136
comDCB.Parity = win32.ODDPARITY
137
comDCB.fParity = 1 # Enable Parity Check
138
elif self._parity == PARITY_MARK:
139
comDCB.Parity = win32.MARKPARITY
140
comDCB.fParity = 1 # Enable Parity Check
141
elif self._parity == PARITY_SPACE:
142
comDCB.Parity = win32.SPACEPARITY
143
comDCB.fParity = 1 # Enable Parity Check
126
145
raise ValueError("Unsupported parity mode: %r" % self._parity)
128
147
if self._stopbits == STOPBITS_ONE:
129
comDCB.StopBits = win32file.ONESTOPBIT
148
comDCB.StopBits = win32.ONESTOPBIT
149
elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
150
comDCB.StopBits = win32.ONE5STOPBITS
130
151
elif self._stopbits == STOPBITS_TWO:
131
comDCB.StopBits = win32file.TWOSTOPBITS
152
comDCB.StopBits = win32.TWOSTOPBITS
133
154
raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
135
156
comDCB.fBinary = 1 # Enable Binary Transmission
136
157
# Char. w/ Parity-Err are replaced with 0xff (if fErrorChar is set to TRUE)
138
comDCB.fRtsControl = win32file.RTS_CONTROL_HANDSHAKE
159
comDCB.fRtsControl = win32.RTS_CONTROL_HANDSHAKE
140
161
comDCB.fRtsControl = self._rtsState
142
comDCB.fDtrControl = win32file.DTR_CONTROL_HANDSHAKE
163
comDCB.fDtrControl = win32.DTR_CONTROL_HANDSHAKE
144
165
comDCB.fDtrControl = self._dtrState
145
166
comDCB.fOutxCtsFlow = self._rtscts
198
211
until the requested number of bytes is read."""
199
212
if not self.hComPort: raise portNotOpenError
201
win32event.ResetEvent(self._overlappedRead.hEvent)
202
flags, comstat = win32file.ClearCommError(self.hComPort)
214
win32.ResetEvent(self._overlappedRead.hEvent)
215
flags = win32.DWORD()
216
comstat = win32.COMSTAT()
217
if not win32.ClearCommError(self.hComPort, ctypes.byref(flags), ctypes.byref(comstat)):
218
raise SerialException('call to ClearCommError failed')
203
219
if self.timeout == 0:
204
220
n = min(comstat.cbInQue, size)
206
rc, buf = win32file.ReadFile(self.hComPort, win32file.AllocateReadBuffer(n), self._overlappedRead)
207
win32event.WaitForSingleObject(self._overlappedRead.hEvent, win32event.INFINITE)
222
buf = ctypes.create_string_buffer(n)
224
err = win32.ReadFile(self.hComPort, buf, n, ctypes.byref(rc), ctypes.byref(self._overlappedRead))
225
if not err and win32.GetLastError() != win32.ERROR_IO_PENDING:
226
raise SerialException("ReadFile failed (%s)" % ctypes.WinError())
227
err = win32.WaitForSingleObject(self._overlappedRead.hEvent, win32.INFINITE)
228
read = buf.raw[:rc.value]
212
rc, buf = win32file.ReadFile(self.hComPort, win32file.AllocateReadBuffer(size), self._overlappedRead)
213
n = win32file.GetOverlappedResult(self.hComPort, self._overlappedRead, 1)
232
buf = ctypes.create_string_buffer(size)
234
err = win32.ReadFile(self.hComPort, buf, size, ctypes.byref(rc), ctypes.byref(self._overlappedRead))
235
if not err and win32.GetLastError() != win32.ERROR_IO_PENDING:
236
raise SerialException("ReadFile failed (%s)" % ctypes.WinError())
237
err = win32.GetOverlappedResult(self.hComPort, ctypes.byref(self._overlappedRead), ctypes.byref(rc), True)
238
read = buf.raw[:rc.value]
219
243
def write(self, data):
220
244
"""Output the given string over the serial port."""
221
245
if not self.hComPort: raise portNotOpenError
222
if not isinstance(data, str):
223
raise TypeError('expected str, got %s' % type(data))
246
#~ if not isinstance(data, (bytes, bytearray)):
247
#~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
248
# convert data (needed in case of memoryview instance: Py 3.1 io lib), ctypes doesn't like memoryview
226
251
#~ win32event.ResetEvent(self._overlappedWrite.hEvent)
227
err, n = win32file.WriteFile(self.hComPort, data, self._overlappedWrite)
228
if err: #will be ERROR_IO_PENDING:
229
# Wait for the write to complete.
230
#~ win32event.WaitForSingleObject(self._overlappedWrite.hEvent, win32event.INFINITE)
231
n = win32file.GetOverlappedResult(self.hComPort, self._overlappedWrite, 1)
233
raise writeTimeoutError
253
err = win32.WriteFile(self.hComPort, data, len(data), ctypes.byref(n), self._overlappedWrite)
254
if not err and win32.GetLastError() != win32.ERROR_IO_PENDING:
255
raise SerialException("WriteFile failed (%s)" % ctypes.WinError())
256
# Wait for the write to complete.
257
#~ win32.WaitForSingleObject(self._overlappedWrite.hEvent, win32.INFINITE)
258
err = win32.GetOverlappedResult(self.hComPort, self._overlappedWrite, ctypes.byref(n), True)
259
if n.value != len(data):
260
raise writeTimeoutError
236
266
def flushInput(self):
237
267
"""Clear input buffer, discarding all that is in the buffer."""
238
268
if not self.hComPort: raise portNotOpenError
239
win32file.PurgeComm(self.hComPort, win32file.PURGE_RXCLEAR | win32file.PURGE_RXABORT)
269
win32.PurgeComm(self.hComPort, win32.PURGE_RXCLEAR | win32.PURGE_RXABORT)
241
271
def flushOutput(self):
242
272
"""Clear output buffer, aborting the current output and
243
273
discarding all that is in the buffer."""
244
274
if not self.hComPort: raise portNotOpenError
245
win32file.PurgeComm(self.hComPort, win32file.PURGE_TXCLEAR | win32file.PURGE_TXABORT)
275
win32.PurgeComm(self.hComPort, win32.PURGE_TXCLEAR | win32.PURGE_TXABORT)
247
277
def sendBreak(self, duration=0.25):
248
"""Send break condition."""
278
"""Send break condition. Timed, returns to idle state after given duration."""
249
279
if not self.hComPort: raise portNotOpenError
251
win32file.SetCommBreak(self.hComPort)
281
win32.SetCommBreak(self.hComPort)
252
282
time.sleep(duration)
253
win32file.ClearCommBreak(self.hComPort)
283
win32.ClearCommBreak(self.hComPort)
285
def setBreak(self, level=1):
286
"""Set break: Controls TXD. When active, to transmitting is possible."""
287
if not self.hComPort: raise portNotOpenError
289
win32.SetCommBreak(self.hComPort)
291
win32.ClearCommBreak(self.hComPort)
255
293
def setRTS(self, level=1):
256
294
"""Set terminal status line: Request To Send"""
257
295
if not self.hComPort: raise portNotOpenError
259
self._rtsState = win32file.RTS_CONTROL_ENABLE
260
win32file.EscapeCommFunction(self.hComPort, win32file.SETRTS)
297
self._rtsState = win32.RTS_CONTROL_ENABLE
298
win32.EscapeCommFunction(self.hComPort, win32.SETRTS)
262
self._rtsState = win32file.RTS_CONTROL_DISABLE
263
win32file.EscapeCommFunction(self.hComPort, win32file.CLRRTS)
300
self._rtsState = win32.RTS_CONTROL_DISABLE
301
win32.EscapeCommFunction(self.hComPort, win32.CLRRTS)
265
303
def setDTR(self, level=1):
266
304
"""Set terminal status line: Data Terminal Ready"""
267
305
if not self.hComPort: raise portNotOpenError
269
self._dtrState = win32file.DTR_CONTROL_ENABLE
270
win32file.EscapeCommFunction(self.hComPort, win32file.SETDTR)
307
self._dtrState = win32.DTR_CONTROL_ENABLE
308
win32.EscapeCommFunction(self.hComPort, win32.SETDTR)
272
self._dtrState = win32file.DTR_CONTROL_DISABLE
273
win32file.EscapeCommFunction(self.hComPort, win32file.CLRDTR)
310
self._dtrState = win32.DTR_CONTROL_DISABLE
311
win32.EscapeCommFunction(self.hComPort, win32.CLRDTR)
313
def _GetCommModemStatus(self):
315
win32.GetCommModemStatus(self.hComPort, ctypes.byref(stat))
275
318
def getCTS(self):
276
319
"""Read terminal status line: Clear To Send"""
277
320
if not self.hComPort: raise portNotOpenError
278
return MS_CTS_ON & win32file.GetCommModemStatus(self.hComPort) != 0
321
return win32.MS_CTS_ON & self._GetCommModemStatus() != 0
280
323
def getDSR(self):
281
324
"""Read terminal status line: Data Set Ready"""
282
325
if not self.hComPort: raise portNotOpenError
283
return MS_DSR_ON & win32file.GetCommModemStatus(self.hComPort) != 0
326
return win32.MS_DSR_ON & self._GetCommModemStatus() != 0
286
329
"""Read terminal status line: Ring Indicator"""
287
330
if not self.hComPort: raise portNotOpenError
288
return MS_RING_ON & win32file.GetCommModemStatus(self.hComPort) != 0
331
return win32.MS_RING_ON & self._GetCommModemStatus() != 0
291
334
"""Read terminal status line: Carrier Detect"""
292
335
if not self.hComPort: raise portNotOpenError
293
return MS_RLSD_ON & win32file.GetCommModemStatus(self.hComPort) != 0
336
return win32.MS_RLSD_ON & self._GetCommModemStatus() != 0
295
338
# - - platform specific - - - -