示例#1
0
def main():
    args = get_argparser().parse_args()
    common_args.init_logger_from_args(args)

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    atexit.register(loop.close)
    signal_handler = SignalHandler()
    signal_handler.setup()
    atexit.register(signal_handler.teardown)

    writer = DBWriter(args.baseurl_db,
                      args.user_db, args.password_db,
                      args.database, args.table)
    writer.start()
    atexit_register_coroutine(writer.stop)

    filter = Filter(args.pattern_file)
    rpc_server = Server({"influxdb_filter": filter}, builtin_terminate=True)
    loop.run_until_complete(rpc_server.start(common_args.bind_address_from_args(args),
                                             args.port_control))
    atexit_register_coroutine(rpc_server.stop)

    reader = MasterReader(args.server_master, args.port_master,
                          args.retry_master, filter._filter, writer)
    reader.start()
    atexit_register_coroutine(reader.stop)

    _, pending = loop.run_until_complete(asyncio.wait(
        [signal_handler.wait_terminate(), rpc_server.wait_terminate()],
        return_when=asyncio.FIRST_COMPLETED))
    for task in pending:
        task.cancel()
示例#2
0
def main():
    args = get_argparser().parse_args()
    common_args.init_logger_from_args(args)

    loop = asyncio.get_event_loop()
    atexit.register(loop.close)

    writer = DBWriter(args.baseurl_db, args.user_db, args.password_db,
                      args.database, args.table)
    writer.start()
    atexit_register_coroutine(writer.stop)

    log = Log(writer)

    server = Logger()
    rpc_server = Server({"schedule_logger": server}, builtin_terminate=True)
    loop.run_until_complete(
        rpc_server.start(common_args.bind_address_from_args(args),
                         args.port_control))
    atexit_register_coroutine(rpc_server.stop)

    reader = MasterReader(args.server_master, args.port_master,
                          args.retry_master, log)
    reader.start()
    atexit_register_coroutine(reader.stop)

    loop.run_until_complete(rpc_server.wait_terminate())
示例#3
0
def main():
    args = get_argparser().parse_args()
    common_args.init_logger_from_args(args)

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    try:
        signal_handler = SignalHandler()
        signal_handler.setup()
        try:
            get_logs_task = asyncio.ensure_future(
                get_logs_sim(args.core_addr) if args.simulation else get_logs(args.core_addr))
            try:
                server = Server({"corelog": PingTarget()}, None, True)
                loop.run_until_complete(server.start(common_args.bind_address_from_args(args), args.port))
                try:
                    _, pending = loop.run_until_complete(asyncio.wait(
                        [signal_handler.wait_terminate(),
                         server.wait_terminate(),
                         get_logs_task],
                        return_when=asyncio.FIRST_COMPLETED))
                    for task in pending:
                        task.cancel()
                finally:
                    loop.run_until_complete(server.stop())
            finally:
                pass
        finally:
            signal_handler.teardown()
    finally:
        loop.close()
示例#4
0
def main():
    args = get_argparser().parse_args()
    common_args.init_logger_from_args(args)

    loop = asyncio.get_event_loop()
    try:
        get_logs_task = asyncio.ensure_future(
            get_logs_sim(args.core_addr) if args.
            simulation else get_logs(args.core_addr))
        try:
            server = Server({"corelog": PingTarget()}, None, True)
            loop.run_until_complete(
                server.start(common_args.bind_address_from_args(args),
                             args.port))
            try:
                loop.run_until_complete(server.wait_terminate())
            finally:
                loop.run_until_complete(server.stop())
        finally:
            get_logs_task.cancel()
            try:
                loop.run_until_complete(get_logs_task)
            except asyncio.CancelledError:
                pass
    finally:
        loop.close()
 def connect_asyncio_server(self):
     self.loop = asyncio.get_event_loop()
     self.asyncio_server = Server(
         {
             "pulse_sequence_visualizer":
             PulseSequenceVisualizerServer(self),
             "simulation_logger": simulation_logger
         }, None, True)
     self.task = self.loop.create_task(
         self.asyncio_server.start("::1", 3289))
