def write(self, data): """Output the given byte string over the serial port.""" if not self.is_open: raise PortNotOpenError() d = to_bytes(data) tx_len = length = len(d) timeout = Timeout(self._write_timeout) while tx_len > 0: try: n = os.write(self.fd, d) if timeout.is_non_blocking: # Zero timeout indicates non-blocking - simply return the # number of bytes of data actually written return n elif not timeout.is_infinite: # when timeout is set, use select to wait for being ready # with the time left as timeout if timeout.expired(): raise SerialTimeoutException('Write timeout') abort, ready, _ = select.select([self.pipe_abort_write_r], [self.fd], [], timeout.time_left()) if abort: os.read(self.pipe_abort_write_r, 1000) break if not ready: raise SerialTimeoutException('Write timeout') else: assert timeout.time_left() is None # wait for write operation abort, ready, _ = select.select([self.pipe_abort_write_r], [self.fd], [], None) if abort: os.read(self.pipe_abort_write_r, 1) break if not ready: raise SerialException('write failed (select)') d = d[n:] tx_len -= n except SerialException: raise except OSError as e: # this is for Python 3.x where select.error is a subclass of # OSError ignore BlockingIOErrors and EINTR. other errors are shown # https://www.python.org/dev/peps/pep-0475. if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): raise SerialException('write failed: {}'.format(e)) except select.error as e: # this is for Python 2.x # ignore BlockingIOErrors and EINTR. all errors are shown # see also http://www.python.org/dev/peps/pep-3151/#select if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): raise SerialException('write failed: {}'.format(e)) if not timeout.is_non_blocking and timeout.expired(): raise SerialTimeoutException('Write timeout') return length - len(d)
def ri(self): """Read terminal status line: Ring Indicator""" if not self.is_open: raise PortNotOpenError() if self.logger: self.logger.info('returning dummy for ri') return False
def cd(self): """Read terminal status line: Carrier Detect""" if not self.is_open: raise PortNotOpenError() if self.logger: self.logger.info('returning dummy for cd)') return True
def reset_input_buffer(self): """Clear input buffer, discarding all that is in the buffer.""" if not self.is_open: raise PortNotOpenError() # just use recv to remove input, while there is some ready = True while ready: ready, _, _ = select.select([self._socket], [], [], 0) try: if ready: ready = self._socket.recv(4096) except OSError as e: # this is for Python 3.x where select.error is a subclass of # OSError ignore BlockingIOErrors and EINTR. other errors are shown # https://www.python.org/dev/peps/pep-0475. if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): raise SerialException('read failed: {}'.format(e)) except (select.error, socket.error) as e: # this is for Python 2.x # ignore BlockingIOErrors and EINTR. all errors are shown # see also http://www.python.org/dev/peps/pep-3151/#select if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): raise SerialException('read failed: {}'.format(e))
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() read = bytearray() timeout = Timeout(self._timeout) poll = select.poll() poll.register(self.fd, select.POLLIN | select.POLLERR | select.POLLHUP | select.POLLNVAL) poll.register(self.pipe_abort_read_r, select.POLLIN | select.POLLERR | select.POLLHUP | select.POLLNVAL) if size > 0: while len(read) < size: # print "\tread(): size",size, "have", len(read) #debug # wait until device becomes ready to read (or something fails) for fd, event in poll.poll(None if timeout.is_infinite else (timeout.time_left() * 1000)): if fd == self.pipe_abort_read_r: break if event & (select.POLLERR | select.POLLHUP | select.POLLNVAL): raise SerialException('device reports error (poll)') # we don't care if it is select.POLLIN or timeout, that's # handled below if fd == self.pipe_abort_read_r: os.read(self.pipe_abort_read_r, 1000) break buf = os.read(self.fd, size - len(read)) read.extend(buf) if timeout.expired() \ or (self._inter_byte_timeout is not None and self._inter_byte_timeout > 0) and not buf: break # early abort on timeout return bytes(read)
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 self._timeout is not None and self._timeout != 0: timeout = time.time() + self._timeout else: timeout = None data = bytearray() while size > 0 and self.is_open: try: b = self.queue.get( timeout=self._timeout) # XXX inter char timeout except queue.Empty: if self._timeout == 0: break else: if b is not None: data += b size -= 1 else: break # check for timeout now, after data has been read. # useful for timeout = 0 (non blocking) read if timeout and time.time() > timeout: if self.logger: self.logger.info('read timeout') break return bytes(data)
def write(self, data): """\ Output the given byte string over the serial port. Can block if the connection is blocked. May raise SerialException if the connection is closed. """ self._cancel_write = False if not self.is_open: raise PortNotOpenError() data = to_bytes(data) # calculate aprox time that would be used to send the data time_used_to_send = 10.0 * len(data) / self._baudrate # when a write timeout is configured check if we would be successful # (not sending anything, not even the part that would have time) if self._write_timeout is not None and time_used_to_send > self._write_timeout: # must wait so that unit test succeeds time_left = self._write_timeout while time_left > 0 and not self._cancel_write: time.sleep(min(time_left, 0.5)) time_left -= 0.5 if self._cancel_write: return 0 # XXX raise SerialTimeoutException('Write timeout') for byte in iterbytes(data): self.queue.put(byte, timeout=self._write_timeout) return len(data)
def cts(self): """Read terminal status line: Clear To Send""" if not self.is_open: raise PortNotOpenError() if self.logger: self.logger.info('CTS -> state of RTS ({!r})'.format(self._rts_state)) return self._rts_state
def cts(self): """Read terminal status line: Clear To Send""" if not self.is_open: raise PortNotOpenError() if self.logger: self.logger.info('returning dummy for cts') return True
def dsr(self): """Read terminal status line: Data Set Ready""" if not self.is_open: raise PortNotOpenError() if self.logger: self.logger.info('returning dummy for dsr') return True
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() read = bytearray() timeout = Timeout(self._timeout) while len(read) < size: try: ready, _, _ = select.select([self.fd, self.pipe_abort_read_r], [], [], timeout.time_left()) if self.pipe_abort_read_r in ready: os.read(self.pipe_abort_read_r, 1000) break # If select was used with a timeout, and the timeout occurs, it # returns with empty lists -> thus abort read operation. # For timeout == 0 (non-blocking operation) also abort when # there is nothing to read. if not ready: break # timeout buf = os.read(self.fd, size - len(read)) except OSError as e: # this is for Python 3.x where select.error is a subclass of # OSError ignore BlockingIOErrors and EINTR. other errors are shown # https://www.python.org/dev/peps/pep-0475. if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): raise SerialException('read failed: {}'.format(e)) except select.error as e: # this is for Python 2.x # ignore BlockingIOErrors and EINTR. all errors are shown # see also http://www.python.org/dev/peps/pep-3151/#select if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): raise SerialException('read failed: {}'.format(e)) else: # read should always return some data as select reported it was # ready to read when we get to this point. if not buf: # Disconnected devices, at least on Linux, show the # behavior that they are always ready to read immediately # but reading returns nothing. raise SerialException( 'device reports readiness to read but returned no data ' '(device disconnected or multiple access on port?)') read.extend(buf) if timeout.expired(): break elif self._inter_byte_timeout is not None and self._inter_byte_timeout > 0: #atleast one char received --> overwrite timeout by setting it to inter_byte_timeout timeout = Timeout(self._inter_byte_timeout) return bytes(read)
def _update_break_state(self): """Set break: Controls TXD. When active, to transmitting is possible.""" if not self.is_open: raise PortNotOpenError() if self._break_state: win32.SetCommBreak(self._port_handle) else: win32.ClearCommBreak(self._port_handle)
def reset_input_buffer(self): if not self.is_open: raise PortNotOpenError() self._hid_handle.send_feature_report( bytes((_REPORT_SET_PURGE_FIFOS, _PURGE_RX_FIFO))) # empty read buffer while self._read_buffer.qsize(): self._read_buffer.get(False)
def flush(self): """\ Flush of file like objects. In this case, wait until all data is written. """ if not self.is_open: raise PortNotOpenError() termios.tcdrain(self.fd)
def reset_output_buffer(self): """\ Clear output buffer, aborting the current output and discarding all that is in the buffer. """ if not self.is_open: raise PortNotOpenError() termios.tcflush(self.fd, termios.TCOFLUSH)
def reset_output_buffer(self): """\ Clear output buffer, aborting the current output and discarding all that is in the buffer. """ if not self.is_open: raise PortNotOpenError() win32.PurgeComm(self._port_handle, win32.PURGE_TXCLEAR | win32.PURGE_TXABORT)
def in_waiting(self): """Return the number of bytes currently in the input buffer.""" if not self.is_open: raise PortNotOpenError() # Poll the socket to see if it is ready for reading. # If ready, at least one byte will be to read. lr, lw, lx = select.select([self._socket], [], [], 0) return len(lr)
def fileno(self): """\ For easier use of the serial port instance with select. WARNING: this function is not portable to different platforms! """ if not self.is_open: raise PortNotOpenError() return self.fd
def send_break(self, duration=0.25): """\ Send break condition. Timed, returns to idle state after given duration. """ if not self.is_open: raise PortNotOpenError() termios.tcsendbreak(self.fd, int(duration / 0.25))
def in_waiting(self): """Return the number of bytes currently in the input buffer.""" if not self.is_open: raise PortNotOpenError() if self.logger: # attention the logged value can differ from return value in # threaded environments... self.logger.debug('in_waiting -> {:d}'.format(self.queue.qsize())) return self.queue.qsize()
def send_break(self, duration=0.25): """\ Send break condition. Timed, returns to idle state after given duration. """ if not self.is_open: raise PortNotOpenError() if self.logger: self.logger.info('ignored send_break({!r})'.format(duration))
def reset_output_buffer(self): """\ Clear output buffer, aborting the current output and discarding all that is in the buffer. """ if not self.is_open: raise PortNotOpenError() if self.logger: self.logger.info('ignored reset_output_buffer')
def out_waiting(self): """Return how many bytes the in the outgoing buffer""" if not self.is_open: raise PortNotOpenError() if self.logger: # attention the logged value can differ from return value in # threaded environments... self.logger.debug('out_waiting -> {:d}'.format(self.queue.qsize())) return self.queue.qsize()
def reset_input_buffer(self): """Clear input buffer, discarding all that is in the buffer.""" if not self.is_open: raise PortNotOpenError() if self.logger: self.logger.info('reset_input_buffer()') try: while self.queue.qsize(): self.queue.get_nowait() except queue.Empty: pass
def write(self, data): if not self.is_open: raise PortNotOpenError() data = to_bytes(data) tx_len = len(data) while tx_len > 0: to_be_sent = min(tx_len, 0x3F) report = to_bytes([to_be_sent]) + data[:to_be_sent] self._hid_handle.write(report) data = data[to_be_sent:] tx_len = len(data)
def set_output_flow_control(self, enable=True): """\ Manually control flow of outgoing data - when hardware or software flow control is enabled. WARNING: this function is not portable to different platforms! """ if not self.is_open: raise PortNotOpenError() if enable: termios.tcflow(self.fd, termios.TCOON) else: termios.tcflow(self.fd, termios.TCOOFF)
def set_input_flow_control(self, enable=True): """\ Manually control flow - when software flow control is enabled. This will send XON (true) or XOFF (false) to the other device. WARNING: this function is not portable to different platforms! """ if not self.is_open: raise PortNotOpenError() if enable: termios.tcflow(self.fd, termios.TCION) else: termios.tcflow(self.fd, termios.TCIOFF)
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() read = bytearray() buf = os.read(self.fd, size - len(read)) read.extend(buf) return bytes(read)
def set_output_flow_control(self, enable=True): """\ Manually control flow - when software flow control is enabled. This will do the same as if XON (true) or XOFF (false) are received from the other device and control the transmission accordingly. WARNING: this function is not portable to different platforms! """ if not self.is_open: raise PortNotOpenError() if enable: win32.EscapeCommFunction(self._port_handle, win32.SETXON) else: win32.EscapeCommFunction(self._port_handle, win32.SETXOFF)
def _update_break_state(self): if not self._hid_handle: raise PortNotOpenError() if self._break_state: self._hid_handle.send_feature_report( bytes((_REPORT_SET_TRANSMIT_LINE_BREAK, 0))) else: # Note that while AN434 states "There are no data bytes in # the payload other than the Report ID", either hidapi or # Linux does not seem to send the report otherwise. self._hid_handle.send_feature_report( bytes((_REPORT_SET_STOP_LINE_BREAK, 0)))