소스 검색

Last commit again

Patrick Schreiber 8 년 전
부모
커밋
3df3dc1169

+ 6 - 0
base/backend/board.py

@@ -102,6 +102,12 @@ class BoardConfiguration():
     def get(self, key):
         return self._config.get(key, None)
 
+    def dump(self):
+        s = ""
+        for key in self._config.keys():
+            s += key + ": " + str(self.get(key)) + ", "
+        return s[:-1]
+
     def update(self, key, value):
         self._config[key] = value
         self._notify_observers(key, value)

+ 4 - 3
base/backend/dataset.py

@@ -1,9 +1,10 @@
 import logging
-import numpy as np
 import time
+
+import numpy as np
 from numpy.polynomial.polynomial import polyval
-from .. import config
-import board
+
+import config
 
 
 def _pad_array(array):

+ 2 - 2
base/backend/io.py

@@ -3,13 +3,13 @@ import math
 import logging
 
 import numpy as np
-from ..config import bunches_per_turn as BUNCHES_PER_TURN
+
+from config import bunches_per_turn as BUNCHES_PER_TURN
 from board import HEADER_SIZE_BYTES
 from dataset import DataSet
 import board
 
 
-
 def is_data_consistent(dataset):
     bunch_numbers = dataset.array[:, -1]
     expected = np.tile(np.arange(0, BUNCHES_PER_TURN), bunch_numbers.shape[0] / BUNCHES_PER_TURN)

+ 16 - 3
base/backendinterface.py

@@ -6,18 +6,22 @@ Functions only used internal in this module will be prefixed _bif_
 """
 
 import logging
-from PyQt4 import QtGui, QtCore
+
 import time
 import os
+
+from PyQt4 import QtGui, QtCore
 import numpy as np
 
 from backend import board
 from backend import io
 from backend import dataset
-from groupedelements import Checkboxes, Buttons, MenuItems, Elements, live_plot_windows
+from groupedelements import Checkboxes, Buttons, Elements, live_plot_windows
 import storage
 import config
 import kcgwidget as kcgw
+from log import log
+
 tr = kcgw.tr
 # import widgets.timingWidget as tw
 
@@ -137,6 +141,7 @@ def _bif_status_readout(): # NOTE: This is a minimalized version and is self imp
     Buttons.setEnabled("synchronize", board.status.calibrated)
     Buttons.setEnabled("set_defaults", board.status.synced)
     Buttons.setEnabled("acquire", board.status.synced)
+    Buttons.setEnabled("acquireTrigger", board.status.synced)
     # Elements.setEnabled("timing", board.status.defaults_set)
     Elements.setEnabled("timing", board.status.synced)
 
@@ -183,6 +188,7 @@ class PopupDialog(QtGui.QDialog):
 
 def bk_start_board():
     _bif_enable_wait_cursor()
+    log(additional="Starting Board - following values are probably default values")
 
     if _bif_continuous_read_is_enabled(tr("Button", "Start Board")):
         _bif_disable_wait_cursor()
@@ -264,6 +270,7 @@ class _bif_ProgressBar(QtGui.QProgressBar):
 thread = None
 cal = None
 def bk_calibrate(do_the_rest=None): # TODO: Wie zeitkritisch ist dies, setValue braucht sicher etwas zeit
+    log(additional="Calibrate")
     global thread
     global cal
     if thread is not None:
@@ -401,6 +408,7 @@ def bk_calibrate(do_the_rest=None): # TODO: Wie zeitkritisch ist dies, setValue
 
 def bk_sync_board():
     _bif_enable_wait_cursor()
+    log(additional="Synchronize")
     if _bif_continuous_read_is_enabled(tr("Dialog", "Synchronize Board")):
         _bif_disable_wait_cursor()
         return
@@ -432,6 +440,7 @@ def bk_sync_board():
 
 def bk_set_defaults():
     _bif_enable_wait_cursor()
+    log(additional="Set Default Values")
     if _bif_continuous_read_is_enabled(tr("Dialog", "Synchronize Board")):
         _bif_disable_wait_cursor()
         return
@@ -507,6 +516,7 @@ def bk_set_defaults():
 
 def bk_stop_board():
     _bif_enable_wait_cursor()
+    log(additional="Stop Board")
     # if not self._check_for_no_continuous_read():
     #     _bif_disable_wait_cursor()
     #     return
@@ -541,6 +551,7 @@ def bk_stop_board():
 
 def bk_soft_reset():
     _bif_enable_wait_cursor()
+    log(additional="Soft Reset")
     # if not self._check_for_no_continuous_read():
     #     _bif_disable_wait_cursor()
     #     return
@@ -700,8 +711,10 @@ def _bif_read_and_update(read_func, *args):
 
 def bk_acquire():
     if board.status.acquisition == True:
+        log(additional="Stopped Acquisition")
         _bif_stop_acquisition()
     else:
+        log(additional="Started Acquisition")
         _bif_start_acquisition()
 
 
@@ -726,7 +739,7 @@ def _bif_start_acquisition():
         elem.setText(tr("Button", "Stop Acquisition"))
     board.acquisition_timer = QtCore.QTimer()
     num_acquisitions = board.config.get("orbits_count")
-    acquisition_progressbar = _bif_ProgressBar(1, num_acquisitions, tr("sw", "Acquiring"))
+    acquisition_progressbar = _bif_ProgressBar(0, num_acquisitions, tr("sw", "Acquiring"))
     board.acquisition_progressbar = acquisition_progressbar
 
     spectrogram_dir = storage.storage.save_location + '/' + storage.storage.subdirname+"/spectrograms_{:0.3f}".format(time.time())

+ 0 - 1
base/controlwidget.py

@@ -9,7 +9,6 @@ import storage
 
 tr = kcgw.tr
 
-
 class LED(QtGui.QWidget):
     """
     Produces a graphical LED

+ 50 - 9
base/groupedelements.py

@@ -1,13 +1,27 @@
 from PyQt4 import QtGui
 import warnings
 
+
 class GroupWarning(Warning):
     pass
 
+warnings.simplefilter('always', GroupWarning)
+
 class GroupedObjects:
     def __init__(self):
         self._objects = {}
         self._status = {}
+        self.warn = False
+        self.autoremove = False
+        self.exception_on_deleted = False
+        self.notify_deletion = False
+
+    def setFlags(self, flagDict):
+        self.warn = flagDict.get('warn', False)
+        self.autoremove = flagDict.get('autoremove', False)
+        self.exception_on_deleted = flagDict.get('exception_on_deleted', False)
+        self.notify_deletion = flagDict.get('notify_deletion', False)
+
     def createEmptyGroup(self, group):
         """
         Create an empty group
@@ -72,23 +86,41 @@ class GroupedObjects:
         :return: -
         """
 
+        to_remove = []
         if group in self._objects:
             # if self._objects[group][0] == None:
             self._status[group] = state
             if self._objects[group] == []:
                 return
             for obj in self._objects[group]:
-                if isinstance(obj, QtGui.QAction):
-                    obj.setEnabled(state)
-                elif isinstance(obj, QtGui.QMenu):
-                    obj.menuAction().setVisible(state)
-                # elif isinstance(obj, QtGui.QCheckBox):
-                #     self.setChecked(group, state) # creates overhead because setChecked does the whole group
-                else:
-                    obj.setEnabled(state)
+                try:
+                    if isinstance(obj, QtGui.QAction):
+                        obj.setEnabled(state)
+                    elif isinstance(obj, QtGui.QMenu):
+                        obj.menuAction().setVisible(state)
+                    # elif isinstance(obj, QtGui.QCheckBox):
+                    #     self.setChecked(group, state) # creates overhead because setChecked does the whole group
+                    else:
+                        obj.setEnabled(state)
+                except RuntimeError, e:
+                    if "deleted" in str(e):
+                        # self.removeItem(group, obj)
+                        if self.autoremove:
+                            to_remove.append([group, obj])
+                        if self.warn:
+                            warnings.warn(str(e), GroupWarning, stacklevel=3)
+                        if self.exception_on_deleted:
+                            raise e
+                    else:
+                        raise e
+            if to_remove and self.autoremove:
+                for rm in to_remove:
+                    if self.notify_deletion:
+                        print "Autoremoving element from group '" + rm[0] + "'"
+                    self.removeItem(*rm)
         else:
             self._status[group] = state
-            warnings.warn("Specified Group \""+group+"\" not in Menuitemgroups", GroupWarning, stacklevel=2)
+            warnings.warn("Specified Group \""+group+"\" not in Elements", GroupWarning, stacklevel=2)
 
     def addMenuItem(self, group, item):
         self.addItem(group, item)
@@ -119,12 +151,21 @@ class GroupedObjects:
             del self._objects[group]
         else:
             warnings.warn("Group was not registered - Nothing removed", GroupWarning, stacklevel=2)
+    def emptyGroup(self, group):
+        self.removeGroup(group)
+        self.createEmptyGroup(group)
     def getElements(self, group):
         if group in self._objects:
             return self._objects[group]
         else:
             return []
 
+    def isEnabled(self, group):
+        if group in self._status:
+            return self._status[group]
+        else:
+            return True  # Default for elements is enabled
+
 class LivePlotWindows():
     def __init__(self):
         self.plotWindows = []

+ 145 - 204
base/kcg.py

@@ -1,4 +1,5 @@
 from PyQt4 import QtGui, QtCore
+import os
 
 # --------[ Backend ]---------
 import backendinterface as bif
@@ -10,25 +11,45 @@ from backend import board
 import kcgwidget as kcgw
 from controlwidget import ControlWidget
 from multiWidget import MultiWidget
-from groupedelements import Checkboxes, Buttons, MenuItems, Elements
+from groupedelements import MenuItems, Elements
+from multipage import MultiPage
 import bitsTable as bt
-# import widgets.acquiresettings as acqs
-# import widgets.timingWidget as tw
-# import widgets.singleread as sr
+from base import log
+# ---------[ Widgets IMPORTANT!!! ]------------------
 from widgets import *
+# from widgets import *  # copy in case the above line gets removed by ide
+# ---------[ IMPORTANT ]---------------------
 
-# tr = QtCore.QCoreApplication.translate
-# translator = QtCore.QTranslator()
-# translator.load(QtCore.QLocale(QtCore.QLocale.German, QtCore.QLocale.Germany), 'kcg_de')
-# tr = translator.translate
 tr = kcgw.tr
 
 import config
 import time
 import getpass
+
+Elements.setFlags({'autoremove': True, 'warn': True, 'exception_on_deleted': False})
+
 def readconfig(parent):
+    """
+    Reads the config and evalues certain variables
+    Also: Validates config to check if all necessary values are there
+    :param parent: parent for popup windows
+    :return: -
+    """
+
+    nec_conf = ['language', 'default_save_location', 'default_subdirectory_name', 'force_ask', 'show_advanced_control',
+                'bunches_per_turn', 'save_header', 'tRev', 'newPlotIcon', 'timingIcon', 'singleReadIcon',
+                'acquireSettingsIcon', 'startIcon', 'stopIcon', 'guiIcon']
+    missing_conf = []
+    for c in nec_conf:
+        if c not in dir(config):
+            missing_conf.append(c)
+    if missing_conf:
+        class ConfigError(Exception):
+            pass
+        raise ConfigError('The Following variables are missing in config.py: "' + '", "'.join(missing_conf)+'"')
+
     if config.language != "en_GB":
-        kcgw.translator.load('lang/'+config.language)
+        kcgw.translator.load('lang/'+ config.language)
     else:
         global tr
         kcgw.tr = lambda _, x: x
@@ -65,6 +86,7 @@ def readconfig(parent):
                 break
             else:
                 session = text.replace(" ", "_")
