8 次代碼提交 d3b325b299 ... c14673dc20

作者 SHA1 備註 提交日期
  Timo Dritschler c14673dc20 Fixed Observer handling for Bunch Shifts 3 年之前
  Timo Dritschler 1b53b45206 Python3 compliancy fix for GroupedItems 3 年之前
  Timo Dritschler a7e6272eed Made Live Plot open automatically on startup 3 年之前
  Timo Dritschler c32aeb6fb0 Changed line break convention to unix 3 年之前
  Timo Dritschler b80a691477 Removed unprofessional default value 3 年之前
  Timo Dritschler 1c3ef08bfe Turned 'Continuous Read' Tick-Box into a button 3 年之前
  Timo Dritschler 5825c15664 Re-Introduced PLL Status LED 3 年之前
  Timo Dritschler df068d1489 Fixed linebreak convention to unix 3 年之前
共有 6 個文件被更改,包括 689 次插入644 次删除
  1. 455 455
      KCG/base/ControlWidget.py
  2. 157 153
      KCG/base/MultiWidget.py
  3. 1 1
      KCG/base/groupedelements.py
  4. 1 1
      KCG/default_config.cfg
  5. 27 10
      KCG/widgets/SingleReadWidget.py
  6. 48 24
      KCG/widgets/TimingWidget.py

+ 455 - 455
KCG/base/ControlWidget.py