示例#6
0
def main():
    args = get_argparser().parse_args()

    root_logger = logging.getLogger()
    root_logger.setLevel(logging.NOTSET)
    source_adder = SourceFilter(logging.WARNING +
                                args.quiet*10 - args.verbose*10,
                                "ctlmgr({})".format(platform.node()))
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(logging.Formatter(
        "%(levelname)s:%(source)s:%(name)s:%(message)s"))
    console_handler.addFilter(source_adder)
    root_logger.addHandler(console_handler)

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    atexit.register(loop.close)
    signal_handler = SignalHandler()
    signal_handler.setup()
    atexit.register(signal_handler.teardown)

    logfwd = LogForwarder(args.server, args.port_logging,
                          args.retry_master)
    logfwd.addFilter(source_adder)
    root_logger.addHandler(logfwd)
    logfwd.start()
    atexit_register_coroutine(logfwd.stop)

    ctlmgr = ControllerManager(args.server, args.port_notify,
                               args.retry_master, args.host_filter)
    ctlmgr.start()
    atexit_register_coroutine(ctlmgr.stop)

    class CtlMgrRPC:
        retry_now = ctlmgr.retry_now

    rpc_target = CtlMgrRPC()
    rpc_server = Server({"ctlmgr": rpc_target}, builtin_terminate=True)
    loop.run_until_complete(rpc_server.start(common_args.bind_address_from_args(args),
                                             args.port_control))
    atexit_register_coroutine(rpc_server.stop)

    _, pending = loop.run_until_complete(asyncio.wait(
        [signal_handler.wait_terminate(), rpc_server.wait_terminate()],
        return_when=asyncio.FIRST_COMPLETED))
    for task in pending:
        task.cancel()
示例#7
0
 async def run():
     with await Shutter.connect(args.device, loop=loop) as dev:
         server = Server({"ptb_shutter": dev}, None, True)
         await server.start(bind_address_from_args(args), args.port)
         try:
             await server.wait_terminate()
         finally:
             await server.stop()
示例#8
0
 async def run():
     async with RPCClient(NetworkConnection(args.device, loop=loop)) as dev:
         server = Server({"laser": dev}, None, True)
         await server.start(common_args.bind_address_from_args(args), args.port)
         try:
             await server.wait_terminate()
         finally:
             await server.stop()
示例#9
0
def main():
    args = get_argparser().parse_args()

    root_logger = logging.getLogger()
    root_logger.setLevel(logging.NOTSET)
    source_adder = SourceFilter(logging.WARNING +
                                args.quiet*10 - args.verbose*10,
                                "ctlmgr({})".format(platform.node()))
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(logging.Formatter(
        "%(levelname)s:%(source)s:%(name)s:%(message)s"))
    console_handler.addFilter(source_adder)
    root_logger.addHandler(console_handler)

    if os.name == "nt":
        loop = asyncio.ProactorEventLoop()
        asyncio.set_event_loop(loop)
    else:
        loop = asyncio.get_event_loop()
    atexit.register(loop.close)

    logfwd = LogForwarder(args.server, args.port_logging,
                          args.retry_master)
    logfwd.addFilter(source_adder)
    root_logger.addHandler(logfwd)
    logfwd.start()
    atexit_register_coroutine(logfwd.stop)

    ctlmgr = ControllerManager(args.server, args.port_notify,
                               args.retry_master)
    ctlmgr.start()
    atexit_register_coroutine(ctlmgr.stop)

    class CtlMgrRPC:
        retry_now = ctlmgr.retry_now

    rpc_target = CtlMgrRPC()
    rpc_server = Server({"ctlmgr": rpc_target}, builtin_terminate=True)
    loop.run_until_complete(rpc_server.start(common_args.bind_address_from_args(args),
                                             args.port_control))
    atexit_register_coroutine(rpc_server.stop)

    loop.run_until_complete(rpc_server.wait_terminate())
示例#10
0
def main():
    args = get_argparser().parse_args()
    common_args.init_logger_from_args(args)

    bind_address = common_args.bind_address_from_args(args)

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    try:
        signal_handler = SignalHandler()
        signal_handler.setup()
        try:
            monitor_mux = MonitorMux()
            comm_moninj = CommMonInj(monitor_mux.monitor_cb,
                                     monitor_mux.injection_status_cb,
                                     monitor_mux.disconnect_cb)
            monitor_mux.comm_moninj = comm_moninj
            loop.run_until_complete(comm_moninj.connect(args.core_addr))
            try:
                proxy_server = ProxyServer(monitor_mux)
                loop.run_until_complete(proxy_server.start(bind_address, args.port_proxy))
                try:
                    server = Server({"moninj_proxy": PingTarget()}, None, True)
                    loop.run_until_complete(server.start(bind_address, args.port_control))
                    try:
                        _, pending = loop.run_until_complete(asyncio.wait(
                            [signal_handler.wait_terminate(),
                             server.wait_terminate(),
                             comm_moninj.wait_terminate()],
                            return_when=asyncio.FIRST_COMPLETED))
                        for task in pending:
                            task.cancel()
                    finally:
                        loop.run_until_complete(server.stop())
                finally:
                    loop.run_until_complete(proxy_server.stop())
            finally:
                loop.run_until_complete(comm_moninj.close())
        finally:
            signal_handler.teardown()
    finally:
        loop.close()
