Ejemplo n.º 1
0
def main():
    args = get_argparser().parse_args()
    init_logger_from_args(args)
    if args.lock_current:
        client = WavemeterPIClientTopticaEthernetCurrent(
            host=args.server,
            port=args.port,
            channel=args.channel,
            dlc_address=args.dlc_address,
            laser_id=args.laser,
            output_offset=args.current_center,
            output_span=args.current_span,
            setpoint=args.setpoint,
            cp=args.cp,
            ci=args.ci,
            integrator_timeout=args.integrator_timeout,
            integrator_cutoff=args.integrator_cutoff,
            output_sensitivity=args.output_sensitivity,
            startup_locked=args.startup_locked)
    else:
        client = WavemeterPIClientTopticaEthernetPZT(
            host=args.server,
            port=args.port,
            channel=args.channel,
            dlc_address=args.dlc_address,
            laser_id=args.laser,
            output_offset=args.pzt_center,
            output_span=args.pzt_span,
            setpoint=args.setpoint,
            cp=args.cp,
            ci=args.ci,
            integrator_timeout=args.integrator_timeout,
            integrator_cutoff=args.integrator_cutoff,
            output_sensitivity=args.output_sensitivity,
            current_center=args.current_center,
            current_span=args.current_span,
            startup_locked=args.startup_locked)

    pub = Publisher(
        {"lock_client_{}".format(args.channel): client.status_notifier})

    asyncio.get_event_loop().run_until_complete(
        pub.start(bind_address_from_args(args), args.port_pub))
    simple_server_loop({"lock_client_{}".format(args.channel): client},
                       bind_address_from_args(args), args.port_rpc)
    client.close_subscriber()
    client.close_dlc_connection()
Ejemplo n.º 2
0
def main():
    args = get_argparser().parse_args()
    init_logger_from_args(args)
    if args.aux_output:
        client = WavemeterPIClientRedLabPlusAuxOut(
            host=args.server,
            port=args.port,
            channel=args.channel,
            board_num=args.board,
            channel_id=args.id,
            board_num_aux=args.board2,
            channel_id_aux=args.id2,
            setpoint=args.setpoint,
            cp=args.cp,
            ci=args.ci,
            integrator_timeout=args.integrator_timeout,
            integrator_cutoff=args.integrator_cutoff,
            output_sensitivity=args.output_sensitivity,
            output_offset=args.output_offset,
            startup_locked=args.startup_locked)
    else:
        client = WavemeterPIClientRedLab(
            host=args.server,
            port=args.port,
            channel=args.channel,
            board_num=args.board,
            channel_id=args.id,
            setpoint=args.setpoint,
            cp=args.cp,
            ci=args.ci,
            integrator_timeout=args.integrator_timeout,
            integrator_cutoff=args.integrator_cutoff,
            output_sensitivity=args.output_sensitivity,
            output_offset=args.output_offset,
            startup_locked=args.startup_locked)
    pub = Publisher(
        {"lock_client_{}".format(args.channel): client.status_notifier})

    asyncio.get_event_loop().run_until_complete(
        pub.start(bind_address_from_args(args), args.port_pub))
    simple_server_loop({"lock_client_{}".format(args.channel): client},
                       bind_address_from_args(args), args.port_rpc)
    client.close_subscriber()