@@ -1,455 +1,455 @@
-"""
-This module defines the Initial view of the gui
-"""
-
-from PyQt4 import QtGui, QtCore
-import logging
-
-from . import kcgwidget as kcgw
-from .kcgwidget import error
-from .backend import board
-from .backend.board import available_boards
-from .groupedelements import Checkboxes, Buttons, Elements
-from . import backendinterface as bif
-from .loghandler import LogArea
-from . import storage
-from .. import config
-
-import traceback
-tr = kcgw.tr
-
-
-# 888     88888888888888888b.
-# 888     888       888  "Y88b
-# 888     888       888    888
-# 888     8888888   888    888
-# 888     888       888    888
-# 888     888       888    888
-# 888     888       888  .d88P
-# 8888888888888888888888888P"
-
-class LED(QtGui.QWidget):
-    """
-    Produces a graphical LED
-    """
-    def __init__(self, parent=None, status=1, height=10, width=10):
-        """
-        Initialize a LED
-        :param parent: (QWidget) parent of this widget
-        :param status: (int) (0=out, 1=off, 2=orange, 3=on) initial status of this LED
-        :param height: (int) height of the LED
-        :param width: (int) width of the LED
-        :return: -
-        """
-        QtGui.QWidget.__init__(self, parent)
-        colorRGB=(255, 0, 0)
-        self.width = width
-        self.height = height
-        self.color = QtGui.QColor(colorRGB[0], colorRGB[1], colorRGB[2])
-        self.center = QtCore.QPoint(width, height)
-        self.setMinimumSize(2 * width, 2 * height)
-        self.setMaximumSize(2 * width, 2 * height)
-        if status == 3:
-            self.set_on()
-        elif status == 1:
-            self.set_off()
-        elif status == 0:
-            self.set_out()
-        elif status == 2:
-            self.set_tri()
-        self.status = status
-
-    def paintEvent(self, event):
-        paint = QtGui.QPainter()
-        paint.begin(self)
-        paint.setRenderHint(QtGui.QPainter.Antialiasing)
-
-        # draw a grey 'socket' for the LED
-        paint.setPen(QtGui.QColor(160, 160, 160))
-        paint.setBrush(QtGui.QColor(180, 180, 180))
-        paint.drawEllipse(self.center, self.width, self.height)
-
-        # draw the body of the LED
-        paint.setBrush(self.color)
-        paint.drawEllipse(self.center, self.width*0.85, self.height*0.85)
-
-    def set_on(self):
-        """
-        Set the LED to "on" state
-        :return: -
-        """
-        self.color = QtGui.QColor(0, 255, 0)
-        self.update()
-        self.status = 3
-
-    def set_off(self):
-        """
-        Set the LED to "off" state
-        :return: -
-        """
-        self.color = QtGui.QColor(255, 0, 0)
-        self.update()
-        self.status = 1
-
-    def set_out(self):
-        """
-        Set the LED to "OUT" state (that is like an LED without power)
-        :return: -
-        """
-        self.color = QtGui.QColor(150, 150, 150)
-        self.update()
-        self.status = 0
-
-    def set_tri(self):
-        """
-        Set the LED to "TRI" state (that is led is orange)
-        :return: -
-        """
-        self.color = QtGui.QColor(255, 255, 0)
-        self.update()
-        self.status = 2
-
-    def set_status(self, status):
-        """
-        Set the status of the led
-        :param status: status (in 0, 1, 2, 3)
-        """
-        if status == 0:
-            self.set_out()
-        elif status == 1:
-            self.set_off()
-        elif status == 2:
-            self.set_tri()
-        elif status == 3:
-            self.set_on()
-
-
-#  .d8888b. 888           888                   888     88888888888888888b.
-# d88P  Y88b888           888                   888     888       888  "Y88b
-# Y88b.     888           888                   888     888       888    888
-#  "Y888b.  888888 8888b. 888888888  888.d8888b 888     8888888   888    888
-#     "Y88b.888       "88b888   888  88888K     888     888       888    888
-#       "888888   .d888888888   888  888"Y8888b.888     888       888    888
-# Y88b  d88PY88b. 888  888Y88b. Y88b 888     X88888     888       888  .d88P
-#  "Y8888P"  "Y888"Y888888 "Y888 "Y88888 88888P'8888888888888888888888888P"
-
-class StatusLED(QtGui.QWidget):
-    """
-    Create a Status LED with Label next to it
-    """
-    def __init__(self, text, status=None):
-        """
-        Initialise StatusLED
-        :param text: label text next to the LED
-        :param status: initial status of the LED
-        :return: -
-        """
-        super(StatusLED, self).__init__()
-        self.layout = QtGui.QHBoxLayout()
-        self.label = QtGui.QLabel(text)
-        self.led = LED(status=status, width=9, height=9)
-        self.layout.addWidget(self.led)
-        self.layout.addWidget(self.label)
-        self.setLayout(self.layout)
-
-    def set_on(self):
-        """
-        See set_on of LED Class
-        """
-        self.led.set_on()
-
-    def set_off(self):
-        """
-        See set_off of LED Class
-        """
-        self.led.set_off()
-
-    def set_out(self):
-        """
-        See set_out of LED Class
-        """
-        self.led.set_out()
-
-    def set_tri(self):
-        """
-        See set_tri of LED Class
-        """
-        self.led.set_tri()
-
-    def set_status(self, status):
-        """
-        See set_status of LED Class
-        :param status: the status to set the led to
-        """
-        self.led.set_status(status)
-
-
-# 888888b.                              888 .d8888b.                 888                  888
-# 888  "88b                             888d88P  Y88b                888                  888
-# 888  .88P                             888888    888                888                  888
-# 8888888K.  .d88b.  8888b. 888d888 .d88888888        .d88b. 88888b. 888888888d888 .d88b. 888
-# 888  "Y88bd88""88b    "88b888P"  d88" 888888       d88""88b888 "88b888   888P"  d88""88b888
-# 888    888888  888.d888888888    888  888888    888888  888888  888888   888    888  888888
-# 888   d88PY88..88P888  888888    Y88b 888Y88b  d88PY88..88P888  888Y88b. 888    Y88..88P888
-# 8888888P"  "Y88P" "Y888888888     "Y88888 "Y8888P"  "Y88P" 888  888 "Y888888     "Y88P" 888
-
-class BoardControl(kcgw.KCGWidgets):
-    """
-    The main view of the gui for each board at startup
-    """
-    def __init__(self, board_id, single=False):
-        super(BoardControl, self).__init__()
-        self.board_id = board_id
-        self.layout = QtGui.QVBoxLayout()
-        self.setLayout(self.layout)
-
-        if not single:
-            self.header_layout = QtGui.QHBoxLayout()
-            left_line = QtGui.QFrame()
-            left_line.setFrameShape(QtGui.QFrame.HLine)
-            left_line.setFrameShadow(QtGui.QFrame.Sunken)
-            right_line = QtGui.QFrame()
-            right_line.setFrameShape(QtGui.QFrame.HLine)
-            right_line.setFrameShadow(QtGui.QFrame.Sunken)
-            self.header_layout.addWidget(left_line)
-            header_label = self.createLabel("Board: {}".format(available_boards.get_board_name_from_id(board_id)))
-            header_label.setFixedWidth(header_label.sizeHint().width())
-            self.header_layout.addWidget(header_label)
-            self.header_layout.addWidget(right_line)
-
-            self.layout.addLayout(self.header_layout)
-
-        self.mainControlLayout = QtGui.QHBoxLayout()
-        self.subControlLayout  = QtGui.QGridLayout()#QtGui.QHBoxLayout()
-        self.subControlWidget  = QtGui.QWidget()
-        self.subControlWidget.setLayout(self.subControlLayout)
-        self.statusLayout = QtGui.QHBoxLayout()
-        self.layout.addLayout(self.mainControlLayout)
-        self.layout.addWidget(self.subControlWidget)
-        self.layout.addLayout(self.statusLayout)
-
-        # ----------[ LED Status ]---------------
-        self.pipeline_led       = StatusLED(tr("Label", "DataFlow Pipeline"))
-        self.master_control_led = StatusLED(tr("Label", "Master Control"))
-        #self.data_check_led     = StatusLED(tr("Label", "Data Check"))
-        #self.pll_ld_led         = StatusLED(tr("Label", "PLL_LD"))
-        self.statusLayout.addWidget(self.pipeline_led)
-        self.statusLayout.addWidget(self.master_control_led)
-        #self.statusLayout.addWidget(self.data_check_led)
-        #self.statusLayout.addWidget(self.pll_ld_led)
-
-        # -----------[ Buttons ]--------------
-        from functools import partial
-        conf = board.get_board_config(board_id)
-        if conf.get('board_version') > 10:
-            logging.critical('Board Offline - GUI not working! - restart with active board')
-            self.mainControlLayout.addWidget(self.createLabel('Board Offline - GUI not working! - restart with active board'))
-        else:
-            self.all_in_one_button = self.createButton(text=tr("Button", "Prepare Board"), connect=self.all_in_one,
-                                                       tooltip=tr("Tooltip", "Start, Calibrate, Synchronize and set Defaults\nCtrl+A"))
-            
-            self.toggleButton = self.createButton(text="", connect=self.toggle_sub_control)
-            self.toggleButton.setIcon(QtGui.QIcon(config.icon_path("chevron-bottom.svg")))
-            self.toggleButton.setFixedWidth(50)
-            # self.all_in_one_button.setShortcut("Ctrl+A")
-            # self.all_in_one_button.setObjectName("all_in_one")
-
-
-            self.skip_init_button = self.createButton(text=tr("Button", "Skip Initialisation"), connect=self.skip_init,
-                                                  tooltip=tr("Tooltip", "Skip Initialisation and read values from board.\n"
-                                                                        "NOTE: ONLY DO THIS IF BOARD WAS CALIBRATED AND SYNCHRONIZED BEFORE"))
-            
-            self.set_default_button = self.createButton(text=tr("Button", "Set Defaults"), connect=lambda x: bif.bk_write_values(board_id=board_id, defaults=True))
-            self.soft_reset_button  = self.createButton(text=tr("Button", "Soft Reset"),   connect=lambda x: bif.bk_soft_reset(board_id=board_id))
-            #self.off_button         = self.createButton(text=tr("Button", "Board Off"),    connect=lambda x: bif.bk_stop_board(board_id=board_id))
-            #self.off_button.setObjectName("off")
-            self.check_status_button = self.createButton(text=tr("Button", "Check Status"), connect=lambda x: bif._bif_status_readout(board_id=board_id))
-
-
-            seqlist = conf.get_sequence_list()
-            columnctr=0
-            linectr = 0
-            seqcolum = -1
-            try:
-                for item in seqlist:
-                    buttontemp = self.createButton(text=tr("Button", conf.get_sequence_comment(item)), connect=partial(bif.bk_run_sequence, board_id=board_id, name=item))
-                    Buttons.addButton(item, buttontemp)
-                    Elements.addItem('no_board_{}'.format(board_id),[buttontemp])
-                    #self.subControlLayout.addWidget(buttontemp)
-                    if 'PLL_sequence' in item:
-                        if seqcolum == -1:
-                            seqcolum = columnctr
-                            columnctr += 1
-                        self.subControlLayout.addWidget(buttontemp, linectr, seqcolum)
-                        linectr += 1
-                        
-                    else:
-                        self.subControlLayout.addWidget(buttontemp, 0,columnctr)
-                        columnctr += 1
-                        
-                    
-                self.subControlLayout.addWidget(self.set_default_button, 0, columnctr)        
-            except Exception as e:
-                traceback.print_exc()
-            
-            Buttons.addButton(['set_defaults_{}'.format(board_id), 'after_start_{}'.format(board_id)], self.set_default_button)
-            Elements.addItem('no_board_{}'.format(board_id),
-                             [ 
-                                 self.set_default_button,
-                                 self.soft_reset_button,
-                                 #self.off_button,
-                                 self.all_in_one_button
-                             ])
-
-            self.mainControlLayout.addWidget(self.all_in_one_button)
-            self.mainControlLayout.addWidget(self.toggleButton)
-            self.mainControlLayout.addWidget(self.skip_init_button)
-            
-            self.mainControlLayout.addWidget(self.soft_reset_button)
-            #self.mainControlLayout.addWidget(self.off_button)
-
-            self.statusLayout.addWidget(self.check_status_button)
-            
-
-        # register the led updater function (used in backendinterface.bk_status_readout)
-        storage.get_board_specific_storage(board_id).update_LED = self.on_check
-        self.geo = self.saveGeometry()
-        self.subControlWidget.hide()
-
-    def toggle_sub_control(self):
-        """
-        Show or hide the subcontrol buttons
-        """
-        self.subControlWidget.setHidden(not self.subControlWidget.isHidden())
-        if self.subControlWidget.isHidden():
-            self.toggleButton.setIcon(QtGui.QIcon(config.icon_path("chevron-bottom.svg")))
-        else:
-            self.toggleButton.setIcon(QtGui.QIcon(config.icon_path("chevron-top.svg")))
-        self.parent().adjustSize()
-
-    def all_in_one(self):
-        """
-        Function that gets called when the Prepare Board Button is pressed.
-        It Starts the board, syncs it and sets defaults.
-        This is accomplished via the Sequences module
-        :return: -
-        """
-        seq = board.get_board_config(self.board_id).get_init_order()
-        for item in seq:
-            if item == 'startup_sequence':
-                if board.is_active(board_id):
-                    logging.info('Board already powered on - skip startup_sequence')
-                    continue
-
-            bif.bk_run_sequence(self.board_id, item)
-
-        popup = kcgw.PopupDialog("Do not forget to turn on the T/H switches!",
-                                title='Reminder', okonly=True)
-        popup.exec_()
-        popup.deleteLater()
-        popup.get_return_value()
-        board.get_board_config(self.board_id).set_startup()
-
-    def skip_init(self):
-        """
-        Skip board initialisation progress and read data from board. This will adjust the values in the gui to those
-        on the board (for every value that is stored on the board)
-        """
-        board.get_board_config(self.board_id).read_from_board()
-        board.get_board_status(self.board_id).calibrated   = True
-        board.get_board_status(self.board_id).synced       = True
-        board.get_board_status(self.board_id).defaults_set = True
-        bif.bk_status_readout()
-        logging.info("Initialisation skipped, configuration and status was read from KAPTURE.")
-
-    def on_check(self):
-        """
-        This function is the handler for the status leds on the ControlWidget View.
-        Parses the registers and sets the colors of the leds according.
-        :return: -
-        """
-        try:
-            status = bif.bk_get_status(self.board_id)
-        except IndexError:
-            error(0x002, "Pci returned not enough registers to update LEDs.")
-            return
-
-        for led, st in list(status.items()):
-            try:
-                getattr(self, led.lower()+"_led").set_status(st)
-            except:
-                pass
-
-
-#  .d8888b.                 888                  888888       888d8b     888                888
-# d88P  Y88b                888                  888888   o   888Y8P     888                888
-# 888    888                888                  888888  d8b  888        888                888
-# 888        .d88b. 88888b. 888888888d888 .d88b. 888888 d888b 888888 .d88888 .d88b.  .d88b. 888888
-# 888       d88""88b888 "88b888   888P"  d88""88b888888d88888b888888d88" 888d88P"88bd8P  Y8b888
-# 888    888888  888888  888888   888    888  88888888888P Y88888888888  888888  88888888888888
-# Y88b  d88PY88..88P888  888Y88b. 888    Y88..88P8888888P   Y8888888Y88b 888Y88b 888Y8b.    Y88b.
-#  "Y8888P"  "Y88P" 888  888 "Y888888     "Y88P" 888888P     Y888888 "Y88888 "Y88888 "Y8888  "Y888
-#                                                                                888
-#                                                                           Y8b d88P
-#                                                                            "Y88P"
-
-class ControlWidget(kcgw.KCGWidgets):
-    """
-    Main Widget that is shown at start of gui.
-    """
-    def __init__(self):
-        super(ControlWidget, self).__init__()
-
-        self.overlayout = QtGui.QVBoxLayout()
-        self.setLayout(self.overlayout)
-
-        self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical)
-        self.overlayout.addWidget(self.splitter)
-
-        self.log_area = LogArea()
-        self.log_area.setReadOnly(True)
-        self.log_area.init_logging()
-        self.log_area.setKeywords([
-            "Activating Board",
-            "Started Board Calibration",
-            "Synchronize PLLs",
-            "Setting default Values",
-            "Updating Values"
-        ])
-
-        self.board_control_list = {i: BoardControl(i, not available_boards.multi_board) for i in available_boards}
-        self.board_widget = QtGui.QWidget()
-        self.board_widget_layout = QtGui.QVBoxLayout()
-        self.board_widget.setLayout(self.board_widget_layout)
-        for bc in list(self.board_control_list.values()):
-            self.board_widget_layout.addWidget(bc)
-        self.board_widget_layout.addStretch(1)
-
-        if available_boards.multi_board:
-            self.scroll_widget = QtGui.QScrollArea()
-            # self.scroll_widget.setMaximumWidth(1.1 * self.board_control_list.values()[0].minimumSizeHint().width())
-            self.scroll_widget.setWidgetResizable(True)
-            self.scroll_widget.setWidget(self.board_widget)
-            self.scroll_widget_container = QtGui.QWidget()
-            self.scroll_widget_layout = QtGui.QHBoxLayout()
-            self.scroll_widget_layout.addWidget(self.scroll_widget)
-            self.scroll_widget_layout.setAlignment(QtCore.Qt.AlignLeft)
-            self.scroll_widget_container.setLayout(self.scroll_widget_layout)
-            self.splitter.addWidget(self.scroll_widget_container)
-        else:
-            self.splitter.addWidget(self.board_widget)
-
-        # self.log_area = QtGui.QTextEdit()
-        
-        self.splitter.addWidget(self.log_area)
-
-        # self.setTabOrder(self.soft_reset_button, self.check_status_button)
-        # self.setTabOrder(self.check_status_button, self.off_button)
-
-        # ------------------[ Logging ]----------------------
-        # log_handler = LogHandler(self.log_area)
-        # self.logger = logging.getLogger()
-        # self.logger.addHandler(log_handler)
-        # self.logger.setLevel(config.log_level)
-        # logging.logger = self.logger
-        # logging.logger.addHandler(log_handler)
+"""
+This module defines the Initial view of the gui
+"""
+
+from PyQt4 import QtGui, QtCore
+import logging
+
+from . import kcgwidget as kcgw
+from .kcgwidget import error
+from .backend import board
+from .backend.board import available_boards
+from .groupedelements import Checkboxes, Buttons, Elements
+from . import backendinterface as bif
+from .loghandler import LogArea
+from . import storage
+from .. import config
+
+import traceback
+tr = kcgw.tr
+
+
+# 888     88888888888888888b.
+# 888     888       888  "Y88b
+# 888     888       888    888
+# 888     8888888   888    888
+# 888     888       888    888
+# 888     888       888    888
+# 888     888       888  .d88P
+# 8888888888888888888888888P"
+
+class LED(QtGui.QWidget):
+    """
+    Produces a graphical LED
+    """
+    def __init__(self, parent=None, status=1, height=10, width=10):
+        """
+        Initialize a LED
+        :param parent: (QWidget) parent of this widget
+        :param status: (int) (0=out, 1=off, 2=orange, 3=on) initial status of this LED
+        :param height: (int) height of the LED
+        :param width: (int) width of the LED
+        :return: -
+        """
+        QtGui.QWidget.__init__(self, parent)
+        colorRGB=(255, 0, 0)
+        self.width = width
+        self.height = height
+        self.color = QtGui.QColor(colorRGB[0], colorRGB[1], colorRGB[2])
+        self.center = QtCore.QPoint(width, height)
+        self.setMinimumSize(2 * width, 2 * height)
+        self.setMaximumSize(2 * width, 2 * height)
+        if status == 3:
+            self.set_on()
+        elif status == 1:
+            self.set_off()
+        elif status == 0:
+            self.set_out()
+        elif status == 2:
+            self.set_tri()
+        self.status = status
+
+    def paintEvent(self, event):
+        paint = QtGui.QPainter()
+        paint.begin(self)
+        paint.setRenderHint(QtGui.QPainter.Antialiasing)
+
+        # draw a grey 'socket' for the LED
+        paint.setPen(QtGui.QColor(160, 160, 160))
+        paint.setBrush(QtGui.QColor(180, 180, 180))
+        paint.drawEllipse(self.center, self.width, self.height)
+
+        # draw the body of the LED
+        paint.setBrush(self.color)
+        paint.drawEllipse(self.center, self.width*0.85, self.height*0.85)
+
+    def set_on(self):
+        """
+        Set the LED to "on" state
+        :return: -
+        """
+        self.color = QtGui.QColor(0, 255, 0)
+        self.update()
+        self.status = 3
+
+    def set_off(self):
+        """
+        Set the LED to "off" state
+        :return: -
+        """
+        self.color = QtGui.QColor(255, 0, 0)
+        self.update()
+        self.status = 1
+
+    def set_out(self):
+        """
+        Set the LED to "OUT" state (that is like an LED without power)
+        :return: -
+        """
+        self.color = QtGui.QColor(150, 150, 150)
+        self.update()
+        self.status = 0
+
+    def set_tri(self):
+        """
+        Set the LED to "TRI" state (that is led is orange)
+        :return: -
+        """
+        self.color = QtGui.QColor(255, 255, 0)
+        self.update()
+        self.status = 2
+
+    def set_status(self, status):
+        """
+        Set the status of the led
+        :param status: status (in 0, 1, 2, 3)
+        """
+        if status == 0:
+            self.set_out()
+        elif status == 1:
+            self.set_off()
+        elif status == 2:
+            self.set_tri()
+        elif status == 3:
+            self.set_on()
+
+
+#  .d8888b. 888           888                   888     88888888888888888b.
+# d88P  Y88b888           888                   888     888       888  "Y88b
+# Y88b.     888           888                   888     888       888    888
+#  "Y888b.  888888 8888b. 888888888  888.d8888b 888     8888888   888    888
+#     "Y88b.888       "88b888   888  88888K     888     888       888    888
+#       "888888   .d888888888   888  888"Y8888b.888     888       888    888
+# Y88b  d88PY88b. 888  888Y88b. Y88b 888     X88888     888       888  .d88P
+#  "Y8888P"  "Y888"Y888888 "Y888 "Y88888 88888P'8888888888888888888888888P"
+
+class StatusLED(QtGui.QWidget):
+    """
+    Create a Status LED with Label next to it
+    """
+    def __init__(self, text, status=None):
+        """
+        Initialise StatusLED
+        :param text: label text next to the LED
+        :param status: initial status of the LED
+        :return: -
+        """
+        super(StatusLED, self).__init__()
+        self.layout = QtGui.QHBoxLayout()
+        self.label = QtGui.QLabel(text)
+        self.led = LED(status=status, width=9, height=9)
+        self.layout.addWidget(self.led)
+        self.layout.addWidget(self.label)
+        self.setLayout(self.layout)
+
+    def set_on(self):
+        """
+        See set_on of LED Class
+        """
+        self.led.set_on()
+
+    def set_off(self):
+        """
+        See set_off of LED Class
+        """
+        self.led.set_off()
+
+    def set_out(self):
+        """
+        See set_out of LED Class
+        """
+        self.led.set_out()
+
+    def set_tri(self):
+        """
+        See set_tri of LED Class
+        """
+        self.led.set_tri()
+
+    def set_status(self, status):
+        """
+        See set_status of LED Class
+        :param status: the status to set the led to
+        """
+        self.led.set_status(status)
+
+
+# 888888b.                              888 .d8888b.                 888                  888
+# 888  "88b                             888d88P  Y88b                888                  888
+# 888  .88P                             888888    888                888                  888
+# 8888888K.  .d88b.  8888b. 888d888 .d88888888        .d88b. 88888b. 888888888d888 .d88b. 888
+# 888  "Y88bd88""88b    "88b888P"  d88" 888888       d88""88b888 "88b888   888P"  d88""88b888
+# 888    888888  888.d888888888    888  888888    888888  888888  888888   888    888  888888
+# 888   d88PY88..88P888  888888    Y88b 888Y88b  d88PY88..88P888  888Y88b. 888    Y88..88P888
+# 8888888P"  "Y88P" "Y888888888     "Y88888 "Y8888P"  "Y88P" 888  888 "Y888888     "Y88P" 888
+
+class BoardControl(kcgw.KCGWidgets):
+    """
+    The main view of the gui for each board at startup
+    """
+    def __init__(self, board_id, single=False):
+        super(BoardControl, self).__init__()
+        self.board_id = board_id
+        self.layout = QtGui.QVBoxLayout()
+        self.setLayout(self.layout)
+
+        if not single:
+            self.header_layout = QtGui.QHBoxLayout()
+            left_line = QtGui.QFrame()
+            left_line.setFrameShape(QtGui.QFrame.HLine)
+            left_line.setFrameShadow(QtGui.QFrame.Sunken)
+            right_line = QtGui.QFrame()
+            right_line.setFrameShape(QtGui.QFrame.HLine)
+            right_line.setFrameShadow(QtGui.QFrame.Sunken)
+            self.header_layout.addWidget(left_line)
+            header_label = self.createLabel("Board: {}".format(available_boards.get_board_name_from_id(board_id)))
+            header_label.setFixedWidth(header_label.sizeHint().width())
+            self.header_layout.addWidget(header_label)
+            self.header_layout.addWidget(right_line)
+
+            self.layout.addLayout(self.header_layout)
+
+        self.mainControlLayout = QtGui.QHBoxLayout()
+        self.subControlLayout  = QtGui.QGridLayout()#QtGui.QHBoxLayout()
+        self.subControlWidget  = QtGui.QWidget()
+        self.subControlWidget.setLayout(self.subControlLayout)
+        self.statusLayout = QtGui.QHBoxLayout()
+        self.layout.addLayout(self.mainControlLayout)
+        self.layout.addWidget(self.subControlWidget)
+        self.layout.addLayout(self.statusLayout)
+
+        # ----------[ LED Status ]---------------
+        self.pipeline_led       = StatusLED(tr("Label", "DataFlow Pipeline"))
+        self.master_control_led = StatusLED(tr("Label", "Master Control"))
+        #self.data_check_led     = StatusLED(tr("Label", "Data Check"))
+        self.pll_ld_led         = StatusLED(tr("Label", "PLL Lock"))
+        self.statusLayout.addWidget(self.pipeline_led)
+        self.statusLayout.addWidget(self.master_control_led)
+        #self.statusLayout.addWidget(self.data_check_led)
+        self.statusLayout.addWidget(self.pll_ld_led)
+
+        # -----------[ Buttons ]--------------
+        from functools import partial
+        conf = board.get_board_config(board_id)
+        if conf.get('board_version') > 10:
+            logging.critical('Board Offline - GUI not working! - restart with active board')
+            self.mainControlLayout.addWidget(self.createLabel('Board Offline - GUI not working! - restart with active board'))
+        else:
+            self.all_in_one_button = self.createButton(text=tr("Button", "Prepare Board"), connect=self.all_in_one,
+                                                       tooltip=tr("Tooltip", "Start, Calibrate, Synchronize and set Defaults\nCtrl+A"))
+
+            self.toggleButton = self.createButton(text="", connect=self.toggle_sub_control)
+            self.toggleButton.setIcon(QtGui.QIcon(config.icon_path("chevron-bottom.svg")))
+            self.toggleButton.setFixedWidth(50)
+            # self.all_in_one_button.setShortcut("Ctrl+A")
+            # self.all_in_one_button.setObjectName("all_in_one")
+
+
+            self.skip_init_button = self.createButton(text=tr("Button", "Skip Initialisation"), connect=self.skip_init,
+                                                  tooltip=tr("Tooltip", "Skip Initialisation and read values from board.\n"
+                                                                        "NOTE: ONLY DO THIS IF BOARD WAS CALIBRATED AND SYNCHRONIZED BEFORE"))
+
+            self.set_default_button = self.createButton(text=tr("Button", "Set Defaults"), connect=lambda x: bif.bk_write_values(board_id=board_id, defaults=True))
+            self.soft_reset_button  = self.createButton(text=tr("Button", "Soft Reset"),   connect=lambda x: bif.bk_soft_reset(board_id=board_id))
+            #self.off_button         = self.createButton(text=tr("Button", "Board Off"),    connect=lambda x: bif.bk_stop_board(board_id=board_id))
+            #self.off_button.setObjectName("off")
+            self.check_status_button = self.createButton(text=tr("Button", "Check Status"), connect=lambda x: bif._bif_status_readout(board_id=board_id))
+
+
+            seqlist = conf.get_sequence_list()
+            columnctr=0
+            linectr = 0
+            seqcolum = -1
+            try:
+                for item in seqlist:
+                    buttontemp = self.createButton(text=tr("Button", conf.get_sequence_comment(item)), connect=partial(bif.bk_run_sequence, board_id=board_id, name=item))
+                    Buttons.addButton(item, buttontemp)
+                    Elements.addItem('no_board_{}'.format(board_id),[buttontemp])
+                    #self.subControlLayout.addWidget(buttontemp)
+                    if 'PLL_sequence' in item:
+                        if seqcolum == -1:
+                            seqcolum = columnctr
+                            columnctr += 1
+                        self.subControlLayout.addWidget(buttontemp, linectr, seqcolum)
+                        linectr += 1
+
+                    else:
+                        self.subControlLayout.addWidget(buttontemp, 0,columnctr)
+                        columnctr += 1
+
+
+                self.subControlLayout.addWidget(self.set_default_button, 0, columnctr)
+            except Exception as e:
+                traceback.print_exc()
+
+            Buttons.addButton(['set_defaults_{}'.format(board_id), 'after_start_{}'.format(board_id)], self.set_default_button)
+            Elements.addItem('no_board_{}'.format(board_id),
+                             [
+                                 self.set_default_button,
+                                 self.soft_reset_button,
+                                 #self.off_button,
+                                 self.all_in_one_button
+                             ])
+
+            self.mainControlLayout.addWidget(self.all_in_one_button)
+            self.mainControlLayout.addWidget(self.toggleButton)
+            self.mainControlLayout.addWidget(self.skip_init_button)
+
+            self.mainControlLayout.addWidget(self.soft_reset_button)
+            #self.mainControlLayout.addWidget(self.off_button)
+
+            self.statusLayout.addWidget(self.check_status_button)
+
+
+        # register the led updater function (used in backendinterface.bk_status_readout)
+        storage.get_board_specific_storage(board_id).update_LED = self.on_check
+        self.geo = self.saveGeometry()
+        self.subControlWidget.hide()
+
+    def toggle_sub_control(self):
+        """
+        Show or hide the subcontrol buttons
+        """
+        self.subControlWidget.setHidden(not self.subControlWidget.isHidden())
+        if self.subControlWidget.isHidden():
+            self.toggleButton.setIcon(QtGui.QIcon(config.icon_path("chevron-bottom.svg")))
+        else:
+            self.toggleButton.setIcon(QtGui.QIcon(config.icon_path("chevron-top.svg")))
+        self.parent().adjustSize()
+
+    def all_in_one(self):
+        """
+        Function that gets called when the Prepare Board Button is pressed.
+        It Starts the board, syncs it and sets defaults.
+        This is accomplished via the Sequences module
+        :return: -
+        """
+        seq = board.get_board_config(self.board_id).get_init_order()
+        for item in seq:
+            if item == 'startup_sequence':
+                if board.is_active(board_id):
+                    logging.info('Board already powered on - skip startup_sequence')
+                    continue
+
+            bif.bk_run_sequence(self.board_id, item)
+
+        popup = kcgw.PopupDialog("Do not forget to turn on the T/H switches!",
+                                title='Reminder', okonly=True)
+        popup.exec_()
+        popup.deleteLater()
+        popup.get_return_value()
+        board.get_board_config(self.board_id).set_startup()
+
+    def skip_init(self):
+        """
+        Skip board initialisation progress and read data from board. This will adjust the values in the gui to those
+        on the board (for every value that is stored on the board)
+        """
+        board.get_board_config(self.board_id).read_from_board()
+        board.get_board_status(self.board_id).calibrated   = True
+        board.get_board_status(self.board_id).synced       = True
+        board.get_board_status(self.board_id).defaults_set = True
+        bif.bk_status_readout()
+        logging.info("Initialisation skipped, configuration and status was read from KAPTURE.")
+
+    def on_check(self):
+        """
+        This function is the handler for the status leds on the ControlWidget View.
+        Parses the registers and sets the colors of the leds according.
+        :return: -
+        """
+        try:
+            status = bif.bk_get_status(self.board_id)
+        except IndexError:
+            error(0x002, "Pci returned not enough registers to update LEDs.")
+            return
+
+        for led, st in list(status.items()):
+            try:
+                getattr(self, led.lower()+"_led").set_status(st)
+            except:
+                pass
+
+
+#  .d8888b.                 888                  888888       888d8b     888                888
+# d88P  Y88b                888                  888888   o   888Y8P     888                888
+# 888    888                888                  888888  d8b  888        888                888
+# 888        .d88b. 88888b. 888888888d888 .d88b. 888888 d888b 888888 .d88888 .d88b.  .d88b. 888888
+# 888       d88""88b888 "88b888   888P"  d88""88b888888d88888b888888d88" 888d88P"88bd8P  Y8b888
+# 888    888888  888888  888888   888    888  88888888888P Y88888888888  888888  88888888888888
+# Y88b  d88PY88..88P888  888Y88b. 888    Y88..88P8888888P   Y8888888Y88b 888Y88b 888Y8b.    Y88b.
+#  "Y8888P"  "Y88P" 888  888 "Y888888     "Y88P" 888888P     Y888888 "Y88888 "Y88888 "Y8888  "Y888
+#                                                                                888
+#                                                                           Y8b d88P
+#                                                                            "Y88P"
+
+class ControlWidget(kcgw.KCGWidgets):
+    """
+    Main Widget that is shown at start of gui.
+    """
+    def __init__(self):
+        super(ControlWidget, self).__init__()
+
+        self.overlayout = QtGui.QVBoxLayout()
+        self.setLayout(self.overlayout)
+
+        self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical)
+        self.overlayout.addWidget(self.splitter)
+
+        self.log_area = LogArea()
+        self.log_area.setReadOnly(True)
+        self.log_area.init_logging()
+        self.log_area.setKeywords([
+            "Activating Board",
+            "Started Board Calibration",
+            "Synchronize PLLs",
+            "Setting default Values",
+            "Updating Values"
+        ])
+
+        self.board_control_list = {i: BoardControl(i, not available_boards.multi_board) for i in available_boards}
+        self.board_widget = QtGui.QWidget()
+        self.board_widget_layout = QtGui.QVBoxLayout()
+        self.board_widget.setLayout(self.board_widget_layout)
+        for bc in list(self.board_control_list.values()):
+            self.board_widget_layout.addWidget(bc)
+        self.board_widget_layout.addStretch(1)
+
+        if available_boards.multi_board:
+            self.scroll_widget = QtGui.QScrollArea()
+            # self.scroll_widget.setMaximumWidth(1.1 * self.board_control_list.values()[0].minimumSizeHint().width())
+            self.scroll_widget.setWidgetResizable(True)
+            self.scroll_widget.setWidget(self.board_widget)
+            self.scroll_widget_container = QtGui.QWidget()
+            self.scroll_widget_layout = QtGui.QHBoxLayout()
+            self.scroll_widget_layout.addWidget(self.scroll_widget)
+            self.scroll_widget_layout.setAlignment(QtCore.Qt.AlignLeft)
+            self.scroll_widget_container.setLayout(self.scroll_widget_layout)
+            self.splitter.addWidget(self.scroll_widget_container)
+        else:
+            self.splitter.addWidget(self.board_widget)
+
+        # self.log_area = QtGui.QTextEdit()
+
+        self.splitter.addWidget(self.log_area)
+
+        # self.setTabOrder(self.soft_reset_button, self.check_status_button)
+        # self.setTabOrder(self.check_status_button, self.off_button)
+
+        # ------------------[ Logging ]----------------------
+        # log_handler = LogHandler(self.log_area)
+        # self.logger = logging.getLogger()
+        # self.logger.addHandler(log_handler)
+        # self.logger.setLevel(config.log_level)
+        # logging.logger = self.logger
+        # logging.logger.addHandler(log_handler)