+
     config.default_subdirectory_name = config.default_subdirectory_name.format(
         dateG=dateG, dateGd=dateGd, dateA=dateA, times=times, timel=timel,
         d=time.strftime("%d"), m=time.strftime("%m"), y=time.strftime("%y"),
@@ -82,187 +104,21 @@ def readconfig(parent):
     else:
         config.save_location = config.default_save_location
 
-    board.config.update('header', config.save_header)
 
 _MultiView_Name_ = "MultiView"
 
-class IdGenerator():
-    """
-    Generate Unique Id for every subwindow
-    """
-    highest_id = 0
-    def genid(self):
-        self.highest_id += 1
-        return self.highest_id
-
-idg = IdGenerator()
-kcgw.idg = idg
-
-class RightSwitch(kcgw.ClickableSVG):
-    """
-    Buttons to change the Page in a MultiPage
-    """
-    def __init__(self, pagesWidget, width=10, height=20, wwidth=None, hidden=False):
-        super(RightSwitch, self).__init__("icons/chevron-right.svg", width, height, wwidth)
-        self.setObjectName("right_switch")
-        if not hidden:
-            self.show()
-        self.clicked.connect(lambda: pagesWidget.setCurrentIndex(pagesWidget.currentIndex()+1))
-
-
-class LeftSwitch(kcgw.ClickableSVG):
-    """
-    Buttons to change the Page in a MultiPage Widget
-    """
-    def __init__(self, pagesWidget, width=10, height=20, wwidth=None, hidden=False):
-        super(LeftSwitch, self).__init__("icons/chevron-left.svg", width, height, wwidth)
-        self.setObjectName("left_switch")
-        if not hidden:
-            self.show()
-        self.clicked.connect(lambda: pagesWidget.setCurrentIndex(pagesWidget.currentIndex()-1))
-
-
-class LeftRightSwitch(QtGui.QWidget):
-    """
-    Small Buttons to change the Page in a MultiPage Widget
-    """
-    def __init__(self, pagesWidget):
-        super(LeftRightSwitch, self).__init__()
-        self.right = RightSwitch(pagesWidget, width=10, height=10)
-        self.right.setObjectName("leftright")
-        self.left = LeftSwitch(pagesWidget, width=10, height=10)
-        self.left.setObjectName("leftright")
-        self.layout = QtGui.QHBoxLayout()
-        self.setLayout(self.layout)
-        self.layout.addWidget(self.left)
-        self.layout.addWidget(self.right)
-    def disable_left(self):
-        # self.left.setStyleSheet("border-radius: 4px; background-color: lightgrey;")
-        self.left.setStyleSheet("#leftright:hover { background-color: none;}")
-        self.left.changeSvg("icons/grey/chevron-left.svg")
-    def enable_left(self):
-        self.left.setStyleSheet("")
-        self.left.changeSvg("icons/chevron-left.svg")
-    def disable_right(self):
-        # self.right.setStyleSheet("border-radius: 4px; background-color: lightgrey;")
-        self.right.setStyleSheet("#leftright:hover { background-color: none;}")
-        self.right.changeSvg("icons/grey/chevron-right.svg")
-    def enable_right(self):
-        self.right.setStyleSheet("")
-        self.right.changeSvg("icons/chevron-right.svg")
-
-
-class MultiPage(QtGui.QStackedWidget):
+class CentralWidget(kcgw.KCGWidgets):
     """
-    Implementation of a Paginated View Widget
+    Central Widget for the KCG gui main window
     """
-    def __init__(self, parent=None):
-        super(MultiPage, self).__init__(parent)
-        self.pages = []
-        self.numOfPages = -1
-        self.leftright = LeftRightSwitch(self)
-        self.leftright.hide()
-        self.setCurrentIndex(0)
-        self.leftShortcut = QtGui.QShortcut(QtGui.QKeySequence("Ctrl+Left"), self, self.left)
-        self.rightShortcut = QtGui.QShortcut(QtGui.QKeySequence("Ctrl+Right"), self, self.right)
-        self.lSwitches = []
-        self.rSwitches = []
-
-    def addPage(self, NewPage, name=None, set_to_first=True):
-        """
-        Add a page (a Widget) to the MultiPage Widget
-        :param NewPage: widget to add as new page
-        :param name: name of that page (e.g. to show in the status bar)
-        :param bool set_to_first: Set the current page to first page
-        :return: -
-        """
-        self.leftright.show()
-        self.numOfPages += 1
-        self.pages.append(QtGui.QWidget())
-        self.pages[-1].widget = NewPage
-        self.rSwitches.append(RightSwitch(self, wwidth=20, hidden=True))
-        self.lSwitches.append(LeftSwitch(self, wwidth=20, hidden=True))
-        NewPage.index = len(self.pages)-1
-        self.pages[-1].name = name
-        self.pages[-1].layout = QtGui.QHBoxLayout()
-        self.pages[-1].setLayout(self.pages[-1].layout)
-        if len(self.pages) == 1:
-            self.pages[-1].layout.addWidget(NewPage)
-        if len(self.pages) > 1:
-            self.rSwitches[-2].show()
-            self.pages[-2].layout.addWidget(self.rSwitches[-2])
-            self.lSwitches[-1].show()
-            self.pages[-1].layout.addWidget(self.lSwitches[-1])
-            self.pages[-1].layout.addWidget(NewPage)
-        self.addWidget(self.pages[-1])
-        if set_to_first:
-            self.setCurrentIndex(0)
-        else:
-            name = self.pages[self.currentIndex()].name+" " if self.pages[self.currentIndex()].name else " "
-            self.window().pageIndicator.setText(name+"| "+str(self.currentIndex()+1)+"/"+str(self.numOfPages+1))
-
-
-    def removePage(self, page):
-        """
-        Removes a page from the pages widget and adjusts switches accordingly
-        :param page: what page to remove
-        :return: -
-        """
-        if self.numOfPages == 1:
-            raise IndexError("Not enough pages left")
-        self.numOfPages -=1
-        idx = page.index
-        self.removeWidget(self.pages[idx])
-        del self.pages[idx]
-        del self.lSwitches[idx]
-        del self.rSwitches[idx]
-        self.pages[-1].layout.removeWidget(self.rSwitches[-1])
-        self.rSwitches[-1].hide()
-        name = self.pages[self.currentIndex()].name+" " if self.pages[self.currentIndex()].name else " "
-        self.window().pageIndicator.setText(name+"| "+str(self.currentIndex()+1)+"/"+str(self.numOfPages+1))
-
-
-    def left(self):
-        self.setCurrentIndex(self.currentIndex()-1)
-    def right(self):
-        self.setCurrentIndex(self.currentIndex()+1)
-
-    def setCurrentIndex(self, p_int):
-        """
-        Set te current Index of the MultiPage Widget (e.g. set the current page)
-        :param p_int: (int) what page
-        :return: -
-        """
-        if self.currentIndex() >= 0 and p_int <= self.numOfPages:
-            MenuItems.setEnabled(self.pages[self.currentIndex()].name.strip(), False)
-        if p_int > self.numOfPages or p_int < 0:
-            return
-        if p_int <= 0:
-            self.leftright.disable_left()
-        else:
-            self.leftright.enable_left()
-        if p_int >= self.numOfPages:
-            self.leftright.disable_right()
-        else:
-            self.leftright.enable_right()
-        name = self.pages[p_int].name+" " if self.pages[p_int].name else " "
-        self.window().pageIndicator.setText(name+"| "+str(p_int+1)+"/"+str(self.numOfPages+1))
-        super(MultiPage, self).setCurrentIndex(p_int)
-        MenuItems.setEnabled(name.strip(), True)
-        if getattr(self.pages[self.currentIndex()].widget, 'pages_update_function', None) is not None:
-            self.pages[self.currentIndex()].widget.pages_update_function()
-
-
-class CentralWidget(kcgw.KCGWidgets):
     def __init__(self, parent=None):
         super(CentralWidget, self).__init__(parent=parent)
-        self.initUI()
 
-    def initUI(self):
         # -------[ Create empty Groups to avoid warnings ]---------
         MenuItems.createEmptyGroup('Setup/Control')
         MenuItems.createEmptyGroup('Bits Table')
         # -------[ END ]---------------
+
         self.layout = QtGui.QHBoxLayout()
         self.setLayout(self.layout)
         self.pagesWidget = MultiPage(self)
@@ -273,44 +129,104 @@ class CentralWidget(kcgw.KCGWidgets):
         self.tableWidget.hide()
         self.pagesWidget.addPage(self.mainControlWidget, "Setup/Control")
         self.pagesWidget.addPage(self.mainMultiWidget, "MultiView")
-        # self.pagesWidget.addPage(self.tableWidget, "Bits Table")
 
 
 
 class Gui(QtGui.QMainWindow):
+    """
+    Main Window of the KCG gui
+    """
     def __init__(self, app):
         super(Gui, self).__init__()
-        self.app = app
-        self.setWindowTitle("KCG - Kapture Control Gui")
-        self.setWindowIcon(QtGui.QIcon(config.guiIcon))
-        Elements.createEmptyGroup("no_board")
+
+        self.createEmptyGroups()
         self.check_for_board()
         readconfig(self)
+
+        # ----------[ Set Variables and create objects ]-----------------
+        self.app = app
         self.storage = storage.Storage()
         storage.storage = self.storage
-        self.populate_storage()
         self.settings = None # Only create Window when used
         self.statusbar = self.statusBar()
-        self.statusbar.showMessage(board.status.status_text)
         kcgw.statusbar = self.statusbar # set status bar to kcgw to easily access from other sources
         self.pageIndicator = QtGui.QLabel()
-        self.statusbar.addPermanentWidget(self.pageIndicator)
-        QtGui.QApplication.setStyle("Oxygen") # Make it look less blown up in Gnome for example
+        self.cw = CentralWidget(self)
+
         self.initUI()
+        self.doMenu()
+        self.finalizeInit()
+
         self.after_start_status_handler()
 
     def initUI(self):
-        self.cw = CentralWidget(self)
+        """
+        Initialize ui
+        :return: -
+        """
+        self.setWindowTitle("KCG - Kapture Control Gui")
+        self.setWindowIcon(QtGui.QIcon(config.guiIcon))
         self.setCentralWidget(self.cw)
-        self.menu = self.menuBar()
+
+        self.statusbar.showMessage(board.status.status_text)
+        self.statusbar.addPermanentWidget(self.pageIndicator)
+
+        QtGui.QApplication.setStyle("Oxygen") # Make it look less blown up in Gnome for example
+
+    def createEmptyGroups(self):
+        # ------[ Create Groups to avoid warnings ]---------
+        Elements.createEmptyGroup("acquire")
+        Elements.createEmptyGroup("timing")
+        Elements.createEmptyGroup("no_board")
+
+
+    def finalizeInit(self):
+        """
+        Final things done at initialisation
+        :return: -
+        """
+
+
+        self.populate_storage()
+
+        with open("style/style.css") as f:
+            styleSheet = f.read()
+        self.setStyleSheet(styleSheet)
+
 
         # evaluate config file regarding advanced_control
         self.showAdvancedControl(config.show_advanced_control)
         self.storage.advanced_control = config.show_advanced_control
 
 
-        # newPlotAction = QtGui.QAction("New Plot", self)
-        # newPlotAction.triggered.connect(lambda: self.changePage_and_execute(1 ,self.cw.mainMultiWidget.leftBar.add_plot))
+        board.config.update('header', config.save_header)
+
+        if not os.path.isdir(storage.storage.save_location + '/' + storage.storage.subdirname):
+            os.makedirs(storage.storage.save_location + '/' + storage.storage.subdirname)
+        self.measurementLogger = log.MeasurementLogger(storage.storage.save_location + '/' + storage.storage.subdirname
+                                                       + "/Measurement.log")
+        self.measurementLogger.register_parameter("Number of Orbits", board.config.get, "orbits_observe")
+        self.measurementLogger.register_parameter("Number of Skipped Orbits", board.config.get, 'orbits_skip')
+        self.measurementLogger.register_parameter("Number of Acquisitions", board.config.get, 'orbits_count')
+        self.measurementLogger.register_parameter("Time between Acquisitions", board.config.get, 'orbits_wait_time')
+        self.measurementLogger.register_parameter("Pilotbunch Simulation", board.config.get, 'pilot_bunch')
+        self.measurementLogger.register_parameter("Header saved", board.config.get, 'header')
+        self.measurementLogger.register_parameter("T/H Delay", board.config.get, 'th_delay')
+        self.measurementLogger.register_parameter("ADC 1 Delay", board.config.get, 'chip_1_delay')
+        self.measurementLogger.register_parameter("ADC 2 Delay", board.config.get, 'chip_2_delay')
+        self.measurementLogger.register_parameter("ADC 3 Delay", board.config.get, 'chip_3_delay')
+        self.measurementLogger.register_parameter("ADC 4 Delay", board.config.get, 'chip_4_delay')
+        self.measurementLogger.register_dumper(board.config.dump)
+        log.logger = self.measurementLogger
+
+
+
+    def doMenu(self):
+        """
+        Create and show the menu and it's entries
+        :return: -
+        """
+        self.menu = self.menuBar()
 
         self.fileMenu = self.menu.addMenu("&"+tr("Button", "File"))
         self.settingsAction = self.fileMenu.addAction(tr("Button", "Settings"), self.showSettings, "Ctrl+P")
@@ -327,7 +243,7 @@ class Gui(QtGui.QMainWindow):
         MenuItems.addMenuItem(_MultiView_Name_, self.acquireMenu)
         self.startAcquisitionAction = self.acquireMenu.addAction(QtGui.QIcon(config.startIcon), tr("Button", "Start Acquisition"), bif.bk_acquire)
         self.startAcquisitionAction.setObjectName("start_acquisition_action")
-        # self.acquireMenu.addAction(self.acquireSettingsAction)
+
         MenuItems.addMenuItem("continuous_read", self.startAcquisitionAction)
         MenuItems.addMenuItem("acquireTrigger", self.startAcquisitionAction)
 
@@ -340,13 +256,6 @@ class Gui(QtGui.QMainWindow):
         self.help.addAction(tr("Button", "Open Manual"), lambda: webbrowser.open("Documentation/build/html/index.html"))
         self.help.addAction(tr("Button", "About"), self.showAbout)
 
-        with open("style/style.css") as f:
-            styleSheet = f.read()
-        self.setStyleSheet(styleSheet)
-
-        # ------[ Create Groups to avoid warnings ]---------
-        Elements.createEmptyGroup("acquire")
-        Elements.createEmptyGroup("timing")
 
     def showAbout(self):
         version = open("VERSION").read()
@@ -354,6 +263,7 @@ class Gui(QtGui.QMainWindow):
         about.setWindowTitle("KCG - About")
         about_label = QtGui.QLabel(tr("About", "KCG - KAPTURE Control Gui\n\n"
                                                "This is the graphical control interface to the KAPTURE board\n\n"
+                                               "KAPTURE - Karlsruhe Pulse-Taking and Ultrafast Readout Electronics\n\n"
                                                "Version: ")+version)
         about_layout = QtGui.QHBoxLayout()
         about.setLayout(about_layout)
@@ -368,15 +278,19 @@ class Gui(QtGui.QMainWindow):
         about.exec_()
 
     def addWindowMenuEntries(self):
+        """
+        Adds Window Menu entries for custom widgets
+        :return: -
+        """
         for f in kcgw.get_registered_widgets():
             self.multiMenu.addAction(*f[:3]) # TODO: icon
 
 
-    def changePage_and_execute(self, page, conn):
-        self.cw.pagesWidget.setCurrentIndex(page)
-        conn()
-
     def showSettings(self):
+        """
+        Create and show settings window
+        :return: -
+        """
         if self.settings: # use preopened window
             self.settings.show()
             self.settings.raise_()
@@ -386,6 +300,11 @@ class Gui(QtGui.QMainWindow):
             self.settings.changed.connect(self.updateSettings)
 
     def updateSettings(self, changedsettings):
+        """
+        Update settings in storage if settings were changed in the settings window.
+        :param changedsettings: list of settings that have been changed
+        :return: -
+        """
         for setting in changedsettings:
             if setting == 'language':
                 lang = getattr(self.storage, setting)
@@ -398,6 +317,11 @@ class Gui(QtGui.QMainWindow):
         # TODO: implement settings updater
 
     def showAdvancedControl(self, value):
+        """
+        Enable or disable advanced table control view (Tables for registers)
+        :param value: (bool) True to show and False to hide advanced view
+        :return: -
+        """
         if value:
             if self.cw.tableWidget.isHidden():
                 self.cw.pagesWidget.addPage(self.cw.tableWidget, 'Bits Table', set_to_first=False)
@@ -408,6 +332,13 @@ class Gui(QtGui.QMainWindow):
                 self.cw.tableWidget.hide()
 
     def check_for_board(self):
+        """
+        Check if board is connected
+        Also overrides the _bif_status_readout function with a function that does nothing (suppresses read attempts that
+        generate errors - if no board is connected, there is nothing to read from)
+        Also overrides the bk_get_temperature function as of the same reasons
+        :return: -
+        """
         if not bif.bk_board_connected():
             Elements.setEnabled('no_board', False)
 
@@ -425,6 +356,10 @@ class Gui(QtGui.QMainWindow):
             bif._bif_status_readout()
 
     def populate_storage(self):
+        """
+        Initially fills storage with predefined settings and configuration values
+        :return: -
+        """
         self.storage.header = config.save_header
         self.storage.subdirname = config.subdirectory_name
         self.storage.save_location = config.save_location
@@ -438,7 +373,7 @@ class Gui(QtGui.QMainWindow):
         :return:
         """
         import re
-        filename = "base/config.py"
+        filename = "config.py"
         RE = '(('+'|'.join(new_conf.keys())+')\s*=)[^\r\n]*?(\r?\n|\r)'
         pat = re.compile(RE)
 
@@ -452,6 +387,12 @@ class Gui(QtGui.QMainWindow):
             f.write(pat.sub(jojo,content))
 
     def closeEvent(self, ev):
+        """
+        Handles closing of the GUI - this function is called by pyqt upon a close event.
+        Asks if user really wants to close the gui
+        :param ev: event
+        :return: -
+        """
         cl = QtGui.QMessageBox.question(self, tr("Heading", "Close KCG"),
                                         tr("Dialog", "Close KCG?\nYou will loose the state of open plots etc."),
                                         QtGui.QMessageBox.No | QtGui.QMessageBox.Yes,

+ 13 - 29
base/kcgwidget.py

@@ -3,8 +3,6 @@ Class containing the creators for buttons etc
 """
 from PyQt4 import QtGui, QtCore, QtSvg
 
-idg = None
-
 class BigIconButton(QtGui.QPushButton):
     def __init__(self, path, width, height, connect=None, tooltip=None, parent=None):
         super(BigIconButton, self).__init__(parent)
@@ -202,32 +200,18 @@ class KCGSubWidget(QtGui.QMdiSubWindow):
     def theName(self, n):
         self._name = n # TODO: ??
 
-    # def createButton(self, x=None, y=None, dimensions=None, text="", tooltip="", connect=False):
-    #     button = QtGui.QPushButton(text, self)
-    #     if tooltip:
-    #         button.setToolTip(tooltip)
-    #     if not dimensions:
-    #         button.resize(button.sizeHint())
-    #     else:
-    #         button.resize(dimensions)
-    #     if x and y:
-    #         button.move(x, y)
-    #     if connect:
-    #         button.clicked.connect(connect)
-    #     return button
-    #
-    # def createLabel(self, text=None, image=None, tooltip=None, click=False):
-    #     if click:
-    #         label = clickLabel(self)
-    #     else:
-    #         label = QtGui.QLabel(self)
-    #     if text:
-    #         label.setText(text)
-    #     if image:
-    #         label.setPixmap(image)
-    #     if tooltip:
-    #         label.setToolTip(tooltip)
-    #     return label
+
+class IdGenerator():
+    """
+    Generate Unique Id for every subwindow
+    """
+    highest_id = 0
+    def genid(self):
+        self.highest_id += 1
+        return self.highest_id
+
+idg = IdGenerator()  # declare idgenerator instance to use globally
+
 
 _registered_possible_widgets = []
 _registered_possible_widget_functions = []
@@ -243,4 +227,4 @@ def get_registered_widgets():
 def get_registered_widget_functions():
     return _registered_possible_widget_functions
 
-consistency_updater = None # To be set in LeftBar
+consistency_updater = None  # To be set in LeftBar

+ 22 - 4
base/leftbar.py

@@ -1,6 +1,5 @@
 # -*- coding: utf-8 -*-
 from PyQt4 import QtGui, QtCore
-import numpy as np
 
 import kcgwidget as kcgw
 from plotWidget import PlotWidget
@@ -8,8 +7,10 @@ from backend import board
 from backend import io
 import storage
 import widgets.acquiresettings as acqs
-from groupedelements import Buttons, Checkboxes, Elements
+from groupedelements import Buttons, Elements
 import backendinterface as bif
+import log
+
 
 tr = kcgw.tr
 
@@ -63,6 +64,7 @@ class AcquisitionAndInfo(kcgw.KCGWidgets):
         )
         board.config.observe(self.orbitswait, lambda x: self.orbitswait.setText(tr("Label", "T_wait:")+ " " + str(x)), 'orbits_wait_time')
         self.acquire = self.createButton(tr("Button", "Start Acquisition"), icon=QtGui.QIcon(config.startIcon), connect=bif.bk_acquire)
