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))
|
||||
|
||||
self.setattr_device("scheduler")
|
||||
self.setattr_device("ccb")
|
||||
|
||||
def run(self):
|
||||
l = len(self.frequency_scan)
|
||||
|
@ -41,6 +42,11 @@ class FloppingF(EnvExperiment):
|
|||
self.set_dataset("flopping_f_fit", np.full(l, np.nan),
|
||||
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):
|
||||
m_brightness = model(f, self.F0) + self.noise_amplitude*random.random()
|
||||
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.broadcast import Receiver
|
||||
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,
|
||||
moninj, datasets, schedule)
|
||||
moninj, datasets, schedule, applets_ccb)
|
||||
|
||||
|
||||
def get_argparser():
|
||||
|
@ -119,10 +119,13 @@ def main():
|
|||
atexit_register_coroutine(subscriber.close)
|
||||
sub_clients[notifier_name] = subscriber
|
||||
|
||||
log_receiver = Receiver("log", [])
|
||||
loop.run_until_complete(log_receiver.connect(
|
||||
broadcast_clients = dict()
|
||||
for target in "log", "ccb":
|
||||
client = Receiver(target, [])
|
||||
loop.run_until_complete(client.connect(
|
||||
args.server, args.port_broadcast))
|
||||
atexit_register_coroutine(log_receiver.close)
|
||||
atexit_register_coroutine(client.close)
|
||||
broadcast_clients[target] = client
|
||||
|
||||
# initialize main window
|
||||
main_window = MainWindow(args.server)
|
||||
|
@ -152,9 +155,10 @@ def main():
|
|||
rpc_clients["dataset_db"])
|
||||
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)
|
||||
smgr.register(d_applets)
|
||||
broadcast_clients["ccb"].notify_cbs.append(d_applets.ccb_notify)
|
||||
|
||||
d_ttl_dds = moninj.MonInj()
|
||||
loop.run_until_complete(d_ttl_dds.start(args.server, args.port_notify))
|
||||
|
@ -166,7 +170,7 @@ def main():
|
|||
|
||||
logmgr = log.LogDockManager(main_window)
|
||||
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
|
||||
|
||||
# lay out docks
|
||||
|
|
|
@ -69,6 +69,13 @@ def main():
|
|||
|
||||
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)
|
||||
|
@ -96,7 +103,8 @@ def main():
|
|||
"scheduler_delete": scheduler.delete,
|
||||
"scheduler_request_termination": scheduler.request_termination,
|
||||
"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()
|
||||
|
||||
|
|
|
@ -118,6 +118,12 @@ class DummyScheduler:
|
|||
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):
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Local experiment running tool")
|
||||
|
@ -183,7 +189,8 @@ def run(with_file=False):
|
|||
init_logger(args)
|
||||
|
||||
device_mgr = DeviceManager(DeviceDB(args.device_db),
|
||||
virtual_devices={"scheduler": DummyScheduler()})
|
||||
virtual_devices={"scheduler": DummyScheduler(),
|
||||
"ccb": DummyCCB()})
|
||||
dataset_db = DatasetDB(args.dataset_db)
|
||||
dataset_mgr = DatasetManager(dataset_db)
|
||||
|
||||
|
|
|
@ -106,6 +106,10 @@ class Scheduler:
|
|||
return self._check_pause(rid)
|
||||
|
||||
|
||||
class CCB:
|
||||
issue = staticmethod(make_parent_action("ccb_issue"))
|
||||
|
||||
|
||||
def get_exp(file, class_name):
|
||||
module = file_import(file, prefix="artiq_worker_")
|
||||
if class_name is None:
|
||||
|
@ -189,7 +193,8 @@ def main():
|
|||
repository_path = None
|
||||
|
||||
device_mgr = DeviceManager(ParentDeviceDB,
|
||||
virtual_devices={"scheduler": Scheduler()})
|
||||
virtual_devices={"scheduler": Scheduler(),
|
||||
"ccb": CCB()})
|
||||
dataset_mgr = DatasetManager(ParentDatasetDB)
|
||||
|
||||
import_cache.install_hook()
|
||||
|
|
Loading…
Reference in New Issue