Bladeren bron

last update

NOTE: Trigger Acquirement with second method doesn't work every second
run
Patrick Schreiber 8 jaren geleden
bovenliggende
commit
fa5287c315
74 gewijzigde bestanden met toevoegingen van 4583 en 128 verwijderingen
  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
     :maxdepth: 2
 
 
     widgets
     widgets
-    multiWidget
-    kcgwidget
-    groupedelements
-    backendinterface
-    settings
+    code/index

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

@@ -6,6 +6,8 @@
 User documentation!
 User documentation!
 ===================
 ===================
 
 
+.. note:: This is out of date.
+
 .. toctree::
 .. toctree::
    :maxdepth: 2
    :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
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
 # ones.
 extensions = [
 extensions = [
-    'sphinx.ext.mathjax',
+#    'sphinx.ext.mathjax',
 ]
 ]
 
 
 # Add any paths that contain templates here, relative to this directory.
 # Add any paths that contain templates here, relative to this directory.
@@ -46,7 +46,7 @@ master_doc = 'index'
 
 
 # General information about the project.
 # General information about the project.
 project = u'KCG'
 project = u'KCG'
-copyright = u'2015, Patrick Schreiber'
+copyright = u'2016, Patrick Schreiber'
 
 
 rst_epilog = """
 rst_epilog = """
 .. |gui_name| replace:: {gui_name}
 .. |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.
 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 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::
 .. toctree::
    :maxdepth: 3
    :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):
 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:
     if simulate:
         start_pilot_bunch_emulator(board_id)
         start_pilot_bunch_emulator(board_id)
 
 
@@ -21,6 +27,11 @@ def acquire_data(board_id, filename, simulate=False):
 
 
 
 
 def data_reset(board_id):
 def data_reset(board_id):
+    """
+    Reset data
+    :param board_id: the board to reset
+    :return:
+    """
     log.vinfo('Data reset')
     log.vinfo('Data reset')
     pci.write(board_id, '000003f5', hex_mask='7')
     pci.write(board_id, '000003f5', hex_mask='7')
     time.sleep(0.05)
     time.sleep(0.05)
@@ -29,24 +40,41 @@ def data_reset(board_id):
 
 
 
 
 def flush_dma(board_id, dma='dma0'):
 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')
     log.vinfo('Flushing DMA Pipeline')
     pci.write(board_id, '03f0', hex_mask='CF0')
     pci.write(board_id, '03f0', hex_mask='CF0')
-    # TODO: implement identifier usage
     pci.read(board_id, dma=dma, destination='/dev/null')
     pci.read(board_id, dma=dma, destination='/dev/null')
 
 
 
 
 def stop_board(board_id):
 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.write(board_id, '0x01', '0x9040')
     pci.stop_dma(board_id)
     pci.stop_dma(board_id)
 
 
 
 
 def soft_reset(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')
     pci.write(board_id, '0x1', '0x9040', hex_mask='0x1')
     time.sleep(1)
     time.sleep(1)
     pci.write(board_id, '0x0', '0x9040', hex_mask='0x1')
     pci.write(board_id, '0x0', '0x9040', hex_mask='0x1')
 
 
 
 
 def start_pilot_bunch_emulator(board_id):
 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')
     log.vinfo('Start pilot bunch emulator')
     pci.write(board_id, '400003f0', hex_mask='400003F0')
     pci.write(board_id, '400003f0', hex_mask='400003F0')
     time.sleep(0.005)
     time.sleep(0.005)
@@ -54,6 +82,10 @@ def start_pilot_bunch_emulator(board_id):
 
 
 
 
 def start_acquisition(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')
     log.vinfo('Start acquisition')
     pci.write(board_id, '1', '4', hex_mask='1')  # what's this? write value 1 to register 4???
     pci.write(board_id, '1', '4', hex_mask='1')  # what's this? write value 1 to register 4???
     time.sleep(0.005)
     time.sleep(0.005)
@@ -61,12 +93,21 @@ def start_acquisition(board_id):
 
 
 
 
 def stop_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')
     log.vinfo('Stop acquisition')
     pci.write(board_id, '003f0', hex_mask='CF0')
     pci.write(board_id, '003f0', hex_mask='CF0')
     time.sleep(0.005)
     time.sleep(0.005)
 
 
 
 
 def enable_transfer(board_id):
 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')
     log.vinfo('Enable data transfer')
     pci.write(board_id, '007f0', hex_mask='CF0')
     pci.write(board_id, '007f0', hex_mask='CF0')
     time.sleep(0.005)
     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):
 class BoardConfiguration(QtGui.QWidget):
+    """
+    The Main configuration class for boards.
+    """
     callback_signal = QtCore.pyqtSignal(str, list)
     callback_signal = QtCore.pyqtSignal(str, list)
 
 
     def __init__(self, identifier, config_file=None):
     def __init__(self, identifier, config_file=None):
@@ -28,6 +31,9 @@ class BoardConfiguration(QtGui.QWidget):
             self.load_config(config_file)
             self.load_config(config_file)
 
 
     def _set_defaults(self):
     def _set_defaults(self):
+        """
+        Set default values
+        """
         self._config ={
         self._config ={
             'fpga_delay_max': 15,
             'fpga_delay_max': 15,
             'fpga_delay': 0,
             'fpga_delay': 0,
@@ -68,11 +74,17 @@ class BoardConfiguration(QtGui.QWidget):
         }
         }
 
 
     def set_default_observers(self):
     def set_default_observers(self):
+        """
+        Set observers that are always used
+        """
         self.observe(None, self.update_header, 'header')
         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), '0x9020'), 'orbits_observe')
         self.observe(None, lambda x: pci.write(self.identifier, hex(x), '0x9028'), 'orbits_skip')
         self.observe(None, lambda x: pci.write(self.identifier, hex(x), '0x9028'), 'orbits_skip')
 
 
     def notify_all_observers(self):
     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():
         for key, value in self._config.items():
             self._notify_observers(key, value)
             self._notify_observers(key, value)
             # observers = self._observers.get(key, None)
             # observers = self._observers.get(key, None)
@@ -82,6 +94,11 @@ class BoardConfiguration(QtGui.QWidget):
 
 
 
 
     def load_config(self, filename):
     def load_config(self, filename):
+        """
+        Load a config from a file
+        :param filename: the configuration file
+        :return:
+        """
         if filename:
         if filename:
             config = ConfigParser.RawConfigParser()
             config = ConfigParser.RawConfigParser()
             if not config.read(str(filename)):
             if not config.read(str(filename)):
@@ -103,6 +120,10 @@ class BoardConfiguration(QtGui.QWidget):
             return False
             return False
 
 
     def save_config(self, filename):
     def save_config(self, filename):
+        """
+        Save the current configuration to a file
+        :param filename: the file to write to
+        """
         if filename:
         if filename:
             # with open(filename, 'w') as f:
             # with open(filename, 'w') as f:
             try:
             try:
@@ -129,24 +150,49 @@ class BoardConfiguration(QtGui.QWidget):
             return False
             return False
 
 
     def get(self, key):
     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:
         if not key in self._config:
             raise NoSuchKeyError(key+" is not registered in BoardConfiguration for board "+str(self.identifier))
             raise NoSuchKeyError(key+" is not registered in BoardConfiguration for board "+str(self.identifier))
         return self._config.get(key, None)
         return self._config.get(key, None)
 
 
     def dump(self):
     def dump(self):