Ejemplo n.º 3
0
def main():
    args = get_argparser().parse_args()
    log_forwarder = init_log(args)
    if os.name == "nt":
        loop = asyncio.ProactorEventLoop()
        asyncio.set_event_loop(loop)
    else:
        loop = asyncio.get_event_loop()
    atexit.register(loop.close)
    bind = common_args.bind_address_from_args(args)

    server_broadcast = Broadcaster()
    loop.run_until_complete(server_broadcast.start(
        bind, args.port_broadcast))
    atexit_register_coroutine(server_broadcast.stop)

    log_forwarder.callback = (lambda msg:
        server_broadcast.broadcast("log", msg))
    def ccb_issue(service, *args, **kwargs):
        msg = {
            "service": service,
            "args": args,
            "kwargs": kwargs
        }
        server_broadcast.broadcast("ccb", msg)

    device_db = DeviceDB(args.device_db)
    dataset_db = DatasetDB(args.dataset_db)
    dataset_db.start()
    atexit_register_coroutine(dataset_db.stop)
    worker_handlers = dict()

    if args.git:
        repo_backend = GitBackend(args.repository)
    else:
        repo_backend = FilesystemBackend(args.repository)
    experiment_db = ExperimentDB(
        repo_backend, worker_handlers, args.experiment_subdir)
    atexit.register(experiment_db.close)

    scheduler = Scheduler(RIDCounter(), worker_handlers, experiment_db)
    scheduler.start()
    atexit_register_coroutine(scheduler.stop)

    config = MasterConfig(args.name)

    worker_handlers.update({
        "get_device_db": device_db.get_device_db,
        "get_device": device_db.get,
        "get_dataset": dataset_db.get,
        "update_dataset": dataset_db.update,
        "scheduler_submit": scheduler.submit,
        "scheduler_delete": scheduler.delete,
        "scheduler_request_termination": scheduler.request_termination,
        "scheduler_get_status": scheduler.get_status,
        "scheduler_check_pause": scheduler.check_pause,
        "ccb_issue": ccb_issue,
    })
    experiment_db.scan_repository_async()

    server_control = RPCServer({
        "master_config": config,
        "master_device_db": device_db,
        "master_dataset_db": dataset_db,
        "master_schedule": scheduler,
        "master_experiment_db": experiment_db
    }, allow_parallel=True)
    loop.run_until_complete(server_control.start(
        bind, args.port_control))
    atexit_register_coroutine(server_control.stop)

    server_notify = Publisher({
        "schedule": scheduler.notifier,
        "devices": device_db.data,
        "datasets": dataset_db.data,
        "explist": experiment_db.explist,
        "explist_status": experiment_db.status
    })
    loop.run_until_complete(server_notify.start(
        bind, args.port_notify))
    atexit_register_coroutine(server_notify.stop)

    server_logging = LoggingServer()
    loop.run_until_complete(server_logging.start(
        bind, args.port_logging))
    atexit_register_coroutine(server_logging.stop)

    print("ARTIQ master is now ready.")
    loop.run_forever()
Ejemplo n.º 4
0
    def __init__(self,
                 channels: List[int] = None,
                 num_hw_channels: int = 8,
                 get_temperature: bool = False,
                 get_pressure: bool = False,
                 skip_threshold_nm: float = 10.,
                 install_callback: bool = True,
                 start_publisher: bool = True,
                 publisher_host: str = "*",
                 publisher_port: int = 3281,
                 event_loop: Any = None):
        self.hf_dll = HFDLL()
        channels = channels if channels is not None else [
            i for i in range(1, 9)
        ]
        self._channels = list(set(["ch{}".format(c) for c in channels]))
        self._get_temperature = get_temperature
        self._get_pressure = get_pressure

        self._mode_dict = dict()
        for k, v in self.hf_dll.const.items():
            if k[0:13] == "cmiWavelength" and int(k[13:]) <= num_hw_channels:
                self._mode_dict.update({v: "ch{}".format(k[13:])})
        if self._get_temperature:
            self._mode_dict.update({self.hf_dll.const["cmiTemperature"]: "T"})
        if self._get_pressure:
            self._mode_dict.update({self.hf_dll.const["cmiPressure"]: "p"})

        self._update_valid_modes()

        self._skip_threshold_nm = skip_threshold_nm

        self._callback_installed = False
        self._wavemeter_callback_type = WINFUNCTYPE(c_int, c_long, c_int,
                                                    c_double)
        self._wavemeter_callback_object = self._wavemeter_callback_type(
            self._wavemeter_callback)

        self.wm_status_dict = {
            "autocal_countdown": 0,
            "calibration_timestamp": -1
        }
        self.status_notifier = Notifier(self.wm_status_dict)

        self._autocal_running = False
        self._stop_autocal = True
        self._autocal_timestamp = -1
        self._autocal_retry_interval = 10

        self.latest_data = {n: [(0, -1.)] for n in self._mode_dict.values()}
        # since latest_data can be an error code, store last valid value separately
        # (avoids jump detection getting triggered after each error)
        self._latest_valid_value = {n: -1. for n in self._mode_dict.values()}

        self.notifiers = {
            n: Notifier(self.latest_data[n])
            for n in self._mode_dict.values()
        }
        self.notifiers.update({"status": self.status_notifier})
        self.publisher = Publisher(self.notifiers)
        self._publisher_host = publisher_host
        self._publisher_port = publisher_port

        # one (thread safe) lock per channel to prevent values from stacking up (discard new while channel is busy)
        self._locks = {n: Lock() for n in self._mode_dict.values()}
        self._queue = None  # Janus uses asyncio.get_current_loop() as of version 0.5
        # -> Queue needs to be created from within _new_value_loop

        # interferogram export variables (index is 0 or 1 for the two different interferometers)
        self._pattern_export_enabled = [
            False, False
        ]  # stores whether export has been enabled
        self._pattern_item_type = [None, None]  # data type (ctypes class)
        self._pattern_item_count = [-1, -1]  # number of data points

        self._event_loop = event_loop if event_loop is not None else asyncio.get_event_loop(
        )
        self._event_loop.create_task(self._new_value_loop())
        if install_callback:
            self.install_wavemeter_callback()
        if start_publisher:
            self._event_loop.create_task(self.start_publisher())
