8 Commits d3b325b299 ... c14673dc20

Author SHA1 Message Date
  Timo Dritschler c14673dc20 Fixed Observer handling for Bunch Shifts 3 years ago
  Timo Dritschler 1b53b45206 Python3 compliancy fix for GroupedItems 3 years ago
  Timo Dritschler a7e6272eed Made Live Plot open automatically on startup 3 years ago
  Timo Dritschler c32aeb6fb0 Changed line break convention to unix 3 years ago
  Timo Dritschler b80a691477 Removed unprofessional default value 3 years ago
  Timo Dritschler 1c3ef08bfe Turned 'Continuous Read' Tick-Box into a button 3 years ago
  Timo Dritschler 5825c15664 Re-Introduced PLL Status LED 3 years ago
  Timo Dritschler df068d1489 Fixed linebreak convention to unix 3 years ago

+ 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: -
         """
         if group is None:
-            group = self._objects.keys()
+            group = list(self._objects.keys())
         groups = group if isinstance(group, list) else [group]
         items = item if isinstance(item, list) else [item]
         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
 # format is: device_names = {'device id': 'device name', ...}
 # 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 = 1
 

+ 27 - 10
KCG/widgets/SingleReadWidget.py

@@ -40,7 +40,9 @@ class SingleReadWidget(kcgw.KCGWidgets):
         self.setLayout(self.outerLayout)
 
         # ---------[ 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.interval_spinbox = self.createSpinbox(0, 100000, start_value=1000)
         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)
 
         # --------[ 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"))
 
+
+        #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.addWidget(self.createLabel(
                 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.outerLayout.addLayout(self.tickLayoutContinuousRead)
         self.outerLayout.addLayout(self.tickLayout)
+        '''
+
+
         self.outerLayout.addLayout(self.layout)
-#        self.outerLayout.addStretch(1)
 
         self.set_interval()
 
@@ -116,19 +126,26 @@ class SingleReadWidget(kcgw.KCGWidgets):
         # if self.board_ticks_continuous_read[id].isChecked():
         self.set_interval()
         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.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:
+            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.single_read_button.setEnabled(True)
         bif.bk_continuous_read(board_id)  # interval=self.interval_spinbox.value())
 
+
     def set_interval(self):
         """
         Set the interval between reads
         """
         storage.continuous_interval = self.interval_spinbox.value()
 
+
     def closeEvent(self, event):
         """
         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.coarseInputAdc,
-                                #self.coarseInputTh_2,
+                                self.coarseInputTh_2,
                                 #self.coarse2InputAdc,
                                 #self.coarse2InputFpga,
                                 self.coarse2InputTh_2
@@ -159,7 +159,11 @@ class TimingPart(kcgw.KCGWidgets):
         Elements.addItem(["timing_{}".format(self.board_id),
             "no_board_{}".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"))
 
@@ -170,7 +174,11 @@ class TimingPart(kcgw.KCGWidgets):
         Elements.addItem(["timing_{}".format(self.board_id),
             "no_board_{}".format(self.board_id),
             "acquire_{}".format(self.board_id),
-            "continuous_read_{}".format(board_id)], self.bunchShiftInput)
+            "continuous_read_{}".format(board_id)], 
+                [
+                    self.bunchShiftInput
+                ]
+                )
 
 
         #---------[ End ]---------
@@ -191,11 +199,12 @@ class TimingPart(kcgw.KCGWidgets):
         #Bunch Shift values are encoded 0x0 - 0x4 in Hardware
         #but displayed as -2 to +2 in the GUI, so we need to offset
         #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 ]------------
@@ -225,11 +234,16 @@ class TimingPart(kcgw.KCGWidgets):
                 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 ]---------------
         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')))
         if self.board_config.is_KAPTURE2():
             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:
                 for i, item in enumerate(self.totalAdcBoxCalib):
@@ -447,7 +469,8 @@ class TimingPart(kcgw.KCGWidgets):
         for i, item in enumerate(self.fineAdcInput):
             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')
@@ -467,29 +490,29 @@ class TimingPart(kcgw.KCGWidgets):
 
 
         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, [
                                     self.coarseInputTh,
-                                    self.coarseInputAdc,
-                                    self.coarseInputFpga
+                                    #self.coarseInputAdc,
+                                    #self.coarseInputFpga
                                   ]
                             )
         if self.board_config.is_KAPTURE2():
             Elements.removeItem(None, [
                                         self.coarse2InputTh,
-                                        self.coarse2InputAdc,
-                                        self.coarse2InputFpga
+                                        #self.coarse2InputAdc,
+                                        #self.coarse2InputFpga
                                       ]
                                 )
             if self.adc_number > 4:
                 Elements.removeItem(None, [
                                             self.coarseInputTh_2,
-                                            self.coarseInputAdc_2,
+                                            #self.coarseInputAdc_2,
                                             #self.coarseInputFpga_2,
 
                                             self.coarse2InputTh_2,
-                                            self.coarse2InputAdc_2,
+                                            #self.coarse2InputAdc_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
 
 kcgw.register_widget(QtGui.QIcon(config.icon_path(config.timingIcon)), tr("Heading", "Timing"), addTimingWidget, "Ctrl+T")
+kcgw.register_widget_creation_function(addTimingWidget)