def test_request_add_remove(self):
        """Test a request being added and then remove it."""
        yield self.client.until_synced()

        def request_sparkling_new(self, req, msg):
            """A new command."""
            return Message.reply(msg.name, "ok", "bling1", "bling2")

        # Check that the request did not exist before
        self.assertNotIn('sparkling-new', self.client.requests)

        # Add a request.
        self.server.request_sparkling_new = request_sparkling_new
        self.server._request_handlers['sparkling-new'] = request_sparkling_new
        self.server.mass_inform(Message.inform('interface-changed'))
        # Do a blocking request to ensure #interface-changed has been received
        yield self.client.simple_request('watchdog')

        yield self.client.until_synced()
        self.assertIn('sparkling-new', self.client.requests)
        req = yield self.client.future_get_request('sparkling-new')
        self.assertEqual(req.name, 'sparkling-new')

        # Remove a request.
        self.server.request_sparkling_new = None
        del(self.server._request_handlers['sparkling-new'])
        self.server.mass_inform(Message.inform('interface-changed'))
        # Do a blocking request to ensure #interface-changed has been received
        self.client.simple_request('watchdog')
        yield self.client.until_synced()
        self.assertNotIn('sparkling_new', self.client.requests)
예제 #2
0
    def test_request_add_remove(self):
        """Test a request being added and then remove it."""
        yield self.client.until_synced()

        def request_sparkling_new(self, req, msg):
            """A new command."""
            return Message.reply(msg.name, "ok", "bling1", "bling2")

        # Check that the request did not exist before
        self.assertNotIn('sparkling-new', self.client.requests)

        # Add a request.
        self.server.request_sparkling_new = request_sparkling_new
        self.server._request_handlers['sparkling-new'] = request_sparkling_new
        self.server.mass_inform(Message.inform('interface-changed'))
        # Do a blocking request to ensure #interface-changed has been received
        yield self.client.simple_request('watchdog')

        yield self.client.until_synced()
        self.assertIn('sparkling-new', self.client.requests)
        req = yield self.client.future_get_request('sparkling-new')
        self.assertEqual(req.name, 'sparkling-new')

        # Remove a request.
        self.server.request_sparkling_new = None
        del(self.server._request_handlers['sparkling-new'])
        self.server.mass_inform(Message.inform('interface-changed'))
        # Do a blocking request to ensure #interface-changed has been received
        self.client.simple_request('watchdog')
        yield self.client.until_synced()
        self.assertNotIn('sparkling_new', self.client.requests)
    def test_sensor_add_remove(self):
        """Test a sensor being added and then remove it."""
        yield self.client.until_synced()

        sensor = DeviceTestSensor(Sensor.INTEGER, "another.int",
                                  "An Integer.",
                                  "count", [-5, 5], timestamp=time.time(),
                                  status=Sensor.NOMINAL, value=3)
        # Check that the sensor does not exist currently
        self.assertNotIn(sensor.name, self.client.sensors)

        # Add a sensor.
        self.server.add_sensor(sensor)
        self.server.mass_inform(Message.inform('interface-changed'))
        # Do a blocking request to ensure #interface-changed has been received
        yield self.client.simple_request('watchdog')
        yield self.client.until_synced()
        self.assertIn('another.int', self.client.sensors)

        # Remove a sensor.
        self.server.remove_sensor(sensor)
        self.server.mass_inform(Message.inform('interface-changed'))
        # Do a blocking request to ensure #interface-changed has been received
        yield self.client.simple_request('watchdog')

        yield self.client.until_synced()
        self.assertNotIn('another.int', self.client.sensors)
예제 #4
0
 def callback((informs, reply)):
     self.assertEquals(informs[2:],
           [Message.inform('sensor-value', '1000', '1', 'device.sensor1',
                           'unknown', '0'),
            Message.inform('sensor-value', '0', '1', 'device.sensor2',
                           'unknown', '0')])
     self.assertEquals(reply, Message.reply('sensor-value', 'ok', '4'))
예제 #5
0
    def test_sensor_add_remove(self):
        """Test a sensor being added and then remove it."""
        yield self.client.until_synced()

        sensor = DeviceTestSensor(Sensor.INTEGER, "another.int",
                                  "An Integer.",
                                  "count", [-5, 5], timestamp=time.time(),
                                  status=Sensor.NOMINAL, value=3)
        # Check that the sensor does not exist currently
        self.assertNotIn(sensor.name, self.client.sensors)

        # Add a sensor.
        self.server.add_sensor(sensor)
        self.server.mass_inform(Message.inform('interface-changed'))
        # Do a blocking request to ensure #interface-changed has been received
        yield self.client.simple_request('watchdog')
        yield self.client.until_synced()
        self.assertIn('another.int', self.client.sensors)

        # Remove a sensor.
        self.server.remove_sensor(sensor)
        self.server.mass_inform(Message.inform('interface-changed'))
        # Do a blocking request to ensure #interface-changed has been received
        yield self.client.simple_request('watchdog')

        yield self.client.until_synced()
        self.assertNotIn('another.int', self.client.sensors)
예제 #6
0
    def request_help(self, msg):
        """Return help on the available requests.

        Return a description of the available requests using a seqeunce of #help informs.

        Parameters
        ----------
        request : str, optional
            The name of the request to return help for (the default is to return help for all requests).

        Informs
        -------
        request : str
            The name of a request.
        description : str
            Documentation for the named request.

        Returns
        -------
        success : {'ok', 'fail'}
            Whether sending the help succeeded.
        informs : int
            Number of #help inform messages sent.

        Examples
        --------
        ::

            ?help
            #help halt ...description...
            #help help ...description...
            ...
            !help ok 5

            ?help halt
            #help halt ...description...
            !help ok 1
        """
        if msg.arguments:
            name = msg.arguments[0]
            meth = getattr(self, 'request_' + name.replace('-', '_'), None)
            if meth is None:
                return Message.reply('help', 'fail', 'Unknown request method.')
            doc = meth.__doc__
            if doc is not None:
                doc = doc.strip()
            self.send_message(Message.inform('help', name, doc))
            return Message.reply('help', 'ok', '1')
        count = 0
        for name in dir(self.__class__):
            item = getattr(self, name)
            if name.startswith('request_') and callable(item):
                sname = name[len('request_'):]
                doc = item.__doc__
                if doc is not None:
                    doc = doc.strip()
                self.send_message(Message.inform('help', sname, doc))
                count += 1
        return Message.reply(msg.name, "ok", str(count))