Ejemplo n.º 5
0
lockClient739 = WavemeterPIClientRedLab(channel="ch8",
                                        board_num=0,
                                        channel_id=10,
                                        output_min=-5.,
                                        output_max=5.,
                                        setpoint=739.049050,
                                        cp=100.,
                                        ci=2.,
                                        output_sensitivity=-0.000741)

pub = Publisher({
    "lock825": lockClient825.status_notifier,
    "lock922": lockClient922.status_notifier,
    "lock946": lockClient946.status_notifier,
    "lock410": lockClient410.status_notifier,
    "lock638": lockClient638.status_notifier,
    "lock935": lockClient935.status_notifier,
    "lock798": lockClient798.status_notifier,
    "lock739": lockClient739.status_notifier
})

asyncio.get_event_loop().create_task(pub.start(None, publisher_port))

simple_server_loop(
    {
        "lock825": lockClient825,
        "lock922": lockClient922,
        "lock946": lockClient946,
        "lock410": lockClient410,
        "lock638": lockClient638,
        "lock935": lockClient935,
Ejemplo n.º 6
0
    def __init__(self):

        self.args = args = get_argparser().parse_args()
        init_logger_from_args(args)

        self.config = load_config(args, "_server")
        self.lasers = self.config["lasers"].keys()

        for laser in self.lasers:
            self.config["lasers"][laser]["lock_ready"] = False

        # connect to hardware
        self.wlm = WLM(args.simulation)

        if self.config.get("osas", "wlm") != "wlm":
            self.osas = NiOSA(self.config["osas"], args.simulation)

        self.exp_min = self.wlm.get_exposure_min()
        self.exp_max = self.wlm.get_exposure_max()
        self.num_ccds = self.wlm.get_num_ccds()

        if self.config["switch"]["type"] == "internal":
            self.switch = self.wlm.get_switch()
        elif self.config["switch"]["type"] == "leoni":
            self.switch = LeoniSwitch(
                self.config["switch"]["ip"], args.simulation)
        else:
            raise ValueError("Unrecognised switch type: {}".format(
                self.config["switch"]["type"]))

        # measurement queue, processed by self.measurement_task
        self.measurement_ids = task_id_generator()
        self.measurements_queued = asyncio.Event()
        self.queue = []

        self.wake_locks = {laser: asyncio.Event() for laser in self.lasers}

        # schedule initial frequency/osa readings all lasers
        self.measurements_queued.set()
        for laser in self.lasers:
            self.queue.append({
                "laser": laser,
                "priority": 0,
                "expiry": time.time(),
                "id": next(self.measurement_ids),
                "get_osa_trace": True,
                "done": asyncio.Event()
            })

        # "notify" interface
        self.laser_db = Notifier(self.config["lasers"])
        self.freq_db = Notifier({laser: {
            "freq": None,
            "status": WLMMeasurementStatus.ERROR,
            "timestamp": 0
        } for laser in self.lasers})
        self.osa_db = Notifier({laser: {
            "trace": None,
            "timestamp": 0
        } for laser in self.lasers})

        self.server_notify = Publisher({
            "laser_db": self.laser_db,  # laser settings
            "freq_db": self.freq_db,  # most recent frequency measurements
            "osa_db": self.osa_db  # most recent osa traces
        })

        # "control" interface
        self.control_interface = ControlInterface(self)
        self.server_control = RPCServer({"control": self.control_interface},
                                        allow_parallel=True)

        self.running = False
Ejemplo n.º 7
0
class WandServer:
    def __init__(self):

        self.args = args = get_argparser().parse_args()
        init_logger_from_args(args)

        self.config = load_config(args, "_server")
        self.lasers = self.config["lasers"].keys()

        for laser in self.lasers:
            self.config["lasers"][laser]["lock_ready"] = False

        # connect to hardware
        self.wlm = WLM(args.simulation)

        if self.config.get("osas", "wlm") != "wlm":
            self.osas = NiOSA(self.config["osas"], args.simulation)

        self.exp_min = self.wlm.get_exposure_min()
        self.exp_max = self.wlm.get_exposure_max()
        self.num_ccds = self.wlm.get_num_ccds()

        if self.config["switch"]["type"] == "internal":
            self.switch = self.wlm.get_switch()
        elif self.config["switch"]["type"] == "leoni":
            self.switch = LeoniSwitch(
                self.config["switch"]["ip"], args.simulation)
        else:
            raise ValueError("Unrecognised switch type: {}".format(
                self.config["switch"]["type"]))

        # measurement queue, processed by self.measurement_task
        self.measurement_ids = task_id_generator()
        self.measurements_queued = asyncio.Event()
        self.queue = []

        self.wake_locks = {laser: asyncio.Event() for laser in self.lasers}

        # schedule initial frequency/osa readings all lasers
        self.measurements_queued.set()
        for laser in self.lasers:
            self.queue.append({
                "laser": laser,
                "priority": 0,
                "expiry": time.time(),
                "id": next(self.measurement_ids),
                "get_osa_trace": True,
                "done": asyncio.Event()
            })

        # "notify" interface
        self.laser_db = Notifier(self.config["lasers"])
        self.freq_db = Notifier({laser: {
            "freq": None,
            "status": WLMMeasurementStatus.ERROR,
            "timestamp": 0
        } for laser in self.lasers})
        self.osa_db = Notifier({laser: {
            "trace": None,
            "timestamp": 0
        } for laser in self.lasers})

        self.server_notify = Publisher({
            "laser_db": self.laser_db,  # laser settings
            "freq_db": self.freq_db,  # most recent frequency measurements
            "osa_db": self.osa_db  # most recent osa traces
        })

        # "control" interface
        self.control_interface = ControlInterface(self)
        self.server_control = RPCServer({"control": self.control_interface},
                                        allow_parallel=True)

        self.running = False

    def start(self):
        """ Start the server """

        self.executor = ThreadPoolExecutor(max_workers=2)
        self.loop = loop = asyncio.get_event_loop()
        atexit.register(loop.close)

        # start control server
        bind = bind_address_from_args(self.args)
        loop.run_until_complete(
            self.server_control.start(bind, self.args.port_control))
        atexit_register_coroutine(self.server_control.stop)

        # start notify server
        loop.run_until_complete(
            self.server_notify.start(bind, self.args.port_notify))
        atexit_register_coroutine(self.server_notify.stop)

        asyncio.ensure_future(self.measurement_task())

        for laser in self.lasers:
            asyncio.ensure_future(self.lock_task(laser))

        # backup of configuration file
        backup_config(self.args, "_server")
        asyncio.ensure_future(regular_config_backup(self.args, "_server"))
        atexit.register(backup_config, self.args, "_server")

        logger.info("server started")
        self.running = True
        loop.run_forever()

    async def lock_task(self, laser):
        conf = self.laser_db.raw_view[laser]

        # only try to lock lasers with a controller specified
        if not conf.get("host") or self.args.simulation:
            return

        while self.running:
            conf["lock_ready"] = False

            try:
                iface = DLPro(conf["host"],
                              target=conf.get("target", "laser1"))
            except OSError:
                logger.warning(
                    "could not connect to laser '{}', retrying in 60s"
                    .format(laser))
                if conf["locked"]:
                    self.control_interface.unlock(laser, conf["lock_owner"])
                await asyncio.sleep(60)
                continue

            self.wake_locks[laser].set()
            conf["lock_ready"] = True

            while self.running:

                if not conf["locked"]:
                    await self.wake_locks[laser].wait()
                    self.wake_locks[laser].clear()
                    continue

                poll_time = conf["lock_poll_time"]
                locked_at = conf["locked_at"]
                timeout = conf["lock_timeout"]
                set_point = conf["lock_set_point"]
                gain = conf["lock_gain"] * poll_time
                capture_range = conf["lock_capture_range"]

                await asyncio.wait({self.wake_locks[laser].wait()},
                                   timeout=poll_time)
                self.wake_locks[laser].clear()

                if timeout is not None and time.time() > (locked_at + timeout):
                    logger.info("'{}'' lock timed out".format(laser))
                    self.control_interface.unlock(laser, conf["lock_owner"])
                    await asyncio.sleep(0)
                    continue

                status, delta, _ = await self.control_interface.get_freq(
                    laser, age=0, priority=5, get_osa_trace=False,
                    blocking=True, mute=False, offset_mode=True)

                if status != WLMMeasurementStatus.OKAY:
                    continue

                f_error = delta - set_point
                V_error = f_error * gain

                if abs(f_error) > capture_range:
                    logger.warning("'{}'' outside capture range".format(laser))
                    self.control_interface.unlock(laser, conf["lock_owner"])
                    await asyncio.sleep(0)
                    continue

                # don't drive the PZT too far in a single step
                V_error = min(V_error, 0.25)
                V_error = max(V_error, -0.25)

                try:
                    v_pzt = iface.get_pzt_voltage()
                    v_pzt -= V_error

                    if v_pzt > 100 or v_pzt < 25:
                        logger.warning("'{}'' lock railed".format(laser))
                        self.control_interface.unlock(laser,
                                                      conf["lock_owner"])
                        await asyncio.sleep(0)
                        continue

                    iface.set_pzt_voltage(v_pzt)

                except OSError:
                    logger.warning("Connection to laser '{}' lost"
                                   .format(laser))
                    self.control_interface.unlock(laser, conf["lock_owner"])
                    await asyncio.sleep(0)
                    break

        try:
            iface.close()
        except Exception:
            pass
        finally:
            conf["lock_ready"] = False

    async def measurement_task(self):
        """ Process queued measurements """
        active_laser = ""

        while True:

            if self.queue == []:
                self.measurements_queued.clear()
            await self.measurements_queued.wait()

            # process in order of priority, followed by submission time
            priorities = [meas["priority"] for meas in self.queue]
            meas = self.queue[priorities.index(max(priorities))]

            laser = meas["laser"]
            laser_conf = self.laser_db.raw_view[laser]

            if laser != active_laser:
                self.switch.set_active_channel(laser_conf["channel"])

                # Switching is slow so we might as well take an OSA trace!
                meas["get_osa_trace"] = True
                active_laser = meas["laser"]

                # We only need to change the range after switching channels
                try:
                    range_ = laser_conf.get("wavelength_range")
                    self.wlm.set_wavelength_range(range_)
                except WLMException:
                    pass

                await asyncio.sleep(self.config["switch"]["dead_time"])

            exposure = laser_conf["exposure"]
            for ccd, exp in enumerate(exposure):
                self.wlm.set_exposure(exposure[ccd], ccd)

            if laser_conf.get("osa", "wlm") == "wlm":
                freq_osa_measurement = self.loop.run_in_executor(
                    self.executor,
                    self.take_freq_osa_measurement,
                    laser,
                    laser_conf["f_ref"],
                    meas["get_osa_trace"])
                wlm_data, osa = await freq_osa_measurement

            else:
                freq_measurement = self.loop.run_in_executor(
                    self.executor,
                    self.take_freq_measurement,
                    laser,
                    laser_conf["f_ref"])

                osa_measurement = self.loop.run_in_executor(
                    self.executor,
                    self.take_osa_measurement,
                    laser,
                    laser_conf.get("osa"),
                    meas["get_osa_trace"])

                wlm_data, osa = (await asyncio.gather(freq_measurement,
                                                      osa_measurement))[:]

            freq, peaks = wlm_data
            self.freq_db[laser] = freq

            if meas["get_osa_trace"]:
                self.osa_db[laser] = osa

            # fast mode timeout
            if laser_conf["fast_mode"]:
                t_en = laser_conf["fast_mode_set_at"]
                if time.time() > (t_en + self.args.fast_mode_timeout):
                    self.laser_db[laser]["fast_mode"] = False
                    self.save_config_file()
                    logger.info("{} fast mode timeout".format(laser))

            # auto-exposure
            if laser_conf["auto_exposure"]:
                new_exp = laser_conf["exposure"]
                for ccd, peak in enumerate(peaks):

                    # don't try to find a suitable exposure for lasers that
                    # aren't on!
                    if peak < 0.05:
                        break

                    if not (0.4 < peak < 0.6):
                        exp = laser_conf["exposure"][ccd]
                        new_exp[ccd] = exp + 1 if peak < 0.4 else exp - 1
                        new_exp[ccd] = min(new_exp[ccd], self.exp_max[ccd])
                        new_exp[ccd] = max(new_exp[ccd], self.exp_min[ccd])

                if new_exp != exp:
                    self.laser_db[laser]["exposure"] = new_exp
                    self.save_config_file()

            # check which other measurements wanted this data
            for task in self.queue:
                if task["laser"] == laser \
                   and (meas["get_osa_trace"] or not task["get_osa_trace"]):
                    task["done"].set()
                    self.queue.remove(task)
                    logger.info("task {} complete".format(task["id"]))

    def take_freq_measurement(self, laser, f0):
        """ Preform a single frequency measurement """
        logger.info("Taking new frequency measurement for {}".format(laser))

        status, freq = self.wlm.get_frequency()
        freq = {
            "freq": freq,
            "status": int(status),
            "timestamp": time.time()
        }

        # make simulation data more interesting!
        if self.args.simulation:
            freq["freq"] = f0 + np.random.normal(loc=0, scale=10e6)

        peaks = [self.wlm.get_fringe_peak(ccd) for ccd in range(self.num_ccds)]

        return freq, peaks

    def take_osa_measurement(self, laser, osa, get_osa_trace):
        """ Capture an osa trace """
        if not get_osa_trace:
            return {
                "trace": None,
                "timestamp": time.time()
            }

        osa = {"trace": self.osas.get_trace(osa).tolist(),
               "timestamp": time.time()
               }
        return osa

    def take_freq_osa_measurement(self, laser, f0, get_osa_trace):
        """ Get frequency and spectral data from the wlm """
        logger.info("Taking new frequency + spectral measurement for {}"
                    .format(laser))

        status, freq = self.wlm.get_frequency()
        freq = {
            "freq": freq,
            "status": int(status),
            "timestamp": time.time()
        }

        # make simulation data more interesting!
        if self.args.simulation:
            freq["freq"] = f0 + np.random.normal(loc=0, scale=10e6)

        peaks = [self.wlm.get_fringe_peak(ccd) for ccd in range(self.num_ccds)]

        if not get_osa_trace:
            osa = {
                "trace": None,
                "timestamp": time.time()
            }
        else:
            osa = {"trace": self.wlm.get_pattern().tolist(),
                   "timestamp": time.time()
                   }

        return (freq, peaks), osa

    def save_config_file(self):
        try:
            self.config["lasers"] = self.laser_db.raw_view
            config_path, _ = get_config_path(self.args, "_server")
            pyon.store_file(config_path, self.config)
        except Exception:
            log.warning("error when trying to save config data")