+        self.log = self.createButton(tr("Button", "Log"), icon=QtGui.QIcon(config.startIcon), connect=log.log)
         self.acquireShortcut = QtGui.QShortcut("Ctrl+B", self, bif.bk_acquire)
         Buttons.addButton("continuous_read", self.acquireShortcut)
         Buttons.addButton("continuous_read", self.acquire)
@@ -80,9 +82,11 @@ class AcquisitionAndInfo(kcgw.KCGWidgets):
         # self.layout.addWidget(self.acquire, 2, 1)
         self.overLayout.addLayout(self.layout)
         self.overLayout.addWidget(self.acquire)
+        self.overLayout.addWidget(self.log)
 
         def update_temp():
-            self.temperature.setText("Temp: " + bif.bk_get_temperature() + u" °C")
+            if board.status.board_connected:
+                self.temperature.setText("Temp: " + bif.bk_get_temperature() + u" °C")
         try:
             update_temp()
         except:
@@ -178,6 +182,8 @@ class LeftBar(kcgw.KCGWidgets):
         if item.is_child:
             self.openPlotWindows[item.usid].setFocus()
         else:
+            if not item.ready:
+                return
             if i==1:
                 position = QtGui.QCursor.pos()
                 menu = QtGui.QMenu(self)
@@ -220,15 +226,27 @@ class LeftBar(kcgw.KCGWidgets):
         if datatype == FILE:
             self.openData[unique_id].fName = fName
         self.openData[unique_id].setText(0, "Live" if datatype == LIVE else fName.split('/')[-1])
-        self.openData[unique_id].setText(1, "+")
+        self.openData[unique_id].setText(1, "Reading")
         if datatype == LIVE: # Insert LIVE on top
             self.treeWidget.insertTopLevelItem(0, self.openData[unique_id])
         else:
             self.treeWidget.addTopLevelItem(self.openData[unique_id])
         self.treeWidget.expandItem(self.openData[unique_id])
         self.treeWidget.resizeColumnToContents(0)
+        self.openData[unique_id].ready = False  # indicates whether data was completely read or not
+        QtGui.qApp.processEvents()
         self.read_data(datatype, unique_id, fName if datatype == FILE else None)
+        self.openData[unique_id].ready = True # indicates whether data was completely read or not
+        self.openData[unique_id].setText(1, "+")
+
     def read_data(self, type, uid, fName):
+        """
+        Reads datafile
+        :param type: FILE or LIVE - type of datasource
+        :param uid: unique id for the treeelement
+        :param fName: filename if type is FILE
+        :return: -
+        """
         if type == FILE:
             self.Data[uid] = io.read_from_file(fName, header=storage.storage.header) # TODO: get header from file????
         else:

+ 53 - 0
base/log.py

@@ -0,0 +1,53 @@
+import datetime
+
+INFO = 0
+DEBUG = 1
+
+class MeasurementLogger(object):
+    def __init__(self, filename, level=INFO, oneline=False):
+        self.level = level
+        self.filename = filename
+        self.parameter_functions = []
+        self.oneline = oneline
+        self.dumper = None
+
+    def __now(self):
+        return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+    def _loggin_formatter(self, info):
+        if self.oneline:
+            return self.__now() + " " + ", ".join(info)
+        return self.__now() + "\n\t" + "\n\t".join(info)
+    def _log(self, stuff):
+        f = open(self.filename, 'a')
+        f.write(stuff+'\n\n')
+        f.close()
+    def register_parameter(self, logstring, func, *args):
+        self.parameter_functions.append([func, args, logstring])
+    def register_dumper(self, func):
+        self.dumper = func
+    def dump(self):
+        self.do_log(self.__now() + " " + self.dumper())
+    def do_log(self, c=None, additional=None):
+        if c:
+            self._log(c)
+        else:
+            st = []
+            if additional:
+                st.append(additional)
+            for par in self.parameter_functions:
+                st.append(par[2]+ ": " + str(par[0](*par[1])))
+            self._log(self._loggin_formatter(st))
+
+logger = None
+def log(c=None, additional=None, dump=False):
+    """
+    Execute logging if logger was registered
+    :return: -
+    """
+    if logger:
+        if dump:
+            logger.dump()
+        else:
+            logger.do_log(c, additional)
+    else:
+        print "No Logger registered"

