Example #1
0
class RedPitayaControlService(BaseService):
    """Control server that runs on the RP that provides high-level methods."""
    def __init__(self, **kwargs):
        self._cached_data = {}
        self.exposed_is_locked = None

        super().__init__()

        from registers import Registers

        self.registers = Registers(**kwargs)
        self.registers.connect(self, self.parameters)

    def run_acquiry_loop(self):
        """Starts a background process that keeps polling control and error
        signal. Every received value is pushed to `parameters.to_plot`."""
        def data_received(is_raw, plot_data, data_uuid):
            # When a parameter is changed, `pause_acquisition` is set.
            # This means that the we should skip new data until we are sure that
            # it was recorded with the new settings.
            if not self.parameters.pause_acquisition.value:
                if data_uuid != self.data_uuid:
                    return

                data_loaded = pickle.loads(plot_data)

                if not is_raw:
                    is_locked = self.parameters.lock.value

                    if not check_plot_data(is_locked, data_loaded):
                        print(
                            "warning: incorrect data received for lock state, ignoring!"
                        )
                        return

                    self.parameters.to_plot.value = plot_data
                    self._generate_signal_stats(data_loaded)

                    # update signal history (if in locked state)
                    (
                        self.parameters.control_signal_history.value,
                        self.parameters.monitor_signal_history.value,
                    ) = update_signal_history(
                        self.parameters.control_signal_history.value,
                        self.parameters.monitor_signal_history.value,
                        data_loaded,
                        is_locked,
                        self.parameters.control_signal_history_length.value,
                    )
                else:
                    self.parameters.acquisition_raw_data.value = plot_data

        self.registers.run_data_acquisition(data_received)
        self.pause_acquisition()
        self.continue_acquisition()

    def _generate_signal_stats(self, to_plot):
        stats = {}

        for signal_name, signal in to_plot.items():
            stats["%s_mean" % signal_name] = np.mean(signal)
            stats["%s_std" % signal_name] = np.std(signal)
            stats["%s_max" % signal_name] = np.max(signal)
            stats["%s_min" % signal_name] = np.min(signal)

        self.parameters.signal_stats.value = stats

    def exposed_write_data(self):
        """Syncs the parameters with the FPGA registers."""
        self.registers.write_registers()

    def task_running(self):
        return (self.parameters.autolock_running.value
                or self.parameters.optimization_running.value
                or self.parameters.psd_acquisition_running.value
                or self.parameters.psd_optimization_running.value)

    def exposed_start_autolock(self,
                               x0,
                               x1,
                               spectrum,
                               additional_spectra=None):
        spectrum = pickle.loads(spectrum)
        # start_watching = self.parameters.watch_lock.value
        start_watching = False
        auto_offset = self.parameters.autolock_determine_offset.value

        if not self.task_running():
            autolock = Autolock(self, self.parameters)
            self.parameters.task.value = autolock
            autolock.run(
                x0,
                x1,
                spectrum,
                should_watch_lock=start_watching,
                auto_offset=auto_offset,
                additional_spectra=pickle.loads(additional_spectra)
                if additional_spectra is not None else None,
            )

    def exposed_start_optimization(self, x0, x1, spectrum):
        if not self.task_running():
            optim = OptimizeSpectroscopy(self, self.parameters)
            self.parameters.task.value = optim
            optim.run(x0, x1, spectrum)

    def exposed_start_psd_acquisition(self):
        if not self.task_running():
            self.parameters.task.value = PSDAcquisition(self, self.parameters)
            self.parameters.task.value.run()

    def exposed_start_pid_optimization(self):
        if not self.task_running():
            self.parameters.task.value = PIDOptimization(self, self.parameters)
            self.parameters.task.value.run()

    def exposed_start_ramp(self):
        self.pause_acquisition()

        self.parameters.combined_offset.value = 0
        self.parameters.lock.value = False
        self.exposed_write_data()

        self.continue_acquisition()

    def exposed_start_lock(self):
        self.pause_acquisition()

        self.parameters.lock.value = True
        self.exposed_write_data()

        self.continue_acquisition()

    def exposed_shutdown(self):
        """Kills the server."""
        self.registers.acquisition.shutdown()
        _thread.interrupt_main()
        # we use SystemExit instead of os._exit because we want to call atexit
        # handlers
        raise SystemExit

    def exposed_get_server_version(self):
        import linien

        return linien.__version__

    def exposed_get_restorable_parameters(self):
        return self.parameters._restorable_parameters

    def exposed_pause_acquisition(self):
        self.pause_acquisition()

    def exposed_continue_acquisition(self):
        self.continue_acquisition()

    def exposed_set_csr_direct(self, k, v):
        """Directly sets a CSR register. This method is intended for debugging.
        Normally, the FPGA should be controlled via manipulation of parameters."""
        self.registers.set(k, v)

    def pause_acquisition(self):
        """Pause continuous acquisition. Call this before changing a parameter
        that alters the error / control signal. This way, no inconsistent signals
        reach the application. After setting the new parameter values, call
        `continue_acquisition`."""
        self.parameters.pause_acquisition.value = True
        self.data_uuid = random()
        self.registers.acquisition.pause_acquisition()

    def continue_acquisition(self):
        """Continue acquisition after a short delay, when we are sure that the
        new parameters values have been written to the FPGA and that data that
        is now recorded is recorded with the correct parameters."""
        self.parameters.pause_acquisition.value = False
        self.registers.acquisition.continue_acquisition(self.data_uuid)