示例#11
0
 async def run():
     await dev.connect(args.uri, user=args.user, password=args.password)
     await dev.misc()
     server = Server({"oors": dev}, None, True)
     await server.start(bind_address_from_args(args), args.port)
     try:
         await server.wait_terminate()
     except KeyboardInterrupt:
         pass
     finally:
         await server.stop()
示例#12
0
 async def run():
     with await Wavemeter.connect(args.device,
                                  port=args.device_port,
                                  loop=loop) as dev:
         # only wavemeter
         # logger.debug("connected, version %s", await dev.get_version())
         server = Server({"wavemeter": dev}, None, True)
         await server.start(common_args.bind_address_from_args(args),
                            args.port)
         try:
             await server.wait_terminate()
         finally:
             await server.stop()
示例#13
0
 def connect_asyncio_server(self):
     self.loop = asyncio.get_event_loop()
     self.asyncio_server = Server(
         {"pmt_histogram": self.RemotePlotting(self)}, None, True)
     self.task = self.loop.create_task(
         self.asyncio_server.start("::1", 3287))
示例#14
0
class PMTReadoutDock(QtWidgets.QDockWidget):
    def __init__(self, acxn):
        QtWidgets.QDockWidget.__init__(self, "PMT Readout")
        self.acxn = acxn
        self.cxn = None
        self.p = None
        try:
            self.cxn = labrad.connect()
            self.p = self.cxn.parametervault
        except:
            logger.error("Failed to initially connect to labrad.",
                         exc_info=True)
            self.setDisabled(True)
        self.current_line = 0
        self.number_lines = 0
        self.hist = None
        self.setObjectName("PMTReadoutHistogram")
        self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable
                         | QtWidgets.QDockWidget.DockWidgetFloatable)
        self.main_widget = QtWidgets.QWidget()
        self.setWidget(self.main_widget)
        self.make_GUI()
        self.connect_GUI()
        self.connect_asyncio_server()

    def save_state(self):
        pass

    def restore_state(self):
        pass

    def connect_asyncio_server(self):
        self.loop = asyncio.get_event_loop()
        self.asyncio_server = Server(
            {"pmt_histogram": self.RemotePlotting(self)}, None, True)
        self.task = self.loop.create_task(
            self.asyncio_server.start("::1", 3287))

    class RemotePlotting:
        def __init__(self, hist):
            self.hist = hist

        def plot(self, data):
            if self.hist.hist is not None:
                for bar in self.hist.hist:
                    try:
                        bar.remove()
                    except ValueError as e:
                        continue
            _, _, self.hist.hist = self.hist.ax.hist(data,
                                                     bins=35,
                                                     histtype="bar",
                                                     rwidth=1,
                                                     edgecolor="k",
                                                     linewidth=1.2)
            self.hist.canvas.draw()
            self.hist.ax.autoscale(enable=True, axis="both")
            self.hist.ax.set_xlim(left=0)
            self.hist.ax.relim()

    def closeEvent(self, event):
        self.task.cancel()
        self.loop.create_task(self.asyncio_server.stop())
        super(PMTReadoutDock, self).closeEvent(event)

    def make_GUI(self):
        layout = QtWidgets.QGridLayout()

        self.fig = Figure()
        self.fig.patch.set_facecolor((.97, .96, .96))
        self.canvas = FigureCanvasQTAgg(self.fig)
        self.canvas.setParent(self)
        self.ax = self.fig.add_subplot(111)
        self.ax.set_ylim((0, 50))
        self.ax.set_xlim((0, 100))
        self.ax.set_facecolor((.97, .96, .96))
        self.ax.tick_params(top=False,
                            bottom=False,
                            left=False,
                            right=False,
                            labeltop=True,
                            labelbottom=True,
                            labelleft=True,
                            labelright=True)
        self.mpl_toolbar = NavigationToolbar2QT(self.canvas, self)
        self.fig.tight_layout()
        self.canvas.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                  QtWidgets.QSizePolicy.Expanding)
        self.ax.tick_params(axis="both", direction="in")

        self.n_thresholds = None
        self.curr_threshold = None
        if self.p:
            lines = self.p.get_parameter(["StateReadout", "threshold_list"])
            slines = sorted(lines)
            if not list(slines) == list(lines):
                self.p.set_parameter(
                    ["StateReadout", "threshold_list", slines])
                lines = slines
            self.number_lines = len(lines)
            self.lines = [
                self.ax.axvline(line, lw=3, color="r") for line in lines
            ]
            self.n_thresholds = QtWidgets.QSpinBox()
            self.n_thresholds.setValue(len(lines))
            self.n_thresholds.setMinimum(1)
            self.n_thresholds.setMaximum(10)
            self.curr_threshold = QtWidgets.QSpinBox()
            self.curr_threshold.setValue(1)
            self.curr_threshold.setMinimum(1)
            self.curr_threshold.setMaximum(len(lines))

            layout.addWidget(self.mpl_toolbar, 0, 0)
            layout.addWidget(QtWidgets.QLabel("no. thresholds: "), 0, 1)
            layout.addWidget(self.n_thresholds, 0, 2)
            layout.addWidget(QtWidgets.QLabel("select threshold: "), 0, 3)
            layout.addWidget(self.curr_threshold, 0, 4)

        layout.addWidget(self.canvas, 1, 0, 1, 5)
        self.main_widget.setLayout(layout)

        if self.cxn:
            self.cxn.disconnect()

    def connect_GUI(self):
        self.canvas.mpl_connect("button_press_event", self.on_click)
        if self.n_thresholds:
            self.n_thresholds.valueChanged.connect(self.n_thresholds_changed)
        if self.curr_threshold:
            self.curr_threshold.valueChanged.connect(
                self.curr_threshold_changed)

    @inlineCallbacks
    def n_thresholds_changed(self, val):
        p = yield self.acxn.get_server("ParameterVault")
        self.curr_threshold.setMaximum(int(val))
        diff = val - self.number_lines
        self.number_lines = val
        if diff < 0:
            for _ in range(abs(diff)):
                l = self.lines.pop()
                l.remove()
                del l
                self.canvas.draw()
            tlist = yield p.get_parameter(["StateReadout", "threshold_list"])
            tlist = tlist[:diff]
            yield p.set_parameter(["StateReadout", "threshold_list", tlist])

        if diff > 0:
            for _ in range(diff):
                tlist = yield p.get_parameter(
                    ["StateReadout", "threshold_list"])
                maxt = max(tlist)
                tlist = np.append(tlist, maxt + 2)
                self.lines.append(self.ax.axvline(maxt + 2, lw=3, color="r"))
                yield p.set_parameter(
                    ["StateReadout", "threshold_list", tlist])
                self.canvas.draw()

    def curr_threshold_changed(self, val):
        self.current_line = int(val) - 1

    @inlineCallbacks
    def on_click(self, event):
        p = yield self.acxn.get_server("ParameterVault")
        if type(event.button) == int and not event.xdata is None:
            xval = int(round(event.xdata))
            idx = self.current_line
            tlist = yield p.get_parameter(["StateReadout", "threshold_list"])
            tlist = tlist
            tlist[idx] = xval
            if idx > 0:
                if tlist[idx - 1] >= tlist[idx]:
                    return
            if idx < len(tlist) - 1:
                if tlist[idx] >= tlist[idx + 1]:
                    return
            yield p.set_parameter(["StateReadout", "threshold_list", tlist])
