def read(self, size=1): """Read size bytes from the serial port. If a timeout is set it may return less characters as requested. With no timeout it will block until the requested number of bytes is read.""" if not self.hComPort: raise portNotOpenError if size > 0: win32.ResetEvent(self._overlappedRead.hEvent) flags = win32.DWORD() comstat = win32.COMSTAT() if not win32.ClearCommError(self.hComPort, ctypes.byref(flags), ctypes.byref(comstat)): raise SerialException('call to ClearCommError failed') if self.timeout == 0: n = min(comstat.cbInQue, size) if n > 0: buf = ctypes.create_string_buffer(n) rc = win32.DWORD() err = win32.ReadFile(self.hComPort, buf, n, ctypes.byref(rc), ctypes.byref(self._overlappedRead)) if not err and win32.GetLastError() != win32.ERROR_IO_PENDING: raise SerialException("ReadFile failed (%r)" % ctypes.WinError()) err = win32.WaitForSingleObject(self._overlappedRead.hEvent, win32.INFINITE) read = buf.raw[:rc.value] else: read = bytes() else: buf = ctypes.create_string_buffer(size) rc = win32.DWORD() err = win32.ReadFile(self.hComPort, buf, size, ctypes.byref(rc), ctypes.byref(self._overlappedRead)) if not err and win32.GetLastError() != win32.ERROR_IO_PENDING: raise SerialException("ReadFile failed (%r)" % ctypes.WinError()) err = win32.GetOverlappedResult(self.hComPort, ctypes.byref(self._overlappedRead), ctypes.byref(rc), True) read = buf.raw[:rc.value] else: read = bytes() return bytes(read)
def write(self, data): """Output the given byte string over the serial port.""" if not self.is_open: raise portNotOpenError #~ if not isinstance(data, (bytes, bytearray)): #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data))) # convert data (needed in case of memoryview instance: Py 3.1 io lib), ctypes doesn't like memoryview data = to_bytes(data) if data: #~ win32event.ResetEvent(self._overlapped_write.hEvent) n = win32.DWORD() err = win32.WriteFile(self._port_handle, data, len(data), ctypes.byref(n), self._overlapped_write) if not err and win32.GetLastError() != win32.ERROR_IO_PENDING: raise SerialException("WriteFile failed ({!r})".format( ctypes.WinError())) if self._write_timeout != 0: # if blocking (None) or w/ write timeout (>0) # Wait for the write to complete. #~ win32.WaitForSingleObject(self._overlapped_write.hEvent, win32.INFINITE) err = win32.GetOverlappedResult(self._port_handle, self._overlapped_write, ctypes.byref(n), True) if win32.GetLastError() == win32.ERROR_OPERATION_ABORTED: return n.value # canceled IO is no error if n.value != len(data): raise writeTimeoutError return n.value else: return 0
def read(self, size=1): """\ Read size bytes from the serial port. If a timeout is set it may return less characters as requested. With no timeout it will block until the requested number of bytes is read. """ if not self.is_open: raise portNotOpenError if size > 0: win32.ResetEvent(self._overlapped_read.hEvent) flags = win32.DWORD() comstat = win32.COMSTAT() if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)): raise SerialException('call to ClearCommError failed') n = min(comstat.cbInQue, size) if self.timeout == 0 else size if n > 0: buf = ctypes.create_string_buffer(n) rc = win32.DWORD() read_ok = win32.ReadFile(self._port_handle, buf, n, ctypes.byref(rc), ctypes.byref(self._overlapped_read)) if not read_ok and win32.GetLastError() not in ( win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING): raise SerialException("ReadFile failed ({!r})".format( ctypes.WinError())) win32.GetOverlappedResult(self._port_handle, ctypes.byref(self._overlapped_read), ctypes.byref(rc), True) read = buf.raw[:rc.value] else: read = bytes() else: read = bytes() return bytes(read)
def write(self, data): """Output the given byte string over the serial port.""" if not self.is_open: raise PortNotOpenError() #~ if not isinstance(data, (bytes, bytearray)): #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data))) # convert data (needed in case of memoryview instance: Py 3.1 io lib), ctypes doesn't like memoryview data = to_bytes(data) if data: #~ win32event.ResetEvent(self._overlapped_write.hEvent) n = win32.DWORD() success = win32.WriteFile(self._port_handle, data, len(data), ctypes.byref(n), self._overlapped_write) if self._write_timeout != 0: # if blocking (None) or w/ write timeout (>0) if not success and win32.GetLastError() not in ( win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING): raise SerialException("WriteFile failed ({!r})".format( ctypes.WinError())) # Wait for the write to complete. #~ win32.WaitForSingleObject(self._overlapped_write.hEvent, win32.INFINITE) win32.GetOverlappedResult(self._port_handle, self._overlapped_write, ctypes.byref(n), True) if win32.GetLastError() == win32.ERROR_OPERATION_ABORTED: return n.value # canceled IO is no error if n.value != len(data): raise SerialTimeoutException('Write timeout') return n.value else: errorcode = win32.ERROR_SUCCESS if success else win32.GetLastError( ) if errorcode in (win32.ERROR_INVALID_USER_BUFFER, win32.ERROR_NOT_ENOUGH_MEMORY, win32.ERROR_OPERATION_ABORTED): return 0 elif errorcode in (win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING): # no info on true length provided by OS function in async mode return len(data) else: raise SerialException("WriteFile failed ({!r})".format( ctypes.WinError())) else: return 0
def _scsi_operation(self, pbuf, size, read, timeout=10): sptdwb = SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER() ctypes.memset(ctypes.addressof(sptdwb), 0, ctypes.sizeof(sptdwb)) sptdwb.sptd.Length = ctypes.sizeof(SCSI_PASS_THROUGH_DIRECT) sptdwb.sptd.PathId = 0 sptdwb.sptd.TargetId = 1 sptdwb.sptd.Lun = 0 sptdwb.sptd.CdbLength = CDB10GENERIC_LENGTH sptdwb.sptd.SenseInfoLength = 0 sptdwb.sptd.DataIn = SCSI_IOCTL_DATA_IN if read else SCSI_IOCTL_DATA_OUT sptdwb.sptd.DataTransferLength = size sptdwb.sptd.TimeOutValue = timeout sptdwb.sptd.DataBuffer = pbuf sptdwb.sptd.SenseInfoOffset = ( SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER.ucSenseBuf.offset ) sptdwb.sptd.Cdb[0] = 0xEF sptdwb.sptd.Cdb[1] = 0xFF if read else 0xFE length = DWORD(ctypes.sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)) returned = DWORD(0) result_ok = DeviceIoControl( self._port_handle, IOCTL_SCSI_PASS_THROUGH_DIRECT, ctypes.pointer(sptdwb), length, ctypes.pointer(sptdwb), length, ctypes.byref(returned), None, ) if not result_ok and win32.GetLastError() not in ( win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING, ): raise WindowsSCSIInterfaceException( "DeviceIoControl failed ({!r})".format(ctypes.WinError()) ) if returned.value < ( SCSI_PASS_THROUGH_DIRECT.ScsiStatus.offset + SCSI_PASS_THROUGH_DIRECT.ScsiStatus.size ): raise WindowsSCSIInterfaceException( "Not enough SCSI information returned to determine error" ) if sptdwb.sptd.ScsiStatus != 0: raise WindowsSCSIInterfaceException( "SCSI Operation returned %d" % (sptdwb.sptd.ScsiStatus,) ) return sptdwb.sptd.DataTransferLength
def read(self, size=1): if not self.is_open: print("ERROR: Port is not opened") exit(1) if size > 0: win32.ResetEvent(self._overlapped_read.hEvent) flags = win32.DWORD() comstat = win32.COMSTAT() if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)): print("ERROR: ClearCommError failed ({!r})".format( ctypes.WinError())) exit(1) n = min(comstat.cbInQue, size) if self.timeout == 0 else size if n > 0: buf = ctypes.create_string_buffer(n) rc = win32.DWORD() read_ok = win32.ReadFile(self._port_handle, buf, n, ctypes.byref(rc), ctypes.byref(self._overlapped_read)) if not read_ok and win32.GetLastError() not in ( win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING): print("ERROR: ReadFile failed ({!r})".format( ctypes.WinError())) exit(1) if not read_ok: print("ERROR: Something bad") return buf.value result_ok = win32.GetOverlappedResult( self._port_handle, ctypes.byref(self._overlapped_read), ctypes.byref(rc), True) if not result_ok: if win32.GetLastError() != win32.ERROR_OPERATION_ABORTED: raise SerialException( "GetOverlappedResult failed ({!r})".format( ctypes.WinError())) read = buf.raw[:rc.value] else: read = bytes() else: read = bytes() return bytes(read)
def _cancel_overlapped_io(self, overlapped): """Cancel a blocking read operation, may be called from other thread""" # check if read operation is pending rc = win32.DWORD() err = win32.GetOverlappedResult(self._port_handle, ctypes.byref(overlapped), ctypes.byref(rc), False) if not err and win32.GetLastError() in (win32.ERROR_IO_PENDING, win32.ERROR_IO_INCOMPLETE): # cancel, ignoring any errors (e.g. it may just have finished on its own) win32.CancelIoEx(self._port_handle, overlapped)
def write(self, data): if not self.is_open: print("Port is not opened") exit(1) data = to_bytes(data) if data: n = win32.DWORD() success = win32.WriteFile(self._port_handle, data, len(data), ctypes.byref(n), self._overlapped_write) if self._write_timeout != 0: if not success and win32.GetLastError() not in ( win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING): print("WriteFile failed ({!r})".format(ctypes.WinError())) exit(1) win32.GetOverlappedResult(self._port_handle, self._overlapped_write, ctypes.byref(n), True) if win32.GetLastError() == win32.ERROR_OPERATION_ABORTED: return n.value if n.value != len(data): print("Write timeout") exit(1) return n.value else: errorcode = win32.ERROR_SUCCESS if success else win32.GetLastError( ) if errorcode in (win32.ERROR_INVALID_USER_BUFFER, win32.ERROR_NOT_ENOUGH_MEMORY, win32.ERROR_OPERATION_ABORTED): return 0 elif errorcode in (win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING): # no info on true length provided by OS function in async mode return len(data) else: print("WriteFile failed ({!r})".format(ctypes.WinError())) exit(1) else: return 0