async def _reconfigure_port(self): """Set communication parameters on opened port.""" if self._socket is None: raise SerialException("Can only operate on open ports") # Setup the connection # to get good performance, all parameter changes are sent first... if not 0 < self._baudrate < 2 ** 32: raise ValueError("invalid baudrate: {!r}".format(self._baudrate)) await self._rfc2217_port_settings['baudrate'].set(struct.pack(b'!I', self._baudrate)) await self._rfc2217_port_settings['datasize'].set(struct.pack(b'!B', self._bytesize)) await self._rfc2217_port_settings['parity'].set(struct.pack(b'!B', RFC2217_PARITY_MAP[self._parity])) await self._rfc2217_port_settings['stopsize'].set(struct.pack(b'!B', RFC2217_STOPBIT_MAP[self._stopbits])) # and now wait until parameters are active items = list(self._rfc2217_port_settings.values()) self.logger.debug("Negotiating settings: {}".format(items)) async def wait(): for o in items: await o.active_event.wait() try: await asyncio.wait_for(wait(), self._network_timeout) except asyncio.TimeoutError: raise SerialException( "Remote does not accept parameter change (RFC2217): {!r}".format(items)) self.logger.info("Negotiated settings: {}".format(items)) if self._rtscts and self._xonxoff: raise ValueError('xonxoff and rtscts together are not supported') elif self._rtscts: await self.rfc2217_set_control(SET_CONTROL_USE_HW_FLOW_CONTROL) elif self._xonxoff: await self.rfc2217_set_control(SET_CONTROL_USE_SW_FLOW_CONTROL) else: await self.rfc2217_set_control(SET_CONTROL_USE_NO_FLOW_CONTROL)
def from_url(self, url): """\ extract host and port from an URL string, other settings are extracted an stored in instance """ parts = urllib.parse.urlsplit(url) if parts.scheme != "rfc2217": raise SerialException( 'expected a string in the form ' '"rfc2217://<host>:<port>[?option[&option...]]": ' 'not starting with rfc2217:// ({!r})'.format(parts.scheme)) try: # process options now, directly altering self for option, values in urllib.parse.parse_qs( parts.query, True).items(): if option == 'logging': self.logger.setLevel(LOGGER_LEVELS[values[0]]) self.logger.debug('enabled logging') elif option == 'ign_set_control': self._ignore_set_control_answer = True elif option == 'poll_modem': self._poll_modem_state = True elif option == 'timeout': self._network_timeout = float(values[0]) else: raise ValueError('unknown option: {!r}'.format(option)) if not 0 <= parts.port < 65536: raise ValueError("port not in range 0...65535") except ValueError as e: raise SerialException( 'expected a string in the form ' '"rfc2217://<host>:<port>[?option[&option...]]": {}'.format(e)) return (parts.hostname, parts.port)
def open(self): """Open the initialized serial port""" if self._port is None: raise SerialException("Port must be configured before use.") if self.isOpen(): raise SerialException("Port is already open.") self._dump = False self.sock = None try: self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) filename = self.portstr[self.portstr.index('://')+3:] if filename.startswith('~/'): home = os.getenv('HOME') if home: filename = os.path.join(home, filename[2:]) self._filename = filename self.sock.connect(self._filename) except Exception as e: self.close() msg = "Could not open port: %s" % (str(e),) if isinstance(e, socket.error): raise SerialExceptionWithErrno(msg, e.errno) else: raise SerialException(msg) self._set_open_state(True) self._lastdtr = None
def open(self, devclass, scheme, vdict, pdict, default_vendor): """Open the initialized serial port""" from serial import SerialException if self._port is None: raise SerialException("Port must be configured before use.") try: vendor, product, interface, sernum, ix = UsbTools.parse_url( self.portstr, devclass, scheme, vdict, pdict, default_vendor) except UsbToolsError, e: raise SerialException(str(e))
def read(self, size=1): """\ Read size bytes from the serial port. If 'timeout' or 'inter_byte_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 = self._timeout while len(read) < size: try: start_time = time.time() ready, _, _ = select.select([self.fd, self.pipe_abort_read_r], [], [], timeout) 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 EAGAIN errors. all other errors are shown if e.errno != errno.EAGAIN and e.errno != errno.EINTR: raise SerialException('read failed: {}'.format(e)) except select.error as e: # this is for Python 2.x # ignore EAGAIN errors. all other errors are shown # see also http://www.python.org/dev/peps/pep-3151/#select if e[0] != errno.EAGAIN: raise SerialException('read failed: {}'.format(e)) if self._inter_byte_timeout is not None: # Use byte timeout for remaining reads timeout = self._inter_byte_timeout elif timeout is not None: timeout -= time.time() - start_time if timeout <= 0: break return bytes(read)
def open(self): """Open the initialized serial port""" if self.port is None: raise SerialException("Port must be configured before use.") try: device = Ftdi.create_from_url(self.port) except (UsbToolsError, IOError) as ex: raise SerialException('Unable to open USB port %s: %s' % (self.portstr, str(ex))) self.udev = device self._set_open_state(True) self._reconfigure_port()
def _configure(self, serial): if self._configured: return res = self._cmd(serial, _seq(_PASSIVE_CODES), 10) if res[0:3] != b"\xAA\xC5\x02" or _check(res): raise SerialException("Incorrect response: {}".format(res.hex())) res = self._cmd(serial, _seq(_SETWORK_CODES), 10) if res[0:3] != b"\xAA\xC5\x06" or _check(res): raise SerialException("Incorrect response: {}".format(res.hex())) res = self._cmd(serial, _seq(_SETCONT_CODES), 10) if res[0:3] != b"\xAA\xC5\x08" or _check(res): raise SerialException("Incorrect response: {}".format(res.hex())) self._configured = True
def readFromSerial(self,numBytes,start='',max_discard = 1000): """ Read total of numBytes, starting with start string (inclusive) """ f_ord = lambda x: map(ord,list(x)) try: L = len(start) output = '' count = 0 firstError = True while output != start: new_byte = self.ser.read(1) output += new_byte count += 1 if len(output)==0: if firstError: self.logger.error('Serial port unresponsive') firstError = False self.logger.warning('WARNING: serial port timed out; check to make sure line receiver turned on (waiting for %s)' % start) count -= 1 if len(new_byte)==0: raise SerialException("Nothing returned from serial port, waiting for %s" % start) output = output[-L:] if count > L: self.logger.info('Serial: need: %s (%s); current: %s; discard #: %d' % (f_ord(start),start,f_ord(output),count - L)) if count-L > max_discard: return None output += self.ser.read(numBytes-L) if len(output) == 0: raise SerialException("Nothing read from serial port") if len(output)!=numBytes: self.logger.error("Expected %d, but read %d from serial port" % (numBytes, len(output))) #raise SerialException("Incorrect number of bytes returned from serial port") return output else: return output except SerialException, se: #keep going in preamble, often just off by one byte in reading output at beginning #(so only throw error if in main loop) if self.running: self.logger.exception('Serial exception occurred: %s') raise SerialException("Serial Exception") else: self.logger.info('%s; not in main loop, so ignoring' % se)
def validatePozyx(self): """Validates whether the connected device is indeed a Pozyx device""" whoami = SingleRegister() if self.getWhoAmI(whoami) != POZYX_SUCCESS: self.printTrace() raise SerialException( "Connected to device, but couldn't read serial data. Is it a Pozyx?" ) if whoami.value != 0x43: self.printTrace() raise SerialException( "POZYX_WHO_AM_I returned 0x%0.2x, something is wrong with Pozyx." % whoami.value)
def read_frame(con): # We read 16 bytes at a time, because that's the size of the struct that the arduino is sending. # 2 bytes (unsigned) time # 12 bytes (signed) reading # 1 byte (unsigned) flags # 1 byte (unsigned) checksum (XOR) frame_size = 16 raw_frame = con.read(frame_size) if len(raw_frame) < frame_size: raise SerialException( 'Timeout occurred. Perhaps the board was disconnected.') # Struct (module) lets us restore data from structures automatically using a format string to tell it the struct members. # The result is put into a tuple. # Arduino is little endian, so we use '<'. # B = uint8 | H = uint16 | h = int16. unpacked_frame = struct.unpack('<HhhhhhhBB', raw_frame) flag_byte = unpacked_frame[7] flag_dict = { # If transmission is over. 'end': get_bit(flag_byte, 0), # What sensor this frame is from. We combine two bits (two's place and unit's place). 'sensor': (2 * get_bit(flag_byte, 2)) + get_bit(flag_byte, 1), # If the button was pressed during this frame. 'button': get_bit(flag_byte, 7) } flag = Flag(**flag_dict) reading = Reading(*[unpacked_frame[i] for i in range(1, 7)]) frame = Frame(time=unpacked_frame[0], reading=reading, flag=flag) return raw_frame, frame
def read_all(self): for _ in range(2): try: return self.__serial.read_all() except (SerialException, OSError): self.__connect() raise SerialException("read_all failed")
def _open(self) -> None: """Open the serial port. Only useful if you closed it.""" if not self.serial.isOpen(): self._find_port_number() try: self.serial.open() except SerialException: raise SerialException( "Must close previous Illuminate connection before " "establishing a new one. If there is a previous instance " "of Illuminate either delete the object or call the " "'close' method.") try: self._open_startup_procedure() except Exception: self.serial.close() raise # Reset cached variables self._led_positions = None self._help = None # get/set firmware constants self.maximum_current = self._maximum_current
async def get_modem_state(self): """\ get last modem state (cached value. If value is "old", request a new one. This cache helps that we don't issue to many requests when e.g. all status lines, one after the other is queried by the user (CTS, DSR etc.) """ # active modem state polling enabled? is the value fresh enough? if self._poll_modem_state and self._modemstate_timeout.expired(): self.logger.debug('polling modem state') # when it is older, request an update await self.rfc2217_send_subnegotiation(NOTIFY_MODEMSTATE) timeout = Timeout(self._network_timeout) while not timeout.expired(): await asyncio.sleep(0.05) # prevent 100% CPU load # when expiration time is updated, it means that there is a new # value if not self._modemstate_timeout.expired(): break else: self.logger.warning('poll for modem state failed') # even when there is a timeout, do not generate an error just # return the last known value. this way we can support buggy # servers that do not respond to polls, but send automatic # updates. if self._modemstate is not None: self.logger.debug('using cached modem state') return self._modemstate else: # never received a notification from the server raise SerialException("remote sends no NOTIFY_MODEMSTATE")
def connectToPozyx(self, port, baudrate, timeout, write_timeout): """Attempts to connect to the Pozyx via a serial connection""" try: if is_correct_pyserial_version(): if not is_pozyx(port) and not self.suppress_warnings: warn( "The passed device is not a recognized Pozyx device, is %s" % get_port_object(port).description, stacklevel=2) self.ser = Serial(port=port, baudrate=baudrate, timeout=timeout, write_timeout=write_timeout) else: if not self.suppress_warnings: warn( "PySerial version %s not supported, please upgrade to 3.0 or (prefferably) higher" % PYSERIAL_VERSION, stacklevel=0) self.ser = Serial(port=port, baudrate=baudrate, timeout=timeout, writeTimeout=write_timeout) except SerialException as exc: self.printTrace() raise SerialException( "Wrong or busy serial port, SerialException:" + str(exc)) except Exception as exc: self.printTrace() raise type(exc)("Couldn't connect to Pozyx, unknown exception:" + str(exc))
def __connection(self): """ Switch the CL-200A to PC connection mode. (Command "54"). In order to perform communication with a PC, this command must be used to set the CL-200A to PC connection mode. :return: None """ # cmd_request = CL200A_utils.cmd_formatter(self.CL200A_utils.cl200a_cmd_dict['command_54']) cmd_request = chr(2) + '00541 ' + chr(3) + '13\r\n' cmd_response = CL200A_utils.cmd_formatter(self.cmd_dict['command_54r']) for i in range(2): CL200A_utils.write_serial_port(obj=self, ser=self.ser, cmd=cmd_request, sleep_time=0.5) pc_connected_mode = self.ser.readline().decode('ascii') self.ser.reset_input_buffer() self.ser.reset_output_buffer() # Check that the response from the CL-200A is correct. if SKIP_CHECK_LIST: break else: if cmd_response in pc_connected_mode: break elif i == 0: logs.logger.warn(f'Error: Attempt one more time') continue else: raise SerialException( 'Konica Minolta CL-200A has an error. Please verify USB cable.' )
def connect(self): Logger.log("i", "connecting") if self.getConnectionState() is ConnectionState.closed: self.setConnectionState(ConnectionState.connecting) if self._baud_rate is None: if self._use_auto_detect: auto_detect_job = AutoDetectBaudJob(self._serial_port) auto_detect_job.start() auto_detect_job.finished.connect(self._autoDetectFinished) return if self._serial is None: try: self._serial = Serial(str(self._serial_port), self._baud_rate, timeout=self._timeout, writeTimeout=self._timeout) self.setConnectionState(ConnectionState.connected) except SerialException: Logger.log( "w", "An exception occured while trying to create serial connection" ) ##FIXME - send printer response self.setConnectionState(ConnectionState.error) raise SerialException( "could not open serial port {}: {}".format( self._serial_port, repr(e))) return
def choose_port(): """ Provides a simple menu for selecting a serial port :raises SerialException: If no ports are found :returns: The selected port """ ports = s.list_serial_ports() if not ports: raise SerialException( "No open serial ports could be found. Check the connections.") print("The following ports were detected:") for index, port in enumerate(ports, start=1): print('PORT', str(index) + ":", port) while True: print('Choose a port (type the number, e.g. 1)') try: selected = int(input('PORT ')) if not (1 <= selected <= len(ports)): raise ValueError() break except ValueError: print("You must enter a valid number") return ports[selected - 1]
def _send(self, message, expected_response): """ Sends message to serial device and verifies if expected_response was returned :param message: message to send :type message: str :param expected_response: response the serial device is expected to return :type expected_response: str """ for _ in range(3): response = self.ser.send(message) if response == expected_response.encode("utf-8"): self._logger.debug("Received expected response %s", repr(response)) return elif response == b"Unknown command. Will not show anything\r\n": self._logger.warning("Unknown command %s", message) return self._logger.debug( "Expected response %s but received %s", repr(expected_response), repr(response), ) self._logger.warning( "Failed to send '%s' - resetting serial connection", message) self.ser.reset() self._logger.critical("Failed to send '%s' after 3 retries", message) raise SerialException("Expected response {} but received {}".format( repr(expected_response), repr(response)))
class UsbSerial(SerialBase): """Base class for Serial port implementation compatible with pyserial API using a USB device. """ BAUDRATES = sorted([9600 * (x + 1) for x in range(6)] + range(115200, 1000000, 115200) + range(1000000, 13000000, 100000)) def makeDeviceName(self, port): return port def open(self, devclass, scheme, vdict, pdict, default_vendor): """Open the initialized serial port""" from serial import SerialException if self._port is None: raise SerialException("Port must be configured before use.") try: vendor, product, interface, sernum, ix = UsbTools.parse_url( self.portstr, devclass, scheme, vdict, pdict, default_vendor) except UsbToolsError, e: raise SerialException(str(e)) try: self.udev = devclass() self.udev.open(vendor, product, interface, ix, sernum) except IOError: raise SerialException('Unable to open USB port %s' % self.portstr) self._isOpen = True self._reconfigurePort() self._product = product
def test_fail_to_open_serial_port(self, serial_port_mock: Mock) -> None: serial_port_mock.is_open = False serial_port_mock.open.side_effect = SerialException( "Cannot open serial port") with self.assertRaises(SerialException): with TestSerialPowerSupply("/dev/ttyUSB0", 9600) as power_supply: power_supply.get_mode()
def read(self): """ Request a sample of data from the device. This method blocks (calls ``time.sleep()``) to emulate other data acquisition units which wait for the requested number of samples to be read. The amount of time to block is dependent on rate and on the samples_per_read. Calls will return with relatively constant frequency, assuming calls occur faster than required (i.e. processing doesn't fall behind). Returns ------- data : ndarray, shape=(n_pins, samples_per_read) Data read from the device. Each pin is a row and each column is a point in time. """ if self._flag: while (not self._data_ready): # cannot time smaller than 10 - 15 ms in Windows # this delays copying a chunk, not reading samples time.sleep(0.01) with self._lock: data = self._data self._data_ready = False # s = self._sample # self._debug_print.print(s) return data else: raise SerialException("Serial port is closed.")
def read(self, size=1): for _ in range(2): try: return self.__serial.read(size) except (SerialException, OSError): self.__connect() raise SerialException("read failed")
class TestDevice(unittest.TestCase): @patch('buoy.client.device.common.base.Serial', side_effect=SerialException()) def test_shouldReturnException_when_theDeviceIsNotPresent(self, mock_serial): serial_config = { 'port': '/dev/weather_station', 'baudrate': 4800, 'stopbits': 1, 'parity': 'N', 'bytesize': 8, 'timeout': 0 } device = Device(device_name="test", db=None, serial_config=serial_config) self.assertRaises(DeviceNoDetectedException, device.connect) @patch.object(Device, 'is_open', return_value=True) def test_shouldReturnException_when_existsExceptionsInQueue(self, mock_is_open): ex = DeviceNoDetectedException(exception=Exception()) serial_config = { 'port': '/dev/weather_station', 'baudrate': 4800, 'stopbits': 1, 'parity': 'N', 'bytesize': 8, 'timeout': 0 } device = Device(device_name="test", db=None, serial_config=serial_config) device.queues['notice'].put_nowait(ex) self.assertRaises(DeviceNoDetectedException, device._listener_exceptions)
def test_basic(self, wait_tty): """Test basic functions of a zigduino node.""" # Node status always returns 0 assert self.node.status() == 0 # programmer instance assert self.node.programmer == self.node.avrdude # Reset the node wait_tty.return_value = 0 assert self.node.reset() == 0 wait_tty.assert_called_once() # Reset with OSError raise by serial setDTR => just a warning is # displayed wait_tty.call_count = 0 self.serial.return_value.close = Mock(side_effect=OSError()) assert self.node.reset() == 0 assert wait_tty.call_count == 1 # Reset with serial error wait_tty.call_count = 0 self.serial.side_effect = SerialException('Error') assert self.node.reset() == 1 assert wait_tty.call_count == 0
def read(self, count): result = self.serial.read(count) if len(result) < count: raise SerialException( "Did read less than expected (expected %d, got only %d), maybe timeout problem." % (count, len(result))) return result
def test_connection_error(self, serial_for_url_mock): """ Connection error. """ serial_for_url_mock.side_effect = SerialException('Something happened') generator = dsmr_datalogger.scripts.dsmr_datalogger_api_client.read_telegram( url_or_port='/dev/X', telegram_timeout=999) with self.assertRaises(RuntimeError): next(generator)
def __init__(self, ttyStr): try: self.ttyStr = ttyStr self.usb = serial.Serial(ttyStr) self.usb.baudrate = 9600 except SerialException as se: raise SerialException("Failed to setup relay: {}".format( se.message)) self.channels = [1, 2]
def init_device(devtype, armdev): """ Initialization of microscope and arm :param devtype: controller :param armdev: devices controlling the arm :return: """ if devtype == 'SM5': try: dev = LuigsNeumann_SM5('COM3') devmic = Leica() microscope = XYMicUnit(dev, devmic, [7, 8]) except: raise SerialException("L&N SM-5 not found.") elif devtype == 'SM10': try: dev = LuigsNeumann_SM10() microscope = XYZUnit(dev, [7, 8, 9]) except SerialException: raise SerialException("L&N SM-10 not found.") else: raise SerialException("No supported device detected") if armdev == 'dev1': arm = XYZUnit(dev, [1, 2, 3]) elif armdev == 'dev2': arm = XYZUnit(dev, [4, 5, 6]) elif armdev == 'Arduino': try: # arduino = appel classe manipulateur arduino #arm = XYZUnit(arduino, [1, 2, 3]) arm = 0 except SerialException: raise SerialException("Arduino not found.") else: raise NameError('Unknown device for arm control.') # Adjust ramp length for accuracy microscope.set_ramp_length([0, 1, 2], 3) arm.set_ramp_length([0, 1, 2], 3) return dev, microscope, arm
async def _read(self, size=1): data = bytearray() while len(data) < size: if self._thread is None or self._thread.done(): raise SerialException('connection failed (reader thread died)') buf = await self._read_buffer.get() if buf is None: break data += buf return bytes(data)
def test_read_3(self, count) -> bytes: data = [] if self.run == 0: data = [0xfe, 0x0d, 0x1e] if self.run == 1: raise SerialException('Attempting to use a port that is not open') result = bytes(data) self.run += 1 return result
def __init__(self, message, errno=None): SerialException.__init__(self, message) self.errno = errno