forked from M-Labs/artiq
master, dashboard: support applet requests from experiments
This commit is contained in:
parent
549e09e06b
commit
e45c089428
|
@ -0,0 +1,89 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from PyQt5 import QtCore, QtWidgets
|
||||||
|
|
||||||
|
from artiq.gui import applets
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class AppletsCCBDock(applets.AppletsDock):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
applets.AppletsDock.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
sep = QtWidgets.QAction(self.table)
|
||||||
|
sep.setSeparator(True)
|
||||||
|
self.table.addAction(sep)
|
||||||
|
self.listen_action = QtWidgets.QAction(
|
||||||
|
"Listen to client control broadcasts", self.table)
|
||||||
|
self.listen_action.setCheckable(True)
|
||||||
|
self.table.addAction(self.listen_action)
|
||||||
|
|
||||||
|
def locate_applet(self, name, group, create_groups):
|
||||||
|
if group is None:
|
||||||
|
group = []
|
||||||
|
elif isinstance(group, str):
|
||||||
|
group = [group]
|
||||||
|
|
||||||
|
parent = self.table.invisibleRootItem()
|
||||||
|
for g in group:
|
||||||
|
new_parent = None
|
||||||
|
for i in range(parent.childCount()):
|
||||||
|
child = parent.child(i)
|
||||||
|
if child.ty == "group" and child.text(1) == g:
|
||||||
|
new_parent = child
|
||||||
|
break
|
||||||
|
if new_parent is None:
|
||||||
|
if create_groups:
|
||||||
|
new_parent = self.new_group(g, parent)
|
||||||
|
else:
|
||||||
|
return None, None
|
||||||
|
parent = new_parent
|
||||||
|
|
||||||
|
applet = None
|
||||||
|
for i in range(parent.childCount()):
|
||||||
|
child = parent.child(i)
|
||||||
|
if child.ty == "applet" and child.text(1) == name:
|
||||||
|
applet = child
|
||||||
|
break
|
||||||
|
return parent, applet
|
||||||
|
|
||||||
|
def ccb_create_applet(self, name, command_or_code, group=None, is_code=False):
|
||||||
|
if not self.listen_action.isChecked():
|
||||||
|
return
|
||||||
|
parent, applet = self.locate_applet(name, group, True)
|
||||||
|
if applet is None:
|
||||||
|
applet = self.new(name=name, command=command_or_code, parent=parent)
|
||||||
|
else:
|
||||||
|
applet.setText(2, command_or_code)
|
||||||
|
applet.setCheckState(0, QtCore.Qt.Checked)
|
||||||
|
|
||||||
|
def ccb_disable_applet(self, name, group=None):
|
||||||
|
if not self.listen_action.isChecked():
|
||||||
|
return
|
||||||
|
parent, applet = self.locate_applet(name, group, False)
|
||||||
|
if applet is not None:
|
||||||
|
applet.setCheckState(0, QtCore.Qt.Unchecked)
|
||||||
|
|
||||||
|
def ccb_notify(self, message):
|
||||||
|
try:
|
||||||
|
service = message["service"]
|
||||||
|
args = message["args"]
|
||||||
|
kwargs = message["kwargs"]
|
||||||
|
if service == "create_applet":
|
||||||
|
self.ccb_create_applet(*args, **kwargs)
|
||||||
|
elif service == "disable_applet":
|
||||||
|
self.ccb_disable_applet(*args, **kwargs)
|
||||||
|
except:
|
||||||
|
logger.error("failed to process CCB", exc_info=True)
|
||||||
|
|
||||||
|
def save_state(self):
|
||||||
|
return {
|
||||||
|
"applets": applets.AppletsDock.save_state(self),
|
||||||
|
"listen": self.listen_action.isChecked()
|
||||||
|
}
|
||||||
|
|
||||||
|
def restore_state(self, state):
|
||||||
|
applets.AppletsDock.restore_state(self, state["applets"])
|
||||||
|
self.listen_action.setChecked(state["listen"])
|
|
@ -29,6 +29,7 @@ class FloppingF(EnvExperiment):
|
||||||
0.1, min=0, max=100, step=0.01))
|
0.1, min=0, max=100, step=0.01))
|
||||||
|
|
||||||
self.setattr_device("scheduler")
|
self.setattr_device("scheduler")
|
||||||
|
self.setattr_device("ccb")
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
l = len(self.frequency_scan)
|
l = len(self.frequency_scan)
|
||||||
|
@ -41,6 +42,11 @@ class FloppingF(EnvExperiment):
|
||||||
self.set_dataset("flopping_f_fit", np.full(l, np.nan),
|
self.set_dataset("flopping_f_fit", np.full(l, np.nan),
|
||||||
broadcast=True, save=False)
|
broadcast=True, save=False)
|
||||||
|
|
||||||
|
self.ccb.issue("create_applet", "flopping_f",
|
||||||
|
"${artiq_applet}plot_xy "
|
||||||
|
"flopping_f_brightness --x flopping_f_frequency "
|
||||||
|
"--fit flopping_f_fit")
|
||||||
|
|
||||||
for i, f in enumerate(self.frequency_scan):
|
for i, f in enumerate(self.frequency_scan):
|
||||||
m_brightness = model(f, self.F0) + self.noise_amplitude*random.random()
|
m_brightness = model(f, self.F0) + self.noise_amplitude*random.random()
|
||||||
self.mutate_dataset("flopping_f_frequency", i, f)
|
self.mutate_dataset("flopping_f_frequency", i, f)
|
||||||
|
|
|
@ -15,9 +15,9 @@ from artiq.tools import (atexit_register_coroutine, verbosity_args,
|
||||||
from artiq.protocols.pc_rpc import AsyncioClient
|
from artiq.protocols.pc_rpc import AsyncioClient
|
||||||
from artiq.protocols.broadcast import Receiver
|
from artiq.protocols.broadcast import Receiver
|
||||||
from artiq.gui.models import ModelSubscriber
|
from artiq.gui.models import ModelSubscriber
|
||||||
from artiq.gui import state, applets, log
|
from artiq.gui import state, log
|
||||||
from artiq.dashboard import (experiments, shortcuts, explorer,
|
from artiq.dashboard import (experiments, shortcuts, explorer,
|
||||||
moninj, datasets, schedule)
|
moninj, datasets, schedule, applets_ccb)
|
||||||
|
|
||||||
|
|
||||||
def get_argparser():
|
def get_argparser():
|
||||||
|
@ -119,10 +119,13 @@ def main():
|
||||||
atexit_register_coroutine(subscriber.close)
|
atexit_register_coroutine(subscriber.close)
|
||||||
sub_clients[notifier_name] = subscriber
|
sub_clients[notifier_name] = subscriber
|
||||||
|
|
||||||
log_receiver = Receiver("log", [])
|
broadcast_clients = dict()
|
||||||
loop.run_until_complete(log_receiver.connect(
|
for target in "log", "ccb":
|
||||||
|
client = Receiver(target, [])
|
||||||
|
loop.run_until_complete(client.connect(
|
||||||
args.server, args.port_broadcast))
|
args.server, args.port_broadcast))
|
||||||
atexit_register_coroutine(log_receiver.close)
|
atexit_register_coroutine(client.close)
|
||||||
|
broadcast_clients[target] = client
|
||||||
|
|
||||||
# initialize main window
|
# initialize main window
|
||||||
main_window = MainWindow(args.server)
|
main_window = MainWindow(args.server)
|
||||||
|
@ -152,9 +155,10 @@ def main():
|
||||||
rpc_clients["dataset_db"])
|
rpc_clients["dataset_db"])
|
||||||
smgr.register(d_datasets)
|
smgr.register(d_datasets)
|
||||||
|
|
||||||
d_applets = applets.AppletsDock(main_window, sub_clients["datasets"])
|
d_applets = applets_ccb.AppletsCCBDock(main_window, sub_clients["datasets"])
|
||||||
atexit_register_coroutine(d_applets.stop)
|
atexit_register_coroutine(d_applets.stop)
|
||||||
smgr.register(d_applets)
|
smgr.register(d_applets)
|
||||||
|
broadcast_clients["ccb"].notify_cbs.append(d_applets.ccb_notify)
|
||||||
|
|
||||||
d_ttl_dds = moninj.MonInj()
|
d_ttl_dds = moninj.MonInj()
|
||||||
loop.run_until_complete(d_ttl_dds.start(args.server, args.port_notify))
|
loop.run_until_complete(d_ttl_dds.start(args.server, args.port_notify))
|
||||||
|
@ -166,7 +170,7 @@ def main():
|
||||||
|
|
||||||
logmgr = log.LogDockManager(main_window)
|
logmgr = log.LogDockManager(main_window)
|
||||||
smgr.register(logmgr)
|
smgr.register(logmgr)
|
||||||
log_receiver.notify_cbs.append(logmgr.append_message)
|
broadcast_clients["log"].notify_cbs.append(logmgr.append_message)
|
||||||
widget_log_handler.callback = logmgr.append_message
|
widget_log_handler.callback = logmgr.append_message
|
||||||
|
|
||||||
# lay out docks
|
# lay out docks
|
||||||
|
|
|
@ -69,6 +69,13 @@ def main():
|
||||||
|
|
||||||
log_forwarder.callback = (lambda msg:
|
log_forwarder.callback = (lambda msg:
|
||||||
server_broadcast.broadcast("log", 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)
|
device_db = DeviceDB(args.device_db)
|
||||||
dataset_db = DatasetDB(args.dataset_db)
|
dataset_db = DatasetDB(args.dataset_db)
|
||||||
|
@ -96,7 +103,8 @@ def main():
|
||||||
"scheduler_delete": scheduler.delete,
|
"scheduler_delete": scheduler.delete,
|
||||||
"scheduler_request_termination": scheduler.request_termination,
|
"scheduler_request_termination": scheduler.request_termination,
|
||||||
"scheduler_get_status": scheduler.get_status,
|
"scheduler_get_status": scheduler.get_status,
|
||||||
"scheduler_check_pause": scheduler.check_pause
|
"scheduler_check_pause": scheduler.check_pause,
|
||||||
|
"ccb_issue": ccb_issue,
|
||||||
})
|
})
|
||||||
experiment_db.scan_repository_async()
|
experiment_db.scan_repository_async()
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,12 @@ class DummyScheduler:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DummyCCB:
|
||||||
|
def issue(self, service, *args, **kwargs):
|
||||||
|
logger.info("CCB for service '%s' (args %s, kwargs %s)",
|
||||||
|
service, args, kwargs)
|
||||||
|
|
||||||
|
|
||||||
def get_argparser(with_file=True):
|
def get_argparser(with_file=True):
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Local experiment running tool")
|
description="Local experiment running tool")
|
||||||
|
@ -183,7 +189,8 @@ def run(with_file=False):
|
||||||
init_logger(args)
|
init_logger(args)
|
||||||
|
|
||||||
device_mgr = DeviceManager(DeviceDB(args.device_db),
|
device_mgr = DeviceManager(DeviceDB(args.device_db),
|
||||||
virtual_devices={"scheduler": DummyScheduler()})
|
virtual_devices={"scheduler": DummyScheduler(),
|
||||||
|
"ccb": DummyCCB()})
|
||||||
dataset_db = DatasetDB(args.dataset_db)
|
dataset_db = DatasetDB(args.dataset_db)
|
||||||
dataset_mgr = DatasetManager(dataset_db)
|
dataset_mgr = DatasetManager(dataset_db)
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,10 @@ class Scheduler:
|
||||||
return self._check_pause(rid)
|
return self._check_pause(rid)
|
||||||
|
|
||||||
|
|
||||||
|
class CCB:
|
||||||
|
issue = staticmethod(make_parent_action("ccb_issue"))
|
||||||
|
|
||||||
|
|
||||||
def get_exp(file, class_name):
|
def get_exp(file, class_name):
|
||||||
module = file_import(file, prefix="artiq_worker_")
|
module = file_import(file, prefix="artiq_worker_")
|
||||||
if class_name is None:
|
if class_name is None:
|
||||||
|
@ -189,7 +193,8 @@ def main():
|
||||||
repository_path = None
|
repository_path = None
|
||||||
|
|
||||||
device_mgr = DeviceManager(ParentDeviceDB,
|
device_mgr = DeviceManager(ParentDeviceDB,
|
||||||
virtual_devices={"scheduler": Scheduler()})
|
virtual_devices={"scheduler": Scheduler(),
|
||||||
|
"ccb": CCB()})
|
||||||
dataset_mgr = DatasetManager(ParentDatasetDB)
|
dataset_mgr = DatasetManager(ParentDatasetDB)
|
||||||
|
|
||||||
import_cache.install_hook()
|
import_cache.install_hook()
|
||||||
|
|
Loading…
Reference in New Issue