forked from M-Labs/artiq
Compare commits
No commits in common. "781afd9a94066e16eeb62980f518f029a811d045" and "0fb31ddbb104889a95ec9284492ecb94e14d9ade" have entirely different histories.
781afd9a94
...
0fb31ddbb1
|
@ -1,311 +0,0 @@
|
||||||
# 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()
|
|
|
@ -8,6 +8,7 @@ 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__)
|
||||||
|
|
|
@ -5,7 +5,6 @@ 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__)
|
||||||
|
@ -30,34 +29,32 @@ class Model(DictSyncModel):
|
||||||
return k
|
return k
|
||||||
|
|
||||||
|
|
||||||
class _InteractiveArgsRequest(EntryTreeWidget):
|
class _InteractiveArgsRequest(QtWidgets.QWidget):
|
||||||
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):
|
||||||
EntryTreeWidget.__init__(self)
|
QtWidgets.QWidget.__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.set_argument(key, self.arguments[key])
|
self.entry_tree.set_argument(key, self.arguments[key])
|
||||||
self.quickStyleClicked.connect(self.supply)
|
self.cancel_btn = QtWidgets.QPushButton("Cancel")
|
||||||
cancel_btn = QtWidgets.QPushButton("Cancel")
|
self.cancel_btn.setIcon(QtWidgets.QApplication.style().standardIcon(
|
||||||
cancel_btn.setIcon(QtWidgets.QApplication.style().standardIcon(
|
|
||||||
QtWidgets.QStyle.SP_DialogCancelButton))
|
QtWidgets.QStyle.SP_DialogCancelButton))
|
||||||
cancel_btn.clicked.connect(self.cancel)
|
self.cancel_btn.clicked.connect(self.cancel)
|
||||||
supply_btn = QtWidgets.QPushButton("Supply")
|
layout.addWidget(self.cancel_btn, 1, 0, 1, 1)
|
||||||
supply_btn.setIcon(QtWidgets.QApplication.style().standardIcon(
|
self.supply_btn = QtWidgets.QPushButton("Supply")
|
||||||
|
self.supply_btn.setIcon(QtWidgets.QApplication.style().standardIcon(
|
||||||
QtWidgets.QStyle.SP_DialogOkButton))
|
QtWidgets.QStyle.SP_DialogOkButton))
|
||||||
supply_btn.clicked.connect(self.supply)
|
self.supply_btn.clicked.connect(self.supply)
|
||||||
buttons = LayoutWidget()
|
layout.addWidget(self.supply_btn, 1, 1, 1, 1)
|
||||||
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()
|
||||||
|
@ -70,27 +67,18 @@ class _InteractiveArgsRequest(EntryTreeWidget):
|
||||||
self.cancelled.emit(self.rid)
|
self.cancelled.emit(self.rid)
|
||||||
|
|
||||||
|
|
||||||
class _InteractiveArgsView(QtWidgets.QStackedWidget):
|
class _InteractiveArgsView(QtWidgets.QTabWidget):
|
||||||
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.QStackedWidget.__init__(self)
|
QtWidgets.QTabWidget.__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):
|
||||||
self.setCurrentIndex(1)
|
for i in range(self.count()):
|
||||||
for i in range(self.tabs.count()):
|
widget = self.widget(i)
|
||||||
widget = self.tabs.widget(i)
|
self.removeTab(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)
|
||||||
|
@ -105,20 +93,17 @@ class _InteractiveArgsView(QtWidgets.QStackedWidget):
|
||||||
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.tabs.insertTab(row, inter_args_request, title)
|
self.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.tabs.widget(first)
|
widget = self.widget(first)
|
||||||
self.tabs.removeTab(first)
|
self.removeTab(first)
|
||||||
widget.deleteLater()
|
widget.deleteLater()
|
||||||
if self.tabs.count() == 0:
|
|
||||||
self.setCurrentIndex(1)
|
|
||||||
|
|
||||||
|
|
||||||
class InteractiveArgsDock(QtWidgets.QDockWidget):
|
class InteractiveArgsDock(QtWidgets.QDockWidget):
|
||||||
|
|
|
@ -3,17 +3,20 @@ import logging
|
||||||
import textwrap
|
import textwrap
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtWidgets
|
from PyQt5 import QtCore, QtWidgets, QtGui
|
||||||
|
|
||||||
from artiq.coredevice.comm_moninj import CommMonInj, TTLOverride, TTLProbe
|
from artiq.coredevice.comm_moninj import *
|
||||||
from artiq.coredevice.ad9912_reg import AD9912_SER_CONF
|
from artiq.coredevice.ad9910 import (
|
||||||
|
_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
|
||||||
|
@ -322,7 +325,8 @@ 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}".format(self.cur_frequency / 1e6))
|
self.value_edit.setText("{:.7f}"
|
||||||
|
.format(self.cur_frequency/1e6))
|
||||||
self.value_edit.setFocus()
|
self.value_edit.setFocus()
|
||||||
self.value_edit.selectAll()
|
self.value_edit.selectAll()
|
||||||
|
|
||||||
|
@ -341,8 +345,10 @@ 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>".format(self.cur_frequency / 1e6))
|
self.value_label.setText("<font size=\"4\">{:.7f}</font>"
|
||||||
self.value_edit.setText("{:.7f}".format(self.cur_frequency / 1e6))
|
.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)
|
||||||
|
@ -384,16 +390,18 @@ 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" and v["class"] == "AD9914"):
|
elif (v["module"] == "artiq.coredevice.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,
|
widget = _WidgetDesc(k, comment, _DDSWidget, (k, bus_channel, channel, model))
|
||||||
(k, bus_channel, channel, model))
|
|
||||||
description.add(widget)
|
description.add(widget)
|
||||||
elif (v["module"] == "artiq.coredevice.ad9910" and v["class"] == "AD9910") or \
|
elif (v["module"] == "artiq.coredevice.ad9910"
|
||||||
(v["module"] == "artiq.coredevice.ad9912" and v["class"] == "AD9912"):
|
and v["class"] == "AD9910") or \
|
||||||
|
(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
|
||||||
|
@ -404,19 +412,17 @@ def setup_from_ddb(ddb):
|
||||||
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,
|
widget = _WidgetDesc(k, comment, _DDSWidget, (k, bus_channel, channel, model))
|
||||||
(k, bus_channel, channel, model))
|
|
||||||
description.add(widget)
|
description.add(widget)
|
||||||
elif (v["module"] == "artiq.coredevice.ad53xx" and v["class"] == "AD53xx") or \
|
elif ( (v["module"] == "artiq.coredevice.ad53xx" and v["class"] == "AD53xx")
|
||||||
(v["module"] == "artiq.coredevice.zotino" and v["class"] == "Zotino"):
|
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,
|
widget = _WidgetDesc((k, channel), comment, _DACWidget, (spi_channel, channel, k))
|
||||||
(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"]
|
||||||
|
@ -714,8 +720,7 @@ class _DeviceManager:
|
||||||
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?",
|
logger.error("failed to connect to moninj. Is aqctl_moninj_proxy running?", exc_info=True)
|
||||||
exc_info=True)
|
|
||||||
await asyncio.sleep(10.)
|
await asyncio.sleep(10.)
|
||||||
self.reconnect_mi.set()
|
self.reconnect_mi.set()
|
||||||
else:
|
else:
|
||||||
|
@ -768,9 +773,12 @@ 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_widgets.values())
|
self.dm.ttl_cb = lambda: self.ttl_dock.layout_widgets(
|
||||||
self.dm.dds_cb = lambda: self.dds_dock.layout_widgets(self.dm.dds_widgets.values())
|
self.dm.ttl_widgets.values())
|
||||||
self.dm.dac_cb = lambda: self.dac_dock.layout_widgets(self.dm.dac_widgets.values())
|
self.dm.dds_cb = lambda: self.dds_dock.layout_widgets(
|
||||||
|
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:
|
||||||
|
|
|
@ -3,6 +3,8 @@ 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__)
|
||||||
|
|
||||||
|
|
|
@ -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
|
from artiq.gui.models import DictSyncTreeSepModel, LocalModelManager
|
||||||
from artiq.gui.dndwidgets import VDragScrollArea, VDragDropSplitter
|
from artiq.gui.dndwidgets import VDragScrollArea, VDragDropSplitter
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ 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
|
||||||
|
|
Loading…
Reference in New Issue