示例#15
0
class CameraReadoutDock(QtWidgets.QDockWidget):
    def __init__(self, acxn):
        QtWidgets.QDockWidget.__init__(self, "Camera Readout")
        self.acxn = acxn
        self.setObjectName("CameraReadoutHistogram")
        self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable
                         | QtWidgets.QDockWidget.DockWidgetFloatable)
        self.image = None
        self.image_region = None
        self.run_time = None
        self.main_widget = QtWidgets.QWidget()
        self.setWidget(self.main_widget)
        self.make_GUI()
        self.connect_GUI()
        self.connect_asyncio_server()

    def connect_asyncio_server(self):
        self.loop = asyncio.get_event_loop()
        self.asyncio_server = Server(
            {"camera_reference_image": self.RemotePlotting(self)}, None, True)
        self.task = self.loop.create_task(
            self.asyncio_server.start("::1", 3288))

    class RemotePlotting:
        def __init__(self, plt):
            self.plt = plt

        def plot(self, image, image_region, run_time=None):
            self.plt.image = image
            self.plt.image_region = image_region
            if run_time is None:
                self.run_time = dt.now().strftime("%Y%m%d_%H%M.%S")
            try:
                cxn = labrad.connect()
                p = cxn.parametervault
            except:
                logger.error("Couldn't connect to parametervault",
                             exc_info=True)
            N = int(p.get_parameter("IonsOnCamera", "ion_number"))
            x_axis = np.arange(image_region[2], image_region[3] + 1,
                               image_region[0])
            y_axis = np.arange(image_region[4], image_region[5] + 1,
                               image_region[1])
            xx, yy = np.meshgrid(x_axis, y_axis)

            fitter = ion_state_detector(N)
            result, params = fitter.guess_parameters_and_fit(xx, yy, image)
            p.set_parameter("IonsOnCamera", "fit_background_level",
                            params["background_level"].value)
            p.set_parameter("IonsOnCamera", "fit_amplitude",
                            params["amplitude"].value)
            p.set_parameter("IonsOnCamera", "fit_rotation_angle",
                            params["rotation_angle"].value)
            p.set_parameter("IonsOnCamera", "fit_center_horizontal",
                            params["center_x"].value)
            p.set_parameter("IonsOnCamera", "fit_center_vertical",
                            params["center_y"].value)
            p.set_parameter("IonsOnCamera", "fit_spacing",
                            params["spacing"].value)
            p.set_parameter("IonsOnCamera", "fit_sigma", params["sigma"].value)

            self.plt.ax.clear()
            with suppress(Exception):
                self.plt.cb.remove()
            I = self.plt.ax.imshow(image,
                                   cmap="cividis",
                                   interpolation="spline16",
                                   extent=[
                                       x_axis.min(),
                                       x_axis.max(),
                                       y_axis.max(),
                                       y_axis.min()
                                   ])
            self.plt.cb = self.plt.fig.colorbar(I, fraction=0.046, pad=0.04)
            x_axis_fit = np.linspace(x_axis.min(), x_axis.max(),
                                     x_axis.size * 10)
            y_axis_fit = np.linspace(y_axis.min(), y_axis.max(),
                                     y_axis.size * 10)
            xx, yy = np.meshgrid(x_axis_fit, y_axis_fit)
            fit = fitter.ion_model(params, xx, yy)
            self.plt.ax.contour(x_axis_fit,
                                y_axis_fit,
                                fit,
                                3,
                                colors=[(1., .49, 0., .75)])

            if result is not None:
                # print(lmfit.fit_report(result, show_correl=False))
                results_text = lmfit.fit_report(result, show_correl=False)
                param_results = results_text.split("\n")[-7:]
                for i, param_result in enumerate(param_results):
                    param_result = param_result.split("(")[0]
                    param_result = param_result.replace(" +/- ", "(")[:-1]
                    param_result = param_result.split(".")
                    param_result1 = param_result[1].split("(")
                    param_result[1] = param_result1[0][:3] + "("
                    try:
                        param_result[2] = param_result[2][:3]
                    except IndexError:
                        pass
                    param_result = ".".join(param_result)
                    param_result += ")"
                    param_results[i] = param_result
                results_text = "\n".join(param_results)
                results_text += "\n    chi_red = {:.2f}".format(result.redchi)
                results_text += "\n    runtime = " + str(self.run_time)
                self.plt.ax.annotate(results_text, (0.5, 0.75),
                                     xycoords="axes fraction",
                                     color=(1., .49, 0., 1.))

            self.plt.canvas.draw()
            self.plt.ax.relim()
            self.plt.ax.autoscale(enable=True, axis="both")

            cxn.disconnect()

        def enable_button(self):
            self.plt.reference_image_button.setDisabled(False)

    def closeEvent(self, event):
        self.task.cancel()
        self.loop.create_task(self.asyncio_server.stop())
        super(CameraReadoutDock, self).closeEvent(event)

    def make_GUI(self):
        layout = QtWidgets.QGridLayout()

        self.fig = Figure(figsize=(10, 10), tight_layout=True)
        self.fig.patch.set_facecolor((.97, .96, .96))
        self.canvas = FigureCanvasQTAgg(self.fig)
        self.canvas.setParent(self)
        # self.canvas.setMinimumSize(800, 800)
        self.ax = self.fig.add_subplot(111)
        self.ax.set_facecolor((.97, .96, .96))
        self.ax.tick_params(top=False,
                            bottom=False,
                            left=False,
                            right=False,
                            labeltop=True,
                            labelbottom=True,
                            labelleft=True,
                            labelright=False)
        self.mpl_toolbar = NavigationToolbar2QT(self.canvas, self)
        self.canvas.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                  QtWidgets.QSizePolicy.Expanding)
        self.ax.tick_params(axis="both", direction="in")
        self.reference_image_button = QtWidgets.QPushButton("reference image")

        try:
            cxn = labrad.connect()
            p = cxn.parametervault
        except:
            pass
        accessed_params = set()
        parameters = p.get_parameter_names("IonsOnCamera")
        for parameter in parameters:
            accessed_params.update({"IonsOnCamera." + parameter})

        d_accessed_parameter_editor = ParameterEditorDock(
            acxn=None, name="Camera Options", accessed_params=accessed_params)
        d_accessed_parameter_editor.setFeatures(
            QtGui.QDockWidget.NoDockWidgetFeatures)
        d_accessed_parameter_editor.setTitleBarWidget(QtGui.QWidget())
        d_accessed_parameter_editor.table.setMaximumWidth(390)

        layout.addWidget(self.mpl_toolbar, 0, 0, 1, 1)
        layout.addWidget(self.reference_image_button, 0, 2, 1, 1)
        layout.addWidget(d_accessed_parameter_editor, 1, 0, 1, 1)
        layout.addWidget(self.canvas, 1, 1, 1, 2)

        self.main_widget.setLayout(layout)

    def connect_GUI(self):
        self.scheduler = Client("::1", 3251, "master_schedule")
        self.reference_image_button.clicked.connect(self.get_reference_image)

    def get_reference_image(self):
        self.reference_image_button.setDisabled(True)
        expid = {
            "arguments": {},
            "class_name": "ReferenceImage",
            "file": "misc/reference_image.py",
            "log_level": 30,
            "repo_rev": None,
            "priority": 2
        }
        self.scheduler.submit("main", expid, 2)

    def save_state(self):
        return {
            "image": self.image,
            "image_region": self.image_region,
            "run_time": self.run_time
        }

    def restore_state(self, state):
        if state["image"] is not None and state["image_region"] is not None:
            r = self.RemotePlotting(self)
            r.plot(state["image"],
                   state["image_region"],
                   run_time=state["run_time"])