예제 #7
0
 def callback((informs, reply)):
     self.assertEquals(informs[2:], [
         Message.inform('sensor-value', '1000', '1', 'device.sensor1',
                        'unknown', '0'),
         Message.inform('sensor-value', '0', '1', 'device.sensor2',
                        'unknown', '0')
     ])
     self.assertEquals(reply, Message.reply('sensor-value', 'ok', '4'))
예제 #8
0
    def request_version_list(self, msg):
        """Request the list of versions of roles and subcomponents.

        Informs
        -------
        name : str
            Name of the role or component.
        version : str
            A string identifying the version of the component. Individual
            components may define the structure of this argument as they
            choose. In the absence of other information clients should
            treat it as an opaque string.
        build_state_or_serial_number : str
            A unique identifier for a particular instance of a component.
            This should change whenever the component is replaced or updated.

        Returns
        -------
        success : {'ok', 'fail'}
            Whether sending the version list succeeded.
        informs : int
            Number of #version-list inform messages sent.

        Examples
        --------
        ::

            ?version-list
            #version-list katcp-protocol 5.0-MI
            #version-list katcp-library katcp-python-tx-0.4 katcp-python-0.4.1
            #version-list katcp-device foodevice-1.0 foodevice-1.0.0rc1
            !version-list ok 3
        """
        versions = [
            ("katcp-protocol", (self.PROTOCOL_INFO, None)),
            ("katcp-library", ("katcp-python-tx-%d.%d" % VERSION[:2],
                               VERSION_STR)),
            ("katcp-device", (self.version(), self.build_state())),
        ]
        extra_versions = sorted(self.extra_versions.items())

        for name, (version, build_state) in versions + extra_versions:
            if build_state is None:
                inform = Message.inform(msg.name, name, version)
            else:
                inform = Message.inform(msg.name, name, version, build_state)
            self.send_reply_inform(inform, msg)

        num_versions = len(versions) + len(extra_versions)
        return Message.reply(msg.name, "ok", str(num_versions))
예제 #9
0
    def request_version_list(self, msg):
        """Request the list of versions of roles and subcomponents.

        Informs
        -------
        name : str
            Name of the role or component.
        version : str
            A string identifying the version of the component. Individual
            components may define the structure of this argument as they
            choose. In the absence of other information clients should
            treat it as an opaque string.
        build_state_or_serial_number : str
            A unique identifier for a particular instance of a component.
            This should change whenever the component is replaced or updated.

        Returns
        -------
        success : {'ok', 'fail'}
            Whether sending the version list succeeded.
        informs : int
            Number of #version-list inform messages sent.

        Examples
        --------
        ::

            ?version-list
            #version-list katcp-protocol 5.0-MI
            #version-list katcp-library katcp-python-tx-0.4 katcp-python-0.4.1
            #version-list katcp-device foodevice-1.0 foodevice-1.0.0rc1
            !version-list ok 3
        """
        versions = [
            ("katcp-protocol", (self.PROTOCOL_INFO, None)),
            ("katcp-library", ("katcp-python-tx-%d.%d" % VERSION[:2],
                               VERSION_STR)),
            ("katcp-device", (self.version(), self.build_state())),
            ]
        extra_versions = sorted(self.extra_versions.items())

        for name, (version, build_state) in versions + extra_versions:
            if build_state is None:
                inform = Message.inform(msg.name, name, version)
            else:
                inform = Message.inform(msg.name, name, version, build_state)
            self.send_reply_inform(inform, msg)

        num_versions = len(versions) + len(extra_versions)
        return Message.reply(msg.name, "ok", str(num_versions))
예제 #10
0
    def setup_sensors(self):
        """
        @brief    Setup the default KATCP sensors.

        @note     As this call is made only upon an PAF configure call a mass inform
                  is required to let connected clients know that the proxy interface has
                  changed.
        """
        self._state_sensor = LoggingSensor.discrete(
            "state",
            description="Denotes the state of this PAF instance",
            params=self.STATES,
            default=self.IDLE,
            initial_status=Sensor.NOMINAL)
        self._state_sensor.set_logger(self.log)
        self.add_sensor(self._state_sensor)

        self._servers_sensor = Sensor.string(
            "servers",
            description=
            "The worker server instances currently allocated to this product",
            default=",".join([
                "{s.hostname}:{s.port}".format(s=server)
                for server in self._servers
            ]),
            initial_status=Sensor.UNKNOWN)
        self.add_sensor(self._servers_sensor)
        self._parent.mass_inform(Message.inform('interface-changed'))
        self._state_sensor.set_value(self.IDLE)
예제 #11
0
 def request_foo(self, msg):
     """ This is called when ?foo is called from the other side.
     """
     # send one inform
     self.send_message(Message.inform('foo', 'fine'))
     # return reply
     return Message.reply('foo', 'ok', '1')
예제 #12
0
    def request_device_list(self, reqmsg):
        """Return a list of devices aggregated by the proxy.

        Returns the list of devices a sequence of #device-list informs.

        Inform Arguments
        ----------------
        device : str
            Name of a device.

        Returns
        -------
        success : {'ok', 'fail'}
            Whether sending the list of devices succeeded.
        informs : int
            Number of #device-list informs sent.

        Examples
        --------
        ?device-list
        #device-list antenna
        #device-list enviro
        !device-list ok 2
        """
        for name in sorted(self.factory.devices):
            self.send_reply_inform(Message.inform("device-list", name,
                                   self.factory.devices[name].TYPE), reqmsg)
        return "ok", len(self.factory.devices)
