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 writeTimeoutError 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 writeTimeoutError 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 writeTimeoutError return length - len(d)
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)) # 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) 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)) if timeout.expired(): break return bytes(read)
def open(self): """\ Open port with current settings. This may throw a SerialException if the port cannot be opened.""" if self._port is None: raise SerialException( "Port must be configured before it can be used.") if self.is_open: raise SerialException("Port is already open.") self.fd = None # open try: self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK) except OSError as msg: self.fd = None raise SerialException( msg.errno, "could not open port {}: {}".format(self._port, msg)) #~ fcntl.fcntl(self.fd, fcntl.F_SETFL, 0) # set blocking try: self._reconfigure_port(force_update=True) except: try: os.close(self.fd) except: # ignore any exception when closing the port # also to keep original exception that happened when setting up pass self.fd = None raise else: self.is_open = True try: if not self._dsrdtr: self._update_dtr_state() if not self._rtscts: self._update_rts_state() except IOError as e: if e.errno in (errno.EINVAL, errno.ENOTTY): # ignore Invalid argument and Inappropriate ioctl pass else: raise self.reset_input_buffer() self.pipe_abort_read_r, self.pipe_abort_read_w = os.pipe() self.pipe_abort_write_r, self.pipe_abort_write_w = os.pipe() fcntl.fcntl(self.pipe_abort_read_r, fcntl.F_SETFL, os.O_NONBLOCK) fcntl.fcntl(self.pipe_abort_write_r, fcntl.F_SETFL, os.O_NONBLOCK)
def _reconfigure_port(self, force_update=True): """Set communication parameters on opened port.""" super(VTIMESerial, self)._reconfigure_port() fcntl.fcntl(self.fd, fcntl.F_SETFL, 0) # clear O_NONBLOCK if self._inter_byte_timeout is not None: vmin = 1 vtime = int(self._inter_byte_timeout * 10) elif self._timeout is None: vmin = 1 vtime = 0 else: vmin = 0 vtime = int(self._timeout * 10) try: orig_attr = termios.tcgetattr(self.fd) iflag, oflag, cflag, lflag, ispeed, ospeed, cc = orig_attr except termios.error as msg: # if a port is nonexistent but has a /dev file, it'll fail here raise SerialException("Could not configure port: {}".format(msg)) if vtime < 0 or vtime > 255: raise ValueError('Invalid vtime: {!r}'.format(vtime)) cc[termios.VTIME] = vtime cc[termios.VMIN] = vmin termios.tcsetattr(self.fd, termios.TCSANOW, [iflag, oflag, cflag, lflag, ispeed, ospeed, cc])
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() poll = select.poll() poll.register( self.fd, 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(self._timeout * 1000): 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 buf = os.read(self.fd, size - len(read)) read.extend(buf) if ((self._timeout is not None and self._timeout >= 0) 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 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 writeTimeoutError 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 out_waiting(self): """Return how many bytes the in the outgoing buffer""" flags = win32.DWORD() comstat = win32.COMSTAT() if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)): raise SerialException("ClearCommError failed ({!r})".format( ctypes.WinError())) return comstat.cbOutQue
def in_waiting(self): """Return the number of bytes currently in the input buffer.""" flags = win32.DWORD() comstat = win32.COMSTAT() if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)): raise SerialException("ClearCommError failed ({!r})".format( ctypes.WinError())) return comstat.cbInQue
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("ClearCommError failed ({!r})".format( ctypes.WinError())) 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())) 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 open(self): """Open port with current settings. This may throw a SerialException if the port cannot be opened.""" if self._port is None: raise SerialException( "Port must be configured before it can be used.") self.fd = None # open try: self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK) except Exception as msg: self.fd = None raise SerialException("could not open port %s: %s" % (self._port, msg)) # ~ fcntl.fcntl(self.fd, FCNTL.F_SETFL, 0) #set blocking try: self._reconfigurePort() except BaseException: os.close(self.fd) self.fd = None else: self._isOpen = True
def _reconfigure_port(self): """Set communication parameters on opened port.""" if not self._port_handle: raise SerialException("Can only operate on a valid port handle") # Set Windows timeout values # timeouts is a tuple with the following items: # (ReadIntervalTimeout,ReadTotalTimeoutMultiplier, # ReadTotalTimeoutConstant,WriteTotalTimeoutMultiplier, # WriteTotalTimeoutConstant) timeouts = win32.COMMTIMEOUTS() if self._timeout is None: pass # default of all zeros is OK elif self._timeout == 0: timeouts.ReadIntervalTimeout = win32.MAXDWORD else: timeouts.ReadTotalTimeoutConstant = max(int(self._timeout * 1000), 1) if self._timeout != 0 and self._inter_byte_timeout is not None: timeouts.ReadIntervalTimeout = max( int(self._inter_byte_timeout * 1000), 1) if self._write_timeout is None: pass elif self._write_timeout == 0: timeouts.WriteTotalTimeoutConstant = win32.MAXDWORD else: timeouts.WriteTotalTimeoutConstant = max( int(self._write_timeout * 1000), 1) win32.SetCommTimeouts(self._port_handle, ctypes.byref(timeouts)) win32.SetCommMask(self._port_handle, win32.EV_ERR) # Setup the connection info. # Get state and modify it: comDCB = win32.DCB() win32.GetCommState(self._port_handle, ctypes.byref(comDCB)) comDCB.BaudRate = self._baudrate if self._bytesize == serialutil.FIVEBITS: comDCB.ByteSize = 5 elif self._bytesize == serialutil.SIXBITS: comDCB.ByteSize = 6 elif self._bytesize == serialutil.SEVENBITS: comDCB.ByteSize = 7 elif self._bytesize == serialutil.EIGHTBITS: comDCB.ByteSize = 8 else: raise ValueError("Unsupported number of data bits: {!r}".format( self._bytesize)) if self._parity == serialutil.PARITY_NONE: comDCB.Parity = win32.NOPARITY comDCB.fParity = 0 # Disable Parity Check elif self._parity == serialutil.PARITY_EVEN: comDCB.Parity = win32.EVENPARITY comDCB.fParity = 1 # Enable Parity Check elif self._parity == serialutil.PARITY_ODD: comDCB.Parity = win32.ODDPARITY comDCB.fParity = 1 # Enable Parity Check elif self._parity == serialutil.PARITY_MARK: comDCB.Parity = win32.MARKPARITY comDCB.fParity = 1 # Enable Parity Check elif self._parity == serialutil.PARITY_SPACE: comDCB.Parity = win32.SPACEPARITY comDCB.fParity = 1 # Enable Parity Check else: raise ValueError("Unsupported parity mode: {!r}".format( self._parity)) if self._stopbits == serialutil.STOPBITS_ONE: comDCB.StopBits = win32.ONESTOPBIT elif self._stopbits == serialutil.STOPBITS_ONE_POINT_FIVE: comDCB.StopBits = win32.ONE5STOPBITS elif self._stopbits == serialutil.STOPBITS_TWO: comDCB.StopBits = win32.TWOSTOPBITS else: raise ValueError("Unsupported number of stop bits: {!r}".format( self._stopbits)) comDCB.fBinary = 1 # Enable Binary Transmission # Char. w/ Parity-Err are replaced with 0xff (if fErrorChar is set to TRUE) if self._rs485_mode is None: if self._rtscts: comDCB.fRtsControl = win32.RTS_CONTROL_HANDSHAKE else: comDCB.fRtsControl = win32.RTS_CONTROL_ENABLE if self._rts_state else win32.RTS_CONTROL_DISABLE comDCB.fOutxCtsFlow = self._rtscts else: # checks for unsupported settings # XXX verify if platform really does not have a setting for those if not self._rs485_mode.rts_level_for_tx: raise ValueError( 'Unsupported value for RS485Settings.rts_level_for_tx: {!r}' .format(self._rs485_mode.rts_level_for_tx, )) if self._rs485_mode.rts_level_for_rx: raise ValueError( 'Unsupported value for RS485Settings.rts_level_for_rx: {!r}' .format(self._rs485_mode.rts_level_for_rx, )) if self._rs485_mode.delay_before_tx is not None: raise ValueError( 'Unsupported value for RS485Settings.delay_before_tx: {!r}' .format(self._rs485_mode.delay_before_tx, )) if self._rs485_mode.delay_before_rx is not None: raise ValueError( 'Unsupported value for RS485Settings.delay_before_rx: {!r}' .format(self._rs485_mode.delay_before_rx, )) if self._rs485_mode.loopback: raise ValueError( 'Unsupported value for RS485Settings.loopback: {!r}'. format(self._rs485_mode.loopback, )) comDCB.fRtsControl = win32.RTS_CONTROL_TOGGLE comDCB.fOutxCtsFlow = 0 if self._dsrdtr: comDCB.fDtrControl = win32.DTR_CONTROL_HANDSHAKE else: comDCB.fDtrControl = win32.DTR_CONTROL_ENABLE if self._dtr_state else win32.DTR_CONTROL_DISABLE comDCB.fOutxDsrFlow = self._dsrdtr comDCB.fOutX = self._xonxoff comDCB.fInX = self._xonxoff comDCB.fNull = 0 comDCB.fErrorChar = 0 comDCB.fAbortOnError = 0 comDCB.XonChar = serialutil.XON comDCB.XoffChar = serialutil.XOFF if not win32.SetCommState(self._port_handle, ctypes.byref(comDCB)): raise SerialException( 'Cannot configure port, something went wrong. ' 'Original message: {!r}'.format(ctypes.WinError()))
def open(self): """\ Open port with current settings. This may throw a SerialException if the port cannot be opened. """ if self._port is None: raise SerialException( "Port must be configured before it can be used.") if self.is_open: raise SerialException("Port is already open.") # the "\\.\COMx" format is required for devices other than COM1-COM8 # not all versions of windows seem to support this properly # so that the first few ports are used with the DOS device name port = self.name try: if port.upper().startswith('COM') and int(port[3:]) > 8: port = '\\\\.\\' + port except ValueError: # for like COMnotanumber pass self._port_handle = win32.CreateFile( port, win32.GENERIC_READ | win32.GENERIC_WRITE, 0, # exclusive access None, # no security win32.OPEN_EXISTING, win32.FILE_ATTRIBUTE_NORMAL | win32.FILE_FLAG_OVERLAPPED, 0) if self._port_handle == win32.INVALID_HANDLE_VALUE: self._port_handle = None # 'cause __del__ is called anyway raise SerialException("could not open port {!r}: {!r}".format( self.portstr, ctypes.WinError())) try: self._overlapped_read = win32.OVERLAPPED() self._overlapped_read.hEvent = win32.CreateEvent(None, 1, 0, None) self._overlapped_write = win32.OVERLAPPED() #~ self._overlapped_write.hEvent = win32.CreateEvent(None, 1, 0, None) self._overlapped_write.hEvent = win32.CreateEvent(None, 0, 0, None) # Setup a 4k buffer win32.SetupComm(self._port_handle, 4096, 4096) # Save original timeout values: self._orgTimeouts = win32.COMMTIMEOUTS() win32.GetCommTimeouts(self._port_handle, ctypes.byref(self._orgTimeouts)) self._reconfigure_port() # Clear buffers: # Remove anything that was there win32.PurgeComm( self._port_handle, win32.PURGE_TXCLEAR | win32.PURGE_TXABORT | win32.PURGE_RXCLEAR | win32.PURGE_RXABORT) except: try: self._close() except: # ignore any exception when closing the port # also to keep original exception that happened when setting up pass self._port_handle = None raise else: self.is_open = True
def _reconfigurePort(self): """Set communication parameters on opened port.""" if self.fd is None: raise SerialException("Can only operate on a valid port handle") custom_baud = None vmin = vtime = 0 # timeout is done via select if self._interCharTimeout is not None: vmin = 1 vtime = int(self._interCharTimeout * 10) try: iflag, oflag, cflag, lflag, ispeed, ospeed, cc = termios.tcgetattr( self.fd) # if a port is nonexistent but has a /dev file, it'll fail here except termios.error as msg: raise SerialException("Could not configure port: %s" % msg) # set up raw mode / no echo / binary cflag |= (TERMIOS.CLOCAL | TERMIOS.CREAD) lflag &= ~(TERMIOS.ICANON | TERMIOS.ECHO | TERMIOS.ECHOE | TERMIOS.ECHOK | TERMIOS.ECHONL | TERMIOS.ISIG | TERMIOS.IEXTEN) # |TERMIOS.ECHOPRT for flag in ('ECHOCTL', 'ECHOKE'): # netbsd workaround for Erk if hasattr(TERMIOS, flag): lflag &= ~getattr(TERMIOS, flag) oflag &= ~(TERMIOS.OPOST) iflag &= ~(TERMIOS.INLCR | TERMIOS.IGNCR | TERMIOS.ICRNL | TERMIOS.IGNBRK) if hasattr(TERMIOS, 'IUCLC'): iflag &= ~TERMIOS.IUCLC if hasattr(TERMIOS, 'PARMRK'): iflag &= ~TERMIOS.PARMRK # setup baudrate try: ispeed = ospeed = getattr(TERMIOS, 'B%s' % (self._baudrate)) except AttributeError: try: ispeed = ospeed = baudrate_constants[self._baudrate] except KeyError: #~ raise ValueError('Invalid baud rate: %r' % self._baudrate) # may need custom baud rate, it isnt in our list. ispeed = ospeed = getattr(TERMIOS, 'B38400') custom_baud = int(self._baudrate) # store for later # setup char len cflag &= ~TERMIOS.CSIZE if self._bytesize == 8: cflag |= TERMIOS.CS8 elif self._bytesize == 7: cflag |= TERMIOS.CS7 elif self._bytesize == 6: cflag |= TERMIOS.CS6 elif self._bytesize == 5: cflag |= TERMIOS.CS5 else: raise ValueError('Invalid char len: %r' % self._bytesize) # setup stopbits if self._stopbits == STOPBITS_ONE: cflag &= ~(TERMIOS.CSTOPB) elif self._stopbits == STOPBITS_TWO: cflag |= (TERMIOS.CSTOPB) else: raise ValueError('Invalid stopit specification: %r' % self._stopbits) # setup parity iflag &= ~(TERMIOS.INPCK | TERMIOS.ISTRIP) if self._parity == PARITY_NONE: cflag &= ~(TERMIOS.PARENB | TERMIOS.PARODD) elif self._parity == PARITY_EVEN: cflag &= ~(TERMIOS.PARODD) cflag |= (TERMIOS.PARENB) elif self._parity == PARITY_ODD: cflag |= (TERMIOS.PARENB | TERMIOS.PARODD) else: raise ValueError('Invalid parity: %r' % self._parity) # setup flow control # xonxoff if hasattr(TERMIOS, 'IXANY'): if self._xonxoff: iflag |= (TERMIOS.IXON | TERMIOS.IXOFF) # |TERMIOS.IXANY) else: iflag &= ~(TERMIOS.IXON | TERMIOS.IXOFF | TERMIOS.IXANY) else: if self._xonxoff: iflag |= (TERMIOS.IXON | TERMIOS.IXOFF) else: iflag &= ~(TERMIOS.IXON | TERMIOS.IXOFF) # rtscts if hasattr(TERMIOS, 'CRTSCTS'): if self._rtscts: cflag |= (TERMIOS.CRTSCTS) else: cflag &= ~(TERMIOS.CRTSCTS) # try it with alternate constant name elif hasattr(TERMIOS, 'CNEW_RTSCTS'): if self._rtscts: cflag |= (TERMIOS.CNEW_RTSCTS) else: cflag &= ~(TERMIOS.CNEW_RTSCTS) # XXX should there be a warning if setting up rtscts (and xonxoff etc) # fails?? # buffer # vmin "minimal number of characters to be read. = for non blocking" if vmin < 0 or vmin > 255: raise ValueError('Invalid vmin: %r ' % vmin) cc[TERMIOS.VMIN] = vmin # vtime if vtime < 0 or vtime > 255: raise ValueError('Invalid vtime: %r' % vtime) cc[TERMIOS.VTIME] = vtime # activate settings termios.tcsetattr(self.fd, TERMIOS.TCSANOW, [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]) # apply custom baud rate, if any if custom_baud is not None: import array buf = array.array('i', [0] * 32) # get serial_struct FCNTL.ioctl(self.fd, TERMIOS.TIOCGSERIAL, buf) # set custom divisor buf[6] = buf[7] / custom_baud # update flags buf[4] &= ~ASYNC_SPD_MASK buf[4] |= ASYNC_SPD_CUST # set serial_struct try: res = FCNTL.ioctl(self.fd, TERMIOS.TIOCSSERIAL, buf) except IOError: raise ValueError('Failed to set custom baud rate: %r' % self._baudrate)
def _reconfigure_port(self, force_update=False): """Set communication parameters on opened port.""" if self.fd is None: raise SerialException( "Can only operate on a valid file descriptor") # if exclusive lock is requested, create it before we modify anything else if self._exclusive is not None: if self._exclusive: try: fcntl.flock(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError as msg: raise SerialException( msg.errno, "Could not exclusively lock port {}: {}".format( self._port, msg)) else: fcntl.flock(self.fd, fcntl.LOCK_UN) custom_baud = None vmin = vtime = 0 # timeout is done via select if self._inter_byte_timeout is not None: vmin = 1 vtime = int(self._inter_byte_timeout * 10) try: orig_attr = termios.tcgetattr(self.fd) iflag, oflag, cflag, lflag, ispeed, ospeed, cc = orig_attr except termios.error as msg: # if a port is nonexistent but has a /dev file, it'll fail here raise SerialException("Could not configure port: {}".format(msg)) # set up raw mode / no echo / binary cflag |= (termios.CLOCAL | termios.CREAD) lflag &= ~(termios.ICANON | termios.ECHO | termios.ECHOE | termios.ECHOK | termios.ECHONL | termios.ISIG | termios.IEXTEN) # |termios.ECHOPRT for flag in ('ECHOCTL', 'ECHOKE'): # netbsd workaround for Erk if hasattr(termios, flag): lflag &= ~getattr(termios, flag) oflag &= ~(termios.OPOST | termios.ONLCR | termios.OCRNL) iflag &= ~(termios.INLCR | termios.IGNCR | termios.ICRNL | termios.IGNBRK) if hasattr(termios, 'IUCLC'): iflag &= ~termios.IUCLC if hasattr(termios, 'PARMRK'): iflag &= ~termios.PARMRK # setup baud rate try: ispeed = ospeed = getattr(termios, 'B{}'.format(self._baudrate)) except AttributeError: try: ispeed = ospeed = self.BAUDRATE_CONSTANTS[self._baudrate] except KeyError: #~ raise ValueError('Invalid baud rate: %r' % self._baudrate) # may need custom baud rate, it isn't in our list. ispeed = ospeed = getattr(termios, 'B38400') try: custom_baud = int(self._baudrate) # store for later except ValueError: raise ValueError('Invalid baud rate: {!r}'.format( self._baudrate)) else: if custom_baud < 0: raise ValueError('Invalid baud rate: {!r}'.format( self._baudrate)) # setup char len cflag &= ~termios.CSIZE if self._bytesize == 8: cflag |= termios.CS8 elif self._bytesize == 7: cflag |= termios.CS7 elif self._bytesize == 6: cflag |= termios.CS6 elif self._bytesize == 5: cflag |= termios.CS5 else: raise ValueError('Invalid char len: {!r}'.format(self._bytesize)) # setup stop bits if self._stopbits == serialutil.STOPBITS_ONE: cflag &= ~(termios.CSTOPB) elif self._stopbits == serialutil.STOPBITS_ONE_POINT_FIVE: cflag |= (termios.CSTOPB ) # XXX same as TWO.. there is no POSIX support for 1.5 elif self._stopbits == serialutil.STOPBITS_TWO: cflag |= (termios.CSTOPB) else: raise ValueError('Invalid stop bit specification: {!r}'.format( self._stopbits)) # setup parity iflag &= ~(termios.INPCK | termios.ISTRIP) if self._parity == serialutil.PARITY_NONE: cflag &= ~(termios.PARENB | termios.PARODD | CMSPAR) elif self._parity == serialutil.PARITY_EVEN: cflag &= ~(termios.PARODD | CMSPAR) cflag |= (termios.PARENB) elif self._parity == serialutil.PARITY_ODD: cflag &= ~CMSPAR cflag |= (termios.PARENB | termios.PARODD) elif self._parity == serialutil.PARITY_MARK and CMSPAR: cflag |= (termios.PARENB | CMSPAR | termios.PARODD) elif self._parity == serialutil.PARITY_SPACE and CMSPAR: cflag |= (termios.PARENB | CMSPAR) cflag &= ~(termios.PARODD) else: raise ValueError('Invalid parity: {!r}'.format(self._parity)) # setup flow control # xonxoff if hasattr(termios, 'IXANY'): if self._xonxoff: iflag |= (termios.IXON | termios.IXOFF) # |termios.IXANY) else: iflag &= ~(termios.IXON | termios.IXOFF | termios.IXANY) else: if self._xonxoff: iflag |= (termios.IXON | termios.IXOFF) else: iflag &= ~(termios.IXON | termios.IXOFF) # rtscts if hasattr(termios, 'CRTSCTS'): if self._rtscts: cflag |= (termios.CRTSCTS) else: cflag &= ~(termios.CRTSCTS) elif hasattr(termios, 'CNEW_RTSCTS'): # try it with alternate constant name if self._rtscts: cflag |= (termios.CNEW_RTSCTS) else: cflag &= ~(termios.CNEW_RTSCTS) # XXX should there be a warning if setting up rtscts (and xonxoff etc) fails?? # buffer # vmin "minimal number of characters to be read. 0 for non blocking" if vmin < 0 or vmin > 255: raise ValueError('Invalid vmin: {!r}'.format(vmin)) cc[termios.VMIN] = vmin # vtime if vtime < 0 or vtime > 255: raise ValueError('Invalid vtime: {!r}'.format(vtime)) cc[termios.VTIME] = vtime # activate settings if force_update or [iflag, oflag, cflag, lflag, ispeed, ospeed, cc ] != orig_attr: termios.tcsetattr(self.fd, termios.TCSANOW, [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]) # apply custom baud rate, if any if custom_baud is not None: self._set_special_baudrate(custom_baud) if self._rs485_mode is not None: self._set_rs485_mode(self._rs485_mode)