forked from M-Labs/artiq
1
0
Fork 0

Compare commits

...

10 Commits

7 changed files with 390 additions and 76 deletions

View File

@ -0,0 +1,311 @@
# Sketching up a potential overhaul for the moninj GUI interface
from PyQt5 import QtWidgets, QtCore
from artiq.gui.models import DictSyncTreeSepModel
from artiq.gui.tools import QRecursiveFilterProxyModel
# Not tested with validators or partial editing (textChanged etc). Intended for simple usage.
class BetterLineEdit(QtWidgets.QLineEdit):
finished = QtCore.pyqtSignal(bool)
def __init__(self, init):
QtWidgets.QLineEdit.__init__(self, init)
self.setFrame(False)
self.setReadOnly(True)
self.returnPressed.connect(self._return_pressed)
self.editingFinished.connect(self._editing_finished)
self._text = init
self._candidate = None
def mouseDoubleClickEvent(self, event):
if self.isReadOnly():
self.setReadOnly(False)
self.setFrame(True)
QtWidgets.QLineEdit.mouseDoubleClickEvent(self, event)
def _return_pressed(self):
self._candidate = self.text()
def _editing_finished(self):
self.setReadOnly(True)
self.setFrame(False)
if self._candidate is not None:
changed = self._candidate != self._text
self._text = self._candidate
self.setText(self._text)
self._candidate = None
self.finished.emit(changed)
else:
self.setText(self._text)
def set_text(self, text):
self.blockSignals(True)
self._text = text
self.setText(self._text)
self.blockSignals(False)
def keyPressEvent(self, event):
key = event.key()
if key == QtCore.Qt.Key_Escape and not self.isReadOnly():
self.editingFinished.emit()
else:
QtWidgets.QLineEdit.keyPressEvent(self, event)
# MoninjView contains these and adds according to the proper type
# (the class should be resolved with a helper and the interface generic)
# All widgets should take a refresh hook (slot) for monitoring
# All widgets should expose an inject signal with the "command" and "value"
# -> this is passed directly to the device manager
# suboptimally multiple signals could be exposed
class _MoninjWidget(QtWidgets.QWidget):
inject = QtCore.pyqtSignal(str, str)
nameChanged = QtCore.pyqtSignal()
def __init__(self, name, channel):
QtWidgets.QWidget.__init__(self)
self.name = name
self.channel = channel
self.setMaximumHeight(100)
self.layout = QtWidgets.QGridLayout()
self.setLayout(self.layout)
self.name_label = BetterLineEdit(self.name) # TODO: make this a cancellable line edit -> add cancellable line edit to gui tools
self.name_label.finished.connect(self.name_changed)
self.layout.addWidget(self.name_label, 0, 0)
def name_changed(self, changed):
if changed:
self.name = self.name_label._text
self.nameChanged.emit()
def refresh(self, value):
raise NotImplementedError
class _TTLWidget(_MoninjWidget):
def __init__(self, name, channel):
_MoninjWidget.__init__(self, name, channel)
self.label = QtWidgets.QLabel("0")
self.layout.addWidget(self.label, 0, 1)
self.button_group = QtWidgets.QButtonGroup()
self.button_group.setExclusive(False)
self.lvl = QtWidgets.QPushButton("LVL")
self.lvl.setCheckable(True)
self.layout.addWidget(self.lvl, 0, 2)
self.button_group.addButton(self.lvl, 0)
self.ovr = QtWidgets.QPushButton("OVR")
self.ovr.setCheckable(True)
self.layout.addWidget(self.ovr, 0, 3)
self.button_group.addButton(self.ovr, 1)
self.button_group.idClicked.connect(self._button_clicked)
def _button_clicked(self, id):
lvl = self.lvl.isChecked()
ovr = self.ovr.isChecked()
if lvl and ovr:
self.inject.emit("ttl", "1")
elif not lvl and ovr:
self.inject.emit("ttl", "0")
elif id == 1:
self.inject.emit("ttl", "exp")
def refresh(self, value):
self.label.setText(value)
class _DDSWidget(_MoninjWidget):
def __init__(self, name, channel):
_MoninjWidget.__init__(self, name, channel)
def refresh(self, value):
raise NotImplementedError
class _DACWidget(_MoninjWidget):
def __init__(self, name, channel):
_MoninjWidget.__init__(self, name, channel) # the channel is the actual uid
def refresh(self, value):
raise NotImplementedError
# The main tree / table view of the dock -> probably inherits from QTreeView and connects with the
# 'MoninjModel' MoninjModel and View could be merged as QTreeWidget <-- this is what we will do...
# dont allow nested groups for now
# strongly resembles and borrows from EntryTreeWidget
class MoninjTreeWidget(QtWidgets.QTreeWidget):
def __init__(self):
QtWidgets.QTreeWidget.__init__(self)
self.setDragDropMode(QtWidgets.QTreeWidget.InternalMove)
def add_group(self):
pass
def add_channel(self, channel_args):
pass
def add_channels(self, channels):
pass
def remove_channel(self, id):
pass
def get_configuration(self):
pass
def set_configuration(self, config):
pass
# Like the _AddChannelDialog but should have search function enabled with QRecursiveFilterProxyModel
class MoninjAddChannelDialog(QtWidgets.QDialog):
def __init__(self, parent):
QtWidgets.QDialog.__init__(self, parent=parent)
self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
self.setWindowTitle("Add channels")
layout = QtWidgets.QVBoxLayout()
self.setLayout(layout)
self._search = QtWidgets.QLineEdit()
self._search.setPlaceholderText("search...")
self._search.editingFinished.connect(self._search_datasets)
layout.addWidget(self._search)
self._model = None
self._tree_view = QtWidgets.QTreeView()
self._tree_view.setHeaderHidden(True)
self._tree_view.setSelectionBehavior(
QtWidgets.QAbstractItemView.SelectItems)
self._tree_view.setSelectionMode(
QtWidgets.QAbstractItemView.ExtendedSelection)
layout.addWidget(self._tree_view)
self._button_box = QtWidgets.QDialogButtonBox(
QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel
)
self._button_box.setCenterButtons(True)
self._button_box.accepted.connect(self.add_channels)
self._button_box.rejected.connect(self.reject)
layout.addWidget(self._button_box)
def setModel(self, model):
self._model = model
self._model_filter = QRecursiveFilterProxyModel()
self._model_filter.setSourceModel(model)
self._tree_view.setModel(self._model_filter)
def _search_datasets(self):
if hasattr(self, "_table_filter"):
self.table_model_filter.setFilterFixedString(self._search.displayText())
def add_channels(self):
selection = self._tree_view.selectedIndexes()
channels = []
for select in selection:
key = self._model.index_to_key(select)
if key is not None:
channels.append([key, *self._model[key].ref, []])
self.channels = channels
self.accept()
# Contains the necessary identifiers for listing all available channels, organized by type and name
# does not do any moninj itself, only exists as reference to add channels to 'MoninjModel'
class MoninjChannelModel(DictSyncTreeSepModel):
def __init__(self, init):
DictSyncTreeSepModel.__init__(self, "/", ["Channels"], init)
# Retains most functionality of old DeviceManager (contain any device interface here)
# What previously connected directly with widgets should now connect with 'MoninjModel'
class DeviceManager:
pass
# A standalone Dock
# Should include
# Toolbar header:
# + save and open configurations
# + search bar (sort options / if not in view itself)
# + add channels dialog window
class MoninjDock(QtWidgets.QDockWidget):
def __init__(self, schedule_ctl):
QtWidgets.QDockWidget.__init__(self, "MonInj")
self.setObjectName("MonInj")
self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable |
QtWidgets.QDockWidget.DockWidgetFloatable)
# connect the device manager (it manages ddb + moninj)
self.dm = DeviceManager(schedule_ctl)
# GridLayout
layout = QtWidgets.QGridLayout()
self.setLayout(layout)
# Options (borrow from waveform)
self._menu_btn = QtWidgets.QPushButton()
self._menu_btn.setIcon(
QtWidgets.QApplication.style().standardIcon(
QtWidgets.QStyle.SP_FileDialogStart))
layout.addWidget(self._menu_btn, 0, 0)
self._file_menu = QtWidgets.QMenu()
# self._add_async_action("Open configuration...", self.load_configuration)
# self._add_async_action("Save configuration...", self.save_configuration)
self._menu_btn.setMenu(self._file_menu)
# Add channels
self.channel_model = MoninjChannelModel()
self.add_channel_dialog = MoninjAddChannelDialog()
self.add_channel_dialog.setModel(self.channel_model)
self._add_btn = QtWidgets.QToolButton()
self._add_btn.setToolTip("Add channels...")
self._add_btn.setIcon(
QtWidgets.QApplication.style().standardIcon(
QtWidgets.QStyle.SP_FileDialogListView))
self._add_btn.clicked.connect(self.add_channel_dialog.open)
layout.addWidget(self._add_btn, 0, 2)
# Add new group
self._add_group_btn = QtWidgets.QToolButton()
self._add_group_btn.setToolTip("Add group...")
self._add_group_btn.setIcon(
QtWidgets.QApplication.style().standardIcon(
QtWidgets.QStyle.SP_FileDialogListView))
# connect device manager to channel model (potentially separate out this)
self.dm.update_channels.connect(self.channel_model.update_channels)
# MoninjView and model
self.moninj_model = MoninjModel()
self.moninj_view = MoninjView()
self.moninj_view.setModel(self.moninj_model)
layout.addWidget(self.moninj_view, 1, 0)
# connect device manager to moninj model / view
self.dm.monitor.connect(self.moninj_view.monitor)
self.moninj_view.inject.connect(self.dm.inject)
# add group
self._add_group_btn.clicked.connect(self.moninj_model.new_group)
# is it acceptable for open/closed knowledge to be dropped? only maintained in state
def save_configuration(self):
pass
def open_configuration(self):
pass
def save_state(self):
pass
def restore_state(self):
pass
async def stop(self):
if self.dm is not None:
await self.dm.close()