예제 #13
0
    def request_deconfigure(self, req):
        """
        @brief      Deconfigure the apsuse worker

        @param      req                 A katcp request object

        @return     katcp reply object [[[ !deconfigure ok | (fail [error description]) ]]]
        """
        log.info("Received deconfigure request")
        self._state_sensor.set_value(self.STOPPING)
        futures = []
        for capture_instance in self._capture_instances:
            capture_instance.target_stop()
            for sensor in capture_instance._sensors:
                try:
                    self.remove_sensor(sensor)
                except Exception as error:
                    log.exception(
                        "Failed to remove sensor with error: {}".format(
                            str(error)))
                    log.warning("Current sensor list: {}".format(self._sensors))
            futures.append(capture_instance.capture_stop())
        self.mass_inform(Message.inform('interface-changed'))
        for future in futures:
            try:
                yield future
            except Exception as error:
                log.exception("Error during capture_stop")
                raise Return(("fail", str(error)))
        self._state_sensor.set_value(self.IDLE)
        log.info("Deconfigured worker server")
        raise Return(("ok",))
예제 #14
0
    def request_client_list(self, msg):
        """Request the list of connected clients.

        The list of clients is sent as a sequence of #client-list informs.

        Informs
        -------
        addr : str
            The address of the client as host:port with host in dotted quad
            notation. If the address of the client could not be determined
            (because, for example, the client disconnected suddenly) then
            a unique string representing the client is sent instead.

        Returns
        -------
        success : {'ok', 'fail'}
            Whether sending the client list succeeded.
        informs : int
            Number of #client-list inform messages sent.

        Examples
        --------
        ::

            ?client-list
            #client-list 127.0.0.1:53600
            !client-list ok 1
        """
        for ip, port in self.factory.clients:
            self.send_message(Message.inform(msg.name, "%s:%s" % (ip, port)))
        return Message.reply(msg.name, "ok", len(self.factory.clients))
예제 #15
0
    def request_target_configuration_start(self, req, product_id,
                                           target_string):
        """
        @brief      Set up a beam configuration sensor for the FBFUSE instance

        @param      product_id     The product identifier
        @param      target_string  A KATPOINT target string (boresight pointing position)
        """
        log.info(
            "Received target configuration request for '{}' with target: {}".
            format(product_id, target_string))
        if not product_id in self._configuration_sensors:
            log.debug(
                "Creating configuration sensor for '{}'".format(product_id))
            self._configuration_sensors[product_id] = Sensor.string(
                "{}-beam-position-configuration".format(product_id),
                description="Configuration description for FBF beam placement",
                default="",
                initial_status=Sensor.UNKNOWN)
            self.add_sensor(self._configuration_sensors[product_id])
            self.mass_inform(Message.inform('interface-changed'))
        initial_config = yield self.get_target_config(product_id,
                                                      target_string)
        self.update_target_config(product_id, initial_config)
        raise Return(("ok", ))
예제 #16
0
    def request_device_list(self, reqmsg):
        """Return a list of devices aggregated by the proxy.

        Returns the list of devices a sequence of #device-list informs.

        Inform Arguments
        ----------------
        device : str
            Name of a device.

        Returns
        -------
        success : {'ok', 'fail'}
            Whether sending the list of devices succeeded.
        informs : int
            Number of #device-list informs sent.

        Examples
        --------
        ?device-list
        #device-list antenna
        #device-list enviro
        !device-list ok 2
        """
        for name in sorted(self.factory.devices):
            self.send_message(
                Message.inform("device-list", name,
                               self.factory.devices[name].TYPE))
        return "ok", len(self.factory.devices)
예제 #17
0
 def worked((informs, reply)):
     self.flushLoggedErrors()  # clean up error about conn lost
     self.proxy.on_device_ready = Deferred().addCallback(back)
     self.assertEquals(informs, [
         Message.inform("sensor-value", "device.rogue",
                        "Sensor reading failed.")
     ])
예제 #18
0
    def connectionMade(self):
        """ Called when connection is made. Send default informs - version
        and build data
        """
        self.transport.registerProducer(self, True)

        katcp_version = self.PROTOCOL_INFO.major
        if katcp_version >= VERSION_CONNECT_KATCP_MAJOR:
            self.send_message(Message.inform(
                "version-connect", "katcp-protocol", self.PROTOCOL_INFO))
            self.send_message(Message.inform("version-connect", "katcp-library",
                                             "katcp-python-tx-%s" % VERSION_STR))
            self.send_message(Message.inform("version-connect", "katcp-device",
                                             self.version(), self.build_state()))
        else:
            self.send_message(Message.inform("version", self.version()))
            self.send_message(Message.inform("build-state", self.build_state()))
예제 #19
0
    def remove_pipeline_sensors(self):
        """
        @brief Remove pipeline sensors from the managed sensors list

        """
        for sensor in self._managed_sensors:
            self.remove_sensor(sensor)
        self._managed_sensors = []
        self.mass_inform(Message.inform('interface-changed'))
예제 #20
0
    def add_pipeline_sensors(self):
        """
        @brief Add pipeline sensors to the managed sensors list

        """
        for sensor in self._pipeline_instance.sensors:
            self.add_sensor(sensor)
            self._managed_sensors.append(sensor)
        self.mass_inform(Message.inform('interface-changed'))