+ 157 - 153
KCG/base/MultiWidget.py

@@ -1,153 +1,157 @@
-"""
-This is the container widget for multiple subwindows
-"""
-from PyQt4 import QtGui, QtCore
-
-from . import kcgwidget as kcgw
-from . import LeftBar
-from .globals import glob as global_objects
-from .. import config
-
-tr = kcgw.tr
-
-
-class WidgetTypeError(Exception):
-    """
-    Simple error that describes when a wrong window type gets added
-    """
-    pass
-
-
-class MDIArea(kcgw.KCGWidgets):
-    """
-    The MDI Area used by Multiwidget
-    """
-    def __init__(self, parent):
-        super(MDIArea, self).__init__("MDIArea")
-        self.parent = parent
-        self.layout = QtGui.QHBoxLayout()
-        self.layout.setContentsMargins(0, 0, 0, 0)
-        self.setLayout(self.layout)
-
-        self.widgets = {}
-        self.area = QtGui.QMdiArea()
-        self.area.setFrameStyle(self.area.StyledPanel | self.area.Sunken)
-        self.layout.addWidget(self.area)
-        brush = QtGui.QBrush(QtGui.QColor('white'))
-        self.area.setBackground(brush)
-
-    def newWidget(self, widget, name, unique_id, widget_type, minSize=False):
-        """
-        Add a new Widget to the MDIArea
-        :param widget: (subclass of QMdiSubWindow) The widget to show
-        :param name: (str) name of the window
-        :param unique_id: (int) unique id of the window
-        :param widget_type: (int) the type of this window
-        :param minSize: (bool) whether to shrink the window to minimum size upon creation
-        :return: -
-        """
-        if not isinstance(widget, kcgw.KCGWidgets):
-            raise WidgetTypeError("Newly Created Widget is of type " +
-                                  type(widget).__name__ +
-                                  ". Expected class derived of " +
-                                  kcgw.KCGWidgets.__name__ + ".")
-        subWidget = kcgw.KCGSubWidget(name=name, unique_id=unique_id, typ=widget_type, minSize=minSize)
-        subWidget.setAttribute(QtCore.Qt.WA_DeleteOnClose)
-        widget.setParent(subWidget)
-
-        if minSize:
-            subWidget.resize(widget.minimumSizeHint()*1.2)
-
-
-        widget.closeSignal.connect(subWidget.close)
-        subWidget.setWidget(widget)
-        self.area.addSubWindow(subWidget)
-        subWidget.show()
-        self.widgets[unique_id] = widget
-
-
-# 888b     d888          888 888    d8b 888       888 d8b      888                   888
-# 8888b   d8888          888 888    Y8P 888   o   888 Y8P      888                   888
-# 88888b.d88888          888 888        888  d8b  888          888                   888
-# 888Y88888P888 888  888 888 888888 888 888 d888b 888 888  .d88888  .d88b.   .d88b.  888888
-# 888 Y888P 888 888  888 888 888    888 888d88888b888 888 d88" 888 d88P"88b d8P  Y8b 888
-# 888  Y8P  888 888  888 888 888    888 88888P Y88888 888 888  888 888  888 88888888 888
-# 888   "   888 Y88b 888 888 Y88b.  888 8888P   Y8888 888 Y88b 888 Y88b 888 Y8b.     Y88b.
-# 888       888  "Y88888 888  "Y888 888 888P     Y888 888  "Y88888  "Y88888  "Y8888   "Y888
-#                                                                       888
-#                                                                  Y8b d88P
-#                                                                   "Y88P"
-class MultiWidget(QtGui.QWidget):
-    """
-    The Widget used as Multiwidget. This is the main View during operation with KCG.
-    """
-    def __init__(self):
-        super(MultiWidget, self).__init__()
-        self.layout = QtGui.QVBoxLayout()
-        self.setLayout(self.layout)
-
-        self.splitter = QtGui.QSplitter(QtCore.Qt.Horizontal)
-
-        self.leftBar = LeftBar.LeftBar(self)
-        self.area = MDIArea(self)
-        self.area.setObjectName("MDIArea")
-
-        self.toolbar = QtGui.QToolBar()
-        global_objects.set_global('area', self.area)
-
-        # --------[ ToolBar ]--------
-        self.new_live_action = QtGui.QAction(QtGui.QIcon(config.icon_path(config.newPlotLiveIcon)), tr("Button", "New Live Plot"), self)
-        self.new_live_action.setShortcut("Ctrl+L")
-        self.toolbar.addAction(self.new_live_action)
-        self.new_live_action.triggered.connect(lambda: self.leftBar.add_plot(LeftBar.LIVE))
-        self.new_live_action.setToolTip(tr("Button", "New Live Plot") + "\n(Ctrl+L)")
-
-        self.new_data_action = QtGui.QAction(QtGui.QIcon(config.icon_path(config.newPlotDataIcon)), tr("Button", "New Data Plot"), self)
-        self.new_data_action.setShortcuts(["Ctrl+D", "Ctrl+O"])
-        self.toolbar.addAction(self.new_data_action)
-        self.new_data_action.triggered.connect(lambda: self.leftBar.add_plot(LeftBar.FILE))
-        self.new_data_action.setToolTip(tr("Button", "New Data Plot") + "\n(Ctrl+D/O)")
-
-        self.layout.addWidget(self.toolbar)
-        # ------[ End Tool Bar ]-----
-
-        self.splitter.addWidget(self.leftBar)
-        self.splitter.addWidget(self.area)
-        self.layout.addWidget(self.splitter)
-
-        self.evaluate_registered_widgets()
-        self.evaluate_registered_widget_functions()
-
-    def addToolbarButton(self, icon, text, target, shortcut=None):
-        """
-        Add a toolbar button.
-        :param icon: (QIcon) The icon to show on the toolbar button
-        :param text: (str) tooltip for this button
-        :param target: (callable) The function to call upon press on button
-        :param shortcut: (str) Keyboard shortcut to call target
-        :return: -
-        """
-        na = QtGui.QAction(icon, text, self)
-        if shortcut:
-            na.setShortcut(shortcut)
-            na.setToolTip(text + "\n("+shortcut+")")
-        self.toolbar.addAction(na)
-        na.triggered.connect(target)
-
-    def evaluate_registered_widgets(self):
-        """
-        Evaluate all the registered widgets and add a toolbar button for those
-        :return:
-        """
-        for f in kcgw.get_registered_widgets():
-            self.addToolbarButton(*f)
-
-    def evaluate_registered_widget_functions(self):
-        """
-        Evaluate the functions that are registered
-        Those are in general functions that have to be called after widgets are created
-        :return:
-        """
-        for f in kcgw.get_registered_widget_functions():
-            f()
-
+"""
+This is the container widget for multiple subwindows
+"""
+from PyQt4 import QtGui, QtCore
+
+from . import kcgwidget as kcgw
+from . import LeftBar
+from .globals import glob as global_objects
+from .. import config
+
+tr = kcgw.tr
+
+
+class WidgetTypeError(Exception):
+    """
+    Simple error that describes when a wrong window type gets added
+    """
+    pass
+
+
+class MDIArea(kcgw.KCGWidgets):
+    """
+    The MDI Area used by Multiwidget
+    """
+    def __init__(self, parent):
+        super(MDIArea, self).__init__("MDIArea")
+        self.parent = parent
+        self.layout = QtGui.QHBoxLayout()
+        self.layout.setContentsMargins(0, 0, 0, 0)
+        self.setLayout(self.layout)
+
+        self.widgets = {}
+        self.area = QtGui.QMdiArea()
+        self.area.setFrameStyle(self.area.StyledPanel | self.area.Sunken)
+        self.layout.addWidget(self.area)
+        brush = QtGui.QBrush(QtGui.QColor('white'))
+        self.area.setBackground(brush)
+
+    def newWidget(self, widget, name, unique_id, widget_type, minSize=False):
+        """
+        Add a new Widget to the MDIArea
+        :param widget: (subclass of QMdiSubWindow) The widget to show
+        :param name: (str) name of the window
+        :param unique_id: (int) unique id of the window
+        :param widget_type: (int) the type of this window
+        :param minSize: (bool) whether to shrink the window to minimum size upon creation
+        :return: -
+        """
+        if not isinstance(widget, kcgw.KCGWidgets):
+            raise WidgetTypeError("Newly Created Widget is of type " +
+                                  type(widget).__name__ +
+                                  ". Expected class derived of " +
+                                  kcgw.KCGWidgets.__name__ + ".")
+        subWidget = kcgw.KCGSubWidget(name=name, unique_id=unique_id, typ=widget_type, minSize=minSize)
+        subWidget.setAttribute(QtCore.Qt.WA_DeleteOnClose)
+        widget.setParent(subWidget)
+
+        if minSize:
+            subWidget.resize(widget.minimumSizeHint()*1.2)
+
+
+        widget.closeSignal.connect(subWidget.close)
+        subWidget.setWidget(widget)
+        self.area.addSubWindow(subWidget)
+        subWidget.show()
+        self.widgets[unique_id] = widget
+
+
+# 888b     d888          888 888    d8b 888       888 d8b      888                   888
+# 8888b   d8888          888 888    Y8P 888   o   888 Y8P      888                   888
+# 88888b.d88888          888 888        888  d8b  888          888                   888
+# 888Y88888P888 888  888 888 888888 888 888 d888b 888 888  .d88888  .d88b.   .d88b.  888888
+# 888 Y888P 888 888  888 888 888    888 888d88888b888 888 d88" 888 d88P"88b d8P  Y8b 888
+# 888  Y8P  888 888  888 888 888    888 88888P Y88888 888 888  888 888  888 88888888 888
+# 888   "   888 Y88b 888 888 Y88b.  888 8888P   Y8888 888 Y88b 888 Y88b 888 Y8b.     Y88b.
+# 888       888  "Y88888 888  "Y888 888 888P     Y888 888  "Y88888  "Y88888  "Y8888   "Y888
+#                                                                       888
+#                                                                  Y8b d88P
+#                                                                   "Y88P"
+class MultiWidget(QtGui.QWidget):
+    """
+    The Widget used as Multiwidget. This is the main View during operation with KCG.
+    """
+    def __init__(self):
+        super(MultiWidget, self).__init__()
+        self.layout = QtGui.QVBoxLayout()
+        self.setLayout(self.layout)
+
+        self.splitter = QtGui.QSplitter(QtCore.Qt.Horizontal)
+
+        self.leftBar = LeftBar.LeftBar(self)
+        self.area = MDIArea(self)
+        self.area.setObjectName("MDIArea")
+
+        self.toolbar = QtGui.QToolBar()
+        global_objects.set_global('area', self.area)
+
+        # --------[ ToolBar ]--------
+        self.new_live_action = QtGui.QAction(QtGui.QIcon(config.icon_path(config.newPlotLiveIcon)), tr("Button", "New Live Plot"), self)
+        self.new_live_action.setShortcut("Ctrl+L")
+        self.toolbar.addAction(self.new_live_action)
+        self.new_live_action.triggered.connect(lambda: self.leftBar.add_plot(LeftBar.LIVE))
+        self.new_live_action.setToolTip(tr("Button", "New Live Plot") + "\n(Ctrl+L)")
+
+        self.new_data_action = QtGui.QAction(QtGui.QIcon(config.icon_path(config.newPlotDataIcon)), tr("Button", "New Data Plot"), self)
+        self.new_data_action.setShortcuts(["Ctrl+D", "Ctrl+O"])
+        self.toolbar.addAction(self.new_data_action)
+        self.new_data_action.triggered.connect(lambda: self.leftBar.add_plot(LeftBar.FILE))
+        self.new_data_action.setToolTip(tr("Button", "New Data Plot") + "\n(Ctrl+D/O)")
+
+        self.layout.addWidget(self.toolbar)
+        # ------[ End Tool Bar ]-----
+
+        self.splitter.addWidget(self.leftBar)
+        self.splitter.addWidget(self.area)
+        self.layout.addWidget(self.splitter)
+
+        self.evaluate_registered_widgets()
+        self.evaluate_registered_widget_functions()
+
+        #Automatically open a Live Plot on load complete
+        #This is purely for user convenience
+        self.leftBar.add_plot(LeftBar.LIVE)
+
+    def addToolbarButton(self, icon, text, target, shortcut=None):
+        """
+        Add a toolbar button.
+        :param icon: (QIcon) The icon to show on the toolbar button
+        :param text: (str) tooltip for this button
+        :param target: (callable) The function to call upon press on button
+        :param shortcut: (str) Keyboard shortcut to call target
+        :return: -
+        """
+        na = QtGui.QAction(icon, text, self)
+        if shortcut:
+            na.setShortcut(shortcut)
+            na.setToolTip(text + "\n("+shortcut+")")
+        self.toolbar.addAction(na)
+        na.triggered.connect(target)
+
+    def evaluate_registered_widgets(self):
+        """
+        Evaluate all the registered widgets and add a toolbar button for those
+        :return:
+        """
+        for f in kcgw.get_registered_widgets():
+            self.addToolbarButton(*f)
+
+    def evaluate_registered_widget_functions(self):
+        """
+        Evaluate the functions that are registered
+        Those are in general functions that have to be called after widgets are created
+        :return:
+        """
+        for f in kcgw.get_registered_widget_functions():
+            f()
+