+ 157 - 0
base/multipage.py

@@ -0,0 +1,157 @@
+from PyQt4 import QtGui, QtCore
+from groupedelements import Elements, MenuItems
+import kcgwidget as kcgw
+
+class RightSwitch(kcgw.ClickableSVG):
+    """
+    Buttons to change the Page in a MultiPage
+    """
+    def __init__(self, pagesWidget, width=10, height=20, wwidth=None, hidden=False):
+        super(RightSwitch, self).__init__("icons/chevron-right.svg", width, height, wwidth)
+        self.setObjectName("right_switch")
+        if not hidden:
+            self.show()
+        self.clicked.connect(lambda: pagesWidget.setCurrentIndex(pagesWidget.currentIndex()+1))
+
+
+class LeftSwitch(kcgw.ClickableSVG):
+    """
+    Buttons to change the Page in a MultiPage Widget
+    """
+    def __init__(self, pagesWidget, width=10, height=20, wwidth=None, hidden=False):
+        super(LeftSwitch, self).__init__("icons/chevron-left.svg", width, height, wwidth)
+        self.setObjectName("left_switch")
+        if not hidden:
+            self.show()
+        self.clicked.connect(lambda: pagesWidget.setCurrentIndex(pagesWidget.currentIndex()-1))
+
+
+class LeftRightSwitch(QtGui.QWidget):
+    """
+    Small Buttons to change the Page in a MultiPage Widget
+    """
+    def __init__(self, pagesWidget):
+        super(LeftRightSwitch, self).__init__()
+        self.right = RightSwitch(pagesWidget, width=10, height=10)
+        self.right.setObjectName("leftright")
+        self.left = LeftSwitch(pagesWidget, width=10, height=10)
+        self.left.setObjectName("leftright")
+        self.layout = QtGui.QHBoxLayout()
+        self.setLayout(self.layout)
+        self.layout.addWidget(self.left)
+        self.layout.addWidget(self.right)
+    def disable_left(self):
+        # self.left.setStyleSheet("border-radius: 4px; background-color: lightgrey;")
+        self.left.setStyleSheet("#leftright:hover { background-color: none;}")
+        self.left.changeSvg("icons/grey/chevron-left.svg")
+    def enable_left(self):
+        self.left.setStyleSheet("")
+        self.left.changeSvg("icons/chevron-left.svg")
+    def disable_right(self):
+        # self.right.setStyleSheet("border-radius: 4px; background-color: lightgrey;")
+        self.right.setStyleSheet("#leftright:hover { background-color: none;}")
+        self.right.changeSvg("icons/grey/chevron-right.svg")
+    def enable_right(self):
+        self.right.setStyleSheet("")
+        self.right.changeSvg("icons/chevron-right.svg")
+
+
+class MultiPage(QtGui.QStackedWidget):
+    """
+    Implementation of a Paginated View Widget
+    """
+    def __init__(self, parent=None):
+        super(MultiPage, self).__init__(parent)
+        self.pages = []
+        self.numOfPages = -1
+        self.leftright = LeftRightSwitch(self)
+        self.leftright.hide()
+        self.setCurrentIndex(0)
+        self.leftShortcut = QtGui.QShortcut(QtGui.QKeySequence("Ctrl+Left"), self, self.left)
+        self.rightShortcut = QtGui.QShortcut(QtGui.QKeySequence("Ctrl+Right"), self, self.right)
+        self.lSwitches = []
+        self.rSwitches = []
+
+    def addPage(self, NewPage, name=None, set_to_first=True):
+        """
+        Add a page (a Widget) to the MultiPage Widget
+        :param NewPage: widget to add as new page
+        :param name: name of that page (e.g. to show in the status bar)
+        :param bool set_to_first: Set the current page to first page
+        :return: -
+        """
+        self.leftright.show()
+        self.numOfPages += 1
+        self.pages.append(QtGui.QWidget())
+        self.pages[-1].widget = NewPage
+        self.rSwitches.append(RightSwitch(self, wwidth=20, hidden=True))
+        self.lSwitches.append(LeftSwitch(self, wwidth=20, hidden=True))
+        NewPage.index = len(self.pages)-1
+        self.pages[-1].name = name
+        self.pages[-1].layout = QtGui.QHBoxLayout()
+        self.pages[-1].setLayout(self.pages[-1].layout)
+        if len(self.pages) == 1:
+            self.pages[-1].layout.addWidget(NewPage)
+        if len(self.pages) > 1:
+            self.rSwitches[-2].show()
+            self.pages[-2].layout.addWidget(self.rSwitches[-2])
+            self.lSwitches[-1].show()
+            self.pages[-1].layout.addWidget(self.lSwitches[-1])
+            self.pages[-1].layout.addWidget(NewPage)
+        self.addWidget(self.pages[-1])
+        if set_to_first:
+            self.setCurrentIndex(0)
+        else:
+            name = self.pages[self.currentIndex()].name+" " if self.pages[self.currentIndex()].name else " "
+            self.window().pageIndicator.setText(name+"| "+str(self.currentIndex()+1)+"/"+str(self.numOfPages+1))
+
+
+    def removePage(self, page):
+        """
+        Removes a page from the pages widget and adjusts switches accordingly
+        :param page: what page to remove
+        :return: -
+        """
+        if self.numOfPages == 1:
+            raise IndexError("Not enough pages left")
+        self.numOfPages -=1
+        idx = page.index
+        self.removeWidget(self.pages[idx])
+        del self.pages[idx]
+        del self.lSwitches[idx]
+        del self.rSwitches[idx]
+        self.pages[-1].layout.removeWidget(self.rSwitches[-1])
+        self.rSwitches[-1].hide()
+        name = self.pages[self.currentIndex()].name+" " if self.pages[self.currentIndex()].name else " "
+        self.window().pageIndicator.setText(name+"| "+str(self.currentIndex()+1)+"/"+str(self.numOfPages+1))
+
+
+    def left(self):
+        self.setCurrentIndex(self.currentIndex()-1)
+    def right(self):
+        self.setCurrentIndex(self.currentIndex()+1)
+
+    def setCurrentIndex(self, p_int):
+        """
+        Set te current Index of the MultiPage Widget (e.g. set the current page)
+        :param p_int: (int) what page
+        :return: -
+        """
+        if self.currentIndex() >= 0 and p_int <= self.numOfPages:
+            MenuItems.setEnabled(self.pages[self.currentIndex()].name.strip(), False)
+        if p_int > self.numOfPages or p_int < 0:
+            return
+        if p_int <= 0:
+            self.leftright.disable_left()
+        else:
+            self.leftright.enable_left()
+        if p_int >= self.numOfPages:
+            self.leftright.disable_right()
+        else:
+            self.leftright.enable_right()
+        name = self.pages[p_int].name+" " if self.pages[p_int].name else " "
+        self.window().pageIndicator.setText(name+"| "+str(p_int+1)+"/"+str(self.numOfPages+1))
+        super(MultiPage, self).setCurrentIndex(p_int)
+        MenuItems.setEnabled(name.strip(), True)
+        if getattr(self.pages[self.currentIndex()].widget, 'pages_update_function', None) is not None:
+            self.pages[self.currentIndex()].widget.pages_update_function()

+ 12 - 4
base/plotWidget.py

@@ -40,15 +40,20 @@ class ThreadFFT(Thread):
 plotList = [tr("Label", "Heatmap"), tr("Label", "FFT"), tr("Label", "Trains"), tr("Label", "Combined")]
 PlotType = Enum(*[str(i) for i in plotList])
 
-class SubPlotWidget(pg.PlotWidget):
+class SubPlotWidget(pg.GraphicsLayoutWidget):
     def __init__(self):
         super(SubPlotWidget, self).__init__()
         # self.setStyleSheet("border: 5px solid black; margin: 10px;")
         self.plotType = 1
+        self.plotItem = pg.PlotItem()
         self.img = pg.ImageItem()
-        # self.plotItem.setLabel('bottom', 'F', "Hz")
-        # self.plotItem.setLabel('left', 'I', "A")
-        self.plotItem.addItem(self.img)
+        self.hlut = pg.HistogramLUTItem(self.img, fillHistogram=True)
+        self.grl = pg.GradientLegend((10,300), (10,30))
+        self.img.setParentItem(self.grl)
+        # self.plotItem.addItem(self.hlut)
+        self.plotItem.addItem(self.grl)
+        self.addItem(self.plotItem)
+        self.addItem(self.hlut)
         def doNothing(*args):
             pass
         # self.plotItemPlot = pg.ScatterPlotItem(pxMode=True, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 255, 255), size=2)
@@ -85,6 +90,7 @@ class SubPlotWidget(pg.PlotWidget):
     @QtCore.pyqtSlot(np.ndarray, tuple, tuple)
     def plot(self, data, xvalueborders=None, yvalueborders=None, autorange=True):
         if self.plotType == PlotType.FFT or self.plotType == PlotType.Heatmap:
+            self.hlut.show()
             self.parent().max_slider.setMinimum(np.min(data))
             self.parent().max_slider.setMaximum(np.max(data))
             self.parent().low_slider.setMinimum(np.min(data))
@@ -128,6 +134,7 @@ class SubPlotWidget(pg.PlotWidget):
 
         if self.plotType == PlotType.Trains:
             self.img.clear()
+            self.hlut.hide()
             self.plotItemPlotScatter.clear()
             self.plotItemPlotScatter1.clear()
             self.plotItemPlotScatter2.clear()
@@ -136,6 +143,7 @@ class SubPlotWidget(pg.PlotWidget):
             # self.plotItem.getViewBox().autoRange()
         if self.plotType == PlotType.Combined:
             self.img.clear()
+            self.hlut.hide()
             self.plotItemPlot.clear()
             self.plotItemPlotScatter.setData(data[0].transpose())
             self.plotItemPlotScatter.setDownsampling(ds=20)

+ 2 - 0
base/settings.py

@@ -1,6 +1,8 @@
 from PyQt4 import QtGui, QtCore
+
 import kcgwidget as kcgw
 import config
+
 tr = kcgw.tr
 
 class Settings(kcgw.KCGWidgets):

+ 1 - 1
config.py

@@ -8,7 +8,7 @@ For possible config settings check this file or the documentation
 # possible languages:
 # en_GB - English
 # de_DE - German
-language ="en_GB"
+language ="de_DE"
 # ------------[ Default Data Save Location ]-----------
 # default_save_location: use "pwd" for current working
 # directory KCG will always save in a subdirectory to

BIN
icons/KCG_Logo_r.png


+ 1 - 2
kcg.pro

@@ -8,8 +8,7 @@ SOURCES += ./base/kcg.py \
 ./base/simpleWidget.py \
 ./base/groupedelements.py \
 ./base/multiWidget.py \
-./base/controlwidget2.py \
-./base/config.py \
+./config.py \
 ./base/test_groupedObjects.py \
 ./base/plotWidget.py \
 ./base/backend/board.py \

+ 142 - 96
kcg_de.ts

@@ -1,135 +1,154 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE TS>
-<TS version="2.0" language="de_DE">
+<!DOCTYPE TS><TS version="2.0" language="de_DE" sourcelanguage="">
+<context>
+    <name>About</name>
+    <message>
+        <location filename="base/kcg.py" line="242"/>
+        <source>KCG - KAPTURE Control Gui
+
+This is the graphical control interface to the KAPTURE board
+
+KAPTURE - Karlsruhe Pulse-Taking and Ultrafast Readout Electronics
+
+Version: </source>
+        <translation>KCG - KAPTURE Control Gui
+
+Dies ist die Grafische Oberfläche für das KAPTURE Board
+
+KAPTURE - Karlsruhe Pulse-Taking and Ultrafast Readout Electronic
+s
+Version: </translation>
+    </message>
+</context>
 <context>
     <name>Button</name>
     <message>
-        <location filename="base/kcg.py" line="300"/>
+        <location filename="base/kcg.py" line="209"/>
         <source>File</source>
         <translation>Datei</translation>
     </message>
     <message>