View File

@ -8,7 +8,6 @@ from sipyco import pyon
from artiq.tools import scale_from_metadata, short_format, exc_to_warning from artiq.tools import scale_from_metadata, short_format, exc_to_warning
from artiq.gui.tools import LayoutWidget, QRecursiveFilterProxyModel from artiq.gui.tools import LayoutWidget, QRecursiveFilterProxyModel
from artiq.gui.models import DictSyncTreeSepModel from artiq.gui.models import DictSyncTreeSepModel
from artiq.gui.scientific_spinbox import ScientificSpinBox
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -5,6 +5,7 @@ from PyQt5 import QtCore, QtWidgets, QtGui
from artiq.gui.models import DictSyncModel from artiq.gui.models import DictSyncModel
from artiq.gui.entries import EntryTreeWidget, procdesc_to_entry from artiq.gui.entries import EntryTreeWidget, procdesc_to_entry
from artiq.gui.tools import LayoutWidget
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -29,32 +30,34 @@ class Model(DictSyncModel):
return k return k
class _InteractiveArgsRequest(QtWidgets.QWidget): class _InteractiveArgsRequest(EntryTreeWidget):
supplied = QtCore.pyqtSignal(int, dict) supplied = QtCore.pyqtSignal(int, dict)
cancelled = QtCore.pyqtSignal(int) cancelled = QtCore.pyqtSignal(int)
def __init__(self, rid, arglist_desc): def __init__(self, rid, arglist_desc):
QtWidgets.QWidget.__init__(self) EntryTreeWidget.__init__(self)
self.rid = rid self.rid = rid
self.arguments = dict() self.arguments = dict()
layout = QtWidgets.QGridLayout()
self.setLayout(layout)
self.entry_tree = EntryTreeWidget()
self.entry_tree.quickStyleClicked.connect(self.supply)
layout.addWidget(self.entry_tree, 0, 0, 1, 2)
for key, procdesc, group, tooltip in arglist_desc: for key, procdesc, group, tooltip in arglist_desc:
self.arguments[key] = {"desc": procdesc, "group": group, "tooltip": tooltip} self.arguments[key] = {"desc": procdesc, "group": group, "tooltip": tooltip}
self.entry_tree.set_argument(key, self.arguments[key]) self.set_argument(key, self.arguments[key])
self.cancel_btn = QtWidgets.QPushButton("Cancel") self.quickStyleClicked.connect(self.supply)
self.cancel_btn.setIcon(QtWidgets.QApplication.style().standardIcon( cancel_btn = QtWidgets.QPushButton("Cancel")
cancel_btn.setIcon(QtWidgets.QApplication.style().standardIcon(
QtWidgets.QStyle.SP_DialogCancelButton)) QtWidgets.QStyle.SP_DialogCancelButton))
self.cancel_btn.clicked.connect(self.cancel) cancel_btn.clicked.connect(self.cancel)
layout.addWidget(self.cancel_btn, 1, 0, 1, 1) supply_btn = QtWidgets.QPushButton("Supply")
self.supply_btn = QtWidgets.QPushButton("Supply") supply_btn.setIcon(QtWidgets.QApplication.style().standardIcon(
self.supply_btn.setIcon(QtWidgets.QApplication.style().standardIcon(
QtWidgets.QStyle.SP_DialogOkButton)) QtWidgets.QStyle.SP_DialogOkButton))
self.supply_btn.clicked.connect(self.supply) supply_btn.clicked.connect(self.supply)
layout.addWidget(self.supply_btn, 1, 1, 1, 1) buttons = LayoutWidget()
buttons.addWidget(cancel_btn, 1, 1)
buttons.addWidget(supply_btn, 1, 2)
buttons.layout.setColumnStretch(0, 1)
buttons.layout.setColumnStretch(1, 0)
buttons.layout.setColumnStretch(2, 0)
buttons.layout.setColumnStretch(3, 1)
self.setItemWidget(self.bottom_item, 1, buttons)
def supply(self): def supply(self):
argument_values = dict() argument_values = dict()
@ -67,18 +70,27 @@ class _InteractiveArgsRequest(QtWidgets.QWidget):
self.cancelled.emit(self.rid) self.cancelled.emit(self.rid)
class _InteractiveArgsView(QtWidgets.QTabWidget): class _InteractiveArgsView(QtWidgets.QStackedWidget):
supplied = QtCore.pyqtSignal(int, dict) supplied = QtCore.pyqtSignal(int, dict)
cancelled = QtCore.pyqtSignal(int) cancelled = QtCore.pyqtSignal(int)
def __init__(self): def __init__(self):
QtWidgets.QTabWidget.__init__(self) QtWidgets.QStackedWidget.__init__(self)
self.tabs = QtWidgets.QTabWidget()
self.default_label = QtWidgets.QLabel("No pending interactive arguments requests.")
self.default_label.setAlignment(QtCore.Qt.AlignCenter)
font = QtGui.QFont(self.default_label.font())
font.setItalic(True)
self.default_label.setFont(font)
self.addWidget(self.tabs)
self.addWidget(self.default_label)
self.model = Model({}) self.model = Model({})
def setModel(self, model): def setModel(self, model):
for i in range(self.count()): self.setCurrentIndex(1)
widget = self.widget(i) for i in range(self.tabs.count()):
self.removeTab(i) widget = self.tabs.widget(i)
self.tabs.removeTab(i)
widget.deleteLater() widget.deleteLater()
self.model = model self.model = model
self.model.rowsInserted.connect(self.rowsInserted) self.model.rowsInserted.connect(self.rowsInserted)
@ -93,17 +105,20 @@ class _InteractiveArgsView(QtWidgets.QTabWidget):
inter_args_request = _InteractiveArgsRequest(rid, arglist_desc) inter_args_request = _InteractiveArgsRequest(rid, arglist_desc)
inter_args_request.supplied.connect(self.supplied) inter_args_request.supplied.connect(self.supplied)
inter_args_request.cancelled.connect(self.cancelled) inter_args_request.cancelled.connect(self.cancelled)
self.insertTab(row, inter_args_request, title) self.tabs.insertTab(row, inter_args_request, title)
def rowsInserted(self, parent, first, last): def rowsInserted(self, parent, first, last):
assert first == last assert first == last
self.setCurrentIndex(0)
self._insert_widget(first) self._insert_widget(first)
def rowsRemoved(self, parent, first, last): def rowsRemoved(self, parent, first, last):
assert first == last assert first == last
widget = self.widget(first) widget = self.tabs.widget(first)
self.removeTab(first) self.tabs.removeTab(first)
widget.deleteLater() widget.deleteLater()
if self.tabs.count() == 0:
self.setCurrentIndex(1)
class InteractiveArgsDock(QtWidgets.QDockWidget): class InteractiveArgsDock(QtWidgets.QDockWidget):