+ 1 - 1
KCG/base/groupedelements.py

@@ -167,7 +167,7 @@ class GroupedObjects:
         :return: -
         :return: -
         """
         """
         if group is None:
         if group is None:
-            group = self._objects.keys()
+            group = list(self._objects.keys())
         groups = group if isinstance(group, list) else [group]
         groups = group if isinstance(group, list) else [group]
         items = item if isinstance(item, list) else [item]
         items = item if isinstance(item, list) else [item]
         for gr in groups:
         for gr in groups:

+ 1 - 1
KCG/default_config.cfg

@@ -121,7 +121,7 @@ device_list = []
 # device_names is a mapping for device ids to pretty names, this makes the use of boards more intuitive
 # device_names is a mapping for device ids to pretty names, this makes the use of boards more intuitive
 # format is: device_names = {'device id': 'device name', ...}
 # format is: device_names = {'device id': 'device name', ...}
 # if this is an empty dict it won't be used
 # if this is an empty dict it won't be used
-device_names = {'test0': 'ich_bin_toll', 'test1': 'ne'}
+device_names = {'test0': 'DEFAULT', 'test1': 'ne'}
 # num_dummy_boards is the number of dummy boards to create
 # num_dummy_boards is the number of dummy boards to create
 num_dummy_boards = 1
 num_dummy_boards = 1
 
 

