diff --git a/artiq/frontend/artiq_gui.py b/artiq/frontend/artiq_gui.py index 65c1a0fee..9f2b2f48a 100755 --- a/artiq/frontend/artiq_gui.py +++ b/artiq/frontend/artiq_gui.py @@ -11,9 +11,8 @@ from pyqtgraph import dockarea from artiq.protocols.file_db import FlatFileDB from artiq.protocols.pc_rpc import AsyncioClient -from artiq.protocols.sync_struct import Subscriber from artiq.gui.explorer import ExplorerDock -from artiq.gui.moninj import MonInjTTLDock, MonInjDDSDock +from artiq.gui.moninj import MonInj from artiq.gui.parameters import ParametersDock from artiq.gui.schedule import ScheduleDock from artiq.gui.log import LogDock @@ -65,20 +64,12 @@ def main(): args.server, args.port_notify)) atexit.register(lambda: loop.run_until_complete(d_explorer.sub_close())) - d_ttl = MonInjTTLDock() - loop.run_until_complete(d_ttl.start()) - atexit.register(lambda: loop.run_until_complete(d_ttl.stop())) - d_dds = MonInjDDSDock() - devices_sub = Subscriber("devices", - [d_ttl.init_devices, d_dds.init_devices]) - loop.run_until_complete( - devices_sub.connect(args.server, args.port_notify)) - atexit.register( - lambda: loop.run_until_complete(devices_sub.close())) - - area.addDock(d_dds, "top") - area.addDock(d_ttl, "above", d_dds) - area.addDock(d_explorer, "above", d_ttl) + d_ttl_dds = MonInj() + loop.run_until_complete(d_ttl_dds.start(args.server, args.port_notify)) + atexit.register(lambda: loop.run_until_complete(d_ttl_dds.stop())) + area.addDock(d_ttl_dds.dds_dock, "top") + area.addDock(d_ttl_dds.ttl_dock, "above", d_ttl_dds.dds_dock) + area.addDock(d_explorer, "above", d_ttl_dds.ttl_dock) d_params = ParametersDock() area.addDock(d_params, "right", d_explorer) diff --git a/artiq/gui/moninj.py b/artiq/gui/moninj.py index 97ced770c..9683754d3 100644 --- a/artiq/gui/moninj.py +++ b/artiq/gui/moninj.py @@ -8,6 +8,7 @@ from quamash import QtGui, QtCore from pyqtgraph import dockarea from artiq.tools import TaskObject +from artiq.protocols.sync_struct import Subscriber logger = logging.getLogger(__name__) @@ -55,27 +56,30 @@ class _TTLWidget(QtGui.QFrame): self._expctl_action.setCheckable(True) menu.addAction(self._expctl_action) self._value.addAction(self._expctl_action) - self._expctl_action.triggered.connect(lambda: self.set_force("exp")) + self._expctl_action.triggered.connect(lambda: self.set_mode("exp")) + separator = QtGui.QAction(self._value) + separator.setSeparator(True) + self._value.addAction(separator) self._force1_action = QtGui.QAction("Force 1", self._value) self._force1_action.setCheckable(True) menu.addAction(self._force1_action) self._value.addAction(self._force1_action) - self._force1_action.triggered.connect(lambda: self.set_force("1")) + self._force1_action.triggered.connect(lambda: self.set_mode("1")) self._force0_action = QtGui.QAction("Force 0", self._value) self._force0_action.setCheckable(True) menu.addAction(self._force0_action) self._value.addAction(self._force0_action) - self._force0_action.triggered.connect(lambda: self.set_force("0")) + self._force0_action.triggered.connect(lambda: self.set_mode("0")) self._forcein_action = QtGui.QAction("Force input", self._value) self._forcein_action.setCheckable(True) self._forcein_action.setEnabled(not force_out) menu.addAction(self._forcein_action) self._value.addAction(self._forcein_action) - self._forcein_action.triggered.connect(lambda: self.set_force("in")) + self._forcein_action.triggered.connect(lambda: self.set_mode("in")) self.set_value(0, False, False) - def set_force(self, mode): + def set_mode(self, mode): data = struct.pack("bbb", 2, # MONINJ_REQ_TTLSET self.channel, _mode_enc[mode]) @@ -107,12 +111,75 @@ class _TTLWidget(QtGui.QFrame): self._expctl_action.setChecked(True) +class _DDSWidget(QtGui.QFrame): + def __init__(self, send_to_device, channel, name): + self.send_to_device = send_to_device + self.channel = channel + self.name = name + + QtGui.QFrame.__init__(self) + + self.setFrameShape(QtGui.QFrame.Panel) + self.setFrameShadow(QtGui.QFrame.Raised) + + grid = QtGui.QGridLayout() + self.setLayout(grid) + label = QtGui.QLabel(name) + label.setAlignment(QtCore.Qt.AlignCenter) + grid.addWidget(label, 1, 1) + + self._override = QtGui.QLabel() + self._override.setAlignment(QtCore.Qt.AlignCenter) + grid.addWidget(self._override, 2, 1) + + self._value = QtGui.QLabel() + self._value.setAlignment(QtCore.Qt.AlignCenter) + grid.addWidget(self._value, 3, 1, 6, 1) + + self._value.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) + self._override_action = QtGui.QAction("Override", self._value) + self._override_action.setCheckable(True) + self._value.addAction(self._override_action) + self._override_action.triggered.connect(self._override_clicked) + + self.set_value(0.0, False) + + def _override_clicked(self): + override_en = self._override_action.isChecked() + if override_en: + frequency, ok = QtGui.QInputDialog.getDouble( + None, "DDS override", + "Frequency in MHz for {}:".format(self.name), + value=self._frequency, min=0, decimals=3) + self._override_action.setChecked(ok) + if ok: + print("override set to", frequency) + else: + print("override disabled") + + def set_value(self, frequency, override): + self._frequency = frequency + self._override_action.setChecked(override) + value_s = "{:.3f} MHz".format(frequency) + if override: + value_s = "" + value_s + "" + color = " color=\"red\"" + self._override.setText("OVERRIDE") + else: + color = "" + self._override.setText("") + self._value.setText("{}" + .format(color, value_s)) + + class _DeviceManager: def __init__(self, send_to_device, init): self.send_to_device = send_to_device self.ddb = dict() self.ttl_cb = lambda: None self.ttl_widgets = dict() + self.dds_cb = lambda: None + self.dds_widgets = dict() for k, v in init.items(): self[k] = v @@ -123,12 +190,19 @@ class _DeviceManager: if not isinstance(v, dict): return try: - if v["type"] == "local" and v["module"] == "artiq.coredevice.ttl": - channel = v["arguments"]["channel"] - force_out = v["class"] == "TTLOut" - self.ttl_widgets[channel] = _TTLWidget( - self.send_to_device, channel, force_out, k) - self.ttl_cb() + if v["type"] == "local": + if v["module"] == "artiq.coredevice.ttl": + channel = v["arguments"]["channel"] + force_out = v["class"] == "TTLOut" + self.ttl_widgets[channel] = _TTLWidget( + self.send_to_device, channel, force_out, k) + self.ttl_cb() + if (v["module"] == "artiq.coredevice.dds" + and v["class"] == "DDS"): + channel = v["arguments"]["channel"] + self.dds_widgets[channel] = _DDSWidget( + self.send_to_device, channel, k) + self.dds_cb() except KeyError: pass @@ -148,27 +222,53 @@ class _DeviceManager: return None -class MonInjTTLDock(dockarea.Dock, TaskObject): - def __init__(self): - dockarea.Dock.__init__(self, "TTL", size=(1500, 500)) - self.dm = _DeviceManager(self.send_to_device, dict()) - self.transport = None +class _MonInjDock(dockarea.Dock): + def __init__(self, name): + dockarea.Dock.__init__(self, name, size=(1500, 500)) self.grid = QtGui.QGridLayout() gridw = QtGui.QWidget() gridw.setLayout(self.grid) self.addWidget(gridw) + def layout_widgets(self, widgets): + w = self.grid.itemAt(0) + while w is not None: + self.grid.removeItem(w) + w = self.grid.itemAt(0) + for i, (_, w) in enumerate(sorted(widgets, key=itemgetter(0))): + self.grid.addWidget(w, i // 4, i % 4) + + +class MonInj(TaskObject): + def __init__(self): + self.ttl_dock = _MonInjDock("TTL") + self.dds_dock = _MonInjDock("DDS") + + self.subscriber = Subscriber("devices", self.init_devices) + self.dm = _DeviceManager(self.send_to_device, dict()) + self.transport = None + @asyncio.coroutine - def start(self): + def start(self, server, port): loop = asyncio.get_event_loop() yield from loop.create_datagram_endpoint(lambda: self, family=socket.AF_INET) - TaskObject.start(self) + try: + yield from self.subscriber.connect(server, port) + try: + TaskObject.start(self) + except: + yield from self.subscriber.close() + raise + except: + self.transport.close() + raise @asyncio.coroutine def stop(self): yield from TaskObject.stop(self) + yield from self.subscriber.close() if self.transport is not None: self.transport.close() self.transport = None @@ -205,25 +305,12 @@ class MonInjTTLDock(dockarea.Dock, TaskObject): # MONINJ_REQ_MONITOR self.send_to_device(b"\x01") - def layout_ttl_widgets(self): - w = self.grid.itemAt(0) - while w is not None: - self.grid.removeItem(w) - w = self.grid.itemAt(0) - for i, (_, w) in enumerate(sorted(self.dm.ttl_widgets.items(), - key=itemgetter(0))): - self.grid.addWidget(w, i // 4, i % 4) - def init_devices(self, d): self.dm = _DeviceManager(self.send_to_device, d) - self.dm.ttl_cb = self.layout_ttl_widgets - self.layout_ttl_widgets() + self.dm.ttl_cb = lambda: self.ttl_dock.layout_widgets( + self.dm.ttl_widgets.items()) + self.dm.dds_cb = lambda: self.dds_dock.layout_widgets( + self.dm.dds_widgets.items()) + self.dm.ttl_cb() + self.dm.dds_cb() return self.dm - - -class MonInjDDSDock(dockarea.Dock): - def __init__(self): - dockarea.Dock.__init__(self, "DDS", size=(1500, 500)) - - def init_devices(self, d): - return d