示例#16
0
 def connect_asyncio_server(self):
     self.loop = asyncio.get_event_loop()
     self.asyncio_server = Server(
         {"camera_reference_image": self.RemotePlotting(self)}, None, True)
     self.task = self.loop.create_task(
         self.asyncio_server.start("::1", 3288))
示例#17
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")
示例#18
0
 def connect_server(self):
     self.loop = asyncio.get_event_loop()
     self.server = Server({"rcg": self.RemotePlotting(self.rcg)}, None,
                          True)
     self.task = self.loop.create_task(
         self.server.start(conf.host, conf.port))
示例#19
0
 async def do_test(self):
     server = Server({"target": Target()})
     await server.start("::1", 7777)
     await self.check_value()
     await server.stop()
    def main(extra_args=None):
        logging.getLogger(name).info("Launching controller %s", name)

        def get_argparser():
            parser = argparse.ArgumentParser(
                description="Generic controller for {}".format(name))
            group = parser.add_argument_group(name)
            group.add_argument(
                "--id",
                required=True,
                type=str,
                help=
                "VISA id to connect to. This Controller will obtain an exclusive lock.",
            )
            group.add_argument(
                "--simulation",
                action="store_true",
                help=
                "Run this controller in simulation mode. ID will be ignored but is still required.",
            )
            common_args.simple_network_args(parser, default_port)
            common_args.verbosity_args(parser)

            return parser

        args = get_argparser().parse_args(extra_args)
        common_args.init_logger_from_args(args)

        driver_obj = driver_class(None,
                                  id=args.id,
                                  simulation=args.simulation,
                                  **driver_kwargs)

        loop = asyncio.get_event_loop()

        # Start an ARTIQ server for this device.
        #
        # Allow parallel connections so that functions which don't touch the
        # serial device can be done simultaneously: functions which do are
        # protected by @with_lock.
        server = Server(
            {name: driver_obj},
            description="An automatically generated server for {}".format(
                driver_class.__name__),
            builtin_terminate=True,
            allow_parallel=True,
        )

        loop.run_until_complete(
            server.start(
                host=common_args.bind_address_from_args(args),
                port=args.port,
            ))

        try:
            loop.run_until_complete(server.wait_terminate())
        finally:
            try:
                loop.run_until_complete(server.stop())
            finally:
                # Close the VISA connection after the server has shutdown
                driver_obj.close()

            loop.close()