예제 #21
0
    def test_interface_change(self):
        DUT = yield self._get_DUT_and_sync(self.default_resource_spec)
        sensors_before = set(DUT.sensor)
        reqs_before = set(DUT.req)

        # Add a new sensor to the server
        sensor = DeviceTestSensor(DeviceTestSensor.INTEGER, "another.int",
                                  "An Integer.",
                                  "count", [-5, 5], timestamp=self.io_loop.time(),
                                  status=DeviceTestSensor.NOMINAL, value=3)
        self.server.add_sensor(sensor)
        # Check that the sensor does not exist currently
        self.assertNotIn(resource.escape_name(sensor.name), sensors_before)

        # Add a new request to the server
        def request_sparkling_new(self, req, msg):
            """A new command."""
            return Message.reply(msg.name, "ok", "bling1", "bling2")
        self.server._request_handlers['sparkling-new'] = request_sparkling_new
        # Check that the request did not exist before
        self.assertNotIn('sparkling-new', reqs_before)

        # Issue #interface-changed
        self.server.mass_inform(Message.inform('interface-changed'))
        yield DUT.until_state('syncing')
        yield DUT.until_state('synced')

        # Check if sensor/request was added
        self.assertEqual(set(DUT.sensor) - sensors_before, set(['another_int']))
        self.assertEqual(set(DUT.req) - reqs_before, set(['sparkling_new']))

        # And now remove them again
        self.server._request_handlers.pop('sparkling-new')
        self.server.remove_sensor('another.int')

        # Issue #interface-changed
        self.server.mass_inform(Message.inform('interface-changed'))
        yield DUT.until_state('syncing')
        yield DUT.until_state('synced')

        # Check if sensor/request was removed
        self.assertEqual(set(DUT.sensor), sensors_before)
        self.assertEqual(set(DUT.req), reqs_before)
예제 #22
0
    def teardown_sensors(self):
        """
        @brief    Remove all sensors created by this product from the parent server.

        @note     This method is required for cleanup to stop the APS sensor pool
                  becoming swamped with unused sensors.
        """
        for sensor in self._managed_sensors:
            self._parent.remove_sensor(sensor)
        self._managed_sensors = []
        self._parent.mass_inform(Message.inform('interface-changed'))
예제 #23
0
    def connectionMade(self):
        """ Called when connection is made. Send default informs - version
        and build data
        """
        self.transport.registerProducer(self, True)

        katcp_version = self.PROTOCOL_INFO.major
        if katcp_version >= VERSION_CONNECT_KATCP_MAJOR:
            self.send_message(
                Message.inform("version-connect", "katcp-protocol",
                               self.PROTOCOL_INFO))
            self.send_message(
                Message.inform("version-connect", "katcp-library",
                               "katcp-python-tx-%s" % VERSION_STR))
            self.send_message(
                Message.inform("version-connect", "katcp-device",
                               self.version(), self.build_state()))
        else:
            self.send_message(Message.inform("version", self.version()))
            self.send_message(Message.inform("build-state",
                                             self.build_state()))
예제 #24
0
    def _log_msg(self, level_name, msg, name, timestamp=None):
        """Create a katcp logging inform message.

           Usually this will be called from inside a DeviceLogger object,
           but it is also used by the methods in this class when errors
           need to be reported to the client.
           """
        if timestamp is None:
            timestamp = time.time()
        return Message.inform("log",
                level_name,
                str(int(timestamp * 1000.0)), # time since epoch in ms
                name,
                msg,
        )
예제 #25
0
    def _kcs_sensor_set(self, sensor):
        """
        Generate #sensor-status informs to update sensors"

        #sensor-status timestamp 1 sensor-name status value

        :param sensor: A katcp.Sensor object
        :return:
        """
        assert self.kcs_sensors
        supdate_inform = Message.inform('sensor-status', time.time(), 1,
                                        sensor.name,
                                        sensor.STATUSES[sensor.status()],
                                        sensor.value())
        self.katcp_server.mass_inform(supdate_inform)
예제 #26
0
    def _kcs_sensor_create(self, sensor):
        """
        Create a sensor the katcp server with a sensor-list inform:

        #sensor-list sensor-name description units type

        :param sensor: A katcp.Sensor object
        :return:
        """
        assert self.kcs_sensors
        descr = sensor.description.replace(' ', '\_')
        screate_inform = Message.inform('sensor-list',
                                        sensor.name, descr,
                                        sensor.units, sensor.type)
        self.katcp_server.mass_inform(screate_inform)
        self._kcs_sensor_set(sensor)
예제 #27
0
    def add_input_stream_sensor(self, streamid):
        """
        Add sensors for i/o buffers for an input stream with given streamid.
        """
        self._polarization_sensors[streamid] = {}
        self._polarization_sensors[streamid]["mkrecv_sensors"] = MkrecvSensors(
            streamid)
        for s in self._polarization_sensors[streamid][
                "mkrecv_sensors"].sensors.values():
            self.add_sensor(s)
        self._polarization_sensors[streamid][
            "input-buffer-fill-level"] = Sensor.float(
                "input-buffer-fill-level-{}".format(streamid),
                description="Fill level of the input buffer for polarization{}"
                .format(streamid),
                initial_status=Sensor.UNKNOWN,
                params=[0, 1])
        self.add_sensor(
            self._polarization_sensors[streamid]["input-buffer-fill-level"])
        self._polarization_sensors[streamid][
            "input-buffer-total-write"] = Sensor.float(
                "input-buffer-total-write-{}".format(streamid),
                description="Total write into input buffer for polarization {}"
                .format(streamid),
                initial_status=Sensor.UNKNOWN,
                params=[0, 1])

        self.add_sensor(
            self._polarization_sensors[streamid]["input-buffer-total-write"])
        self._polarization_sensors[streamid][
            "output-buffer-fill-level"] = Sensor.float(
                "output-buffer-fill-level-{}".format(streamid),
                description="Fill level of the output buffer for polarization {}"
                .format(streamid),
                initial_status=Sensor.UNKNOWN)
        self._polarization_sensors[streamid][
            "output-buffer-total-read"] = Sensor.float(
                "output-buffer-total-read-{}".format(streamid),
                description="Total read from output buffer for polarization {}"
                .format(streamid),
                initial_status=Sensor.UNKNOWN)
        self.add_sensor(
            self._polarization_sensors[streamid]["output-buffer-total-read"])
        self.add_sensor(
            self._polarization_sensors[streamid]["output-buffer-fill-level"])
        self.mass_inform(Message.inform('interface-changed'))
