mirror of https://github.com/m-labs/artiq.git
gui: DDS monitor/injection (WIP)
This commit is contained in:
parent
f84c51fed5
commit
86fbe38371
|
@ -11,9 +11,8 @@ from pyqtgraph import dockarea
|
||||||
|
|
||||||
from artiq.protocols.file_db import FlatFileDB
|
from artiq.protocols.file_db import FlatFileDB
|
||||||
from artiq.protocols.pc_rpc import AsyncioClient
|
from artiq.protocols.pc_rpc import AsyncioClient
|
||||||
from artiq.protocols.sync_struct import Subscriber
|
|
||||||
from artiq.gui.explorer import ExplorerDock
|
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.parameters import ParametersDock
|
||||||
from artiq.gui.schedule import ScheduleDock
|
from artiq.gui.schedule import ScheduleDock
|
||||||
from artiq.gui.log import LogDock
|
from artiq.gui.log import LogDock
|
||||||
|
@ -65,20 +64,12 @@ def main():
|
||||||
args.server, args.port_notify))
|
args.server, args.port_notify))
|
||||||
atexit.register(lambda: loop.run_until_complete(d_explorer.sub_close()))
|
atexit.register(lambda: loop.run_until_complete(d_explorer.sub_close()))
|
||||||
|
|
||||||
d_ttl = MonInjTTLDock()
|
d_ttl_dds = MonInj()
|
||||||
loop.run_until_complete(d_ttl.start())
|
loop.run_until_complete(d_ttl_dds.start(args.server, args.port_notify))
|
||||||
atexit.register(lambda: loop.run_until_complete(d_ttl.stop()))
|
atexit.register(lambda: loop.run_until_complete(d_ttl_dds.stop()))
|
||||||
d_dds = MonInjDDSDock()
|
area.addDock(d_ttl_dds.dds_dock, "top")
|
||||||
devices_sub = Subscriber("devices",
|
area.addDock(d_ttl_dds.ttl_dock, "above", d_ttl_dds.dds_dock)
|
||||||
[d_ttl.init_devices, d_dds.init_devices])
|
area.addDock(d_explorer, "above", d_ttl_dds.ttl_dock)
|
||||||
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_params = ParametersDock()
|
d_params = ParametersDock()
|
||||||
area.addDock(d_params, "right", d_explorer)
|
area.addDock(d_params, "right", d_explorer)
|
||||||
|
|
|
@ -8,6 +8,7 @@ from quamash import QtGui, QtCore
|
||||||
from pyqtgraph import dockarea
|
from pyqtgraph import dockarea
|
||||||
|
|
||||||
from artiq.tools import TaskObject
|
from artiq.tools import TaskObject
|
||||||
|
from artiq.protocols.sync_struct import Subscriber
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -55,27 +56,30 @@ class _TTLWidget(QtGui.QFrame):
|
||||||
self._expctl_action.setCheckable(True)
|
self._expctl_action.setCheckable(True)
|
||||||
menu.addAction(self._expctl_action)
|
menu.addAction(self._expctl_action)
|
||||||
self._value.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 = QtGui.QAction("Force 1", self._value)
|
||||||
self._force1_action.setCheckable(True)
|
self._force1_action.setCheckable(True)
|
||||||
menu.addAction(self._force1_action)
|
menu.addAction(self._force1_action)
|
||||||
self._value.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 = QtGui.QAction("Force 0", self._value)
|
||||||
self._force0_action.setCheckable(True)
|
self._force0_action.setCheckable(True)
|
||||||
menu.addAction(self._force0_action)
|
menu.addAction(self._force0_action)
|
||||||
self._value.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 = QtGui.QAction("Force input", self._value)
|
||||||
self._forcein_action.setCheckable(True)
|
self._forcein_action.setCheckable(True)
|
||||||
self._forcein_action.setEnabled(not force_out)
|
self._forcein_action.setEnabled(not force_out)
|
||||||
menu.addAction(self._forcein_action)
|
menu.addAction(self._forcein_action)
|
||||||
self._value.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)
|
self.set_value(0, False, False)
|
||||||
|
|
||||||
def set_force(self, mode):
|
def set_mode(self, mode):
|
||||||
data = struct.pack("bbb",
|
data = struct.pack("bbb",
|
||||||
2, # MONINJ_REQ_TTLSET
|
2, # MONINJ_REQ_TTLSET
|
||||||
self.channel, _mode_enc[mode])
|
self.channel, _mode_enc[mode])
|
||||||
|
@ -107,12 +111,75 @@ class _TTLWidget(QtGui.QFrame):
|
||||||
self._expctl_action.setChecked(True)
|
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 = "<b>" + value_s + "</b>"
|
||||||
|
color = " color=\"red\""
|
||||||
|
self._override.setText("<font size=\"1\" color=\"red\">OVERRIDE</font>")
|
||||||
|
else:
|
||||||
|
color = ""
|
||||||
|
self._override.setText("")
|
||||||
|
self._value.setText("<font size=\"9\"{}>{}</font>"
|
||||||
|
.format(color, value_s))
|
||||||
|
|
||||||
|
|
||||||
class _DeviceManager:
|
class _DeviceManager:
|
||||||
def __init__(self, send_to_device, init):
|
def __init__(self, send_to_device, init):
|
||||||
self.send_to_device = send_to_device
|
self.send_to_device = send_to_device
|
||||||
self.ddb = dict()
|
self.ddb = dict()
|
||||||
self.ttl_cb = lambda: None
|
self.ttl_cb = lambda: None
|
||||||
self.ttl_widgets = dict()
|
self.ttl_widgets = dict()
|
||||||
|
self.dds_cb = lambda: None
|
||||||
|
self.dds_widgets = dict()
|
||||||
for k, v in init.items():
|
for k, v in init.items():
|
||||||
self[k] = v
|
self[k] = v
|
||||||
|
|
||||||
|
@ -123,12 +190,19 @@ class _DeviceManager:
|
||||||
if not isinstance(v, dict):
|
if not isinstance(v, dict):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
if v["type"] == "local" and v["module"] == "artiq.coredevice.ttl":
|
if v["type"] == "local":
|
||||||
|
if v["module"] == "artiq.coredevice.ttl":
|
||||||
channel = v["arguments"]["channel"]
|
channel = v["arguments"]["channel"]
|
||||||
force_out = v["class"] == "TTLOut"
|
force_out = v["class"] == "TTLOut"
|
||||||
self.ttl_widgets[channel] = _TTLWidget(
|
self.ttl_widgets[channel] = _TTLWidget(
|
||||||
self.send_to_device, channel, force_out, k)
|
self.send_to_device, channel, force_out, k)
|
||||||
self.ttl_cb()
|
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:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -148,27 +222,53 @@ class _DeviceManager:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class MonInjTTLDock(dockarea.Dock, TaskObject):
|
class _MonInjDock(dockarea.Dock):
|
||||||
def __init__(self):
|
def __init__(self, name):
|
||||||
dockarea.Dock.__init__(self, "TTL", size=(1500, 500))
|
dockarea.Dock.__init__(self, name, size=(1500, 500))
|
||||||
self.dm = _DeviceManager(self.send_to_device, dict())
|
|
||||||
self.transport = None
|
|
||||||
|
|
||||||
self.grid = QtGui.QGridLayout()
|
self.grid = QtGui.QGridLayout()
|
||||||
gridw = QtGui.QWidget()
|
gridw = QtGui.QWidget()
|
||||||
gridw.setLayout(self.grid)
|
gridw.setLayout(self.grid)
|
||||||
self.addWidget(gridw)
|
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
|
@asyncio.coroutine
|
||||||
def start(self):
|
def start(self, server, port):
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
yield from loop.create_datagram_endpoint(lambda: self,
|
yield from loop.create_datagram_endpoint(lambda: self,
|
||||||
family=socket.AF_INET)
|
family=socket.AF_INET)
|
||||||
|
try:
|
||||||
|
yield from self.subscriber.connect(server, port)
|
||||||
|
try:
|
||||||
TaskObject.start(self)
|
TaskObject.start(self)
|
||||||
|
except:
|
||||||
|
yield from self.subscriber.close()
|
||||||
|
raise
|
||||||
|
except:
|
||||||
|
self.transport.close()
|
||||||
|
raise
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def stop(self):
|
def stop(self):
|
||||||
yield from TaskObject.stop(self)
|
yield from TaskObject.stop(self)
|
||||||
|
yield from self.subscriber.close()
|
||||||
if self.transport is not None:
|
if self.transport is not None:
|
||||||
self.transport.close()
|
self.transport.close()
|
||||||
self.transport = None
|
self.transport = None
|
||||||
|
@ -205,25 +305,12 @@ class MonInjTTLDock(dockarea.Dock, TaskObject):
|
||||||
# MONINJ_REQ_MONITOR
|
# MONINJ_REQ_MONITOR
|
||||||
self.send_to_device(b"\x01")
|
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):
|
def init_devices(self, d):
|
||||||
self.dm = _DeviceManager(self.send_to_device, d)
|
self.dm = _DeviceManager(self.send_to_device, d)
|
||||||
self.dm.ttl_cb = self.layout_ttl_widgets
|
self.dm.ttl_cb = lambda: self.ttl_dock.layout_widgets(
|
||||||
self.layout_ttl_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
|
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
|
|
||||||
|
|
Loading…
Reference in New Issue