+ 27 - 10
KCG/widgets/SingleReadWidget.py

@@ -40,7 +40,9 @@ class SingleReadWidget(kcgw.KCGWidgets):
         self.setLayout(self.outerLayout)
         self.setLayout(self.outerLayout)
 
 
         # ---------[ Create Labels and corresponding Fields ]---------
         # ---------[ Create Labels and corresponding Fields ]---------
-        self.single_read_button = self.createButton(tr("Button", "Single Read"), connect=self.on_single_read)
+        self.single_read_button = self.createButton(tr("Button", "Single Acquisition"), connect=self.on_single_read)
+        self.continuous_read_button = self.createButton(tr("Button", "Continuous Acquisition"),
+                connect=lambda: self.on_continuous_read(True, available_boards[0]))
         self.single_read_input  = self.createInput()
         self.single_read_input  = self.createInput()
         self.interval_spinbox = self.createSpinbox(0, 100000, start_value=1000)
         self.interval_spinbox = self.createSpinbox(0, 100000, start_value=1000)
         self.interval_spinbox.valueChanged.connect(self.set_interval)
         self.interval_spinbox.valueChanged.connect(self.set_interval)
@@ -62,14 +64,20 @@ class SingleReadWidget(kcgw.KCGWidgets):
             Elements.addItem(["acquire_{}".format(board_id), "no_board_{}".format(board_id)], tick)
             Elements.addItem(["acquire_{}".format(board_id), "no_board_{}".format(board_id)], tick)
 
 
         # --------[ Fill Grid ]----------------
         # --------[ Fill Grid ]----------------
