def connect(self, timeout=None): """Connect to KATCP interface, starting what is needed Parameters ---------- timeout : float, None Time to wait until connected. No waiting if None. Raises ------ :class:`tornado.gen.TimeoutError` if the connect timeout expires """ # Start KATCP device client. assert not self._running maybe_timeout = future_timeout_manager(timeout) self._logger.debug('Starting katcp client') self.katcp_client.start() try: yield maybe_timeout(self.katcp_client.until_running()) self._logger.debug('Katcp client running') except tornado.gen.TimeoutError: self.katcp_client.stop() raise if timeout: yield maybe_timeout(self.katcp_client.until_connected()) self._logger.debug('Katcp client connected') self._running = True self._state_loop()
def inspect(self): timeout_manager = future_timeout_manager(self.sync_timeout) request_changes = yield self.inspect_requests(timeout=timeout_manager.remaining()) sensor_changes = yield self.inspect_sensors(timeout=timeout_manager.remaining()) model_changes = AttrDict() if request_changes: model_changes.requests = request_changes if sensor_changes: model_changes.sensors = sensor_changes if model_changes: raise Return(model_changes)
def inspect(self): """Inspect device requests and sensors, update model Returns ------- Tornado future that resolves with: model_changes : Nested AttrDict or None Contains sets of added/removed request/sensor names Example structure: {'requests': { 'added': set(['req1', 'req2']), 'removed': set(['req10', 'req20'])} 'sensors': { 'added': set(['sens1', 'sens2']), 'removed': set(['sens10', 'sens20'])} } If there are no changes keys may be omitted. If an item is in both the 'added' and 'removed' sets that means that it changed. If neither request not sensor changes are present, None is returned instead of a nested structure. """ timeout_manager = future_timeout_manager(self.sync_timeout) sensor_index_before = copy.copy(self._sensors_index) request_index_before = copy.copy(self._requests_index) try: request_changes = yield self.inspect_requests( timeout=timeout_manager.remaining()) sensor_changes = yield self.inspect_sensors( timeout=timeout_manager.remaining()) except Exception: # Ensure atomicity of sensor and request updates ; if the one # fails, the other should act as if it has failed too. self._sensors_index = sensor_index_before self._requests_index = request_index_before raise model_changes = AttrDict() if request_changes: model_changes.requests = request_changes if sensor_changes: model_changes.sensors = sensor_changes if model_changes: raise Return(model_changes)
def inspect(self): """Inspect device requests and sensors, update model""" timeout_manager = future_timeout_manager(self.sync_timeout) sensor_index_before = copy.copy(self._sensors_index) request_index_before = copy.copy(self._requests_index) try: request_changes = yield self.inspect_requests(timeout=timeout_manager.remaining()) sensor_changes = yield self.inspect_sensors(timeout=timeout_manager.remaining()) except Exception: # Ensure atomicity of sensor and request updates ; if the one # fails, the other should act as if it has failed too. self._sensors_index = sensor_index_before self._requests_index = request_index_before raise model_changes = AttrDict() if request_changes: model_changes.requests = request_changes if sensor_changes: model_changes.sensors = sensor_changes if model_changes: raise Return(model_changes)
def inspect_requests(self, name=None, timeout=None): """Inspect all or one requests on the device. Update requests index. Parameters ---------- name : str or None, optional Name of the request or None to get all requests. timeout : float or None, optional Timeout for request inspection, None for no timeout Returns ------- Tornado future that resolves with: changes : :class:`~katcp.core.AttrDict` AttrDict with keys ``added`` and ``removed`` (of type :class:`set`), listing the requests that have been added or removed respectively. Modified requests are listed in both. If there are no changes, returns ``None`` instead. Example structure: {'added': set(['req1', 'req2']), 'removed': set(['req10', 'req20'])} """ maybe_timeout = future_timeout_manager(timeout) if name is None: msg = katcp.Message.request('help') else: msg = katcp.Message.request('help', name) reply, informs = yield self.katcp_client.future_request( msg, timeout=maybe_timeout.remaining()) if not reply.reply_ok(): # If an unknown request is specified the desired result is to return # an empty list even though the request will fail if name is None or 'Unknown request' not in reply.arguments[1]: raise SyncError( 'Error reply during sync process for {}: {}'.format( self.bind_address_string, reply)) # Get recommended timeouts hints for slow requests if the server # provides them timeout_hints_available = ( self.katcp_client.protocol_flags.request_timeout_hints) if timeout_hints_available: timeout_hints = yield self._get_request_timeout_hints( name, timeout=maybe_timeout.remaining()) else: timeout_hints = {} requests_old = set(self._requests_index.keys()) requests_updated = set() for msg in informs: req_name = msg.arguments[0] req = { 'name': req_name, 'description': msg.arguments[1], 'timeout_hint': timeout_hints.get(req_name) } requests_updated.add(req_name) self._update_index(self._requests_index, req_name, req) added, removed = self._difference(requests_old, requests_updated, name, self._requests_index) if added or removed: raise Return(AttrDict(added=added, removed=removed))