예제 #28
0
    def request_get_schedule_block_configuration(self, req, product_id, sb_id):
        """
        @brief      Get an FBFUSE configuration for the current instance

        @param      product_id  The product identifier
        @param      sb_id       The schedule block identifier

        @note       The product_id argument may be superfluous, although it allows
                    the CA server to look up parameters on the unconfigured product
                    from the FBFUSE sensor set through katportalclient
        """
        if product_id in self._configuration_sensors:
            self.remove_sensor(self._configuration_sensors[product_id])
            del self._configuration_sensors[product_id]
            self.mass_inform(Message.inform('interface-changed'))
        config = yield self.get_sb_config(product_id, sb_id)
        raise Return(("ok", json.dumps(config)))
예제 #29
0
    def configure(self, config_json):
        """
        @brief Configure the pipeline with the given config_json
        """
        log.info("Configuring EDD backend for processing")
        log.info("Configuration string: '{}'".format(config_json))
        yield self.set(config_json)

        if isinstance(self._config['input_data_streams'], dict):
            log.warning(
                "CHANGING INPUT DATA STREAM TYPE FROM DICT TO LIST - THIS IS A HACKY HACK AND BE DONE PROPERLY!"
            )
            l = [i for i in self._config['input_data_streams'].values()]
            self._config['input_data_streams'] = l
            log.debug(self._config)

        cfs = json.dumps(self._config, indent=4)
        log.info("Final configuration:\n" + cfs)

        self.__coreManager = CoreManager(self.numa_number)
        self.__coreManager.add_task("mkrecv",
                                    self._config["nstreams"] + 1,
                                    prefere_isolated=True)
        self.__coreManager.add_task("dspsr", self._config["dspsr_threads"])
        self.__coreManager.add_task("merge", self._config["merge_threads"])

        # The master contoller provides the data store IP as default gloal
        # config to all pipelines
        self.__eddDataStore = EDDDataStore(self._config["data_store"]["ip"],
                                           self._config["data_store"]["port"])

        self.sync_epoch = self._config['input_data_streams'][0]['sync_time']
        log.debug("sync_epoch = {}".format(self.sync_epoch))
        for key in self._dada_buffers:
            self._create_ring_buffer(key, self.numa_number)
            yield

        self.tzpar_dir = os.path.join("/mnt/", self._config["tzpar"])
        if not os.path.isdir(self.tzpar_dir):
            log.error("Not a directory {} !".format(self.tzpar_dir))
            raise RuntimeError("tzpar directory is no directory: {}".format(
                self.tzpar_dir))
        if os.path.isfile("/tmp/t2pred.dat"):
            os.remove("/tmp/t2pred.dat")
        self.add_input_stream_sensor("")
        self.mass_inform(Message.inform('interface-changed'))
    def setup_sensors(self):
        """
        @brief    Setup the default KATCP sensors.

        @note     As this call is made only upon an EDD product configure call a mass inform
                  is required to let connected clients know that the proxy interface has
                  changed.
        """
        super(EddRoach2ProductController, self).setup_sensors()
        self._firmware_server_sensor = Sensor.string(
            "firmware-server",
            description=
            "The address of the firmware server started by this product",
            default="",
            initial_status=Sensor.UNKNOWN)
        self.add_sensor(self._firmware_server_sensor)
        self._parent.mass_inform(Message.inform('interface-changed'))
예제 #31
0
파일: sensors.py 프로젝트: ska-sa/corr2
    def _kcs_sensor_set(self, sensor):
        """
        Generate #sensor-status informs to update sensors"

        #sensor-status timestamp 1 sensor-name status value

        :param sensor: A katcp.Sensor object
        :return:
        """
        if self._debug_mode:
            self.logger.info('SENSOR_DEBUG: sensor-status ' + str(time.time()) +
                        ' ' + sensor.name + ' ' +
                        str(sensor.STATUSES[sensor.status()]) + ' ' +
                        str(sensor.value()))
            return
        assert self.kcs_sensors
        supdate_inform = Message.inform(
            'sensor-status', time.time(), 1, sensor.name,
            sensor.STATUSES[sensor.status()], sensor.value())
        self.katcp_server.mass_inform(supdate_inform)
예제 #32
0
파일: sensors.py 프로젝트: ska-sa/corr2
    def _kcs_sensor_create(self, sensor):
        """
        Create a sensor on the katcp server with a sensor-list inform.

        #sensor-list sensor-name description units type

        :param sensor: A katcp.Sensor object
        :return:
        """
        # descr = sensor.description.replace(' ', '\_')
        descr = sensor.description
        if self._debug_mode:
            self.logger.info('SENSOR_DEBUG: sensor-list ' + sensor.name + ' ' +
                        descr + ' ' + sensor.units + ' ' + str(sensor.type))
            return
        assert self.kcs_sensors
        screate_inform = Message.inform(
            'sensor-list', sensor.name, descr,
            sensor.units, sensor.type)
        self.katcp_server.mass_inform(screate_inform)
        self._kcs_sensor_set(sensor)
예제 #33
0
 def test_inform_one(self):
     """Test inform with no defaults."""
     req = ""
     self.assertEqual(self.device.inform_one(Message.inform(
                      "one", "2", "on", "0")), None)
