Browse Source

last update

NOTE: Trigger Acquirement with second method doesn't work every second
run
Patrick Schreiber 8 years ago
parent
commit
fa5287c315
74 changed files with 4583 additions and 128 deletions
  1. 13 0
      KCG/Documentation/source/Dev/code/__init__.rst
  2. 15 0
      KCG/Documentation/source/Dev/code/base/__init__.rst
  3. 13 0
      KCG/Documentation/source/Dev/code/base/backend/__init__.rst
  4. 15 0
      KCG/Documentation/source/Dev/code/base/backend/board/__init__.rst
  5. 74 0
      KCG/Documentation/source/Dev/code/base/backend/board/actions.rst
  6. 167 0
      KCG/Documentation/source/Dev/code/base/backend/board/board_config.rst
  7. 87 0
      KCG/Documentation/source/Dev/code/base/backend/board/boards_connected.rst
  8. 106 0
      KCG/Documentation/source/Dev/code/base/backend/board/communication.rst
  9. 36 0
      KCG/Documentation/source/Dev/code/base/backend/board/errors.rst
  10. 21 0
      KCG/Documentation/source/Dev/code/base/backend/board/index.rst
  11. 36 0
      KCG/Documentation/source/Dev/code/base/backend/board/sequences.rst
  12. 23 0
      KCG/Documentation/source/Dev/code/base/backend/board/status.rst
  13. 72 0
      KCG/Documentation/source/Dev/code/base/backend/board/utils.rst
  14. 54 0
      KCG/Documentation/source/Dev/code/base/backend/dataset.rst
  15. 17 0
      KCG/Documentation/source/Dev/code/base/backend/index.rst
  16. 50 0
      KCG/Documentation/source/Dev/code/base/backend/io.rst
  17. 390 0
      KCG/Documentation/source/Dev/code/base/backendinterface.rst
  18. 116 0
      KCG/Documentation/source/Dev/code/base/bitsTable.rst
  19. 72 0
      KCG/Documentation/source/Dev/code/base/callbacks.rst
  20. 127 0
      KCG/Documentation/source/Dev/code/base/controlwidget.rst
  21. 36 0
      KCG/Documentation/source/Dev/code/base/globals.rst
  22. 150 0
      KCG/Documentation/source/Dev/code/base/groupedelements.rst
  23. 30 0
      KCG/Documentation/source/Dev/code/base/index.rst
  24. 124 0
      KCG/Documentation/source/Dev/code/base/kcg.rst
  25. 392 0
      KCG/Documentation/source/Dev/code/base/kcgwidget.rst
  26. 172 0
      KCG/Documentation/source/Dev/code/base/leftbar.rst
  27. 111 0
      KCG/Documentation/source/Dev/code/base/log.rst
  28. 69 0
      KCG/Documentation/source/Dev/code/base/loghandler.rst
  29. 64 0
      KCG/Documentation/source/Dev/code/base/multiWidget.rst
  30. 106 0
      KCG/Documentation/source/Dev/code/base/multipage.rst
  31. 220 0
      KCG/Documentation/source/Dev/code/base/plotWidget.rst
  32. 72 0
      KCG/Documentation/source/Dev/code/base/settings.rst
  33. 112 0
      KCG/Documentation/source/Dev/code/base/storage.rst
  34. 78 0
      KCG/Documentation/source/Dev/code/config.rst
  35. 21 0
      KCG/Documentation/source/Dev/code/index.rst
  36. 44 0
      KCG/Documentation/source/Dev/code/kcg.rst
  37. 15 0
      KCG/Documentation/source/Dev/code/setup.rst
  38. 15 0
      KCG/Documentation/source/Dev/code/widgets/__init__.rst
  39. 145 0
      KCG/Documentation/source/Dev/code/widgets/acquiresettings.rst
  40. 30 0
      KCG/Documentation/source/Dev/code/widgets/example_widget.rst
  41. 18 0
      KCG/Documentation/source/Dev/code/widgets/index.rst
  42. 80 0
      KCG/Documentation/source/Dev/code/widgets/initialconfig.rst
  43. 55 0
      KCG/Documentation/source/Dev/code/widgets/singleread.rst
  44. 169 0
      KCG/Documentation/source/Dev/code/widgets/timingWidget.rst
  45. 1 5
      KCG/Documentation/source/Dev/index.rst
  46. 2 0
      KCG/Documentation/source/Man/index.rst
  47. 2 2
      KCG/Documentation/source/conf.py
  48. 4 2
      KCG/Documentation/source/index.rst
  49. 1 1
      KCG/VERSION
  50. 42 1
      KCG/base/backend/board/actions.py
  51. 103 0
      KCG/base/backend/board/board_config.py
  52. 13 2
      KCG/base/backend/board/boards_connected.py
  53. 15 6
      KCG/base/backend/board/communication.py
  54. 15 0
      KCG/base/backend/board/errors.py
  55. 12 0
      KCG/base/backend/board/sequences.py
  56. 33 0
      KCG/base/backend/board/utils.py
  57. 72 28
      KCG/base/backendinterface.py
  58. 22 4
      KCG/base/controlwidget.py
  59. 13 0
      KCG/base/globals.py
  60. 5 16
      KCG/base/groupedelements.py
  61. 27 8
      KCG/base/kcg.py
  62. 81 8
      KCG/base/kcgwidget.py
  63. 14 1
      KCG/base/leftbar.py
  64. 17 0
      KCG/base/log.py
  65. 42 0
      KCG/base/loghandler.py
  66. 39 5
      KCG/base/plotWidget.py
  67. 30 0
      KCG/base/settings.py
  68. 54 2
      KCG/base/storage.py
  69. 1 1
      KCG/config.cfg
  70. 29 3
      KCG/kcg.py
  71. 46 16
      KCG/widgets/acquiresettings.py
  72. 3 0
      KCG/widgets/singleread.py
  73. 12 16
      KCG/widgets/timingWidget.py
  74. 1 1
      setup.py

+ 13 - 0
KCG/Documentation/source/Dev/code/__init__.rst

@@ -0,0 +1,13 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: __init__
+
+
+.. ___init__:
+
+
+
+Module __init__
+===============
+

+ 15 - 0
KCG/Documentation/source/Dev/code/base/__init__.rst

@@ -0,0 +1,15 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: __init__
+
+
+.. ___init__:
+
+
+
+Module __init__
+===============
+
+
+

+ 13 - 0
KCG/Documentation/source/Dev/code/base/backend/__init__.rst

@@ -0,0 +1,13 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: __init__
+
+
+.. ___init__:
+
+
+
+Module __init__
+===============
+

+ 15 - 0
KCG/Documentation/source/Dev/code/base/backend/board/__init__.rst

@@ -0,0 +1,15 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: __init__
+
+
+.. ___init__:
+
+
+
+Module __init__
+===============
+
+
+

+ 74 - 0
KCG/Documentation/source/Dev/code/base/backend/board/actions.rst

@@ -0,0 +1,74 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: actions
+
+
+.. _actions:
+
+
+
+Module actions
+==============
+
+
+Actions performed on the board.  
+Fore some more actions also see sequences.py  
+
+.. py:method:: acquire_data(board_id, filename, simulate=False)
+
+    Acquire data. This sets registers and reads data to a file  
+
+    :param board_id: the id of the board to acquire with  
+    :param filename: the file to write to  
+    :param simulate: whether to use the pilotbunch simulator or not  
+
+.. py:method:: data_reset(board_id)
+
+    Reset data  
+
+    :param board_id: the board to reset  
+
+.. py:method:: flush_dma(board_id, dma='dma0')
+
+    Flush dma. This basically reads data to /dev/null  
+
+    :param board_id: the id to flush dma  
+    :param dma: the dma to flush  
+
+.. py:method:: stop_board(board_id)
+
+    Stop a board (turn it off)  
+
+    :param board_id: the board to work with  
+
+.. py:method:: soft_reset(board_id)
+
+    Perform a soft reset on the board.  
+
+    :param board_id: the board to reset  
+
+.. py:method:: start_pilot_bunch_emulator(board_id)
+
+    Start the pilot bunch emulator  
+
+    :param board_id: the board to start it for  
+
+.. py:method:: start_acquisition(board_id)
+
+    Start an acquisition. This will only tell the board to acquire. It will not read data  
+
+    :param board_id: the id to acquire with  
+
+.. py:method:: stop_acquisition(board_id)
+
+    Stop an acquisition. This will only stop the acquisition on the board.  
+
+    :param board_id: the board to stop for  
+
+.. py:method:: enable_transfer(board_id)
+
+    Enable data transfer. This will not transfer data.  
+
+    :param board_id: the id of the board to transfer data from  
+

+ 167 - 0
KCG/Documentation/source/Dev/code/base/backend/board/board_config.rst

@@ -0,0 +1,167 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: board_config
+
+
+.. _board_config:
+
+
+
+Module board_config
+===================
+
+
+Configuration for each board  
+
+.. py:class:: BoardConfiguration(QtGui.QWidget)
+
+    The Main configuration class for boards.  
+
+    .. py:method:: __init__(self, identifier, config_file=None)
+
+
+    .. py:method:: _set_defaults(self)
+
+        Set default values  
+
+    .. py:method:: set_default_observers(self)
+
+        Set observers that are always used  
+
+    .. py:method:: notify_all_observers(self)
+
+        Notify all observers not only the ones that are affected by a change  
+
+    .. py:method:: load_config(self, filename)
+
+        Load a config from a file  
+
+        :param filename: the configuration file  
+
+    .. py:method:: save_config(self, filename)
+
+        Save the current configuration to a file  
+
+        :param filename: the file to write to  
+
+    .. py:method:: get(self, key)
+
+        Get the configuration value for key  
+
+        :param key: the key to get the value for  
+        :return: the value of the configuration for key  
+
+    .. py:method:: dump(self)
+
+        Dump all configuration values  
+
+        :return: all configuration values as list  
+
+    .. py:method:: update(self, key, value)
+
+        Update the value for key in the configuration  
+
+        :param key: the key to update  
+        :param value: the value to set the configuration for key to  
+
+    .. py:method:: updateSilent(self, key, value)
+
+        Update the configuration without notifying observers  
+
+        :param key: the key to updae  
+        :param value: the value to set the configuration of key to  
+
+    .. py:method:: observe(self, who, callback, key)
+
+        Register an observer. (A callback that is called when the according configuration value changes)  
+
+        :param who: who is observing  
+        :param callback: the callback to call on change of the configuration value  
+        :param key: the key to observe  
+
+    .. py:method:: observe_all(self, callback)
+
+        Register a observer that is called when any key changes  
+
+        :param callback: the callback to register  
+
+    .. py:method:: unobserve(self, who, key=None)
+
+        Remove an observer  
+
+        :param who: the observing entity  
+        :param key: the key to remove it from  
+
+    .. py:method:: unobserve_all_observer(self, callback)
+
+        Unobserve an observer that observes all keys.  
+
+        :param callback: the callback to unobserve  
+
+    .. py:method:: _notify_observers_receiver(self, key, value)
+
+        The pyqt signal slot for notifications of observers  
+
+        :param key: the key that changed  
+        :param value: the new value  
+
+    .. py:method:: _notify_observers(self, key, value)
+
+        Notify observers. This emits a pyqt signal to make it thread save  
+
+        :param key: the key that changed  
+        :param value: the new value  
+
+    .. py:method:: make_uint(self, value, maximum, name=None)
+
+        Convert a value to an uint  
+
+        :param value: the value  
+        :param maximum: the maximum of the returned value  
+        :param name: the name of this value  
+        :return: the converted value  
+
+    .. py:method:: set_fpga_delay(self, value)
+
+        Set the fpga_delays on the board  
+
+        :param value: the value to set the delays to  
+
+    .. py:method:: set_chip_delay(self, adcs, values)
+
+        Set the chip_delays on the board  
+
+        :param adcs: the adcs to set the delays for  
+        :param values: the value to set the delays to  
+
+    .. py:method:: set_th_delay(self, value)
+
+        Set the track and hold delay on the board  
+
+        :param value: the value to set the delay to  
+
+    .. py:method:: set_adc_delay(self, adc, value)
+
+        Set the adc delay for the given adc on the board  
+
+        :param adc: the adc to change the delay for  
+        :param value: the value to set the delay to  
+
+    .. py:method:: set_delay(self, n, ignore_seperate_delay=False)
+
+        Set delays  
+
+        :param n: ?  
+        :param ignore_seperate_delay: ignore the setting of a seperate delay for adc 1  
+
+    .. py:method:: update_header(self, state)
+
+        Set the flag to write Header to files when acquiring.  
+
+        :param state: True to enabling header and False to disable  
+
+    .. py:method:: read_from_board(self)
+
+        Read values from board and update them in the configuration (Mainly used for skip init functionality)  
+

+ 87 - 0
KCG/Documentation/source/Dev/code/base/backend/board/boards_connected.rst

@@ -0,0 +1,87 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: boards_connected
+
+
+.. _boards_connected:
+
+
+
+Module boards_connected
+=======================
+
+
+Discover and manage connected boards  
+
+.. py:class:: BoardsConnected(object)
+
+    Container for connected/available boards  
+    This will work as a generator and yield the available board_ids  
+    NOTE: this is subject to change. In the future this may yield board_names or tuples or something else  
+
+    .. py:method:: __init__(self)
+
+
+    .. py:method:: _device_id(self, dev_file)
+
+        Get the device id  
+
+        :param dev_file: the dev_file to use  
+        :return: string for the dev id  
+
+    .. py:method:: discover(self)
+
+        Discover connected boards  
+        This is either a dummy implementation that defaults to /dev/fpga0 for every board  
+        it will create 'virtual' boards  
+        OR:  
+        If config.use_dev_fpga_for_detection == True use number of /dev/fpga devices and use them  
+
+    .. py:method:: has_boards(self)
+
+        Check if at least one board is connected  
+
+    .. py:method:: board_ids(self)
+
+        Get Board Ids as list  
+
+    .. py:method:: board_names(self)
+
+        Get Board Names as list  
+
+
+    .. py:method:: get_board_name_from_id(self, board_id)
+
+        Get the name of a board with the given board_id  
+
+        :param board_id: the board to get the name for  
+        :return: the name of the board with id board_id  
+
+    .. py:method:: get_board_id_from_name(self, board_name)
+
+        Get the id of a board with the name board_name  
+
+        :param board_name: the name of the board to get the id for  
+        :return: the id of the board with name board_name  
+
+    .. py:method:: get_device_file(self, board_id)
+
+        Get the device file (/dev/...) to use when communicating with the board  
+
+        :param board_id: the id of the board  
+        :return: the device file as string  
+
+    .. py:method:: multi_board(self)
+
+        If multiple boards are connected this is true else false  
+
+    .. py:method:: __iter__(self)
+
+
+    .. py:method:: next(self)
+
+
+    .. py:method:: __getitem__(self, item)
+
+

+ 106 - 0
KCG/Documentation/source/Dev/code/base/backend/board/communication.rst

@@ -0,0 +1,106 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: communication
+
+
+.. _communication:
+
+
+
+Module communication
+====================
+
+
+Communication part of the board package  
+
+.. py:class:: PCI(object)
+
+    The Interface to the pci command  
+
+    .. py:method:: __init__(self)
+
+
+    .. py:method:: _safe_call(self, cmd)
+
+        Actually call the pci command  
+
+        :param cmd: the command line to execute as list  
+        :return: the output of the command  
+
+    .. py:method:: _format(self, output)
+
+        Format output values (remove unnecessary parts of the output)  
+
+        :param output: the unformatted output  
+        :return: the formatted output  
+
+    .. py:method:: read(self, board_id, amount=1, reg=None, dma=None, destination=None, decimal=False, timeout=None)
+
+        Read from boards  
+          
+
+        :param board_id: id of the board to write to (mandatory)  
+        :param amount: number of 32byte blocks to read (default is 1) [1]  
+        :param reg: register to read from [1]  
+        :param dma: the dma to read from [1]  
+        :param destination: the destination to write the retrieved data to ('memory' to return the data)  
+        :param decimal: whether to return the result as decimal number (default is False)  
+        :param timeout: the timeout for the read (only useful when reading data from dma)  
+          
+        [1]: If neither reg nor dma are given reg will default to 0x9000 and data from registers will be read  
+             If reg is given, data from registers will be read  
+             If dma is given, data from dma will be read and amount is ignored  
+             If both reg and dma are given, an error will be raised  
+
+    .. py:method:: write(self, board_id, value, reg='0x9040', hex_mask='FFFFFFFF')
+
+        Write to boards  
+
+        :param board_id: id of the board to write to (mandatory)  
+        :param value: value to write (mandatory)  
+        :param reg: register to write to (optional, default is '0x9040')  
+        :param hex_mask: hex mask to apply to value before writing (optional)  
+
+    .. py:method:: read_data_to_file(self, board_id, filename, dma='dma0', timeout=None)
+
+        Read data from board and write to file  
+          
+
+        :param board_id: the board to read from  
+        :param filename: the filename to write to  
+        :param dma: the dma to use?  
+        :param timeout: if not None: the timeout for the underlying pci command  
+
+    .. py:method:: read_data_to_variable(self, board_id, dma='dma0', timeout=None)
+
+        Read data and return it.  
+          
+
+        :param board_id: the board to read from  
+        :param dma: the dma to use?  
+        :param timeout: if not None: the timeout for the underlying pci command  
+        :return: string with data read from board  
+
+    .. py:method:: start_dma(self, board_id, dma='dma0r')
+
+        Start dma engine.  
+          
+
+        :param board_id: the board to start the dma engine for  
+        :param dma: the dma to use  
+
+    .. py:method:: stop_dma(self, board_id, dma='dma0r')
+
+        Stop dma engine.  
+          
+
+        :param board_id: the board to stop the dma engine for  
+        :param dma: the dma to use  
+
+    .. py:method:: info(self, board_id=None, dev_file=None)
+
+        Get Device info (output of pci -i)  
+
+        :return: Information string returned by pci -i  
+

+ 36 - 0
KCG/Documentation/source/Dev/code/base/backend/board/errors.rst

@@ -0,0 +1,36 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: errors
+
+
+.. _errors:
+
+
+
+Module errors
+=============
+
+
+Errors for board actions  
+
+.. py:class:: BoardError(Exception)
+
+    A General Error with the Board  
+
+.. py:class:: InterfaceNotFoundError(Exception)
+
+    Error if not pci command was found  
+
+.. py:class:: ObserverError(Exception)
+
+    Error in Observation of configuration values  
+
+.. py:class:: NoBoardId(Exception)
+
+    Error if not board id was given  
+
+.. py:class:: NoSuchKeyError(Exception)
+
+    Error if a key is requested that does not exist in configuration  
+

+ 21 - 0
KCG/Documentation/source/Dev/code/base/backend/board/index.rst

@@ -0,0 +1,21 @@
+.. KCG documentation master file, created by
+   sphinx-quickstart on Thu Jan 28 15:25:31 2016.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Package board
+=============
+
+Contents:
+
+.. toctree::
+   actions
+   board_config
+   boards_connected
+   communication
+   errors
+   sequences
+   status
+   utils
+   :maxdepth: 4
+

+ 36 - 0
KCG/Documentation/source/Dev/code/base/backend/board/sequences.rst

@@ -0,0 +1,36 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: sequences
+
+
+.. _sequences:
+
+
+
+Module sequences
+================
+
+
+Sequences for various board actions  
+These methods are generators that will yield as first element the number  
+of actions (other yields) excluding it self  
+They will then perform the next action in row (setting registers or reading values from boards etc)  
+and will yield True or False depending on the result of the action performed  
+
+.. py:method:: startup_sequence(board_id)
+
+    Star the board  
+
+.. py:method:: calibration_sequence(board_id)
+
+    Calibrate the board  
+
+.. py:method:: synchronisation_sequence(board_id)
+
+    Synchronize the board  
+
+.. py:method:: write_value_sequence(board_id)
+
+    Write values to the board  
+

+ 23 - 0
KCG/Documentation/source/Dev/code/base/backend/board/status.rst

@@ -0,0 +1,23 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: status
+
+
+.. _status:
+
+
+
+Module status
+=============
+
+
+Status for boards  
+
+.. py:class:: StatusStorage(object)
+
+    Class used as Container for various storage purposes  
+
+    .. py:method:: __getattr__(self, item)
+
+

+ 72 - 0
KCG/Documentation/source/Dev/code/base/backend/board/utils.rst

@@ -0,0 +1,72 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: utils
+
+
+.. _utils:
+
+
+
+Module utils
+============
+
+
+Helper methods  
+
+.. py:method:: get_dec_from_bits(bits, msb=-1, lsb=-1)
+
+    Get decimal values from a string represented binary string  
+
+    :param bits: the string to convert  
+    :param msb: the most significant bit to use  
+    :param lsb: the least significant bit to use  
+    :return: the decimal value  
+
+.. py:method:: get_status(board_id)
+
+    Get the satatus of the board (this is used for the status leds)  
+
+    :param board_id: the id of the board  
+    :return: dictionary with the bits for each led (lower case led names are the keys of this dict)  
+
+.. py:method:: is_conneced(board_id)
+
+    Is the board connected?  
+
+    :param board_id: the id for the board to check  
+    :return: True if the board is connected else False  
+
+.. py:method:: is_active(board_id)
+
+    Check if a board is active  
+
+    :param board_id: the board to check for  
+    :return: True if it is active else False  
+
+.. py:method:: wait_for_revolutions(board_id)
+
+    Sleep as long as the revolutions in the accelerator last to not stop the acquisition before it ended.  
+
+    :param board_id: the board to wait for?  
+
+.. py:method:: create_new_board_config(identifier)
+
+    This creates a new instance of BoardConfiguration and also a new instance of StatusStorage  
+
+    :param identifier: the identifier for this board (not the id)  
+
+.. py:method:: get_board_config(id)
+
+    Get the configuration instance for the board with the given id  
+
+    :param id: the id of the desired board  
+    :return: the instance of configuration  
+
+.. py:method:: get_board_status(id)
+
+    Get the status storage instance for the board with the given id  
+
+    :param id: the id of the desired board  
+    :return: the instance of the status storage  
+

+ 54 - 0
KCG/Documentation/source/Dev/code/base/backend/dataset.rst

@@ -0,0 +1,54 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: dataset
+
+
+.. _dataset:
+
+
+
+Module dataset
+==============
+
+
+
+.. py:method:: _pad_array(array)
+
+
+.. py:class:: DataSet(object)
+
+
+    .. py:method:: __init__(self, array, filename, header=None)
+
+
+    .. py:method:: skipped_turns(self)
+
+
+    .. py:method:: bunch(self, number)
+
+
+    .. py:method:: num_bunches(self)
+
+
+    .. py:method:: num_turns(self)
+
+
+    .. py:method:: heatmap(self, adc=1, frm=0, to=-1, bunch_frm=0, bunch_to=-1)
+
+
+    .. py:method:: fft(self, adc=1, frm=0, to=-1, drop_first_bin=False)
+
+
+    .. py:method:: fft_max_freq(self)
+
+
+    .. py:method:: fft_freq_dist(self)
+
+
+    .. py:method:: train(self, adc=1, frm=0, to=-1, **kwargs)
+
+
+    .. py:method:: combined(self, frm=0, to=-1, show_reconstructed=True)
+
+

+ 17 - 0
KCG/Documentation/source/Dev/code/base/backend/index.rst

@@ -0,0 +1,17 @@
+.. KCG documentation master file, created by
+   sphinx-quickstart on Thu Jan 28 15:25:31 2016.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Package backend
+===============
+
+Contents:
+
+.. toctree::
+   io
+   __init__
+   dataset
+   board/index
+   :maxdepth: 4
+

+ 50 - 0
KCG/Documentation/source/Dev/code/base/backend/io.rst