+        """
+        Dump all configuration values
+        :return: all configuration values as list
+        """
         s = ""
         s = ""
         for key in self._config.keys():
         for key in self._config.keys():
             s += key + ": " + str(self.get(key)) + ", "
             s += key + ": " + str(self.get(key)) + ", "
         return s[:-1]
         return s[:-1]
 
 
     def update(self, key, value):
     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._config[key] = value
         self._notify_observers(key, value)
         self._notify_observers(key, value)
 
 
     def updateSilent(self, 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
         self._config[key] = value
 
 
     def observe(self, who, callback, key):
     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():
         if key not in self._config.keys():
             raise ObserverError(str("Key '%s' is unknown." % key))
             raise ObserverError(str("Key '%s' is unknown." % key))
 
 
@@ -156,12 +202,21 @@ class BoardConfiguration(QtGui.QWidget):
         self._observers[key].append([who, callback])
         self._observers[key].append([who, callback])
 
 
     def observe_all(self, 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:
         if callback not in self._observers_for_all:
             self._observers_for_all.append(callback)
             self._observers_for_all.append(callback)
         else:
         else:
             raise ObserverError("Observer already registered")
             raise ObserverError("Observer already registered")
 
 
     def unobserve(self, who, key=None):
     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:
         if key is not None:
             observers = np.array(self._observers.get(key, None))
             observers = np.array(self._observers.get(key, None))
             if observers is None:
             if observers is None:
@@ -183,10 +238,19 @@ class BoardConfiguration(QtGui.QWidget):
                         del self._observers[_key]
                         del self._observers[_key]
 
 
     def unobserve_all_observer(self, callback):
     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:
         if callback in self._observers_for_all:
             del self._observers_for_all[self._observers_for_all.index(callback)]
             del self._observers_for_all[self._observers_for_all.index(callback)]
 
 
     def _notify_observers_receiver(self, key, value):
     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)
         observers = self._observers.get(str(key), None)
         value = value[0]
         value = value[0]
         if observers is None:
         if observers is None:
@@ -198,9 +262,21 @@ class BoardConfiguration(QtGui.QWidget):
             cb(key, value)
             cb(key, value)
 
 
     def _notify_observers(self, 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])
         self.callback_signal.emit(key, [value])
 
 
     def make_uint(self, value, maximum, name=None):
     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:
         if value is None:
             raise ValueError(str("%s Value is invalid (None)" % name))
             raise ValueError(str("%s Value is invalid (None)" % name))
 
 
@@ -220,6 +296,10 @@ class BoardConfiguration(QtGui.QWidget):
         return val
         return val
 
 
     def set_fpga_delay(self, value):
     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')
         time_factor = self.make_uint(value, self.get('fpga_delay_max'), 'FPGA_Delay')
         reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "0"
         reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "0"
         pci.write(self.identifier, reg_value, '0x9060')
         pci.write(self.identifier, reg_value, '0x9060')
@@ -227,6 +307,11 @@ class BoardConfiguration(QtGui.QWidget):
         self.update('fpga_delay', value)
         self.update('fpga_delay', value)
 
 
     def set_chip_delay(self, adcs, values):
     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:
         if not adcs or not values:
             logging.vinfo("Nothing to do for chip delay.")
             logging.vinfo("Nothing to do for chip delay.")
             return
             return
@@ -268,6 +353,10 @@ class BoardConfiguration(QtGui.QWidget):
             self.update(s, value)
             self.update(s, value)
 
 
     def set_th_delay(self, 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')
         time_factor = self.make_uint(value, self.get('th_delay_max'), 'TH_Delay')
         reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "3"
         reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "3"
         pci.write(self.identifier, reg_value, '0x9060')
         pci.write(self.identifier, reg_value, '0x9060')
@@ -275,6 +364,11 @@ class BoardConfiguration(QtGui.QWidget):
         self.update('th_delay', value)
         self.update('th_delay', value)
 
 
     def set_adc_delay(self, adc, 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:
         if adc is None or value is None:
             logging.vinfo("Nothing to do for ADC delay.")
             logging.vinfo("Nothing to do for ADC delay.")
             return
             return
@@ -288,7 +382,13 @@ class BoardConfiguration(QtGui.QWidget):
         self.update(adc_s, _val)
         self.update(adc_s, _val)
 
 
     def set_delay(self, n, ignore_seperate_delay=False):
     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):
         def write_delay(value, channel):
+            '''write the delays to the board'''
             cmd = '00501' + '%01x' % value + str(channel)
             cmd = '00501' + '%01x' % value + str(channel)
             pci.write(self.identifier, cmd, reg='0x9060')
             pci.write(self.identifier, cmd, reg='0x9060')
             time.sleep(0.005)
             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)
             logging.error("Error in Board Communication, was unable to write value to board "+reason)
 
 
     def read_from_board(self):
     def read_from_board(self):
+        """
+        Read values from board and update them in the configuration (Mainly used for skip init functionality)
+        """
         try:
         try:
             settings = ['chip_1_delay','chip_2_delay','chip_3_delay','chip_4_delay']
             settings = ['chip_1_delay','chip_2_delay','chip_3_delay','chip_4_delay']
             # --[ read fine/chip delays ]
             # --[ 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)
             return dict_.get(what, what)
 
 
         if config.board_detection_method == 'dev':
         if config.board_detection_method == 'dev':
-            # searchstring = '/dev/fpga'
-            searchstring = '/dev/lp'
+            searchstring = '/dev/fpga'
+            # searchstring = '/dev/lp'
             device_list = glob.glob(searchstring+'*')
             device_list = glob.glob(searchstring+'*')
             log.info("Found {num} devices.".format(num=len(device_list)))
             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
         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
     @property
     def board_ids(self):
     def board_ids(self):

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

@@ -11,10 +11,18 @@ from ...kcgwidget import error
 
 
 
 
 class PCI(object):
 class PCI(object):
+    """
+    The Interface to the pci command
+    """
     def __init__(self):
     def __init__(self):
         pass
         pass
 
 
     def _safe_call(self, cmd):
     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)
         log.debug(cmd)
         try:
         try:
             # if '-r' in cmd:
             # if '-r' in cmd:
@@ -31,6 +39,11 @@ class PCI(object):
                 raise BoardError('{}: {}'.format(' '.join(cmd), str(e)))
                 raise BoardError('{}: {}'.format(' '.join(cmd), str(e)))
 
 
     def _format(self, output):
     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")
         output = output.split("\n")
         lines = []
         lines = []
         for line in output:
         for line in output:
@@ -73,7 +86,7 @@ class PCI(object):
         if reg:
         if reg:
             cmd_extend = ["-s%i" % amount]
             cmd_extend = ["-s%i" % amount]
         else:
         else:
-            cmd_extend = ['-o', dst, '--multipacket']
+            cmd_extend = ['--multipacket', '-o', dst]
             if timeout:
             if timeout:
                 cmd_extend.extend(['--timeout', str(timeout)])
                 cmd_extend.extend(['--timeout', str(timeout)])
             log.vinfo('Write data to {}'.format(dst))
             log.vinfo('Write data to {}'.format(dst))
@@ -99,8 +112,6 @@ class PCI(object):
         else:
         else:
             if dst == '/dev/stdout':
             if dst == '/dev/stdout':
                 return output.split('Writting')[0]
                 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'):
     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]
         cmd = ['pci', '-d', available_boards.get_device_file(board_id), '-w', reg, value]
         self._safe_call(cmd)
         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):
     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
         :param dma: the dma to use
         :return:
         :return:
         """
         """
-        # TODO: implement identifier usage
         log.vinfo('Start DMA')
         log.vinfo('Start DMA')
         cmd = ['pci', '-d', available_boards.get_device_file(board_id), '--start-dma', dma]
         cmd = ['pci', '-d', available_boards.get_device_file(board_id), '--start-dma', dma]
         self._safe_call(cmd)
         self._safe_call(cmd)
@@ -173,7 +183,6 @@ class PCI(object):
         :param dma: the dma to use
         :param dma: the dma to use
         :return:
         :return:
         """
         """
-        # TODO: implement identifier usage
         log.vinfo('Stop DMA')
         log.vinfo('Stop DMA')
         cmd = ['pci', '-d', available_boards.get_device_file(board_id), '--stop-dma', dma]
         cmd = ['pci', '-d', available_boards.get_device_file(board_id), '--stop-dma', dma]
         self._safe_call(cmd)
         self._safe_call(cmd)

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

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

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

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

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