-        self.layout.addWidget(self.single_read_button, 0, 1)
-        self.layout.addWidget(self.createLabel(tr("Label", "info:")), 1, 0)
-        self.layout.addWidget(self.single_read_input, 1, 1)
-        # self.layout.addWidget(self.continuous_read_button, 0, 1)
-        self.layout.addWidget(self.createLabel(tr("Label", "Interval:") + " (ms)"), 2, 0)
-        self.layout.addWidget(self.interval_spinbox, 2, 1)
+        self.layout.addWidget(self.continuous_read_button, 0, 1)
+        self.layout.addWidget(self.single_read_button, 1, 1)
+        self.layout.addWidget(self.createLabel(tr("Label", "info:")), 2, 0)
+        self.layout.addWidget(self.single_read_input, 2, 1)
+        self.layout.addWidget(self.createLabel(tr("Label", "Interval:") + " (ms)"), 3, 0)
+        self.layout.addWidget(self.interval_spinbox, 3, 1)
         self.setWindowTitle(tr("Heading", "Single and Continuous Read"))
         self.setWindowTitle(tr("Heading", "Single and Continuous Read"))
 
 
+
+        #01.04.2021 by Timo
+        #We currently only support a single board.
+        #However, this might change again in the future, so we only hide
+        #the board selection checkbox until then, to avoid confusion
+        '''
         self.tickLayout = QtGui.QHBoxLayout()
         self.tickLayout = QtGui.QHBoxLayout()
         self.tickLayout.addWidget(self.createLabel(
         self.tickLayout.addWidget(self.createLabel(
                 tr("Label", "Boards"), tooltip=tr("Tooltip", "Check the board you want to select for single read"))
                 tr("Label", "Boards"), tooltip=tr("Tooltip", "Check the board you want to select for single read"))
@@ -90,8 +98,10 @@ class SingleReadWidget(kcgw.KCGWidgets):
             self.tickLayoutContinuousRead.addWidget(tick)
             self.tickLayoutContinuousRead.addWidget(tick)
         self.outerLayout.addLayout(self.tickLayoutContinuousRead)
         self.outerLayout.addLayout(self.tickLayoutContinuousRead)
         self.outerLayout.addLayout(self.tickLayout)
         self.outerLayout.addLayout(self.tickLayout)
+        '''
+
+
         self.outerLayout.addLayout(self.layout)
         self.outerLayout.addLayout(self.layout)