-        <location filename="base/kcg.py" line="301"/>
+        <location filename="base/kcg.py" line="210"/>
         <source>Settings</source>
         <translation>Einstellungen</translation>
     </message>
     <message>
-        <location filename="base/kcg.py" line="302"/>
+        <location filename="base/kcg.py" line="211"/>
         <source>Quit</source>
         <translation>Beenden</translation>
     </message>
     <message>
-        <location filename="base/kcg.py" line="306"/>
+        <location filename="base/kcg.py" line="215"/>
         <source>Windows</source>
         <translation>Fenster</translation>
     </message>
     <message>
-        <location filename="base/multiWidget.py" line="68"/>
+        <location filename="base/multiWidget.py" line="56"/>
         <source>New Plot</source>
         <translation>Neuer Plot</translation>
     </message>
     <message>
-        <location filename="base/kcg.py" line="311"/>
+        <location filename="base/kcg.py" line="220"/>
         <source>Acquire</source>
         <translation>Aufnahme</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="711"/>
+        <location filename="base/backendinterface.py" line="718"/>
         <source>Start Acquisition</source>
         <translation>Starte Aufnahme</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="184"/>
+        <location filename="base/backendinterface.py" line="191"/>
         <source>Start Board</source>
         <translation>Starte Board</translation>
     </message>
     <message>
-        <location filename="base/controlwidget.py" line="198"/>
+        <location filename="base/controlwidget.py" line="199"/>
         <source>Calibrate</source>
         <translation>Calibriere</translation>
     </message>
     <message>
-        <location filename="base/controlwidget.py" line="199"/>
+        <location filename="base/controlwidget.py" line="200"/>
         <source>Synchronize</source>
         <translation>Synchronisiere</translation>
     </message>
     <message>
-        <location filename="base/controlwidget.py" line="200"/>
+        <location filename="base/controlwidget.py" line="201"/>
         <source>Set Defaults</source>
         <translation>Setze default Werte</translation>
     </message>
     <message>
-        <location filename="base/controlwidget.py" line="201"/>
+        <location filename="base/controlwidget.py" line="202"/>
         <source>Soft Reset</source>
         <translation>Soft Reset</translation>
     </message>
     <message>
-        <location filename="base/controlwidget.py" line="202"/>
+        <location filename="base/controlwidget.py" line="203"/>
         <source>Board Off</source>
         <translation>Board ausschalten</translation>
     </message>
     <message>
-        <location filename="base/controlwidget.py" line="203"/>
+        <location filename="base/controlwidget.py" line="204"/>
         <source>Prepare Board</source>
         <translation>Board vorbereiten</translation>
     </message>
     <message>
-        <location filename="base/controlwidget.py" line="227"/>
+        <location filename="base/controlwidget.py" line="229"/>
         <source>Check Status</source>
         <translation>Statusüberprüfung</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="159"/>
+        <location filename="base/backendinterface.py" line="166"/>
         <source>Ok</source>
         <translation>OK</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="164"/>
+        <location filename="base/backendinterface.py" line="171"/>
         <source>Cancel</source>
         <translation>Abbrechen</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="199"/>
+        <location filename="base/backendinterface.py" line="206"/>
         <source>Switch On the power supply --&gt; FIRST &lt;--</source>
         <translation>Schalten sie die ERSTE Stroversorgung ein</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="270"/>
+        <location filename="base/backendinterface.py" line="277"/>
         <source>Calibrate Board</source>
         <translation>Calibriere Board</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="723"/>
+        <location filename="base/backendinterface.py" line="730"/>
         <source>Stop Acquisition</source>
         <translation>Stoppe Aufnahme</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="845"/>
+        <location filename="base/backendinterface.py" line="852"/>
         <source>Start time scan</source>
         <translation>Starte timescan</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="864"/>
+        <location filename="base/backendinterface.py" line="871"/>
         <source>Stop time scan</source>
         <translation>Stoppe timescan</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="185"/>
+        <location filename="base/leftbar.py" line="187"/>
         <source>Heatmap</source>
         <translation>Heatmap</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="186"/>
+        <location filename="base/leftbar.py" line="188"/>
         <source>FFT</source>
         <translation>FFT</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="187"/>
+        <location filename="base/leftbar.py" line="189"/>
         <source>Trains</source>
         <translation>Züge</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="188"/>
+        <location filename="base/leftbar.py" line="190"/>
         <source>Combined</source>
         <translation>Kombiniert</translation>
     </message>
@@ -139,27 +158,27 @@
         <translation>Schließen</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="358"/>
+        <location filename="base/leftbar.py" line="372"/>
         <source>Live</source>
         <translation>Live</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="359"/>
+        <location filename="base/leftbar.py" line="373"/>
         <source>Open File</source>
         <translation>Datei öffnen</translation>
     </message>
     <message>
-        <location filename="base/settings.py" line="18"/>
+        <location filename="base/settings.py" line="20"/>
         <source>Header</source>
         <translation>Header</translation>
     </message>
     <message>
-        <location filename="base/settings.py" line="26"/>
+        <location filename="base/settings.py" line="28"/>
         <source>Apply</source>
         <translation>Anwenden</translation>
     </message>
     <message>
-        <location filename="base/settings.py" line="27"/>
+        <location filename="base/settings.py" line="29"/>
         <source>OK</source>
         <translation>OK</translation>
     </message>
@@ -169,17 +188,17 @@
         <translation>Time Scan</translation>
     </message>
     <message>
-        <location filename="widgets/singleread.py" line="29"/>
+        <location filename="widgets/singleread.py" line="28"/>
         <source>Single Read</source>
         <translation>Einzelne Aufnahme</translation>
     </message>
     <message>
-        <location filename="widgets/singleread.py" line="48"/>
+        <location filename="widgets/singleread.py" line="45"/>
         <source>Start Continuous Read</source>
         <translation>Starte kontinuierliches Auslesen</translation>
     </message>
     <message>
-        <location filename="widgets/singleread.py" line="45"/>
+        <location filename="widgets/singleread.py" line="42"/>
         <source>Stop Continuous Read</source>
         <translation>Stoppe kontinuierliches Auslesen</translation>
     </message>
@@ -193,11 +212,26 @@
         <source>Build Spectograms</source>
         <translation>Generiere Spektrogramme</translation>
     </message>
+    <message>
+        <location filename="base/kcg.py" line="232"/>
+        <source>Help</source>
+        <translation>Hilfe</translation>
+    </message>
+    <message>
+        <location filename="base/kcg.py" line="234"/>
+        <source>Open Manual</source>
+        <translation>Öffne Benutzerhandbuch</translation>
+    </message>
+    <message>
+        <location filename="base/kcg.py" line="235"/>
+        <source>About</source>
+        <translation>Über</translation>
+    </message>
 </context>
 <context>
     <name>Dialog</name>
     <message>
-        <location filename="base/kcg.py" line="46"/>
+        <location filename="base/kcg.py" line="65"/>
         <source>Enter a name for the Subdirectory
 in which data will be saved:
 NOTE: You are being asked because it was set this way in the config file.</source>
@@ -207,7 +241,7 @@ HINWEIS: Sie werden gefragt, da dies so in
 der Konfigurations Datei festgelegt wurde.</translation>
     </message>
     <message>
-        <location filename="base/kcg.py" line="60"/>
+        <location filename="base/kcg.py" line="79"/>
         <source>Enter Sessionname
 NOTE: You are being asked because it was set this way in the config file.:</source>
         <translation>Geben sie einen Sitzungsnamen ein.
@@ -215,79 +249,86 @@ HINWEIS: Sie werden gefragt, da dies so in
 der Konfigurations Datei festgelegt wurde.:</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="104"/>
+        <location filename="base/backendinterface.py" line="110"/>
         <source>Continuous read is currently active!
 Stop continuous read and proceed?</source>
         <translation>Kontinuierliche Auslese ist aktiviert.
 Stoppe die kontinuierliche Auslese und fahre fort?</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="147"/>
+        <location filename="base/backendinterface.py" line="154"/>
         <source>User action required</source>
         <translation>Benutzereingabe erforderlich</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="212"/>
+        <location filename="base/backendinterface.py" line="219"/>
         <source>Switch On the power supply --&gt; SECOND &lt;--</source>
         <translation>Schalten sie die ZWEITE Stromversorgung ein</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="432"/>
+        <location filename="base/backendinterface.py" line="439"/>
         <source>Synchronize Board</source>
         <translation>Synchronisiere Board</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="544"/>
+        <location filename="base/backendinterface.py" line="551"/>
         <source>Soft Reset Board</source>
         <translation>Softresette das Board</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="685"/>
+        <location filename="base/backendinterface.py" line="692"/>
         <source>Data is inconsistent!</source>
         <translation>Daten sind Inkonsistent!</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="279"/>
+        <location filename="base/leftbar.py" line="293"/>
         <source>Close this plot source?</source>
         <translation>Diese Datenquelle schließen?</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="304"/>
+        <location filename="base/leftbar.py" line="318"/>
         <source>There are open plot windows.
 Close this plot source and all corresponding plot windows?</source>
         <translation>Es gibt offene Plot Fenster.
 Diese Datenquelle und alle dazugehörigen Plot Fenster schließen?</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="355"/>
+        <location filename="base/leftbar.py" line="369"/>
         <source>Open file from disk or read live data?</source>
         <translation>Datei von der Festplatte öffnen oder live Daten lesen?</translation>
     </message>
+    <message>
+        <location filename="base/kcg.py" line="374"/>
+        <source>Close KCG?
+You will loose the state of open plots etc.</source>
+        <translation>KCG Schließen?
+Sie verlieren den Status von offenen Plot Fenstern etc.</translation>
+    </message>
 </context>
 <context>
     <name>Heading</name>
     <message>
-        <location filename="base/kcg.py" line="46"/>
+        <location filename="base/kcg.py" line="65"/>
         <source>Subdirectory</source>
         <translation>Unterordner</translation>
     </message>
     <message>
-        <location filename="base/kcg.py" line="60"/>
+        <location filename="base/kcg.py" line="79"/>
         <source>Sessionname</source>
         <translation>Sitzungsname</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="279"/>
+        <location filename="base/leftbar.py" line="293"/>
         <source>Close Plot</source>
         <translation>Plot Schließen</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="304"/>
+        <location filename="base/leftbar.py" line="318"/>
         <source>Close Data Source</source>
         <translation>Datenquelle Schließen</translation>
     </message>
     <message>
-        <location filename="base/settings.py" line="61"/>
+        <location filename="base/settings.py" line="63"/>
         <source>KCG - Settings</source>
         <translation>KCG - Einstellungen</translation>
     </message>
@@ -302,27 +343,27 @@ Diese Datenquelle und alle dazugehörigen Plot Fenster schließen?</translation>
         <translation>Timescan Ergebnisse:</translation>
     </message>
     <message>
-        <location filename="widgets/timingWidget.py" line="365"/>
+        <location filename="widgets/timingWidget.py" line="363"/>
         <source>Timing</source>
         <translation>Timing</translation>
     </message>
     <message>
-        <location filename="widgets/timingWidget.py" line="272"/>
+        <location filename="widgets/timingWidget.py" line="271"/>
         <source>Timing result</source>
         <translation>Timing Ergebnis</translation>
     </message>
     <message>
-        <location filename="widgets/singleread.py" line="42"/>
+        <location filename="widgets/singleread.py" line="39"/>
         <source>Single and Continuous Read</source>
         <translation>Einzelnes und kontiniuierliches Auslesen</translation>
     </message>
     <message>
-        <location filename="widgets/acquiresettings.py" line="159"/>
+        <location filename="widgets/acquiresettings.py" line="149"/>
         <source>Acquire Settings</source>
         <translation>Aufnahme Einstellungen</translation>
     </message>
     <message>
-        <location filename="widgets/singleread.py" line="81"/>
+        <location filename="widgets/singleread.py" line="72"/>
         <source>Single Read</source>
         <translation>Einzelne Aufnahme</translation>
     </message>
@@ -341,111 +382,116 @@ Diese Datenquelle und alle dazugehörigen Plot Fenster schließen?</translation>
         <source>Maximum C:{c} F:{f}</source>
         <translation>Maximum G:{c} F:{f}</translation>
     </message>
+    <message>
+        <location filename="base/kcg.py" line="374"/>
+        <source>Close KCG</source>
+        <translation>KCG Schließen</translation>
+    </message>
 </context>
 <context>
     <name>Label</name>
     <message>