@@ -0,0 +1,50 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: io
+
+
+.. _io:
+
+
+
+Module io
+=========
+
+
+
+.. py:method:: is_data_consistent(dataset)
+
+
+.. py:method:: _cached_exist(filename)
+
+
+.. py:method:: decode_data(data)
+
+
+.. py:method:: data_has_header(data)
+
+
+.. py:method:: get_num_of_skipped_turns(data, header_info)
+
+
+.. py:method:: parse_header(data, header_info)
+
+    Parse the Header and return the values in a dictionary  
+
+    :param data: the data which contains a header  
+    :return: dictionary with header entries  
+
+.. py:method:: read_from_file(filename, force=False, header=False, cache=False)
+
+    Read data from file  
+
+    :param filename: file to read  
+    :param force: force reread and do not take values from cache  
+    :param header: only for backwards compatibility  
+    :param cache: save cache  
+    :return: dataset  
+
+.. py:method:: read_from_string(raw_data, force=False, header=False, cache=False, cache_filename="_heb_data_cache")
+
+

+ 390 - 0
KCG/Documentation/source/Dev/code/base/backendinterface.rst

@@ -0,0 +1,390 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: backendinterface
+
+
+.. _backendinterface:
+
+
+
+Module backendinterface
+=======================
+
+
+This is the interface to the backend.  
+It is used to make the backend easily interchangable.  
+All Functions that interface directly with the backend are prefixed with bk\_  
+Functions only used internal in this module will be prefixed _bif_  
+
+.. py:method:: initStatus(st)
+
+    Initialize Status variables. These variables are used to transfer status variables over different modules.  
+
+    :param st: variable to use (most likely a DummyStorage instance)  
+
+.. py:method:: _bif_enable_wait_cursor()
+
+    Show the "Wait Cursor"  
+
+.. py:method:: _bif_disable_wait_cursor()
+
+    Show the normal Cursor  
+
+.. py:method:: _bif_continuous_read_is_enabled(board_id, popup_title_text=None)
+
+    Checks if continuous read is enabled and if yes shows a popup dialog to ask if it shall be disabled  
+
+    :param board_id: id of the board do manipulate  
+    :param popup_title_text: Text to display in the popup that asks to disable continuous read  
+    :return: bool (True if continuous read is enabled and not disabled in popup else False)  
+
+.. py:method:: bk_status_readout()
+
+    Read Status for every connected board  
+
+.. py:method:: _bif_status_readout(board_id)
+
+    Read Status from board and update variables  
+    as well as enable and disable corresponding Buttons  
+
+
+.. py:class:: PopupDialog(QtGui.QDialog)
+
+    Simple Class to show a popup dialog.  
+
+    .. py:method:: __init__(self, text, title=None, parent=None)
+
+
+    .. py:method:: on_okay(self)
+
+        Handler for the press of the ok button  
+
+    .. py:method:: on_cancel(self)
+
+        Handler for the press of the cancel button  
+
+
+    .. py:method:: get_return_value(self)
+
+        Get True if the Window was closed with OK else False  
+
+        :return: True if OK else False  
+
+.. py:method:: bk_start_board(board_id)
+
+    Start the Board.  
+    This will set initial Registers to power up the Board.  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:class:: _bif_ProgressBar(QtGui.QProgressBar)
+
+    Simple Progressbar class.  
+
+    .. py:method:: __init__(self, min, max, text)
+
+
+    .. py:method:: remove(self, timeout=None)
+
+        Remove this instance of a progressbar  
+
+        :param timeout: the time from calling this function to wanishing of the progressbar  
+
+.. py:method:: bk_calibrate(board_id, do_the_rest=None)
+
+    Send commands to the board that will enable it to calibrate itself.  
+    This function checks if a read command is still running. BUT: It does not check if  
+    the board is acquiring or something like this.  
+    So Another instance of KCG can still be acquiring or calibrating at the same time. This can be dangerous.  
+
+    :param board_id: id of the board do manipulate  
+    :param do_the_rest: function to call after calibration. This is used when "Prepare Board" is pressed.  
+
+.. py:method:: bk_sync_board(board_id)
+
+    Sends commands to the board to sync with triggers.  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: bk_write_values(board_id, defaults=False)
+
+    Write values to board.  
+
+    :param board_id: id of the board do manipulate  
+    :param defaults: (bool) if True Writes default values  
+
+.. py:method:: bk_stop_board(board_id)
+
+    Stops the board and shuts it down  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: bk_soft_reset(board_id)
+
+    Perform a soft reset.  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: bk_update_config(board_id, key, value, silent=False)
+
+    Interface to the update command of the BoardConfiguration class.  
+
+    :param board_id: id of the board do manipulate  
+    :param key: Key to update  
+    :param value: Value to set for key  
+    :param silent: (bool) if True do not inform observers on update  
+
+.. py:method:: bk_get_config(board_id, key)
+
+    Interface to the get command of the BoardConfiguration class.  
+
+    :param board_id: id of the board do manipulate  
+    :param key: Key to get the value for  
+    :return: value stored for key  
+
+.. py:method:: bk_get_board_status(board_id, status_variable)
+
+    Interface to the status class for each board.  
+
+    :param board_id: id of the board do manipulate  
+    :param status_variable: Key to get the value for  
+    :return: value stored for key  
+
+.. py:method:: bk_get_status(board_id)
+
+    Interface to the get_status of the board  
+    NOTE: This is not get_board_status  
+
+    :return: status dictionary  
+
+.. py:method:: bk_get_board_config(board_id)
+
+    Get the board config instance  
+
+    :param board_id: the id of the board  
+    :return: the config instance  
+
+.. py:method:: bk_change_num_of_orbits(board_id, value, silent=False)
+
+    Send new number of orbits to board and update in config  
+
+    :param board_id: id of the board do manipulate  
+    :param value: the value to send  
+    :param silent: (bool) if True do not inform observers on update  
+
+.. py:method:: bk_change_num_of_skipped_orbits(board_id, value, silent=False)
+
+    Send new number of orbits to skip to board and update in config  
+
+    :param board_id: id of the board do manipulate  
+    :param value: the value to send  
+    :param silent: (bool) if True do not inform observers on update  
+
+.. py:method:: bk_change_count(board_id, value, silent=False)
+
+    Change the number of acquisitions you want to make.  
+
+    :param board_id: id of the board do manipulate  
+    :param value: (int) Number of acquisitions  
+    :param silent: (bool) if True do not inform observers on update  
+
+.. py:method:: bk_change_wait(board_id, value, silent=False)
+
+    Change the time between acquisitions.  
+
+    :param board_id: id of the board do manipulate  
+    :param value: (bool) Time in seconds  
+    :param silent: (bool) if True do not inform observers on update  
+
+.. py:method:: bk_change_build_spectrograms(board_id, value, silent=False)
+
+    Change if spectrograms are built or not)  
+
+    :param board_id: id of the board do manipulate  
+    :param value: (bool) True or False built or not  
+    :param silent: (bool) if True do not inform observers on update  
+
+.. py:method:: bk_change_pilot_bunch(board_id, value, silent=False)
+
+    Change if pilot bunch is simulated  
+
+    :param board_id: id of the board do manipulate  
+    :param value: (bool) True or False to simulate or not  
+    :param silent: (bool) if True do not inform observers on update  
+
+.. py:method:: _bif_iterate_spectrograms(board_id, path)
+
+    BROKEN (DOES NOT GET ANY DATA)  
+    Built Spectrograms line by line  
+
+    :param board_id: id of the board do manipulate  
+    :param path: where to built the spectrogram  
+
+.. py:method:: _bif_read_data_and_save(board_id)
+
+    Tell the pci command to start acquisition and save data  
+    Also generates the filename from settings  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: _bif_read_and_update_data_from_file(board_id, filename)
+
+    Proxy function for _bif_read_and_update to call with correct read_func  
+
+    :param board_id: id of the board do manipulate  
+    :param filename: filename to read data from  
+
+.. py:method:: _bif_read_and_update_data_from_string(board_id, raw_data)
+
+    Proxy function for _bif_read_and_update to call with correct read_func  
+
+    :param board_id: id of the board do manipulate  
+    :param raw_data: Data as string  
+
+.. py:method:: _bif_read_and_update(board_id, read_func, *args)
+
+    Function to read data from file or string (depending on read_func) and update plots etc.  
+
+    :param board_id: id of the board do manipulate  
+    :param read_func: function to use to read data  
+    :param args: filename or raw_data (see _bif_read_and_update_from_{filename, string}  
+
+.. py:method:: bk_acquire(board_id)
+
+    Toggle Acqisition  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: _bif_stop_acquisition(board_id)
+
+    Stop acquisition  
+    This does stop the timer started by _bif_start_acquisition()  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: _bif_start_acquisition(board_id)
+
+    Start acquisition.  
+    This will start a timer to automatically acquire data.  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: bk_single_read(board_id)
+
+    Perform a single read of data  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: _bif_set_continuous_read_active(board_id)
+
+    Enable continuous read  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: _bif_set_continuous_read_inactive(board_id)
+
+    Disable continuous read  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: bk_continuous_read(board_id, interval=100)
+
+    Toggle continuous read  
+
+    :param board_id: id of the board do manipulate  
+    :param interval: Time between two consecutive reads.  
+
+.. py:method:: _bif_continuous_read(board_id, interval=None)
+
+    Perform continuous read based on a timer.  
+
+    :param interval:  
+
+.. py:method:: _bif_read_data(board_id)
+
+    Reads data acquired by board.  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: bk_board_connected(board_id)
+
+    Interface to the board to check if it is connected.  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: bk_get_temperature(board_id)
+
+    Get Temperature from board and format it  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: bk_time_scan(board_id, c_frm, c_to, f_frm, f_to, ts_pbar, plot_func, orbits_observe=None, orbits_skip=None)
+
+    Toggle Timescan.  
+
+    :param board_id: id of the board do manipulate  
+    :param c_frm: (int) From value for Coarse scan  
+    :param c_to:  (int) To value for Coarse scan  
+    :param f_frm: (int) From value for Fine scan  
+    :param f_to: (int) To value for fine scan  
+    :param ts_pbar: Handle to the Timescan Progressbar  
+    :param plot_func: Function to plot when timescan ended.  
+    :param orbits_observe: Number of orbits to observe for the timescan (original values will be restored after timescan)  
+    :param orbits_skip: Number of orbits to skipfor the timescan (original values will be restored after timescan)  
+
+.. py:method:: _bif_stop_time_scan(board_id, ts_pbar)
+
+    Stop the timescan. This stops the timer.  
+
+    :param board_id: id of the board do manipulate  
+    :param ts_pbar: Timescan Progressbar handle  
+
+.. py:method:: _bif_start_time_scan(board_id, c_frm, c_to, f_frm, f_to, timescan_progressbar, plot_func, orbits_observe, orbits_skip)
+
+    Start the timscan. This starts the timer  
+
+    :param board_id: id of the board do manipulate  
+    :param c_frm: From value for coarse scan  
+    :param c_to: To value for coarse scan  
+    :param f_frm: From value for fine scan  
+    :param f_to: To value for fine scan  
+    :param timescan_progressbar: Handle for the timescanprogressbar  
+    :param plot_func: Function to use to plot the data  
+    :param orbits_observe: Number of orbits to observe for the timescan (original values will be restored after timescan)  
+    :param orbits_skip: Number of orbits to skipfor the timescan (original values will be restored after timescan)  
+
+.. py:method:: bk_check_for_board(board_id)
+
+    Check if board is connected  
+    Also overrides the bk_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  
+
+    :param board_id: id of the board do manipulate  
+
+.. py:method:: bk_toggle_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, timeout=None, method=None)
+
+    Toggle waiting for trigger signal to acquire  
+
+    :param board_id: id of the board do manipulate  
+    :param num_of_acquisitions: number of acquisitions to wait for  
+    :param skip: how much trigger signals to skip between acquisitions  
+    :param timeout: the timeout for the pci to wait for date  
+    :param method: wait method to use  
+            1 for wait in pci command and 2 for waiting until register is set that KAPTURE has read data  
+            NOTE: this also means that method 1 enables simultaneous read and write to dma and method 2 does write and  
+            read sequentially  
+
+.. py:method:: _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, timeout=None, method=None)
+
+    Start waiting on external acquisition trigger. This starts the timer  
+
+    :param board_id: id of the board do manipulate  
+    :param num_of_acquisitions: number of acquisitions to do  
+    :param count_label: Handle for the countlabel  
+    :param method: wait method to use  
+            1 for wait in pci command and 2 for waiting until register is set that KAPTURE has read data  
+            NOTE: this also means that method 1 enables simultaneous read and write to dma and method 2 does write and  
+            read sequentially  
+

+ 116 - 0
KCG/Documentation/source/Dev/code/base/bitsTable.rst

@@ -0,0 +1,116 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: bitsTable
+
+
+.. _bitsTable:
+
+
+
+Module bitsTable
+================
+
+
+This defines the Tables used as Bits display  
+
+.. py:class:: BitsDisplayTable(QtGui.QTableWidget)
+
+    Widget to use to display the Bits (as table)  
+
+    .. py:method:: __init__(self, value, parent=None, optimalSize=True)
+
+
+    .. py:method:: do_style(self)
+
+
+    .. py:method:: width(self)
+
+
+    .. py:method:: height(self)
+
+
+    .. py:method:: do_optimal_size(self)
+
+
+    .. py:method:: stretch_to_width(self, width_in)
+
+
+    .. py:method:: set_item(self, row, col, value)
+
+
+    .. py:method:: set_numbers(self, value)
+
+
+    .. py:method:: set_label(self, start, end, label, color=None)
+
+
+    .. py:method:: grey_out_column(self, column)
+
+
+    .. py:method:: undo_grey_out_column(self, column)
+
+
+    .. py:method:: _get_table_item_width(self, item)
+
+
+.. py:class:: BitsEditTable(BitsDisplayTable)
+
+
+    .. py:method:: __init__(self, value, parent=None, optimalSize=True)
+
+
+    .. py:method:: populate_checkboxes(self)
+
+
+    .. py:method:: set_numbers(self, value)
+
+
+    .. py:method:: get_bits(self)
+
+
+    .. py:method:: get_bit(self, bit)
+
+
+    .. py:method:: clear_all_bits(self)
+
+
+.. py:class:: AdvancedBoardInterface(QtGui.QWidget)
+
+
+    .. py:method:: __init__(self, parent=None, board_id=None)
+
+
+    .. py:method:: do_layout(self)
+
+
+    .. py:method:: send_control_to_board(self)
+
+
+    .. py:method:: do_status1_table_layout(self, table)
+
+
+    .. py:method:: do_status2_table_layout(self, table)
+
+
+    .. py:method:: do_status3_table_layout(self, table)
+
+
+    .. py:method:: do_control_table_layout(self, table)
+
+
+    .. py:method:: update_status(self, registers)
+
+
+    .. py:method:: do_status_update(self)
+
+
+.. py:class:: AdvanceControlView(kcgw.KCGWidgets)
+
+
+    .. py:method:: __init__(self)
+
+
+    .. py:method:: pages_update_function(self)
+
+

+ 72 - 0
KCG/Documentation/source/Dev/code/base/callbacks.rst

@@ -0,0 +1,72 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: callbacks
+
+
+.. _callbacks:
+
+
+
+Module callbacks
+================
+
+
+
+.. py:class:: NoCallbackError(Exception)
+
+
+.. py:class:: CallbackExistsError(Exception)
+
+
+.. py:class:: CallbackHandler(QtCore.QObject)
+
+    Handler for custom callbacks.  
+    It can handle synchronous callbacks as well as async callbacks (using pyqtSignals)  
+
+    .. py:method:: __init__(self)
+
+
+    .. py:method:: callback(self, name, *args, **kwargs)
+
+        Call all registered callback method for name  
+        This passes all additional arguments and keyword arguments down to the callbacks  
+        NOTE: all callbacks therefore need to accept the same number of arguments  
+
+        :param name: the name for which the callbacks are to be called  
+        :param args: arguments to be passed to the callbacks  
+        :param kwargs: keyword arguments to be passed to the callbacks  
+
+    .. py:method:: __async_callback_receiver(self, name, *args)
+
+        Internal Method (Called when async callbacks are to be executed)  
+
+    .. py:method:: async_callback(self, name, *args, **kwargs)
+
+        Perform a async callback (same as callback but through pyqtSignal and therefore allowed in threads)  
+
+        :param name: the name for which the callbacks are to be called  
+        :param args: arguments to be passed to the callbacks  
+        :param kwargs: keyword arguments to be passed to the callbacks  
+
+    .. py:method:: add_callback(self, name, callback)
+
+        Register a callback for name  
+
+        :param name: the name to register against  
+        :param callback: the callback to register  
+
+    .. py:method:: delete_callback(self, name, callback)
+
+        Delete a callback from name  
+        if no callback for name is left the whole group is deleted  
+
+        :param name: the name to delete the callback from  
+        :param callback: the callback to delete  
+
+    .. py:method:: delete_callback_class(self, name)
+
+        Delete a whole callback class  
+
+        :param name: the name of the class  
+

+ 127 - 0
KCG/Documentation/source/Dev/code/base/controlwidget.rst

@@ -0,0 +1,127 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: controlwidget
+
+
+.. _controlwidget:
+
+
+
+Module controlwidget
+====================
+
+
+This module defines the Initial view of the gui  
+
+.. py:class:: LED(QtGui.QWidget)
+
+    Produces a graphical LED  
+
+    .. py:method:: __init__(self, parent=None, status=1, height=10, width=10)
+
+        Initialize a LED  
+
+        :param parent: (QWidget) parent of this widget  
+        :param status: (int) (0=out, 1=off, 2=orange, 3=on) initial status of this LED  
+        :param height: (int) height of the LED  
+        :param width: (int) width of the LED  
+
+    .. py:method:: paintEvent(self, event)
+
+
+    .. py:method:: set_on(self)
+
+        Set the LED to "on" state  
+
+
+    .. py:method:: set_off(self)
+
+        Set the LED to "off" state  
+
+
+    .. py:method:: set_out(self)
+
+        Set the LED to "OUT" state (that is like an LED without power)  
+
+
+    .. py:method:: set_tri(self)
+
+        Set the LED to "TRI" state (that is led is orange)  
+
+
+    .. py:method:: set_status(self, status)
+
+        Set the status of the led  
+
+        :param status: status (in 0, 1, 2, 3)  
+
+.. py:class:: StatusLED(QtGui.QWidget)
+
+    Create a Status LED with Label next to it  
+
+    .. py:method:: __init__(self, text, status=None)
+
+        Initialise StatusLED  
+
+        :param text: label text next to the LED  
+        :param status: initial status of the LED  
+
+    .. py:method:: set_on(self)
+
+        See set_on of LED Class  
+
+    .. py:method:: set_off(self)
+
+        See set_off of LED Class  
+
+    .. py:method:: set_out(self)
+
+        See set_out of LED Class  
+
+    .. py:method:: set_tri(self)
+
+        See set_tri of LED Class  
+
+    .. py:method:: set_status(self, status)
+
+        See set_status of LED Class  
+
+        :param status: the status to set the led to  
+
+.. py:class:: BoardControl(kcgw.KCGWidgets)
+
+    The main view of the gui for each board at startup  
+
+    .. py:method:: __init__(self, board_id, single=False)
+
+
+    .. py:method:: toggle_sub_control(self)
+
+        Show or hide the subcontrol buttons  
+
+    .. py:method:: all_in_one(self)
+
+        Function that gets called when the Prepare Board Button is pressed.  
+        It Starts the board, syncs it and sets defaults.  
+        This is accomplished via the backendinterface module  
+
+
+    .. py:method:: skip_init(self)
+
+        Skip board initialisation progress and read data from board. This will adjust the values in the gui to those  
+        on the board (for every value that is stored on the board)  
+
+    .. py:method:: on_check(self)
+
+        This function is the handler for the status leds on the ControlWidget View.  
+        Parses the registers and sets the colors of the leds according.  
+
+
+.. py:class:: ControlWidget(kcgw.KCGWidgets)
+
+    Main Widget that is shown at start of gui.  
+
+    .. py:method:: __init__(self)
+
+

+ 36 - 0
KCG/Documentation/source/Dev/code/base/globals.rst

@@ -0,0 +1,36 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: globals
+
+
+.. _globals:
+
+
+
+Module globals
+==============
+
+
+
+.. py:class:: Globals(object)
+
+    Object to make it easy to work with global values  
+
+    .. py:method:: __init__(self)
+
+
+    .. py:method:: get_global(self, item)
+
+        Get a global value  
+
+        :param item: the item to get  
+        :return: the value of the global value of item  
+
+    .. py:method:: set_global(self, key, value)
+
+        Set a global value  
+
+        :param key: the key to set  
+        :param value: the value to set it to  
+

+ 150 - 0
KCG/Documentation/source/Dev/code/base/groupedelements.rst