示例#21
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()
class PulseSequenceVisualizer(QtWidgets.QDockWidget):
    def __init__(self):
        QtWidgets.QDockWidget.__init__(self, "Pulse Sequence")
        self.setObjectName("PulseSequenceDock")
        self.setFeatures(QtWidgets.QDockWidget.NoDockWidgetFeatures)
        # Initialize
        self.last_seq_data = None
        self.last_plot = None
        self.subscribed = False
        self.current_box = None
        self.mpl_connection = None
        self.main_widget = QtWidgets.QWidget()
        self.setWidget(self.main_widget)
        self.create_layout()
        self.connect_asyncio_server()

    def connect_asyncio_server(self):
        self.loop = asyncio.get_event_loop()
        self.asyncio_server = Server(
            {
                "pulse_sequence_visualizer":
                PulseSequenceVisualizerServer(self),
                "simulation_logger": simulation_logger
            }, None, True)
        self.task = self.loop.create_task(
            self.asyncio_server.start("::1", 3289))

    def create_layout(self):
        # Creates GUI layout
        layout = QtGui.QVBoxLayout()
        plot_layout = self.create_plot_layout()
        layout.addLayout(plot_layout)
        self.main_widget.setLayout(layout)

    def create_plot_layout(self):
        # Creates empty matplotlib plot layout
        layout = QtGui.QVBoxLayout()
        self.fig = Figure()
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self)
        self.axes = self.fig.add_subplot(111)
        self.axes.legend(loc='best')
        self.mpl_toolbar = NavigationToolbar(self.canvas, self)
        self.axes.set_title('Most Recent Pulse Sequence', fontsize=22)
        self.axes.set_xlabel('Time (ms)')
        self.fig.tight_layout()
        # Create an empty an invisible annotation, which will be moved around and set to visible later when needed
        self.annot = self.axes.annotate("",
                                        xy=(0, 0),
                                        xytext=(-0.5, 0.5),
                                        textcoords="offset points",
                                        bbox=dict(boxstyle="round", fc="w"),
                                        horizontalalignment='center',
                                        multialignment='left',
                                        verticalalignment='center')
        self.annot.get_bbox_patch().set_alpha(0.8)
        self.annot.set_visible(False)
        # Add the canvas to the GUI widget.
        layout.addWidget(self.mpl_toolbar)
        layout.addWidget(self.canvas)
        return layout

    def on_new_seq(self, dds, ttl, channels, signal_time):
        # Temporary stop tracking mouse movement
        if self.mpl_connection:
            self.canvas.mpl_disconnect(self.mpl_connection)
        self.last_seq_data = {'DDS': dds, 'TTL': ttl, 'channels': channels}
        # Create SequenceAnalyzer object instance
        self.sequence = SequenceAnalyzer(ttl, dds, channels)
        # Clear the plot of all drawn objects
        self.clear_plot()
        # Call the SequenceAnalyzer object's create_full_plot method to draw the plot on the GUI's axes.
        self.sequence.create_full_plot(self.axes)
        self.axes.set_title('Most Recent Pulse Sequence, ' +
                            time.strftime('%Y-%m-%d %H:%M:%S', signal_time))
        # Draw and reconnect to mouse hover events
        self.canvas.draw_idle()
        self.mpl_connection = self.canvas.mpl_connect("motion_notify_event",
                                                      self.hover)

    def clear_plot(self):
        # Remove all lines, boxes, and annotations, except for the hover annotation
        for child in self.axes.get_children():
            if isinstance(child,
                          (matplotlib.lines.Line2D, matplotlib.text.Annotation,
                           matplotlib.collections.PolyCollection)):
                if child is not self.annot:
                    child.remove()

    def format_starttime(self, t):
        # Function for formatting times in the hover annotation
        if round(1e6 * t) < 1000:
            return '{:.1f} $\mu$s'.format(1e6 * t)
        else:
            return '{:.3f} ms'.format(1e3 * t)

    def format_duration(self, t):
        # Function for formatting times in the hover annotation
        if round(1e6 * t) < 1000:
            return '%#.4g $\mu$s' % (1e6 * t)
        else:
            return '%#.4g ms' % (1e3 * t)

    def update_annot(self, dds_box):
        # This function updates the text of the hover annotation.
        drawx = 1e3 * (dds_box.starttime() + dds_box.duration() / 2.0)
        drawy = dds_box.offset + dds_box.scale / 2.0
        self.annot.xy = (drawx, drawy)
        text = '{0}\nStart: {1}\nDuration: {2}\n{3:.4f} MHz\n{4:.2f} amp w/att'.format(
            dds_box.channel, self.format_starttime(dds_box.starttime()),
            self.format_duration(dds_box.duration()), dds_box.frequency(),
            dds_box.amplitude())
        self.annot.set_text(text)

    def hover(self, event):
        # This function is called when the mouse moves
        # It updates the hover annotation if necessary.
        (self.last_mouse_x, self.last_mouse_y) = (event.x, event.y)
        vis = self.annot.get_visible()
        if event.inaxes == self.axes:
            for dds_box in self.sequence.dds_boxes:
                if dds_box.box.contains(event)[0]:
                    if dds_box is not self.current_box:
                        self.current_box = dds_box
                        self.update_annot(dds_box)
                        self.annot.set_visible(True)
                        self.canvas.draw_idle()
                    break
                else:
                    self.current_box = None
                    if vis:
                        self.annot.set_visible(False)
                        self.canvas.draw_idle()
        else:
            self.current_box = None

    def closeEvent(self, event):
        self.loop.create_task(self.asyncio_server.stop())
        super(PulseSequenceVisualizer, self).closeEvent(event)