-        <location filename="base/controlwidget.py" line="182"/>
+        <location filename="base/controlwidget.py" line="183"/>
         <source>Board Control</source>
         <translation>Board Kontrolle</translation>
     </message>
     <message>
-        <location filename="base/controlwidget.py" line="183"/>
+        <location filename="base/controlwidget.py" line="184"/>
         <source>Detailed Board Control</source>
         <translation>Detaillierte Board Kontrolle</translation>
     </message>
     <message>
-        <location filename="base/controlwidget.py" line="184"/>
+        <location filename="base/controlwidget.py" line="185"/>
         <source>Board Status</source>
         <translation>Board Status</translation>
     </message>
     <message>
-        <location filename="base/controlwidget.py" line="187"/>
+        <location filename="base/controlwidget.py" line="188"/>
         <source>DataFlow Pipeline</source>
         <translation>DataFlow Pipeline</translation>
     </message>
     <message>
-        <location filename="base/controlwidget.py" line="188"/>
+        <location filename="base/controlwidget.py" line="189"/>
         <source>Master Control</source>
         <translation>Master Control</translation>
     </message>
     <message>
-        <location filename="base/controlwidget.py" line="189"/>
+        <location filename="base/controlwidget.py" line="190"/>
         <source>Data Check</source>
         <translation>Daten Check</translation>
     </message>
     <message>
-        <location filename="base/controlwidget.py" line="190"/>
+        <location filename="base/controlwidget.py" line="191"/>
         <source>PLL_LD</source>
         <translation>PLL_LD</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="190"/>
+        <location filename="base/leftbar.py" line="192"/>
         <source>Heatmap</source>
         <translation>Heatmap</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="191"/>
+        <location filename="base/leftbar.py" line="193"/>
         <source>FFT</source>
         <translation>FFT</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="192"/>
+        <location filename="base/leftbar.py" line="194"/>
         <source>Trains</source>
         <translation>Züge</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="193"/>
+        <location filename="base/leftbar.py" line="195"/>
         <source>Combined</source>
         <translation>Kombiniert</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="36"/>
+        <location filename="base/leftbar.py" line="35"/>
         <source>Temp</source>
         <translation>Temp</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="43"/>
+        <location filename="base/leftbar.py" line="42"/>
         <source>O_skip:</source>
         <translation>O_Skip:</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="50"/>
+        <location filename="base/leftbar.py" line="49"/>
         <source>O_obs:</source>
         <translation>O_Beob:</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="57"/>
+        <location filename="base/leftbar.py" line="56"/>
         <source>Count:</source>
         <translation>Anzahl:</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="64"/>
+        <location filename="base/leftbar.py" line="63"/>
         <source>T_wait:</source>
         <translation>T_warte:</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="340"/>
+        <location filename="base/leftbar.py" line="354"/>
         <source>Live</source>
         <translation>Live</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="342"/>
+        <location filename="base/leftbar.py" line="356"/>
         <source>File</source>
         <translation>Datei</translation>
     </message>
     <message>
-        <location filename="base/settings.py" line="48"/>
+        <location filename="base/settings.py" line="50"/>
         <source>Subdirectory Name:</source>
         <translation>Unterordner Name:</translation>
     </message>
     <message>
-        <location filename="base/settings.py" line="50"/>
+        <location filename="base/settings.py" line="52"/>
         <source>Save location:</source>
         <translation>Speicherort:</translation>
     </message>
     <message>
-        <location filename="base/settings.py" line="52"/>
+        <location filename="base/settings.py" line="54"/>
         <source>Language</source>
         <translation>Sprache</translation>
     </message>
@@ -475,12 +521,12 @@ Diese Datenquelle und alle dazugehörigen Plot Fenster schließen?</translation>
         <translation>Feine Verzögerung</translation>
     </message>
     <message>
-        <location filename="widgets/timingWidget.py" line="213"/>
+        <location filename="widgets/timingWidget.py" line="212"/>
         <source>Total Delay</source>
         <translation>Gesamt Verzögerung</translation>
     </message>
     <message>
-        <location filename="widgets/singleread.py" line="40"/>
+        <location filename="widgets/singleread.py" line="37"/>
         <source>Interval:</source>
         <translation>Intervall:</translation>
     </message>
@@ -505,7 +551,7 @@ Diese Datenquelle und alle dazugehörigen Plot Fenster schließen?</translation>
         <translation>Warte (s)</translation>
     </message>
     <message>
-        <location filename="base/settings.py" line="22"/>
+        <location filename="base/settings.py" line="24"/>
         <source>Enable Advanced Table View</source>
         <translation>Aktiviere Erweiterten Register Tabellen Modus</translation>
     </message>
@@ -513,50 +559,50 @@ Diese Datenquelle und alle dazugehörigen Plot Fenster schließen?</translation>
 <context>
     <name>Tooltip</name>
     <message>
-        <location filename="base/leftbar.py" line="37"/>
+        <location filename="base/leftbar.py" line="36"/>
         <source>Skipped orbits
 Klick to open acquire settings</source>
         <translation>Übersprungene Orbits
 Klick um die Aufnahmeeinstellungen zu öffnen</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="44"/>
+        <location filename="base/leftbar.py" line="43"/>
         <source>Number of observed Orbits
 Klick to open acquire settings</source>
         <translation>Anzahl beobachteter Orbits
 Klick um die Aufnahmeeinstellungen zu öffnen</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="51"/>
+        <location filename="base/leftbar.py" line="50"/>
         <source>Number of acquisitions
 Klick to open acquire settings</source>
         <translation>Anzahl der Aufnahmen
 Klick um die Aufnahmeeinstellungen zu öffnen</translation>
     </message>
     <message>
-        <location filename="base/leftbar.py" line="58"/>
+        <location filename="base/leftbar.py" line="57"/>
         <source>Time in seconds to wait between acquisitions
 Klick to open acquire settings</source>
         <translation>Zeit in Sekunden, zwischen Aufnahmen
 Klick um die Aufnahmeeinstellungen zu öffnen</translation>
     </message>
     <message>
-        <location filename="base/settings.py" line="42"/>
+        <location filename="base/settings.py" line="44"/>
         <source>Save header in output file</source>
         <translation>Speichere Header in ausgabe Datei</translation>
     </message>
     <message>
-        <location filename="base/settings.py" line="43"/>
+        <location filename="base/settings.py" line="45"/>
         <source>Save settings</source>
         <translation>Speichere Einstellungen</translation>
     </message>
     <message>
-        <location filename="base/settings.py" line="44"/>
+        <location filename="base/settings.py" line="46"/>
         <source>Save settings and close settings-window</source>
         <translation>Speichere Einstellungen und schließe Einstellungsfenster</translation>
     </message>
     <message>
-        <location filename="base/settings.py" line="45"/>
+        <location filename="base/settings.py" line="47"/>
         <source>Discard changes and close settings-window</source>
         <translation>Verwerve Änderungen und schließe Einstellungsfenster</translation>
     </message>
@@ -569,37 +615,37 @@ Klick um die Aufnahmeeinstellungen zu öffnen</translation>
 <context>
     <name>sw</name>
     <message>
-        <location filename="base/kcg.py" line="377"/>
+        <location filename="base/kcg.py" line="330"/>
         <source>Board not connected</source>
         <translation>Kein Board verbunden</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="41"/>
+        <location filename="base/backendinterface.py" line="43"/>
         <source>Ready</source>
         <translation>Fertig</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="273"/>
+        <location filename="base/backendinterface.py" line="280"/>
         <source>Calibrating</source>
         <translation>Kalibriere</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="406"/>
+        <location filename="base/backendinterface.py" line="413"/>
         <source>Synchronizing</source>
         <translation>Synchronisiere</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="437"/>
+        <location filename="base/backendinterface.py" line="444"/>
         <source>Setting Defaults</source>
         <translation>Setze Default Werte</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="726"/>
+        <location filename="base/backendinterface.py" line="733"/>
         <source>Acquiring</source>
         <translation>Nehme auf</translation>
     </message>
     <message>
-        <location filename="base/backendinterface.py" line="988"/>
+        <location filename="base/backendinterface.py" line="995"/>
         <source>Coarserange:{c_f}-{c_t} ; Finerange:{f_f}-{f_t}</source>
         <translation>Groberbereich:{c_f}-{c_t} ; Feinerbereich:{f_f}-{f_t}</translation>
     </message>

+ 607 - 0
kcg_de.ts_backup

