class KatportalClientWrapper(object): def __init__(self, host, callback=None): self._client = KATPortalClient(host, on_update_callback=callback, logger=logging.getLogger('katcp')) @coroutine def _query(self, component, sensor): log.debug("Querying sensor '{}' on component '{}'".format( sensor, component)) sensor_name = yield self._client.sensor_subarray_lookup( component=component, sensor=sensor, return_katcp_name=False) log.debug("Found sensor name: {}".format(sensor_name)) sensor_sample = yield self._client.sensor_value(sensor_name, include_value_ts=False) log.debug("Sensor value: {}".format(sensor_sample)) raise Return(sensor_sample) @coroutine def get_observer_string(self, antenna): sensor_sample = yield self._query(antenna, "observer") raise Return(sensor_sample.value) @coroutine def get_observer_strings(self, antennas): query = "^({})_observer".format("|".join(antennas)) log.debug("Regex query '{}'".format(query)) sensor_samples = yield self._client.sensor_values( query, include_value_ts=False) log.debug("Sensor value: {}".format(sensor_samples)) antennas = {} for key, value in sensor_samples.items(): antennas[key.strip("_observer")] = value.value raise Return(antennas) @coroutine def get_antenna_feng_id_map(self, instrument_name, antennas): sensor_sample = yield self._query( 'cbf', '{}.input-labelling'.format(instrument_name)) labels = eval(sensor_sample.value) mapping = {} for input_label, input_index, _, _ in labels: antenna_name = input_label.strip("vh").lower() if antenna_name.startswith("m") and antenna_name in antennas: mapping[antenna_name] = input_index // 2 raise Return(mapping) @coroutine def get_bandwidth(self, stream): sensor_sample = yield self._query( 'sub', 'streams.{}.bandwidth'.format(stream)) raise Return(sensor_sample.value) @coroutine def get_cfreq(self, stream): sensor_sample = yield self._query( 'sub', 'streams.{}.centre-frequency'.format(stream)) raise Return(sensor_sample.value) @coroutine def get_sideband(self, stream): sensor_sample = yield self._query('sub', 'streams.{}.sideband'.format(stream)) raise Return(sensor_sample.value) @coroutine def get_sync_epoch(self): sensor_sample = yield self._query('sub', 'synchronisation-epoch') raise Return(sensor_sample.value) @coroutine def get_itrf_reference(self): sensor_sample = yield self._query('sub', 'array-position-itrf') x, y, z = [float(i) for i in sensor_sample.value.split(",")] raise Return((x, y, z))
class KatportalClientWrapper(object): def __init__(self, host, callback=None): self._host = host self._client = KATPortalClient(host, on_update_callback=callback, logger=logging.getLogger('katcp')) @coroutine def _query(self, component, sensor, include_value_ts=False): log.debug("Querying sensor '{}' on component '{}'".format( sensor, component)) sensor_name = yield self._client.sensor_subarray_lookup( component=component, sensor=sensor, return_katcp_name=False) log.debug("Found sensor name: {}".format(sensor_name)) sensor_sample = yield self._client.sensor_value( sensor_name, include_value_ts=include_value_ts) log.debug("Sensor value: {}".format(sensor_sample)) if sensor_sample.status != Sensor.STATUSES[Sensor.NOMINAL]: message = "Sensor {} not in NOMINAL state".format(sensor_name) log.error(message) raise Exception(sensor_name) raise Return(sensor_sample) @coroutine def get_observer_string(self, antenna): sensor_sample = yield self._query(antenna, "observer") raise Return(sensor_sample.value) @coroutine def get_observer_strings(self, antennas): query = "^({})_observer".format("|".join(antennas)) log.debug("Regex query '{}'".format(query)) sensor_samples = yield self._client.sensor_values( query, include_value_ts=False) log.debug("Sensor value: {}".format(sensor_samples)) antennas = {} for key, value in sensor_samples.items(): antennas[key.strip("_observer")] = value.value raise Return(antennas) @coroutine def get_antenna_feng_id_map(self, instrument_name, antennas): sensor_sample = yield self._query( 'cbf', '{}.input-labelling'.format(instrument_name)) labels = eval(sensor_sample.value) mapping = {} for input_label, input_index, _, _ in labels: antenna_name = input_label.strip("vh").lower() if antenna_name.startswith("m") and antenna_name in antennas: mapping[antenna_name] = input_index // 2 raise Return(mapping) @coroutine def get_bandwidth(self, stream): sensor_sample = yield self._query( 'sub', 'streams.{}.bandwidth'.format(stream)) raise Return(sensor_sample.value) @coroutine def get_cfreq(self, stream): sensor_sample = yield self._query( 'sub', 'streams.{}.centre-frequency'.format(stream)) raise Return(sensor_sample.value) @coroutine def get_sideband(self, stream): sensor_sample = yield self._query('sub', 'streams.{}.sideband'.format(stream)) raise Return(sensor_sample.value) @coroutine def get_sync_epoch(self): sensor_sample = yield self._query('sub', 'synchronisation-epoch') raise Return(sensor_sample.value) @coroutine def get_itrf_reference(self): sensor_sample = yield self._query('sub', 'array-position-itrf') x, y, z = [float(i) for i in sensor_sample.value.split(",")] raise Return((x, y, z)) @coroutine def get_proposal_id(self): sensor_sample = yield self._query('sub', 'script-proposal-id') raise Return(sensor_sample.value) @coroutine def get_sb_id(self): sensor_sample = yield self._query('sub', 'script-experiment-id') raise Return(sensor_sample.value) @coroutine def get_telstate(self, key='_wide_'): sensor_sample = yield self._query('sdp', 'subarray-product-ids') products = sensor_sample.value.split(",") for product in products: print product if key in product: product_id = product break else: raise SDPWideProductNotFound sensor_sample = yield self._query( 'sdp', 'spmc_{}_telstate_telstate'.format(product_id)) raise Return(sensor_sample.value) @coroutine def get_last_phaseup_timestamp(self): sensor_sample = yield self._query('sub', 'script-last-phaseup', include_value_ts=True) raise Return(sensor_sample.value_time) @coroutine def get_last_delay_cal_timestamp(self): sensor_sample = yield self._query('sub', 'script-last-delay-calibration', include_value_ts=True) raise Return(sensor_sample.value_time) @coroutine def get_last_calibration_timestamp(self): delay_cal_error = None phase_cal_error = None try: delay_cal = yield self.get_last_delay_cal_timestamp() except Exception as error: delay_cal_error = error try: phase_cal = yield self.get_last_phaseup_timestamp() except Exception as error: phase_cal_error = error if phase_cal_error and delay_cal_error: raise Exception( "No valid calibration timestamps: delay error: {}, phaseup error: {}" .format(delay_cal_error, phase_cal_error)) elif phase_cal_error: raise Return(delay_cal) elif delay_cal_error: raise Return(phase_cal) else: raise Return(max(delay_cal, phase_cal)) @coroutine def get_gains(self): val = yield self.get_telstate() telstate_address = "{}:{}".format(*eval(val)) last_calibration = yield self.get_last_calibration_timestamp() telstate = katsdptelstate.TelescopeState(telstate_address) corrections = get_phaseup_corrections(telstate, last_calibration, 1.0, False) raise Return(corrections) @coroutine def get_fbfuse_address(self): sensor_sample = yield self._query('fbfuse', 'fbfmc-address') raise Return(eval(sensor_sample.value)) @coroutine def get_fbfuse_target_config(self, product_id): sensor_list = ["phase-reference", "coherent-beam-shape"] fbf_config = {} fbfuse_proxy = yield self.get_fbfuse_proxy_id() prefix = "{}_fbfmc_{}_".format(fbfuse_proxy, product_id) query = "^{}({})$".format( prefix, "|".join([s.replace("-", "_") for s in sensor_list])) log.debug("Regex query '{}'".format(query)) sensor_samples = yield self._client.sensor_values( query, include_value_ts=False) log.debug("Sensor value: {}".format(sensor_samples)) for sensor_name in sensor_list: full_name = "{}{}".format(prefix, sensor_name.replace("-", "_")) sensor_sample = sensor_samples[full_name] log.debug(sensor_sample) if sensor_sample.status != Sensor.STATUSES[Sensor.NOMINAL]: message = "Sensor {} not in NOMINAL state".format(full_name) log.error(message) raise Exception(sensor_name) else: fbf_config[sensor_name] = sensor_sample.value raise Return(fbf_config) @coroutine def get_fbfuse_sb_config(self, product_id): sensor_list = [ "bandwidth", "nchannels", "centre-frequency", "coherent-beam-count", "coherent-beam-count-per-group", "coherent-beam-ngroups", "coherent-beam-tscrunch", "coherent-beam-fscrunch", "coherent-beam-antennas", "coherent-beam-multicast-groups", "coherent-beam-multicast-group-mapping", "coherent-beam-multicast-groups-data-rate", "coherent-beam-heap-size", "coherent-beam-idx1-step", "coherent-beam-subband-nchans", "coherent-beam-time-resolution", "incoherent-beam-count", "incoherent-beam-tscrunch", "incoherent-beam-fscrunch", "incoherent-beam-antennas", "incoherent-beam-multicast-group", "incoherent-beam-multicast-group-data-rate", "incoherent-beam-heap-size", "incoherent-beam-idx1-step", "incoherent-beam-subband-nchans", "incoherent-beam-time-resolution" ] fbf_config = {} fbfuse_proxy = yield self.get_fbfuse_proxy_id() prefix = "{}_fbfmc_{}_".format(fbfuse_proxy, product_id) query = "^{}({})$".format( prefix, "|".join([s.replace("-", "_") for s in sensor_list])) log.debug("Regex query '{}'".format(query)) sensor_samples = yield self._client.sensor_values( query, include_value_ts=False) log.debug("Sensor value: {}".format(sensor_samples)) for sensor_name in sensor_list: full_name = "{}{}".format(prefix, sensor_name.replace("-", "_")) sensor_sample = sensor_samples[full_name] log.debug(sensor_sample) if sensor_sample.status != Sensor.STATUSES[Sensor.NOMINAL]: message = "Sensor {} not in NOMINAL state".format(full_name) log.error(message) raise Exception(sensor_name) else: fbf_config[sensor_name] = sensor_sample.value raise Return(fbf_config) @coroutine def get_fbfuse_coherent_beam_positions(self, product_id): component = product_id.replace("array", "fbfuse") prefix = "{}_fbfmc_{}_".format(component, product_id) query = "^{}.*cfbf.*$".format(prefix) sensor_samples = yield self._client.sensor_values( query, include_value_ts=False) beams = {} for key, reading in sensor_samples.items(): beam_name = key.split("_")[-1] if reading.status == Sensor.STATUSES[Sensor.NOMINAL]: beams[beam_name] = reading.value raise Return(beams) @coroutine def get_fbfuse_proxy_id(self): sensor_sample = yield self._query('sub', 'allocations') for resource, _, _ in eval(sensor_sample.value): if resource.startswith("fbfuse"): raise Return(resource) else: raise Exception("No FBFUSE proxy found in current subarray") def get_sensor_tracker(self, component, sensor_name): return SensorTracker(self._host, component, sensor_name)