@@ -9,9 +9,17 @@ from errors import *
 from status import StatusStorage
 from status import StatusStorage
 from board_config import BoardConfiguration
 from board_config import BoardConfiguration
 from .... import config as kcg_config
 from .... import config as kcg_config
+from boards_connected import available_boards
 
 
 
 
 def get_dec_from_bits(bits, msb=-1, lsb=-1):
 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
     rtrnValue = 0
     if (msb < 0 or lsb < 0):
     if (msb < 0 or lsb < 0):
         rtrnValue = int(bits)
         rtrnValue = int(bits)
@@ -101,6 +109,11 @@ def get_status(board_id):
 
 
 
 
 def is_conneced(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:
     try:
         pci.read(board_id, 1, '0x9040')
         pci.read(board_id, 1, '0x9040')
         return True
         return True
@@ -111,12 +124,22 @@ def is_conneced(board_id):
 
 
 
 
 def is_active(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 = pci.read(board_id, 1, '0x9040')[0]
     control_bits = '{0:032b}'.format(int(control, 16))
     control_bits = '{0:032b}'.format(int(control, 16))
     return control_bits[22:26] == "1111"
     return control_bits[22:26] == "1111"
 
 
 
 
 def wait_for_revolutions(board_id):
 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 = 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
     # n = 1 # Use this for debugging purposes if no board is connected
     spin_time_ns = kcg_config.tRev * n
     spin_time_ns = kcg_config.tRev * n
@@ -140,8 +163,18 @@ def create_new_board_config(identifier):
 
 
 
 
 def get_board_config(id):
 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]
     return _configs[id]
 
 
 
 
 def get_board_status(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]
     return _status[id]

+ 72 - 28
KCG/base/backendinterface.py

@@ -1,7 +1,7 @@
 """
 """
 This is the interface to the backend.
 This is the interface to the backend.
 It is used to make the backend easily interchangable.
 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_
 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():
 def bk_status_readout():
+    """
+    Read Status for every connected board
+    """
+    if not available_boards.has_boards:
+        return
     for brd in available_boards.board_ids:
     for brd in available_boards.board_ids:
         _bif_status_readout(brd)
         _bif_status_readout(brd)
 
 
@@ -137,10 +142,8 @@ class PopupDialog(QtGui.QDialog):
         QtGui.QDialog.__init__(self, parent)
         QtGui.QDialog.__init__(self, parent)
         self.text = text
         self.text = text
         self.setWindowTitle(title if title else tr("Dialog", "User action required"))
         self.setWindowTitle(title if title else tr("Dialog", "User action required"))
-        self.do_layout()
         self.return_value = False
         self.return_value = False
 
 
-    def do_layout(self):
         size = QtCore.QSize(200, 200)
         size = QtCore.QSize(200, 200)
         # self.setMaximumSize(size)
         # self.setMaximumSize(size)
         self.setMinimumSize(size)
         self.setMinimumSize(size)
@@ -160,13 +163,24 @@ class PopupDialog(QtGui.QDialog):
         self.setLayout(box)
         self.setLayout(box)
 
 
     def on_okay(self):
     def on_okay(self):
+        """
+        Handler for the press of the ok button
+        """
         self.return_value = True
         self.return_value = True
         self.close()
         self.close()
 
 
     def on_cancel(self):
     def on_cancel(self):
+        """
+        Handler for the press of the cancel button
+        :return:
+        """
         self.close()
         self.close()
 
 
     def get_return_value(self):
     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
         return self.return_value
 
 
 
 
@@ -305,6 +319,10 @@ def bk_calibrate(board_id, do_the_rest=None):
         finished = QtCore.pyqtSignal()
         finished = QtCore.pyqtSignal()
 
 
         def calibrate(self):
         def calibrate(self):
+            """
+            The method that is called inside the thread and that does the calibration
+            :return:
+            """
             try:
             try:
                 logging.info('Started Board Calibration')
                 logging.info('Started Board Calibration')
                 for idx, step in enumerate(sequence):
                 for idx, step in enumerate(sequence):
@@ -321,6 +339,10 @@ def bk_calibrate(board_id, do_the_rest=None):
             self.finished.emit()
             self.finished.emit()
 
 
     def thread_quit():
     def thread_quit():
+        """
+        Method to handle the end of the calibration thread
+        :return:
+        """
         thread.stop()
         thread.stop()
         bk_status_readout()
         bk_status_readout()
         progressbar.remove(0)
         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])
     storage.get_board_specific_storage(board_id).acquisition_progressbar.setValue(storage.storage.current_acquisition[board_id])
 
 
     def on_timeout():
     def on_timeout():
+        '''Handler for the timeout of the acquisition timer. This does the acquisition'''
         if storage.storage.current_acquisition[board_id] < num_acquisitions:
         if storage.storage.current_acquisition[board_id] < num_acquisitions:
             storage.storage.current_acquisition[board_id] += 1
             storage.storage.current_acquisition[board_id] += 1
             storage.get_board_specific_storage(board_id).acquisition_progressbar.setValue(storage.storage.current_acquisition[board_id])
             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)
         data_raw = board.pci.read_data_to_variable(board_id)
         _bif_read_and_update_data_from_string(board_id, data_raw)
         _bif_read_and_update_data_from_string(board_id, data_raw)
     except board.BoardError as e:
     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):
 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
     :param board_id: id of the board do manipulate
     :return: -
     :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):
 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))
     timescan_progressbar.setRange(1, ((f_to - f_frm) + 1) * ((c_to - c_frm) + 1))
 
 
     class thread_time_scan(QtCore.QObject):
     class thread_time_scan(QtCore.QObject):
+        '''Timescan Thread class'''
         pbarSignal = QtCore.pyqtSignal(int)
         pbarSignal = QtCore.pyqtSignal(int)
         stopSignal = QtCore.pyqtSignal()
         stopSignal = QtCore.pyqtSignal()
         finished = 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
             self.timescan_progressbar = timescan_progressbar
 
 
         def time_scan(self):
         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)))
             Elements.setEnabled('acquire_{}'.format(board_id), False, exclude=Elements.getElements('start_time_scan_{}'.format(board_id)))
             if orbits_observe:
             if orbits_observe:
                 if not hasattr(storage.storage, 'orbits_observe_before_timescan'):
                 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.
                         # This information has to be removed here.
                         # To do so we split the output string from PCI at "Writting" (Note: Writting is correct as
                         # 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)
                         # 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)
                         data = io.read_from_string(data_raw, force=True, cache=False)
                     except board.BoardError as e:
                     except board.BoardError as e:
                         self.stopSignal.emit()
                         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()
             self.finished.emit()
 
 
     def finished(timescan_progressbar):
     def finished(timescan_progressbar):
+        '''Method to handle the end of the thread'''
         thread.stop()
         thread.stop()
         _bif_stop_time_scan(board_id, timescan_progressbar)
         _bif_stop_time_scan(board_id, timescan_progressbar)
         Elements.setEnabled('acquire_{}'.format(board_id), True, exclude=Elements.getElements('start_time_scan_{}'.format(board_id)))
         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
     :param board_id: id of the board do manipulate
     :return: -
     :return: -
     """
     """
-    global bk_status_readout, bk_get_temperature
+    # global bk_status_readout, bk_get_temperature
     board_status = bk_board_connected(board_id)
     board_status = bk_board_connected(board_id)
     if board_status:
     if board_status:
         if not hasattr(board.get_board_status(board_id), 'board_connected') or \
         if not hasattr(board.get_board_status(board_id), 'board_connected') or \
                 not board.get_board_status(board_id).board_connected:
                 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
         board.get_board_status(board_id).board_connected = True
 
 
     else:
     else:
@@ -1219,8 +1244,8 @@ def bk_check_for_board(board_id):
         def no_temp(board_id):
         def no_temp(board_id):
             return "-"
             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
         board.get_board_status(board_id).board_connected = False
         if board_status == False:
         if board_status == False:
             board.get_board_status(board_id).status_text = tr("sw", "Board {} not connected".format(board_id))
             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:
     if thread.running:
         # Elements.getElements("acquireTrigger_{}".format(board_id))[0].setText(tr("Button", "Start Acquisition"))
         # 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))
         log(board_id=board_id, additional="Stop wait on trigger on board {}".format(board_id))