@@ -0,0 +1,607 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="de_DE">
+<context>
+    <name>Button</name>
+    <message>
+        <location filename="base/kcg.py" line="300"/>
+        <source>File</source>
+        <translation>Datei</translation>
+    </message>
+    <message>
+        <location filename="base/kcg.py" line="301"/>
+        <source>Settings</source>
+        <translation>Einstellungen</translation>
+    </message>
+    <message>
+        <location filename="base/kcg.py" line="302"/>
+        <source>Quit</source>
+        <translation>Beenden</translation>
+    </message>
+    <message>
+        <location filename="base/kcg.py" line="306"/>
+        <source>Windows</source>
+        <translation>Fenster</translation>
+    </message>
+    <message>
+        <location filename="base/multiWidget.py" line="68"/>
+        <source>New Plot</source>
+        <translation>Neuer Plot</translation>
+    </message>
+    <message>
+        <location filename="base/kcg.py" line="311"/>
+        <source>Acquire</source>
+        <translation>Aufnahme</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="711"/>
+        <source>Start Acquisition</source>
+        <translation>Starte Aufnahme</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="184"/>
+        <source>Start Board</source>
+        <translation>Starte Board</translation>
+    </message>
+    <message>
+        <location filename="base/controlwidget.py" line="198"/>
+        <source>Calibrate</source>
+        <translation>Calibriere</translation>
+    </message>
+    <message>
+        <location filename="base/controlwidget.py" line="199"/>
+        <source>Synchronize</source>
+        <translation>Synchronisiere</translation>
+    </message>
+    <message>
+        <location filename="base/controlwidget.py" line="200"/>
+        <source>Set Defaults</source>
+        <translation>Setze default Werte</translation>
+    </message>
+    <message>
+        <location filename="base/controlwidget.py" line="201"/>
+        <source>Soft Reset</source>
+        <translation>Soft Reset</translation>
+    </message>
+    <message>
+        <location filename="base/controlwidget.py" line="202"/>
+        <source>Board Off</source>
+        <translation>Board ausschalten</translation>
+    </message>
+    <message>
+        <location filename="base/controlwidget.py" line="203"/>
+        <source>Prepare Board</source>
+        <translation>Board vorbereiten</translation>
+    </message>
+    <message>
+        <location filename="base/controlwidget.py" line="227"/>
+        <source>Check Status</source>
+        <translation>Statusüberprüfung</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="159"/>
+        <source>Ok</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="164"/>
+        <source>Cancel</source>
+        <translation>Abbrechen</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="199"/>
+        <source>Switch On the power supply --&gt; FIRST &lt;--</source>
+        <translation>Schalten sie die ERSTE Stroversorgung ein</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="270"/>
+        <source>Calibrate Board</source>
+        <translation>Calibriere Board</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="723"/>
+        <source>Stop Acquisition</source>
+        <translation>Stoppe Aufnahme</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="845"/>
+        <source>Start time scan</source>
+        <translation>Starte timescan</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="864"/>
+        <source>Stop time scan</source>
+        <translation>Stoppe timescan</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="185"/>
+        <source>Heatmap</source>
+        <translation>Heatmap</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="186"/>
+        <source>FFT</source>
+        <translation>FFT</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="187"/>
+        <source>Trains</source>
+        <translation>Züge</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="188"/>
+        <source>Combined</source>
+        <translation>Kombiniert</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="163"/>
+        <source>Close</source>
+        <translation>Schließen</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="358"/>
+        <source>Live</source>
+        <translation>Live</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="359"/>
+        <source>Open File</source>
+        <translation>Datei öffnen</translation>
+    </message>
+    <message>
+        <location filename="base/settings.py" line="18"/>
+        <source>Header</source>
+        <translation>Header</translation>
+    </message>
+    <message>
+        <location filename="base/settings.py" line="26"/>
+        <source>Apply</source>
+        <translation>Anwenden</translation>
+    </message>
+    <message>
+        <location filename="base/settings.py" line="27"/>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="189"/>
+        <source>Time Scan</source>
+        <translation>Time Scan</translation>
+    </message>
+    <message>
+        <location filename="widgets/singleread.py" line="29"/>
+        <source>Single Read</source>
+        <translation>Einzelne Aufnahme</translation>
+    </message>
+    <message>
+        <location filename="widgets/singleread.py" line="48"/>
+        <source>Start Continuous Read</source>
+        <translation>Starte kontinuierliches Auslesen</translation>
+    </message>
+    <message>
+        <location filename="widgets/singleread.py" line="45"/>
+        <source>Stop Continuous Read</source>
+        <translation>Stoppe kontinuierliches Auslesen</translation>
+    </message>
+    <message>
+        <location filename="widgets/acquiresettings.py" line="35"/>
+        <source>Simulate Pilot Bunch</source>
+        <translation>Simuliere Pilot Bunch</translation>
+    </message>
+    <message>
+        <location filename="widgets/acquiresettings.py" line="36"/>
+        <source>Build Spectograms</source>
+        <translation>Generiere Spektrogramme</translation>
+    </message>
+</context>
+<context>
+    <name>Dialog</name>
+    <message>
+        <location filename="base/kcg.py" line="46"/>
+        <source>Enter a name for the Subdirectory
+in which data will be saved:
+NOTE: You are being asked because it was set this way in the config file.</source>
+        <translation>Geben sie den Namen des Unterordners,
+in dem die Daten gespeichert werden sollen ein.
+HINWEIS: Sie werden gefragt, da dies so in 
+der Konfigurations Datei festgelegt wurde.</translation>
+    </message>
+    <message>
+        <location filename="base/kcg.py" line="60"/>
+        <source>Enter Sessionname
+NOTE: You are being asked because it was set this way in the config file.:</source>
+        <translation>Geben sie einen Sitzungsnamen ein.
+HINWEIS: Sie werden gefragt, da dies so in 
+der Konfigurations Datei festgelegt wurde.:</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="104"/>
+        <source>Continuous read is currently active!
+Stop continuous read and proceed?</source>
+        <translation>Kontinuierliche Auslese ist aktiviert.
+Stoppe die kontinuierliche Auslese und fahre fort?</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="147"/>
+        <source>User action required</source>
+        <translation>Benutzereingabe erforderlich</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="212"/>
+        <source>Switch On the power supply --&gt; SECOND &lt;--</source>
+        <translation>Schalten sie die ZWEITE Stromversorgung ein</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="432"/>
+        <source>Synchronize Board</source>
+        <translation>Synchronisiere Board</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="544"/>
+        <source>Soft Reset Board</source>
+        <translation>Softresette das Board</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="685"/>
+        <source>Data is inconsistent!</source>
+        <translation>Daten sind Inkonsistent!</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="279"/>
+        <source>Close this plot source?</source>
+        <translation>Diese Datenquelle schließen?</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="304"/>
+        <source>There are open plot windows.
+Close this plot source and all corresponding plot windows?</source>
+        <translation>Es gibt offene Plot Fenster.
+Diese Datenquelle und alle dazugehörigen Plot Fenster schließen?</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="355"/>
+        <source>Open file from disk or read live data?</source>
+        <translation>Datei von der Festplatte öffnen oder live Daten lesen?</translation>
+    </message>
+</context>
+<context>
+    <name>Heading</name>
+    <message>
+        <location filename="base/kcg.py" line="46"/>
+        <source>Subdirectory</source>
+        <translation>Unterordner</translation>
+    </message>
+    <message>
+        <location filename="base/kcg.py" line="60"/>
+        <source>Sessionname</source>
+        <translation>Sitzungsname</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="279"/>
+        <source>Close Plot</source>
+        <translation>Plot Schließen</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="304"/>
+        <source>Close Data Source</source>
+        <translation>Datenquelle Schließen</translation>
+    </message>
+    <message>
+        <location filename="base/settings.py" line="61"/>
+        <source>KCG - Settings</source>
+        <translation>KCG - Einstellungen</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="73"/>
+        <source>Timescan Results</source>
+        <translation>Timescan Ergebnisse</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="119"/>
+        <source>Timescan Result:</source>
+        <translation>Timescan Ergebnisse:</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="365"/>
+        <source>Timing</source>
+        <translation>Timing</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="272"/>
+        <source>Timing result</source>
+        <translation>Timing Ergebnis</translation>
+    </message>
+    <message>
+        <location filename="widgets/singleread.py" line="42"/>
+        <source>Single and Continuous Read</source>
+        <translation>Einzelnes und kontiniuierliches Auslesen</translation>
+    </message>
+    <message>
+        <location filename="widgets/acquiresettings.py" line="159"/>
+        <source>Acquire Settings</source>
+        <translation>Aufnahme Einstellungen</translation>
+    </message>
+    <message>
+        <location filename="widgets/singleread.py" line="81"/>
+        <source>Single Read</source>
+        <translation>Einzelne Aufnahme</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="48"/>
+        <source>Coarse delay</source>
+        <translation>Grobe Verzögerung</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="49"/>
+        <source>Fine delay</source>
+        <translation>Feine Verzögerung</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="125"/>
+        <source>Maximum C:{c} F:{f}</source>
+        <translation>Maximum G:{c} F:{f}</translation>
+    </message>
+</context>
+<context>
+    <name>Label</name>
+    <message>
+        <location filename="base/controlwidget.py" line="182"/>
+        <source>Board Control</source>
+        <translation>Board Kontrolle</translation>
+    </message>
+    <message>
+        <location filename="base/controlwidget.py" line="183"/>
+        <source>Detailed Board Control</source>
+        <translation>Detaillierte Board Kontrolle</translation>
+    </message>
+    <message>
+        <location filename="base/controlwidget.py" line="184"/>
+        <source>Board Status</source>
+        <translation>Board Status</translation>
+    </message>
+    <message>
+        <location filename="base/controlwidget.py" line="187"/>
+        <source>DataFlow Pipeline</source>
+        <translation>DataFlow Pipeline</translation>
+    </message>
+    <message>
+        <location filename="base/controlwidget.py" line="188"/>
+        <source>Master Control</source>
+        <translation>Master Control</translation>
+    </message>
+    <message>
+        <location filename="base/controlwidget.py" line="189"/>
+        <source>Data Check</source>
+        <translation>Daten Check</translation>
+    </message>
+    <message>
+        <location filename="base/controlwidget.py" line="190"/>
+        <source>PLL_LD</source>
+        <translation>PLL_LD</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="190"/>
+        <source>Heatmap</source>
+        <translation>Heatmap</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="191"/>
+        <source>FFT</source>
+        <translation>FFT</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="192"/>
+        <source>Trains</source>
+        <translation>Züge</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="193"/>
+        <source>Combined</source>
+        <translation>Kombiniert</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="36"/>
+        <source>Temp</source>
+        <translation>Temp</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="43"/>
+        <source>O_skip:</source>
+        <translation>O_Skip:</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="50"/>
+        <source>O_obs:</source>
+        <translation>O_Beob:</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="57"/>
+        <source>Count:</source>
+        <translation>Anzahl:</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="64"/>
+        <source>T_wait:</source>
+        <translation>T_warte:</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="340"/>
+        <source>Live</source>
+        <translation>Live</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="342"/>
+        <source>File</source>
+        <translation>Datei</translation>
+    </message>
+    <message>
+        <location filename="base/settings.py" line="48"/>
+        <source>Subdirectory Name:</source>
+        <translation>Unterordner Name:</translation>
+    </message>
+    <message>
+        <location filename="base/settings.py" line="50"/>
+        <source>Save location:</source>
+        <translation>Speicherort:</translation>
+    </message>
+    <message>
+        <location filename="base/settings.py" line="52"/>
+        <source>Language</source>
+        <translation>Sprache</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="151"/>
+        <source>Coarse scan range</source>
+        <translation>Grober Scanbereich</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="152"/>
+        <source>Fine scan range</source>
+        <translation>Feiner Scanbereich</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="178"/>
+        <source>T/H Delay</source>
+        <translation>T/H Verzögerung</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="179"/>
+        <source>Coarse Delay</source>
+        <translation>Grobe Verzögerung</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="182"/>
+        <source>Fine Delay</source>
+        <translation>Feine Verzögerung</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="213"/>
+        <source>Total Delay</source>
+        <translation>Gesamt Verzögerung</translation>
+    </message>
+    <message>
+        <location filename="widgets/singleread.py" line="40"/>
+        <source>Interval:</source>
+        <translation>Intervall:</translation>
+    </message>
+    <message>
+        <location filename="widgets/acquiresettings.py" line="27"/>
+        <source>Number of orbits to observe</source>
+        <translation>Anzahl beobachteter Orbits</translation>
+    </message>
+    <message>
+        <location filename="widgets/acquiresettings.py" line="28"/>
+        <source>Number os orbits to skip</source>
+        <translation>Anzahl übersprungener Orbits</translation>
+    </message>
+    <message>
+        <location filename="widgets/acquiresettings.py" line="31"/>
+        <source>Count</source>
+        <translation>Anzahl</translation>
+    </message>
+    <message>
+        <location filename="widgets/acquiresettings.py" line="33"/>
+        <source>Wait(s)</source>
+        <translation>Warte (s)</translation>
+    </message>
+    <message>
+        <location filename="base/settings.py" line="22"/>
+        <source>Enable Advanced Table View</source>
+        <translation>Aktiviere Erweiterten Register Tabellen Modus</translation>
+    </message>
+</context>
+<context>
+    <name>Tooltip</name>
+    <message>
+        <location filename="base/leftbar.py" line="37"/>
+        <source>Skipped orbits
+Klick to open acquire settings</source>
+        <translation>Übersprungene Orbits
+Klick um die Aufnahmeeinstellungen zu öffnen</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="44"/>
+        <source>Number of observed Orbits
+Klick to open acquire settings</source>
+        <translation>Anzahl beobachteter Orbits
+Klick um die Aufnahmeeinstellungen zu öffnen</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="51"/>
+        <source>Number of acquisitions
+Klick to open acquire settings</source>
+        <translation>Anzahl der Aufnahmen
+Klick um die Aufnahmeeinstellungen zu öffnen</translation>
+    </message>
+    <message>
+        <location filename="base/leftbar.py" line="58"/>
+        <source>Time in seconds to wait between acquisitions
+Klick to open acquire settings</source>
+        <translation>Zeit in Sekunden, zwischen Aufnahmen
+Klick um die Aufnahmeeinstellungen zu öffnen</translation>
+    </message>
+    <message>
+        <location filename="base/settings.py" line="42"/>
+        <source>Save header in output file</source>
+        <translation>Speichere Header in ausgabe Datei</translation>
+    </message>
+    <message>
+        <location filename="base/settings.py" line="43"/>
+        <source>Save settings</source>
+        <translation>Speichere Einstellungen</translation>
+    </message>
+    <message>
+        <location filename="base/settings.py" line="44"/>
+        <source>Save settings and close settings-window</source>
+        <translation>Speichere Einstellungen und schließe Einstellungsfenster</translation>
+    </message>
+    <message>
+        <location filename="base/settings.py" line="45"/>
+        <source>Discard changes and close settings-window</source>
+        <translation>Verwerve Änderungen und schließe Einstellungsfenster</translation>
+    </message>
+    <message>
+        <location filename="widgets/timingWidget.py" line="189"/>
+        <source>Show time scan part</source>
+        <translation>Zeige Time Scan Abschnitt</translation>
+    </message>
+</context>
+<context>
+    <name>sw</name>
+    <message>
+        <location filename="base/kcg.py" line="377"/>
+        <source>Board not connected</source>
+        <translation>Kein Board verbunden</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="41"/>
+        <source>Ready</source>
+        <translation>Fertig</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="273"/>
+        <source>Calibrating</source>
+        <translation>Kalibriere</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="406"/>
+        <source>Synchronizing</source>
+        <translation>Synchronisiere</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="437"/>
+        <source>Setting Defaults</source>
+        <translation>Setze Default Werte</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="726"/>
+        <source>Acquiring</source>
+        <translation>Nehme auf</translation>
+    </message>
+    <message>
+        <location filename="base/backendinterface.py" line="988"/>
+        <source>Coarserange:{c_f}-{c_t} ; Finerange:{f_f}-{f_t}</source>
+        <translation>Groberbereich:{c_f}-{c_t} ; Feinerbereich:{f_f}-{f_t}</translation>
+    </message>
+</context>
+</TS>

+ 39 - 0
kcg_remote_client.py