예제 #34
0
    def request_sensor_list(self, msg):
        """Request the list of sensors.

        The list of sensors is sent as a sequence of #sensor-list informs.

        Parameters
        ----------
        name : str or pattern, optional
            If the name is not a pattern, list just the sensor with the given
            name. A pattern starts and ends with a slash ('/') and uses the
            Python re module's regular expression syntax. All sensors whose
            names contain the pattern are listed.  The default is to list all
            sensors.

        Inform Arguments
        ----------------
        name : str
            The name of the sensor being described.
        description : str
            Description of the named sensor.
        units : str
            Units for the value of the named sensor.
        type : str
            Type of the named sensor.
        params : list of str, optional
            Additional sensor parameters (type dependent). For integer and
            float sensors the additional parameters are the minimum and maximum
            sensor value. For discrete sensors the additional parameters are
            the allowed values. For all other types no additional parameters
            are sent.

        Returns
        -------
        success : {'ok', 'fail'}
            Whether sending the sensor list succeeded.
        informs : int
            Number of #sensor-list inform messages sent.

        Examples
        --------
        ?sensor-list
        #sensor-list psu.voltage PSU\_voltage. V float 0.0 5.0
        #sensor-list cpu.status CPU\_status. \@ discrete on off error
        ...
        !sensor-list ok 5

        ?sensor-list /voltage/
        #sensor-list psu.voltage PSU\_voltage. V float 0.0 5.0
        #sensor-list cpu.voltage CPU\_voltage. V float 0.0 3.0
        !sensor-list ok 2

        ?sensor-list cpu.power.on
        #sensor-list cpu.power.on Whether\_CPU\_hase\_power. \@ boolean
        !sensor-list ok 1
        """
        # handle non-regex cases
        if not msg.arguments or not (msg.arguments[0].startswith("/")
            and msg.arguments[0].endswith("/")):
            return DeviceProtocol.request_sensor_list(self, msg)

        # handle regex
        name_re = re.compile(msg.arguments[0][1:-1])
        sensors = dict([(name, sensor) for name, sensor in
            self.factory.sensors.iteritems() if name_re.search(name)])

        for name, sensor in sorted(sensors.items(), key=lambda x: x[0]):
            self.send_reply_inform(Message.inform("sensor-list",
                name, sensor.description, sensor.units, sensor.stype,
                *sensor.formatted_params), msg)

        return Message.reply(msg.name, "ok", len(sensors))
예제 #35
0
 def connectionMade(self):
     """ Called when a connection is made, send out-of-band inform
     """
     self.send_message(Message.inform('out-of-band'))
     DeviceProtocol.connectionMade(self)
예제 #36
0
class ProxyProtocol(DeviceProtocol):
    @request(include_msg=True)
    @return_reply(Int(min=0))
    def request_device_list(self, reqmsg):
        """Return a list of devices aggregated by the proxy.

        Returns the list of devices a sequence of #device-list informs.

        Inform Arguments
        ----------------
        device : str
            Name of a device.

        Returns
        -------
        success : {'ok', 'fail'}
            Whether sending the list of devices succeeded.
        informs : int
            Number of #device-list informs sent.

        Examples
        --------
        ?device-list
        #device-list antenna
        #device-list enviro
        !device-list ok 2
        """
        for name in sorted(self.factory.devices):
            self.send_message(
                Message.inform("device-list", name,
                               self.factory.devices[name].TYPE))
        return "ok", len(self.factory.devices)

    def request_sensor_list(self, msg):
        """Request the list of sensors.

        The list of sensors is sent as a sequence of #sensor-list informs.

        Parameters
        ----------
        name : str or pattern, optional
            If the name is not a pattern, list just the sensor with the given name.
            A pattern starts and ends with a slash ('/') and uses the Python re
            module's regular expression syntax. All sensors whose names contain the
            pattern are listed.  The default is to list all sensors.

        Inform Arguments
        ----------------
        name : str
            The name of the sensor being described.
        description : str
            Description of the named sensor.
        units : str
            Units for the value of the named sensor.
        type : str
            Type of the named sensor.
        params : list of str, optional
            Additional sensor parameters (type dependent). For integer and float
            sensors the additional parameters are the minimum and maximum sensor
            value. For discrete sensors the additional parameters are the allowed
            values. For all other types no additional parameters are sent.

        Returns
        -------
        success : {'ok', 'fail'}
            Whether sending the sensor list succeeded.
        informs : int
            Number of #sensor-list inform messages sent.

        Examples
        --------
        ?sensor-list
        #sensor-list psu.voltage PSU\_voltage. V float 0.0 5.0
        #sensor-list cpu.status CPU\_status. \@ discrete on off error
        ...
        !sensor-list ok 5

        ?sensor-list /voltage/
        #sensor-list psu.voltage PSU\_voltage. V float 0.0 5.0
        #sensor-list cpu.voltage CPU\_voltage. V float 0.0 3.0
        !sensor-list ok 2

        ?sensor-list cpu.power.on
        #sensor-list cpu.power.on Whether\_CPU\_hase\_power. \@ boolean
        !sensor-list ok 1
        """
        # handle non-regex cases
        if not msg.arguments or not (msg.arguments[0].startswith("/")
                                     and msg.arguments[0].endswith("/")):
            return DeviceProtocol.request_sensor_list(self, msg)

        # handle regex
        name_re = re.compile(msg.arguments[0][1:-1])
        sensors = dict([(name, sensor)
                        for name, sensor in self.factory.sensors.iteritems()
                        if name_re.search(name)])

        for name, sensor in sorted(sensors.items(), key=lambda x: x[0]):
            self.send_message(
                Message.inform("sensor-list", name, sensor.description,
                               sensor.units, sensor.stype,
                               *sensor.formatted_params))

        return Message.reply(msg.name, "ok", len(sensors))

    def _send_all_sensors(self, filter=None):
        """ Sends all sensor values with given filter (None = all)
        """
        counter = [0]  # this has to be a list or an object, thanks to

        # python lexical scoping rules (we could not write count += 1
        # in a function)

        def device_ok((informs, reply), device):
            for inform in informs:
                inform.arguments[2] = device.name + '.' + \
                                      inform.arguments[2]
                if filter is None or re.match(filter, inform.arguments[2]):
                    self.send_message(inform)
                    counter[0] += 1

        def all_ok(_):
            self.send_message(
                Message.reply('sensor-value', 'ok', str(counter[0])))

        wait_for = []
        for device in self.factory.devices.itervalues():
            if device.state == device.SYNCED:
                d = device.send_request('sensor-value')
                d.addCallback(device_ok, device)
                wait_for.append(d)
            # otherwise we don't have the list of sensors, so we don't
            # send the message
        DeferredList(wait_for).addCallback(all_ok)
        for name, sensor in self.factory.sensors.iteritems():
            if not isinstance(sensor, ProxiedSensor):
                if filter is None or re.match(filter, name):
                    timestamp_ms, status, value = sensor.read_formatted()
                    counter[0] += 1
                    self.send_message(
                        Message.inform('sensor-value', timestamp_ms, "1", name,
                                       status, value))