+        thread.quit()
         thread.stop()
         thread.stop()
         # for elem in Elements.getElements("acquire_{}".format(board_id)):
         # for elem in Elements.getElements("acquire_{}".format(board_id)):
         #     if isinstance(elem, QtGui.QShortcut):
         #     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")
     board.pci.write(board_id, hex(num_of_acquisitions), "9024")
     time.sleep(0.1)
     time.sleep(0.1)
     board.pci.write(board_id, hex(skip), "902C")
     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
     # 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
     # 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
     # 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
     # Logging (using the logging module) is directly connected to the main thread and could cause problems
     class thread_wait_on_signal(QtCore.QObject):
     class thread_wait_on_signal(QtCore.QObject):
+        '''Class to run the wait on signal functionality in a thread'''
         countUpdate = QtCore.pyqtSignal(int)
         countUpdate = QtCore.pyqtSignal(int)
         stopSignal = QtCore.pyqtSignal()
         stopSignal = QtCore.pyqtSignal()
         finished = 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__()
             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.noa = num_of_acquisitions
             self.path = path
             self.path = path
             self.timeout = timeout
             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)))
             # Elements.setEnabled('acquireTrigger_{}'.format(board_id), False) # exclude=Elements.getElements('wait_on_trigger_{}'.format(board_id)))
 
 
         def wait_rw_simul(self):
         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
             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):
             for num_of_acq in xrange(self.noa):
                 # def step():
                 # def step():
                 filename = self.path +'/{:0.3f}.out'.format(time.time())
                 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.read_data_to_file(board_id, filename=filename, timeout=(self.timeout*1000000))
                 # rename with correct timestamp - last modified time
                 # 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:
                 if self._quit:
                     break
                     break
 
 
@@ -1343,20 +1377,21 @@ def _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, ti
                     continue
                     continue
 
 
                 newfile = '{path}/trigger_{num:05}_{htime}_{unixtime}.out'.format(
                 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'),
                     htime=dt.fromtimestamp(os.path.getmtime(filename)).strftime('%Y-%m-%dT%Hh%Mm%Ss%f'),
                     unixtime=int(os.path.getmtime(filename)),
                     unixtime=int(os.path.getmtime(filename)),
                     path=self.path
                     path=self.path
                 )
                 )
                 os.rename(filename, newfile)
                 os.rename(filename, newfile)
                 if os.path.getsize(newfile) > 0:
                 if os.path.getsize(newfile) > 0:
-                    self.liveplot.emit(newfile)
+                    self.liveplot.emit(board_id, newfile)
                 else:
                 else:
                     logging.info("Acquired 0b, possible trigger timeout.")
                     logging.info("Acquired 0b, possible trigger timeout.")
 
 
             self.finished.emit()
             self.finished.emit()
 
 
         def wait_rw_seq(self):
         def wait_rw_seq(self):
+            '''Wait sequentially (in the gui) for a trigger signal'''
             for num_of_acq in xrange(self.noa):
             for num_of_acq in xrange(self.noa):
                 board.pci.write(board_id, '00bf0', hex_mask='CF0')  # enable readout
                 board.pci.write(board_id, '00bf0', hex_mask='CF0')  # enable readout
                 pre_acq_num = board.pci.read(board_id, 1, '9034')[0]
                 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
                     board.pci.write(board_id, '007f0', hex_mask='CF0')  # enable transfer
                     filename = self.path +'/{:0.3f}.out'.format(time.time())
                     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.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))
                     self.countUpdate.emit(copy.deepcopy(num_of_acq+1))
                     if self._quit:
                     if self._quit:
                         break
                         break
@@ -1384,13 +1419,13 @@ def _bif_start_wait_on_trigger(board_id, num_of_acquisitions=None, skip=None, ti
                         continue
                         continue
 
 
                     newfile = '{path}/trigger_{num:05}_{htime}_{unixtime}.out'.format(
                     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'),
                         htime=dt.fromtimestamp(os.path.getmtime(filename)).strftime('%Y-%m-%dT%Hh%Mm%Ss%f'),
                         unixtime=int(os.path.getmtime(filename)),
                         unixtime=int(os.path.getmtime(filename)),
                         path=self.path
                         path=self.path
                     )
                     )
                     os.rename(filename, newfile)
                     os.rename(filename, newfile)
-                    self.liveplot.emit(newfile)
+                    self.liveplot.emit(board_id, newfile)
                 else:
                 else:
                     logging.info("Trigger timeout.")
                     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()
             self.finished.emit()
 
 
         def quit(self):
         def quit(self):
+            '''quit this thread'''
             self._quit = True
             self._quit = True
 
 
         def __del__(self):
         def __del__(self):
+            print 'quite'
             board.pci.write(board_id, '0', '9024')
             board.pci.write(board_id, '0', '9024')
             time.sleep(0.1)
             time.sleep(0.1)
             board.pci.write(board_id, '0', '902C')
             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
             board.pci.write(board_id, '3f0', hex_mask='ff0')  # TODO: This writes t/h 3/4 but enable_transfer etc do not
 
 
     def finished():
     def finished():
+        '''Handle the end of the thread'''
         board.pci.write(board_id, '0', '9024')
         board.pci.write(board_id, '0', '9024')
         time.sleep(0.1)
         time.sleep(0.1)
         board.pci.write(board_id, '0', '902C')
         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
         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('countUpdate', storage.get_board_specific_storage(board_id).trigger_progressbar.setValue)
     thread.connect('finished', finished)
     thread.connect('finished', finished)
     thread.connect('liveplot', _bif_read_and_update_data_from_file)
     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)
         self.setLayout(self.layout)
 
 
     def set_on(self):
     def set_on(self):
-        """ See set_on of LED Class """
+        """
+        See set_on of LED Class
+        """
         self.led.set_on()
         self.led.set_on()
 
 
     def set_off(self):
     def set_off(self):
-        """ See set_off of LED Class """
+        """
+        See set_off of LED Class
+        """
         self.led.set_off()
         self.led.set_off()
 
 
     def set_out(self):
     def set_out(self):
-        """ See set_out of LED Class """
+        """
+        See set_out of LED Class
+        """
         self.led.set_out()
         self.led.set_out()
 
 
     def set_tri(self):
     def set_tri(self):
-        """ See set_tri of LED Class """
+        """
+        See set_tri of LED Class
+        """
         self.led.set_tri()
         self.led.set_tri()
 
 
     def set_status(self, status):
     def set_status(self, status):
@@ -158,6 +166,9 @@ class StatusLED(QtGui.QWidget):
 
 
 
 
 class BoardControl(kcgw.KCGWidgets):
 class BoardControl(kcgw.KCGWidgets):
+    """
+    The main view of the gui for each board at startup
+    """
     def __init__(self, board_id, single=False):
     def __init__(self, board_id, single=False):
         super(BoardControl, self).__init__()
         super(BoardControl, self).__init__()
         self.board_id = board_id
         self.board_id = board_id
@@ -255,6 +266,9 @@ class BoardControl(kcgw.KCGWidgets):
         self.subControlWidget.hide()
         self.subControlWidget.hide()
 
 
     def toggle_sub_control(self):
     def toggle_sub_control(self):
+        """
+        Show or hide the subcontrol buttons
+        """
         self.subControlWidget.setHidden(not self.subControlWidget.isHidden())
         self.subControlWidget.setHidden(not self.subControlWidget.isHidden())
         if self.subControlWidget.isHidden():
         if self.subControlWidget.isHidden():
             self.toggleButton.setIcon(QtGui.QIcon(config.install_path+"icons/chevron-bottom.svg"))
             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)
             bif.bk_calibrate(self.board_id, do_the_rest)
 
 
     def skip_init(self):
     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_config(self.board_id).read_from_board()
         board.get_board_status(self.board_id).calibrated = True
         board.get_board_status(self.board_id).calibrated = True
         board.get_board_status(self.board_id).synced = True
         board.get_board_status(self.board_id).synced = True