@@ -0,0 +1,39 @@
+import socket
+import argparse as ap
+import readline
+
+
+def connect(host, port):
+    soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    soc.connect((host, port))
+    return soc
+
+def send(string, host, port):
+    soc = connect(host, port)
+    soc.send(string)
+    while True:
+        try:
+            soc.settimeout(20)
+            res = soc.recv(1024)
+            if '.' == res[0]:
+                print res[1:]
+            else:
+                print res
+                return
+        except socket.timeout:
+            print "Timed Out"
+            return
+
+def main():
+    parse = ap.ArgumentParser("Remote Client for KCG - KAPTURE Control Gui")
+    parse.add_argument("--port", "-p", type=int, help="Port")
+    parse.add_argument("--host", "-H", type=str, help="Host")
+    args = parse.parse_args()
+
+    input = None
+    while input != "stop":
+        input = raw_input("KCG > ")
+        send(input, args.host, args.port)
+
+if __name__ == '__main__':
+    main()

BIN
lang/de_DE.qm


+ 1 - 1
widgets/__init__.py

@@ -1 +1 @@
-__all__ = ['acquiresettings', 'singleread', 'timingWidget'] #, 'example_widget']
+__all__ = ['acquiresettings', 'singleread', 'timingWidget', 'remote'] #, 'example_widget']

+ 5 - 5
widgets/acquiresettings.py

@@ -1,12 +1,12 @@
-from PyQt4 import QtGui, QtCore
+import sys
+
+from PyQt4 import QtGui
 
 import base.kcgwidget as kcgw
-import logging
-import sys
 from base.backend import board
 bif = sys.modules["base.backendinterface"] # reuse backendinterfacemodule since importing at this point will result in an error
-from base.groupedelements import Buttons, Checkboxes, MenuItems, Elements
-import base.config as config
+from base.groupedelements import Elements
+import config
 tr = kcgw.tr
 
 __widget_id__ = None

+ 1 - 0
widgets/example_widget.py

@@ -1,5 +1,6 @@
 from PyQt4 import QtGui
 
+
 import base.kcgwidget as kcgw
 
 __widget_id__ = None

+ 225 - 0
widgets/remote.py

@@ -0,0 +1,225 @@
+from PyQt4 import QtGui, QtCore
+import socket
+import multiprocessing as mp
+import base.kcgwidget as kcgw
+import base.backendinterface as bif
+from base.backend import board
+from base.groupedelements import Elements
+from base import storage
+
+import time
+
+
+__widget_id__ = None
+
+class Remote(kcgw.KCGWidgets):
+    response = QtCore.pyqtSignal(str)
+    def __init__(self, unique_id, parent):
+        super(Remote, self).__init__()
+
+        self.id = unique_id
+        self.par = parent
+
+        self.status = False
+        self.host = '0.0.0.0'
+
+        self.layout = QtGui.QGridLayout()
+        self.setLayout(self.layout)
+        self.start_stop_button = self.createButton("Start Remote Control", connect=self.start_stop)
+        self.port = self.createSpinbox(1024, 65000, interval=1, start_value=1330)
+        self.port_label = self.createLabel("Port")
+        self.layout.addWidget(self.port_label, 0, 0)
+        self.layout.addWidget(self.port, 0, 1)
+        self.layout.addWidget(self.start_stop_button, 1, 1)
+
+        self.rl = RemoteListener(self.host, self.port.value(), parent=self)
+        self.rl.command_received.connect(self.evaluate)
+        self.response.connect(self.rl.response)
+
+        self.commands = {
+            'calibrate': [["after_start"], bif.bk_calibrate],
+            'sync': [["after_start", "synchronize"], bif.bk_sync_board],
+            'set_defaults': [['after_start', 'set_defaults'], bif.bk_set_defaults],
+            'soft_reset': [['after_start'], bif.bk_soft_reset]
+        }
+        self.value_types = {
+            'fpga_delay_max': int,
+            'fpga_delay': int,
+            'fpga_delay_factor': int,
+            'chip_delay_max': int,
+            'chip_1_delay': int,
+            'chip_2_delay': int,
+            'chip_3_delay': int,
+            'chip_4_delay': int,
+            'chip_delay_factor': int,
+            'th_delay_max': int,
+            'th_delay': int,
+            'th_delay_factor': int,
+            'adc_delay_max': int,
+            'adc_1_delay': int,
+            'adc_2_delay': int,
+            'adc_3_delay': int,
+            'adc_4_delay': int,
+            'adc_delay_factor': int,
+            'th_to_adc_cycles': int,
+            'adc_1_delay_individual': int,
+            'orbits_observe': int,
+            'orbits_skip': int,
+            'orbits_count': int,
+            'orbits_wait_time': int,
+            'build_spectrograms': bool,
+            'pilot_bunch': bool,
+            'header': bool
+        }
+
+    def is_possible(self, groups):
+        for group in groups:
+            if not Elements.isEnabled(group):
+                return False
+        return True
+
+    @QtCore.pyqtSlot(str)
+    def evaluate(self, command):
+        c = str(command).split(" ")
+        try:
+            if c[0] == 'acquire':
+                if self.is_possible(["acquireTrigger"]):
+                    bif.bk_acquire()
+                    if board.status.acquisition:
+                        self.response.emit("Acquisition started - Check status using 'get status'")
+                    else:
+                        self.response.emit("Acquisition stopped")
+                else:
+                    self.response.emit("Not Possible")
+
+
+            if c[0] in self.commands:
+                if self.is_possible(self.commands[c[0]][0]):
+                    self.response.emit(".Processing")
+                    self.commands[c[0]][1]()
+                    self.response.emit("Success")
+                else:
+                    self.response.emit("Not Possible")
+            if c[0] == 'set': #  set values in board.config
+                board.config.update(c[1], self.value_types[c[1]](c[2]))
+                print 'setting', c[1], 'to', c[2]
+                self.response.emit("Success")
+            if c[0] == 'get':  # get values from board.config
+                if c[1] == 'status':
+                    if board.status.acquisition:
+                        perc = int(board.acquisition_progressbar.value() / float(
+                                                                     board.acquisition_progressbar.maximum() -
+                                                                     board.acquisition_progressbar.minimum()) * 100)
+                        perc = str(perc) + "%"
+                    else:
+                        perc = "No Acquisition"
+                    self.response.emit(str(perc))
+                elif c[1] == 'all_acquisition': # get all values important for acquisition
+                    resp = "Orbits Observed: " + str(board.config.get("orbits_observe")) + "\n" + \
+                           "Orbits Skipped: " + str(board.config.get("orbits_skip")) + "\n" + \
+                           "Count: " + str(board.config.get("orbits_count")) + "\n" + \
+                           "Wait Time: " + str(board.config.get("orbits_wait_time")) + "\n" + \
+                           "Pilot Bunch Simulator: " + str(board.config.get("pilot_bunch")) + "\n" + \
+                           "Header: " + str(board.config.get("header"))
+                    self.response.emit(resp)
+                else:
+                    self.response.emit(str(board.config.get(c[1])))
+
+        except Exception, e:
+            self.response.emit("Failed \n"+str(e))
+
+
+    def start_stop(self):
+        self.status = not self.status
+        self.rl.status = self.status
+        if not self.status:
+            self.listen_process.terminate()
+            self.start_stop_button.setText("Start Remote Control")
+            del self.listen_process
+        else:
+            # self.listen_process = mp.Process(target=self.rl.listener)
+            self.listen_process = QtCore.QThread()
+            self.rl.moveToThread(self.listen_process)
+            self.listen_process.started.connect(self.rl.listener)
+            self.listen_process.start()
+            self.start_stop_button.setText("Stop Remote Control")
+
+    def closeEvent(self, event):
+        global __widget_id__
+        __widget_id__ = None
+        del self.par.widgets[self.id]
+
+def addRemoteWidget():
+    global __widget_id__
+    if __widget_id__:
+        kcgw.area.widgets[__widget_id__].setFocus()
+    else:
+        nid = kcgw.idg.genid()
+        __widget_id__ = nid
+        w = Remote(nid, kcgw.area)
+        kcgw.area.newWidget(w, "Remote Widget", nid, widget_type=4, minSize=True)
+
+kcgw.register_widget(QtGui.QIcon("icons/project.svg"), "Remote Widget", addRemoteWidget, "Ctrl+r")
+
+class RemoteListener(QtCore.QObject):
+    command_received = QtCore.pyqtSignal(str)
+
+    def __init__(self, host, port, parent=None):
+        super(RemoteListener, self).__init__()
+        self.host = host
+        self.port = port
+        self.parent = parent
+        self.status = True
+        self.soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        self.soc.bind((self.host, self.port))
+        self.soc.listen(0)
+        self.response_text = None
+
+    def evaluate(self, command):
+        self.command_received.emit(command)
+
+    def listener(self):
+
+        # conn, addr = soc.accept()
+        while self.status:
+            try:
+                conn, addr = self.soc.accept()
+                command = conn.recv(1024)
+                if not command: continue
+                if command == "stop":
+                    break
+                self.evaluate(command)
+                # while True:
+                #     if self.response:
+                #         self.soc.send(self.response)
+                #     else:
+                #         time.sleep(0.01)
+                self.wait_signal(self.parent.response, 2000)
+                if self.response_text:
+                    while self.response_text[0] == '.':
+                        conn.send(self.response_text)
+                        self.wait_signal(self.parent.response, 2000)
+                    conn.send(self.response_text)
+                else:
+                    conn.send("Failed")
+
+                self.response_text = None
+
+                conn.close()
+            except socket.error:  # Go on even in case of exception
+                pass
+        conn.close()
+
+    def response(self, res):
+        self.response_text = res
+
+    def wait_signal(self, signal, timeout=10000):
+        """Block loop until signal emitted, or timeout (ms) elapses."""
+        loop = QtCore.QEventLoop()
+        signal.connect(loop.quit)
+
+        if timeout is not None:
+            QtCore.QTimer.singleShot(timeout, loop.quit)
+        loop.exec_()
+

+ 6 - 8
widgets/singleread.py

@@ -1,12 +1,10 @@
 # -*- coding: utf-8 -*-
-from PyQt4 import QtGui, QtCore
-import logging
+from PyQt4 import QtGui
 
 import base.kcgwidget as kcgw
-from base.backend import board
 import base.backendinterface as bif
-from base.groupedelements import Buttons, Checkboxes, MenuItems, Elements
-import base.config as config
+from base.groupedelements import Elements
+import config
 
 tr = kcgw.tr
 
@@ -35,9 +33,9 @@ class singleReadWidget(kcgw.KCGWidgets):
 
         #--------[ Fill Grid ]----------------
         self.layout.addWidget(self.single_read_button, 0, 0)
-        self.layout.addWidget(self.continuous_read_button, 1, 0)
-        self.layout.addWidget(self.createLabel(tr("Label", "Interval:") + " (ms)"))
-        self.layout.addWidget(self.interval_spinbox, 2, 1)
+        self.layout.addWidget(self.continuous_read_button, 0, 1)
+        self.layout.addWidget(self.createLabel(tr("Label", "Interval:") + " (ms)"), 1, 0)
+        self.layout.addWidget(self.interval_spinbox, 1, 1)
         self.setWindowTitle(tr("Heading", "Single and Continuous Read"))
     def on_continuous_read(self):
         if not self.continuous_read:

+ 7 - 7
widgets/timingWidget.py

@@ -1,14 +1,14 @@
-from PyQt4 import QtGui, QtCore
-
 import logging
 
+from PyQt4 import QtGui, QtCore
+import pyqtgraph as pg
+import numpy as np
+
 import base.kcgwidget as kcgw
 from base.backend import board
 import base.backendinterface as bif
-from base.groupedelements import Buttons, Checkboxes, MenuItems, Elements
-import base.config as config
-import pyqtgraph as pg
-import numpy as np
+from base.groupedelements import Elements
+import config
 
 tr = kcgw.tr
 
@@ -310,7 +310,7 @@ class timingWidget(kcgw.KCGWidgets):
         global __widget_id__
         __widget_id__ = None
         del self.par.widgets[self.id]
-        Elements.removeGroup('timing')
+        Elements.emptyGroup('timing')
         board.config.unobserve(self.fineAdc1Input, 'chip_1_delay')
         board.config.unobserve(self.fineAdc2Input, 'chip_2_delay')
         board.config.unobserve(self.fineAdc3Input, 'chip_3_delay')