예제 #37
0
    def request_sensor_list(self, msg):
        """Request the list of sensors.

        The list of sensors is sent as a sequence of #sensor-list informs.

        Parameters
        ----------
        name : str or pattern, optional
            If the name is not a pattern, list just the sensor with the given name.
            A pattern starts and ends with a slash ('/') and uses the Python re
            module's regular expression syntax. All sensors whose names contain the
            pattern are listed.  The default is to list all sensors.

        Inform Arguments
        ----------------
        name : str
            The name of the sensor being described.
        description : str
            Description of the named sensor.
        units : str
            Units for the value of the named sensor.
        type : str
            Type of the named sensor.
        params : list of str, optional
            Additional sensor parameters (type dependent). For integer and float
            sensors the additional parameters are the minimum and maximum sensor
            value. For discrete sensors the additional parameters are the allowed
            values. For all other types no additional parameters are sent.

        Returns
        -------
        success : {'ok', 'fail'}
            Whether sending the sensor list succeeded.
        informs : int
            Number of #sensor-list inform messages sent.

        Examples
        --------
        ?sensor-list
        #sensor-list psu.voltage PSU\_voltage. V float 0.0 5.0
        #sensor-list cpu.status CPU\_status. \@ discrete on off error
        ...
        !sensor-list ok 5

        ?sensor-list /voltage/
        #sensor-list psu.voltage PSU\_voltage. V float 0.0 5.0
        #sensor-list cpu.voltage CPU\_voltage. V float 0.0 3.0
        !sensor-list ok 2

        ?sensor-list cpu.power.on
        #sensor-list cpu.power.on Whether\_CPU\_hase\_power. \@ boolean
        !sensor-list ok 1
        """
        # handle non-regex cases
        if not msg.arguments or not (msg.arguments[0].startswith("/")
                                     and msg.arguments[0].endswith("/")):
            return DeviceProtocol.request_sensor_list(self, msg)

        # handle regex
        name_re = re.compile(msg.arguments[0][1:-1])
        sensors = dict([(name, sensor)
                        for name, sensor in self.factory.sensors.iteritems()
                        if name_re.search(name)])

        for name, sensor in sorted(sensors.items(), key=lambda x: x[0]):
            self.send_message(
                Message.inform("sensor-list", name, sensor.description,
                               sensor.units, sensor.stype,
                               *sensor.formatted_params))

        return Message.reply(msg.name, "ok", len(sensors))
예제 #38
0
 def test_inform_one(self):
     """Test inform with no defaults."""
     sock = ""
     self.assertEqual(
         self.device.inform_one(sock, Message.inform("one", "2", "on",
                                                     "0")), None)
예제 #39
0
 def worked((informs, reply)):
     self.flushLoggedErrors() # clean up error about conn lost
     self.proxy.on_device_ready = Deferred().addCallback(back)
     self.assertEquals(informs, [Message.inform("sensor-value", "device.rogue",
                                            "Sensor reading failed.")])
예제 #40
0
 def connectionMade(self):
     """ Called when connection is made. Send default informs - version
     and build data
     """
     self.send_message(Message.inform("version", *self.VERSION))
     self.send_message(Message.inform("build-state", *self.BUILD_STATE))
예제 #41
0
 def callback(sensor, timestamp_ms, status, value):
     self.send_message(Message.inform('sensor-status', timestamp_ms, "1",
                                      sensor.name, status, value))