+ 13 - 0
KCG/base/globals.py

@@ -1,11 +1,24 @@
 class Globals(object):
 class Globals(object):
+    """
+    Object to make it easy to work with global values
+    """
     def __init__(self):
     def __init__(self):
         self._globals = dict()
         self._globals = dict()
 
 
     def get_global(self, item):
     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)
         return self._globals.get(item, None)
 
 
     def set_global(self, key, value):
     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
         self._globals[key] = value
 
 
 glob = Globals()
 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.
         Set Flags that define the behaviour of GroupedObjects in various events.
         :param flagDict: Dictionary containing the Flags.
         :param flagDict: Dictionary containing the Flags.
                         Possible Flags are: (They are to be of type bool)
                         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
                             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
                             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
                             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)
                             autoremove is performed (see above)
         :return: -
         :return: -
         """
         """
@@ -260,18 +261,6 @@ class LivePlotWindows():
 
 
 # Every Element is acessible through every Variable set here. Checkboxes, Buttons and MenuItems variables are set
 # 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
 # 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()
 Elements = Checkboxes = Buttons = MenuItems = GroupedObjects()
 live_plot_windows = LivePlotWindows()
 live_plot_windows = LivePlotWindows()

+ 27 - 8
KCG/base/kcg.py

@@ -139,7 +139,6 @@ class CentralWidget(kcgw.KCGWidgets):
         self.tableWidget.hide()
         self.tableWidget.hide()
 
 
 
 
-
 class Gui(QtGui.QMainWindow):
 class Gui(QtGui.QMainWindow):
     """
     """
     Main Window of the KCG gui
     Main Window of the KCG gui
@@ -177,7 +176,6 @@ class Gui(QtGui.QMainWindow):
         self.after_start_status_handler()
         self.after_start_status_handler()
         self.setContentsMargins(0, -10, 0, 0)
         self.setContentsMargins(0, -10, 0, 0)
 
 
-
     def initUI(self):
     def initUI(self):
         """
         """
         Initialize ui
         Initialize ui
@@ -230,7 +228,6 @@ class Gui(QtGui.QMainWindow):
         for e in config.default_log_entries:  # for every entry:
         for e in config.default_log_entries:  # for every entry:
             if e in logStrings:
             if e in logStrings:
                 self.measurementLogger.register_parameter(e, functionAndParameter[logStrings.index(e)][0], functionAndParameter[logStrings.index(e)][1])
                 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:
         if log.no_epics and log.epics_reachable:
             logging.error("Epics installation not found. Logfiles will not contain information that is to be "
             logging.error("Epics installation not found. Logfiles will not contain information that is to be "
                          "obtained via epics.")
                          "obtained via epics.")
@@ -239,7 +236,6 @@ class Gui(QtGui.QMainWindow):
                         "information that is to be obtained via epics.")
                         "information that is to be obtained via epics.")
 
 
 
 
-
     def doMenu(self):
     def doMenu(self):
         """
         """
         Create and show the menu and it's entries
         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)
         self.help.addAction(tr("Button", "About"), self.showAbout)
 
 
     def saveConfig(self, board_id):
     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 = QtGui.QFileDialog(self, tr("Heading", "Save Configuration"), '', 'KAPTURE Configuration File (*.kcf)')
         filenameDialog.setDefaultSuffix("kcf")
         filenameDialog.setDefaultSuffix("kcf")
         filenameDialog.setAcceptMode(filenameDialog.AcceptSave)
         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."))
             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):
     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)')
         filename = QtGui.QFileDialog.getOpenFileName(self, 'Open Configuration', '', 'KAPTURE Configuration File (*.kcf)')
         if not filename:
         if not filename:
             return
             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."))
             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):
     def rerunConfig(self):
+        """
+        Rerun the initial configuration wizard
+        """
         self.setupConfig = initialconfig.ConfigSetup(restart=True)
         self.setupConfig = initialconfig.ConfigSetup(restart=True)
         self.setupConfig.setWindowModality(QtCore.Qt.ApplicationModal)
         self.setupConfig.setWindowModality(QtCore.Qt.ApplicationModal)
         def restart():
         def restart():
