blob: 54d3e12bc4749b122c79e778501f76b0f99ab1cd [file] [log] [blame]
cliechti89b4af12002-02-12 23:24:41 +00001#! python
Chris Liechti3e02f702015-12-16 23:06:04 +01002#
3# backend for Windows ("win32" incl. 32/64 bit support)
cliechti89b4af12002-02-12 23:24:41 +00004#
Chris Liechti68340d72015-08-03 14:15:48 +02005# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
Chris Liechtifbdd8a02015-08-09 02:37:45 +02006#
Chris Liechti3e02f702015-12-16 23:06:04 +01007# This file is part of pySerial. https://github.com/pyserial/pyserial
Chris Liechtifbdd8a02015-08-09 02:37:45 +02008# SPDX-License-Identifier: BSD-3-Clause
cliechti183d4ae2009-07-23 22:03:51 +00009#
10# Initial patch to use ctypes by Giovanni Bajo <rasky@develer.com>
cliechti89b4af12002-02-12 23:24:41 +000011
Kurt McKee057387c2018-02-07 22:10:38 -060012from __future__ import absolute_import
13
Chris Liechti409e10b2016-02-10 22:40:34 +010014# pylint: disable=invalid-name,too-few-public-methods
cliechti183d4ae2009-07-23 22:03:51 +000015import ctypes
Chris Liechtid240cf52015-08-05 02:57:03 +020016import time
cliechti39cfb7b2011-08-22 00:30:07 +000017from serial import win32
cliechti183d4ae2009-07-23 22:03:51 +000018
Chris Liechti033f17c2015-08-30 21:28:04 +020019import serial
Chris Liechtie99bda32020-09-14 03:59:52 +020020from serial.serialutil import SerialBase, SerialException, to_bytes, PortNotOpenError, SerialTimeoutException
cliechti89b4af12002-02-12 23:24:41 +000021
cliechti4a567a02009-07-27 22:09:31 +000022
Chris Liechtief6b7b42015-08-06 22:19:26 +020023class Serial(SerialBase):
cliechti1e2a6df2009-07-24 02:00:50 +000024 """Serial port implementation for Win32 based on ctypes."""
cliechti89b4af12002-02-12 23:24:41 +000025
cliechti4a567a02009-07-27 22:09:31 +000026 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
27 9600, 19200, 38400, 57600, 115200)
cliechti80a0ed12003-10-03 23:53:42 +000028
cliechti5735a072009-10-26 23:57:48 +000029 def __init__(self, *args, **kwargs):
Chris Liechti3ad62fb2015-08-29 21:53:32 +020030 self._port_handle = None
31 self._overlapped_read = None
32 self._overlapped_write = None
Chris Liechtie509cf22016-01-22 02:20:57 +010033 super(Serial, self).__init__(*args, **kwargs)
cliechti5735a072009-10-26 23:57:48 +000034
cliechtid6bf52c2003-10-01 02:28:12 +000035 def open(self):
cliechti7d448562014-08-03 21:57:45 +000036 """\
37 Open port with current settings. This may throw a SerialException
38 if the port cannot be opened.
39 """
cliechtid6bf52c2003-10-01 02:28:12 +000040 if self._port is None:
41 raise SerialException("Port must be configured before it can be used.")
Chris Liechti3ad62fb2015-08-29 21:53:32 +020042 if self.is_open:
cliechti8f69e702011-03-19 00:22:32 +000043 raise SerialException("Port is already open.")
cliechti8b7cff02008-06-24 12:11:57 +000044 # the "\\.\COMx" format is required for devices other than COM1-COM8
45 # not all versions of windows seem to support this properly
46 # so that the first few ports are used with the DOS device name
Chris Liechtief1fe252015-08-27 23:25:21 +020047 port = self.name
cliechti4a567a02009-07-27 22:09:31 +000048 try:
49 if port.upper().startswith('COM') and int(port[3:]) > 8:
50 port = '\\\\.\\' + port
51 except ValueError:
52 # for like COMnotanumber
53 pass
Chris Liechti033f17c2015-08-30 21:28:04 +020054 self._port_handle = win32.CreateFile(
Chris Liechti9eaa40c2016-02-12 23:32:59 +010055 port,
56 win32.GENERIC_READ | win32.GENERIC_WRITE,
57 0, # exclusive access
58 None, # no security
59 win32.OPEN_EXISTING,
60 win32.FILE_ATTRIBUTE_NORMAL | win32.FILE_FLAG_OVERLAPPED,
61 0)
Chris Liechti3ad62fb2015-08-29 21:53:32 +020062 if self._port_handle == win32.INVALID_HANDLE_VALUE:
63 self._port_handle = None # 'cause __del__ is called anyway
Chris Liechti1f6643d2016-02-16 21:06:52 +010064 raise SerialException("could not open port {!r}: {!r}".format(self.portstr, ctypes.WinError()))
cliechtie37b6a82009-07-24 12:19:50 +000065
cliechti1ae5ab02013-10-11 01:08:02 +000066 try:
Chris Liechti3ad62fb2015-08-29 21:53:32 +020067 self._overlapped_read = win32.OVERLAPPED()
68 self._overlapped_read.hEvent = win32.CreateEvent(None, 1, 0, None)
69 self._overlapped_write = win32.OVERLAPPED()
70 #~ self._overlapped_write.hEvent = win32.CreateEvent(None, 1, 0, None)
71 self._overlapped_write.hEvent = win32.CreateEvent(None, 0, 0, None)
cliechti89b4af12002-02-12 23:24:41 +000072
cliechti1ae5ab02013-10-11 01:08:02 +000073 # Setup a 4k buffer
Chris Liechti3ad62fb2015-08-29 21:53:32 +020074 win32.SetupComm(self._port_handle, 4096, 4096)
cliechti89b4af12002-02-12 23:24:41 +000075
cliechti1ae5ab02013-10-11 01:08:02 +000076 # Save original timeout values:
77 self._orgTimeouts = win32.COMMTIMEOUTS()
Chris Liechti3ad62fb2015-08-29 21:53:32 +020078 win32.GetCommTimeouts(self._port_handle, ctypes.byref(self._orgTimeouts))
cliechtiedfba4e2009-02-07 00:29:47 +000079
Chris Liechti3ad62fb2015-08-29 21:53:32 +020080 self._reconfigure_port()
cliechti89b4af12002-02-12 23:24:41 +000081
cliechti1ae5ab02013-10-11 01:08:02 +000082 # Clear buffers:
83 # Remove anything that was there
Chris Liechti033f17c2015-08-30 21:28:04 +020084 win32.PurgeComm(
Chris Liechti9eaa40c2016-02-12 23:32:59 +010085 self._port_handle,
86 win32.PURGE_TXCLEAR | win32.PURGE_TXABORT |
87 win32.PURGE_RXCLEAR | win32.PURGE_RXABORT)
cliechti1ae5ab02013-10-11 01:08:02 +000088 except:
89 try:
90 self._close()
91 except:
92 # ignore any exception when closing the port
93 # also to keep original exception that happened when setting up
94 pass
Chris Liechti3ad62fb2015-08-29 21:53:32 +020095 self._port_handle = None
cliechti1ae5ab02013-10-11 01:08:02 +000096 raise
97 else:
Chris Liechti3ad62fb2015-08-29 21:53:32 +020098 self.is_open = True
cliechti1ae5ab02013-10-11 01:08:02 +000099
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200100 def _reconfigure_port(self):
cliechticc8d9d22008-07-06 22:42:44 +0000101 """Set communication parameters on opened port."""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200102 if not self._port_handle:
cliechtid6bf52c2003-10-01 02:28:12 +0000103 raise SerialException("Can only operate on a valid port handle")
cliechtiedfba4e2009-02-07 00:29:47 +0000104
105 # Set Windows timeout values
106 # timeouts is a tuple with the following items:
107 # (ReadIntervalTimeout,ReadTotalTimeoutMultiplier,
108 # ReadTotalTimeoutConstant,WriteTotalTimeoutMultiplier,
109 # WriteTotalTimeoutConstant)
Chris Liechticc128012015-11-06 02:34:16 +0100110 timeouts = win32.COMMTIMEOUTS()
cliechtid6bf52c2003-10-01 02:28:12 +0000111 if self._timeout is None:
Chris Liechtie1927242015-11-03 00:38:43 +0100112 pass # default of all zeros is OK
cliechtid6bf52c2003-10-01 02:28:12 +0000113 elif self._timeout == 0:
Chris Liechtie1927242015-11-03 00:38:43 +0100114 timeouts.ReadIntervalTimeout = win32.MAXDWORD
cliechtid6bf52c2003-10-01 02:28:12 +0000115 else:
Chris Liechtie1927242015-11-03 00:38:43 +0100116 timeouts.ReadTotalTimeoutConstant = max(int(self._timeout * 1000), 1)
Chris Liechti518b0d32015-08-30 02:20:39 +0200117 if self._timeout != 0 and self._inter_byte_timeout is not None:
Chris Liechtie1927242015-11-03 00:38:43 +0100118 timeouts.ReadIntervalTimeout = max(int(self._inter_byte_timeout * 1000), 1)
cliechtiedfba4e2009-02-07 00:29:47 +0000119
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200120 if self._write_timeout is None:
cliechti62611612004-04-20 01:55:43 +0000121 pass
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200122 elif self._write_timeout == 0:
Chris Liechtie1927242015-11-03 00:38:43 +0100123 timeouts.WriteTotalTimeoutConstant = win32.MAXDWORD
cliechti62611612004-04-20 01:55:43 +0000124 else:
Chris Liechtie1927242015-11-03 00:38:43 +0100125 timeouts.WriteTotalTimeoutConstant = max(int(self._write_timeout * 1000), 1)
126 win32.SetCommTimeouts(self._port_handle, ctypes.byref(timeouts))
cliechti89b4af12002-02-12 23:24:41 +0000127
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200128 win32.SetCommMask(self._port_handle, win32.EV_ERR)
cliechti89b4af12002-02-12 23:24:41 +0000129
cliechti95c62212002-03-04 22:17:53 +0000130 # Setup the connection info.
131 # Get state and modify it:
cliechti183d4ae2009-07-23 22:03:51 +0000132 comDCB = win32.DCB()
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200133 win32.GetCommState(self._port_handle, ctypes.byref(comDCB))
cliechtid6bf52c2003-10-01 02:28:12 +0000134 comDCB.BaudRate = self._baudrate
135
Chris Liechti033f17c2015-08-30 21:28:04 +0200136 if self._bytesize == serial.FIVEBITS:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200137 comDCB.ByteSize = 5
Chris Liechti033f17c2015-08-30 21:28:04 +0200138 elif self._bytesize == serial.SIXBITS:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200139 comDCB.ByteSize = 6
Chris Liechti033f17c2015-08-30 21:28:04 +0200140 elif self._bytesize == serial.SEVENBITS:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200141 comDCB.ByteSize = 7
Chris Liechti033f17c2015-08-30 21:28:04 +0200142 elif self._bytesize == serial.EIGHTBITS:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200143 comDCB.ByteSize = 8
cliechtid6bf52c2003-10-01 02:28:12 +0000144 else:
Chris Liechti1f6643d2016-02-16 21:06:52 +0100145 raise ValueError("Unsupported number of data bits: {!r}".format(self._bytesize))
cliechtid6bf52c2003-10-01 02:28:12 +0000146
Chris Liechti033f17c2015-08-30 21:28:04 +0200147 if self._parity == serial.PARITY_NONE:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200148 comDCB.Parity = win32.NOPARITY
Chris Liechti033f17c2015-08-30 21:28:04 +0200149 comDCB.fParity = 0 # Disable Parity Check
150 elif self._parity == serial.PARITY_EVEN:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200151 comDCB.Parity = win32.EVENPARITY
Chris Liechti033f17c2015-08-30 21:28:04 +0200152 comDCB.fParity = 1 # Enable Parity Check
153 elif self._parity == serial.PARITY_ODD:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200154 comDCB.Parity = win32.ODDPARITY
Chris Liechti033f17c2015-08-30 21:28:04 +0200155 comDCB.fParity = 1 # Enable Parity Check
156 elif self._parity == serial.PARITY_MARK:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200157 comDCB.Parity = win32.MARKPARITY
Chris Liechti033f17c2015-08-30 21:28:04 +0200158 comDCB.fParity = 1 # Enable Parity Check
159 elif self._parity == serial.PARITY_SPACE:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200160 comDCB.Parity = win32.SPACEPARITY
Chris Liechti033f17c2015-08-30 21:28:04 +0200161 comDCB.fParity = 1 # Enable Parity Check
cliechtid6bf52c2003-10-01 02:28:12 +0000162 else:
Chris Liechti1f6643d2016-02-16 21:06:52 +0100163 raise ValueError("Unsupported parity mode: {!r}".format(self._parity))
cliechtid6bf52c2003-10-01 02:28:12 +0000164
Chris Liechti033f17c2015-08-30 21:28:04 +0200165 if self._stopbits == serial.STOPBITS_ONE:
166 comDCB.StopBits = win32.ONESTOPBIT
167 elif self._stopbits == serial.STOPBITS_ONE_POINT_FIVE:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200168 comDCB.StopBits = win32.ONE5STOPBITS
Chris Liechti033f17c2015-08-30 21:28:04 +0200169 elif self._stopbits == serial.STOPBITS_TWO:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200170 comDCB.StopBits = win32.TWOSTOPBITS
cliechtid6bf52c2003-10-01 02:28:12 +0000171 else:
Chris Liechti1f6643d2016-02-16 21:06:52 +0100172 raise ValueError("Unsupported number of stop bits: {!r}".format(self._stopbits))
cliechtiedfba4e2009-02-07 00:29:47 +0000173
Chris Liechti033f17c2015-08-30 21:28:04 +0200174 comDCB.fBinary = 1 # Enable Binary Transmission
cliechtid6bf52c2003-10-01 02:28:12 +0000175 # Char. w/ Parity-Err are replaced with 0xff (if fErrorChar is set to TRUE)
Chris Liechti33f0ec52015-08-06 16:37:21 +0200176 if self._rs485_mode is None:
177 if self._rtscts:
178 comDCB.fRtsControl = win32.RTS_CONTROL_HANDSHAKE
179 else:
Chris Liechtief1fe252015-08-27 23:25:21 +0200180 comDCB.fRtsControl = win32.RTS_CONTROL_ENABLE if self._rts_state else win32.RTS_CONTROL_DISABLE
Chris Liechti33f0ec52015-08-06 16:37:21 +0200181 comDCB.fOutxCtsFlow = self._rtscts
cliechtid6bf52c2003-10-01 02:28:12 +0000182 else:
Chris Liechti33f0ec52015-08-06 16:37:21 +0200183 # checks for unsupported settings
184 # XXX verify if platform really does not have a setting for those
185 if not self._rs485_mode.rts_level_for_tx:
186 raise ValueError(
Chris Liechti1f6643d2016-02-16 21:06:52 +0100187 'Unsupported value for RS485Settings.rts_level_for_tx: {!r}'.format(
188 self._rs485_mode.rts_level_for_tx,))
Chris Liechti33f0ec52015-08-06 16:37:21 +0200189 if self._rs485_mode.rts_level_for_rx:
190 raise ValueError(
Chris Liechti1f6643d2016-02-16 21:06:52 +0100191 'Unsupported value for RS485Settings.rts_level_for_rx: {!r}'.format(
192 self._rs485_mode.rts_level_for_rx,))
Chris Liechti33f0ec52015-08-06 16:37:21 +0200193 if self._rs485_mode.delay_before_tx is not None:
194 raise ValueError(
Chris Liechti1f6643d2016-02-16 21:06:52 +0100195 'Unsupported value for RS485Settings.delay_before_tx: {!r}'.format(
196 self._rs485_mode.delay_before_tx,))
Chris Liechti33f0ec52015-08-06 16:37:21 +0200197 if self._rs485_mode.delay_before_rx is not None:
198 raise ValueError(
Chris Liechti1f6643d2016-02-16 21:06:52 +0100199 'Unsupported value for RS485Settings.delay_before_rx: {!r}'.format(
200 self._rs485_mode.delay_before_rx,))
Chris Liechti33f0ec52015-08-06 16:37:21 +0200201 if self._rs485_mode.loopback:
202 raise ValueError(
Chris Liechti1f6643d2016-02-16 21:06:52 +0100203 'Unsupported value for RS485Settings.loopback: {!r}'.format(
204 self._rs485_mode.loopback,))
Chris Liechti33f0ec52015-08-06 16:37:21 +0200205 comDCB.fRtsControl = win32.RTS_CONTROL_TOGGLE
206 comDCB.fOutxCtsFlow = 0
207
cliechtif46e0a82005-05-19 15:24:57 +0000208 if self._dsrdtr:
Chris Liechti033f17c2015-08-30 21:28:04 +0200209 comDCB.fDtrControl = win32.DTR_CONTROL_HANDSHAKE
cliechtif46e0a82005-05-19 15:24:57 +0000210 else:
Chris Liechti033f17c2015-08-30 21:28:04 +0200211 comDCB.fDtrControl = win32.DTR_CONTROL_ENABLE if self._dtr_state else win32.DTR_CONTROL_DISABLE
212 comDCB.fOutxDsrFlow = self._dsrdtr
213 comDCB.fOutX = self._xonxoff
214 comDCB.fInX = self._xonxoff
215 comDCB.fNull = 0
216 comDCB.fErrorChar = 0
217 comDCB.fAbortOnError = 0
218 comDCB.XonChar = serial.XON
219 comDCB.XoffChar = serial.XOFF
cliechtid6bf52c2003-10-01 02:28:12 +0000220
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200221 if not win32.SetCommState(self._port_handle, ctypes.byref(comDCB)):
Chris Liechti1f6643d2016-02-16 21:06:52 +0100222 raise SerialException(
223 'Cannot configure port, something went wrong. '
224 'Original message: {!r}'.format(ctypes.WinError()))
cliechti95c62212002-03-04 22:17:53 +0000225
cliechtid6bf52c2003-10-01 02:28:12 +0000226 #~ def __del__(self):
227 #~ self.close()
228
cliechti1ae5ab02013-10-11 01:08:02 +0000229 def _close(self):
230 """internal close port helper"""
Chris Liechti34018402016-05-25 01:51:42 +0200231 if self._port_handle is not None:
cliechti1ae5ab02013-10-11 01:08:02 +0000232 # Restore original timeout values:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200233 win32.SetCommTimeouts(self._port_handle, self._orgTimeouts)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200234 if self._overlapped_read is not None:
Chris Liechti5a39b882016-05-03 22:10:39 +0200235 self.cancel_read()
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200236 win32.CloseHandle(self._overlapped_read.hEvent)
237 self._overlapped_read = None
238 if self._overlapped_write is not None:
Chris Liechti5a39b882016-05-03 22:10:39 +0200239 self.cancel_write()
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200240 win32.CloseHandle(self._overlapped_write.hEvent)
241 self._overlapped_write = None
Chris Liechti34018402016-05-25 01:51:42 +0200242 win32.CloseHandle(self._port_handle)
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200243 self._port_handle = None
cliechti1ae5ab02013-10-11 01:08:02 +0000244
cliechtid6bf52c2003-10-01 02:28:12 +0000245 def close(self):
246 """Close port"""
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200247 if self.is_open:
cliechti1ae5ab02013-10-11 01:08:02 +0000248 self._close()
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200249 self.is_open = False
cliechtid6bf52c2003-10-01 02:28:12 +0000250
251 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechtiedfba4e2009-02-07 00:29:47 +0000252
Chris Liechtief1fe252015-08-27 23:25:21 +0200253 @property
254 def in_waiting(self):
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200255 """Return the number of bytes currently in the input buffer."""
cliechti183d4ae2009-07-23 22:03:51 +0000256 flags = win32.DWORD()
257 comstat = win32.COMSTAT()
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200258 if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)):
Chris Liechtif9560572017-02-15 02:47:54 +0100259 raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError()))
cliechti89b4af12002-02-12 23:24:41 +0000260 return comstat.cbInQue
261
cliechti4a567a02009-07-27 22:09:31 +0000262 def read(self, size=1):
cliechti7d448562014-08-03 21:57:45 +0000263 """\
264 Read size bytes from the serial port. If a timeout is set it may
265 return less characters as requested. With no timeout it will block
Chris Liechti5a39b882016-05-03 22:10:39 +0200266 until the requested number of bytes is read.
267 """
Chris Liechtiacac2362016-03-29 22:37:48 +0200268 if not self.is_open:
Chris Liechtie99bda32020-09-14 03:59:52 +0200269 raise PortNotOpenError()
cliechti89b4af12002-02-12 23:24:41 +0000270 if size > 0:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200271 win32.ResetEvent(self._overlapped_read.hEvent)
cliechti183d4ae2009-07-23 22:03:51 +0000272 flags = win32.DWORD()
273 comstat = win32.COMSTAT()
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200274 if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)):
Chris Liechti229604e2016-06-01 01:58:05 +0200275 raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError()))
denglj25f1deb2016-01-25 12:34:44 +0800276 n = min(comstat.cbInQue, size) if self.timeout == 0 else size
277 if n > 0:
278 buf = ctypes.create_string_buffer(n)
cliechti183d4ae2009-07-23 22:03:51 +0000279 rc = win32.DWORD()
Chris Liechti70ca49c2016-02-07 23:54:03 +0100280 read_ok = win32.ReadFile(
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100281 self._port_handle,
282 buf,
283 n,
284 ctypes.byref(rc),
285 ctypes.byref(self._overlapped_read))
Chris Liechti7731e982015-11-02 23:46:07 +0100286 if not read_ok and win32.GetLastError() not in (win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING):
Chris Liechti1f6643d2016-02-16 21:06:52 +0100287 raise SerialException("ReadFile failed ({!r})".format(ctypes.WinError()))
Chris Liechti91f63fd2016-05-31 23:43:19 +0200288 result_ok = win32.GetOverlappedResult(
Chris Liechti9eaa40c2016-02-12 23:32:59 +0100289 self._port_handle,
290 ctypes.byref(self._overlapped_read),
291 ctypes.byref(rc),
292 True)
Chris Liechti91f63fd2016-05-31 23:43:19 +0200293 if not result_ok:
294 if win32.GetLastError() != win32.ERROR_OPERATION_ABORTED:
Chris Liechti229604e2016-06-01 01:58:05 +0200295 raise SerialException("GetOverlappedResult failed ({!r})".format(ctypes.WinError()))
cliechti183d4ae2009-07-23 22:03:51 +0000296 read = buf.raw[:rc.value]
denglj25f1deb2016-01-25 12:34:44 +0800297 else:
298 read = bytes()
cliechtif622faf2003-07-12 23:41:43 +0000299 else:
cliechti4a567a02009-07-27 22:09:31 +0000300 read = bytes()
301 return bytes(read)
cliechti89b4af12002-02-12 23:24:41 +0000302
cliechti4a567a02009-07-27 22:09:31 +0000303 def write(self, data):
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200304 """Output the given byte string over the serial port."""
Chris Liechtiacac2362016-03-29 22:37:48 +0200305 if not self.is_open:
Chris Liechtie99bda32020-09-14 03:59:52 +0200306 raise PortNotOpenError()
cliechti23dc2a02009-07-30 17:25:09 +0000307 #~ if not isinstance(data, (bytes, bytearray)):
308 #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
309 # convert data (needed in case of memoryview instance: Py 3.1 io lib), ctypes doesn't like memoryview
cliechti38077122013-10-16 02:57:27 +0000310 data = to_bytes(data)
cliechtib2f5fc82006-10-20 00:09:07 +0000311 if data:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200312 #~ win32event.ResetEvent(self._overlapped_write.hEvent)
cliechti183d4ae2009-07-23 22:03:51 +0000313 n = win32.DWORD()
Chris Liechti2a7ed532016-09-17 16:42:27 +0200314 success = win32.WriteFile(self._port_handle, data, len(data), ctypes.byref(n), self._overlapped_write)
Chris Liechti033f17c2015-08-30 21:28:04 +0200315 if self._write_timeout != 0: # if blocking (None) or w/ write timeout (>0)
Chris Liechtidc56ac92017-01-10 22:22:44 +0100316 if not success and win32.GetLastError() not in (win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING):
Chris Liechti2a7ed532016-09-17 16:42:27 +0200317 raise SerialException("WriteFile failed ({!r})".format(ctypes.WinError()))
318
cliechti31000fc2011-08-05 01:47:26 +0000319 # Wait for the write to complete.
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200320 #~ win32.WaitForSingleObject(self._overlapped_write.hEvent, win32.INFINITE)
Chris Liechti2a7ed532016-09-17 16:42:27 +0200321 win32.GetOverlappedResult(self._port_handle, self._overlapped_write, ctypes.byref(n), True)
Chris Liechti34018402016-05-25 01:51:42 +0200322 if win32.GetLastError() == win32.ERROR_OPERATION_ABORTED:
Chris Liechti77d922b2016-05-26 17:14:58 +0200323 return n.value # canceled IO is no error
cliechti31000fc2011-08-05 01:47:26 +0000324 if n.value != len(data):
Chris Liechtie99bda32020-09-14 03:59:52 +0200325 raise SerialTimeoutException('Write timeout')
Chris Liechtiab1ff482016-09-16 23:53:21 +0200326 return n.value
327 else:
Chris Liechti2a7ed532016-09-17 16:42:27 +0200328 errorcode = win32.ERROR_SUCCESS if success else win32.GetLastError()
329 if errorcode in (win32.ERROR_INVALID_USER_BUFFER, win32.ERROR_NOT_ENOUGH_MEMORY,
330 win32.ERROR_OPERATION_ABORTED):
331 return 0
Chris Liechtic759d292016-09-29 23:58:26 +0200332 elif errorcode in (win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING):
Chris Liechti2a7ed532016-09-17 16:42:27 +0200333 # no info on true length provided by OS function in async mode
334 return len(data)
335 else:
336 raise SerialException("WriteFile failed ({!r})".format(ctypes.WinError()))
cliechti23dc2a02009-07-30 17:25:09 +0000337 else:
338 return 0
cliechtiedfba4e2009-02-07 00:29:47 +0000339
cliechti26409782013-05-31 00:47:16 +0000340 def flush(self):
cliechti7d448562014-08-03 21:57:45 +0000341 """\
342 Flush of file like objects. In this case, wait until all data
343 is written.
344 """
Chris Liechtibc119fd2015-09-09 17:08:25 +0200345 while self.out_waiting:
cliechti26409782013-05-31 00:47:16 +0000346 time.sleep(0.05)
347 # XXX could also use WaitCommEvent with mask EV_TXEMPTY, but it would
Chris Liechti2a7ed532016-09-17 16:42:27 +0200348 # require overlapped IO and it's also only possible to set a single mask
cliechti26409782013-05-31 00:47:16 +0000349 # on the port---
cliechti89b4af12002-02-12 23:24:41 +0000350
Chris Liechtief1fe252015-08-27 23:25:21 +0200351 def reset_input_buffer(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000352 """Clear input buffer, discarding all that is in the buffer."""
Chris Liechtiacac2362016-03-29 22:37:48 +0200353 if not self.is_open:
Chris Liechtie99bda32020-09-14 03:59:52 +0200354 raise PortNotOpenError()
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200355 win32.PurgeComm(self._port_handle, win32.PURGE_RXCLEAR | win32.PURGE_RXABORT)
cliechti89b4af12002-02-12 23:24:41 +0000356
Chris Liechtief1fe252015-08-27 23:25:21 +0200357 def reset_output_buffer(self):
cliechti7d448562014-08-03 21:57:45 +0000358 """\
359 Clear output buffer, aborting the current output and discarding all
360 that is in the buffer.
361 """
Chris Liechtiacac2362016-03-29 22:37:48 +0200362 if not self.is_open:
Chris Liechtie99bda32020-09-14 03:59:52 +0200363 raise PortNotOpenError()
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200364 win32.PurgeComm(self._port_handle, win32.PURGE_TXCLEAR | win32.PURGE_TXABORT)
cliechti89b4af12002-02-12 23:24:41 +0000365
Chris Liechtief1fe252015-08-27 23:25:21 +0200366 def _update_break_state(self):
cliechti997b63c2008-06-21 00:09:31 +0000367 """Set break: Controls TXD. When active, to transmitting is possible."""
Chris Liechtiacac2362016-03-29 22:37:48 +0200368 if not self.is_open:
Chris Liechtie99bda32020-09-14 03:59:52 +0200369 raise PortNotOpenError()
Chris Liechtief1fe252015-08-27 23:25:21 +0200370 if self._break_state:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200371 win32.SetCommBreak(self._port_handle)
cliechti997b63c2008-06-21 00:09:31 +0000372 else:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200373 win32.ClearCommBreak(self._port_handle)
cliechti997b63c2008-06-21 00:09:31 +0000374
Chris Liechtief1fe252015-08-27 23:25:21 +0200375 def _update_rts_state(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000376 """Set terminal status line: Request To Send"""
Chris Liechtief1fe252015-08-27 23:25:21 +0200377 if self._rts_state:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200378 win32.EscapeCommFunction(self._port_handle, win32.SETRTS)
cliechti89b4af12002-02-12 23:24:41 +0000379 else:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200380 win32.EscapeCommFunction(self._port_handle, win32.CLRRTS)
cliechti89b4af12002-02-12 23:24:41 +0000381
Chris Liechtief1fe252015-08-27 23:25:21 +0200382 def _update_dtr_state(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000383 """Set terminal status line: Data Terminal Ready"""
Chris Liechtief1fe252015-08-27 23:25:21 +0200384 if self._dtr_state:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200385 win32.EscapeCommFunction(self._port_handle, win32.SETDTR)
cliechti89b4af12002-02-12 23:24:41 +0000386 else:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200387 win32.EscapeCommFunction(self._port_handle, win32.CLRDTR)
cliechti183d4ae2009-07-23 22:03:51 +0000388
389 def _GetCommModemStatus(self):
Chris Liechtiacac2362016-03-29 22:37:48 +0200390 if not self.is_open:
Chris Liechtie99bda32020-09-14 03:59:52 +0200391 raise PortNotOpenError()
cliechti183d4ae2009-07-23 22:03:51 +0000392 stat = win32.DWORD()
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200393 win32.GetCommModemStatus(self._port_handle, ctypes.byref(stat))
cliechti183d4ae2009-07-23 22:03:51 +0000394 return stat.value
cliechti89b4af12002-02-12 23:24:41 +0000395
Chris Liechtief1fe252015-08-27 23:25:21 +0200396 @property
397 def cts(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000398 """Read terminal status line: Clear To Send"""
cliechti183d4ae2009-07-23 22:03:51 +0000399 return win32.MS_CTS_ON & self._GetCommModemStatus() != 0
cliechti89b4af12002-02-12 23:24:41 +0000400
Chris Liechtief1fe252015-08-27 23:25:21 +0200401 @property
402 def dsr(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000403 """Read terminal status line: Data Set Ready"""
cliechti183d4ae2009-07-23 22:03:51 +0000404 return win32.MS_DSR_ON & self._GetCommModemStatus() != 0
cliechti89b4af12002-02-12 23:24:41 +0000405
Chris Liechtief1fe252015-08-27 23:25:21 +0200406 @property
407 def ri(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000408 """Read terminal status line: Ring Indicator"""
cliechti183d4ae2009-07-23 22:03:51 +0000409 return win32.MS_RING_ON & self._GetCommModemStatus() != 0
cliechti89b4af12002-02-12 23:24:41 +0000410
Chris Liechtief1fe252015-08-27 23:25:21 +0200411 @property
412 def cd(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000413 """Read terminal status line: Carrier Detect"""
cliechti183d4ae2009-07-23 22:03:51 +0000414 return win32.MS_RLSD_ON & self._GetCommModemStatus() != 0
cliechti89b4af12002-02-12 23:24:41 +0000415
cliechtia30a8a02003-10-05 12:28:13 +0000416 # - - platform specific - - - -
417
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200418 def set_buffer_size(self, rx_size=4096, tx_size=None):
cliechti59199642011-12-28 20:54:30 +0000419 """\
420 Recommend a buffer size to the driver (device driver can ignore this
Mohammad Ghasemiahmadi98b8c1a2018-05-15 10:21:35 -0700421 value). Must be called after the port is opened.
cliechti59199642011-12-28 20:54:30 +0000422 """
Chris Liechti033f17c2015-08-30 21:28:04 +0200423 if tx_size is None:
424 tx_size = rx_size
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200425 win32.SetupComm(self._port_handle, rx_size, tx_size)
cliechti59199642011-12-28 20:54:30 +0000426
Chris Liechti518b0d32015-08-30 02:20:39 +0200427 def set_output_flow_control(self, enable=True):
cliechti2f0f8a32011-12-28 22:10:00 +0000428 """\
429 Manually control flow - when software flow control is enabled.
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200430 This will do the same as if XON (true) or XOFF (false) are received
431 from the other device and control the transmission accordingly.
cliechti2f0f8a32011-12-28 22:10:00 +0000432 WARNING: this function is not portable to different platforms!
433 """
Chris Liechtiacac2362016-03-29 22:37:48 +0200434 if not self.is_open:
Chris Liechtie99bda32020-09-14 03:59:52 +0200435 raise PortNotOpenError()
Chris Liechti518b0d32015-08-30 02:20:39 +0200436 if enable:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200437 win32.EscapeCommFunction(self._port_handle, win32.SETXON)
cliechtia30a8a02003-10-05 12:28:13 +0000438 else:
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200439 win32.EscapeCommFunction(self._port_handle, win32.SETXOFF)
cliechtia30a8a02003-10-05 12:28:13 +0000440
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200441 @property
442 def out_waiting(self):
443 """Return how many bytes the in the outgoing buffer"""
cliechti183d4ae2009-07-23 22:03:51 +0000444 flags = win32.DWORD()
445 comstat = win32.COMSTAT()
Chris Liechti3ad62fb2015-08-29 21:53:32 +0200446 if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)):
Chris Liechtid5790182017-03-05 23:53:40 +0100447 raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError()))
cliechtic8e83d82009-07-21 21:34:05 +0000448 return comstat.cbOutQue
Chris Liechti5a39b882016-05-03 22:10:39 +0200449
450 def _cancel_overlapped_io(self, overlapped):
451 """Cancel a blocking read operation, may be called from other thread"""
452 # check if read operation is pending
453 rc = win32.DWORD()
454 err = win32.GetOverlappedResult(
455 self._port_handle,
456 ctypes.byref(overlapped),
457 ctypes.byref(rc),
458 False)
Chris Liechtic0d6a0f2016-05-12 23:48:01 +0200459 if not err and win32.GetLastError() in (win32.ERROR_IO_PENDING, win32.ERROR_IO_INCOMPLETE):
Chris Liechti5a39b882016-05-03 22:10:39 +0200460 # cancel, ignoring any errors (e.g. it may just have finished on its own)
461 win32.CancelIoEx(self._port_handle, overlapped)
462
463 def cancel_read(self):
464 """Cancel a blocking read operation, may be called from other thread"""
465 self._cancel_overlapped_io(self._overlapped_read)
466
467 def cancel_write(self):
468 """Cancel a blocking write operation, may be called from other thread"""
469 self._cancel_overlapped_io(self._overlapped_write)
Chris Liechti700a2382017-03-04 23:58:28 +0100470
471 @SerialBase.exclusive.setter
472 def exclusive(self, exclusive):
473 """Change the exclusive access setting."""
474 if exclusive is not None and not exclusive:
475 raise ValueError('win32 only supports exclusive access (not: {})'.format(exclusive))
Chris Liechtid5790182017-03-05 23:53:40 +0100476 else:
477 serial.SerialBase.exclusive.__set__(self, exclusive)