@@ -0,0 +1,150 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: groupedelements
+
+
+.. _groupedelements:
+
+
+
+Module groupedelements
+======================
+
+
+Module to easily group elements of a gui  
+
+.. py:class:: GroupWarning(Warning)
+
+    General Warning Class for GroupedObjects  
+
+.. py:class:: GroupedObjects
+
+    This class enables grouping of objects to easily access them as groups throughout the gui.  
+
+    .. py:method:: __init__(self)
+
+        Initialise this object  
+
+
+    .. py:method:: setFlags(self, flagDict)
+
+        Set Flags that define the behaviour of GroupedObjects in various events.  
+
+        :param flagDict: Dictionary containing the Flags.  
+                        Possible Flags are: (They are to be of type bool)  
+          
+                        * warn: If an element is deleted and the corresponding entry is encountered by setEnabled, a  
+                            Warning is raised if warn is True  
+                        * autoremove: If an element is deleted and the corresponding entry is encountered by setEnabled,  
+                            the Element will be removed from GroupedObjects if autoremove is True  
+                        * exception_on_deleted: If an element is deleted and the corresponding entry is encountered by  
+                            setEnabled an Exception will be raised if exception_on_deleted is True  
+                        * notify_deletion: If this is set to True a notification will be printed to STDOUT whenever an  
+                            autoremove is performed (see above)  
+
+    .. py:method:: createEmptyGroup(self, group)
+
+        Create an empty group  
+
+        :param group: (str) the name of the group  
+
+    .. py:method:: addItem(self, group, item)
+
+        Add a item or items to a group and thus register with the GroupedObjects object  
+
+        :param group: (list or str) List of groups or single group where the item is to be added  
+        :param item: (single item or list) What item/s  
+
+    .. py:method:: setChecked(self, group, state)
+
+        Set the state of all the checkboxes in the group  
+
+        :param group: What group  
+        :param state: True for checked, False for unchecked  
+
+    .. py:method:: setEnabled(self, group, state, exclude=None)
+
+        Set the state of all the items in the group  
+
+        :param group: What group  
+        :param state: True for enabled, False for disabled  
+        :param exclude: Exclude this item  
+
+    .. py:method:: addMenuItem(self, group, item)
+
+        Deprecated. Use addItem.  
+
+    .. py:method:: addButton(self, group, item)
+
+        Deprecated. Use addItem.  
+
+    .. py:method:: addCheckbox(self, group, item)
+
+        Deprecated. Use addItem.  
+
+    .. py:method:: removeItem(self, group, item)
+
+        Remove an element from a gropu  
+
+        :param group: (list or str) list of groups or groupname  
+        :param item:  (list or item) list of items or item to remove  
+
+    .. py:method:: removeGroup(self, group)
+
+        Remove a group from GroupedObjects. If the group is not registered, a warning will be raised.  
+
+        :param group: (str) the group to remove  
+
+    .. py:method:: emptyGroup(self, group)
+
+        Unregister all elements from group. (This will delete the group and recreate it.  
+
+        :param group: (str) the group to clean out.  
+
+    .. py:method:: getElements(self, group)
+
+        Get the elements of a group as list.  
+
+        :param group: (str) the gorup you want the elements of  
+        :return: (list) Elements in group  
+
+    .. py:method:: isEnabled(self, group)
+
+        Check if a group is enabled.  
+
+        :param group: (str) the gorup to check.  
+        :return: (bool) State of group  
+
+.. py:class:: LivePlotWindows()
+
+    Container class to hold open LivePlotWindows.  
+    Added LivePlotWindows will automatically be plotted to on the event of new data.  
+
+    .. py:method:: __init__(self)
+
+
+    .. py:method:: addWindow(self, board_id, window)
+
+        Register a Window.  
+
+        :param window: (PlotWidget) The window to be added.  
+
+    .. py:method:: getWindows(self, board_id)
+
+        Get the list of registered plot windows.  
+
+        :return: (list) List of plotWindows  
+
+    .. py:method:: hasWindows(self, board_id)
+
+        Check if Windows are registered.  
+
+        :return: (bool) True if there are windows and False if not.  
+
+    .. py:method:: removeWindow(self, board_id, window)
+
+        Remove a window from open plot windows  
+
+        :param window: the window to remove  
+

+ 30 - 0
KCG/Documentation/source/Dev/code/base/index.rst

@@ -0,0 +1,30 @@
+.. KCG documentation master file, created by
+   sphinx-quickstart on Thu Jan 28 15:25:31 2016.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Package Base
+============
+
+Contents:
+
+.. toctree::
+   backend/index
+   storage
+   backendinterface
+   kcgwidget
+   kcg
+   settings
+   log
+   controlwidget
+   __init__
+   bitsTable
+   leftbar
+   multipage
+   plotWidget
+   multiWidget
+   groupedelements
+   callbacks
+   globals
+   loghandler
+   :maxdepth: 4

+ 124 - 0
KCG/Documentation/source/Dev/code/base/kcg.rst

@@ -0,0 +1,124 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: kcg
+
+
+.. _kcg:
+
+
+
+Module kcg
+==========
+
+
+
+.. py:method:: 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  
+
+.. py:class:: CentralWidget(kcgw.KCGWidgets)
+
+    Central Widget for the KCG gui main window  
+
+    .. py:method:: __init__(self, parent=None)
+
+
+.. py:class:: Gui(QtGui.QMainWindow)
+
+    Main Window of the KCG gui  
+
+    .. py:method:: __init__(self)
+
+
+    .. py:method:: initUI(self)
+
+        Initialize ui  
+
+
+    .. py:method:: createEmptyGroups(self)
+
+        This creates empty groups with the GroupedObjects class in groupedelements module.  
+        This has to be done to avoid warnings when groups are enabled or disabled before creation.  
+
+
+    .. py:method:: finalizeInit(self)
+
+        Final things done at initialisation  
+
+
+    .. py:method:: doMenu(self)
+
+        Create and show the menu and it's entries  
+
+
+    .. py:method:: saveConfig(self, board_id)
+
+        Save the current configuration to a configuration file  
+
+        :param board_id: the board to save the configuration for  
+
+    .. py:method:: loadConfig(self, board_id)
+
+        Load the configuration for the given board from a file  
+
+        :param board_id: the board to read the configuration for  
+
+    .. py:method:: rerunConfig(self)
+
+        Rerun the initial configuration wizard  
+
+    .. py:method:: showAbout(self)
+
+        Show the about window.  
+
+
+    .. py:method:: addWindowMenuEntries(self)
+
+        Adds Window Menu entries for custom widgets  
+
+
+    .. py:method:: showSettings(self)
+
+        Create and show settings window  
+
+
+    .. py:method:: updateSettings(self, changedsettings)
+
+        Update settings in storage if settings were changed in the settings window.  
+
+        :param changedsettings: list of settings that have been changed  
+
+    .. py:method:: 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  
+
+    .. py:method:: after_start_status_handler(self)
+
+        Method to check for boards and perform a status_readout after the gui is fully started  
+
+
+    .. py:method:: populate_storage(self)
+
+        Initially fills storage with predefined settings and configuration values  
+
+
+    .. py:method:: update_configuration_file(self, new_conf)
+
+        Update variablevalues in config file  
+        NOTE: this doesn't use standard ConfigParser as that would delete comments  
+
+        :param new_conf: Dictionary with variable, value pair  
+
+    .. py:method:: 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  
+

+ 392 - 0
KCG/Documentation/source/Dev/code/base/kcgwidget.rst

@@ -0,0 +1,392 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: kcgwidget
+
+
+.. _kcgwidget:
+
+
+
+Module kcgwidget
+================
+
+
+Base Classes used in KCG.  
+This module also contains various helpful Classes to make live easier ;)  
+
+.. py:method:: tr(_, x)
+
+    Dummy Translation method that does not translate  
+
+    :param _: unused  
+    :param x: the string to "translate"  
+    :return: x  
+
+.. py:class:: BigIconButton(QtGui.QPushButton)
+
+    This is a Button with a big Icon (that can fill the whole button)  
+
+    .. py:method:: __init__(self, path, width, height, connect=None, tooltip=None, parent=None)
+
+        Setting various properties  
+
+        :param path: (str) the path to the icon  
+        :param width: (int) with of the button  
+        :param height: (int) height of the button  
+        :param connect: (callable) function to call when button is pressed  
+        :param tooltip: (str) tool tip to show  
+        :param parent: (QWidget) parent widget.  
+
+.. py:class:: clickLabel(QtGui.QLabel)
+
+    Clickable Label  
+
+    .. py:method:: mouseReleaseEvent(self, QMouseEvent)
+
+        Reimplementation of QLabel.mouseReleaseEvent to make this clickable  
+
+.. py:class:: ClickableHBoxLayout(QtGui.QHBoxLayout)
+
+    A clickable HBoxLayout  
+
+    .. py:method:: event(self, QEvent)
+
+        Reimplementation of QHBoxLayout.event to make it clickable  
+
+.. py:class:: switchLabel(QtGui.QLabel)
+
+    This implements a Switch.  
+    It switches between left and right.  
+
+    .. py:method:: __init__(self, startRight=False): 
+
+        Initialise switchLabel  
+        As a normal Button it emits the clicked event when clicked.  
+        It does NOT have two events for each side at the moment.  
+
+        :param startRight: (bool) whether the switch is initially set to the right position (default is left (False))  
+
+    .. py:method:: mouseReleaseEvent(self, QMouseEvent)
+
+        Reimplementation of QLabel.mouseReleaseEvent to make it clickable  
+
+.. py:class:: Switch(QtGui.QWidget)
+
+    A Simple Switch  
+
+    .. py:method:: __init__(self, leftLabel, rightLabel, startRight=False)
+
+
+    .. py:method:: state(self)
+
+        Get the state of this switch  
+
+        :return: the state of this switch  
+
+.. py:class:: ClickableSVG(QtGui.QWidget)
+
+    This implements a clickable SVG Image  
+
+    .. py:method:: __init__(self, path, width, height, wwidth=None, wheight=None, parent=None)
+
+        Initialisation of ClickabeSVG  
+
+        :param path: (str) path to the svg file  
+        :param width: (int) width of the svg  
+        :param height: (int) height of the svg  
+        :param wwidth: (int) width of the widget (not the svg)  
+        :param wheight: (int) height of the widget (not the svg)  
+        :param parent: (QWidget) parent widget of the ClickableSVG  
+
+    .. py:method:: mouseReleaseEvent(self, QMouseEvent)
+
+        Reimplementation of QWidget.mouseReleaseEvent to make it clickable  
+
+    .. py:method:: changeSvg(self, path)
+
+        Change the SVG of this widget  
+
+        :param path: (str) path to the new svg file  
+
+.. py:class:: KCGWidgets(QtGui.QWidget)
+
+    Base Class for alsmost all Widgets used in KCG.  
+    It holds various properties as well as methods that simplify creation of certain objects such as labels, buttons ...  
+
+    .. py:method:: __init__(self, name=None, parent=None)
+
+        Initialise this baseclass  
+
+        :param name: (str) name of the widget  
+        :param parent: (QWidget) parent of this widget  
+
+    .. py:method:: theType(self)
+
+        Type of this widget  
+
+    .. py:method:: theId(self)
+
+        ID of this widget  
+
+    .. py:method:: theName(self)
+
+        Name of this widget  
+
+    .. py:method:: theType(self, t)
+
+        Setter for the type of this widget  
+
+        :param t: (int) type  
+
+    .. py:method:: theId(self, i)
+
+        Setter for the id of this widget  
+
+        :param i: (int) id  
+
+    .. py:method:: theName(self, n)
+
+        Setter for the name of this widget  
+
+        :param n: (str) name  
+
+    .. py:method:: createButton(self, text="", x=None, y=None, dimensions=None, tooltip="", connect=False, icon=None)
+
+        Create a Button  
+
+        :param text: (str) Text to display on the button  
+        :param x: (int) x-position  
+        :param y: (int) y-position  
+        :param dimensions: (QSize) dimensions of the button  
+        :param tooltip: (str) tooltip to display  
+        :param connect: (callable) connect the button pressed event to this callable  
+        :param icon: (QIcon) Icon to display on the button  
+
+    .. py:method:: createLabel(self, text=None, image=None, tooltip=None, click=False, connect=None)
+
+        Create a Label  
+
+        :param text: (str) Text to display on this label  
+        :param image: (QPixmap) Image to display on this label  
+        :param tooltip: (str) tooltip to display  
+        :param click: (bool) make this a clickable label?  
+        :param connect: (callable) if click is true, connect the clicked event to this callable  
+
+    .. py:method:: createSpinbox(self, min, max, interval=1, start_value=0, connect=None)
+
+        create a Spinbox  
+
+        :param min: (int) minimum Value  
+        :param max: (int) maximum Value  
+        :param interval: (int) interval  
+        :param start_value: (int) start Value  
+        :param connect: (callable) function to call on value change  
+
+    .. py:method:: createInput(self, text=None, read_only=False, width=None)
+
+        Create Input  
+
+        :param text: (str) Default Text  
+        :param read_only: (bool) set input as read only  
+        :param width: (int) width of the input field in pixels  
+
+    .. py:method:: createCheckbox(self, text="", tooltip="", checked=False, connect=None)
+
+        Create Checkbox  
+
+        :param tooltip: (str) what tooltip text to display  
+        :param checked: (bool) Checkt as default?  
+        :param connect: (callable) function to connect  
+
+    .. py:method:: createSwitch(self, startRight=False, connect=None)
+
+        Create a Switch  
+
+        :param startRight: (bool) if this is True the initial setting is set to right (default is left)  
+        :param connect: (callable) connect the switches clicked event to this callable  
+
+    .. py:method:: closeEvent(self, event)
+
+        Reimplementation of QWidget.closeEvent  
+
+.. py:class:: KCGSubWidget(QtGui.QMdiSubWindow)
+
+    Base Class for Subwindows in the KCG Gui  
+
+    .. py:method:: __init__(self, name=None, unique_id=None, typ=None, minSize=False)
+
+        Initialise a Subwindow  
+
+        :param name: (str) name of this window  
+        :param unique_id: (int) unique id of this window  
+        :param typ: (int) type of this window  
+        :param minSize: (bool) whether the window is to be resized to its minimum size  
+
+    .. py:method:: theType(self)
+
+        Type of this widget  
+
+    .. py:method:: theId(self)
+
+        ID of this widget  
+
+    .. py:method:: theName(self)
+
+        Name of this widget  
+
+    .. py:method:: theType(self, t)
+
+        Setter for the type of this widget  
+
+        :param t: (int) type  
+
+    .. py:method:: theId(self, i)
+
+        Setter for the id of this widget  
+
+        :param i: (int) id  
+
+    .. py:method:: theName(self, n)
+
+        Setter for the name of this widget  
+
+        :param n: (str) name  
+
+.. py:class:: AccordionClickLine(QtGui.QWidget)
+
+    A simple clickable line used in the accordion widget below  
+
+    .. py:method:: __init__(self, text)
+
+
+    .. py:method:: mouseReleaseEvent(self, QMouseEvent)
+
+        Reimplementation of QWidget.mouseReleaseEvent to make it clickable  
+
+    .. py:method:: expand(self, state)
+
+        Expand or deexpand the Accordion entry  
+
+        :param state: True to expand False to deexpand  
+
+.. py:class:: AccordionWidget(QtGui.QWidget):  
+
+    Simple accordion widget similar to QToolBox  
+
+    .. py:method:: __init__(self)
+
+        Initialise the accordion widget  
+
+    .. py:method:: resizeEvent(self, QResizeEvent)
+
+        Reimplementation of QWidget.resizeEvent to make it look nice  
+
+    .. py:method:: addItem(self, widget, text)
+
+        Add a Widget to the Accordion widget  
+
+        :param widget: the widget to add  
+        :param text: the text for this widget  
+
+    .. py:method:: toggleIndex(self, index)
+
+        Toggle the visibility of the widget with index index  
+
+        :param index: the index to toggle  
+
+    .. py:method:: expandIndex(self, index)
+
+        Expand the widget with index index  
+
+        :param index: the index of the widget to show  
+
+    .. py:method:: hideIndex(self, index)
+
+        Hide the widget with the index index  
+
+        :param index: the index of the widget to hide  
+
+    .. py:method:: hideAll(self)
+
+        Hide all widgets  
+
+    .. py:method:: showAll(self)
+
+        Show all widgets  
+
+.. py:class:: MultilineInputDialog(QtGui.QDialog)
+
+    Multiline Input Dialog  
+    When using this dialog, create is and open it with get_text. this also returns the entered text.  
+
+    .. py:method:: __init__(self)
+
+
+    .. py:method:: fill(self, heading, label)
+
+        Fill the widget with elements  
+
+        :param heading: (str) the heading of this widget  
+        :param label: (str) the text to show above the input field  
+
+    .. py:method:: ok(self)
+
+        This gets executed when the ok button is pressed  
+
+    .. py:method:: cancel(self)
+
+        This gets executed when the cancel button is pressed  
+
+    .. py:method:: get_text(self, heading, label)
+
+        This function is the main entry point.  
+
+        :param heading: (str) the heading of the widget  
+        :param label: (str) the text to show above the input field  
+        :return: (unicode) the entered text  
+
+.. py:class:: IdGenerator()
+
+    Generate Unique Id for every subwindow  
+
+    .. py:method:: genid(self)
+
+        Generate a new Id  
+
+
+.. py:method:: register_widget_creation_function(creation_func)
+
+    Register the function to create a certain widget  
+
+    :param creation_func: (callable) function to call when the widget is to be created  
+
+.. py:method:: register_widget(icon, text, target, shortcut=None)
+
+    Register a widget  
+
+    :param icon: (QIcon) Icon to show on the toolbar button  
+    :param text: (str) tooltip for the toolbar button  
+    :param target: (callable) the function to create the widget  
+    :param shortcut: (str) keyboard shortcut to open this widget  
+
+.. py:method:: get_registered_widgets()
+
+    Get the registered widgets  
+
+    :return: (list) list of registered widgets  
+
+.. py:method:: get_registered_widget_functions()
+
+    Get the functions that are registered  
+
+    :return: (list) list of functions  
+
+.. py:method:: error(code, text, severe=False)
+
+    Log an error using the logging module  
+
+    :param code: the error code  
+    :param text: the text to show  
+    :param severe: if it is a severe error that has to quit the program  
+

+ 172 - 0
KCG/Documentation/source/Dev/code/base/leftbar.rst