View File

@ -3,20 +3,17 @@ import logging
import textwrap import textwrap
from collections import namedtuple from collections import namedtuple
from PyQt5 import QtCore, QtWidgets, QtGui from PyQt5 import QtCore, QtWidgets
from artiq.coredevice.comm_moninj import * from artiq.coredevice.comm_moninj import CommMonInj, TTLOverride, TTLProbe
from artiq.coredevice.ad9910 import ( from artiq.coredevice.ad9912_reg import AD9912_SER_CONF
_AD9910_REG_PROFILE0, _AD9910_REG_PROFILE7,
_AD9910_REG_FTW, _AD9910_REG_CFR1
)
from artiq.coredevice.ad9912_reg import AD9912_POW1, AD9912_SER_CONF
from artiq.gui.tools import LayoutWidget from artiq.gui.tools import LayoutWidget
from artiq.gui.flowlayout import FlowLayout from artiq.gui.flowlayout import FlowLayout
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class _CancellableLineEdit(QtWidgets.QLineEdit): class _CancellableLineEdit(QtWidgets.QLineEdit):
def escapePressedConnect(self, cb): def escapePressedConnect(self, cb):
self.esc_cb = cb self.esc_cb = cb
@ -131,7 +128,7 @@ class _TTLWidget(QtWidgets.QFrame):
else: else:
color = "" color = ""
self.value.setText("<font size=\"5\"{}>{}</font>".format( self.value.setText("<font size=\"5\"{}>{}</font>".format(
color, value_s)) color, value_s))
oe = self.cur_oe or self.force_out oe = self.cur_oe or self.force_out
direction = "OUT" if oe else "IN" direction = "OUT" if oe else "IN"
self.direction.setText("<font size=\"2\">" + direction + "</font>") self.direction.setText("<font size=\"2\">" + direction + "</font>")
@ -189,7 +186,7 @@ class _DDSModel:
self.cur_reg = 0 self.cur_reg = 0
self.dds_type = dds_type self.dds_type = dds_type
self.is_urukul = dds_type in ["AD9910", "AD9912"] self.is_urukul = dds_type in ["AD9910", "AD9912"]
if dds_type == "AD9914": if dds_type == "AD9914":
self.ftw_per_hz = 2**32 / ref_clk self.ftw_per_hz = 2**32 / ref_clk
else: else:
@ -281,7 +278,7 @@ class _DDSWidget(QtWidgets.QFrame):
set_btn.setText("Set") set_btn.setText("Set")
set_btn.setToolTip("Set frequency") set_btn.setToolTip("Set frequency")
set_grid.addWidget(set_btn, 0, 1, 1, 1) set_grid.addWidget(set_btn, 0, 1, 1, 1)
# for urukuls also allow switching off RF # for urukuls also allow switching off RF
if self.dds_model.is_urukul: if self.dds_model.is_urukul:
off_btn = QtWidgets.QToolButton() off_btn = QtWidgets.QToolButton()
@ -325,18 +322,17 @@ class _DDSWidget(QtWidgets.QFrame):
def set_clicked(self, set): def set_clicked(self, set):
self.data_stack.setCurrentIndex(1) self.data_stack.setCurrentIndex(1)
self.button_stack.setCurrentIndex(1) self.button_stack.setCurrentIndex(1)
self.value_edit.setText("{:.7f}" self.value_edit.setText("{:.7f}".format(self.cur_frequency / 1e6))
.format(self.cur_frequency/1e6))
self.value_edit.setFocus() self.value_edit.setFocus()
self.value_edit.selectAll() self.value_edit.selectAll()
def off_clicked(self, set): def off_clicked(self, set):
self.dm.dds_channel_toggle(self.dds_name, self.dds_model, sw=False) self.dm.dds_channel_toggle(self.dds_name, self.dds_model, sw=False)
def apply_changes(self, apply): def apply_changes(self, apply):
self.data_stack.setCurrentIndex(0) self.data_stack.setCurrentIndex(0)
self.button_stack.setCurrentIndex(0) self.button_stack.setCurrentIndex(0)
frequency = float(self.value_edit.text())*1e6 frequency = float(self.value_edit.text()) * 1e6
self.dm.dds_set_frequency(self.dds_name, self.dds_model, frequency) self.dm.dds_set_frequency(self.dds_name, self.dds_model, frequency)
def cancel_changes(self, cancel): def cancel_changes(self, cancel):
@ -345,10 +341,8 @@ class _DDSWidget(QtWidgets.QFrame):
def refresh_display(self): def refresh_display(self):
self.cur_frequency = self.dds_model.cur_frequency self.cur_frequency = self.dds_model.cur_frequency
self.value_label.setText("<font size=\"4\">{:.7f}</font>" self.value_label.setText("<font size=\"4\">{:.7f}</font>".format(self.cur_frequency / 1e6))
.format(self.cur_frequency/1e6)) self.value_edit.setText("{:.7f}".format(self.cur_frequency / 1e6))
self.value_edit.setText("{:.7f}"
.format(self.cur_frequency/1e6))
def sort_key(self): def sort_key(self):
return (self.bus_channel, self.channel) return (self.bus_channel, self.channel)
@ -363,7 +357,7 @@ class _DACWidget(_SimpleDisplayWidget):
def refresh_display(self): def refresh_display(self):
self.value.setText("<font size=\"4\">{:.3f}</font><font size=\"2\"> %</font>" self.value.setText("<font size=\"4\">{:.3f}</font><font size=\"2\"> %</font>"
.format(self.cur_value*100/2**16)) .format(self.cur_value * 100 / 2**16))
def sort_key(self): def sort_key(self):
return (self.spi_channel, self.channel) return (self.spi_channel, self.channel)
@ -390,18 +384,16 @@ def setup_from_ddb(ddb):
force_out = v["class"] == "TTLOut" force_out = v["class"] == "TTLOut"
widget = _WidgetDesc(k, comment, _TTLWidget, (channel, force_out, k)) widget = _WidgetDesc(k, comment, _TTLWidget, (channel, force_out, k))
description.add(widget) description.add(widget)
elif (v["module"] == "artiq.coredevice.ad9914" elif (v["module"] == "artiq.coredevice.ad9914" and v["class"] == "AD9914"):
and v["class"] == "AD9914"):
bus_channel = v["arguments"]["bus_channel"] bus_channel = v["arguments"]["bus_channel"]
channel = v["arguments"]["channel"] channel = v["arguments"]["channel"]
dds_sysclk = v["arguments"]["sysclk"] dds_sysclk = v["arguments"]["sysclk"]
model = _DDSModel(v["class"], dds_sysclk) model = _DDSModel(v["class"], dds_sysclk)
widget = _WidgetDesc(k, comment, _DDSWidget, (k, bus_channel, channel, model)) widget = _WidgetDesc(k, comment, _DDSWidget,
(k, bus_channel, channel, model))
description.add(widget) description.add(widget)
elif (v["module"] == "artiq.coredevice.ad9910" elif (v["module"] == "artiq.coredevice.ad9910" and v["class"] == "AD9910") or \
and v["class"] == "AD9910") or \ (v["module"] == "artiq.coredevice.ad9912" and v["class"] == "AD9912"):
(v["module"] == "artiq.coredevice.ad9912"
and v["class"] == "AD9912"):
channel = v["arguments"]["chip_select"] - 4 channel = v["arguments"]["chip_select"] - 4
if channel < 0: if channel < 0:
continue continue
@ -411,18 +403,20 @@ def setup_from_ddb(ddb):
pll = v["arguments"]["pll_n"] pll = v["arguments"]["pll_n"]
refclk = ddb[dds_cpld]["arguments"]["refclk"] refclk = ddb[dds_cpld]["arguments"]["refclk"]
clk_div = v["arguments"].get("clk_div", 0) clk_div = v["arguments"].get("clk_div", 0)
model = _DDSModel( v["class"], refclk, dds_cpld, pll, clk_div) model = _DDSModel(v["class"], refclk, dds_cpld, pll, clk_div)
widget = _WidgetDesc(k, comment, _DDSWidget, (k, bus_channel, channel, model)) widget = _WidgetDesc(k, comment, _DDSWidget,
description.add(widget) (k, bus_channel, channel, model))
elif ( (v["module"] == "artiq.coredevice.ad53xx" and v["class"] == "AD53xx") description.add(widget)
or (v["module"] == "artiq.coredevice.zotino" and v["class"] == "Zotino")): elif (v["module"] == "artiq.coredevice.ad53xx" and v["class"] == "AD53xx") or \
(v["module"] == "artiq.coredevice.zotino" and v["class"] == "Zotino"):
spi_device = v["arguments"]["spi_device"] spi_device = v["arguments"]["spi_device"]
spi_device = ddb[spi_device] spi_device = ddb[spi_device]
while isinstance(spi_device, str): while isinstance(spi_device, str):
spi_device = ddb[spi_device] spi_device = ddb[spi_device]
spi_channel = spi_device["arguments"]["channel"] spi_channel = spi_device["arguments"]["channel"]
for channel in range(32): for channel in range(32):
widget = _WidgetDesc((k, channel), comment, _DACWidget, (spi_channel, channel, k)) widget = _WidgetDesc((k, channel), comment, _DACWidget,
(spi_channel, channel, k))
description.add(widget) description.add(widget)
elif v["type"] == "controller" and k == "core_moninj": elif v["type"] == "controller" and k == "core_moninj":
mi_addr = v["host"] mi_addr = v["host"]
@ -483,7 +477,7 @@ class _DeviceManager:
self.setup_dac_monitoring(False, widget.spi_channel, widget.channel) self.setup_dac_monitoring(False, widget.spi_channel, widget.channel)
widget.deleteLater() widget.deleteLater()
del self.dac_widgets[(widget.spi_channel, widget.channel)] del self.dac_widgets[(widget.spi_channel, widget.channel)]
self.dac_cb() self.dac_cb()
else: else:
raise ValueError raise ValueError
@ -562,7 +556,7 @@ class _DeviceManager:
cpld_dev = """self.setattr_device("core_cache") cpld_dev = """self.setattr_device("core_cache")
self.setattr_device("{}")""".format(dds_model.cpld) self.setattr_device("{}")""".format(dds_model.cpld)
# `sta`/`rf_sw`` variables are guaranteed for urukuls # `sta`/`rf_sw`` variables are guaranteed for urukuls
# so {action} can use it # so {action} can use it
# if there's no RF enabled, CPLD may have not been initialized # if there's no RF enabled, CPLD may have not been initialized
# but if there is, it has been initialised - no need to do again # but if there is, it has been initialised - no need to do again
@ -621,8 +615,8 @@ class _DeviceManager:
channel_init=channel_init)) channel_init=channel_init))
asyncio.ensure_future( asyncio.ensure_future(
self._submit_by_content( self._submit_by_content(
dds_exp, dds_exp,
title, title,
log_msg)) log_msg))
def dds_set_frequency(self, dds_channel, dds_model, freq): def dds_set_frequency(self, dds_channel, dds_model, freq):
@ -637,8 +631,8 @@ class _DeviceManager:
dds_channel, dds_channel,
dds_model, dds_model,
action, action,
"SetDDS", "SetDDS",
"Set DDS {} {}MHz".format(dds_channel, freq/1e6)) "Set DDS {} {}MHz".format(dds_channel, freq / 1e6))
def dds_channel_toggle(self, dds_channel, dds_model, sw=True): def dds_channel_toggle(self, dds_channel, dds_model, sw=True):
# urukul only # urukul only
@ -658,7 +652,7 @@ class _DeviceManager:
dds_channel, dds_channel,
dds_model, dds_model,
action, action,
"ToggleDDS", "ToggleDDS",
"Toggle DDS {} {}".format(dds_channel, "on" if sw else "off")) "Toggle DDS {} {}".format(dds_channel, "on" if sw else "off"))
def setup_ttl_monitoring(self, enable, channel): def setup_ttl_monitoring(self, enable, channel):
@ -716,11 +710,12 @@ class _DeviceManager:
await self.mi_connection.close() await self.mi_connection.close()
self.mi_connection = None self.mi_connection = None
new_mi_connection = CommMonInj(self.monitor_cb, self.injection_status_cb, new_mi_connection = CommMonInj(self.monitor_cb, self.injection_status_cb,
self.disconnect_cb) self.disconnect_cb)
try: try:
await new_mi_connection.connect(self.mi_addr, self.mi_port) await new_mi_connection.connect(self.mi_addr, self.mi_port)
except Exception: except Exception:
logger.error("failed to connect to moninj. Is aqctl_moninj_proxy running?", exc_info=True) logger.error("failed to connect to moninj. Is aqctl_moninj_proxy running?",
exc_info=True)
await asyncio.sleep(10.) await asyncio.sleep(10.)
self.reconnect_mi.set() self.reconnect_mi.set()
else: else:
@ -773,12 +768,9 @@ class MonInj:
self.dac_dock = _MonInjDock("DAC") self.dac_dock = _MonInjDock("DAC")
self.dm = _DeviceManager(schedule_ctl) self.dm = _DeviceManager(schedule_ctl)
self.dm.ttl_cb = lambda: self.ttl_dock.layout_widgets( self.dm.ttl_cb = lambda: self.ttl_dock.layout_widgets(self.dm.ttl_widgets.values())
self.dm.ttl_widgets.values()) self.dm.dds_cb = lambda: self.dds_dock.layout_widgets(self.dm.dds_widgets.values())
self.dm.dds_cb = lambda: self.dds_dock.layout_widgets( self.dm.dac_cb = lambda: self.dac_dock.layout_widgets(self.dm.dac_widgets.values())
self.dm.dds_widgets.values())
self.dm.dac_cb = lambda: self.dac_dock.layout_widgets(
self.dm.dac_widgets.values())
async def stop(self): async def stop(self):
if self.dm is not None: if self.dm is not None:

View File

@ -3,8 +3,6 @@ from functools import partial
from PyQt5 import QtCore, QtWidgets from PyQt5 import QtCore, QtWidgets
from artiq.gui.tools import LayoutWidget
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -17,7 +17,7 @@ from artiq.tools import exc_to_warning, short_format
from artiq.coredevice import comm_analyzer from artiq.coredevice import comm_analyzer
from artiq.coredevice.comm_analyzer import WaveformType from artiq.coredevice.comm_analyzer import WaveformType
from artiq.gui.tools import LayoutWidget, get_open_file_name, get_save_file_name from artiq.gui.tools import LayoutWidget, get_open_file_name, get_save_file_name
from artiq.gui.models import DictSyncTreeSepModel, LocalModelManager from artiq.gui.models import DictSyncTreeSepModel
from artiq.gui.dndwidgets import VDragScrollArea, VDragDropSplitter from artiq.gui.dndwidgets import VDragScrollArea, VDragDropSplitter

View File

@ -6,7 +6,6 @@ import atexit
import importlib import importlib
import os import os
import logging import logging
import sys
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from qasync import QEventLoop from qasync import QEventLoop