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