示例#23
0
class rcgDock(QDockWidgetCloseDetect):
    def __init__(self, main_window):
        QDockWidgetCloseDetect.__init__(self, "Real Complicated Grapher")
        self.setObjectName("RCG")
        self.main_window = main_window
        self.is_closed = False
        self.main_window.addDockWidget(QtCore.Qt.TopDockWidgetArea, self)
        self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable)
        self.setFloating(True)
        self.rcg = RCG()
        self.setWidget(self.rcg)
        self.setTitleBarWidget(QtWidgets.QMainWindow())
        self.top_level_changed()
        self.connect_server()

    def top_level_changed(self):
        if self.isFloating():
            self.setWindowFlags(QtCore.Qt.CustomizeWindowHint
                                | QtCore.Qt.Window
                                | QtCore.Qt.WindowMinimizeButtonHint
                                | QtCore.Qt.WindowMaximizeButtonHint
                                | QtCore.Qt.WindowCloseButtonHint)

    def connect_server(self):
        self.loop = asyncio.get_event_loop()
        self.server = Server({"rcg": self.RemotePlotting(self.rcg)}, None,
                             True)
        self.task = self.loop.create_task(
            self.server.start(conf.host, conf.port))

    def closeEvent(self, event):
        self.is_closed = True
        self.task.cancel()
        self.loop.create_task(self.server.stop())
        super(rcgDock, self).closeEvent(event)

    class RemotePlotting:
        def __init__(self, rcg):
            self.rcg = rcg

        def echo(self, mssg):
            return mssg

        def get_tab_index_from_name(self, name):
            return self.rcg.tabs[name]

        def plot(self,
                 x,
                 y,
                 tab_name="Current",
                 plot_name=None,
                 plot_title="new_plot",
                 append=False,
                 file_=None,
                 range_guess=None):
            if plot_name is None:
                # need to clean this up
                for tab, graph_configs in conf.tab_configs:
                    for gc in graph_configs:
                        if gc.name == tab_name:
                            plot_name = tab_name
                            tab_name = tab
                            break
            idx = self.rcg.tabs[tab_name]
            if type(x) is np.ndarray:
                x = x[~np.isnan(x)]
            if type(y) is np.ndarray:
                y = y[~np.isnan(y)]
            if (plot_title
                    in self.rcg.widget(idx).gw_dict[plot_name].items.keys()
                    and not append):
                i = 1
                while True:
                    try_plot_title = plot_title + str(i)
                    if try_plot_title not in self.rcg.widget(
                            idx).gw_dict[plot_name].items.keys():
                        plot_title = try_plot_title
                        break
                    else:
                        i += 1
            try:
                self.rcg.widget(idx).gw_dict[plot_name].add_plot_item(
                    plot_title,
                    x,
                    y,
                    append=append,
                    file_=file_,
                    range_guess=range_guess)
            except AttributeError:
                # curve not currently displayed on graph
                return

        def plot_from_file(self, file_, tab_name="Current", plot_name=None):
            if plot_name is None:
                plot_name = tab_name
            idx = self.rcg.tabs[tab_name]
            self.rcg.widget(idx).gw_dict[plot_name].upload_curve(file_=file_)
示例#24
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