@@ -330,7 +337,7 @@ class Gui(QtGui.QMainWindow):
         :return: -
         :return: -
         """
         """
         version = open(config.install_path+"VERSION").read()
         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.setWindowTitle("KCG - About")
         about_label = QtGui.QLabel(tr("About", "KAPTURE Control Gui\n"
         about_label = QtGui.QLabel(tr("About", "KAPTURE Control Gui\n"
                                       "KCG is a graphical control interface to the KAPTURE board\n\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)
                 QtGui.QMessageBox.information(self, "Change Language", "Language change takes effect after Gui restart", 1)
             if setting == 'advanced_control':
             if setting == 'advanced_control':
                 self.showAdvancedControl(getattr(self.storage, setting))
                 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):
     def showAdvancedControl(self, value):
         """
         """
@@ -420,7 +432,13 @@ class Gui(QtGui.QMainWindow):
                 self.cw.tableWidget.hide()
                 self.cw.tableWidget.hide()
 
 
     def after_start_status_handler(self):
     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):
     def populate_storage(self):
         """
         """
@@ -433,6 +451,7 @@ class Gui(QtGui.QMainWindow):
         self.storage.language = config.language
         self.storage.language = config.language
         self.storage.advanced_control = False
         self.storage.advanced_control = False
         def update_header(val):
         def update_header(val):
+            '''Update header'''
             self.storage.header = val
             self.storage.header = val
             if self.settings:
             if self.settings:
                 self.settings.headerTick.setChecked(val)
                 self.settings.headerTick.setChecked(val)

+ 81 - 8
KCG/base/kcgwidget.py

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

+ 14 - 1
KCG/base/leftbar.py

@@ -22,6 +22,9 @@ FILE = 2
 
 
 
 
 class BoardSpecificInformation(kcgw.KCGWidgets):
 class BoardSpecificInformation(kcgw.KCGWidgets):
+    """
+    Specific Part for each board
+    """
     def __init__(self, board_id):
     def __init__(self, board_id):
         """
         """
         This creates the information part for board with id 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:"))
         self.temperature = self.createLabel(tr("Label", "Temp:"))
 
 
         def update_temp():
         def update_temp():
+            '''update the temperature in the gui'''
             if bif.bk_get_board_status(board_id, 'board_connected'):
             if bif.bk_get_board_status(board_id, 'board_connected'):
                 self.temperature.setText("Temp: " + bif.bk_get_temperature(board_id) + u" °C")
                 self.temperature.setText("Temp: " + bif.bk_get_temperature(board_id) + u" °C")
         try:
         try:
@@ -82,7 +86,7 @@ class BoardSpecificInformation(kcgw.KCGWidgets):
 
 
         self.boardSpecificLayout = QtGui.QVBoxLayout()
         self.boardSpecificLayout = QtGui.QVBoxLayout()
         self.setLayout(self.boardSpecificLayout)
         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.temperature, 0, 0)
         self.layout.addWidget(self.skipturns, 1, 1)
         self.layout.addWidget(self.skipturns, 1, 1)
         self.layout.addWidget(self.orbitsobserved, 1, 0)
         self.layout.addWidget(self.orbitsobserved, 1, 0)
@@ -278,6 +282,7 @@ class AcquisitionAndInfo(kcgw.KCGWidgets):
         pos = event.globalPos()
         pos = event.globalPos()
 
 
         def configure_log():
         def configure_log():
+            '''Open the configuration window for logs'''
             c = log.ConfigureLog(self)
             c = log.ConfigureLog(self)
             c.exec_()
             c.exec_()
             del c
             del c
@@ -326,6 +331,9 @@ class LeftBar(kcgw.KCGWidgets):
         self.initUI()
         self.initUI()
 
 
     def initUI(self):
     def initUI(self):
+        """
+        Initialise the UI
+        """
         self.layout = QtGui.QVBoxLayout()
         self.layout = QtGui.QVBoxLayout()
         self.layout.setContentsMargins(0, 0, 5, 0)
         self.layout.setContentsMargins(0, 0, 5, 0)
         self.setMinimumWidth(230)
         self.setMinimumWidth(230)
@@ -348,6 +356,11 @@ class LeftBar(kcgw.KCGWidgets):
         self.setLayout(self.layout)
         self.setLayout(self.layout)
 
 
     def _generate_menu(self, menu, item):
     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"))
         heatmap = menu.addAction(tr("Button", "Heatmap"))
         fft = menu.addAction(tr("Button", "FFT"))
         fft = menu.addAction(tr("Button", "FFT"))
         trains = menu.addAction(tr("Button", "Trains"))
         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
 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
     NONE = -1
     INFO = 0
     INFO = 0
     DEBUG = 1
     DEBUG = 1
@@ -182,6 +185,7 @@ class MeasurementLogger(object):
                     self._log(bid, c)
                     self._log(bid, c)
         else:
         else:
             def do_the_log(bid):
             def do_the_log(bid):
+                '''Actually perform the log'''
                 st = []
                 st = []
                 if additional:
                 if additional:
                     s = additional.split('\n')[0]
                     s = additional.split('\n')[0]
@@ -259,7 +263,9 @@ class ConfigureLog(QtGui.QDialog):
             self.parameter.append((QtGui.QCheckBox(par[0]), par[1]))
             self.parameter.append((QtGui.QCheckBox(par[0]), par[1]))
 
 
         self.i = 0
         self.i = 0
+
         def add(w):
         def add(w):
+            '''add a widget to the layout. if w is 'sep' a seperator is added'''
             if w == 'sep':
             if w == 'sep':
                 sep = QtGui.QFrame()
                 sep = QtGui.QFrame()
                 sep.setFrameShape(QtGui.QFrame.HLine)
                 sep.setFrameShape(QtGui.QFrame.HLine)
@@ -318,11 +324,17 @@ class ConfigureLog(QtGui.QDialog):
         self.initial_ticks()
         self.initial_ticks()
 
 
     def initial_ticks(self):
     def initial_ticks(self):
+        """
+        Set the initial ticks.
+        """
         pf = np.array(logger.parameter_functions)
         pf = np.array(logger.parameter_functions)
         for cb, _ in self.parameter:
         for cb, _ in self.parameter:
             cb.setChecked(str(cb.text()) in pf[:, 2])
             cb.setChecked(str(cb.text()) in pf[:, 2])
 
 
     def all_changed(self):
     def all_changed(self):
+        """
+        This is called when the "all" checkbox is checked. It de/activates the other checkboxes
+        """
         if self.all.isChecked():
         if self.all.isChecked():
             for cb, _ in self.parameter:
             for cb, _ in self.parameter:
                 cb.setEnabled(False)
                 cb.setEnabled(False)
@@ -331,9 +343,14 @@ class ConfigureLog(QtGui.QDialog):
                 cb.setEnabled(True)
                 cb.setEnabled(True)
 
 
     def do(self):
     def do(self):
+        """
+        Change the logger instance to the activated log entries
+        :return:
+        """
         global logger
         global logger
         logger.reset_parameters()
         logger.reset_parameters()
         def nif(cb, f, args):
         def nif(cb, f, args):
+            '''actually set the new parameters'''
             if cb.isChecked() or self.all.isChecked():
             if cb.isChecked() or self.all.isChecked():
                 logger.register_parameter(str(cb.text()), f, args)
                 logger.register_parameter(str(cb.text()), f, args)
         for cb, par in self.parameter:
         for cb, par in self.parameter:

+ 42 - 0
KCG/base/loghandler.py

@@ -1,6 +1,11 @@
 import logging
 import logging
+from logging import handlers
+import os
+import sys
 from PyQt4 import QtGui, QtCore
 from PyQt4 import QtGui, QtCore
 
 
+from .. import config
+
 """
 """
 This intends to be a QThread save logging handler with syntax highlighting
 This intends to be a QThread save logging handler with syntax highlighting
 """
 """
@@ -19,12 +24,18 @@ class LogHandler(logging.Handler):
         self._bold = 100
         self._bold = 100
 
 
     def emit(self, record):
     def emit(self, record):
+        """
+        Emit a log record
+        """
         self.acquire()
         self.acquire()
         self.text_area.append_signal.emit(record)
         self.text_area.append_signal.emit(record)
         self.release()
         self.release()
 
 
 
 
 class Highlighter(QtGui.QSyntaxHighlighter):
 class Highlighter(QtGui.QSyntaxHighlighter):
+    """
+    Highlighter for the logging area
+    """
     def __init__(self, parent, theme):
     def __init__(self, parent, theme):
         super(Highlighter, self).__init__(parent, )
         super(Highlighter, self).__init__(parent, )
         self.parent = parent
         self.parent = parent
@@ -57,6 +68,10 @@ class Highlighter(QtGui.QSyntaxHighlighter):
         self.highlightingRules.append((self.error_pattern, error))
         self.highlightingRules.append((self.error_pattern, error))
 
 
     def setKeywords(self, kw):
     def setKeywords(self, kw):
+        """
+        Set the keywords to check for
+        :param kw: the keywords
+        """
         keyword = QtGui.QTextCharFormat()
         keyword = QtGui.QTextCharFormat()
         keyword.setForeground(QtCore.Qt.darkBlue)
         keyword.setForeground(QtCore.Qt.darkBlue)
         keyword.setFontWeight(QtGui.QFont.Bold)
         keyword.setFontWeight(QtGui.QFont.Bold)
@@ -66,6 +81,10 @@ class Highlighter(QtGui.QSyntaxHighlighter):
             self.highlightingRules.append((pattern, keyword))
             self.highlightingRules.append((pattern, keyword))
 
 
     def highlightBlock(self, text):
     def highlightBlock(self, text):
+        """
+        Highlight a block of text
+        :param text: the text to check in
+        """
         for pattern, format in self.highlightingRules:
         for pattern, format in self.highlightingRules:
             start = 0
             start = 0
             if pattern not in [self.timestamp_pattern, self.error_pattern, self.loglevel_pattern]:
             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):
 class LogArea(QtGui.QTextEdit):
+    """
+    The log area for the KCG Gui
+    """
     append_signal = QtCore.pyqtSignal(logging.LogRecord)
     append_signal = QtCore.pyqtSignal(logging.LogRecord)
 
 
     def __init__(self):
     def __init__(self):
         super(LogArea, self).__init__()
         super(LogArea, self).__init__()
         self.highlighter = Highlighter(self, 'Classic')
         self.highlighter = Highlighter(self, 'Classic')
         self.logHandler = None
         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)
         self.append_signal.connect(self.append)
 
 
     def init_logging(self):
     def init_logging(self):
+        """
+        Initialize logging
+        """
         self.logHandler = LogHandler(self)
         self.logHandler = LogHandler(self)
+        self.logHandler.setLevel(config.log_level)
         logging.getLogger().addHandler(self.logHandler)
         logging.getLogger().addHandler(self.logHandler)
 
 
     def append(self, record):
     def append(self, record):
+        """
+        Append to the logarea
+        :param record: the record to append
+        """
         super(LogArea, self).append(self.logHandler.format(record))
         super(LogArea, self).append(self.logHandler.format(record))
         self.ensureCursorVisible()
         self.ensureCursorVisible()
 
 
     def setKeywords(self, kw):
     def setKeywords(self, kw):
+        """
+        Set the keywords for the highlighter
+        :param kw: the keywords to set
+        """
         self.highlighter.setKeywords(kw)
         self.highlighter.setKeywords(kw)

+ 39 - 5
KCG/base/plotWidget.py