예제 #42
0
 def fail(_, sensor):
     self.send_message(Message.inform('log',
                                      'Connection lost.'))
    def prepare(self, sb_id):
        """
        @brief      Prepare the beamformer for streaming

        @detail     This method evaluates the current configuration creates a new DelayEngine
                    and passes a prepare call to all allocated servers.
        """
        if not self.idle:
            raise FbfProductStateError([self.IDLE], self.state)
        self.log.info("Preparing FBFUSE product")
        self._state_sensor.set_value(self.PREPARING)
        self.log.debug("Product moved to 'preparing' state")
        # Here we need to parse the streams and assign beams to streams:
        #mcast_addrs, mcast_port = parse_stream(self._streams['cbf.antenna_channelised_voltage']['i0.antenna-channelised-voltage'])

        if not self._ca_client:
            self.log.warning("No configuration authority found, using default configuration parameters")
            cm = self.set_sb_configuration(self._default_sb_config)
        else:
            #TODO: get the schedule block ID into this call from somewhere (configure?)
            try:
                config = yield self.get_ca_sb_configuration(sb_id)
                cm = self.set_sb_configuration(config)
            except Exception as error:
                self.log.error("Configuring from CA failed with error: {}".format(str(error)))
                self.log.warning("Reverting to default configuration")
                cm = self.set_sb_configuration(self._default_sb_config)

        cbc_antennas_names = parse_csv_antennas(self._cbc_antennas_sensor.value())
        cbc_antennas = [self._antenna_map[name] for name in cbc_antennas_names]
        self._beam_manager = BeamManager(self._cbc_nbeams_sensor.value(), cbc_antennas)
        self._delay_config_server = DelayConfigurationServer("127.0.0.1", 0, self._beam_manager)
        self._delay_config_server.start()
        self.log.info("Started delay engine at: {}".format(self._delay_config_server.bind_address))
        de_ip, de_port = self._delay_config_server.bind_address
        self._delay_config_server_sensor.set_value((de_ip, de_port))

        # Need to tear down the beam sensors here
        # Here calculate the beam to multicast map
        self._beam_sensors = []
        mcast_to_beam_map = {}
        groups = [ip for ip in self._cbc_mcast_groups]
        idxs = [beam.idx for beam in self._beam_manager.get_beams()]
        for group in groups:
            self.log.debug("Allocating beams to {}".format(str(group)))
            key = str(group)
            for _ in range(self._cbc_nbeams_per_group.value()):
                if not key in mcast_to_beam_map:
                    mcast_to_beam_map[str(group)] = []
                value = idxs.pop(0)
                self.log.debug("--> Allocated {} to {}".format(value, str(group)))
                mcast_to_beam_map[str(group)].append(value)
        self._cbc_mcast_groups_mapping_sensor.set_value(json.dumps(mcast_to_beam_map))
        for beam in self._beam_manager.get_beams():
            sensor = Sensor.string(
                "coherent-beam-{}".format(beam.idx),
                description="R.A. (deg), declination (deg) and source name for coherent beam with ID {}".format(beam.idx),
                default=self._beam_to_sensor_string(beam),
                initial_status=Sensor.UNKNOWN)
            beam.register_observer(lambda beam, sensor=sensor:
                sensor.set_value(self._beam_to_sensor_string(beam)))
            self._beam_sensors.append(sensor)
            self.add_sensor(sensor)
        self._parent.mass_inform(Message.inform('interface-changed'))

        #Here we actually start to prepare the remote workers
        ip_splits = self._streams.split(N_FENG_STREAMS_PER_WORKER)

        # This is assuming lower sideband and bandwidth is always +ve
        fbottom = self._feng_config['centre-frequency'] - self._feng_config['bandwidth']/2.

        coherent_beam_config = {
        'tscrunch':self._cbc_tscrunch_sensor.value(),
        'fscrunch':self._cbc_fscrunch_sensor.value(),
        'antennas':self._cbc_antennas_sensor.value()
        }

        incoherent_beam_config = {
        'tscrunch':self._ibc_tscrunch_sensor.value(),
        'fscrunch':self._ibc_fscrunch_sensor.value(),
        'antennas':self._ibc_antennas_sensor.value()
        }

        prepare_futures = []
        for ii, (server, ip_range) in enumerate(zip(self._servers, ip_splits)):
            chan0_idx = cm.nchans_per_worker * ii
            chan0_freq =  fbottom + chan0_idx * cm.channel_bandwidth
            future = server.prepare(ip_range.format_katcp(), cm.nchans_per_group,
                        chan0_idx, chan0_freq, cm.channel_bandwidth, mcast_to_beam_map,
                        self._feng_config['feng-antenna-map'], coherent_beam_config,
                        incoherent_beam_config, de_ip, de_port)
            prepare_futures.append(future)

        failure_count = 0
        for future in prepare_futures:
            try:
                yield future
            except Exception as error:
                log.error("Failed to configure server with error: {}".format(str(error)))
                failure_count += 1

        if failure_count > 0:
            self._state_sensor.set_value(self.ERROR)
            self.log.info("Failed to prepare FBFUSE product")
        else:
            self._state_sensor.set_value(self.READY)
            self.log.info("Successfully prepared FBFUSE product")
예제 #44
0
 def one_ok(sensor, timestamp_ms, status, value):
     self.send_message(Message.inform(msg.name, timestamp_ms, "1",
                                      sensor.name, status, value))
예제 #45
0
 def one_fail(failure, sensor):
     self.send_message(Message.inform(msg.name, sensor.name,
                                      "Sensor reading failed."))
예제 #46
0
    def request_sensor_list(self, msg):
        """Request the list of sensors.

        The list of sensors is sent as a sequence of #sensor-list informs.

        Parameters
        ----------
        name : str, optional
            Name of the sensor to list (the default is to list all sensors).
            If name starts and ends with '/' it is treated as a regular expression and
            all sensors whose names contain the regular expression are returned.

        Informs
        -------
        name : str
            The name of the sensor being described.
        description : str
            Description of the named sensor.
        units : str
            Units for the value of the named sensor.
        type : str
            Type of the named sensor.
        params : list of str, optional
            Additional sensor parameters (type dependent). For integer and float
            sensors the additional parameters are the minimum and maximum sensor
            value. For discrete sensors the additional parameters are the allowed
            values. For all other types no additional parameters are sent.

        Returns
        -------
        success : {'ok', 'fail'}
            Whether sending the sensor list succeeded.
        informs : int
            Number of #sensor-list inform messages sent.

        Examples
        --------
        ::

            ?sensor-list
            #sensor-list psu.voltage PSU\_voltage. V float 0.0 5.0
            #sensor-list cpu.status CPU\_status. \@ discrete on off error
            ...
            !sensor-list ok 5

            ?sensor-list cpu.power.on
            #sensor-list cpu.power.on Whether\_CPU\_hase\_power. \@ boolean
            !sensor-list ok 1
        """
        exact, name_filter = construct_name_filter(msg.arguments[0]
                    if msg.arguments else None)
        sensors = [(name, sensor) for name, sensor in
                    sorted(self.factory.sensors.iteritems()) if name_filter(name)]

        if exact and not sensors:
            return Message.reply(msg.name, "fail", "Unknown sensor name.")

        for name, sensor in sensors:
            self.send_message(Message.inform(msg.name, name, sensor.description,
                                             sensor.units, sensor.stype,
                                             *sensor.formatted_params))
        return Message.reply(msg.name, "ok", len(sensors))