Example #2
0
class RedPitayaControlService(BaseService):
    """Control server that runs on the RP that provides high-level methods."""
    def __init__(self, **kwargs):
        self._cached_data = {}
        self.exposed_is_locked = None

        super().__init__(Parameters)

        from registers import Registers
        self.registers = Registers(**kwargs)
        self.registers.connect(self, self.parameters)

    def run_acquiry_loop(self):
        """Starts a background process that keeps polling control and error
        signal. Every received value is pushed to `parameters.to_plot`."""
        def data_received(plot_data, data_uuid):
            # When a parameter is changed, `pause_acquisition` is set.
            # This means that the we should skip new data until we are sure that
            # it was recorded with the new settings.
            if not self.parameters.pause_acquisition.value:
                if data_uuid != self.data_uuid:
                    return

                s1, s2, slow_out = pickle.loads(plot_data)
                is_locked = self.parameters.lock.value

                if is_locked:
                    data = {'error_signal': s1, 'control_signal': s2}
                    if self.parameters.pid_on_slow_enabled.value:
                        data['slow'] = slow_out
                else:
                    data = {'error_signal_1': s1, 'error_signal_2': s2}

                self.parameters.to_plot.value = pickle.dumps(data)

                self.parameters.control_signal_history.value = \
                    update_control_signal_history(
                        self.parameters.control_signal_history.value,
                        data,
                        is_locked,
                        self.parameters.control_signal_history_length.value
                    )

        self.registers.run_data_acquisition(data_received)
        self.pause_acquisition()
        self.continue_acquisition()

    def exposed_write_data(self):
        """Syncs the parameters with the FPGA registers."""
        self.registers.write_registers()

    def task_running(self):
        return self.parameters.autolock_running.value or \
            self.parameters.optimization_running.value

    def exposed_start_autolock(self, x0, x1, spectrum, auto_offset=True):
        spectrum = pickle.loads(spectrum)
        start_watching = self.parameters.watch_lock.value
        auto_offset = self.parameters.autolock_determine_offset.value

        if not self.task_running():
            autolock = Autolock(self, self.parameters)
            self.parameters.task.value = autolock
            autolock.run(x0,
                         x1,
                         spectrum,
                         should_watch_lock=start_watching,
                         auto_offset=auto_offset)

    def exposed_start_optimization(self, x0, x1, spectrum):
        if not self.task_running():
            optim = OptimizeSpectroscopy(self, self.parameters)
            self.parameters.task.value = optim
            optim.run(x0, x1, spectrum)

    def exposed_start_ramp(self):
        self.pause_acquisition()

        self.parameters.combined_offset.value = 0
        self.parameters.lock.value = False
        self.exposed_write_data()

        self.continue_acquisition()

    def exposed_start_lock(self):
        self.pause_acquisition()

        self.parameters.lock.value = True
        self.exposed_write_data()

        self.continue_acquisition()

    def exposed_shutdown(self):
        """Kills the server."""
        self.registers.acquisition.shutdown()
        _thread.interrupt_main()
        os._exit(0)

    def exposed_get_server_version(self):
        import linien
        return linien.__version__

    def exposed_get_restorable_parameters(self):
        return self.parameters.restorable_parameters

    def exposed_pause_acquisition(self):
        self.pause_acquisition()

    def exposed_continue_acquisition(self):
        self.continue_acquisition()

    def pause_acquisition(self):
        """Pause continuous acquisition. Call this before changing a parameter
        that alters the error / control signal. This way, no inconsistent signals
        reach the application. After setting the new parameter values, call
        `continue_acquisition`."""
        self.parameters.pause_acquisition.value = True
        self.data_uuid = random()

    def continue_acquisition(self):
        """Continue acquisition after a short delay, when we are sure that the
        new parameters values have been written to the FPGA and that data that
        is now recorded is recorded with the correct parameters."""
        self.parameters.pause_acquisition.value = False
        self.registers.acquisition.clear_data_cache(self.data_uuid)