@@ -77,11 +77,19 @@ gradient = {'mode': 'rgb',
 
 
 
 
 class CustomGradientEditorItem(pg.GradientEditorItem):
 class CustomGradientEditorItem(pg.GradientEditorItem):
+    """
+    A Gradient Editor Item to insert a perception linear gradient
+    """
     def __init__(self, **kwargs):
     def __init__(self, **kwargs):
         pg.GradientEditorItem.__init__(self, **kwargs)
         pg.GradientEditorItem.__init__(self, **kwargs)
         self.customGradients = {}
         self.customGradients = {}
 
 
     def addGrad(self, name, grad_dic):
     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:
         if name not in self.customGradients:
             self.customGradients[name] = grad_dic
             self.customGradients[name] = grad_dic
             px = QtGui.QPixmap(100, 15)
             px = QtGui.QPixmap(100, 15)
@@ -110,6 +118,10 @@ class CustomGradientEditorItem(pg.GradientEditorItem):
         self.restoreState(grad_dic)
         self.restoreState(grad_dic)
 
 
     def restoreState(self, state):
     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'])
         self.setColorMode(state['mode'])
         for t in list(self.ticks.keys()):
         for t in list(self.ticks.keys()):
             self.removeTick(t, finish=False)
             self.removeTick(t, finish=False)
@@ -134,12 +146,23 @@ class CustomGradientEditorItem(pg.GradientEditorItem):
         self.sigGradientChangeFinished.emit(self)
         self.sigGradientChangeFinished.emit(self)
 
 
     def loadPreset(self, name):
     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:
         if name in self.customGradients:
             self.restoreState(self.customGradients[name])
             self.restoreState(self.customGradients[name])
         else:
         else:
             super(CustomGradientEditorItem, self).loadPreset(name)
             super(CustomGradientEditorItem, self).loadPreset(name)
 
 
     def tickMoved(self, tick, pos):
     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]:
         if tick is self.bottomTick[0]:
             # self.bottomTick[1] = pos.x()
             # self.bottomTick[1] = pos.x()
             pg.TickSliderItem.tickMoved(self, tick, pos)
             pg.TickSliderItem.tickMoved(self, tick, pos)
@@ -270,7 +293,9 @@ class SubPlotWidget(pg.GraphicsLayoutWidget):
 
 
         self.gradient_legend = SpectrogramColorLegendItem(self.img)
         self.gradient_legend = SpectrogramColorLegendItem(self.img)
         def changelut():
         def changelut():
-            """ Handle changing of the lookup table"""
+            """
+            Handle changing of the lookup table
+            """
             self.img.setLookupTable(self.gradient_legend.getLookupTable(512))
             self.img.setLookupTable(self.gradient_legend.getLookupTable(512))
             self.img2.setLookupTable(self.gradient_legend.getLookupTable(512))
             self.img2.setLookupTable(self.gradient_legend.getLookupTable(512))
         self.gradient_legend.gradientChanged.connect(changelut)
         self.gradient_legend.gradientChanged.connect(changelut)
@@ -307,7 +332,7 @@ class SubPlotWidget(pg.GraphicsLayoutWidget):
         :return:
         :return:
         """
         """
         def newAutoRange(*args, **kwargs):
         def newAutoRange(*args, **kwargs):
-            """ function to handle the new autorange """
+            ''' function to handle the new autorange '''
             bounds = [np.min(data), np.max(data)]
             bounds = [np.min(data), np.max(data)]
             self.plotItem.vb.setRange(xRange=[0, len(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)
                 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.plotItem.getViewBox().autoRange()
 
 
         self.labelAxes()
         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):
     def labelAxes(self):
         """
         """
@@ -502,8 +528,8 @@ class SubPlotWidget(pg.GraphicsLayoutWidget):
         if type != self.plotType:
         if type != self.plotType:
             self._type_changed = True
             self._type_changed = True
         self.plotType = type
         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):
 class PlotWidget(kcgw.KCGWidgets):
     """
     """
@@ -706,6 +732,10 @@ class PlotWidget(kcgw.KCGWidgets):
         self.combined_button.setDisabled(b_bool)
         self.combined_button.setDisabled(b_bool)
 
 
     def changePlotType(self, type):
     def changePlotType(self, type):
+        """
+        Change the plot type to the given type.
+        :param type: the new type
+        """
         if type not in [ERROR, NO_DATA]:
         if type not in [ERROR, NO_DATA]:
             self._old_type = type
             self._old_type = type
         self.theType = 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)
             self.plot_widget.plot(self.data.combined(frm=f, to=t), autorange=autorange)
 
 
     def change_identifier_text(self):
     def change_identifier_text(self):
+        """
+        Change the text that identifies the plot in the left bar
+        :return:
+        """
         if self.theType is PlotType.Compare:
         if self.theType is PlotType.Compare:
             the_text = str(self.adc)+"+"+str(self.secadc)
             the_text = str(self.adc)+"+"+str(self.secadc)
         else:
         else:

+ 30 - 0
KCG/base/settings.py

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

+ 54 - 2
KCG/base/storage.py

@@ -18,6 +18,12 @@ class Storage(object):
             self._storage = default
             self._storage = default
 
 
     def setdefault(self, key, object):
     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)
         return self._storage.setdefault(key, object)
 
 
     def __setattr__(self, key, value):
     def __setattr__(self, key, value):
@@ -40,6 +46,11 @@ _board_specific_storages = {}
 
 
 
 
 def get_board_specific_storage(board_id):
 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:
     if board_id in _board_specific_storages:
         return _board_specific_storages[board_id]
         return _board_specific_storages[board_id]
     else:
     else:
@@ -64,8 +75,23 @@ class ThreadStorage(object):
         """
         """
         del self._q_thread  # start over
         del self._q_thread  # start over
         self._q_thread = QtCore.QThread()
         self._q_thread = QtCore.QThread()
+        self._q_thread.started.connect(self.__start)
         self._threaded_object = threaded_object
         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):
     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
         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)
         self._threaded_object.moveToThread(self._q_thread)
         if isinstance(method_to_run_in_thread, str):
         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:
         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._q_thread.start()
         self.running = True
         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):
     def stop(self):
         """
         """
         Call quit and wait to the underlying QThread
         Call quit and wait to the underlying QThread
@@ -115,3 +151,19 @@ class ThreadStorage(object):
             getattr(self._threaded_object, signal).connect(slot)
             getattr(self._threaded_object, signal).connect(slot)
         else:
         else:
             signal.connect(slot)
             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
 # '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
 # (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)
 # specified /dev/ files will be used with pci without validation)
-board_detection_method = 'dummy'
+board_detection_method = 'dev'
 device_list = []
 device_list = []
 # device_names is a mapping for device ids to pretty names, this makes the use of boards more intuitive
 # device_names is a mapping for device ids to pretty names, this makes the use of boards more intuitive
 # format is: device_names = {'device id': 'device name', ...}
 # format is: device_names = {'device id': 'device name', ...}

+ 29 - 3
KCG/kcg.py

@@ -8,6 +8,15 @@ import sys
 import os
 import os
 import argparse as ap
 import argparse as ap
 import logging
 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 base.kcgwidget as kcgw
 import config
 import config
@@ -35,6 +44,10 @@ except ImportError:
 
 
 
 
 def print_version(verbose=False):
 def print_version(verbose=False):
+    """
+    Print the version of the current used KCG instance
+    :param verbose: print verbose?
+    """
     # print "KCG - KAPTURE Control Gui"
     # print "KCG - KAPTURE Control Gui"
     # print "=" * 30
     # print "=" * 30
     print "KCG",
     print "KCG",
@@ -49,10 +62,22 @@ def print_version(verbose=False):
 
 
 
 
 def inject_setting(section, setting, value, args):
 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) + ';'
     args.config += section + '->' + setting + '=' + str(value) + ';'
 
 
 
 
 def log_type(level):
 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:
     try:
         return int(level)
         return int(level)
     except ValueError:
     except ValueError:
@@ -100,10 +125,11 @@ def run():
     if args.fpga_detection:
     if args.fpga_detection:
         inject_setting('Misc', 'board_detection_method', '"dev"', args)
         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):
     def vinfo(content):