-#        self.outerLayout.addStretch(1)
 
 
         self.set_interval()
         self.set_interval()
 
 
@@ -116,19 +126,26 @@ class SingleReadWidget(kcgw.KCGWidgets):
         # if self.board_ticks_continuous_read[id].isChecked():
         # if self.board_ticks_continuous_read[id].isChecked():
         self.set_interval()
         self.set_interval()
         if state:
         if state:
-            # self.continuous_read_button.setText(tr("Button", "Stop Continuous Read"))
+            self.continuous_read_button.setText(tr("Button", "Stop Continuous Acquisition"))
+            self.continuous_read_button.clicked.connect(lambda: self.on_continuous_read(False, board_id))
+            self.single_read_button.setEnabled(False)
             # self.continuous_read[id] = True
             # self.continuous_read[id] = True
-            self.board_ticks_continuous_read[board_id].setStyleSheet("border-color: green; border-width: 3px;")
+            # self.board_ticks_continuous_read[board_id].setStyleSheet("border-color: green; border-width: 3px;")
         else:
         else:
+            self.continuous_read_button.setText(tr("Button", "Continuous Acquisition"))
+            self.continuous_read_button.clicked.connect(lambda: self.on_continuous_read(True, board_id))
             self.board_ticks_continuous_read[board_id].setStyleSheet("")
             self.board_ticks_continuous_read[board_id].setStyleSheet("")
+            self.single_read_button.setEnabled(True)
         bif.bk_continuous_read(board_id)  # interval=self.interval_spinbox.value())
         bif.bk_continuous_read(board_id)  # interval=self.interval_spinbox.value())
 
 
+
     def set_interval(self):
     def set_interval(self):
         """
         """
         Set the interval between reads
         Set the interval between reads
         """
         """
         storage.continuous_interval = self.interval_spinbox.value()
         storage.continuous_interval = self.interval_spinbox.value()
 
 
+
     def closeEvent(self, event):
     def closeEvent(self, event):
         """
         """
         Event handler to handle the event of closing this window and gracefully delete ids and such
         Event handler to handle the event of closing this window and gracefully delete ids and such

+ 48 - 24
KCG/widgets/TimingWidget.py