@@ -0,0 +1,172 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: leftbar
+
+
+.. _leftbar:
+
+
+
+Module leftbar
+==============
+
+
+
+.. py:class:: BoardSpecificInformation(kcgw.KCGWidgets)
+
+    Specific Part for each board  
+
+    .. py:method:: __init__(self, board_id)
+
+        This creates the information part for board with id board_id.  
+        This is used to be able to create a variable number of board information areas.  
+
+        :param board_id: the id of the board  
+
+.. py:class:: AcquisitionAndInfo(kcgw.KCGWidgets)
+
+    Widget to show below the plot list.  
+    Show certain information.  
+    Provide Start Acquisition button and settings.  
+
+    .. py:method:: __init__(self)
+
+
+    .. py:method:: toggle_acquisition(self)
+
+        Turn acquisition on/off. This gets the information about which board to use by checking state of the checkboxes.  
+
+
+    .. py:method:: update_acq_tickboxes(self)
+
+        If at least one checkbox is checked, set all checkboxes with other state (acquiring or not)  
+        to disabled. This prevents the user to start with one board and stop with the other simultaneously.  
+        TODO: add option in settings to allow the now eliminated behaviour  
+
+    .. py:method:: acquisition_stopped(self, board_id)
+
+        This is called when a acquisition is stopped.  
+        (has to be registered in Callbacks under 'acquisition_stopped'  
+
+        :param board_id: id of the board  
+
+    .. py:method:: acquisition_started(self, board_id)
+
+        This is called when a acquisition is started.  
+        (has to be registered in Callbacks under 'acquisition_started'  
+
+        :param board_id: id of the board  
+
+    .. py:method:: do_log_w_comment(self)
+
+        Function to handle logging with comments  
+
+    .. py:method:: log_configure_context_menu(self, event)
+
+        Function that creates the context menu for the log buttons  
+
+        :param event: (QEvent) the event  
+
+    .. py:method:: update_consistency(self, status)
+
+        Set consistency indicator  
+
+        :param status: True if consistent, False if inconsistent, None is nothing  
+
+.. py:class:: LeftBar(kcgw.KCGWidgets)
+
+    Left bar in the main view of the gui.  
+    Shows plot list and acquisition and info panel  
+
+    .. py:method:: __init__(self, parent)
+
+
+    .. py:method:: initUI(self)
+
+        Initialise the UI  
+
+    .. py:method:: _generate_menu(self, menu, item)
+
+        Generate the right click menu  
+
+        :param menu: the menu to add the entries to  
+        :param item: the item that was clicked on  
+
+    .. py:method:: contextMenuEventListView(self, event)
+
+        Gets called when right mouse button is clicked  
+
+        :param event: the event that causes the call of this function  
+
+    .. py:method:: plot_clicked(self, item, i)
+
+        Function to handle when a plot item is clicked.  
+
+        :param item: what item is clicked  
+        :param i: what column  
+
+    .. py:method:: add_plot_tree(self, text=False, unique_id=None, datatype=None)
+
+        Add a top node to the plot list.  
+
+        :param text: (str) text to be displayed in the plot list  
+        :param unique_id: (int) unique id of this top node  
+        :param datatype: (int) live or data from file  
+
+    .. py:method:: read_data(self, d_type, uid, file_name)
+
+        Reads datafile  
+
+        :param d_type: FILE or LIVE - type of datasource  
+        :param uid: unique id for the treeelement  
+        :param file_name: filename if type is FILE  
+
+    .. py:method:: add_plot_node(self, board_id=None, text=False, unique_id=None, d_type=None, datatype=None)
+
+        Actually open a new plot window.  
+
+        :param board_id: the id of the board to which the plot corresponds  
+        :param text: (str) text that is displayed in the plot list  
+        :param unique_id: (int) unique id of this plot window  
+        :param d_type: (int) type of this plot window  
+        :param datatype: (int) live or data from file  
+
+    .. py:method:: remove_plot(self, unique_id, silent=False, close_plot_window=False)
+
+        Removes a plot from the plot list.  
+
+        :param unique_id: (int) the unique id of the plot to remove  
+        :param silent: (bool) Ask to close the plot source node in the list if the last plot window is closed  
+                        (if False the source node will not be closed)  
+        :param close_plot_window: (bool) close the corresponding plot window  
+
+    .. py:method:: remove_plot_tree(self, unique_id, silent=False)
+
+        Remove the top node from the plot list  
+
+        :param unique_id: (int) the id of the top node  
+        :param silent: (bool) ask to close even if corresponding plot windows are open  
+
+    .. py:method:: update_plot(self, uid, b_type, add)
+
+        Updates the plot list when the type of a plot window changes  
+
+        :param uid: (int) unique id of the plot window to update  
+        :param b_type: (int) type of that plot window  
+        :param str add: the add, board and additional text to update  
+
+    .. py:method:: handle_dialog(self, value, diag=None,)
+
+        Function that handles the return of the dialog that asks for live or data from file  
+
+        :param value: (int) the value of the pressed button in the dialog  
+        :param diag: (QDialog) the dialog that is to be closed (optional)  
+
+    .. py:method:: add_plot(self, d_type=None)
+
+        Handles the creation of a plot.  
+        Also shows the dialog that asks for the data source.  
+
+        :param d_type: the type of the plot to add  
+

+ 111 - 0
KCG/Documentation/source/Dev/code/base/log.rst

@@ -0,0 +1,111 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: log
+
+
+.. _log:
+
+
+
+Module log
+==========
+
+
+This is a custom logfile creation module  
+
+.. py:class:: LogLevels:  
+
+    Used Log Levels Container  
+
+.. py:class:: MeasurementLogger(object)
+
+    Logfile creator class  
+    It will automatically get the info needed to create a logfile entry from registered functions.  
+
+    .. py:method:: __init__(self, filename=None, level=LogLevels.INFO, oneline=False)
+
+        Initialise the logfile creator  
+
+        :param filename: (str) filename of the logfile THIS IS IGNORED AS OF NOW  
+        :param level: (int) valid log level (see LogLevels)  
+        :param oneline: (bool) whether to format the logfile entries in multilines or one line  
+
+    .. py:method:: __now(self)
+
+        Get the current time in %Y-%m-%d %H:%M:%S format  
+
+        :return: the time  
+
+    .. py:method:: _logging_formatter(self, info)
+
+        Formatter for the logfile entries  
+        Override this to implement custom formatters  
+
+    .. py:method:: _log(self, board_id, stuff)
+
+        Write entries to logfile  
+        This will also make shure the directory the logfile is located is available and if not creates it  
+
+        :param stuff: (str) the entrie to write  
+
+    .. py:method:: register_parameter(self, logstring, func, args)
+
+        This function is used to register parameters for the logfile entries  
+
+        :param logstring: (str) the string to describe the value in the logfile  
+        :param func: (callable) the function used to get the value  
+        :param args: arguments to pass to func upon gathering of information  
+
+    .. py:method:: reset_parameters(self)
+
+        Resets all parameters (unregisteres all parameters)  
+
+    .. py:method:: register_dumper(self, func)
+
+        Register a dumper that is used to dump a log of data into the logfile  
+
+        :param func: (callable) Function that is used as dumper  
+
+    .. py:method:: dump(self, board_id)
+
+        Perform a dump (see register_dumper)  
+
+
+    .. py:method:: do_log(self, c=None, additional=None, board_id=None, level=LogLevels.INFO)
+
+        Perform a log. This creates a log entry in the logfile  
+
+        :param c: (str) if this is not None this is the only text written to the logfile (in addition to the current time)  
+        :param additional: (str) This text is written below the current time to customize log entries  
+        :param board_id: the id of the board to log for, if this is not given, all boards are logged  
+
+.. py:method:: log(c=None, additional=None, dump=False, board_id=None, level=LogLevels.INFO)
+
+    Execute logging if logger was registered  
+
+    :param (str) c: if this is given c is the only entry that is created (additional is ignored)  
+    :param (str) additional: the additional text that is written below the current time  
+    :param (bool) dump: if this is true, a dump of every log value is performed  
+    :param board_id: the board id to log for, if this is not given, all boards are logged  
+
+.. py:class:: ConfigureLog(QtGui.QDialog)
+
+    Class that is basically a QDialog to configure the logger  
+
+    .. py:method:: __init__(self, parent=None):  
+
+
+    .. py:method:: initial_ticks(self)
+
+        Set the initial ticks.  
+
+    .. py:method:: all_changed(self)
+
+        This is called when the "all" checkbox is checked. It de/activates the other checkboxes  
+
+    .. py:method:: do(self)
+
+        Change the logger instance to the activated log entries  
+
+

+ 69 - 0
KCG/Documentation/source/Dev/code/base/loghandler.rst

@@ -0,0 +1,69 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: loghandler
+
+
+.. _loghandler:
+
+
+
+Module loghandler
+=================
+
+
+
+.. py:class:: LogHandler(logging.Handler)
+
+    Handler Class to configure Logging  
+    This also enables logging to the output field in the gui  
+
+    .. py:method:: __init__(self, log_area)
+
+
+    .. py:method:: emit(self, record)
+
+        Emit a log record  
+
+.. py:class:: Highlighter(QtGui.QSyntaxHighlighter)
+
+    Highlighter for the logging area  
+
+    .. py:method:: __init__(self, parent, theme)
+
+
+    .. py:method:: setKeywords(self, kw)
+
+        Set the keywords to check for  
+
+        :param kw: the keywords  
+
+    .. py:method:: highlightBlock(self, text)
+
+        Highlight a block of text  
+
+        :param text: the text to check in  
+
+.. py:class:: LogArea(QtGui.QTextEdit)
+
+    The log area for the KCG Gui  
+
+    .. py:method:: __init__(self)
+
+
+    .. py:method:: init_logging(self)
+
+        Initialize logging  
+
+    .. py:method:: append(self, record)
+
+        Append to the logarea  
+
+        :param record: the record to append  
+
+    .. py:method:: setKeywords(self, kw)
+
+        Set the keywords for the highlighter  
+
+        :param kw: the keywords to set  
+

+ 64 - 0
KCG/Documentation/source/Dev/code/base/multiWidget.rst

@@ -0,0 +1,64 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: multiWidget
+
+
+.. _multiWidget:
+
+
+
+Module multiWidget
+==================
+
+
+This is the container widget for multiple subwindows  
+
+.. py:class:: WidgetTypeError(Exception)
+
+    Simple error that describes when a wrong window type gets added  
+
+.. py:class:: MDIArea(kcgw.KCGWidgets)
+
+    The MDI Area used by Multiwidget  
+
+    .. py:method:: __init__(self, parent)
+
+
+    .. py:method:: newWidget(self, widget, name, unique_id, widget_type, minSize=False)
+
+        Add a new Widget to the MDIArea  
+
+        :param widget: (subclass of QMdiSubWindow) The widget to show  
+        :param name: (str) name of the window  
+        :param unique_id: (int) unique id of the window  
+        :param widget_type: (int) the type of this window  
+        :param minSize: (bool) whether to shrink the window to minimum size upon creation  
+
+.. py:class:: MultiWidget(QtGui.QWidget)
+
+    The Widget used as Multiwidget. This is the main View during operation with KCG.  
+
+    .. py:method:: __init__(self)
+
+
+    .. py:method:: addToolbarButton(self, icon, text, target, shortcut=None)
+
+        Add a toolbar button.  
+
+        :param icon: (QIcon) The icon to show on the toolbar button  
+        :param text: (str) tooltip for this button  
+        :param target: (callable) The function to call upon press on button  
+        :param shortcut: (str) Keyboard shortcut to call target  
+
+    .. py:method:: evaluate_registered_widgets(self)
+
+        Evaluate all the registered widgets and add a toolbar button for those  
+
+
+    .. py:method:: evaluate_registered_widget_functions(self)
+
+        Evaluate the functions that are registered  
+        Those are in general functions that have to be called after widgets are created  
+
+

+ 106 - 0
KCG/Documentation/source/Dev/code/base/multipage.rst

@@ -0,0 +1,106 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: multipage
+
+
+.. _multipage:
+
+
+
+Module multipage
+================
+
+
+
+.. py:class:: RightSwitch(kcgw.ClickableSVG)
+
+    Buttons to change the Page in a MultiPage  
+
+    .. py:method:: __init__(self, pagesWidget, width=10, height=20, wwidth=None, hidden=False)
+
+        Initialise a RightSwitch  
+
+        :param pagesWidget: (MultiPage) The MultiPage widget to switch pages upon press  
+        :param width: (int) width of the icon shown on the switch  
+        :param height: (int) height of the icon shown on the switch  
+        :param wwidth: (int) Width of the switch  
+        :param hidden: (bool) whether this switch is shown or hidden  
+
+.. py:class:: LeftSwitch(kcgw.ClickableSVG)
+
+    Buttons to change the Page in a MultiPage Widget  
+
+    .. py:method:: __init__(self, pagesWidget, width=10, height=20, wwidth=None, hidden=False)
+
+        Initialise a LeftSwitch  
+
+        :param pagesWidget: (MultiPage) The MultiPage widget to switch pages upon press  
+        :param width: (int) width of the icon shown on the switch  
+        :param height: (int) height of the icon shown on the switch  
+        :param wwidth: (int) Width of the switch  
+        :param hidden: (bool) whether this switch is shown or hidden  
+
+.. py:class:: LeftRightSwitch(QtGui.QWidget)
+
+    Small Buttons to change the Page in a MultiPage Widget  
+
+    .. py:method:: __init__(self, pagesWidget)
+
+        Initialise a combination of left and right switch  
+
+        :param pagesWidget: (MultiPage) The multipage widget instance to change pages on  
+
+    .. py:method:: disable_left(self)
+
+        Disable the switch to the page left of the current one  
+
+
+    .. py:method:: enable_left(self)
+
+        Enable the switch to the page left of the current one  
+
+
+    .. py:method:: disable_right(self)
+
+        Disable the switch to the page right of the current one  
+
+
+    .. py:method:: enable_right(self)
+
+        Enable the switch to the page right of the current one  
+
+
+.. py:class:: MultiPage(QtGui.QStackedWidget)
+
+    Implementation of a Paginated View Widget  
+
+    .. py:method:: __init__(self, parent=None)
+
+
+    .. py:method:: 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  
+
+    .. py:method:: removePage(self, page)
+
+        Removes a page from the pages widget and adjusts switches accordingly  
+
+        :param page: what page to remove  
+
+    .. py:method:: left(self)
+
+
+    .. py:method:: right(self)
+
+
+    .. py:method:: setCurrentIndex(self, p_int)
+
+        Set te current Index of the MultiPage Widget (e.g. set the current page)  
+
+        :param p_int: (int) what page  
+

+ 220 - 0
KCG/Documentation/source/Dev/code/base/plotWidget.rst

@@ -0,0 +1,220 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: plotWidget
+
+
+.. _plotWidget:
+
+
+
+Module plotWidget
+=================
+
+
+This Module implements the Plot Windows used in KCG  
+
+.. py:class:: Enum()
+
+    Simple Enum Class (as this is not supported by clean python)  
+
+    .. py:method:: __init__(self, *args)
+
+
+.. py:class:: CustomGradientEditorItem(pg.GradientEditorItem)
+
+    A Gradient Editor Item to insert a perception linear gradient  
+
+    .. py:method:: __init__(self, **kwargs)
+
+
+    .. py:method:: addGrad(self, name, grad_dic)
+
+        Add a gradient to the list of gradients in the gui  
+
+        :param name: the name of the gradient  
+        :param grad_dic: the dictionary containing the gradient data  
+
+    .. py:method:: restoreState(self, state)
+
+        Reimplemented of pyqtgraph.GradientEditorItem.restoreState to work with our custom perception linear gradient.  
+
+        :param state: the state to restore to  
+
+    .. py:method:: loadPreset(self, name)
+
+        Reimplemented of pyqtgraph.GradientEditorItem.loadPreset to work with our custom perception linear gradient.  
+
+        :param name: the name of the preset to load  
+
+    .. py:method:: tickMoved(self, tick, pos)
+
+        Reimplemented of pyqtgraph.GradientEditorItem.tickMoved to work with our custom perception linear gradient,  
+        which has a lot of steps which would create a lot of ticks in the gradient legend. This removes all but 2  
+        ticks and aligns all the internal ticks accordingly.  
+
+        :param tick: the tick to move  
+        :param pos: the position to move to  
+
+.. py:class:: SpectrogramColorLegendItem(pg.GraphicsWidget)
+
+    The Item used as Legend for Heatmap and FFT Plot  
+
+    .. py:method:: __init__(self, img=None)
+
+        Initialise the Legend  
+
+        :param img: (ImageItem) the image item this is the legend for  
+
+    .. py:method:: gradient_changed(self)
+
+        Proxy function for the gradient_cnahged event of the GradientEditorItem  
+
+
+    .. py:method:: set_image(self, img)
+
+        Set the Image this is the legend for (only needed if not already done upon initialisation)  
+
+        :param img: (ImageItem) The image item to use  
+
+    .. py:method:: update_axis(self)
+
+        Update the axis of this legend  
+
+
+    .. py:method:: reset_gradient(self)
+
+        Reset the gradient to the preset "spectrum"  
+
+
+    .. py:method:: image_changed(self, reset_gradient=True)
+
+        Call this to adjust the legend when the image has changed  
+
+        :param reset_gradient: (bool) whether to reset the gradient or not  
+
+    .. py:method:: getLookupTable(self, nPts, alpha=None)
+
+        Get the look up table of the imageitem  
+
+        :param nPts: (int) number of points the lookup table is defined on  
+        :param alpha: ??  
+
+    .. py:method:: resizeEvent(self, event)
+
+        Handle resizing of the window  
+
+.. py:class:: SubPlotWidget(pg.GraphicsLayoutWidget)
+
+    The Widget actually containing the plots and images  
+
+    .. py:method:: __init__(self, dType=FILE)
+
+
+    .. py:method:: _enableCustomAutoRange(self, data)
+
+        Enable custom auto range in this plot  
+
+        :param data: the data to autorange  
+
+    .. py:method:: _disableCustomAutoRange(self)
+
+        Disable the custom autorange and reset it to default  
+
+
+    .. py:method:: plot(self, data, xvalueborders=None, yvalueborders=None, autorange=True)
+
+        Plot Data. The plot type depends on the type property  
+
+        :param data: (dataset.DataSet) data to plot  
+        :param xvalueborders: (touple) the borders for the xvalues  
+        :param yvalueborders: (touple) the borders for the yvalues  
+        :param autorange: (bool) whether to perform a autorange or not  
+
+    .. py:method:: labelAxes(self)
+
+        Add Labels to the axis depending on the self.plotType property.  
+
+
+    .. py:method:: changeType(self, type)
+
+        Change the plot Type  
+
+        :param type: (int) the new type  
+
+.. py:class:: PlotWidget(kcgw.KCGWidgets)
+
+    The container Class holding various buttons and controls and the actual plots as SubPlotWidgets instance  
+
+    .. py:method:: __init__(self, board_id, parent=None, name=None, unique_id=None, type=None, datatype=None, prefix=None, fName=None, data=None)
+
+        Initialise the Plot Widgt  
+
+        :param parent: (QWidget) the parent widget  
+        :param name: (str) name of this widget  
+        :param unique_id: (int) unique id of this widget  
+        :param type: (int) type of this widget  
+        :param datatype: (int) datatype (LIVE or FILE)  
+        :param prefix: (str) prefix for text in the listview in LeftBar  
+        :param fName: (str) the filename (this is only used if datatype is FILE)  
+        :param data: (dataset.DataSet) the data to be plotted  
+
+    .. py:method:: initUI(self)
+
+        Initialise the UI  
+
+
+    .. py:method:: change_adc(self)
+
+        Change the adc for which data is plotted  
+
+
+    .. py:method:: change_adc_compare(self, who)
+
+        Change the adcs displayed in a compare plot  
+
+
+    .. py:method:: disable_buttons(self, b_bool)
+
+        Disable the buttons on this widget  
+        This is not used at the moment  
+
+        :param b_bool: (bool) disable(False) or enable(True)  
+
+    .. py:method:: changePlotType(self, type)
+
+        Change the plot type to the given type.  
+
+        :param type: the new type  
+
+    .. py:method:: plot(self, type=None)
+
+        Wrapper function to call the correct plot function depending on type  
+
+        :param type: (int) the plot type  
+
+    .. py:method:: plot_live(self, type=None, data=None)
+
+        Function to call when livedata is to be plotted  
+
+        :param type: (int) plot type  
+        :param data: (dataset.DataSet) data to plot  
+
+    .. py:method:: do_plot(self, type, autorange=True)
+
+        Actually perform a plot (this calls SubPlotWidget.plot)  
+
+        :param type: (int) plot type  
+        :param autorange: (bool) whether to perform a autorange upon plot  
+
+    .. py:method:: change_identifier_text(self)
+
+        Change the text that identifies the plot in the left bar  
+
+
+    .. py:method:: closeEvent(self, event)
+
+        Event Handler to handle the event of closing this window  
+
+        :param event: QEvent  
+

+ 72 - 0
KCG/Documentation/source/Dev/code/base/settings.rst

@@ -0,0 +1,72 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: settings
+
+
+.. _settings:
+
+
+
+Module settings
+===============
+
+
+
+.. py:class:: Settings(kcgw.KCGWidgets)
+
+    Settings Window  
+
+    .. py:method:: __init__(self, storage_handler)
+
+        Initialise the Settings Window  
+
+        :param storage_handler: the container class used to store settings  
+
+    .. py:method:: initUI(self)
+
+        Initialise the UI  
+
+    .. py:method:: build_new_setting(self, handle, value)
+
+        Build a new setting.  
+        This will add the setting to the local_storage.  
+
+        :param handle: the handle of the new setting (input field, checkbox etc)  
+        :param value: (str) key for this setting  
+        :return: the handle :)  
+
+    .. py:method:: _read_setting_from_object(self, object)
+
+        Get the value from a settings object  
+
+        :param object: the object to read the value from  
+
+    .. py:method:: _setSettings(self)
+
+        Set the values in the settings window to the current values  
+
+
+    .. py:method:: _apply(self)
+
+        Called when the apply button is pressed. It emits the changed signal if anything was changed  
+
+    .. py:method:: _ok(self)
+
+        Handler for the ok button. It calls _apply and close  
+
+
+    .. py:method:: _cancel(self)
+
+        Handler for the cancel button. It calls close() and discards changed values  
+
+
+    .. py:method:: show(self)
+
+        Shows the window and sets the current values (calls _setSettings)  
+
+
+    .. py:method:: keyPressEvent(self, QKeyEvent)
+
+        Reimplementation of the keyPressEvent of QWidget to close the window on ESC press.  
+

+ 112 - 0
KCG/Documentation/source/Dev/code/base/storage.rst

@@ -0,0 +1,112 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: storage
+
+
+.. _storage:
+
+
+
+Module storage
+==============
+
+
+
+.. py:class:: StorageError(Exception)
+
+    Simple Storage Error Base Class  
+
+.. py:class:: Storage(object)
+
+    Simple Class to store Values and Throw an error if a value is retrieved that has not been stored before.  
+
+    .. py:method:: __init__(self, default=None)
+
+
+    .. py:method:: setdefault(self, key, object)
+
+        Call setdefault on the underlying dictionary and return the result  
+
+        :param key: the key to call setdefault with  
+        :param object: the object to call setdefault with  
+        :return: the return value of setdefault of the dictionary  
+
+    .. py:method:: __setattr__(self, key, value)
+
+
+    .. py:method:: __getattr__(self, item)
+
+
+.. py:method:: get_board_specific_storage(board_id)
+
+    Get the storage instance for a specific board  
+
+    :param board_id: the board to get the storage for  
+    :return: the instance of the storage for the given board  
+
+.. py:class:: ThreadStorage(object)
+
+    Wrapper for QThreads  
+
+    .. py:method:: __init__(self)
+
+
+    .. py:method:: register(self, threaded_object)
+
+        Register a class object to run in a QThread  
+
+        :param threaded_object: the class object  
+
+    .. py:method:: is_registered(self)
+
+        Check if a class for this thread is registered.  
+
+
+    .. py:method:: __start(self)
+
+        This will be registered to the QThread started signal and will call the actual start_method  
+
+
+    .. py:method:: start(self, method_to_run_in_thread)
+
+        Move the class object to a QThread, connect the QThread.started signal to the given method of the  
+        class object  
+
+        :param method_to_run_in_thread: the method to start when starting the QThread  
+
+    .. py:method:: quit(self)
+
+        Quit the thread class (if it has a method to quit)  
+
+
+    .. py:method:: stop(self)
+
+        Call quit and wait to the underlying QThread  
+
+
+    .. py:method:: __getattr__(self, item)
+
+        Get Attributes of the registered class object  
+
+        :param item: the item to get from the class object  
+        :return: the attribute of the class object  
+
+    .. py:method:: connect(self, signal, slot)
+
+        Connect signals of the class object to the given slots  
+
+        :param signal: the signal  
+        :param slot: the slot  
+
+    .. py:method:: disconnect(self, *args)
+
+        Disconnect the given signals  
+
+        :param args: the signals to disconnect  
+
+    .. py:method:: init(self, *args, **kwargs)
+
+        call the threaded objects init method (not __init__) with the passed arguments  
+
+

+ 78 - 0
KCG/Documentation/source/Dev/code/config.rst

@@ -0,0 +1,78 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: config
+
+
+.. _config:
+
+
+
+Module config
+=============
+
+
+Configuration Module.  
+This reads the configuration file and conveniently makes the settings available to KCG  
+
+.. py:class:: NoValueException(Exception)
+
+    Simple Exception that gets thrown when no Value was given in the configuration file  
+
+.. py:class:: MisconfigurationError(Exception)
+
+    Simple Exception to indicate that a misconfiguration was found.  
+
+.. py:method:: leval(string)
+
+    Wrapper arount ast.literal_eval that throws NoValueException if the value was empty  
+
+    :param string:  
+
+.. py:class:: ConfSection(object)
+
+    Class to handle a section in the configuration.  
+
+    .. py:method:: __init__(self, section, settings, config_object, default_config_object=None, log_level=logging.ERROR)
+
+
+    .. py:method:: feed_arguments(self, arg_dict)
+
+        Feed this section with commandline arguments for this section. The given arguments will  
+        override the ones in configuration files.  
+
+        :param arg_dict: the dictionary for all sections  
+
+    .. py:method:: read(self)
+
+        Read and evaluate configuration settings.  
+
+
+.. py:class:: Configuration(object)
+
+    Class to handle configuration  
+
+    .. py:method:: __init__(self, args=None, log_level=logging.INFO)
+
+
+    .. py:method:: parse_command_line(self)
+
+        Parses the command line configuration arguments  
+
+
+    .. py:method:: read(self)
+
+        This function reads the configuration file and the default config fille (in case the  
+        user config file does not contain all values) and adds them as parameters to this module  
+
+
+    .. py:method:: setup(self)
+
+        Check for the user config file and if not exists calls doSetup  
+
+
+    .. py:method:: doSetup(self, rerun=False, parent=None)
+
+        Shows the initial config dialog  
+
+

+ 21 - 0
KCG/Documentation/source/Dev/code/index.rst

@@ -0,0 +1,21 @@
+.. KCG documentation master file, created by
+   sphinx-quickstart on Thu Jan 28 15:25:31 2016.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+KCG Code
+========
+
+Documentation for KCGs Code is entirely generated automatically from docstrings.
+
+For a more in detail insight see the code itself.
+
+Contents:
+
+.. toctree::
+   base/index 
+   widgets/index
+   kcg
+   config
+   __init__
+   :maxdepth: 4

+ 44 - 0
KCG/Documentation/source/Dev/code/kcg.rst

@@ -0,0 +1,44 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: kcg
+
+
+.. _kcg:
+
+
+
+Module kcg
+==========
+
+
+This is the main program for KCG  
+It imports all modules and starts the Gui  
+
+.. py:method:: print_version(verbose=False)
+
+    Print the version of the current used KCG instance  
+
+    :param verbose: print verbose?  
+
+.. py:method:: inject_setting(section, setting, value, args)
+
+    Inject a setting from the command line  
+
+    :param section: the section to inject to  
+    :param setting: the setting to inject  
+    :param value: the value of this setting  
+    :param args: the argparse parsed instance  
+
+.. py:method:: log_type(level)
+
+    Method to validate and cast the log level  
+
+    :param level: the level to validate and cast  
+    :return: a valid logging level  
+
+.. py:method:: run()
+
+    Main Function, gets called when GUI is started  
+
+

+ 15 - 0
KCG/Documentation/source/Dev/code/setup.rst

@@ -0,0 +1,15 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: setup
+
+
+.. _setup:
+
+
+
+Module setup
+============
+
+
+

+ 15 - 0
KCG/Documentation/source/Dev/code/widgets/__init__.rst

@@ -0,0 +1,15 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: __init__
+
+
+.. ___init__:
+
+
+
+Module __init__
+===============
+
+
+

+ 145 - 0
KCG/Documentation/source/Dev/code/widgets/acquiresettings.rst

@@ -0,0 +1,145 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: acquiresettings
+
+
+.. _acquiresettings:
+
+
+
+Module acquiresettings
+======================
+
+
+This Module Is the Acquiresettings subWindow.  
+
+.. py:class:: AcquireSettingsTab(kcgw.KCGWidgets)
+
+    A single tab in the acquire settings window  
+
+    .. py:method:: __init__(self, board_id, same_as_widgets, parent=None)
+
+
+    .. py:method:: build_same_as_list(self)
+
+        Build the list to show in the same-as drop down menu  
+
+
+    .. py:method:: same_as(self)
+
+        Toggle SameAs functionality  
+
+
+    .. py:method:: update_external_trigger(self, state)
+
+        Update the use external trigger tick  
+
+        :param state: the state to set the tick to  
+
+    .. py:method:: use_external_trigger(self, state, update_config=True)
+
+        Set use external trigger to state  
+
+        :param state: the state to set to  
+        :param update_config: true to update the board config  
+
+    .. py:method:: set_value_silent(self, element, value)
+
+        Set a Value silent without notifying observers  
+
+        :param element: what element  
+        :param value: set to what value  
+
+    .. py:method:: tick_silent(self, element, state)
+
+        Tick a tickbox without notifying observers  
+
+        :param element: what tickbox  
+        :param state: (bool) to what state  
+
+    .. py:method:: set_values(self)
+
+        Set Initial Values when creating this Window.  
+        This will read the appropriate Values from the base.backend.board.BoardConfiguration instance used in the gui.  
+
+
+    .. py:method:: on_number_of_orbits_changed(self)
+
+        Handle the change of the number of orbits  
+
+    .. py:method:: on_number_of_skipped_orbits_changed(self)
+
+        Handle the change of the number of skipped orbits  
+
+    .. py:method:: on_count_changed(self)
+
+        Handle the change of the count value  
+
+    .. py:method:: on_wait_changed(self)
+
+        Handle the change of the wait time  
+
+    .. py:method:: on_build_spectrograms_changed(self)
+
+        Handle the change of the build_spectrograms checkbox  
+
+    .. py:method:: on_simulate_pilot_bunch_changed(self)
+
+        Handle the change of the simulate_pilot_bunch checkbox  
+
+    .. py:method:: on_trigger_skip_signals_changed(self, value)
+
+        Handle change of trigger skip signal spinbox  
+
+        :param int value: the value to set trigger_skip to (the number of trigger signals to skip between acquisitions  
+
+    .. py:method:: on_trigger_method_changed(self)
+
+        Handle change of trigger method.  
+
+    .. py:method:: on_trigger_timeout_changed(self, value)
+
+        Handle change of trigger timeout spinbox  
+
+        :param int value: the value to set the trigger_timout to  
+
+    .. py:method:: closeEvent(self, event)
+
+        Event handler to handle the event of closing this window and gracefully delete resources and such  
+
+        :param event: the event to handle (gets passed to by PyQt)  
+
+.. py:class:: AcquireSettings(kcgw.KCGWidgets)
+
+    This is the actual Acquire Settings Window.  
+
+    .. py:method:: __init__(self, unique_id, parent=None)
+
+        Initialise the acquire settings window  
+
+        :param unique_id: the id for thiw widget  
+        :param parent: parent object  
+
+    .. py:method:: show_tab(self, board_id)
+
+        Show the tab for the given board  
+
+        :param board_id: the id of the board to show  
+
+    .. py:method:: closeEvent(self, event)
+
+
+.. py:method:: add_acquire_settings_widget(board_id=None)
+
+    Add this widget to the gui.  
+    This function will actually open the subwindow.  
+
+
+.. py:method:: setValueSilent(key, value)
+
+    Set values without notifying observers  
+
+    :param key: the key  
+    :param value: the value to set  
+

+ 30 - 0
KCG/Documentation/source/Dev/code/widgets/example_widget.rst

@@ -0,0 +1,30 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: example_widget
+
+
+.. _example_widget:
+
+
+
+Module example_widget
+=====================
+
+
+
+.. py:class:: exampleWidget(kcgw.KCGWidgets)
+
+
+    .. py:method:: __init__(self, unique_id, parent)
+
+
+    .. py:method:: pressed(self)
+
+
+    .. py:method:: closeEvent(self, event)
+
+
+.. py:method:: addExampleWidget()
+
+

+ 18 - 0
KCG/Documentation/source/Dev/code/widgets/index.rst

@@ -0,0 +1,18 @@
+.. KCG documentation master file, created by
+   sphinx-quickstart on Thu Jan 28 15:25:31 2016.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Package widgets
+===============
+
+Contents:
+
+.. toctree::
+   acquiresettings
+   singleread
+   example_widget
+   __init__
+   initialconfig
+   timingWidget
+   :maxdepth: 4

+ 80 - 0
KCG/Documentation/source/Dev/code/widgets/initialconfig.rst

@@ -0,0 +1,80 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: initialconfig
+
+
+.. _initialconfig:
+
+
+
+Module initialconfig
+====================
+
+
+This defines the window for initial configuration  
+
+.. py:class:: ConfigEntry(kcgw.KCGWidgets)
+
+    Container for a single entry in the init config window  
+
+    .. py:method:: __init__(self, comm='', conf='', type=str, multiline=False)
+
+        Initialise an entry  
+
+        :param comm: comment  
+        :param conf: configuration option  
+        :param type: data type for this option  
+        :param multiline: if multiline editfield or not  
+
+    .. py:method:: toggle(self)
+
+        Toggle the visibility of the comment  
+
+
+    .. py:method:: set_comment(self, comm)
+
+        Set the comment  
+
+        :param comm:  
+
+    .. py:method:: set_config(self, conf)
+
+        Set the config option  
+
+        :param conf:  
+
+    .. py:method:: validate(self, mark=False)
+
+        Validate if entered value is valid  
+
+        :param mark: mark false entered values?  
+
+    .. py:method:: san(self, val)
+
+        Sanitise string entries (adding " or ' and converting mixed ones)  
+
+        :param val: the value to sanitise  
+        :return: sanitised value and errors  
+
+    .. py:method:: __str__(self)
+
+        Convert this entry to a string that can be saved to a configuration file  
+
+
+.. py:class:: ConfigSetup(kcgw.KCGWidgets)
+
+    This is the Config window  
+
+    .. py:method:: __init__(self, restart=False)
+
+        Initialise this config window  
+
+
+    .. py:method:: save(self)
+
+        Save the configuration entered in the config window to a configuration file  
+        namely: os.path.expanduser("~")+"/.kcg/config.cfg"  
+        This also makes shure the entered information is valid to some level  
+
+

+ 55 - 0
KCG/Documentation/source/Dev/code/widgets/singleread.rst

@@ -0,0 +1,55 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: singleread
+
+
+.. _singleread:
+
+
+
+Module singleread
+=================
+
+
+This Module is the SingleRead window.  
+
+.. py:class:: SingleReadWidget(kcgw.KCGWidgets)
+
+    The actual single read window.  
+
+    .. py:method:: __init__(self, unique_id, parent=None)
+
+        Initialise the single read widget  
+
+        :param unique_id: the id for this widget  
+        :param parent: parent object  
+
+    .. py:method:: on_single_read(self)
+
+        Perform a single read on all boards which ticks are set  
+
+
+    .. py:method:: on_continuous_read(self, state, board_id)
+
+        Toggle function to toggle continuous read when the corresponding button is pressed.  
+
+        :param bool state: True to activate and False to deactivate continuous read for board_id  
+        :param int? board_id: the id of the board to take action with  
+
+    .. py:method:: set_interval(self)
+
+        Set the interval between reads  
+
+    .. py:method:: closeEvent(self, event)
+
+        Event handler to handle the event of closing this window and gracefully delete ids and such  
+
+        :param event: the event to process (gets passed by PyQt)  
+
+.. py:method:: add_single_read_widget()
+
+    Add this widget to the gui.  
+    This function will actually open the subwindow.  
+
+

+ 169 - 0
KCG/Documentation/source/Dev/code/widgets/timingWidget.rst

@@ -0,0 +1,169 @@
+.. This is a autogemerated documentation from python docstrings. It was generated using DStrings2Doc.
+
+
+.. module:: timingWidget
+
+
+.. _timingWidget:
+
+
+
+Module timingWidget
+===================
+
+
+This Module Is the Timingsettings subWindow.  
+
+.. py:class:: timingPlotWidget(kcgw.KCGWidgets)
+
+    The Timescan result plot subwindow.  
+
+    .. py:method:: __init__(self, unique_id, board_id, parent=None)
+
+        Initialises the timing plot window  
+
+        :param unique_id: the id for this window  
+        :param parent: parent object  
+
+    .. py:method:: switch(self)
+
+        Switch Plot types  
+
+
+    .. py:method:: colour_plot(self)
+
+        Initialize Color Plot  
+
+
+    .. py:method:: remove_colour_plot(self)
+
+        Remove the color plot elements  
+
+
+    .. py:method:: line_plot_axis_strings(self, values, scale, spacing)
+
+        Plot to format the strings for the line plot  
+        This is used to override the default tickStrings method of pyqtgraph.AxisItem  
+
+        :param values: See pyqtgraph.AxisItem.tickStrings  
+        :param scale: See pyqtgraph.AxisItem.tickStrings  
+        :param spacing: See pyqtgraph.AxisItem.tickStrings  
+        :return: See pyqtgraph.AxisItem.tickStrings  
+
+    .. py:method:: spacing(self, minVal, maxVal, size)
+
+        Calculate spacing between ticks  
+        This is used to override the default tickSpacing method of pyqtgraph.AxisItem  
+
+        :param minVal: See pyqtgraph.AxisItem.tickSpacing  
+        :param maxVal: See pyqtgraph.AxisItem.tickSpacing  
+        :param size: See pyqtgraph.AxisItem.tickSpacing  
+        :return: See pyqtgraph.AxisItem.tickSpacing  
+
+    .. py:method:: y_axis_strings(self, values, scale, spacing)
+
+        Sets the strings for the y axis  
+
+        :param values:  
+        :param scale:  
+        :param spacing:  
+
+    .. py:method:: line_plot(self)
+
+        Initialise the Line Plot  
+
+
+    .. py:method:: setInputs(self, coarse_input, fine_inputs)
+
+        Register the Inputfields for timing in the timingsettings window  
+
+        :param coarse_input: (QSpinBox) Spinbox for coarse timing settings  
+        :param fine_inputs: (list) List of (QSpinBox)es for fine timing settings  
+
+    .. py:method:: click(self, adc, event)
+
+        Handler for the click event in color plots  
+
+        :param adc: (str) The ADC plot that was clicked on  
+        :param event: (QEvent) the event  
+
+    .. py:method:: plot(self, data=None, levels=None, newTitle=None, maxima=None)
+
+        Plot Data  
+
+        :param data: (numpy 4d array) data to plot  
+        :param levels: (tuple) Min and Max Values for color plot  
+        :param newTitle: (str) The title for the window  
+        :param maxima: (list) Maximum for each adc  
+
+    .. py:method:: closeEvent(self, event)
+
+        Event handler for closing this window  
+
+.. py:class:: timingPart(kcgw.KCGWidgets)
+
+    The actual timing settings window  
+
+    .. py:method:: __init__(self, board_id, parent=None)
+
+        Initialise the timing settings window  
+
+        :param unique_id:  
+        :param parent:  
+
+    .. py:method:: toggleAdc1IndividualDelay(self)
+
+        Toggle to use an individual delay for adc1 or not  
+
+
+    .. py:method:: showTimeScan(self)
+
+        Show the time scan part of this window  
+
+
+    .. py:method:: time_scan(self)
+
+        Toggle timescan and create timingPlotWidget if it doesn't exist  
+
+
+    .. py:method:: setValueSilent(self, element, value)
+
+        Set Values to inputs without notifying observers  
+
+        :param element: the input  
+        :param value: the value  
+
+    .. py:method:: setValues(self)
+
+        Set Values to inputs (initially)  
+
+
+    .. py:method:: closeEvent(self, event)
+
+        Event handler when this window is closed  
+
+    .. py:method:: on_adc_delay_changed(self)
+
+        Handler that gets called when an adc delay gets changed  
+
+.. py:class:: timingWidget(kcgw.KCGWidgets)
+
+    This is the container that holds the tab widget which contains the timing widgets for each board  
+
+    .. py:method:: __init__(self, unique_id, parent=None)
+
+
+    .. py:method:: adjustSizeForTimeScan(self)
+
+        Adjust the size of the widget to accomodate the time_scan part  
+
+
+    .. py:method:: closeEvent(self, event)
+
+
+.. py:method:: addTimingWidget()
+
+    Add this widget to the gui.  
+    This function will actually open the subwindow.  
+
+

+ 1 - 5
KCG/Documentation/source/Dev/index.rst

@@ -7,8 +7,4 @@ KCG - KAPTURE Control Gui is the Graphical user interface for the KAPTURE board.
     :maxdepth: 2
 
     widgets
-    multiWidget
-    kcgwidget
-    groupedelements
-    backendinterface
-    settings
+    code/index

+ 2 - 0
KCG/Documentation/source/Man/index.rst

@@ -6,6 +6,8 @@
 User documentation!
 ===================
 
+.. note:: This is out of date.
+
 .. toctree::
    :maxdepth: 2
 

+ 2 - 2
KCG/Documentation/source/conf.py

@@ -29,7 +29,7 @@ import os
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
 extensions = [
-    'sphinx.ext.mathjax',
+#    'sphinx.ext.mathjax',
 ]
 
 # Add any paths that contain templates here, relative to this directory.
@@ -46,7 +46,7 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'KCG'
-copyright = u'2015, Patrick Schreiber'
+copyright = u'2016, Patrick Schreiber'
 
 rst_epilog = """
 .. |gui_name| replace:: {gui_name}

+ 4 - 2
KCG/Documentation/source/index.rst

@@ -8,10 +8,12 @@ Welcome to KCG's documentation!
 
 This documentation consists of two parts, the user part and the developer part.
 
+.. note:: The user documentation is out of date
+
 The user part gives a brief explanation on how to use the gui during measurements etc.
 
-The developer part gives an overview on how to add custom widgets and gives insight in various interface methods. But keep
-in mind: this is NOT a full documentation of the source code.
+The developer part gives an overview on how to add custom widgets and gives insight in the source code. It is autogenerated
+from docstrings in the code. 
 
 .. toctree::
    :maxdepth: 3

+ 1 - 1
KCG/VERSION

@@ -1 +1 @@
-0.3.2.162.0331-beta
+0.3.2.178.0412-beta

+ 42 - 1
KCG/base/backend/board/actions.py

@@ -9,6 +9,12 @@ from utils import wait_for_revolutions
 
 
 def acquire_data(board_id, filename, simulate=False):
+    """
+    Acquire data. This sets registers and reads data to a file
+    :param board_id: the id of the board to acquire with
+    :param filename: the file to write to
+    :param simulate: whether to use the pilotbunch simulator or not
+    """
     if simulate:
         start_pilot_bunch_emulator(board_id)
 
@@ -21,6 +27,11 @@ def acquire_data(board_id, filename, simulate=False):
 
 
 def data_reset(board_id):
+    """
+    Reset data
+    :param board_id: the board to reset
+    :return:
+    """
     log.vinfo('Data reset')
     pci.write(board_id, '000003f5', hex_mask='7')
     time.sleep(0.05)
@@ -29,24 +40,41 @@ def data_reset(board_id):
 
 
 def flush_dma(board_id, dma='dma0'):
+    """
+    Flush dma. This basically reads data to /dev/null
+    :param board_id: the id to flush dma
+    :param dma: the dma to flush
+    """
     log.vinfo('Flushing DMA Pipeline')
     pci.write(board_id, '03f0', hex_mask='CF0')
-    # TODO: implement identifier usage
     pci.read(board_id, dma=dma, destination='/dev/null')
 
 
 def stop_board(board_id):
+    """
+    Stop a board (turn it off)
+    :param board_id: the board to work with
+    """
     pci.write(board_id, '0x01', '0x9040')
     pci.stop_dma(board_id)
 
 
 def soft_reset(board_id):
+    """
+    Perform a soft reset on the board.
+    :param board_id: the board to reset
+    :return:
+    """
     pci.write(board_id, '0x1', '0x9040', hex_mask='0x1')
     time.sleep(1)
     pci.write(board_id, '0x0', '0x9040', hex_mask='0x1')
 
 
 def start_pilot_bunch_emulator(board_id):
+    """
+    Start the pilot bunch emulator
+    :param board_id: the board to start it for
+    """
     log.vinfo('Start pilot bunch emulator')
     pci.write(board_id, '400003f0', hex_mask='400003F0')
     time.sleep(0.005)
@@ -54,6 +82,10 @@ def start_pilot_bunch_emulator(board_id):
 
 
 def start_acquisition(board_id):
+    """
+    Start an acquisition. This will only tell the board to acquire. It will not read data
+    :param board_id: the id to acquire with
+    """
     log.vinfo('Start acquisition')
     pci.write(board_id, '1', '4', hex_mask='1')  # what's this? write value 1 to register 4???
     time.sleep(0.005)
@@ -61,12 +93,21 @@ def start_acquisition(board_id):
 
 
 def stop_acquisition(board_id):
+    """
+    Stop an acquisition. This will only stop the acquisition on the board.
+    :param board_id: the board to stop for
+    """
     log.vinfo('Stop acquisition')
     pci.write(board_id, '003f0', hex_mask='CF0')
     time.sleep(0.005)
 
 
 def enable_transfer(board_id):
+    """
+    Enable data transfer. This will not transfer data.
+    :param board_id: the id of the board to transfer data from
+    :return:
+    """
     log.vinfo('Enable data transfer')
     pci.write(board_id, '007f0', hex_mask='CF0')
     time.sleep(0.005)

+ 103 - 0
KCG/base/backend/board/board_config.py

@@ -12,6 +12,9 @@ from .... import config as kcg_config
 
 
 class BoardConfiguration(QtGui.QWidget):
+    """
+    The Main configuration class for boards.
+    """
     callback_signal = QtCore.pyqtSignal(str, list)
 
     def __init__(self, identifier, config_file=None):
@@ -28,6 +31,9 @@ class BoardConfiguration(QtGui.QWidget):
             self.load_config(config_file)
 
     def _set_defaults(self):
+        """
+        Set default values
+        """
         self._config ={
             'fpga_delay_max': 15,
             'fpga_delay': 0,
@@ -68,11 +74,17 @@ class BoardConfiguration(QtGui.QWidget):
         }
 
     def set_default_observers(self):
+        """
+        Set observers that are always used
+        """
         self.observe(None, self.update_header, 'header')
         self.observe(None, lambda x: pci.write(self.identifier, hex(x), '0x9020'), 'orbits_observe')
         self.observe(None, lambda x: pci.write(self.identifier, hex(x), '0x9028'), 'orbits_skip')
 
     def notify_all_observers(self):
+        """
+        Notify all observers not only the ones that are affected by a change
+        """
         for key, value in self._config.items():
             self._notify_observers(key, value)
             # observers = self._observers.get(key, None)
@@ -82,6 +94,11 @@ class BoardConfiguration(QtGui.QWidget):
 
 
     def load_config(self, filename):
+        """
+        Load a config from a file
+        :param filename: the configuration file
+        :return:
+        """
         if filename:
             config = ConfigParser.RawConfigParser()
             if not config.read(str(filename)):
@@ -103,6 +120,10 @@ class BoardConfiguration(QtGui.QWidget):
             return False
 
     def save_config(self, filename):
+        """
+        Save the current configuration to a file
+        :param filename: the file to write to
+        """
         if filename:
             # with open(filename, 'w') as f:
             try:
@@ -129,24 +150,49 @@ class BoardConfiguration(QtGui.QWidget):
             return False
 
     def get(self, key):
+        """
+        Get the configuration value for key
+        :param key: the key to get the value for
+        :return: the value of the configuration for key
+        """
         if not key in self._config:
             raise NoSuchKeyError(key+" is not registered in BoardConfiguration for board "+str(self.identifier))
         return self._config.get(key, None)
 
     def dump(self):
+        """
+        Dump all configuration values
+        :return: all configuration values as list
+        """
         s = ""
         for key in self._config.keys():
             s += key + ": " + str(self.get(key)) + ", "
         return s[:-1]
 
     def update(self, key, value):
+        """
+        Update the value for key in the configuration
+        :param key: the key to update
+        :param value: the value to set the configuration for key to
+        """
         self._config[key] = value
         self._notify_observers(key, value)
 
     def updateSilent(self, key, value):
+        """
+        Update the configuration without notifying observers
+        :param key: the key to updae
+        :param value: the value to set the configuration of key to
+        """
         self._config[key] = value
 
     def observe(self, who, callback, key):
+        """
+        Register an observer. (A callback that is called when the according configuration value changes)
+        :param who: who is observing
+        :param callback: the callback to call on change of the configuration value
+        :param key: the key to observe
+        """
         if key not in self._config.keys():
             raise ObserverError(str("Key '%s' is unknown." % key))
 
@@ -156,12 +202,21 @@ class BoardConfiguration(QtGui.QWidget):
         self._observers[key].append([who, callback])
 
     def observe_all(self, callback):
+        """
+        Register a observer that is called when any key changes
+        :param callback: the callback to register
+        """
         if callback not in self._observers_for_all:
             self._observers_for_all.append(callback)
         else:
             raise ObserverError("Observer already registered")
 
     def unobserve(self, who, key=None):
+        """
+        Remove an observer
+        :param who: the observing entity
+        :param key: the key to remove it from
+        """
         if key is not None:
             observers = np.array(self._observers.get(key, None))
             if observers is None:
@@ -183,10 +238,19 @@ class BoardConfiguration(QtGui.QWidget):
                         del self._observers[_key]
 
     def unobserve_all_observer(self, callback):
+        """
+        Unobserve an observer that observes all keys.
+        :param callback: the callback to unobserve
+        """
         if callback in self._observers_for_all:
             del self._observers_for_all[self._observers_for_all.index(callback)]
 
     def _notify_observers_receiver(self, key, value):
+        """
+        The pyqt signal slot for notifications of observers
+        :param key: the key that changed
+        :param value: the new value
+        """
         observers = self._observers.get(str(key), None)
         value = value[0]
         if observers is None:
@@ -198,9 +262,21 @@ class BoardConfiguration(QtGui.QWidget):
             cb(key, value)
 
     def _notify_observers(self, key, value):
+        """
+        Notify observers. This emits a pyqt signal to make it thread save
+        :param key: the key that changed
+        :param value: the new value
+        """
         self.callback_signal.emit(key, [value])
 
     def make_uint(self, value, maximum, name=None):
+        """
+        Convert a value to an uint
+        :param value: the value
+        :param maximum: the maximum of the returned value
+        :param name: the name of this value
+        :return: the converted value
+        """
         if value is None:
             raise ValueError(str("%s Value is invalid (None)" % name))
 
@@ -220,6 +296,10 @@ class BoardConfiguration(QtGui.QWidget):
         return val
 
     def set_fpga_delay(self, value):
+        """
+        Set the fpga_delays on the board
+        :param value: the value to set the delays to
+        """
         time_factor = self.make_uint(value, self.get('fpga_delay_max'), 'FPGA_Delay')
         reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "0"
         pci.write(self.identifier, reg_value, '0x9060')
@@ -227,6 +307,11 @@ class BoardConfiguration(QtGui.QWidget):
         self.update('fpga_delay', value)
 
     def set_chip_delay(self, adcs, values):
+        """
+        Set the chip_delays on the board
+        :param adcs: the adcs to set the delays for
+        :param values: the value to set the delays to
+        """
         if not adcs or not values:
             logging.vinfo("Nothing to do for chip delay.")
             return
@@ -268,6 +353,10 @@ class BoardConfiguration(QtGui.QWidget):
             self.update(s, value)
 
     def set_th_delay(self, value):
+        """
+        Set the track and hold delay on the board
+        :param value: the value to set the delay to
+        """
         time_factor = self.make_uint(value, self.get('th_delay_max'), 'TH_Delay')
         reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "3"
         pci.write(self.identifier, reg_value, '0x9060')
@@ -275,6 +364,11 @@ class BoardConfiguration(QtGui.QWidget):
         self.update('th_delay', value)
 
     def set_adc_delay(self, adc, value):
+        """
+        Set the adc delay for the given adc on the board
+        :param adc: the adc to change the delay for
+        :param value: the value to set the delay to
+        """
         if adc is None or value is None:
             logging.vinfo("Nothing to do for ADC delay.")
             return
@@ -288,7 +382,13 @@ class BoardConfiguration(QtGui.QWidget):
         self.update(adc_s, _val)
 
     def set_delay(self, n, ignore_seperate_delay=False):
+        """
+        Set delays
+        :param n: ?
+        :param ignore_seperate_delay: ignore the setting of a seperate delay for adc 1
+        """
         def write_delay(value, channel):
+            '''write the delays to the board'''
             cmd = '00501' + '%01x' % value + str(channel)
             pci.write(self.identifier, cmd, reg='0x9060')
             time.sleep(0.005)
@@ -342,6 +442,9 @@ class BoardConfiguration(QtGui.QWidget):
             logging.error("Error in Board Communication, was unable to write value to board "+reason)
 
     def read_from_board(self):
+        """
+        Read values from board and update them in the configuration (Mainly used for skip init functionality)
+        """
         try:
             settings = ['chip_1_delay','chip_2_delay','chip_3_delay','chip_4_delay']
             # --[ read fine/chip delays ]

+ 13 - 2
KCG/base/backend/board/boards_connected.py

@@ -57,8 +57,8 @@ class BoardsConnected(object):
             return dict_.get(what, what)
 
         if config.board_detection_method == 'dev':
-            # searchstring = '/dev/fpga'
-            searchstring = '/dev/lp'
+            searchstring = '/dev/fpga'
+            # searchstring = '/dev/lp'
             device_list = glob.glob(searchstring+'*')
             log.info("Found {num} devices.".format(num=len(device_list)))
 
@@ -85,6 +85,17 @@ class BoardsConnected(object):
 
         self._board_ids_reverse = {v: k for k, v in self._board_ids.items()}  # build reverse look up
 
+    @property
+    def has_boards(self):
+        """
+        Check if at least one board is connected
+        """
+        if len(self.board_ids) == 1 and self._board_ids[0] is None:
+            return False
+        elif len(self.board_ids) > 0:
+            return True
+        else:
+            return False
 
     @property
     def board_ids(self):

+ 15 - 6
KCG/base/backend/board/communication.py

@@ -11,10 +11,18 @@ from ...kcgwidget import error
 
 
 class PCI(object):
+    """
+    The Interface to the pci command
+    """
     def __init__(self):
         pass
 
     def _safe_call(self, cmd):
+        """
+        Actually call the pci command
+        :param cmd: the command line to execute as list
+        :return: the output of the command
+        """
         log.debug(cmd)
         try:
             # if '-r' in cmd:
@@ -31,6 +39,11 @@ class PCI(object):
                 raise BoardError('{}: {}'.format(' '.join(cmd), str(e)))
 
     def _format(self, output):
+        """
+        Format output values (remove unnecessary parts of the output)
+        :param output: the unformatted output
+        :return: the formatted output
+        """
         output = output.split("\n")
         lines = []
         for line in output:
@@ -73,7 +86,7 @@ class PCI(object):
         if reg:
             cmd_extend = ["-s%i" % amount]
         else:
-            cmd_extend = ['-o', dst, '--multipacket']
+            cmd_extend = ['--multipacket', '-o', dst]
             if timeout:
                 cmd_extend.extend(['--timeout', str(timeout)])
             log.vinfo('Write data to {}'.format(dst))
@@ -99,8 +112,6 @@ class PCI(object):
         else:
             if dst == '/dev/stdout':
                 return output.split('Writting')[0]
-            else:
-                self.write(board_id, '003f0', hex_mask='CF0')  # what does this do?
 
     def write(self, board_id, value, reg='0x9040', hex_mask='FFFFFFFF'):
         """
@@ -126,7 +137,7 @@ class PCI(object):
 
         cmd = ['pci', '-d', available_boards.get_device_file(board_id), '-w', reg, value]
         self._safe_call(cmd)
-        log.debug('Written %str to register %s' % (value, reg))
+        log.debug('Written %s to register %s' % (value, reg))
 
     def read_data_to_file(self, board_id, filename, dma='dma0', timeout=None):
         """
@@ -159,7 +170,6 @@ class PCI(object):
         :param dma: the dma to use
         :return:
         """
-        # TODO: implement identifier usage
         log.vinfo('Start DMA')
         cmd = ['pci', '-d', available_boards.get_device_file(board_id), '--start-dma', dma]
         self._safe_call(cmd)
@@ -173,7 +183,6 @@ class PCI(object):
         :param dma: the dma to use
         :return:
         """
-        # TODO: implement identifier usage
         log.vinfo('Stop DMA')
         cmd = ['pci', '-d', available_boards.get_device_file(board_id), '--stop-dma', dma]
         self._safe_call(cmd)

+ 15 - 0
KCG/base/backend/board/errors.py

@@ -2,21 +2,36 @@
 Errors for board actions
 """
 class BoardError(Exception):
+    """
+    A General Error with the Board
+    """
     pass
 
 
 class InterfaceNotFoundError(Exception):
+    """
+    Error if not pci command was found
+    """
     pass
 
 
 class ObserverError(Exception):
+    """
+    Error in Observation of configuration values
+    """
     pass
 
 
 class NoBoardId(Exception):
+    """
+    Error if not board id was given
+    """
     pass
 
 
 class NoSuchKeyError(Exception):
+    """
+    Error if a key is requested that does not exist in configuration
+    """
     pass
 

+ 12 - 0
KCG/base/backend/board/sequences.py

@@ -12,6 +12,9 @@ from utils import *
 
 
 def startup_sequence(board_id):
+    """
+    Star the board
+    """
     NUMBER = 4
     yield NUMBER
 
@@ -34,6 +37,9 @@ def startup_sequence(board_id):
 
 
 def calibration_sequence(board_id):
+    """
+    Calibrate the board
+    """
     NUMBER = 15
     yield NUMBER
 
@@ -99,6 +105,9 @@ def calibration_sequence(board_id):
 
 
 def synchronisation_sequence(board_id):
+    """
+    Synchronize the board
+    """
     NUMBER = 2
     yield NUMBER
 
@@ -110,6 +119,9 @@ def synchronisation_sequence(board_id):
     yield True
 
 def write_value_sequence(board_id):
+    """
+    Write values to the board
+    """
     NUMBER = 8
     yield NUMBER
 

+ 33 - 0
KCG/base/backend/board/utils.py

@@ -9,9 +9,17 @@ from errors import *
 from status import StatusStorage
 from board_config import BoardConfiguration
 from .... import config as kcg_config
+from boards_connected import available_boards
 
 
 def get_dec_from_bits(bits, msb=-1, lsb=-1):
+    """
+    Get decimal values from a string represented binary string
+    :param bits: the string to convert
+    :param msb: the most significant bit to use
+    :param lsb: the least significant bit to use
+    :return: the decimal value
+    """
     rtrnValue = 0
     if (msb < 0 or lsb < 0):
         rtrnValue = int(bits)
@@ -101,6 +109,11 @@ def get_status(board_id):
 
 
 def is_conneced(board_id):
+    """
+    Is the board connected?
+    :param board_id: the id for the board to check
+    :return: True if the board is connected else False
+    """
     try:
         pci.read(board_id, 1, '0x9040')
         return True
@@ -111,12 +124,22 @@ def is_conneced(board_id):
 
 
 def is_active(board_id):
+    """
+    Check if a board is active
+    :param board_id: the board to check for
+    :return: True if it is active else False
+    """
     control = pci.read(board_id, 1, '0x9040')[0]
     control_bits = '{0:032b}'.format(int(control, 16))
     return control_bits[22:26] == "1111"
 
 
 def wait_for_revolutions(board_id):
+    """
+    Sleep as long as the revolutions in the accelerator last to not stop the acquisition before it ended.
+    :param board_id: the board to wait for?
+    :return:
+    """
     n = pci.read(board_id, 1, '0x9020', decimal=True)[0]  # Get the amount of orbits to observe
     # n = 1 # Use this for debugging purposes if no board is connected
     spin_time_ns = kcg_config.tRev * n
@@ -140,8 +163,18 @@ def create_new_board_config(identifier):
 
 
 def get_board_config(id):
+    """
+    Get the configuration instance for the board with the given id
+    :param id: the id of the desired board
+    :return: the instance of configuration
+    """
     return _configs[id]
 
 
 def get_board_status(id):
+    """
+    Get the status storage instance for the board with the given id
+    :param id: the id of the desired board
+    :return: the instance of the status storage
+    """
     return _status[id]

+ 72 - 28
KCG/base/backendinterface.py

@@ -1,7 +1,7 @@
 """
 This is the interface to the backend.
 It is used to make the backend easily interchangable.
-All Functions that interface directly with the backend are prefixed with be_
+All Functions that interface directly with the backend are prefixed with bk\_
 Functions only used internal in this module will be prefixed _bif_
 """
 
@@ -90,6 +90,11 @@ def _bif_continuous_read_is_enabled(board_id, popup_title_text=None):
 
 
 def bk_status_readout():
+    """
+    Read Status for every connected board
+    """
+    if not available_boards.has_boards:
+        return
     for brd in available_boards.board_ids:
         _bif_status_readout(brd)
 
@@ -137,10 +142,8 @@ class PopupDialog(QtGui.QDialog):
         QtGui.QDialog.__init__(self, parent)
         self.text = text
         self.setWindowTitle(title if title else tr("Dialog", "User action required"))
-        self.do_layout()
         self.return_value = False
 
-    def do_layout(self):
         size = QtCore.QSize(200, 200)
         # self.setMaximumSize(size)
         self.setMinimumSize(size)
@@ -160,13 +163,24 @@ class PopupDialog(QtGui.QDialog):
         self.setLayout(box)
 
     def on_okay(self):
+        """
+        Handler for the press of the ok button
+        """
         self.return_value = True
         self.close()
 
     def on_cancel(self):
+        """
+        Handler for the press of the cancel button
+        :return:
+        """
         self.close()
 
     def get_return_value(self):
+        """
+        Get True if the Window was closed with OK else False
+        :return: True if OK else False
+        """
         return self.return_value
 
 
@@ -305,6 +319,10 @@ def bk_calibrate(board_id, do_the_rest=None):
         finished = QtCore.pyqtSignal()
 
         def calibrate(self):
+            """
+            The method that is called inside the thread and that does the calibration
+            :return:
+            """
             try:
                 logging.info('Started Board Calibration')
                 for idx, step in enumerate(sequence):
@@ -321,6 +339,10 @@ def bk_calibrate(board_id, do_the_rest=None):
             self.finished.emit()
 
     def thread_quit():
+        """
+        Method to handle the end of the calibration thread
+        :return:
+        """
         thread.stop()
         bk_status_readout()
         progressbar.remove(0)
@@ -791,6 +813,7 @@ def _bif_start_acquisition(board_id):
     storage.get_board_specific_storage(board_id).acquisition_progressbar.setValue(storage.storage.current_acquisition[board_id])
 
     def on_timeout():
+        '''Handler for the timeout of the acquisition timer. This does the acquisition'''
         if storage.storage.current_acquisition[board_id] < num_acquisitions:
             storage.storage.current_acquisition[board_id] += 1
             storage.get_board_specific_storage(board_id).acquisition_progressbar.setValue(storage.storage.current_acquisition[board_id])
@@ -898,7 +921,7 @@ def _bif_read_data(board_id):
         data_raw = board.pci.read_data_to_variable(board_id)
         _bif_read_and_update_data_from_string(board_id, data_raw)
     except board.BoardError as e:
-        logging.error("Reading failed: {}".format(str(e)))  # TODO: board id
+        logging.error("Reading failed for board {}: {}".format(str(board_id), str(e)))
 
 
 def bk_board_connected(board_id):
@@ -907,10 +930,10 @@ def bk_board_connected(board_id):
     :param board_id: id of the board do manipulate
     :return: -
     """
-    # return board.is_conneced(board_id)
-    if len(available_boards.board_ids) > 0:
-        return True
-    return False
+    if not available_boards.has_boards:
+        return False
+    else:
+        return board_id in available_boards.board_ids
 
 
 def bk_get_temperature(board_id):
@@ -1027,6 +1050,7 @@ def _bif_start_time_scan(board_id, c_frm, c_to, f_frm, f_to, timescan_progressba
     timescan_progressbar.setRange(1, ((f_to - f_frm) + 1) * ((c_to - c_frm) + 1))
 
     class thread_time_scan(QtCore.QObject):
+        '''Timescan Thread class'''
         pbarSignal = QtCore.pyqtSignal(int)
         stopSignal = QtCore.pyqtSignal()
         finished = QtCore.pyqtSignal()
@@ -1040,6 +1064,7 @@ def _bif_start_time_scan(board_id, c_frm, c_to, f_frm, f_to, timescan_progressba
             self.timescan_progressbar = timescan_progressbar
 
         def time_scan(self):
+            '''Method to run in the thread that does the timescan'''
             Elements.setEnabled('acquire_{}'.format(board_id), False, exclude=Elements.getElements('start_time_scan_{}'.format(board_id)))
             if orbits_observe:
                 if not hasattr(storage.storage, 'orbits_observe_before_timescan'):
@@ -1096,7 +1121,6 @@ def _bif_start_time_scan(board_id, c_frm, c_to, f_frm, f_to, timescan_progressba
                         # This information has to be removed here.
                         # To do so we split the output string from PCI at "Writting" (Note: Writting is correct as
                         # this is a typo in the PCI driver)
-                        # TODO: does this need board_id? (was there)
                         data = io.read_from_string(data_raw, force=True, cache=False)
                     except board.BoardError as e:
                         self.stopSignal.emit()
@@ -1126,6 +1150,7 @@ def _bif_start_time_scan(board_id, c_frm, c_to, f_frm, f_to, timescan_progressba
             self.finished.emit()
 
     def finished(timescan_progressbar):
+        '''Method to handle the end of the thread'''
         thread.stop()
         _bif_stop_time_scan(board_id, timescan_progressbar)
         Elements.setEnabled('acquire_{}'.format(board_id), True, exclude=Elements.getElements('start_time_scan_{}'.format(board_id)))
@@ -1201,13 +1226,13 @@ def bk_check_for_board(board_id):
     :param board_id: id of the board do manipulate
     :return: -
     """
-    global bk_status_readout, bk_get_temperature
+    # global bk_status_readout, bk_get_temperature
     board_status = bk_board_connected(board_id)
     if board_status:
         if not hasattr(board.get_board_status(board_id), 'board_connected') or \
                 not board.get_board_status(board_id).board_connected:
-            bk_status_readout = backup_readout
-            bk_get_temperature = backup_get_temp
+            globals()['bk_status_readout'] = backup_readout
+            globals()['bk_get_temperature'] = backup_get_temp
         board.get_board_status(board_id).board_connected = True
 
     else:
@@ -1219,8 +1244,8 @@ def bk_check_for_board(board_id):
         def no_temp(board_id):
             return "-"
 
-        bk_status_readout = do_nothing
-        bk_get_temperature = no_temp
+        globals()['bk_status_readout'] = do_nothing
+        globals()['bk_get_temperature'] = no_temp
         board.get_board_status(board_id).board_connected = False
         if board_status == False:
             board.get_board_status(board_id).status_text = tr("sw", "Board {} not connected".format(board_id))
@@ -1246,6 +1271,7 @@ def bk_toggle_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, tim
     if thread.running:
         # Elements.getElements("acquireTrigger_{}".format(board_id))[0].setText(tr("Button", "Start Acquisition"))
         log(board_id=board_id, additional="Stop wait on trigger on board {}".format(board_id))
+        thread.quit()
         thread.stop()
         # for elem in Elements.getElements("acquire_{}".format(board_id)):
         #     if isinstance(elem, QtGui.QShortcut):
@@ -1299,8 +1325,8 @@ def _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, ti
     board.pci.write(board_id, hex(num_of_acquisitions), "9024")
     time.sleep(0.1)
     board.pci.write(board_id, hex(skip), "902C")
-    time.sleep(0.1)
-    board.pci.write(board_id, 'ff0', hex_mask='ff0')  # TODO: This writes t/h 3/4 but enable_transfer etc do not
+    # time.sleep(0.1)
+    # board.pci.write(board_id, 'ff0', hex_mask='ff0')  # TODO: This writes t/h 3/4 but enable_transfer etc do not
 
     # This seems to sometimes lead to segfaults of python it self. An Idea to prevent this
     # is to use copy.deepcopy in __init__. But there is no reason to think that that causes the problem. In fact
@@ -1311,13 +1337,21 @@ def _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, ti
     # Something that is likely to cause the problem is the log.debug in board.safe_call
     # Logging (using the logging module) is directly connected to the main thread and could cause problems
     class thread_wait_on_signal(QtCore.QObject):
+        '''Class to run the wait on signal functionality in a thread'''
         countUpdate = QtCore.pyqtSignal(int)
         stopSignal = QtCore.pyqtSignal()
         finished = QtCore.pyqtSignal()
-        liveplot = QtCore.pyqtSignal(str)
+        liveplot = QtCore.pyqtSignal(int, str)  # This has to be changed if board_id is no integer
 
-        def __init__(self, num_of_acquisitions, path, timeout):
+        def __init__(self):
             super(thread_wait_on_signal, self).__init__()
+            self.noa = None
+            self.path = None
+            self.timeout = None
+            self._quit = False
+
+        def init(self, num_of_acquisitions, path, timeout):
+            '''initialise a new run'''
             self.noa = num_of_acquisitions
             self.path = path
             self.timeout = timeout
@@ -1326,14 +1360,14 @@ def _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, ti
             # Elements.setEnabled('acquireTrigger_{}'.format(board_id), False) # exclude=Elements.getElements('wait_on_trigger_{}'.format(board_id)))
 
         def wait_rw_simul(self):
+            '''Wait simultaniously (with the pci command) for a trigger signal'''
             board.pci.write(board_id, 'ff0', hex_mask='ff0')  # TODO: This writes t/h 3/4 but enable_transfer etc do not
             for num_of_acq in xrange(self.noa):
                 # def step():
                 filename = self.path +'/{:0.3f}.out'.format(time.time())
                 board.pci.read_data_to_file(board_id, filename=filename, timeout=(self.timeout*1000000))
                 # rename with correct timestamp - last modified time
-                # TODO: Exception handling when pci does not create file
-                self.countUpdate.emit(num_of_acquisitions + 1)
+                self.countUpdate.emit(num_of_acq + 1)
                 if self._quit:
                     break
 
@@ -1343,20 +1377,21 @@ def _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, ti
                     continue
 
                 newfile = '{path}/trigger_{num:05}_{htime}_{unixtime}.out'.format(
-                    num=num_of_acquisitions,
+                    num=num_of_acq,
                     htime=dt.fromtimestamp(os.path.getmtime(filename)).strftime('%Y-%m-%dT%Hh%Mm%Ss%f'),
                     unixtime=int(os.path.getmtime(filename)),
                     path=self.path
                 )
                 os.rename(filename, newfile)
                 if os.path.getsize(newfile) > 0:
-                    self.liveplot.emit(newfile)
+                    self.liveplot.emit(board_id, newfile)
                 else:
                     logging.info("Acquired 0b, possible trigger timeout.")
 
             self.finished.emit()
 
         def wait_rw_seq(self):
+            '''Wait sequentially (in the gui) for a trigger signal'''
             for num_of_acq in xrange(self.noa):
                 board.pci.write(board_id, '00bf0', hex_mask='CF0')  # enable readout
                 pre_acq_num = board.pci.read(board_id, 1, '9034')[0]
@@ -1374,7 +1409,7 @@ def _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, ti
                     board.pci.write(board_id, '007f0', hex_mask='CF0')  # enable transfer
                     filename = self.path +'/{:0.3f}.out'.format(time.time())
                     board.pci.read_data_to_file(board_id, filename=filename, timeout=(self.timeout*1000000))
-                    board.pci.write(board_id, '000f0', hex_mask='4F0') # disable transfer
+                    # board.pci.write(board_id, '000f0', hex_mask='4F0') # disable transfer
                     self.countUpdate.emit(copy.deepcopy(num_of_acq+1))
                     if self._quit:
                         break
@@ -1384,13 +1419,13 @@ def _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, ti
                         continue
 
                     newfile = '{path}/trigger_{num:05}_{htime}_{unixtime}.out'.format(
-                        num=num_of_acquisitions,
+                        num=num_of_acq,
                         htime=dt.fromtimestamp(os.path.getmtime(filename)).strftime('%Y-%m-%dT%Hh%Mm%Ss%f'),
                         unixtime=int(os.path.getmtime(filename)),
                         path=self.path
                     )
                     os.rename(filename, newfile)
-                    self.liveplot.emit(newfile)
+                    self.liveplot.emit(board_id, newfile)
                 else:
                     logging.info("Trigger timeout.")
 
@@ -1398,9 +1433,11 @@ def _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, ti
             self.finished.emit()
 
         def quit(self):
+            '''quit this thread'''
             self._quit = True
 
         def __del__(self):
+            print 'quite'
             board.pci.write(board_id, '0', '9024')
             time.sleep(0.1)
             board.pci.write(board_id, '0', '902C')
@@ -1408,6 +1445,7 @@ def _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, ti
             board.pci.write(board_id, '3f0', hex_mask='ff0')  # TODO: This writes t/h 3/4 but enable_transfer etc do not
 
     def finished():
+        '''Handle the end of the thread'''
         board.pci.write(board_id, '0', '9024')
         time.sleep(0.1)
         board.pci.write(board_id, '0', '902C')
@@ -1430,9 +1468,15 @@ def _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, ti
 
         return
 
-    twt = thread_wait_on_signal(num_of_acquisitions, storage.storage.save_location + '/' + storage.storage.subdirname,
-                                timeout)
-    thread.register(twt)
+    # twt = thread_wait_on_signal(num_of_acquisitions, storage.storage.save_location + '/' + storage.storage.subdirname,
+    #                             timeout)
+    if not thread.is_registered():
+        twt = thread_wait_on_signal()
+        thread.register(twt)
+    else:
+        thread.disconnect('countUpdate', 'finished', 'liveplot')
+    thread.init(num_of_acquisitions, storage.storage.save_location + '/' + storage.storage.subdirname, timeout)
+    # reconnect signals to make sure the correct versions of methods are called
     thread.connect('countUpdate', storage.get_board_specific_storage(board_id).trigger_progressbar.setValue)
     thread.connect('finished', finished)
     thread.connect('liveplot', _bif_read_and_update_data_from_file)

+ 22 - 4
KCG/base/controlwidget.py

@@ -134,19 +134,27 @@ class StatusLED(QtGui.QWidget):
         self.setLayout(self.layout)
 
     def set_on(self):
-        """ See set_on of LED Class """
+        """
+        See set_on of LED Class
+        """
         self.led.set_on()
 
     def set_off(self):
-        """ See set_off of LED Class """
+        """
+        See set_off of LED Class
+        """
         self.led.set_off()
 
     def set_out(self):
-        """ See set_out of LED Class """
+        """
+        See set_out of LED Class
+        """
         self.led.set_out()
 
     def set_tri(self):
-        """ See set_tri of LED Class """
+        """
+        See set_tri of LED Class
+        """
         self.led.set_tri()
 
     def set_status(self, status):
@@ -158,6 +166,9 @@ class StatusLED(QtGui.QWidget):
 
 
 class BoardControl(kcgw.KCGWidgets):
+    """
+    The main view of the gui for each board at startup
+    """
     def __init__(self, board_id, single=False):
         super(BoardControl, self).__init__()
         self.board_id = board_id
@@ -255,6 +266,9 @@ class BoardControl(kcgw.KCGWidgets):
         self.subControlWidget.hide()
 
     def toggle_sub_control(self):
+        """
+        Show or hide the subcontrol buttons
+        """
         self.subControlWidget.setHidden(not self.subControlWidget.isHidden())
         if self.subControlWidget.isHidden():
             self.toggleButton.setIcon(QtGui.QIcon(config.install_path+"icons/chevron-bottom.svg"))
@@ -277,6 +291,10 @@ class BoardControl(kcgw.KCGWidgets):
             bif.bk_calibrate(self.board_id, do_the_rest)
 
     def skip_init(self):
+        """
+        Skip board initialisation progress and read data from board. This will adjust the values in the gui to those
+        on the board (for every value that is stored on the board)
+        """
         board.get_board_config(self.board_id).read_from_board()
         board.get_board_status(self.board_id).calibrated = True
         board.get_board_status(self.board_id).synced = True

+ 13 - 0
KCG/base/globals.py

@@ -1,11 +1,24 @@
 class Globals(object):
+    """
+    Object to make it easy to work with global values
+    """
     def __init__(self):
         self._globals = dict()
 
     def get_global(self, item):
+        """
+        Get a global value
+        :param item: the item to get
+        :return: the value of the global value of item
+        """
         return self._globals.get(item, None)
 
     def set_global(self, key, value):
+        """
+        Set a global value
+        :param key: the key to set
+        :param value: the value to set it to
+        """
         self._globals[key] = value
 
 glob = Globals()

+ 5 - 16
KCG/base/groupedelements.py

@@ -36,13 +36,14 @@ class GroupedObjects:
         Set Flags that define the behaviour of GroupedObjects in various events.
         :param flagDict: Dictionary containing the Flags.
                         Possible Flags are: (They are to be of type bool)
-                        warn: If an element is deleted and the corresponding entry is encountered by setEnabled, a
+
+                        * warn: If an element is deleted and the corresponding entry is encountered by setEnabled, a
                             Warning is raised if warn is True
-                        autoremove: If an element is deleted and the corresponding entry is encountered by setEnabled,
+                        * autoremove: If an element is deleted and the corresponding entry is encountered by setEnabled,
                             the Element will be removed from GroupedObjects if autoremove is True
-                        exception_on_deleted: If an element is deleted and the corresponding entry is encountered by
+                        * exception_on_deleted: If an element is deleted and the corresponding entry is encountered by
                             setEnabled an Exception will be raised if exception_on_deleted is True
-                        notify_deletion: If this is set to True a notification will be printed to STDOUT whenever an
+                        * notify_deletion: If this is set to True a notification will be printed to STDOUT whenever an
                             autoremove is performed (see above)
         :return: -
         """
@@ -260,18 +261,6 @@ class LivePlotWindows():
 
 # Every Element is acessible through every Variable set here. Checkboxes, Buttons and MenuItems variables are set
 # to improve readability of the code. They refer to the same Object
-class Proxy(object):
-    def __init__(self, target):
-        object.__setattr__(self, 'target', target)
-    def __setattr__(self, key, value):
-        setattr(object.__getattribute__(self, 'target')[object.__getattribute__(self, 'id')], key, value)
-    def __set_id__(self, id):
-        object.__setattr__(self, 'id', id)
-    def __getattr__(self, item):
-        if item == '__set_id__':
-            return object.__getattribute__(self, item)
-        else:
-            return getattr(object.__getattribute__(self, 'target')[object.__getattribute__(self, 'id')], item)
 
 Elements = Checkboxes = Buttons = MenuItems = GroupedObjects()
 live_plot_windows = LivePlotWindows()

+ 27 - 8
KCG/base/kcg.py

@@ -139,7 +139,6 @@ class CentralWidget(kcgw.KCGWidgets):
         self.tableWidget.hide()
 
 
-
 class Gui(QtGui.QMainWindow):
     """
     Main Window of the KCG gui
@@ -177,7 +176,6 @@ class Gui(QtGui.QMainWindow):
         self.after_start_status_handler()
         self.setContentsMargins(0, -10, 0, 0)
 
-
     def initUI(self):
         """
         Initialize ui
@@ -230,7 +228,6 @@ class Gui(QtGui.QMainWindow):
         for e in config.default_log_entries:  # for every entry:
             if e in logStrings:
                 self.measurementLogger.register_parameter(e, functionAndParameter[logStrings.index(e)][0], functionAndParameter[logStrings.index(e)][1])
-        # self.measurementLogger.register_dumper(board.config.dump)  # TODO: register dumper for all boards
         if log.no_epics and log.epics_reachable:
             logging.error("Epics installation not found. Logfiles will not contain information that is to be "
                          "obtained via epics.")
@@ -239,7 +236,6 @@ class Gui(QtGui.QMainWindow):
                         "information that is to be obtained via epics.")
 
 
-
     def doMenu(self):
         """
         Create and show the menu and it's entries
@@ -281,6 +277,10 @@ class Gui(QtGui.QMainWindow):
         self.help.addAction(tr("Button", "About"), self.showAbout)
 
     def saveConfig(self, board_id):
+        """
+        Save the current configuration to a configuration file
+        :param board_id: the board to save the configuration for
+        """
         filenameDialog = QtGui.QFileDialog(self, tr("Heading", "Save Configuration"), '', 'KAPTURE Configuration File (*.kcf)')
         filenameDialog.setDefaultSuffix("kcf")
         filenameDialog.setAcceptMode(filenameDialog.AcceptSave)
@@ -293,6 +293,10 @@ class Gui(QtGui.QMainWindow):
             QtGui.QMessageBox.critical(self, tr("Heading", "Error Saving Config"), tr("Dialog", "There was an error saving to a config file."))
 
     def loadConfig(self, board_id):
+        """
+        Load the configuration for the given board from a file
+        :param board_id: the board to read the configuration for
+        """
         filename = QtGui.QFileDialog.getOpenFileName(self, 'Open Configuration', '', 'KAPTURE Configuration File (*.kcf)')
         if not filename:
             return
@@ -302,6 +306,9 @@ class Gui(QtGui.QMainWindow):
             QtGui.QMessageBox.critical(self, tr("Heading", "Error Loading Config"), tr("Dialog", "There was an error loading the config file, make sure it is valid and try again."))
 
     def rerunConfig(self):
+        """
+        Rerun the initial configuration wizard
+        """
         self.setupConfig = initialconfig.ConfigSetup(restart=True)
         self.setupConfig.setWindowModality(QtCore.Qt.ApplicationModal)
         def restart():
@@ -330,7 +337,7 @@ class Gui(QtGui.QMainWindow):
         :return: -
         """
         version = open(config.install_path+"VERSION").read()
-        about = QtGui.QDialog(self) # TODO: read about text externally? read version externally?
+        about = QtGui.QDialog(self)
         about.setWindowTitle("KCG - About")
         about_label = QtGui.QLabel(tr("About", "KAPTURE Control Gui\n"
                                       "KCG is a graphical control interface to the KAPTURE board\n\n"
@@ -401,8 +408,13 @@ class Gui(QtGui.QMainWindow):
                 QtGui.QMessageBox.information(self, "Change Language", "Language change takes effect after Gui restart", 1)
             if setting == 'advanced_control':
                 self.showAdvancedControl(getattr(self.storage, setting))
-            if bif.bk_get_config(setting) != None:
-                bif.bk_update_config(setting, getattr(self.storage, setting))
+
+            for bid in available_boards.board_ids:
+                try:
+                    if bif.bk_get_config(bid, setting) != None:
+                        bif.bk_update_config(bid, setting, getattr(self.storage, setting))
+                except board.NoSuchKeyError:
+                    pass
 
     def showAdvancedControl(self, value):
         """
@@ -420,7 +432,13 @@ class Gui(QtGui.QMainWindow):
                 self.cw.tableWidget.hide()
 
     def after_start_status_handler(self):
-            bif.bk_status_readout()
+        """
+        Method to check for boards and perform a status_readout after the gui is fully started
+        :return:
+        """
+        for bid in available_boards.board_ids:  # there is always at least a dummy board
+            bif.bk_check_for_board(bid)
+        bif.bk_status_readout()
 
     def populate_storage(self):
         """
@@ -433,6 +451,7 @@ class Gui(QtGui.QMainWindow):
         self.storage.language = config.language
         self.storage.advanced_control = False
         def update_header(val):
+            '''Update header'''
             self.storage.header = val
             if self.settings:
                 self.settings.headerTick.setChecked(val)

+ 81 - 8
KCG/base/kcgwidget.py

@@ -10,6 +10,12 @@ from .. import config
 
 
 def tr(_, x):
+    """
+    Dummy Translation method that does not translate
+    :param _: unused
+    :param x: the string to "translate"
+    :return: x
+    """
     return x
 
 
@@ -44,11 +50,20 @@ class clickLabel(QtGui.QLabel):
     """
     clicked = QtCore.pyqtSignal()
     def mouseReleaseEvent(self, QMouseEvent):
+        """
+        Reimplementation of QLabel.mouseReleaseEvent to make this clickable
+        """
         self.clicked.emit()
 
 class ClickableHBoxLayout(QtGui.QHBoxLayout):
+    """
+    A clickable HBoxLayout
+    """
     clicked = QtCore.pyqtSignal()
     def event(self, QEvent):
+        """
+        Reimplementation of QHBoxLayout.event to make it clickable
+        """
         self.clicked.emit()
         if QEvent.type() == QtCore.QEvent.MouseButtonRelease:
             self.clicked.emit()
@@ -83,7 +98,11 @@ class switchLabel(QtGui.QLabel):
         else:
             self.setPixmap(self.leftSwitch)
             self.state = False
+
     def mouseReleaseEvent(self, QMouseEvent):
+        """
+        Reimplementation of QLabel.mouseReleaseEvent to make it clickable
+        """
         if self.state:
             self.state = False
             self.setPixmap(self.leftSwitch)
@@ -93,7 +112,11 @@ class switchLabel(QtGui.QLabel):
         self.clicked.emit()
 
 class Switch(QtGui.QWidget):
+    """
+    A Simple Switch
+    """
     clicked = QtCore.pyqtSignal()
+
     def __init__(self, leftLabel, rightLabel, startRight=False):
         super(Switch, self).__init__()
         self.layout = QtGui.QHBoxLayout()
@@ -107,6 +130,10 @@ class Switch(QtGui.QWidget):
         self.layout.addStretch(1)
 
     def state(self):
+        """
+        Get the state of this switch
+        :return: the state of this switch
+        """
         return self.switch.state
 
 
@@ -139,6 +166,9 @@ class ClickableSVG(QtGui.QWidget):
             self.setFixedHeight(wheight)
 
     def mouseReleaseEvent(self, QMouseEvent):
+        """
+        Reimplementation of QWidget.mouseReleaseEvent to make it clickable
+        """
         self.clicked.emit()
 
     def changeSvg(self, path):
@@ -198,7 +228,7 @@ class KCGWidgets(QtGui.QWidget):
         Setter for the type of this widget
         :param t: (int) type
         """
-        self._type = t # TODO: ??
+        self._type = t
 
     @theId.setter
     def theId(self, i):
@@ -206,7 +236,7 @@ class KCGWidgets(QtGui.QWidget):
         Setter for the id of this widget
         :param i: (int) id
         """
-        self._id = i # TODO: ??
+        self._id = i
 
     @theName.setter
     def theName(self, n):
@@ -214,7 +244,7 @@ class KCGWidgets(QtGui.QWidget):
         Setter for the name of this widget
         :param n: (str) name
         """
-        self._name = n # TODO: ??
+        self._name = n
 
     def createButton(self, text="", x=None, y=None, dimensions=None, tooltip="", connect=False, icon=None):
         """
@@ -329,6 +359,9 @@ class KCGWidgets(QtGui.QWidget):
         return sw
 
     def closeEvent(self, event):
+        """
+        Reimplementation of QWidget.closeEvent
+        """
         super(KCGWidgets, self).closeEvent(event)
         self.closeSignal.emit()
 
@@ -358,32 +391,56 @@ class KCGSubWidget(QtGui.QMdiSubWindow):
         if typ != None:
             self.theType = typ
 
-
     @property
     def theType(self):
+        """
+        Type of this widget
+        """
         return self._type
 
     @property
     def theId(self):
+        """
+        ID of this widget
+        """
         return self._id
 
     @property
     def theName(self):
+        """
+        Name of this widget
+        """
         return self._name
 
     @theType.setter
     def theType(self, t):
-        self._type = t # TODO: ??
+        """
+        Setter for the type of this widget
+        :param t: (int) type
+        """
+        self._type = t
 
     @theId.setter
     def theId(self, i):
-        self._id = i # TODO: ??
+        """
+        Setter for the id of this widget
+        :param i: (int) id
+        """
+        self._id = i
 
     @theName.setter
     def theName(self, n):
-        self._name = n # TODO: ??
+        """
+        Setter for the name of this widget
+        :param n: (str) name
+        """
+        self._name = n
+
 
 class AccordionClickLine(QtGui.QWidget):
+    """
+    A simple clickable line used in the accordion widget below
+    """
     clicked = QtCore.pyqtSignal()
     def __init__(self, text):
         super(AccordionClickLine, self).__init__()
@@ -403,10 +460,17 @@ class AccordionClickLine(QtGui.QWidget):
         self.expanded = True
 
     def mouseReleaseEvent(self, QMouseEvent):
+        """
+        Reimplementation of QWidget.mouseReleaseEvent to make it clickable
+        """
         self.clicked.emit()
         super(AccordionClickLine, self).mouseReleaseEvent(QMouseEvent)
 
     def expand(self, state):
+        """
+        Expand or deexpand the Accordion entry
+        :param state: True to expand False to deexpand
+        """
         if state:  # if you want to expand
             if not self.expanded:  # and it is not already expanded
                 self.layout.removeWidget(self.down_chev)
@@ -440,6 +504,9 @@ class AccordionWidget(QtGui.QWidget):  # TODO: accordion or accordeon?
         self.headers = []
 
     def resizeEvent(self, QResizeEvent):
+        """
+        Reimplementation of QWidget.resizeEvent to make it look nice
+        """
         self.setMaximumHeight(self.layout.sizeHint().height())
         super(AccordionWidget, self).resizeEvent(QResizeEvent)
 
@@ -471,6 +538,7 @@ class AccordionWidget(QtGui.QWidget):  # TODO: accordion or accordeon?
             self.expandIndex(index)
         else:
             self.hideIndex(index)
+
     def expandIndex(self, index):
         """
         Expand the widget with index index
@@ -479,6 +547,7 @@ class AccordionWidget(QtGui.QWidget):  # TODO: accordion or accordeon?
         self.widgets[index].show()
         self.headers[index].expand(True)
         self.resize(1, 1)  # this will trigger a resizeEvent and thus will set the correct size
+
     def hideIndex(self, index):
         """
         Hide the widget with the index index
@@ -487,6 +556,7 @@ class AccordionWidget(QtGui.QWidget):  # TODO: accordion or accordeon?
         self.widgets[index].hide()
         self.headers[index].expand(False)
         self.resize(1, 1)  # this will trigger a resizeEvent and thus will set the correct size
+
     def hideAll(self):
         """
         Hide all widgets
@@ -580,6 +650,10 @@ class IdGenerator():
     """
     highest_id = 0
     def genid(self):
+        """
+        Generate a new Id
+        :return:
+        """
         self.highest_id += 1
         return self.highest_id
 
@@ -635,7 +709,6 @@ def error(code, text, severe=False):
     :param severe: if it is a severe error that has to quit the program
     :return:
     """
-    # TODO: implement error logging to file
     if isinstance(code, str) and code[0:2] == '0x':
         cde = code
     elif isinstance(code, str):

+ 14 - 1
KCG/base/leftbar.py

@@ -22,6 +22,9 @@ FILE = 2
 
 
 class BoardSpecificInformation(kcgw.KCGWidgets):
+    """
+    Specific Part for each board
+    """
     def __init__(self, board_id):
         """
         This creates the information part for board with id board_id.
@@ -32,6 +35,7 @@ class BoardSpecificInformation(kcgw.KCGWidgets):
         self.temperature = self.createLabel(tr("Label", "Temp:"))
 
         def update_temp():
+            '''update the temperature in the gui'''
             if bif.bk_get_board_status(board_id, 'board_connected'):
                 self.temperature.setText("Temp: " + bif.bk_get_temperature(board_id) + u" °C")
         try:
@@ -82,7 +86,7 @@ class BoardSpecificInformation(kcgw.KCGWidgets):
 
         self.boardSpecificLayout = QtGui.QVBoxLayout()
         self.setLayout(self.boardSpecificLayout)
-        self.layout = QtGui.QGridLayout()  # TODO: add text for build_spectrograms ? was???
+        self.layout = QtGui.QGridLayout()
         self.layout.addWidget(self.temperature, 0, 0)
         self.layout.addWidget(self.skipturns, 1, 1)
         self.layout.addWidget(self.orbitsobserved, 1, 0)
@@ -278,6 +282,7 @@ class AcquisitionAndInfo(kcgw.KCGWidgets):
         pos = event.globalPos()
 
         def configure_log():
+            '''Open the configuration window for logs'''
             c = log.ConfigureLog(self)
             c.exec_()
             del c
@@ -326,6 +331,9 @@ class LeftBar(kcgw.KCGWidgets):
         self.initUI()
 
     def initUI(self):
+        """
+        Initialise the UI
+        """
         self.layout = QtGui.QVBoxLayout()
         self.layout.setContentsMargins(0, 0, 5, 0)
         self.setMinimumWidth(230)
@@ -348,6 +356,11 @@ class LeftBar(kcgw.KCGWidgets):
         self.setLayout(self.layout)
 
     def _generate_menu(self, menu, item):
+        """
+        Generate the right click menu
+        :param menu: the menu to add the entries to
+        :param item: the item that was clicked on
+        """
         heatmap = menu.addAction(tr("Button", "Heatmap"))
         fft = menu.addAction(tr("Button", "FFT"))
         trains = menu.addAction(tr("Button", "Trains"))

+ 17 - 0
KCG/base/log.py

@@ -49,6 +49,9 @@ tr = lambda _, x: x  # log entries will not be translated
 
 
 class LogLevels:  # Keep every new value an integer. Every level with higher value will include those with lower level
+    """
+    Used Log Levels Container
+    """
     NONE = -1
     INFO = 0
     DEBUG = 1
@@ -182,6 +185,7 @@ class MeasurementLogger(object):
                     self._log(bid, c)
         else:
             def do_the_log(bid):
+                '''Actually perform the log'''
                 st = []
                 if additional:
                     s = additional.split('\n')[0]
@@ -259,7 +263,9 @@ class ConfigureLog(QtGui.QDialog):
             self.parameter.append((QtGui.QCheckBox(par[0]), par[1]))
 
         self.i = 0
+
         def add(w):
+            '''add a widget to the layout. if w is 'sep' a seperator is added'''
             if w == 'sep':
                 sep = QtGui.QFrame()
                 sep.setFrameShape(QtGui.QFrame.HLine)
@@ -318,11 +324,17 @@ class ConfigureLog(QtGui.QDialog):
         self.initial_ticks()
 
     def initial_ticks(self):
+        """
+        Set the initial ticks.
+        """
         pf = np.array(logger.parameter_functions)
         for cb, _ in self.parameter:
             cb.setChecked(str(cb.text()) in pf[:, 2])
 
     def all_changed(self):
+        """
+        This is called when the "all" checkbox is checked. It de/activates the other checkboxes
+        """
         if self.all.isChecked():
             for cb, _ in self.parameter:
                 cb.setEnabled(False)
@@ -331,9 +343,14 @@ class ConfigureLog(QtGui.QDialog):
                 cb.setEnabled(True)
 
     def do(self):
+        """
+        Change the logger instance to the activated log entries
+        :return:
+        """
         global logger
         logger.reset_parameters()
         def nif(cb, f, args):
+            '''actually set the new parameters'''
             if cb.isChecked() or self.all.isChecked():
                 logger.register_parameter(str(cb.text()), f, args)
         for cb, par in self.parameter:

+ 42 - 0
KCG/base/loghandler.py

@@ -1,6 +1,11 @@
 import logging
+from logging import handlers
+import os
+import sys
 from PyQt4 import QtGui, QtCore
 
+from .. import config
+
 """
 This intends to be a QThread save logging handler with syntax highlighting
 """
@@ -19,12 +24,18 @@ class LogHandler(logging.Handler):
         self._bold = 100
 
     def emit(self, record):
+        """
+        Emit a log record
+        """
         self.acquire()
         self.text_area.append_signal.emit(record)
         self.release()
 
 
 class Highlighter(QtGui.QSyntaxHighlighter):
+    """
+    Highlighter for the logging area
+    """
     def __init__(self, parent, theme):
         super(Highlighter, self).__init__(parent, )
         self.parent = parent
@@ -57,6 +68,10 @@ class Highlighter(QtGui.QSyntaxHighlighter):
         self.highlightingRules.append((self.error_pattern, error))
 
     def setKeywords(self, kw):
+        """
+        Set the keywords to check for
+        :param kw: the keywords
+        """
         keyword = QtGui.QTextCharFormat()
         keyword.setForeground(QtCore.Qt.darkBlue)
         keyword.setFontWeight(QtGui.QFont.Bold)
@@ -66,6 +81,10 @@ class Highlighter(QtGui.QSyntaxHighlighter):
             self.highlightingRules.append((pattern, keyword))
 
     def highlightBlock(self, text):
+        """
+        Highlight a block of text
+        :param text: the text to check in
+        """
         for pattern, format in self.highlightingRules:
             start = 0
             if pattern not in [self.timestamp_pattern, self.error_pattern, self.loglevel_pattern]:
@@ -85,21 +104,44 @@ class Highlighter(QtGui.QSyntaxHighlighter):
 
 
 class LogArea(QtGui.QTextEdit):
+    """
+    The log area for the KCG Gui
+    """
     append_signal = QtCore.pyqtSignal(logging.LogRecord)
 
     def __init__(self):
         super(LogArea, self).__init__()
         self.highlighter = Highlighter(self, 'Classic')
         self.logHandler = None
+        self.streamLogger = logging.StreamHandler(stream=sys.stdout)
+        self.streamLogger.setLevel(config.log_level)
+        self.streamLogger.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s: %(message)s'))
+        logging.getLogger().addHandler(self.streamLogger)
+        self.fileLogHandler = handlers.RotatingFileHandler(os.path.expanduser("~")+"/.kcg/kcg.log", maxBytes=10**7, backupCount=5)
+        self.fileLogHandler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s: %(message)s'))
+        self.fileLogHandler.setLevel(config.log_level)
+        logging.getLogger().addHandler(self.fileLogHandler)
         self.append_signal.connect(self.append)
 
     def init_logging(self):
+        """
+        Initialize logging
+        """
         self.logHandler = LogHandler(self)
+        self.logHandler.setLevel(config.log_level)
         logging.getLogger().addHandler(self.logHandler)
 
     def append(self, record):
+        """
+        Append to the logarea
+        :param record: the record to append
+        """
         super(LogArea, self).append(self.logHandler.format(record))
         self.ensureCursorVisible()
 
     def setKeywords(self, kw):
+        """
+        Set the keywords for the highlighter
+        :param kw: the keywords to set
+        """
         self.highlighter.setKeywords(kw)

+ 39 - 5
KCG/base/plotWidget.py

@@ -77,11 +77,19 @@ gradient = {'mode': 'rgb',
 
 
 class CustomGradientEditorItem(pg.GradientEditorItem):
+    """
+    A Gradient Editor Item to insert a perception linear gradient
+    """
     def __init__(self, **kwargs):
         pg.GradientEditorItem.__init__(self, **kwargs)
         self.customGradients = {}
 
     def addGrad(self, name, grad_dic):
+        """
+        Add a gradient to the list of gradients in the gui
+        :param name: the name of the gradient
+        :param grad_dic: the dictionary containing the gradient data
+        """
         if name not in self.customGradients:
             self.customGradients[name] = grad_dic
             px = QtGui.QPixmap(100, 15)
@@ -110,6 +118,10 @@ class CustomGradientEditorItem(pg.GradientEditorItem):
         self.restoreState(grad_dic)
 
     def restoreState(self, state):
+        """
+        Reimplemented of pyqtgraph.GradientEditorItem.restoreState to work with our custom perception linear gradient.
+        :param state: the state to restore to
+        """
         self.setColorMode(state['mode'])
         for t in list(self.ticks.keys()):
             self.removeTick(t, finish=False)
@@ -134,12 +146,23 @@ class CustomGradientEditorItem(pg.GradientEditorItem):
         self.sigGradientChangeFinished.emit(self)
 
     def loadPreset(self, name):
+        """
+        Reimplemented of pyqtgraph.GradientEditorItem.loadPreset to work with our custom perception linear gradient.
+        :param name: the name of the preset to load
+        """
         if name in self.customGradients:
             self.restoreState(self.customGradients[name])
         else:
             super(CustomGradientEditorItem, self).loadPreset(name)
 
     def tickMoved(self, tick, pos):
+        """
+        Reimplemented of pyqtgraph.GradientEditorItem.tickMoved to work with our custom perception linear gradient,
+        which has a lot of steps which would create a lot of ticks in the gradient legend. This removes all but 2
+        ticks and aligns all the internal ticks accordingly.
+        :param tick: the tick to move
+        :param pos: the position to move to
+        """
         if tick is self.bottomTick[0]:
             # self.bottomTick[1] = pos.x()
             pg.TickSliderItem.tickMoved(self, tick, pos)
@@ -270,7 +293,9 @@ class SubPlotWidget(pg.GraphicsLayoutWidget):
 
         self.gradient_legend = SpectrogramColorLegendItem(self.img)
         def changelut():
-            """ Handle changing of the lookup table"""
+            """
+            Handle changing of the lookup table
+            """
             self.img.setLookupTable(self.gradient_legend.getLookupTable(512))
             self.img2.setLookupTable(self.gradient_legend.getLookupTable(512))
         self.gradient_legend.gradientChanged.connect(changelut)
@@ -307,7 +332,7 @@ class SubPlotWidget(pg.GraphicsLayoutWidget):
         :return:
         """
         def newAutoRange(*args, **kwargs):
-            """ function to handle the new autorange """
+            ''' function to handle the new autorange '''
             bounds = [np.min(data), np.max(data)]
             self.plotItem.vb.setRange(xRange=[0, len(data)],
                 yRange=[bounds[0]-0.1*(bounds[1]-bounds[0])-1, bounds[1]+0.1*(bounds[1]-bounds[0])+1], update=True)
@@ -468,7 +493,8 @@ class SubPlotWidget(pg.GraphicsLayoutWidget):
             self.plotItem.getViewBox().autoRange()
 
         self.labelAxes()
-        self.gradient_legend.update_axis()
+        if self.plotType in [PlotType.FFT, PlotType.Heatmap, PlotType.Compare]:
+            self.gradient_legend.update_axis()
 
     def labelAxes(self):
         """
@@ -502,8 +528,8 @@ class SubPlotWidget(pg.GraphicsLayoutWidget):
         if type != self.plotType:
             self._type_changed = True
         self.plotType = type
-        self.gradient_legend.image_changed()
-
+        # if type in [PlotType.FFT, PlotType.Compare, PlotType.Heatmap]:  # this will generate an error
+        #     self.gradient_legend.image_changed()
 
 class PlotWidget(kcgw.KCGWidgets):
     """
@@ -706,6 +732,10 @@ class PlotWidget(kcgw.KCGWidgets):
         self.combined_button.setDisabled(b_bool)
 
     def changePlotType(self, type):
+        """
+        Change the plot type to the given type.
+        :param type: the new type
+        """
         if type not in [ERROR, NO_DATA]:
             self._old_type = type
         self.theType = type
@@ -815,6 +845,10 @@ class PlotWidget(kcgw.KCGWidgets):
             self.plot_widget.plot(self.data.combined(frm=f, to=t), autorange=autorange)
 
     def change_identifier_text(self):
+        """
+        Change the text that identifies the plot in the left bar
+        :return:
+        """
         if self.theType is PlotType.Compare:
             the_text = str(self.adc)+"+"+str(self.secadc)
         else:

+ 30 - 0
KCG/base/settings.py

@@ -46,6 +46,9 @@ class Settings(kcgw.KCGWidgets):
         self.show()
 
     def initUI(self):
+        """
+        Initialise the UI
+        """
         self.setLayout(self.layout)
         self.layout.addLayout(self.grid)
 
@@ -84,6 +87,11 @@ class Settings(kcgw.KCGWidgets):
         return handle
 
     def _read_setting_from_object(self, object):
+        """
+        Get the value from a settings object
+        :param object: the object to read the value from
+        :return:
+        """
         if type(object).__name__ == 'QCheckBox':
             return object.isChecked()
         if isinstance(object, QtGui.QLineEdit):
@@ -92,6 +100,10 @@ class Settings(kcgw.KCGWidgets):
             return object.currentText()
 
     def _setSettings(self):
+        """
+        Set the values in the settings window to the current values
+        :return:
+        """
         self.headerTick.setChecked(self.storage_handler.header)
         self.subDirName.setText(self.storage_handler.subdirname)
         self.dirName.setText(self.storage_handler.save_location)
@@ -99,6 +111,9 @@ class Settings(kcgw.KCGWidgets):
         self.advanced_control.setChecked(self.storage_handler.advanced_control)
 
     def _apply(self):
+        """
+        Called when the apply button is pressed. It emits the changed signal if anything was changed
+        """
         hasChanged = False
         changedSettings = []
         for object in self.local_storage:
@@ -110,16 +125,31 @@ class Settings(kcgw.KCGWidgets):
             self.changed.emit(changedSettings)
 
     def _ok(self):
+        """
+        Handler for the ok button. It calls _apply and close
+        :return:
+        """
         self._apply()
         self.close()
 
     def _cancel(self):
+        """
+        Handler for the cancel button. It calls close() and discards changed values
+        :return:
+        """
         self.close()
 
     def show(self):
+        """
+        Shows the window and sets the current values (calls _setSettings)
+        :return:
+        """
         self._setSettings()
         super(Settings, self).show()
 
     def keyPressEvent(self, QKeyEvent):
+        """
+        Reimplementation of the keyPressEvent of QWidget to close the window on ESC press.
+        """
         if QKeyEvent.key() == QtCore.Qt.Key_Escape:
             self.close()

+ 54 - 2
KCG/base/storage.py

@@ -18,6 +18,12 @@ class Storage(object):
             self._storage = default
 
     def setdefault(self, key, object):
+        """
+        Call setdefault on the underlying dictionary and return the result
+        :param key: the key to call setdefault with
+        :param object: the object to call setdefault with
+        :return: the return value of setdefault of the dictionary
+        """
         return self._storage.setdefault(key, object)
 
     def __setattr__(self, key, value):
@@ -40,6 +46,11 @@ _board_specific_storages = {}
 
 
 def get_board_specific_storage(board_id):
+    """
+    Get the storage instance for a specific board
+    :param board_id: the board to get the storage for
+    :return: the instance of the storage for the given board
+    """
     if board_id in _board_specific_storages:
         return _board_specific_storages[board_id]
     else:
@@ -64,8 +75,23 @@ class ThreadStorage(object):
         """
         del self._q_thread  # start over
         self._q_thread = QtCore.QThread()
+        self._q_thread.started.connect(self.__start)
         self._threaded_object = threaded_object
 
+    def is_registered(self):
+        """
+        Check if a class for this thread is registered.
+        :return:
+        """
+        return not (self._threaded_object is None)
+
+    def __start(self):
+        """
+        This will be registered to the QThread started signal and will call the actual start_method
+        :return:
+        """
+        self._start_method()
+
     def start(self, method_to_run_in_thread):
         """
         Move the class object to a QThread, connect the QThread.started signal to the given method of the
@@ -75,12 +101,22 @@ class ThreadStorage(object):
         """
         self._threaded_object.moveToThread(self._q_thread)
         if isinstance(method_to_run_in_thread, str):
-            self._q_thread.started.connect(getattr(self._threaded_object, method_to_run_in_thread))
+            self._start_method = getattr(self._threaded_object, method_to_run_in_thread)
+            # self._q_thread.started.connect(getattr(self._threaded_object, method_to_run_in_thread))
         else:
-            self._q_thread.started.connect(method_to_run_in_thread)
+            self._start_method = method_to_run_in_thread
+            # self._q_thread.started.connect(method_to_run_in_thread)
         self._q_thread.start()
         self.running = True
 
+    def quit(self):
+        """
+        Quit the thread class (if it has a method to quit)
+        :return:
+        """
+        if hasattr(self._threaded_object, 'quit'):
+            self._threaded_object.quit()
+
     def stop(self):
         """
         Call quit and wait to the underlying QThread
@@ -115,3 +151,19 @@ class ThreadStorage(object):
             getattr(self._threaded_object, signal).connect(slot)
         else:
             signal.connect(slot)
+
+    def disconnect(self, *args):
+        """
+        Disconnect the given signals
+        :param args: the signals to disconnect
+        :return:
+        """
+        for signal in args:
+            getattr(self._threaded_object, signal).disconnect()
+
+    def init(self, *args, **kwargs):
+        """
+        call the threaded objects init method (not __init__) with the passed arguments
+        :return:
+        """
+        self._threaded_object.init(*args, **kwargs)

+ 1 - 1
KCG/config.cfg

@@ -113,7 +113,7 @@ style = 'default'
 # 'list' means: use boards specified with board_list
 # (board_list has to be a python list with device files as strings (e.g. '/dev/fpga0'), becareful the
 # specified /dev/ files will be used with pci without validation)
-board_detection_method = 'dummy'
+board_detection_method = 'dev'
 device_list = []
 # device_names is a mapping for device ids to pretty names, this makes the use of boards more intuitive
 # format is: device_names = {'device id': 'device name', ...}

+ 29 - 3
KCG/kcg.py

@@ -8,6 +8,15 @@ import sys
 import os
 import argparse as ap
 import logging
+from logging import handlers
+
+# -------[ Register Logger here to enable logging before anything of this app is performed ]---------------
+logging.getLogger().setLevel(0)
+fileLogHandler = handlers.RotatingFileHandler(os.path.expanduser("~")+"/.kcg/kcg.log.full", maxBytes=10**7, backupCount=5)
+fileLogHandler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s: %(message)s'))
+fileLogHandler.setLevel(0)
+logging.getLogger().addHandler(fileLogHandler)
+logging.info("==========[Start Application]===========")
 
 import base.kcgwidget as kcgw
 import config
@@ -35,6 +44,10 @@ except ImportError:
 
 
 def print_version(verbose=False):
+    """
+    Print the version of the current used KCG instance
+    :param verbose: print verbose?
+    """
     # print "KCG - KAPTURE Control Gui"
     # print "=" * 30
     print "KCG",
@@ -49,10 +62,22 @@ def print_version(verbose=False):
 
 
 def inject_setting(section, setting, value, args):
+    """
+    Inject a setting from the command line
+    :param section: the section to inject to
+    :param setting: the setting to inject
+    :param value: the value of this setting
+    :param args: the argparse parsed instance
+    """
     args.config += section + '->' + setting + '=' + str(value) + ';'
 
 
 def log_type(level):
+    """
+    Method to validate and cast the log level
+    :param level: the level to validate and cast
+    :return: a valid logging level
+    """
     try:
         return int(level)
     except ValueError:
@@ -100,10 +125,11 @@ def run():
     if args.fpga_detection:
         inject_setting('Misc', 'board_detection_method', '"dev"', args)
 
-    logger = logging.getLogger()
-    logger.setLevel(args.log)
-    logging.logger = logger
+    # logger = logging.getLogger()
+    # logger.setLevel(args.log)
+    # logging.logger = logger
     def vinfo(content):
+        '''log with level VINFO'''
         logging.log(logging.getLevelName('VINFO'), content)
     logging.vinfo = vinfo
 

+ 46 - 16
KCG/widgets/acquiresettings.py

@@ -17,6 +17,9 @@ __widget_id__ = None
 
 
 class AcquireSettingsTab(kcgw.KCGWidgets):
+    """
+    A single tab in the acquire settings window
+    """
     available_for_same_as = OrderedDict()
 
     def __init__(self, board_id, same_as_widgets, parent=None):
@@ -45,17 +48,13 @@ class AcquireSettingsTab(kcgw.KCGWidgets):
             self.sameAsLabel.hide()
 
         # ---------[ Create Labels and corresponding Fields ]---------
-        self.numOfOrbitsLabel = self.createLabel(tr("Label", "Number of orbits to observe"))  # TODO: Better Text
-        self.numOfSkipOrbitsLabel = self.createLabel(tr("Label", "Number of orbits to skip"))  # TODO: Better Text
-        # TODO: does 10000000 as max make sense?
+        self.numOfOrbitsLabel = self.createLabel(tr("Label", "Number of orbits to observe"))
+        self.numOfSkipOrbitsLabel = self.createLabel(tr("Label", "Number of orbits to skip"))
         self.numOfOrbitsSpinbox = self.createSpinbox(1, 10000000, connect=self.on_number_of_orbits_changed)
-        # TODO: 100 as max make sense?
         self.numOfSkipOrbitsSpinbox = self.createSpinbox(0, 100, connect=self.on_number_of_skipped_orbits_changed)
         self.countLabel = self.createLabel(tr("Label", "Number of acquisitions"))
-        # TODO: does 10000000 as max make sense?
         self.countSpinbox = self.createSpinbox(1, 10000000, start_value=10, connect=self.on_count_changed)
         self.waitLabel = self.createLabel(tr("Label", "Wait(s)"))
-        # TODO: does 60 as max and default as 15 make sense?
         self.waitSpinbox = self.createSpinbox(0, 60, start_value=15, connect=self.on_wait_changed)
         self.simulatePilotBunch = self.createCheckbox(tr("Button", "Simulate Pilot Bunch"),
                                                       connect=self.on_simulate_pilot_bunch_changed)
@@ -137,6 +136,10 @@ class AcquireSettingsTab(kcgw.KCGWidgets):
         self.layout.addWidget(line, 8, 0, 1, 2)
 
     def build_same_as_list(self):
+        """
+        Build the list to show in the same-as drop down menu
+        :return:
+        """
         for wid_id, wid in self.widgets.iteritems():
             wid.sameAsCombo.clear()
             for key, value in self.available_for_same_as.iteritems():
@@ -157,7 +160,7 @@ class AcquireSettingsTab(kcgw.KCGWidgets):
             self.available_for_same_as[self.board_id] = False
             self.sameAsCombo.setEnabled(False)
             board.get_board_config(c_t).observe_all(
-                board.get_board_config(self.board_id).update)  # TODO: in zukunft ist die id kein int mehr
+                board.get_board_config(self.board_id).update)
             self.widgets[c_t].sameAsTick.setEnabled(False)
             self.widgets[c_t].sameAsCombo.setEnabled(False)
             Elements.setEnabled('acquire_{}'.format(self.board_id), False)
@@ -167,7 +170,7 @@ class AcquireSettingsTab(kcgw.KCGWidgets):
             self.available_for_same_as[self.board_id] = True
             self.sameAsCombo.setEnabled(True)
             board.get_board_config(c_t).unobserve_all_observer(
-                board.get_board_config(self.board_id).update)  # TODO: in zukunft ist die id kein int mehr
+                board.get_board_config(self.board_id).update)
             self.widgets[c_t].sameAsTick.setEnabled(True)
             self.widgets[c_t].sameAsCombo.setEnabled(True)
             Elements.setEnabled('acquire_{}'.format(self.board_id), True)
@@ -181,10 +184,19 @@ class AcquireSettingsTab(kcgw.KCGWidgets):
         bif._bif_disable_wait_cursor()
 
     def update_external_trigger(self, state):
+        """
+        Update the use external trigger tick
+        :param state: the state to set the tick to
+        """
         self.tick_silent(self.trigger_tick, state)
         self.use_external_trigger(state, update_config=False)
 
     def use_external_trigger(self, state, update_config=True):
+        """
+        Set use external trigger to state
+        :param state: the state to set to
+        :param update_config: true to update the board config
+        """
         if state:
             if update_config:
                 board.get_board_config(self.board_id).update('use_trigger', True)
@@ -259,7 +271,7 @@ class AcquireSettingsTab(kcgw.KCGWidgets):
         This will read the appropriate Values from the base.backend.board.BoardConfiguration instance used in the gui.
         :return: -
         """
-        # TODO: bk_get_config has to be done for each widget seperately (get dientifier by widget.board_id)
+        # bk_get_config has to be done for each widget seperately (get dientifier by widget.board_id)
         self.set_value_silent(self.numOfOrbitsSpinbox, bif.bk_get_config(self.board_id, 'orbits_observe'))
         self.set_value_silent(self.numOfSkipOrbitsSpinbox, bif.bk_get_config(self.board_id, 'orbits_skip'))
         self.set_value_silent(self.countSpinbox, bif.bk_get_config(self.board_id, 'acquisition_count'))
@@ -270,42 +282,54 @@ class AcquireSettingsTab(kcgw.KCGWidgets):
 
     # -----------------[ Value Change Handlers ]---------------------------
     def on_number_of_orbits_changed(self):
-        """ Handle the change of the number of orbits"""
+        """
+        Handle the change of the number of orbits
+        """
         bif.bk_change_num_of_orbits(self.board_id, self.numOfOrbitsSpinbox.value())
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
             bif.bk_change_num_of_orbits(wid.board_id, wid.numOfOrbitsSpinbox.value())
 
     def on_number_of_skipped_orbits_changed(self):
-        """ Handle the change of the number of skipped orbits"""
+        """
+        Handle the change of the number of skipped orbits
+        """
         bif.bk_change_num_of_skipped_orbits(self.board_id, self.numOfSkipOrbitsSpinbox.value())
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
             bif.bk_change_num_of_skipped_orbits(wid.board_id, wid.numOfSkipOrbitsSpinbox.value())
 
     def on_count_changed(self):
-        """ Handle the change of the count value """
+        """
+        Handle the change of the count value
+        """
         bif.bk_change_count(self.board_id, self.countSpinbox.value())
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
             bif.bk_change_count(wid.board_id, wid.countSpinbox.value())
 
     def on_wait_changed(self):
-        """ Handle the change of the wait time """
+        """
+        Handle the change of the wait time
+        """
         bif.bk_change_wait(self.board_id, self.waitSpinbox.value())
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
             bif.bk_change_wait(wid.board_id, wid.waitSpinbox.value())
 
     def on_build_spectrograms_changed(self):
-        """ Handle the change of the build_spectrograms checkbox"""
+        """
+        Handle the change of the build_spectrograms checkbox
+        """
         bif.bk_change_build_spectrograms(self.board_id, self.buildSpectrogrammTickbox.checkState())
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
             bif.bk_change_build_spectrograms(wid.board_id, wid.buildSpectrogrammTickbox.checkState())
 
     def on_simulate_pilot_bunch_changed(self):
-        """ Handle the change of the simulate_pilot_bunch checkbox"""
+        """
+        Handle the change of the simulate_pilot_bunch checkbox
+        """
         bif.bk_change_pilot_bunch(self.board_id, self.simulatePilotBunch.checkState())
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
@@ -322,7 +346,9 @@ class AcquireSettingsTab(kcgw.KCGWidgets):
             bif.bk_update_config(wid.board_id, 'trigger_skip', value)
 
     def on_trigger_method_changed(self):
-        """ Handle change of trigger method. """
+        """
+        Handle change of trigger method.
+        """
         bif.bk_update_config(self.board_id, 'trigger_method', 2 if self.method.state() else 1)
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
@@ -403,6 +429,10 @@ class AcquireSettings(kcgw.KCGWidgets):
             wid.set_values()
 
     def show_tab(self, board_id):
+        """
+        Show the tab for the given board
+        :param board_id: the id of the board to show
+        """
         if not available_boards.multi_board:
             return
         self.tabs.setCurrentIndex(self.widgets.keys().index(board_id))

+ 3 - 0
KCG/widgets/singleread.py

@@ -116,6 +116,9 @@ class SingleReadWidget(kcgw.KCGWidgets):
         bif.bk_continuous_read(board_id)  # interval=self.interval_spinbox.value())
 
     def set_interval(self):
+        """
+        Set the interval between reads
+        """
         storage.continuous_interval = self.interval_spinbox.value()
 
     def closeEvent(self, event):

+ 12 - 16
KCG/widgets/timingWidget.py

@@ -209,11 +209,6 @@ class timingPlotWidget(kcgw.KCGWidgets):
             lax.setTickSpacing()
             lax.tickStrings = self.y_axis_strings
 
-
-
-
-
-
     def setInputs(self, coarse_input, fine_inputs):
         """
         Register the Inputfields for timing in the timingsettings window
@@ -251,7 +246,6 @@ class timingPlotWidget(kcgw.KCGWidgets):
         elif adc == "ADC 4":
             self.adc4_f_input.setValue(int(pos.x()))
 
-
     def plot(self, data=None, levels=None, newTitle=None, maxima=None):
         """
         Plot Data
@@ -298,7 +292,7 @@ class timingPlotWidget(kcgw.KCGWidgets):
         if self.plot_type == 'line':
             # self.line_plot()
             def reshape(data):
-                """ simply reshape the data"""
+                ''' simply reshape the data'''
                 return np.reshape(data, data.shape[0]*data.shape[1], order='F')
             self.adc1_plot_widget.plotItem.clear()
             self.adc2_plot_widget.plotItem.clear()
@@ -391,6 +385,7 @@ class timingPart(kcgw.KCGWidgets):
         #  --------[ Create Labels and corresponding Fields ]---------
 
         def update_delay(which, spinbox):
+            '''update the delays on the board'''
             board.get_board_config(board_id).update(which, getattr(self, spinbox).value())
             board.get_board_config(board_id).set_delay(self.coarseInput.value())
         self.thdelayLabel = self.createLabel(tr("Label", "T/H Delay"))
@@ -423,12 +418,14 @@ class timingPart(kcgw.KCGWidgets):
         ])
         Elements.addItem('acquire_{}'.format(self.board_id), self.time_scan_button)
         def setValueSilent(value, spinbox):
+            '''set values silent to not trigger signals'''
             spinbox.blockSignals(True)
             spinbox.setValue(value)
             spinbox.blockSignals(False)
 
         # --------[ Set observers ]------------
         def obs(who, what):
+            '''observe something'''
             board.get_board_config(board_id).observe(
                 who,
                 lambda value=None: setValueSilent(value=value, spinbox=who),
@@ -449,11 +446,13 @@ class timingPart(kcgw.KCGWidgets):
         self.totalAdc4Box = self.createInput("", read_only=True)
 
         def observe_function(x, box):
+            '''method to pass as callable to to the configuration as observer'''
             box.setText('%i + %i' % (board.get_board_config(board_id).get('th_delay')*
                                      board.get_board_config(board_id).get('th_delay_factor'),
                                      x*board.get_board_config(board_id).get('chip_delay_factor')))
 
         def observe_function_total(x, box, adc):
+            '''method to pass as callable to to the configuration as observer'''
             box.setText('%i + %i' % (x *
                                      board.get_board_config(board_id).get('th_delay_factor'),
                                      board.get_board_config(board_id).get('chip_'+adc+'_delay') *
@@ -535,7 +534,6 @@ class timingPart(kcgw.KCGWidgets):
         self.setValues()
         self.setWindowTitle(tr("Heading", "Timing"))
 
-
     def toggleAdc1IndividualDelay(self):
         """
         Toggle to use an individual delay for adc1 or not
@@ -545,7 +543,6 @@ class timingPart(kcgw.KCGWidgets):
         if not self.adc1CoarseInput.isEnabled():
             board.get_board_config(self.board_id).update('adc_1_delay_individual', -1) # Be careful this does no silent update
 
-
     def showTimeScan(self):
         """
         Show the time scan part of this window
@@ -560,7 +557,6 @@ class timingPart(kcgw.KCGWidgets):
 
         self.parent.adjustSizeForTimeScan()
 
-
     def time_scan(self):
         """
         Toggle timescan and create timingPlotWidget if it doesn't exist
@@ -593,7 +589,6 @@ class timingPart(kcgw.KCGWidgets):
             orbits_skip = self.orbits_skip_spinbox.value()
         )
 
-
     def setValueSilent(self, element, value):
         """
         Set Values to inputs without notifying observers
@@ -604,6 +599,7 @@ class timingPart(kcgw.KCGWidgets):
         element.blockSignals(True)
         element.setValue(value)
         element.blockSignals(False)
+
     def setValues(self):
         """
         Set Values to inputs (initially)
@@ -628,7 +624,6 @@ class timingPart(kcgw.KCGWidgets):
         self.totalAdc4Box.setText('%i + %i' % (board.get_board_config(self.board_id).get('th_delay')* board.get_board_config(self.board_id).get('th_delay_factor'),
                                                board.get_board_config(self.board_id).get('chip_4_delay')*board.get_board_config(self.board_id).get('chip_delay_factor')))
 
-
     def closeEvent(self, event):
         """
         Event handler when this window is closed
@@ -678,6 +673,7 @@ class timingPart(kcgw.KCGWidgets):
             bif.bk_status_readout(self.board_id)
             return
 
+
 class timingWidget(kcgw.KCGWidgets):
     """
     This is the container that holds the tab widget which contains the timing widgets for each board
@@ -704,8 +700,11 @@ class timingWidget(kcgw.KCGWidgets):
             self.single_board_widget = self.widgets.values()[0]
             self.layout.addWidget(self.single_board_widget)
 
-
     def adjustSizeForTimeScan(self):
+        """
+        Adjust the size of the widget to accomodate the time_scan part
+        :return:
+        """
                 # self.parentWindow = self.parent().parent().parent().parent()  # one up is stacked widget, second up is
                 #                     tab widget, third up is timingWidget fourh up is KCGWSubWindow (the actual window)
         QtCore.QCoreApplication.processEvents()
@@ -715,7 +714,6 @@ class timingWidget(kcgw.KCGWidgets):
             # self.parent().resize(self.minimumSizeHint().width() * 1.2, self.minimumSizeHint().height()*1.1)
             self.parent().adjustSize()
 
-
     def closeEvent(self, event):
         global __widget_id__
         __widget_id__ = None
@@ -726,8 +724,6 @@ class timingWidget(kcgw.KCGWidgets):
         super(timingWidget, self).closeEvent(event)
 
 
-
-
 def addTimingWidget():
     """
     Add this widget to the gui.

+ 1 - 1
setup.py

@@ -5,7 +5,7 @@ DESCRIPTION = "KCG KAPTURE Control Gui"
 
 setup(
     name='KCG',
-    version='0.3.2.162.0331-beta',
+    version='0.3.2.178.0412-beta',
     author='Patrick Schreiber',
     author_email='uldfk@student.kit.edu',
 #    license='GPL',