+        '''log with level VINFO'''
         logging.log(logging.getLevelName('VINFO'), content)
         logging.log(logging.getLevelName('VINFO'), content)
     logging.vinfo = vinfo
     logging.vinfo = vinfo
 
 

+ 46 - 16
KCG/widgets/acquiresettings.py

@@ -17,6 +17,9 @@ __widget_id__ = None
 
 
 
 
 class AcquireSettingsTab(kcgw.KCGWidgets):
 class AcquireSettingsTab(kcgw.KCGWidgets):
+    """
+    A single tab in the acquire settings window
+    """
     available_for_same_as = OrderedDict()
     available_for_same_as = OrderedDict()
 
 
     def __init__(self, board_id, same_as_widgets, parent=None):
     def __init__(self, board_id, same_as_widgets, parent=None):
@@ -45,17 +48,13 @@ class AcquireSettingsTab(kcgw.KCGWidgets):
             self.sameAsLabel.hide()
             self.sameAsLabel.hide()
 
 
         # ---------[ Create Labels and corresponding Fields ]---------
         # ---------[ 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)
         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.numOfSkipOrbitsSpinbox = self.createSpinbox(0, 100, connect=self.on_number_of_skipped_orbits_changed)
         self.countLabel = self.createLabel(tr("Label", "Number of acquisitions"))
         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.countSpinbox = self.createSpinbox(1, 10000000, start_value=10, connect=self.on_count_changed)
         self.waitLabel = self.createLabel(tr("Label", "Wait(s)"))
         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.waitSpinbox = self.createSpinbox(0, 60, start_value=15, connect=self.on_wait_changed)
         self.simulatePilotBunch = self.createCheckbox(tr("Button", "Simulate Pilot Bunch"),
         self.simulatePilotBunch = self.createCheckbox(tr("Button", "Simulate Pilot Bunch"),
                                                       connect=self.on_simulate_pilot_bunch_changed)
                                                       connect=self.on_simulate_pilot_bunch_changed)
@@ -137,6 +136,10 @@ class AcquireSettingsTab(kcgw.KCGWidgets):
         self.layout.addWidget(line, 8, 0, 1, 2)
         self.layout.addWidget(line, 8, 0, 1, 2)
 
 
     def build_same_as_list(self):
     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():
         for wid_id, wid in self.widgets.iteritems():
             wid.sameAsCombo.clear()
             wid.sameAsCombo.clear()
             for key, value in self.available_for_same_as.iteritems():
             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.available_for_same_as[self.board_id] = False
             self.sameAsCombo.setEnabled(False)
             self.sameAsCombo.setEnabled(False)
             board.get_board_config(c_t).observe_all(
             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].sameAsTick.setEnabled(False)
             self.widgets[c_t].sameAsCombo.setEnabled(False)
             self.widgets[c_t].sameAsCombo.setEnabled(False)
             Elements.setEnabled('acquire_{}'.format(self.board_id), 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.available_for_same_as[self.board_id] = True
             self.sameAsCombo.setEnabled(True)
             self.sameAsCombo.setEnabled(True)
             board.get_board_config(c_t).unobserve_all_observer(
             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].sameAsTick.setEnabled(True)
             self.widgets[c_t].sameAsCombo.setEnabled(True)
             self.widgets[c_t].sameAsCombo.setEnabled(True)
             Elements.setEnabled('acquire_{}'.format(self.board_id), True)
             Elements.setEnabled('acquire_{}'.format(self.board_id), True)
@@ -181,10 +184,19 @@ class AcquireSettingsTab(kcgw.KCGWidgets):
         bif._bif_disable_wait_cursor()
         bif._bif_disable_wait_cursor()
 
 
     def update_external_trigger(self, state):
     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.tick_silent(self.trigger_tick, state)
         self.use_external_trigger(state, update_config=False)
         self.use_external_trigger(state, update_config=False)
 
 
     def use_external_trigger(self, state, update_config=True):
     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 state:
             if update_config:
             if update_config:
                 board.get_board_config(self.board_id).update('use_trigger', True)
                 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.
         This will read the appropriate Values from the base.backend.board.BoardConfiguration instance used in the gui.
         :return: -
         :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.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.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'))
         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 ]---------------------------
     # -----------------[ Value Change Handlers ]---------------------------
     def on_number_of_orbits_changed(self):
     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())
         bif.bk_change_num_of_orbits(self.board_id, self.numOfOrbitsSpinbox.value())
         for b_id in self.same_as_widgets[self.board_id]:
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
             wid = self.widgets[b_id]
             bif.bk_change_num_of_orbits(wid.board_id, wid.numOfOrbitsSpinbox.value())
             bif.bk_change_num_of_orbits(wid.board_id, wid.numOfOrbitsSpinbox.value())
 
 
     def on_number_of_skipped_orbits_changed(self):
     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())
         bif.bk_change_num_of_skipped_orbits(self.board_id, self.numOfSkipOrbitsSpinbox.value())
         for b_id in self.same_as_widgets[self.board_id]:
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
             wid = self.widgets[b_id]
             bif.bk_change_num_of_skipped_orbits(wid.board_id, wid.numOfSkipOrbitsSpinbox.value())
             bif.bk_change_num_of_skipped_orbits(wid.board_id, wid.numOfSkipOrbitsSpinbox.value())
 
 
     def on_count_changed(self):
     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())
         bif.bk_change_count(self.board_id, self.countSpinbox.value())
         for b_id in self.same_as_widgets[self.board_id]:
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
             wid = self.widgets[b_id]
             bif.bk_change_count(wid.board_id, wid.countSpinbox.value())
             bif.bk_change_count(wid.board_id, wid.countSpinbox.value())
 
 
     def on_wait_changed(self):
     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())
         bif.bk_change_wait(self.board_id, self.waitSpinbox.value())
         for b_id in self.same_as_widgets[self.board_id]:
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
             wid = self.widgets[b_id]
             bif.bk_change_wait(wid.board_id, wid.waitSpinbox.value())
             bif.bk_change_wait(wid.board_id, wid.waitSpinbox.value())
 
 
     def on_build_spectrograms_changed(self):
     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())
         bif.bk_change_build_spectrograms(self.board_id, self.buildSpectrogrammTickbox.checkState())
         for b_id in self.same_as_widgets[self.board_id]:
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
             wid = self.widgets[b_id]
             bif.bk_change_build_spectrograms(wid.board_id, wid.buildSpectrogrammTickbox.checkState())
             bif.bk_change_build_spectrograms(wid.board_id, wid.buildSpectrogrammTickbox.checkState())
 
 
     def on_simulate_pilot_bunch_changed(self):
     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())
         bif.bk_change_pilot_bunch(self.board_id, self.simulatePilotBunch.checkState())
         for b_id in self.same_as_widgets[self.board_id]:
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
             wid = self.widgets[b_id]
@@ -322,7 +346,9 @@ class AcquireSettingsTab(kcgw.KCGWidgets):
             bif.bk_update_config(wid.board_id, 'trigger_skip', value)
             bif.bk_update_config(wid.board_id, 'trigger_skip', value)
 
 
     def on_trigger_method_changed(self):
     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)
         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]:
         for b_id in self.same_as_widgets[self.board_id]:
             wid = self.widgets[b_id]
             wid = self.widgets[b_id]
@@ -403,6 +429,10 @@ class AcquireSettings(kcgw.KCGWidgets):
             wid.set_values()
             wid.set_values()
 
 
     def show_tab(self, board_id):
     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:
         if not available_boards.multi_board:
             return
             return
         self.tabs.setCurrentIndex(self.widgets.keys().index(board_id))
         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())
         bif.bk_continuous_read(board_id)  # interval=self.interval_spinbox.value())
 
 
     def set_interval(self):
     def set_interval(self):
+        """
+        Set the interval between reads
+        """
         storage.continuous_interval = self.interval_spinbox.value()
         storage.continuous_interval = self.interval_spinbox.value()
 
 
     def closeEvent(self, event):
     def closeEvent(self, event):

+ 12 - 16
KCG/widgets/timingWidget.py

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

+ 1 - 1
setup.py

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