@@ -126,7 +126,7 @@ class TimingPart(kcgw.KCGWidgets):
                              [
                              [
                                 #self.coarseInputFpga,
                                 #self.coarseInputFpga,
                                 #self.coarseInputAdc,
                                 #self.coarseInputAdc,
-                                #self.coarseInputTh_2,
+                                self.coarseInputTh_2,
                                 #self.coarse2InputAdc,
                                 #self.coarse2InputAdc,
                                 #self.coarse2InputFpga,
                                 #self.coarse2InputFpga,
                                 self.coarse2InputTh_2
                                 self.coarse2InputTh_2
@@ -159,7 +159,11 @@ class TimingPart(kcgw.KCGWidgets):
         Elements.addItem(["timing_{}".format(self.board_id),
         Elements.addItem(["timing_{}".format(self.board_id),
             "no_board_{}".format(self.board_id),
             "no_board_{}".format(self.board_id),
             "acquire_{}".format(self.board_id),
             "acquire_{}".format(self.board_id),
-            "continuous_read_{}".format(board_id)], self.fineAdcInput)
+            "continuous_read_{}".format(board_id)], 
+                [
+                    self.fineAdcInput
+                ]
+                )
 
 
         self.bunchShiftLabel = self.createLabel(tr("Label", "Bunch Shift"))
         self.bunchShiftLabel = self.createLabel(tr("Label", "Bunch Shift"))
 
 
@@ -170,7 +174,11 @@ class TimingPart(kcgw.KCGWidgets):
         Elements.addItem(["timing_{}".format(self.board_id),
         Elements.addItem(["timing_{}".format(self.board_id),
             "no_board_{}".format(self.board_id),
             "no_board_{}".format(self.board_id),
             "acquire_{}".format(self.board_id),
             "acquire_{}".format(self.board_id),
-            "continuous_read_{}".format(board_id)], self.bunchShiftInput)
+            "continuous_read_{}".format(board_id)], 
+                [
+                    self.bunchShiftInput
+                ]
+                )
 
 
 
 
         #---------[ End ]---------
         #---------[ End ]---------
@@ -191,11 +199,12 @@ class TimingPart(kcgw.KCGWidgets):
         #Bunch Shift values are encoded 0x0 - 0x4 in Hardware
         #Bunch Shift values are encoded 0x0 - 0x4 in Hardware
         #but displayed as -2 to +2 in the GUI, so we need to offset
         #but displayed as -2 to +2 in the GUI, so we need to offset
         #the received register value by -2 when receiving an update
         #the received register value by -2 when receiving an update
-        def setBunchShiftValuesSilent(values):
-            for i, v in enumerate(values):
-                self.bunchShiftInput[i].blockSignals(True)
-                self.bunchShiftInput[i].setValue(v-2)
-                self.bunchShiftInput[i].blockSignals(False)
+        #Values is passed in fro the callback and is expected to be
+        #a list with values for each ADC
+        def setBunchShiftValueSilent(values, adc):
+            self.bunchShiftInput[adc].blockSignals(True)
+            self.bunchShiftInput[adc].setValue(values[adc]-2)
+            self.bunchShiftInput[adc].blockSignals(False)
 
 
 
 
         # --------[ Set observers ]------------
         # --------[ Set observers ]------------
@@ -225,11 +234,16 @@ class TimingPart(kcgw.KCGWidgets):
                 obs(self.coarse25Adc_2, 'delay_25_adc_2')
                 obs(self.coarse25Adc_2, 'delay_25_adc_2')
 
 
 
 
-        board.get_board_config(board_id).observe(
-                self.bunchShiftInput,
-                setBunchShiftValuesSilent,
-                'bunch_shift'
-                )
+        #Observers need to be set on individual control elements
+        #But the callback will be fed with a list of values,
+        #one entry for each ADC
+        for i, item in enumerate(self.bunchShiftInput):
+            board.get_board_config(board_id).observe(
+                    item,
+                    lambda values: setBunchShiftValueSilent(values, i),
+                    'bunch_shift'
+                    )
+
 
 
         # -------[ Create outputs ]---------------
         # -------[ Create outputs ]---------------
         self.totalLabel = self.createLabel(tr("Label", "Total Delay"))
         self.totalLabel = self.createLabel(tr("Label", "Total Delay"))
@@ -348,8 +362,16 @@ class TimingPart(kcgw.KCGWidgets):
                                            self.board_config.get('chip_delay')[i] * self.board_config.get('chip_delay_factor')))
                                            self.board_config.get('chip_delay')[i] * self.board_config.get('chip_delay_factor')))
         if self.board_config.is_KAPTURE2():
         if self.board_config.is_KAPTURE2():
             for i, item in enumerate(self.totalAdcBoxCalib):
             for i, item in enumerate(self.totalAdcBoxCalib):
-                value = theCalibration.calibrateX(i, self.board_config.get('delay_330_th'), self.board_config.get('delay_25_th'), self.board_config.get('chip_delay')[i], self.board_config.get("delay_25_th_2"))
-                item.setText('{}'.format(np.round(value*1e12,1)))
+
+                #Calibration throws errors when opening the Timing Widget
+                #without a calibration file existing. 
+                #I am muting this error for now
+                try:
+                    value = theCalibration.calibrateX(i, self.board_config.get('delay_330_th'), self.board_config.get('delay_25_th'), self.board_config.get('chip_delay')[i], self.board_config.get("delay_25_th_2"))
+                    item.setText('{}'.format(np.round(value*1e12,1)))
+                except:
+                    pass #TODO: Create an exception type for 'No Calibration File' and handle accordingly
+
             """
             """
             if self.fileHandle is not None:
             if self.fileHandle is not None:
                 for i, item in enumerate(self.totalAdcBoxCalib):
                 for i, item in enumerate(self.totalAdcBoxCalib):
@@ -447,7 +469,8 @@ class TimingPart(kcgw.KCGWidgets):
         for i, item in enumerate(self.fineAdcInput):
         for i, item in enumerate(self.fineAdcInput):
             self.board_config.unobserve(item, 'chip_delay')
             self.board_config.unobserve(item, 'chip_delay')
 
 
-        self.board_config.unobserve(self.bunchShiftInput, 'bunch_shift')
+        for i, item in enumerate(self.bunchShiftInput):
+            self.board_config.unobserve(item,'bunch_shift')
 
 
 
 
         self.board_config.unobserve(self.coarseInputTh, 'delay_330_th')
         self.board_config.unobserve(self.coarseInputTh, 'delay_330_th')
@@ -467,29 +490,29 @@ class TimingPart(kcgw.KCGWidgets):
 
 
 
 
         Elements.emptyGroup('timing_{}'.format(self.board_id))
         Elements.emptyGroup('timing_{}'.format(self.board_id))
-        Elements.removeItem(None, self.fineAdcInput)
-        Elements.removeItem(None, self.bunchShiftInput)
+        Elements.removeItem(None, [self.fineAdcInput])
+        Elements.removeItem(None, [self.bunchShiftInput])
         Elements.removeItem(None, [
         Elements.removeItem(None, [
                                     self.coarseInputTh,
                                     self.coarseInputTh,
-                                    self.coarseInputAdc,
-                                    self.coarseInputFpga
+                                    #self.coarseInputAdc,
+                                    #self.coarseInputFpga
                                   ]
                                   ]
                             )
                             )
         if self.board_config.is_KAPTURE2():
         if self.board_config.is_KAPTURE2():
             Elements.removeItem(None, [
             Elements.removeItem(None, [
                                         self.coarse2InputTh,
                                         self.coarse2InputTh,
-                                        self.coarse2InputAdc,
-                                        self.coarse2InputFpga
+                                        #self.coarse2InputAdc,
+                                        #self.coarse2InputFpga
                                       ]
                                       ]
                                 )
                                 )
             if self.adc_number > 4:
             if self.adc_number > 4:
                 Elements.removeItem(None, [
                 Elements.removeItem(None, [
                                             self.coarseInputTh_2,
                                             self.coarseInputTh_2,
-                                            self.coarseInputAdc_2,
+                                            #self.coarseInputAdc_2,
                                             #self.coarseInputFpga_2,
                                             #self.coarseInputFpga_2,
 
 
                                             self.coarse2InputTh_2,
                                             self.coarse2InputTh_2,
-                                            self.coarse2InputAdc_2,
+                                            #self.coarse2InputAdc_2,
                                             #self.coarse2InputFpga_2
                                             #self.coarse2InputFpga_2
                                           ]
                                           ]
                                     )
                                     )
@@ -613,3 +636,4 @@ def addTimingWidget():
         global_objects.get_global('area').newWidget(w, tr("Heading", "Timing"), nid, widget_type=4, minSize=True) #TODO: proper type
         global_objects.get_global('area').newWidget(w, tr("Heading", "Timing"), nid, widget_type=4, minSize=True) #TODO: proper type
 
 
 kcgw.register_widget(QtGui.QIcon(config.icon_path(config.timingIcon)), tr("Heading", "Timing"), addTimingWidget, "Ctrl+T")
 kcgw.register_widget(QtGui.QIcon(config.icon_path(config.timingIcon)), tr("Heading", "Timing"), addTimingWidget, "Ctrl+T")
+kcgw.register_widget_creation_function(addTimingWidget)