|
@@ -1,1517 +1,1503 @@
|
|
|
-"""
|
|
|
-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_
|
|
|
-"""
|
|
|
-
|
|
|
-import logging
|
|
|
-import time
|
|
|
-from datetime import datetime as dt
|
|
|
-import os
|
|
|
-import copy
|
|
|
-from PyQt4 import QtGui, QtCore
|
|
|
-import numpy as np
|
|
|
-from .backend import board
|
|
|
-from .backend.board import available_boards
|
|
|
-from .backend import io
|
|
|
-from .backend import dataset
|
|
|
-from .groupedelements import Buttons, Elements, live_plot_windows
|
|
|
-from . import storage
|
|
|
-from .. import config
|
|
|
-from . import kcgwidget as kcgw
|
|
|
-from .kcgwidget import error
|
|
|
-from .callbacks import callbacks
|
|
|
-from .log import log
|
|
|
-from .globals import glob as global_objects
|
|
|
-
|
|
|
-tr = kcgw.tr
|
|
|
-
|
|
|
-livePlotData = None
|
|
|
-
|
|
|
-
|
|
|
-def 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)
|
|
|
- :return: -
|
|
|
- """
|
|
|
- st.continuous_read = False
|
|
|
- st.calibrated = False
|
|
|
- st.synced = False
|
|
|
- st.defaults_set = False
|
|
|
- st.status_text = tr("sw", "Ready")
|
|
|
- st.time_scan = False
|
|
|
- st.wait_on_trigger = False
|
|
|
- st.last_file = None
|
|
|
- st.board_connected = True
|
|
|
- st.continuous_interval = 1000
|
|
|
-
|
|
|
-
|
|
|
-# -----------[ Backend Interface ]----------------------
|
|
|
-def _bif_enable_wait_cursor():
|
|
|
- """
|
|
|
- Show the "Wait Cursor"
|
|
|
- """
|
|
|
- QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
|
|
|
-
|
|
|
-
|
|
|
-def _bif_disable_wait_cursor():
|
|
|
- """
|
|
|
- Show the normal Cursor
|
|
|
- """
|
|
|
- QtGui.QApplication.restoreOverrideCursor()
|
|
|
-
|
|
|
-
|
|
|
-def _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)
|
|
|
- """
|
|
|
- if board.get_board_status(board_id).continuous_read:
|
|
|
- if not available_boards.multi_board:
|
|
|
- popup = PopupDialog(tr("Dialog", "Continuous read is currently active!\nStop continuous read and proceed?"),
|
|
|
- title=popup_title_text)
|
|
|
- else:
|
|
|
- popup = PopupDialog(tr("Dialog", "Board {board_id}\nContinuous read is currently active!\nStop continuous read and proceed?").format(board_id=board_id),
|
|
|
- title=popup_title_text)
|
|
|
- popup.exec_()
|
|
|
- popup.deleteLater()
|
|
|
- if popup.get_return_value() is False:
|
|
|
- return False
|
|
|
- else:
|
|
|
- _bif_set_continuous_read_inactive(board_id)
|
|
|
- Elements.setChecked("continuousread_"+str(board_id), False)
|
|
|
- return True
|
|
|
- else:
|
|
|
- return False
|
|
|
-
|
|
|
-
|
|
|
-def bk_status_readout():
|
|
|
- """
|
|
|
- Read Status for every connected board
|
|
|
- """
|
|
|
- if not available_boards.has_boards:
|
|
|
- return
|
|
|
- for brd in available_boards.board_ids:
|
|
|
- _bif_status_readout(brd)
|
|
|
-
|
|
|
-
|
|
|
-def _bif_status_readout(board_id):
|
|
|
- """
|
|
|
- Read Status from board and update variables
|
|
|
- as well as enable and disable corresponding Buttons
|
|
|
- :return: -
|
|
|
- """
|
|
|
- # part_TODO: NOTE: Problem with this is that certain buttons will be greyed out until other buttons are pressed
|
|
|
- # part_TODO: even if only the gui is restarted and the board is in the same state
|
|
|
- if kcgw.testing:
|
|
|
- return
|
|
|
- if board.is_active(board_id):
|
|
|
- Buttons.setEnabled("after_start_{}".format(board_id), True)
|
|
|
- Buttons.setEnabled("start_board_{}".format(board_id), False)
|
|
|
- Buttons.setEnabled("continuous_read_{}".format(board_id), True)
|
|
|
-
|
|
|
- # MenuItems.setEnabled("continuous_read", True)
|
|
|
- else:
|
|
|
- board.get_board_status(board_id).calibrated = False
|
|
|
- board.get_board_status(board_id).synced = False
|
|
|
- board.get_board_status(board_id).defaults_set = False
|
|
|
- Buttons.setEnabled("after_start_{}".format(board_id), False)
|
|
|
- Buttons.setEnabled("continuous_read_{}".format(board_id), False)
|
|
|
- Buttons.setEnabled("synchronize_{}".format(board_id), board.get_board_status(board_id).calibrated)
|
|
|
- Buttons.setEnabled("set_defaults_{}".format(board_id), board.get_board_status(board_id).synced)
|
|
|
- Buttons.setEnabled("acquire_{}".format(board_id), board.get_board_status(board_id).synced)
|
|
|
- Buttons.setEnabled("acquireTrigger_{}".format(board_id), board.get_board_status(board_id).synced)
|
|
|
- Elements.setEnabled("timing_{}".format(board_id), board.get_board_status(board_id).synced)
|
|
|
-
|
|
|
- storage.get_board_specific_storage(board_id).update_LED()
|
|
|
-
|
|
|
-
|
|
|
-backup_readout = bk_status_readout
|
|
|
-
|
|
|
-
|
|
|
-class PopupDialog(QtGui.QDialog):
|
|
|
- """
|
|
|
- Simple Class to show a popup dialog.
|
|
|
- """
|
|
|
-
|
|
|
- def __init__(self, text, title=None, parent=None):
|
|
|
- QtGui.QDialog.__init__(self, parent)
|
|
|
- self.text = text
|
|
|
- self.setWindowTitle(title if title else tr("Dialog", "User action required"))
|
|
|
- self.return_value = False
|
|
|
-
|
|
|
- size = QtCore.QSize(200, 200)
|
|
|
- # self.setMaximumSize(size)
|
|
|
- self.setMinimumSize(size)
|
|
|
- box = QtGui.QVBoxLayout()
|
|
|
- self.text_label = QtGui.QLabel(self.text)
|
|
|
- self.text_label.setAlignment(QtCore.Qt.AlignCenter)
|
|
|
- box.addWidget(self.text_label)
|
|
|
- self.okay_btn = QtGui.QPushButton(tr("Button", "Ok"))
|
|
|
- self.okay_btn.setStyleSheet("padding: 15px;")
|
|
|
- self.okay_btn.clicked.connect(self.on_okay)
|
|
|
- box.addWidget(self.okay_btn)
|
|
|
- box.addSpacerItem(QtGui.QSpacerItem(1, 20))
|
|
|
- self.cancel_btn = QtGui.QPushButton(tr("Button", "Cancel"))
|
|
|
- self.cancel_btn.setStyleSheet("padding: 15px;")
|
|
|
- self.cancel_btn.clicked.connect(self.on_cancel)
|
|
|
- box.addWidget(self.cancel_btn)
|
|
|
- self.setLayout(box)
|
|
|
-
|
|
|
- def on_okay(self):
|
|
|
- """
|
|
|
- Handler for the press of the ok button
|
|
|
- """
|
|
|
- self.return_value = True
|
|
|
- self.close()
|
|
|
-
|
|
|
- def on_cancel(self):
|
|
|
- """
|
|
|
- Handler for the press of the cancel button
|
|
|
- :return:
|
|
|
- """
|
|
|
- self.close()
|
|
|
-
|
|
|
- def get_return_value(self):
|
|
|
- """
|
|
|
- Get True if the Window was closed with OK else False
|
|
|
- :return: True if OK else False
|
|
|
- """
|
|
|
- return self.return_value
|
|
|
-
|
|
|
-
|
|
|
-def 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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- _bif_enable_wait_cursor()
|
|
|
- log(board_id=board_id, additional="Starting Board - following values are probably default values")
|
|
|
-
|
|
|
- sequence = board.startup_sequence(board_id)
|
|
|
- number = next(sequence)
|
|
|
-
|
|
|
- if _bif_continuous_read_is_enabled(board_id, tr("Button", "Start Board")):
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- return False
|
|
|
-
|
|
|
- try:
|
|
|
- if board.is_active(board_id):
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- bk_status_readout()
|
|
|
- return
|
|
|
-
|
|
|
- logging.info("Activating Board")
|
|
|
- next(sequence)
|
|
|
- time.sleep(1.0)
|
|
|
- dialog1 = PopupDialog(tr("Button", "Switch On the power supply --> FIRST <-- (on board {0})".format(board_id)))
|
|
|
- dialog1.exec_()
|
|
|
- dialog1.deleteLater()
|
|
|
-
|
|
|
- if not dialog1.get_return_value():
|
|
|
- logging.error("Starting procedure canceled")
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- return False
|
|
|
-
|
|
|
- logging.info("Switch ON T/Hs")
|
|
|
- next(sequence)
|
|
|
- time.sleep(0.1)
|
|
|
- dialog2 = PopupDialog(tr("Dialog", "Switch On the power supply --> SECOND <-- (on board {0})".format(board_id)))
|
|
|
- dialog2.exec_()
|
|
|
- dialog2.deleteLater()
|
|
|
-
|
|
|
- if not dialog2.get_return_value():
|
|
|
- logging.info("Starting procedure canceled")
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- return False
|
|
|
-
|
|
|
- logging.info("Switch ON ADCs")
|
|
|
- next(sequence)
|
|
|
- time.sleep(0.1)
|
|
|
-
|
|
|
- next(sequence)
|
|
|
- time.sleep(1.0)
|
|
|
-
|
|
|
- for step in sequence:
|
|
|
- time.sleep(0.1)
|
|
|
-
|
|
|
- logging.info("Board started successfully!")
|
|
|
- except board.BoardError as e:
|
|
|
- logging.error("Starting board failed: {}".format(str(e)))
|
|
|
-
|
|
|
- bk_update_config(board_id, 'header', bk_get_config(board_id, 'header'))
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- bk_status_readout()
|
|
|
-
|
|
|
-
|
|
|
-class _bif_ProgressBar(QtGui.QProgressBar):
|
|
|
- """
|
|
|
- Simple Progressbar class.
|
|
|
- """
|
|
|
-
|
|
|
- def __init__(self, min, max, text):
|
|
|
- super(_bif_ProgressBar, self).__init__()
|
|
|
- self.setRange(min, max)
|
|
|
- self.setMaximumHeight(18)
|
|
|
- # kcgw.statusbar.clearMessage()
|
|
|
- self.label = QtGui.QLabel(text)
|
|
|
- global_objects.get_global('statusbar').insertWidget(0, self.label)
|
|
|
- global_objects.get_global('statusbar').insertWidget(1, self)
|
|
|
- self.setValue(0)
|
|
|
- QtGui.qApp.processEvents()
|
|
|
-
|
|
|
- def remove(self, timeout=None):
|
|
|
- """
|
|
|
- Remove this instance of a progressbar
|
|
|
- :param timeout: the time from calling this function to wanishing of the progressbar
|
|
|
- :return: -
|
|
|
- """
|
|
|
-
|
|
|
- def remove_progressbar():
|
|
|
- global_objects.get_global('statusbar').removeWidget(self)
|
|
|
- global_objects.get_global('statusbar').removeWidget(self.label)
|
|
|
- # kcgw.statusbar.showMessage(board.status.status_text)
|
|
|
- self.destroy()
|
|
|
-
|
|
|
- if timeout:
|
|
|
- QtCore.QTimer.singleShot(timeout, remove_progressbar)
|
|
|
- else:
|
|
|
- remove_progressbar()
|
|
|
-
|
|
|
-
|
|
|
-# thread = None
|
|
|
-# cal = None
|
|
|
-def 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.
|
|
|
- :return: -
|
|
|
- """
|
|
|
- log(board_id=board_id, additional="Calibrate")
|
|
|
- thread = storage.get_board_specific_storage(board_id).setdefault('CalibrateThread', storage.ThreadStorage())
|
|
|
- if thread.running:
|
|
|
- logging.info("Calibration already running")
|
|
|
- return
|
|
|
- _bif_enable_wait_cursor()
|
|
|
- if _bif_continuous_read_is_enabled(board_id, tr("Button", "Calibrate Board")):
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- return
|
|
|
-
|
|
|
- sequence = board.calibration_sequence(board_id)
|
|
|
- number = next(sequence)
|
|
|
- progressbar = _bif_ProgressBar(0, number, tr("sw", "Calibrating"))
|
|
|
-
|
|
|
- class Calibrate(QtCore.QObject):
|
|
|
- """
|
|
|
- Class to use as thread class. NOTE: this is not used at the moment.
|
|
|
- """
|
|
|
- update_progressbar_signal = QtCore.pyqtSignal(int)
|
|
|
- finished = QtCore.pyqtSignal()
|
|
|
-
|
|
|
- def calibrate(self):
|
|
|
- """
|
|
|
- The method that is called inside the thread and that does the calibration
|
|
|
- :return:
|
|
|
- """
|
|
|
- try:
|
|
|
- logging.info('Started Board Calibration')
|
|
|
- for idx, step in enumerate(sequence):
|
|
|
- time.sleep(0.5)
|
|
|
- self.update_progressbar_signal.emit(idx)
|
|
|
- board.get_board_status(board_id).calibrated = True
|
|
|
- except board.BoardError as e:
|
|
|
- logging.error("Calibration failed: {}".format(str(e)))
|
|
|
- # self.do_status_readout()
|
|
|
- self.finished.emit()
|
|
|
- return
|
|
|
-
|
|
|
- logging.info("Board Calibration successful!")
|
|
|
- self.finished.emit()
|
|
|
-
|
|
|
- def thread_quit():
|
|
|
- """
|
|
|
- Method to handle the end of the calibration thread
|
|
|
- :return:
|
|
|
- """
|
|
|
- thread.stop()
|
|
|
- bk_status_readout()
|
|
|
- progressbar.remove(0)
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- if do_the_rest: # execute sync and set defaults (this is set if prepare board was pressed)
|
|
|
- do_the_rest(board_id)
|
|
|
-
|
|
|
- cal = Calibrate()
|
|
|
- thread.register(cal)
|
|
|
- thread.connect('update_progressbar_signal', progressbar.setValue)
|
|
|
- thread.connect('finished', thread_quit)
|
|
|
- thread.start('calibrate')
|
|
|
-
|
|
|
-def bk_sync_board(board_id):
|
|
|
- """
|
|
|
- Sends commands to the board to sync with triggers.
|
|
|
- :param board_id: id of the board do manipulate
|
|
|
- :return: -
|
|
|
- """
|
|
|
- _bif_enable_wait_cursor()
|
|
|
- log(board_id=board_id, additional="Synchronize")
|
|
|
- if _bif_continuous_read_is_enabled(board_id, tr("Dialog", "Synchronize Board")):
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- return
|
|
|
-
|
|
|
- progressbar = _bif_ProgressBar(0, 100, tr("sw", "Synchronizing"))
|
|
|
- sequence = board.synchronisation_sequence(board_id)
|
|
|
- try:
|
|
|
- next(sequence) # skip number
|
|
|
- logging.info("Synchronize PLLs")
|
|
|
- next(sequence)
|
|
|
- for i in range(1, 101):
|
|
|
- time.sleep(0.01)
|
|
|
- progressbar.setValue(i)
|
|
|
- next(sequence)
|
|
|
- except board.BoardError as e:
|
|
|
- logging.error("Synchronization failed: {}".format(str(e)))
|
|
|
- progressbar.remove(0)
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- bk_status_readout()
|
|
|
- return
|
|
|
-
|
|
|
- progressbar.remove(0)
|
|
|
-
|
|
|
- logging.info("Board synchronization successful!")
|
|
|
- # self.set_defaults_button.setEnabled(True)
|
|
|
- board.get_board_status(board_id).synced = True
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- bk_status_readout()
|
|
|
-
|
|
|
-
|
|
|
-def 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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- _bif_enable_wait_cursor()
|
|
|
- if defaults:
|
|
|
- log(board_id=board_id, additional="Set Default Values")
|
|
|
- else:
|
|
|
- log(board_id=board_id, additional="Update Values on board")
|
|
|
- if _bif_continuous_read_is_enabled(board_id, tr("Dialog", "Update Values on Board")):
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- return
|
|
|
-
|
|
|
- sequence = board.write_value_sequence(board_id)
|
|
|
- number = next(sequence)
|
|
|
- if defaults:
|
|
|
- board.get_board_config(board_id)._set_defaults()
|
|
|
- progressbar = _bif_ProgressBar(0, number, tr("sw", "Setting Defaults"))
|
|
|
- logging.info("Setting default Values")
|
|
|
- else:
|
|
|
- progressbar = _bif_ProgressBar(0, number, tr("sw", "Updating Values on Board"))
|
|
|
- logging.info("Updating Values")
|
|
|
-
|
|
|
- try:
|
|
|
- for idx, step in enumerate(sequence):
|
|
|
- time.sleep(0.1)
|
|
|
- progressbar.setValue(idx)
|
|
|
- except board.BoardError as e:
|
|
|
- logging.error("Updating Values failed: {}".format(str(e)))
|
|
|
- progressbar.remove(0)
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- bk_status_readout()
|
|
|
- return
|
|
|
-
|
|
|
- board.get_board_status(board_id).defaults_set = True
|
|
|
- progressbar.remove(0)
|
|
|
-
|
|
|
- if defaults:
|
|
|
- logging.info("Default values set successfully!")
|
|
|
- else:
|
|
|
- logging.info("Updated values successfully!")
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- bk_status_readout()
|
|
|
- board.get_board_config(board_id).notify_all_observers()
|
|
|
-
|
|
|
-
|
|
|
-def bk_stop_board(board_id):
|
|
|
- """
|
|
|
- Stops the board and shuts it down
|
|
|
- :param board_id: id of the board do manipulate
|
|
|
- :return: -
|
|
|
- """
|
|
|
- _bif_enable_wait_cursor()
|
|
|
- log(board_id=board_id, additional="Stop Board")
|
|
|
- if _bif_continuous_read_is_enabled(board_id, tr("Dialog", "Soft Reset Board")):
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- return
|
|
|
-
|
|
|
- try:
|
|
|
- logging.info("Switching Off Board {}".format(board_id))
|
|
|
- board.pci.write(board_id, '0x9040')
|
|
|
- board.pci.stop_dma(board_id)
|
|
|
- board.stop_board(board_id)
|
|
|
- time.sleep(0.5)
|
|
|
- except board.BoardError as e:
|
|
|
- logging.error("Sequence failed: {}".format(str(e)))
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- bk_status_readout()
|
|
|
- return
|
|
|
-
|
|
|
- logging.info("Board switched off successfully!")
|
|
|
- Buttons.setEnabled("after_start_{}".format(board_id), False)
|
|
|
- Buttons.setEnabled("start_board_{}".format(board_id), True)
|
|
|
- board.get_board_status(board_id).calibrated = False
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- bk_status_readout()
|
|
|
-
|
|
|
-def bk_soft_reset(board_id):
|
|
|
- """
|
|
|
- Perform a soft reset.
|
|
|
- :param board_id: id of the board do manipulate
|
|
|
- :return:
|
|
|
- """
|
|
|
- _bif_enable_wait_cursor()
|
|
|
- log(board_id=board_id, additional="Soft Reset")
|
|
|
- if _bif_continuous_read_is_enabled(board_id, tr("Dialog", "Soft Reset Board")):
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- return
|
|
|
-
|
|
|
- try:
|
|
|
- logging.info("Soft-Resetting Board {}...".format(board_id))
|
|
|
- board.soft_reset(board_id)
|
|
|
- except board.BoardError as e:
|
|
|
- logging.error("Sequence failed: {}".format(str(e)))
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- bk_status_readout()
|
|
|
- return
|
|
|
-
|
|
|
- _bif_disable_wait_cursor()
|
|
|
- bk_status_readout()
|
|
|
- board.get_board_config(board_id).update('header', True) # reset header (might be reset by soft reset)
|
|
|
- logging.info("Soft-Reset successful.")
|
|
|
-
|
|
|
-
|
|
|
-def 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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- try:
|
|
|
- if silent:
|
|
|
- board.get_board_config(board_id).updateSilent(key, value)
|
|
|
- else:
|
|
|
- board.get_board_config(board_id).update(key, value)
|
|
|
- except board.BoardError as e:
|
|
|
- logging.error("Setting value of {} failed: {}".format(key, str(e)))
|
|
|
-
|
|
|
-
|
|
|
-def 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
|
|
|
- """
|
|
|
- return board.get_board_config(board_id).get(key)
|
|
|
-
|
|
|
-
|
|
|
-def 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
|
|
|
- """
|
|
|
- return getattr(board.get_board_status(board_id), status_variable, None)
|
|
|
-
|
|
|
-
|
|
|
-def bk_get_status(board_id):
|
|
|
- """
|
|
|
- Interface to the get_status of the board
|
|
|
- NOTE: This is not get_board_status
|
|
|
- :return: status dictionary
|
|
|
- """
|
|
|
- return board.get_status(board_id)
|
|
|
-
|
|
|
-
|
|
|
-def bk_get_board_config(board_id):
|
|
|
- """
|
|
|
- Get the board config instance
|
|
|
- :param board_id: the id of the board
|
|
|
- :return: the config instance
|
|
|
- """
|
|
|
- return board.get_board_config(board_id)
|
|
|
-
|
|
|
-def 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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- bk_update_config(board_id, "orbits_observe", value, silent=silent)
|
|
|
-
|
|
|
-
|
|
|
-def 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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- bk_update_config(board_id, "orbits_skip", value, silent=silent)
|
|
|
-
|
|
|
-
|
|
|
-def 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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- bk_update_config(board_id, "acquisition_count", value, silent=silent)
|
|
|
-
|
|
|
-
|
|
|
-def 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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- bk_update_config(board_id, "orbits_wait_time", value, silent=silent)
|
|
|
-
|
|
|
-
|
|
|
-def 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
|
|
|
- :return:
|
|
|
- """
|
|
|
- bk_update_config(board_id, "build_spectrograms", value, silent=silent)
|
|
|
-
|
|
|
-
|
|
|
-def 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
|
|
|
- :return:
|
|
|
- """
|
|
|
- bk_update_config(board_id, "pilot_bunch", value, silent=silent)
|
|
|
-
|
|
|
-
|
|
|
-def _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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- return # because it is broken
|
|
|
- if not os.path.isdir(str(path)):
|
|
|
- return
|
|
|
-
|
|
|
- # how does this get data? dataset.data does not exist
|
|
|
- transform = dataset.data.fft(1, frm=0, to=-1)
|
|
|
- for i in range(config.bunches_per_turn - 1):
|
|
|
- filename = os.path.join(storage.storage.save_location, storage.storage.subdirname, str(path), "%i.hsp" % i)
|
|
|
- write_header = False
|
|
|
- if not os.path.isfile(filename):
|
|
|
- write_header = True
|
|
|
- f = open(filename, 'ab')
|
|
|
- if write_header:
|
|
|
- f.write("#hsp\n") # heb spectrogram magic number
|
|
|
- f.write("#"+str(board.get_board_config(board_id).get("orbits_skip")))
|
|
|
- f.write("\n")
|
|
|
- line = transform[i, :]
|
|
|
- f.write('{:0.3f} '.format(time.time()))
|
|
|
- for e in line:
|
|
|
- f.write("%s " % np.absolute(e))
|
|
|
- f.write("\n")
|
|
|
- f.close()
|
|
|
-
|
|
|
-
|
|
|
-def _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
|
|
|
- :return:
|
|
|
- """
|
|
|
- now = time.time()
|
|
|
- if not os.path.isdir(str(storage.storage.save_location + '/' + storage.storage.subdirname)):
|
|
|
- os.makedirs(str(storage.storage.save_location + '/' + storage.storage.subdirname))
|
|
|
- filename = storage.storage.save_location + '/' + storage.storage.subdirname+'/{:0.3f}.out'.format(now)
|
|
|
- board.get_board_status(board_id).last_file = filename
|
|
|
-
|
|
|
- try:
|
|
|
- simulate = board.get_board_config(board_id).get("pilot_bunch")
|
|
|
- try:
|
|
|
- board.acquire_data(board_id, filename, simulate=simulate)
|
|
|
- if not os.path.isfile(filename):
|
|
|
- error(0x001, "No File Created")
|
|
|
- except IndexError:
|
|
|
- error(0x002, "Unexpected output of pci for number of orbits to observe. Returning")
|
|
|
- return
|
|
|
- _bif_read_and_update_data_from_file(board_id, filename)
|
|
|
- except board.BoardError as e:
|
|
|
- logging.error("Reading failed: {}".format(str(e)))
|
|
|
-
|
|
|
-
|
|
|
-def _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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- _bif_read_and_update(board_id, io.read_from_file, str(filename))
|
|
|
-
|
|
|
-
|
|
|
-def _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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- _bif_read_and_update(board_id, io.read_from_string, raw_data)
|
|
|
-
|
|
|
-
|
|
|
-def _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}
|
|
|
- :return: -
|
|
|
- """
|
|
|
- _bif_enable_wait_cursor()
|
|
|
-
|
|
|
- header = board.get_board_config(board_id).get('header')
|
|
|
- # TODO: force_read: meaning ignore cache and read new -> in the old gui this was a commandline option
|
|
|
- # TODO: cache_data: meaning cache already processed numpy data -> in the old gui this was a commandline option
|
|
|
- if live_plot_windows.hasWindows(board_id):
|
|
|
- data = read_func(*args, force=False, header=header, cache=False)
|
|
|
-
|
|
|
- if not io.is_data_consistent(data):
|
|
|
- callbacks.async_callback('update_consistency', False)
|
|
|
- global_objects.get_global('statusbar').showMessage(tr("Dialog", "Data is inconsistent!"))
|
|
|
- if read_func == io.read_from_string:
|
|
|
- logging.info("Data is inconsistent")
|
|
|
- else:
|
|
|
- logging.info("Data is inconsistent - file: " + args[0])
|
|
|
- else:
|
|
|
- callbacks.async_callback('update_consistency', True)
|
|
|
- global_objects.get_global('statusbar').showMessage(tr("Dialog", ""))
|
|
|
-
|
|
|
- for plotwin in live_plot_windows.getWindows(board_id):
|
|
|
- plotwin.plot_live(data=data)
|
|
|
- QtGui.qApp.processEvents()
|
|
|
- else:
|
|
|
- callbacks.async_callback('update_consistency', None)
|
|
|
-
|
|
|
- _bif_disable_wait_cursor()
|
|
|
-
|
|
|
-
|
|
|
-def bk_acquire(board_id):
|
|
|
- """
|
|
|
- Toggle Acqisition
|
|
|
- :param board_id: id of the board do manipulate
|
|
|
- :return:
|
|
|
- """
|
|
|
- if not bk_get_config(board_id, 'use_trigger'):
|
|
|
- if board.get_board_status(board_id).acquisition == True:
|
|
|
- log(board_id=board_id, additional="Manually Stopped Acquisition\nPerformed Acquisitions: " + str(storage.storage.current_acquisition))
|
|
|
- _bif_stop_acquisition(board_id)
|
|
|
- else:
|
|
|
- _bif_start_acquisition(board_id)
|
|
|
- else:
|
|
|
- bk_toggle_wait_on_trigger(board_id)
|
|
|
-
|
|
|
-
|
|
|
-def _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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- board.get_board_status(board_id).acquisition = False
|
|
|
- storage.get_board_specific_storage(board_id).acquisition_progressbar.remove(0)
|
|
|
- storage.get_board_specific_storage(board_id).acquisition_timer.stop()
|
|
|
- # for elem in Elements.getElements("acquireTrigger_{}".format(board_id)):
|
|
|
- # if isinstance(elem, QtGui.QShortcut) or isinstance(elem, QtGui.QCheckBox):
|
|
|
- # continue
|
|
|
- # elem.setIcon(QtGui.QIcon(config.install_path + config.startIcon))
|
|
|
- # elem.setText(tr("Button", "Start Acquisition"))
|
|
|
- Elements.setEnabled('acquire_{}'.format(board_id), True)
|
|
|
- callbacks.callback('acquisition_stopped', board_id)
|
|
|
-
|
|
|
-
|
|
|
-def _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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- log(board_id=board_id, additional="Started Acquisition")
|
|
|
- board.get_board_status(board_id).acquisition = True
|
|
|
- Elements.setEnabled('acquire_{}'.format(board_id), False)
|
|
|
- # for elem in Elements.getElements("acquireTrigger_{}".format(board_id)):
|
|
|
- # if isinstance(elem, QtGui.QShortcut) or isinstance(elem, QtGui.QCheckBox):
|
|
|
- # continue
|
|
|
- # elem.setIcon(QtGui.QIcon(config.install_path + config.stopIcon))
|
|
|
- # elem.setText(tr("Button", "Stop Acquisition"))
|
|
|
- callbacks.callback('acquisition_started', board_id)
|
|
|
- storage.get_board_specific_storage(board_id).acquisition_timer = QtCore.QTimer()
|
|
|
- num_acquisitions = board.get_board_config(board_id).get("acquisition_count")
|
|
|
- storage.get_board_specific_storage(board_id).acquisition_progressbar = \
|
|
|
- _bif_ProgressBar(0, num_acquisitions, tr("sw", "Acquiring with board ")+str(board_id))
|
|
|
- # storage.storage.acquisition_progressbar = acquisition_progressbar
|
|
|
-
|
|
|
- # We increase already once because we do a single acquisition before the
|
|
|
- # timer is started, otherwise we have to wait until the timer fires the
|
|
|
- # first time.
|
|
|
- try:
|
|
|
- if isinstance(storage.storage.current_acquisition, dict):
|
|
|
- storage.storage.current_acquisition[board_id] = 1
|
|
|
- else:
|
|
|
- storage.storage.current_acquisition = {board_id: 1}
|
|
|
- except storage.StorageError:
|
|
|
- storage.storage.current_acquisition = {board_id: 1}
|
|
|
- _bif_read_data_and_save(board_id)
|
|
|
-
|
|
|
- if board.get_board_config(board_id).get("build_spectrograms"):
|
|
|
- spectrogram_dir = storage.storage.save_location + '/' + storage.storage.subdirname+"/spectrograms_{:0.3f}".format(time.time())
|
|
|
- os.makedirs(spectrogram_dir)
|
|
|
- _bif_iterate_spectrograms(board_id, spectrogram_dir) # TODO: not here?
|
|
|
-
|
|
|
- storage.get_board_specific_storage(board_id).acquisition_progressbar.setValue(storage.storage.current_acquisition[board_id])
|
|
|
-
|
|
|
- def on_timeout():
|
|
|
- '''Handler for the timeout of the acquisition timer. This does the acquisition'''
|
|
|
- if storage.storage.current_acquisition[board_id] < num_acquisitions:
|
|
|
- storage.storage.current_acquisition[board_id] += 1
|
|
|
- storage.get_board_specific_storage(board_id).acquisition_progressbar.setValue(storage.storage.current_acquisition[board_id])
|
|
|
- _bif_read_data_and_save(board_id)
|
|
|
- if board.get_board_config(board_id).get("build_spectrograms"):
|
|
|
- _bif_iterate_spectrograms(board_id, spectrogram_dir) # TODO: not here ?
|
|
|
- else:
|
|
|
- log(board_id=board_id, additional="Stopped Acquisition")
|
|
|
- _bif_stop_acquisition(board_id)
|
|
|
- storage.get_board_specific_storage(board_id).acquisition_progressbar.remove(0)
|
|
|
-
|
|
|
- storage.get_board_specific_storage(board_id).acquisition_timer.timeout.connect(on_timeout)
|
|
|
- storage.get_board_specific_storage(board_id).acquisition_timer.start(board.get_board_config(board_id).get('orbits_wait_time') * 1000)
|
|
|
-
|
|
|
-
|
|
|
-def bk_single_read(board_id):
|
|
|
- """
|
|
|
- Perform a single read of data
|
|
|
- :param board_id: id of the board do manipulate
|
|
|
- :return:
|
|
|
- """
|
|
|
- Elements.setEnabled("acquire_{}".format(board_id), False)
|
|
|
- _bif_read_data_and_save(board_id)
|
|
|
- log(board_id=board_id, additional="Single Read\nFilename: "+board.get_board_status(board_id).last_file.split('/')[-1])
|
|
|
- Elements.setEnabled("acquire_{}".format(board_id), True)
|
|
|
-
|
|
|
-
|
|
|
-def _bif_set_continuous_read_active(board_id):
|
|
|
- """
|
|
|
- Enable continuous read
|
|
|
- :param board_id: id of the board do manipulate
|
|
|
- :return: -
|
|
|
- """
|
|
|
- Elements.setEnabled("acquire_{}".format(board_id), False)
|
|
|
- Elements.setEnabled("acquireTrigger_{}".format(board_id), False)
|
|
|
- Elements.setEnabled("continuous_read_{}".format(board_id), True)
|
|
|
- board.get_board_status(board_id).continuous_read = True
|
|
|
-
|
|
|
-
|
|
|
-def _bif_set_continuous_read_inactive(board_id):
|
|
|
- """
|
|
|
- Disable continuous read
|
|
|
- :param board_id: id of the board do manipulate
|
|
|
- :return: -
|
|
|
- """
|
|
|
- if board.get_board_status(board_id).continuous_read:
|
|
|
- board.get_board_status(board_id).continuous_read = False
|
|
|
- storage.get_board_specific_storage(board_id).continuous_read_timer.stop()
|
|
|
- Elements.setEnabled('acquire_{}'.format(board_id), True)
|
|
|
- Elements.setEnabled('acquireTrigger_{}'.format(board_id), True)
|
|
|
-
|
|
|
-
|
|
|
-def 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.
|
|
|
- :return: -
|
|
|
- """
|
|
|
- if not board.get_board_status(board_id).continuous_read:
|
|
|
- _bif_set_continuous_read_active(board_id)
|
|
|
- _bif_continuous_read(board_id, interval)
|
|
|
- else:
|
|
|
- _bif_set_continuous_read_inactive(board_id)
|
|
|
-
|
|
|
-
|
|
|
-def _bif_continuous_read(board_id, interval=None):
|
|
|
- """
|
|
|
- Perform continuous read based on a timer.
|
|
|
- :param interval:
|
|
|
- :return:
|
|
|
- """
|
|
|
- if interval is not None:
|
|
|
- # TODO: ueberall checken, dass der board specific storage verwendet wird
|
|
|
- storage.get_board_specific_storage(board_id).continuous_interval = interval
|
|
|
- storage.get_board_specific_storage(board_id).continuous_read_timer = QtCore.QTimer()
|
|
|
- logging.info("Start continuous read")
|
|
|
-
|
|
|
- def continuous_read_step():
|
|
|
- if board.get_board_status(board_id).continuous_read:
|
|
|
- _bif_read_data(board_id)
|
|
|
- storage.get_board_specific_storage(board_id).continuous_read_timer.singleShot(storage.storage.continuous_interval, continuous_read_step)
|
|
|
-
|
|
|
- storage.get_board_specific_storage(board_id).continuous_read_timer.singleShot(storage.storage.continuous_interval, continuous_read_step)
|
|
|
-
|
|
|
-
|
|
|
-def _bif_read_data(board_id):
|
|
|
- """
|
|
|
- Reads data acquired by board.
|
|
|
- :param board_id: id of the board do manipulate
|
|
|
- :return:
|
|
|
- """
|
|
|
- try:
|
|
|
- if board.get_board_config(board_id).get('pilot_bunch'):
|
|
|
- board.start_pilot_bunch_emulator(board_id)
|
|
|
-
|
|
|
- board.start_acquisition(board_id)
|
|
|
- try:
|
|
|
- board.wait_for_revolutions(board_id)
|
|
|
- except IndexError:
|
|
|
- error(0x002, "Unexpected output of pci for number of orbits to observe. Returning")
|
|
|
- return
|
|
|
- board.stop_acquisition(board_id)
|
|
|
- board.enable_transfer(board_id)
|
|
|
- data_raw = board.pci.read_data_to_variable(board_id)
|
|
|
- _bif_read_and_update_data_from_string(board_id, data_raw)
|
|
|
- except board.BoardError as e:
|
|
|
- logging.error("Reading failed for board {}: {}".format(str(board_id), str(e)))
|
|
|
-
|
|
|
-
|
|
|
-def bk_board_connected(board_id):
|
|
|
- """
|
|
|
- Interface to the board to check if it is connected.
|
|
|
- :param board_id: id of the board do manipulate
|
|
|
- :return: -
|
|
|
- """
|
|
|
- if not available_boards.has_boards:
|
|
|
- return False
|
|
|
- else:
|
|
|
- return board_id in available_boards.board_ids
|
|
|
-
|
|
|
-
|
|
|
-def bk_get_temperature(board_id):
|
|
|
- """
|
|
|
- Get Temperature from board and format it
|
|
|
- :param board_id: id of the board do manipulate
|
|
|
- :return: -
|
|
|
- """
|
|
|
- fpga_temp_raw_hex = board.pci.read(board_id, 1, '0x9110')[0]
|
|
|
- fpga_temp_raw_hex = fpga_temp_raw_hex[-3:]
|
|
|
- fpga_temp_raw_bin = '{0:012b}'.format(int(fpga_temp_raw_hex, 16))
|
|
|
- fpga_temp_encoded = board.get_dec_from_bits(fpga_temp_raw_bin, 9, 0)
|
|
|
- fpga_temp_celsius = '{0:2.2f}'.format(((fpga_temp_encoded * 503.975) / 1024) - 273.15)
|
|
|
- return fpga_temp_celsius
|
|
|
-
|
|
|
-
|
|
|
-backup_get_temp = bk_get_temperature
|
|
|
-
|
|
|
-
|
|
|
-def bk_time_scan(board_id, c_frm, c_to, f_frm, f_to, ts_pbar, plot_func, orbits_observe=None, orbits_skip=None, bucket_to_use=None, threshold_counts=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)
|
|
|
- :return: -
|
|
|
- """
|
|
|
- if board.get_board_status(board_id).time_scan:
|
|
|
- _bif_stop_time_scan(board_id, ts_pbar)
|
|
|
- else:
|
|
|
- _bif_start_time_scan(board_id, c_frm, c_to, f_frm, f_to, ts_pbar, plot_func, orbits_observe, orbits_skip, bucket_to_use, threshold_counts)
|
|
|
-
|
|
|
-
|
|
|
-def _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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- Elements.getElements("start_time_scan_{}".format(board_id))[0].setText(tr("Button", "Start time scan"))
|
|
|
- board.get_board_status(board_id).time_scan = False
|
|
|
- board.get_board_config(board_id).set_delay(storage.storage.th_old[board_id])
|
|
|
- board.get_board_config(board_id).set_chip_delay(
|
|
|
- [0, 1, 2, 3],
|
|
|
- [
|
|
|
- storage.storage.chip_1_old[board_id],
|
|
|
- storage.storage.chip_2_old[board_id],
|
|
|
- storage.storage.chip_3_old[board_id],
|
|
|
- storage.storage.chip_4_old[board_id]
|
|
|
- ]
|
|
|
- )
|
|
|
- ts_pbar.reset()
|
|
|
-
|
|
|
-
|
|
|
-# tst = None # Ugly but necessary for the thread not to be killed when function ends (which is almost immediately after start)
|
|
|
-# thread_ts = None
|
|
|
-
|
|
|
-
|
|
|
-def _bif_start_time_scan(board_id, c_frm, c_to, f_frm, f_to, timescan_progressbar, plot_func, orbits_observe, orbits_skip, bucket_to_use=None, threshold_counts=None):
|
|
|
- """
|
|
|
- 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 timescan progressbar
|
|
|
- :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 skip for the timescan (original values will be restored after timescan)
|
|
|
- :param bucket_to_use: Number of the bucket whos data will be used to calculate the average signal at each timescan step (if None all bunches will be used)
|
|
|
- :param threshold_counts: Skip buckets with adc counts between 2048 +- threshold_counts
|
|
|
- :return: -
|
|
|
- """
|
|
|
- thread = storage.get_board_specific_storage(board_id).setdefault("TimeScanThread", storage.ThreadStorage())
|
|
|
- # if thread_ts is not None:
|
|
|
- # logging.info("Time scan already running")
|
|
|
- # return
|
|
|
- if thread.running:
|
|
|
- logging.info("Time scan already running")
|
|
|
- return
|
|
|
-
|
|
|
- board.get_board_status(board_id).time_scan = True
|
|
|
- Elements.getElements("start_time_scan_{}".format(board_id))[0].setText(tr("Button", "Stop time scan"))
|
|
|
- if c_frm > c_to:
|
|
|
- logging.info('Coarse Scan Interval is invalid: (%i > %i)' % (c_frm, c_to))
|
|
|
- return
|
|
|
- if f_frm > f_to:
|
|
|
- logging.info('Fine Scan Interval is invalid: (%i > %i)' % (f_frm, f_to))
|
|
|
- return
|
|
|
-
|
|
|
- # the following could be made nicer with the use of setdefault and the use of get_board_specific_storage
|
|
|
- if not hasattr(storage.storage, 'th_old'):
|
|
|
- storage.storage.th_old = {}
|
|
|
- storage.storage.chip_1_old = {}
|
|
|
- storage.storage.chip_2_old = {}
|
|
|
- storage.storage.chip_3_old = {}
|
|
|
- storage.storage.chip_4_old = {}
|
|
|
-
|
|
|
- storage.storage.th_old[board_id] = board.get_board_config(board_id).get('th_delay')
|
|
|
- storage.storage.chip_1_old[board_id] = board.get_board_config(board_id).get('chip_1_delay')
|
|
|
- storage.storage.chip_2_old[board_id] = board.get_board_config(board_id).get('chip_2_delay')
|
|
|
- storage.storage.chip_3_old[board_id] = board.get_board_config(board_id).get('chip_3_delay')
|
|
|
- storage.storage.chip_4_old[board_id] = board.get_board_config(board_id).get('chip_4_delay')
|
|
|
-
|
|
|
- minimum = [None, None, None, None]
|
|
|
- maximum = np.zeros((4, 3))
|
|
|
- heatmap = np.zeros((4, (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):
|
|
|
- '''Timescan Thread class'''
|
|
|
- pbarSignal = QtCore.pyqtSignal(int)
|
|
|
- stopSignal = QtCore.pyqtSignal()
|
|
|
- finished = QtCore.pyqtSignal()
|
|
|
-
|
|
|
- def __init__(self, c_frm, c_to, f_frm, f_to, timescan_progressbar, bucket_to_use, threshold_counts):
|
|
|
- super(thread_time_scan, self).__init__()
|
|
|
- self.c_frm = c_frm
|
|
|
- self.c_to = c_to
|
|
|
- self.f_frm = f_frm
|
|
|
- self.f_to = f_to
|
|
|
- self.timescan_progressbar = timescan_progressbar
|
|
|
- self.bucket_to_use = bucket_to_use
|
|
|
- self.threshold_counts = threshold_counts
|
|
|
-
|
|
|
- def time_scan(self):
|
|
|
- '''Method to run in the thread that does the timescan'''
|
|
|
- Elements.setEnabled('acquire_{}'.format(board_id), False, exclude=Elements.getElements('start_time_scan_{}'.format(board_id)))
|
|
|
- if orbits_observe:
|
|
|
- if not hasattr(storage.storage, 'orbits_observe_before_timescan'):
|
|
|
- storage.storage.orbits_observe_before_timescan = {}
|
|
|
- storage.storage.orbits_observe_before_timescan[board_id] = board.get_board_config(board_id).get("orbits_observe") # save old values to restore after timescan
|
|
|
- board.get_board_config(board_id).update("orbits_observe", orbits_observe)
|
|
|
- bk_change_num_of_orbits(board_id, orbits_observe)
|
|
|
- if orbits_skip is not None:
|
|
|
- if not hasattr(storage.storage, 'orbits_skip_before_timescan'):
|
|
|
- storage.storage.orbits_skip_before_timescan = {}
|
|
|
- storage.storage.orbits_skip_before_timescan[board_id] = board.get_board_config(board_id).get("orbits_skip")
|
|
|
- board.get_board_config(board_id).update("orbits_skip", orbits_skip)
|
|
|
- bk_change_num_of_skipped_orbits(board_id, orbits_skip)
|
|
|
-
|
|
|
- c_step = 0
|
|
|
- for coarse in range(self.c_frm, self.c_to + 1):
|
|
|
- try:
|
|
|
- board.get_board_config(board_id).set_delay(coarse)
|
|
|
- except board.BoardError as e:
|
|
|
- self.stopSignal.emit()
|
|
|
- self.finished.emit()
|
|
|
- return
|
|
|
-
|
|
|
- f_step = 0
|
|
|
- for fine in range(self.f_frm, self.f_to + 1):
|
|
|
- board.get_board_config(board_id).set_chip_delay([0, 1, 2, 3], [fine, fine, fine, fine])
|
|
|
-
|
|
|
- try:
|
|
|
- if bk_get_config(board_id, 'pilot_bunch') is True:
|
|
|
- board.start_pilot_bunch_emulator(board_id)
|
|
|
-
|
|
|
- board.start_acquisition(board_id)
|
|
|
- try:
|
|
|
- board.wait_for_revolutions(board_id) # Wait before asking for data
|
|
|
- except IndexError:
|
|
|
- error(0x002, "Unexpected output of pci for number of orbits to observe. Stopping Timescan")
|
|
|
- self.stopSignal.emit()
|
|
|
- return
|
|
|
- board.stop_acquisition(board_id)
|
|
|
- board.enable_transfer(board_id)
|
|
|
-
|
|
|
- # -----------[ IMPORTANT ]---------------------
|
|
|
- if not kcgw.testing:
|
|
|
- data_raw = board.pci.read_data_to_variable(board_id)
|
|
|
- board.flush_dma(board_id)
|
|
|
- # ----------------------------------------------
|
|
|
- else:
|
|
|
- f_name = "{InsertPathToPreAcquiredTimscanDataHere}" + str(
|
|
|
- coarse) + "_" + str(fine) + ".str"
|
|
|
- f = open(f_name, 'r')
|
|
|
- data_raw = f.read()
|
|
|
-
|
|
|
- # The PCI software not only prints the desired data but also some additional information.
|
|
|
- # This information has to be removed here.
|
|
|
- # To do so we split the output string from PCI at "Writting" (Note: Writting is correct as
|
|
|
- # this is a typo in the PCI driver)
|
|
|
- data = io.read_from_string(data_raw, force=True, cache=False)
|
|
|
- except board.BoardError as e:
|
|
|
- self.stopSignal.emit()
|
|
|
- self.finished.emit()
|
|
|
- return
|
|
|
-
|
|
|
- for adc in range(4):
|
|
|
- if self.bucket_to_use is None:
|
|
|
- if self.threshold_counts is not None:
|
|
|
- indexes = np.where(np.logical_or(data.array[:, adc] > 2048+self.threshold_counts, data.array[:, adc] < 2048-self.threshold_counts))[0]
|
|
|
- if indexes.shape[0] == 0:
|
|
|
- buckets = data.array[:, adc]
|
|
|
- else:
|
|
|
- buckets = data.array[indexes, adc]
|
|
|
- else:
|
|
|
- buckets = data.array[:, adc]
|
|
|
- else:
|
|
|
- buckets = data.array[self.bucket_to_use::config.bunches_per_turn, adc]
|
|
|
- heatmap[adc, f_step, c_step] = float(buckets.sum()) / buckets.shape[0]
|
|
|
- # Uncomment this to change back to the old (non functional) method of maxima determination
|
|
|
- # if heatmap[adc, f_step, c_step] > maximum[adc, 0]:
|
|
|
- # maximum[adc, 0] = heatmap[adc, f_step, c_step]
|
|
|
- # maximum[adc, 1] = coarse
|
|
|
- # maximum[adc, 2] = fine
|
|
|
- # if minimum[adc] is None or minimum[adc] > heatmap[adc, f_step, c_step]:
|
|
|
- # minimum[adc] = heatmap[adc, f_step, c_step]
|
|
|
-
|
|
|
- self.pbarSignal.emit(((c_step * (f_to - f_frm + 1)) + f_step) + 1)
|
|
|
-
|
|
|
- #GUI is blocked in our tight loop. Give it an opportunity to handle events
|
|
|
- # QtGui.QApplication.processEvents() # remove this if moved to thread again
|
|
|
- if board.get_board_status(board_id).time_scan is False:
|
|
|
- # Time Scan Stop is already performed by button press. Nothing else to do but leave
|
|
|
- self.finished.emit()
|
|
|
- return
|
|
|
- f_step += 1
|
|
|
- c_step += 1
|
|
|
- self.finished.emit()
|
|
|
-
|
|
|
- def finished(timescan_progressbar):
|
|
|
- '''Method to handle the end of the thread'''
|
|
|
- thread.stop()
|
|
|
- _bif_stop_time_scan(board_id, timescan_progressbar)
|
|
|
- Elements.setEnabled('acquire_{}'.format(board_id), True, exclude=Elements.getElements('start_time_scan_{}'.format(board_id)))
|
|
|
- if orbits_observe:
|
|
|
- board.get_board_config(board_id).update("orbits_observe", storage.storage.orbits_observe_before_timescan[board_id]) # restore values
|
|
|
- bk_change_num_of_orbits(board_id, storage.storage.orbits_observe_before_timescan[board_id])
|
|
|
- if orbits_skip:
|
|
|
- board.get_board_config(board_id).update("orbits_skip", storage.storage.orbits_skip_before_timescan[board_id])
|
|
|
- bk_change_num_of_skipped_orbits(board_id, storage.storage.orbits_skip_before_timescan[board_id])
|
|
|
- board.get_board_config(board_id).set_delay(storage.storage.th_old[board_id])
|
|
|
-
|
|
|
- board.get_board_config(board_id).set_chip_delay(
|
|
|
- [0, 1, 2, 3],
|
|
|
- [
|
|
|
- storage.storage.chip_1_old[board_id],
|
|
|
- storage.storage.chip_2_old[board_id],
|
|
|
- storage.storage.chip_3_old[board_id],
|
|
|
- storage.storage.chip_4_old[board_id]
|
|
|
- ]
|
|
|
- )
|
|
|
-
|
|
|
-# maximum = []
|
|
|
- for adc, a in enumerate(heatmap):
|
|
|
- f, c = np.unravel_index(np.argmax(a), a.shape)
|
|
|
- maximum[adc] = [a[f, c], c+c_frm, f+f_frm]
|
|
|
-
|
|
|
- m = [np.min(heatmap[heatmap != 0]), np.max(heatmap)] # this gives the same levels for all 4 adcs
|
|
|
- plot_func(heatmap, levels=m, ranges=[c_frm,c_to,f_frm,f_to], newTitle=str(tr("sw", "Coarserange:{c_f}-{c_t} ; Finerange:{f_f}-{f_t}")).format(
|
|
|
- c_f=c_frm,
|
|
|
- c_t=c_to,
|
|
|
- f_f=f_frm,
|
|
|
- f_t=f_to),
|
|
|
- maxima=maximum
|
|
|
- )
|
|
|
-
|
|
|
- now = time.time()
|
|
|
- if not os.path.isdir(str(os.path.join(storage.storage.save_location, storage.storage.subdirname, 'timescan'))):
|
|
|
- os.makedirs((os.path.join(storage.storage.save_location, storage.storage.subdirname, 'timescan')))
|
|
|
- filename = os.path.join(storage.storage.save_location, storage.storage.subdirname, 'timescan', 'timescan_{:0.3f}.out'.format(
|
|
|
- now))
|
|
|
- f = open(filename, 'wr')
|
|
|
-
|
|
|
- for adc in range(4):
|
|
|
- f.write("#ADC_%s\n" % adc)
|
|
|
- for coarse, curr_cor in enumerate(np.transpose(heatmap[adc])):
|
|
|
- for fine, value in enumerate(curr_cor):
|
|
|
- f.write("%i;%i;%f\n" % ((coarse + c_frm), (fine + f_frm), value))
|
|
|
- f.write('\n')
|
|
|
-
|
|
|
- f.close()
|
|
|
- f = open(filename + '.gnuplot', 'wr')
|
|
|
- f.write('set datafile separator ";"\n')
|
|
|
- f.write('set multiplot layout 2,2\n')
|
|
|
- f.write('unset key\n')
|
|
|
- for i in range(4):
|
|
|
- f.write('set label 1 "ADC_%i" at graph 0.7,0.95 font ",8"\n' % (i + 1))
|
|
|
- f.write('plot "%s" every :::%i::%i using 3 with lines\n' % (filename, i, i))
|
|
|
- f.write('unset multiplot\n')
|
|
|
- f.close()
|
|
|
-
|
|
|
- return
|
|
|
-
|
|
|
- tst = thread_time_scan(c_frm, c_to, f_frm, f_to, timescan_progressbar, bucket_to_use, threshold_counts)
|
|
|
- thread.register(tst)
|
|
|
- thread.connect('pbarSignal', timescan_progressbar.setValue)
|
|
|
- thread.connect('finished', lambda: finished(timescan_progressbar))
|
|
|
- thread.connect('stopSignal', lambda: _bif_stop_time_scan(board_id, timescan_progressbar))
|
|
|
- thread.start('time_scan')
|
|
|
-
|
|
|
-
|
|
|
-def 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
|
|
|
- :return: -
|
|
|
- """
|
|
|
- # global bk_status_readout, bk_get_temperature
|
|
|
- board_status = bk_board_connected(board_id)
|
|
|
- if board_status:
|
|
|
- if not hasattr(board.get_board_status(board_id), 'board_connected') or \
|
|
|
- not board.get_board_status(board_id).board_connected:
|
|
|
- globals()['bk_status_readout'] = backup_readout
|
|
|
- globals()['bk_get_temperature'] = backup_get_temp
|
|
|
- board.get_board_status(board_id).board_connected = True
|
|
|
-
|
|
|
- else:
|
|
|
- Elements.setEnabled('no_board_{}'.format(board_id), False)
|
|
|
-
|
|
|
- def do_nothing():
|
|
|
- pass
|
|
|
-
|
|
|
- def no_temp(board_id):
|
|
|
- return "-"
|
|
|
-
|
|
|
- globals()['bk_status_readout'] = do_nothing
|
|
|
- globals()['bk_get_temperature'] = no_temp
|
|
|
- board.get_board_status(board_id).board_connected = False
|
|
|
- if board_status == False:
|
|
|
- board.get_board_status(board_id).status_text = tr("sw", "Board {} not connected".format(board_id))
|
|
|
- elif board_status == None:
|
|
|
- board.get_board_status(board_id).status_text = tr("sw", "Software Interface not found")
|
|
|
-
|
|
|
-
|
|
|
-def 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
|
|
|
- :return:
|
|
|
- """
|
|
|
- thread = storage.get_board_specific_storage(board_id).setdefault('TriggerThread', storage.ThreadStorage())
|
|
|
- if thread.running:
|
|
|
- Elements.getElements("acquireTrigger_{}".format(board_id))[0].setText(tr("Button", "Stopping Acquisition"))
|
|
|
- # FIXME: Button not updated otherwise:
|
|
|
- QtGui.qApp.processEvents()
|
|
|
- log(board_id=board_id, additional="Stop wait on trigger on board {}".format(board_id))
|
|
|
- thread.quit()
|
|
|
- thread.stop()
|
|
|
- # for elem in Elements.getElements("acquire_{}".format(board_id)):
|
|
|
- # if isinstance(elem, QtGui.QShortcut):
|
|
|
- # continue
|
|
|
- # elem.setText(tr("Button", "Stopping Acquisition"))
|
|
|
- # elem.setEnabled(False)
|
|
|
- else:
|
|
|
- log(board_id=board_id, additional="Start wait on trigger on board {}".format(board_id))
|
|
|
- # for elem in Elements.getElements("acquireTrigger_{}".format(board_id)):
|
|
|
- # if isinstance(elem, QtGui.QShortcut):
|
|
|
- # continue
|
|
|
- # elem.setIcon(QtGui.QIcon(config.install_path + config.stopIcon))
|
|
|
- # elem.setText(tr("Button", "Stop Acquisition"))
|
|
|
- Elements.setEnabled('acquire_{}'.format(board_id), False)
|
|
|
- callbacks.callback('acquisition_started', board_id)
|
|
|
- _bif_start_wait_on_trigger(board_id, num_of_acquisitions, skip, timeout, method)
|
|
|
-
|
|
|
-
|
|
|
-def _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
|
|
|
- :return: -
|
|
|
- """
|
|
|
-
|
|
|
- # FIXme: This is a work around, for method 2 to work everytime a standard single read needs to be perform before acquisition is started
|
|
|
- board.acquire_data(board_id, '/dev/null')
|
|
|
- #with workaround no flush dema need, because it is done at end of board.acquire_data() anyway.
|
|
|
- #board.flush_dma(board_id) # TODO: really at begining and end of function necessary?
|
|
|
- thread = storage.get_board_specific_storage(board_id).setdefault('TriggerThread', storage.ThreadStorage())
|
|
|
- if thread.running:
|
|
|
- logging.info("Wait already running on board {}".format(board_id))
|
|
|
- return
|
|
|
- log(board_id=board_id, additional="Start wait on trigger")
|
|
|
- board.get_board_status(board_id).wait_on_trigger = True
|
|
|
- if not os.path.isdir(str(os.path.join(storage.storage.save_location, storage.storage.subdirname))):
|
|
|
- os.makedirs(str(os.path.join(storage.storage.save_location, storage.storage.subdirname)))
|
|
|
-
|
|
|
- if not num_of_acquisitions:
|
|
|
- num_of_acquisitions = bk_get_config(board_id, 'acquisition_count')
|
|
|
- if not skip:
|
|
|
- skip = bk_get_config(board_id, 'trigger_skip')
|
|
|
- if not timeout:
|
|
|
- timeout = bk_get_config(board_id, 'trigger_timeout')
|
|
|
- if not method:
|
|
|
- method = bk_get_config(board_id, 'trigger_method')
|
|
|
-
|
|
|
- storage.get_board_specific_storage(board_id).trigger_progressbar = \
|
|
|
- _bif_ProgressBar(0, num_of_acquisitions, tr("sw", "Acquiring with board ")+str(board_id))
|
|
|
- board.pci.write(board_id, hex(num_of_acquisitions), "9024")
|
|
|
- time.sleep(0.1)
|
|
|
- board.pci.write(board_id, hex(skip), "902C")
|
|
|
- # time.sleep(0.1)
|
|
|
- # board.pci.write(board_id, 'ff0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
|
|
|
-
|
|
|
- # 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
|
|
|
- # I don't have an idea why it crashes.
|
|
|
- # A possible reason could the os.rename be (or even the board.safe_call as that saves data to the disk) But I think
|
|
|
- # this is rather unlikely
|
|
|
- # ~~NOTE~~: the thread of calibration also triggered segfaults sometimes. But this seems to be miraculously solved.
|
|
|
- # Something that is likely to cause the problem is the log.debug in board.safe_call
|
|
|
- # Logging (using the logging module) is directly connected to the main thread and could cause problems
|
|
|
- class thread_wait_on_signal(QtCore.QObject):
|
|
|
- '''Class to run the wait on signal functionality in a thread'''
|
|
|
- countUpdate = QtCore.pyqtSignal(int)
|
|
|
- stopSignal = QtCore.pyqtSignal()
|
|
|
- finished = QtCore.pyqtSignal()
|
|
|
- liveplot = QtCore.pyqtSignal(int, str) # This has to be changed if board_id is no integer
|
|
|
-
|
|
|
- def __init__(self):
|
|
|
- super(thread_wait_on_signal, self).__init__()
|
|
|
- self.noa = None
|
|
|
- self.path = None
|
|
|
- self.timeout = None
|
|
|
- self._quit = False
|
|
|
-
|
|
|
- def init(self, num_of_acquisitions, path, timeout):
|
|
|
- '''initialise a new run'''
|
|
|
- self.noa = num_of_acquisitions
|
|
|
- self.path = path
|
|
|
- self.timeout = timeout
|
|
|
- self._quit = False
|
|
|
-
|
|
|
- # Elements.setEnabled('acquireTrigger_{}'.format(board_id), False) # exclude=Elements.getElements('wait_on_trigger_{}'.format(board_id)))
|
|
|
-
|
|
|
- def wait_rw_simul(self): # Method 1
|
|
|
- '''Wait simultaniously (with the pci command) for a trigger signal'''
|
|
|
- board.pci.write(board_id, 'ff0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
|
|
|
- for num_of_acq in range(self.noa):
|
|
|
- # def step():
|
|
|
- if self._quit:
|
|
|
- break
|
|
|
- filename = self.path +'/{:0.3f}.out'.format(time.time())
|
|
|
- board.pci.read_data_to_file(board_id, filename=filename, timeout=(self.timeout*1000000))
|
|
|
- # rename with correct timestamp - last modified time
|
|
|
- self.countUpdate.emit(num_of_acq + 1)
|
|
|
-
|
|
|
- # file operations
|
|
|
- if not os.path.isfile(filename):
|
|
|
- error(0x001, "No File Created")
|
|
|
- continue
|
|
|
-
|
|
|
- newfile = '{path}/trigger_{num:05}_{htime}_{unixtime}.out'.format(
|
|
|
- num=num_of_acq,
|
|
|
- htime=dt.fromtimestamp(os.path.getmtime(filename)).strftime('%Y-%m-%dT%Hh%Mm%Ss%f'),
|
|
|
- unixtime=int(os.path.getmtime(filename)),
|
|
|
- path=self.path
|
|
|
- )
|
|
|
- os.rename(filename, newfile)
|
|
|
- if os.path.getsize(newfile) > 0:
|
|
|
- self.liveplot.emit(board_id, newfile)
|
|
|
- else:
|
|
|
- logging.info("Acquired 0b, possible trigger timeout.")
|
|
|
-
|
|
|
- self.finished.emit()
|
|
|
-
|
|
|
- def wait_rw_seq(self): # Method 2
|
|
|
- '''Wait sequentially (in the gui) for a trigger signal'''
|
|
|
- for num_of_acq in range(self.noa):
|
|
|
- board.pci.write(board_id, '00bf0', hex_mask='CF0') # enable readout
|
|
|
- pre_acq_num = board.pci.read(board_id, 1, '9034')[0]
|
|
|
- time_a = time.time()
|
|
|
- timeout = False
|
|
|
- while pre_acq_num == board.pci.read(board_id, 1, '9034')[0]:
|
|
|
- if time.time() - time_a > self.timeout:
|
|
|
- timeout = True
|
|
|
- break
|
|
|
- if self._quit:
|
|
|
- self.finished.emit()
|
|
|
- return
|
|
|
- if not timeout:
|
|
|
- board.pci.write(board_id, '000f0', hex_mask='8F0') # disable readout
|
|
|
- board.pci.write(board_id, '007f0', hex_mask='CF0') # enable transfer
|
|
|
- filename = self.path +'/{:0.3f}.out'.format(time.time())
|
|
|
- board.pci.read_data_to_file(board_id, filename=filename, timeout=(self.timeout*1000000))
|
|
|
- # board.pci.write(board_id, '000f0', hex_mask='4F0') # disable transfer
|
|
|
- self.countUpdate.emit(copy.deepcopy(num_of_acq+1))
|
|
|
- if self._quit: # is this really the correct position? file is taken but not renamed!
|
|
|
- self.finished.emit()
|
|
|
- break
|
|
|
-
|
|
|
- if not os.path.isfile(filename):
|
|
|
- error(0x001, "No File Created")
|
|
|
- continue
|
|
|
-
|
|
|
- newfile = '{path}/trigger_{num:05}_{htime}_{unixtime}.out'.format(
|
|
|
- num=num_of_acq,
|
|
|
- htime=dt.fromtimestamp(os.path.getmtime(filename)).strftime('%Y-%m-%dT%Hh%Mm%Ss%f'),
|
|
|
- unixtime=int(os.path.getmtime(filename)),
|
|
|
- path=self.path
|
|
|
- )
|
|
|
- os.rename(filename, newfile)
|
|
|
- self.liveplot.emit(board_id, newfile)
|
|
|
- else:
|
|
|
- logging.info("Trigger timeout.")
|
|
|
-
|
|
|
-
|
|
|
- self.finished.emit()
|
|
|
-
|
|
|
- def quit(self):
|
|
|
- '''quit this thread'''
|
|
|
- self._quit = True
|
|
|
-
|
|
|
- def __del__(self):
|
|
|
- print('quite')
|
|
|
- board.pci.write(board_id, '0', '9024')
|
|
|
- time.sleep(0.1)
|
|
|
- board.pci.write(board_id, '0', '902C')
|
|
|
- time.sleep(0.1)
|
|
|
- board.pci.write(board_id, '3f0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
|
|
|
- board.flush_dma(board_id)
|
|
|
-
|
|
|
- def finished():
|
|
|
- '''Handle the end of the thread'''
|
|
|
- board.pci.write(board_id, '0', '9024')
|
|
|
- time.sleep(0.1)
|
|
|
- board.pci.write(board_id, '0', '902C')
|
|
|
- time.sleep(0.1)
|
|
|
- board.pci.write(board_id, '3f0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
|
|
|
- board.flush_dma(board_id)
|
|
|
-
|
|
|
- thread.stop()
|
|
|
- board.get_board_status(board_id).wait_on_trigger = False
|
|
|
- storage.get_board_specific_storage(board_id).trigger_progressbar.remove(0)
|
|
|
- log(board_id=board_id, additional="Stop wait on trigger")
|
|
|
- Elements.setEnabled('acquire_{}'.format(board_id), True)
|
|
|
- callbacks.callback('acquisition_stopped', board_id)
|
|
|
-
|
|
|
- # for elem in Elements.getElements("acquire_{}".format(board_id)):
|
|
|
- # if isinstance(elem, QtGui.QShortcut):
|
|
|
- # continue
|
|
|
- # elem.setIcon(QtGui.QIcon(config.install_path + config.startIcon))
|
|
|
- # elem.setText(tr("Button", "Start Acquisition"))
|
|
|
- # elem.setEnabled(True)
|
|
|
-
|
|
|
- return
|
|
|
-
|
|
|
- # twt = thread_wait_on_signal(num_of_acquisitions, storage.storage.save_location + '/' + storage.storage.subdirname,
|
|
|
- # timeout)
|
|
|
- if not thread.is_registered():
|
|
|
- twt = thread_wait_on_signal()
|
|
|
- thread.register(twt)
|
|
|
- else:
|
|
|
- thread.disconnect('countUpdate', 'finished', 'liveplot')
|
|
|
- thread.init(num_of_acquisitions, storage.storage.save_location + '/' + storage.storage.subdirname, timeout)
|
|
|
- # reconnect signals to make sure the correct versions of methods are called
|
|
|
- thread.connect('countUpdate', storage.get_board_specific_storage(board_id).trigger_progressbar.setValue)
|
|
|
- thread.connect('finished', finished)
|
|
|
- thread.connect('liveplot', _bif_read_and_update_data_from_file)
|
|
|
- if method == 1:
|
|
|
- thread.start('wait_rw_simul')
|
|
|
- elif method == 2:
|
|
|
- thread.start('wait_rw_seq')
|
|
|
- else:
|
|
|
- raise ValueError("Wrong method")
|
|
|
+"""
|
|
|
+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_
|
|
|
+"""
|
|
|
+
|
|
|
+import logging
|
|
|
+import time
|
|
|
+from datetime import datetime as dt
|
|
|
+import os
|
|
|
+import copy
|
|
|
+from PyQt4 import QtGui, QtCore
|
|
|
+import numpy as np
|
|
|
+from backend import board
|
|
|
+from backend.board import available_boards
|
|
|
+from backend import io
|
|
|
+from backend import dataset
|
|
|
+from groupedelements import Buttons, Elements, live_plot_windows
|
|
|
+import storage
|
|
|
+from .. import config
|
|
|
+import kcgwidget as kcgw
|
|
|
+from kcgwidget import error
|
|
|
+from callbacks import callbacks
|
|
|
+from log import log
|
|
|
+from globals import glob as global_objects
|
|
|
+
|
|
|
+tr = kcgw.tr
|
|
|
+
|
|
|
+livePlotData = None
|
|
|
+
|
|
|
+
|
|
|
+def 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)
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ st.continuous_read = False
|
|
|
+ st.calibrated = False
|
|
|
+ st.synced = False
|
|
|
+ st.defaults_set = False
|
|
|
+ st.status_text = tr("sw", "Ready")
|
|
|
+ st.time_scan = False
|
|
|
+ st.wait_on_trigger = False
|
|
|
+ st.last_file = None
|
|
|
+ st.board_connected = True
|
|
|
+ st.continuous_interval = 1000
|
|
|
+
|
|
|
+
|
|
|
+# -----------[ Backend Interface ]----------------------
|
|
|
+def _bif_enable_wait_cursor():
|
|
|
+ """
|
|
|
+ Show the "Wait Cursor"
|
|
|
+ """
|
|
|
+ QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
|
|
|
+
|
|
|
+
|
|
|
+def _bif_disable_wait_cursor():
|
|
|
+ """
|
|
|
+ Show the normal Cursor
|
|
|
+ """
|
|
|
+ QtGui.QApplication.restoreOverrideCursor()
|
|
|
+
|
|
|
+
|
|
|
+def _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)
|
|
|
+ """
|
|
|
+ if board.get_board_status(board_id).continuous_read:
|
|
|
+ if not available_boards.multi_board:
|
|
|
+ popup = PopupDialog(tr("Dialog", "Continuous read is currently active!\nStop continuous read and proceed?"),
|
|
|
+ title=popup_title_text)
|
|
|
+ else:
|
|
|
+ popup = PopupDialog(tr("Dialog", "Board {board_id}\nContinuous read is currently active!\nStop continuous read and proceed?").format(board_id=board_id),
|
|
|
+ title=popup_title_text)
|
|
|
+ popup.exec_()
|
|
|
+ popup.deleteLater()
|
|
|
+ if popup.get_return_value() is False:
|
|
|
+ return False
|
|
|
+ else:
|
|
|
+ _bif_set_continuous_read_inactive(board_id)
|
|
|
+ Elements.setChecked("continuousread_"+str(board_id), False)
|
|
|
+ return True
|
|
|
+ else:
|
|
|
+ return False
|
|
|
+
|
|
|
+
|
|
|
+def bk_status_readout():
|
|
|
+ """
|
|
|
+ Read Status for every connected board
|
|
|
+ """
|
|
|
+ if not available_boards.has_boards:
|
|
|
+ return
|
|
|
+ for brd in available_boards.board_ids:
|
|
|
+ _bif_status_readout(brd)
|
|
|
+
|
|
|
+
|
|
|
+def _bif_status_readout(board_id):
|
|
|
+ """
|
|
|
+ Read Status from board and update variables
|
|
|
+ as well as enable and disable corresponding Buttons
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ # part_TODO: NOTE: Problem with this is that certain buttons will be greyed out until other buttons are pressed
|
|
|
+ # part_TODO: even if only the gui is restarted and the board is in the same state
|
|
|
+ if kcgw.testing:
|
|
|
+ return
|
|
|
+ if board.is_active(board_id):
|
|
|
+ Buttons.setEnabled("after_start_{}".format(board_id), True)
|
|
|
+ Buttons.setEnabled("start_board_{}".format(board_id), False)
|
|
|
+ Buttons.setEnabled("continuous_read_{}".format(board_id), True)
|
|
|
+
|
|
|
+ # MenuItems.setEnabled("continuous_read", True)
|
|
|
+ else:
|
|
|
+ board.get_board_status(board_id).calibrated = False
|
|
|
+ board.get_board_status(board_id).synced = False
|
|
|
+ board.get_board_status(board_id).defaults_set = False
|
|
|
+ Buttons.setEnabled("after_start_{}".format(board_id), False)
|
|
|
+ Buttons.setEnabled("continuous_read_{}".format(board_id), False)
|
|
|
+ Buttons.setEnabled("synchronize_{}".format(board_id), board.get_board_status(board_id).calibrated)
|
|
|
+ Buttons.setEnabled("set_defaults_{}".format(board_id), board.get_board_status(board_id).synced)
|
|
|
+ Buttons.setEnabled("acquire_{}".format(board_id), board.get_board_status(board_id).synced)
|
|
|
+ Buttons.setEnabled("acquireTrigger_{}".format(board_id), board.get_board_status(board_id).synced)
|
|
|
+ Elements.setEnabled("timing_{}".format(board_id), board.get_board_status(board_id).synced)
|
|
|
+
|
|
|
+ storage.get_board_specific_storage(board_id).update_LED()
|
|
|
+
|
|
|
+
|
|
|
+backup_readout = bk_status_readout
|
|
|
+
|
|
|
+
|
|
|
+class PopupDialog(QtGui.QDialog):
|
|
|
+ """
|
|
|
+ Simple Class to show a popup dialog.
|
|
|
+ """
|
|
|
+
|
|
|
+ def __init__(self, text, title=None, parent=None):
|
|
|
+ QtGui.QDialog.__init__(self, parent)
|
|
|
+ self.text = text
|
|
|
+ self.setWindowTitle(title if title else tr("Dialog", "User action required"))
|
|
|
+ self.return_value = False
|
|
|
+
|
|
|
+ size = QtCore.QSize(200, 200)
|
|
|
+ # self.setMaximumSize(size)
|
|
|
+ self.setMinimumSize(size)
|
|
|
+ box = QtGui.QVBoxLayout()
|
|
|
+ self.text_label = QtGui.QLabel(self.text)
|
|
|
+ self.text_label.setAlignment(QtCore.Qt.AlignCenter)
|
|
|
+ box.addWidget(self.text_label)
|
|
|
+ self.okay_btn = QtGui.QPushButton(tr("Button", "Ok"))
|
|
|
+ self.okay_btn.setStyleSheet("padding: 15px;")
|
|
|
+ self.okay_btn.clicked.connect(self.on_okay)
|
|
|
+ box.addWidget(self.okay_btn)
|
|
|
+ box.addSpacerItem(QtGui.QSpacerItem(1, 20))
|
|
|
+ self.cancel_btn = QtGui.QPushButton(tr("Button", "Cancel"))
|
|
|
+ self.cancel_btn.setStyleSheet("padding: 15px;")
|
|
|
+ self.cancel_btn.clicked.connect(self.on_cancel)
|
|
|
+ box.addWidget(self.cancel_btn)
|
|
|
+ self.setLayout(box)
|
|
|
+
|
|
|
+ def on_okay(self):
|
|
|
+ """
|
|
|
+ Handler for the press of the ok button
|
|
|
+ """
|
|
|
+ self.return_value = True
|
|
|
+ self.close()
|
|
|
+
|
|
|
+ def on_cancel(self):
|
|
|
+ """
|
|
|
+ Handler for the press of the cancel button
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ self.close()
|
|
|
+
|
|
|
+ def get_return_value(self):
|
|
|
+ """
|
|
|
+ Get True if the Window was closed with OK else False
|
|
|
+ :return: True if OK else False
|
|
|
+ """
|
|
|
+ return self.return_value
|
|
|
+
|
|
|
+
|
|
|
+def 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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ _bif_enable_wait_cursor()
|
|
|
+ log(board_id=board_id, additional="Starting Board - following values are probably default values")
|
|
|
+
|
|
|
+ sequence = board.startup_sequence(board_id)
|
|
|
+ number = sequence.next()
|
|
|
+
|
|
|
+ if _bif_continuous_read_is_enabled(board_id, tr("Button", "Start Board")):
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ return False
|
|
|
+
|
|
|
+ try:
|
|
|
+ if board.is_active(board_id):
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ bk_status_readout()
|
|
|
+ return
|
|
|
+
|
|
|
+ logging.info("Activating Board")
|
|
|
+ sequence.next()
|
|
|
+ time.sleep(1.0)
|
|
|
+ dialog1 = PopupDialog(tr("Button", "Switch On the power supply --> FIRST <-- (on board {0})".format(board_id)))
|
|
|
+ dialog1.exec_()
|
|
|
+ dialog1.deleteLater()
|
|
|
+
|
|
|
+ if not dialog1.get_return_value():
|
|
|
+ logging.error("Starting procedure canceled")
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ return False
|
|
|
+
|
|
|
+ logging.info("Switch ON T/Hs")
|
|
|
+ sequence.next()
|
|
|
+ time.sleep(0.1)
|
|
|
+ dialog2 = PopupDialog(tr("Dialog", "Switch On the power supply --> SECOND <-- (on board {0})".format(board_id)))
|
|
|
+ dialog2.exec_()
|
|
|
+ dialog2.deleteLater()
|
|
|
+
|
|
|
+ if not dialog2.get_return_value():
|
|
|
+ logging.info("Starting procedure canceled")
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ return False
|
|
|
+
|
|
|
+ logging.info("Switch ON ADCs")
|
|
|
+ sequence.next()
|
|
|
+ time.sleep(0.1)
|
|
|
+
|
|
|
+ sequence.next()
|
|
|
+ time.sleep(1.0)
|
|
|
+
|
|
|
+ for step in sequence:
|
|
|
+ time.sleep(0.1)
|
|
|
+
|
|
|
+ logging.info("Board started successfully!")
|
|
|
+ except board.BoardError as e:
|
|
|
+ logging.error("Starting board failed: {}".format(str(e)))
|
|
|
+
|
|
|
+ bk_update_config(board_id, 'header', bk_get_config(board_id, 'header'))
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ bk_status_readout()
|
|
|
+
|
|
|
+
|
|
|
+class _bif_ProgressBar(QtGui.QProgressBar):
|
|
|
+ """
|
|
|
+ Simple Progressbar class.
|
|
|
+ """
|
|
|
+
|
|
|
+ def __init__(self, min, max, text):
|
|
|
+ super(_bif_ProgressBar, self).__init__()
|
|
|
+ self.setRange(min, max)
|
|
|
+ self.setMaximumHeight(18)
|
|
|
+ # kcgw.statusbar.clearMessage()
|
|
|
+ self.label = QtGui.QLabel(text)
|
|
|
+ global_objects.get_global('statusbar').insertWidget(0, self.label)
|
|
|
+ global_objects.get_global('statusbar').insertWidget(1, self)
|
|
|
+ self.setValue(0)
|
|
|
+ QtGui.qApp.processEvents()
|
|
|
+
|
|
|
+ def remove(self, timeout=None):
|
|
|
+ """
|
|
|
+ Remove this instance of a progressbar
|
|
|
+ :param timeout: the time from calling this function to wanishing of the progressbar
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+
|
|
|
+ def remove_progressbar():
|
|
|
+ global_objects.get_global('statusbar').removeWidget(self)
|
|
|
+ global_objects.get_global('statusbar').removeWidget(self.label)
|
|
|
+ # kcgw.statusbar.showMessage(board.status.status_text)
|
|
|
+ self.destroy()
|
|
|
+
|
|
|
+ if timeout:
|
|
|
+ QtCore.QTimer.singleShot(timeout, remove_progressbar)
|
|
|
+ else:
|
|
|
+ remove_progressbar()
|
|
|
+
|
|
|
+
|
|
|
+# thread = None
|
|
|
+# cal = None
|
|
|
+def 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.
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ log(board_id=board_id, additional="Calibrate")
|
|
|
+ thread = storage.get_board_specific_storage(board_id).setdefault('CalibrateThread', storage.ThreadStorage())
|
|
|
+ if thread.running:
|
|
|
+ logging.info("Calibration already running")
|
|
|
+ return
|
|
|
+ _bif_enable_wait_cursor()
|
|
|
+ if _bif_continuous_read_is_enabled(board_id, tr("Button", "Calibrate Board")):
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ return
|
|
|
+
|
|
|
+ sequence = board.calibration_sequence(board_id)
|
|
|
+ number = sequence.next()
|
|
|
+ progressbar = _bif_ProgressBar(0, number, tr("sw", "Calibrating"))
|
|
|
+
|
|
|
+ class Calibrate(QtCore.QObject):
|
|
|
+ """
|
|
|
+ Class to use as thread class. NOTE: this is not used at the moment.
|
|
|
+ """
|
|
|
+ update_progressbar_signal = QtCore.pyqtSignal(int)
|
|
|
+ finished = QtCore.pyqtSignal()
|
|
|
+
|
|
|
+ def calibrate(self):
|
|
|
+ """
|
|
|
+ The method that is called inside the thread and that does the calibration
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ logging.info('Started Board Calibration')
|
|
|
+ for idx, step in enumerate(sequence):
|
|
|
+ time.sleep(0.5)
|
|
|
+ self.update_progressbar_signal.emit(idx)
|
|
|
+ board.get_board_status(board_id).calibrated = True
|
|
|
+ except board.BoardError as e:
|
|
|
+ logging.error("Calibration failed: {}".format(str(e)))
|
|
|
+ # self.do_status_readout()
|
|
|
+ self.finished.emit()
|
|
|
+ return
|
|
|
+
|
|
|
+ logging.info("Board Calibration successful!")
|
|
|
+ self.finished.emit()
|
|
|
+
|
|
|
+ def thread_quit():
|
|
|
+ """
|
|
|
+ Method to handle the end of the calibration thread
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ thread.stop()
|
|
|
+ bk_status_readout()
|
|
|
+ progressbar.remove(0)
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ if do_the_rest: # execute sync and set defaults (this is set if prepare board was pressed)
|
|
|
+ do_the_rest(board_id)
|
|
|
+
|
|
|
+ cal = Calibrate()
|
|
|
+ thread.register(cal)
|
|
|
+ thread.connect('update_progressbar_signal', progressbar.setValue)
|
|
|
+ thread.connect('finished', thread_quit)
|
|
|
+ thread.start('calibrate')
|
|
|
+
|
|
|
+def bk_sync_board(board_id):
|
|
|
+ """
|
|
|
+ Sends commands to the board to sync with triggers.
|
|
|
+ :param board_id: id of the board do manipulate
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ _bif_enable_wait_cursor()
|
|
|
+ log(board_id=board_id, additional="Synchronize")
|
|
|
+ if _bif_continuous_read_is_enabled(board_id, tr("Dialog", "Synchronize Board")):
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ return
|
|
|
+
|
|
|
+ progressbar = _bif_ProgressBar(0, 100, tr("sw", "Synchronizing"))
|
|
|
+ sequence = board.synchronisation_sequence(board_id)
|
|
|
+ try:
|
|
|
+ sequence.next() # skip number
|
|
|
+ logging.info("Synchronize PLLs")
|
|
|
+ sequence.next()
|
|
|
+ for i in range(1, 101):
|
|
|
+ time.sleep(0.01)
|
|
|
+ progressbar.setValue(i)
|
|
|
+ sequence.next()
|
|
|
+ except board.BoardError as e:
|
|
|
+ logging.error("Synchronization failed: {}".format(str(e)))
|
|
|
+ progressbar.remove(0)
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ bk_status_readout()
|
|
|
+ return
|
|
|
+
|
|
|
+ progressbar.remove(0)
|
|
|
+
|
|
|
+ logging.info("Board synchronization successful!")
|
|
|
+ # self.set_defaults_button.setEnabled(True)
|
|
|
+ board.get_board_status(board_id).synced = True
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ bk_status_readout()
|
|
|
+
|
|
|
+
|
|
|
+def 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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ _bif_enable_wait_cursor()
|
|
|
+ if defaults:
|
|
|
+ log(board_id=board_id, additional="Set Default Values")
|
|
|
+ else:
|
|
|
+ log(board_id=board_id, additional="Update Values on board")
|
|
|
+ if _bif_continuous_read_is_enabled(board_id, tr("Dialog", "Update Values on Board")):
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ return
|
|
|
+
|
|
|
+ sequence = board.write_value_sequence(board_id)
|
|
|
+ number = sequence.next()
|
|
|
+ if defaults:
|
|
|
+ board.get_board_config(board_id)._set_defaults()
|
|
|
+ progressbar = _bif_ProgressBar(0, number, tr("sw", "Setting Defaults"))
|
|
|
+ logging.info("Setting default Values")
|
|
|
+ else:
|
|
|
+ progressbar = _bif_ProgressBar(0, number, tr("sw", "Updating Values on Board"))
|
|
|
+ logging.info("Updating Values")
|
|
|
+
|
|
|
+ try:
|
|
|
+ for idx, step in enumerate(sequence):
|
|
|
+ time.sleep(0.1)
|
|
|
+ progressbar.setValue(idx)
|
|
|
+ except board.BoardError as e:
|
|
|
+ logging.error("Updating Values failed: {}".format(str(e)))
|
|
|
+ progressbar.remove(0)
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ bk_status_readout()
|
|
|
+ return
|
|
|
+
|
|
|
+ board.get_board_status(board_id).defaults_set = True
|
|
|
+ progressbar.remove(0)
|
|
|
+
|
|
|
+ if defaults:
|
|
|
+ logging.info("Default values set successfully!")
|
|
|
+ else:
|
|
|
+ logging.info("Updated values successfully!")
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ bk_status_readout()
|
|
|
+ board.get_board_config(board_id).notify_all_observers()
|
|
|
+
|
|
|
+
|
|
|
+def bk_stop_board(board_id):
|
|
|
+ """
|
|
|
+ Stops the board and shuts it down
|
|
|
+ :param board_id: id of the board do manipulate
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ _bif_enable_wait_cursor()
|
|
|
+ log(board_id=board_id, additional="Stop Board")
|
|
|
+ if _bif_continuous_read_is_enabled(board_id, tr("Dialog", "Soft Reset Board")):
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ return
|
|
|
+
|
|
|
+ try:
|
|
|
+ logging.info("Switching Off Board {}".format(board_id))
|
|
|
+ board.pci.write(board_id, '0x9040')
|
|
|
+ board.pci.stop_dma(board_id)
|
|
|
+ board.stop_board(board_id)
|
|
|
+ time.sleep(0.5)
|
|
|
+ except board.BoardError as e:
|
|
|
+ logging.error("Sequence failed: {}".format(str(e)))
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ bk_status_readout()
|
|
|
+ return
|
|
|
+
|
|
|
+ logging.info("Board switched off successfully!")
|
|
|
+ Buttons.setEnabled("after_start_{}".format(board_id), False)
|
|
|
+ Buttons.setEnabled("start_board_{}".format(board_id), True)
|
|
|
+ board.get_board_status(board_id).calibrated = False
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ bk_status_readout()
|
|
|
+
|
|
|
+def bk_soft_reset(board_id):
|
|
|
+ """
|
|
|
+ Perform a soft reset.
|
|
|
+ :param board_id: id of the board do manipulate
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ _bif_enable_wait_cursor()
|
|
|
+ log(board_id=board_id, additional="Soft Reset")
|
|
|
+ if _bif_continuous_read_is_enabled(board_id, tr("Dialog", "Soft Reset Board")):
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ return
|
|
|
+
|
|
|
+ try:
|
|
|
+ logging.info("Soft-Resetting Board {}...".format(board_id))
|
|
|
+ board.soft_reset(board_id)
|
|
|
+ except board.BoardError as e:
|
|
|
+ logging.error("Sequence failed: {}".format(str(e)))
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ bk_status_readout()
|
|
|
+ return
|
|
|
+
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+ bk_status_readout()
|
|
|
+ board.get_board_config(board_id).update('header', True) # reset header (might be reset by soft reset)
|
|
|
+ logging.info("Soft-Reset successful.")
|
|
|
+
|
|
|
+
|
|
|
+def 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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ if silent:
|
|
|
+ board.get_board_config(board_id).updateSilent(key, value)
|
|
|
+ else:
|
|
|
+ board.get_board_config(board_id).update(key, value)
|
|
|
+ except board.BoardError as e:
|
|
|
+ logging.error("Setting value of {} failed: {}".format(key, str(e)))
|
|
|
+
|
|
|
+
|
|
|
+def 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
|
|
|
+ """
|
|
|
+ return board.get_board_config(board_id).get(key)
|
|
|
+
|
|
|
+
|
|
|
+def 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
|
|
|
+ """
|
|
|
+ return getattr(board.get_board_status(board_id), status_variable, None)
|
|
|
+
|
|
|
+
|
|
|
+def bk_get_status(board_id):
|
|
|
+ """
|
|
|
+ Interface to the get_status of the board
|
|
|
+ NOTE: This is not get_board_status
|
|
|
+ :return: status dictionary
|
|
|
+ """
|
|
|
+ return board.get_status(board_id)
|
|
|
+
|
|
|
+
|
|
|
+def bk_get_board_config(board_id):
|
|
|
+ """
|
|
|
+ Get the board config instance
|
|
|
+ :param board_id: the id of the board
|
|
|
+ :return: the config instance
|
|
|
+ """
|
|
|
+ return board.get_board_config(board_id)
|
|
|
+
|
|
|
+def 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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ bk_update_config(board_id, "orbits_observe", value, silent=silent)
|
|
|
+
|
|
|
+
|
|
|
+def 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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ bk_update_config(board_id, "orbits_skip", value, silent=silent)
|
|
|
+
|
|
|
+
|
|
|
+def 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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ bk_update_config(board_id, "acquisition_count", value, silent=silent)
|
|
|
+
|
|
|
+
|
|
|
+def 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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ bk_update_config(board_id, "orbits_wait_time", value, silent=silent)
|
|
|
+
|
|
|
+
|
|
|
+def 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
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ bk_update_config(board_id, "build_spectrograms", value, silent=silent)
|
|
|
+
|
|
|
+
|
|
|
+def 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
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ bk_update_config(board_id, "pilot_bunch", value, silent=silent)
|
|
|
+
|
|
|
+
|
|
|
+def _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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ return # because it is broken
|
|
|
+ if not os.path.isdir(str(path)):
|
|
|
+ return
|
|
|
+
|
|
|
+ # how does this get data? dataset.data does not exist
|
|
|
+ transform = dataset.data.fft(1, frm=0, to=-1)
|
|
|
+ for i in range(config.bunches_per_turn - 1):
|
|
|
+ filename = os.path.join(storage.storage.save_location, storage.storage.subdirname, str(path), "%i.hsp" % i)
|
|
|
+ write_header = False
|
|
|
+ if not os.path.isfile(filename):
|
|
|
+ write_header = True
|
|
|
+ f = open(filename, 'ab')
|
|
|
+ if write_header:
|
|
|
+ f.write("#hsp\n") # heb spectrogram magic number
|
|
|
+ f.write("#"+str(board.get_board_config(board_id).get("orbits_skip")))
|
|
|
+ f.write("\n")
|
|
|
+ line = transform[i, :]
|
|
|
+ f.write('{:0.3f} '.format(time.time()))
|
|
|
+ for e in line:
|
|
|
+ f.write("%s " % np.absolute(e))
|
|
|
+ f.write("\n")
|
|
|
+ f.close()
|
|
|
+
|
|
|
+
|
|
|
+def _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
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ now = time.time()
|
|
|
+ if not os.path.isdir(str(storage.storage.save_location + '/' + storage.storage.subdirname)):
|
|
|
+ os.makedirs(str(storage.storage.save_location + '/' + storage.storage.subdirname))
|
|
|
+ filename = storage.storage.save_location + '/' + storage.storage.subdirname+'/{:0.3f}.out'.format(now)
|
|
|
+ board.get_board_status(board_id).last_file = filename
|
|
|
+
|
|
|
+ try:
|
|
|
+ simulate = board.get_board_config(board_id).get("pilot_bunch")
|
|
|
+ try:
|
|
|
+ board.acquire_data(board_id, filename, simulate=simulate)
|
|
|
+ if not os.path.isfile(filename):
|
|
|
+ error(0x001, "No File Created")
|
|
|
+ except IndexError:
|
|
|
+ error(0x002, "Unexpected output of pci for number of orbits to observe. Returning")
|
|
|
+ return
|
|
|
+ _bif_read_and_update_data_from_file(board_id, filename)
|
|
|
+ except board.BoardError as e:
|
|
|
+ logging.error("Reading failed: {}".format(str(e)))
|
|
|
+
|
|
|
+
|
|
|
+def _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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ _bif_read_and_update(board_id, io.read_from_file, str(filename))
|
|
|
+
|
|
|
+
|
|
|
+def _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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ _bif_read_and_update(board_id, io.read_from_string, raw_data)
|
|
|
+
|
|
|
+
|
|
|
+def _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}
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ _bif_enable_wait_cursor()
|
|
|
+
|
|
|
+ header = board.get_board_config(board_id).get('header')
|
|
|
+ # TODO: force_read: meaning ignore cache and read new -> in the old gui this was a commandline option
|
|
|
+ # TODO: cache_data: meaning cache already processed numpy data -> in the old gui this was a commandline option
|
|
|
+ if live_plot_windows.hasWindows(board_id):
|
|
|
+ data = read_func(*args, force=False, header=header, cache=False)
|
|
|
+
|
|
|
+ if not io.is_data_consistent(data):
|
|
|
+ callbacks.async_callback('update_consistency', False)
|
|
|
+ global_objects.get_global('statusbar').showMessage(tr("Dialog", "Data is inconsistent!"))
|
|
|
+ if read_func == io.read_from_string:
|
|
|
+ logging.info("Data is inconsistent")
|
|
|
+ else:
|
|
|
+ logging.info("Data is inconsistent - file: " + args[0])
|
|
|
+ else:
|
|
|
+ callbacks.async_callback('update_consistency', True)
|
|
|
+ global_objects.get_global('statusbar').showMessage(tr("Dialog", ""))
|
|
|
+
|
|
|
+ for plotwin in live_plot_windows.getWindows(board_id):
|
|
|
+ plotwin.plot_live(data=data)
|
|
|
+ QtGui.qApp.processEvents()
|
|
|
+ else:
|
|
|
+ callbacks.async_callback('update_consistency', None)
|
|
|
+
|
|
|
+ _bif_disable_wait_cursor()
|
|
|
+
|
|
|
+
|
|
|
+def bk_acquire(board_id):
|
|
|
+ """
|
|
|
+ Toggle Acqisition
|
|
|
+ :param board_id: id of the board do manipulate
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ if not bk_get_config(board_id, 'use_trigger'):
|
|
|
+ if board.get_board_status(board_id).acquisition == True:
|
|
|
+ log(board_id=board_id, additional="Manually Stopped Acquisition\nPerformed Acquisitions: " + str(storage.storage.current_acquisition))
|
|
|
+ _bif_stop_acquisition(board_id)
|
|
|
+ else:
|
|
|
+ _bif_start_acquisition(board_id)
|
|
|
+ else:
|
|
|
+ bk_toggle_wait_on_trigger(board_id)
|
|
|
+
|
|
|
+
|
|
|
+def _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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ board.get_board_status(board_id).acquisition = False
|
|
|
+ storage.get_board_specific_storage(board_id).acquisition_progressbar.remove(0)
|
|
|
+ storage.get_board_specific_storage(board_id).acquisition_timer.stop()
|
|
|
+ # for elem in Elements.getElements("acquireTrigger_{}".format(board_id)):
|
|
|
+ # if isinstance(elem, QtGui.QShortcut) or isinstance(elem, QtGui.QCheckBox):
|
|
|
+ # continue
|
|
|
+ # elem.setIcon(QtGui.QIcon(config.install_path + config.startIcon))
|
|
|
+ # elem.setText(tr("Button", "Start Acquisition"))
|
|
|
+ Elements.setEnabled('acquire_{}'.format(board_id), True)
|
|
|
+ callbacks.callback('acquisition_stopped', board_id)
|
|
|
+
|
|
|
+
|
|
|
+def _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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ log(board_id=board_id, additional="Started Acquisition")
|
|
|
+ board.get_board_status(board_id).acquisition = True
|
|
|
+ Elements.setEnabled('acquire_{}'.format(board_id), False)
|
|
|
+ # for elem in Elements.getElements("acquireTrigger_{}".format(board_id)):
|
|
|
+ # if isinstance(elem, QtGui.QShortcut) or isinstance(elem, QtGui.QCheckBox):
|
|
|
+ # continue
|
|
|
+ # elem.setIcon(QtGui.QIcon(config.install_path + config.stopIcon))
|
|
|
+ # elem.setText(tr("Button", "Stop Acquisition"))
|
|
|
+ callbacks.callback('acquisition_started', board_id)
|
|
|
+ storage.get_board_specific_storage(board_id).acquisition_timer = QtCore.QTimer()
|
|
|
+ num_acquisitions = board.get_board_config(board_id).get("acquisition_count")
|
|
|
+ storage.get_board_specific_storage(board_id).acquisition_progressbar = \
|
|
|
+ _bif_ProgressBar(0, num_acquisitions, tr("sw", "Acquiring with board ")+str(board_id))
|
|
|
+ # storage.storage.acquisition_progressbar = acquisition_progressbar
|
|
|
+
|
|
|
+ # We increase already once because we do a single acquisition before the
|
|
|
+ # timer is started, otherwise we have to wait until the timer fires the
|
|
|
+ # first time.
|
|
|
+ try:
|
|
|
+ if isinstance(storage.storage.current_acquisition, dict):
|
|
|
+ storage.storage.current_acquisition[board_id] = 1
|
|
|
+ else:
|
|
|
+ storage.storage.current_acquisition = {board_id: 1}
|
|
|
+ except storage.StorageError:
|
|
|
+ storage.storage.current_acquisition = {board_id: 1}
|
|
|
+ _bif_read_data_and_save(board_id)
|
|
|
+
|
|
|
+ if board.get_board_config(board_id).get("build_spectrograms"):
|
|
|
+ spectrogram_dir = storage.storage.save_location + '/' + storage.storage.subdirname+"/spectrograms_{:0.3f}".format(time.time())
|
|
|
+ os.makedirs(spectrogram_dir)
|
|
|
+ _bif_iterate_spectrograms(board_id, spectrogram_dir) # TODO: not here?
|
|
|
+
|
|
|
+ storage.get_board_specific_storage(board_id).acquisition_progressbar.setValue(storage.storage.current_acquisition[board_id])
|
|
|
+
|
|
|
+ def on_timeout():
|
|
|
+ '''Handler for the timeout of the acquisition timer. This does the acquisition'''
|
|
|
+ if storage.storage.current_acquisition[board_id] < num_acquisitions:
|
|
|
+ storage.storage.current_acquisition[board_id] += 1
|
|
|
+ storage.get_board_specific_storage(board_id).acquisition_progressbar.setValue(storage.storage.current_acquisition[board_id])
|
|
|
+ _bif_read_data_and_save(board_id)
|
|
|
+ if board.get_board_config(board_id).get("build_spectrograms"):
|
|
|
+ _bif_iterate_spectrograms(board_id, spectrogram_dir) # TODO: not here ?
|
|
|
+ else:
|
|
|
+ log(board_id=board_id, additional="Stopped Acquisition")
|
|
|
+ _bif_stop_acquisition(board_id)
|
|
|
+ storage.get_board_specific_storage(board_id).acquisition_progressbar.remove(0)
|
|
|
+
|
|
|
+ storage.get_board_specific_storage(board_id).acquisition_timer.timeout.connect(on_timeout)
|
|
|
+ storage.get_board_specific_storage(board_id).acquisition_timer.start(board.get_board_config(board_id).get('orbits_wait_time') * 1000)
|
|
|
+
|
|
|
+
|
|
|
+def bk_single_read(board_id):
|
|
|
+ """
|
|
|
+ Perform a single read of data
|
|
|
+ :param board_id: id of the board do manipulate
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ Elements.setEnabled("acquire_{}".format(board_id), False)
|
|
|
+ _bif_read_data_and_save(board_id)
|
|
|
+ log(board_id=board_id, additional="Single Read\nFilename: "+board.get_board_status(board_id).last_file.split('/')[-1])
|
|
|
+ Elements.setEnabled("acquire_{}".format(board_id), True)
|
|
|
+
|
|
|
+
|
|
|
+def _bif_set_continuous_read_active(board_id):
|
|
|
+ """
|
|
|
+ Enable continuous read
|
|
|
+ :param board_id: id of the board do manipulate
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ Elements.setEnabled("acquire_{}".format(board_id), False)
|
|
|
+ Elements.setEnabled("acquireTrigger_{}".format(board_id), False)
|
|
|
+ Elements.setEnabled("continuous_read_{}".format(board_id), True)
|
|
|
+ board.get_board_status(board_id).continuous_read = True
|
|
|
+
|
|
|
+
|
|
|
+def _bif_set_continuous_read_inactive(board_id):
|
|
|
+ """
|
|
|
+ Disable continuous read
|
|
|
+ :param board_id: id of the board do manipulate
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ if board.get_board_status(board_id).continuous_read:
|
|
|
+ board.get_board_status(board_id).continuous_read = False
|
|
|
+ storage.get_board_specific_storage(board_id).continuous_read_timer.stop()
|
|
|
+ Elements.setEnabled('acquire_{}'.format(board_id), True)
|
|
|
+ Elements.setEnabled('acquireTrigger_{}'.format(board_id), True)
|
|
|
+
|
|
|
+
|
|
|
+def 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.
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ if not board.get_board_status(board_id).continuous_read:
|
|
|
+ _bif_set_continuous_read_active(board_id)
|
|
|
+ _bif_continuous_read(board_id, interval)
|
|
|
+ else:
|
|
|
+ _bif_set_continuous_read_inactive(board_id)
|
|
|
+
|
|
|
+
|
|
|
+def _bif_continuous_read(board_id, interval=None):
|
|
|
+ """
|
|
|
+ Perform continuous read based on a timer.
|
|
|
+ :param interval:
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ if interval is not None:
|
|
|
+ # TODO: ueberall checken, dass der board specific storage verwendet wird
|
|
|
+ storage.get_board_specific_storage(board_id).continuous_interval = interval
|
|
|
+ storage.get_board_specific_storage(board_id).continuous_read_timer = QtCore.QTimer()
|
|
|
+ logging.info("Start continuous read")
|
|
|
+
|
|
|
+ def continuous_read_step():
|
|
|
+ if board.get_board_status(board_id).continuous_read:
|
|
|
+ _bif_read_data(board_id)
|
|
|
+ storage.get_board_specific_storage(board_id).continuous_read_timer.singleShot(storage.storage.continuous_interval, continuous_read_step)
|
|
|
+
|
|
|
+ storage.get_board_specific_storage(board_id).continuous_read_timer.singleShot(storage.storage.continuous_interval, continuous_read_step)
|
|
|
+
|
|
|
+
|
|
|
+def _bif_read_data(board_id):
|
|
|
+ """
|
|
|
+ Reads data acquired by board.
|
|
|
+ :param board_id: id of the board do manipulate
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ if board.get_board_config(board_id).get('pilot_bunch'):
|
|
|
+ board.start_pilot_bunch_emulator(board_id)
|
|
|
+
|
|
|
+ board.start_acquisition(board_id)
|
|
|
+ try:
|
|
|
+ board.wait_for_revolutions(board_id)
|
|
|
+ except IndexError:
|
|
|
+ error(0x002, "Unexpected output of pci for number of orbits to observe. Returning")
|
|
|
+ return
|
|
|
+ board.stop_acquisition(board_id)
|
|
|
+ board.enable_transfer(board_id)
|
|
|
+ data_raw = board.pci.read_data_to_variable(board_id)
|
|
|
+ _bif_read_and_update_data_from_string(board_id, data_raw)
|
|
|
+ except board.BoardError as e:
|
|
|
+ logging.error("Reading failed for board {}: {}".format(str(board_id), str(e)))
|
|
|
+
|
|
|
+
|
|
|
+def bk_board_connected(board_id):
|
|
|
+ """
|
|
|
+ Interface to the board to check if it is connected.
|
|
|
+ :param board_id: id of the board do manipulate
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ if not available_boards.has_boards:
|
|
|
+ return False
|
|
|
+ else:
|
|
|
+ return board_id in available_boards.board_ids
|
|
|
+
|
|
|
+
|
|
|
+def bk_get_temperature(board_id):
|
|
|
+ """
|
|
|
+ Get Temperature from board and format it
|
|
|
+ :param board_id: id of the board do manipulate
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ fpga_temp_raw_hex = board.pci.read(board_id, 1, '0x9110')[0]
|
|
|
+ fpga_temp_raw_hex = fpga_temp_raw_hex[-3:]
|
|
|
+ fpga_temp_raw_bin = '{0:012b}'.format(int(fpga_temp_raw_hex, 16))
|
|
|
+ fpga_temp_encoded = board.get_dec_from_bits(fpga_temp_raw_bin, 9, 0)
|
|
|
+ fpga_temp_celsius = '{0:2.2f}'.format(((fpga_temp_encoded * 503.975) / 1024) - 273.15)
|
|
|
+ return fpga_temp_celsius
|
|
|
+
|
|
|
+
|
|
|
+backup_get_temp = bk_get_temperature
|
|
|
+
|
|
|
+
|
|
|
+def bk_time_scan(board_id, c_frm, c_to, f_frm, f_to, ts_pbar, plot_func, orbits_observe=None, orbits_skip=None, bucket_to_use=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)
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ if board.get_board_status(board_id).time_scan:
|
|
|
+ _bif_stop_time_scan(board_id, ts_pbar)
|
|
|
+ else:
|
|
|
+ _bif_start_time_scan(board_id, c_frm, c_to, f_frm, f_to, ts_pbar, plot_func, orbits_observe, orbits_skip, bucket_to_use)
|
|
|
+
|
|
|
+
|
|
|
+def _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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ Elements.getElements("start_time_scan_{}".format(board_id))[0].setText(tr("Button", "Start time scan"))
|
|
|
+ board.get_board_status(board_id).time_scan = False
|
|
|
+ board.get_board_config(board_id).set_delay(storage.storage.th_old[board_id])
|
|
|
+ board.get_board_config(board_id).set_chip_delay(
|
|
|
+ [0, 1, 2, 3],
|
|
|
+ [
|
|
|
+ storage.storage.chip_1_old[board_id],
|
|
|
+ storage.storage.chip_2_old[board_id],
|
|
|
+ storage.storage.chip_3_old[board_id],
|
|
|
+ storage.storage.chip_4_old[board_id]
|
|
|
+ ]
|
|
|
+ )
|
|
|
+ ts_pbar.reset()
|
|
|
+
|
|
|
+
|
|
|
+# tst = None # Ugly but necessary for the thread not to be killed when function ends (which is almost immediately after start)
|
|
|
+# thread_ts = None
|
|
|
+
|
|
|
+
|
|
|
+def _bif_start_time_scan(board_id, c_frm, c_to, f_frm, f_to, timescan_progressbar, plot_func, orbits_observe, orbits_skip, bucket_to_use=None):
|
|
|
+ """
|
|
|
+ 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 timescan progressbar
|
|
|
+ :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 skip for the timescan (original values will be restored after timescan)
|
|
|
+ :param bucket_to_use: Number of the bucket whos data will be used to calculate the average signal at each timescan step (if None all bunches will be used)
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ thread = storage.get_board_specific_storage(board_id).setdefault("TimeScanThread", storage.ThreadStorage())
|
|
|
+ # if thread_ts is not None:
|
|
|
+ # logging.info("Time scan already running")
|
|
|
+ # return
|
|
|
+ if thread.running:
|
|
|
+ logging.info("Time scan already running")
|
|
|
+ return
|
|
|
+
|
|
|
+ board.get_board_status(board_id).time_scan = True
|
|
|
+ Elements.getElements("start_time_scan_{}".format(board_id))[0].setText(tr("Button", "Stop time scan"))
|
|
|
+ if c_frm > c_to:
|
|
|
+ logging.info('Coarse Scan Interval is invalid: (%i > %i)' % (c_frm, c_to))
|
|
|
+ return
|
|
|
+ if f_frm > f_to:
|
|
|
+ logging.info('Fine Scan Interval is invalid: (%i > %i)' % (f_frm, f_to))
|
|
|
+ return
|
|
|
+
|
|
|
+ # the following could be made nicer with the use of setdefault and the use of get_board_specific_storage
|
|
|
+ if not hasattr(storage.storage, 'th_old'):
|
|
|
+ storage.storage.th_old = {}
|
|
|
+ storage.storage.chip_1_old = {}
|
|
|
+ storage.storage.chip_2_old = {}
|
|
|
+ storage.storage.chip_3_old = {}
|
|
|
+ storage.storage.chip_4_old = {}
|
|
|
+
|
|
|
+ storage.storage.th_old[board_id] = board.get_board_config(board_id).get('th_delay')
|
|
|
+ storage.storage.chip_1_old[board_id] = board.get_board_config(board_id).get('chip_1_delay')
|
|
|
+ storage.storage.chip_2_old[board_id] = board.get_board_config(board_id).get('chip_2_delay')
|
|
|
+ storage.storage.chip_3_old[board_id] = board.get_board_config(board_id).get('chip_3_delay')
|
|
|
+ storage.storage.chip_4_old[board_id] = board.get_board_config(board_id).get('chip_4_delay')
|
|
|
+
|
|
|
+ minimum = [None, None, None, None]
|
|
|
+ maximum = np.zeros((4, 3))
|
|
|
+ heatmap = np.zeros((4, (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):
|
|
|
+ '''Timescan Thread class'''
|
|
|
+ pbarSignal = QtCore.pyqtSignal(int)
|
|
|
+ stopSignal = QtCore.pyqtSignal()
|
|
|
+ finished = QtCore.pyqtSignal()
|
|
|
+
|
|
|
+ def __init__(self, c_frm, c_to, f_frm, f_to, timescan_progressbar, bucket_to_use):
|
|
|
+ super(thread_time_scan, self).__init__()
|
|
|
+ self.c_frm = c_frm
|
|
|
+ self.c_to = c_to
|
|
|
+ self.f_frm = f_frm
|
|
|
+ self.f_to = f_to
|
|
|
+ self.timescan_progressbar = timescan_progressbar
|
|
|
+ self.bucket_to_use = bucket_to_use
|
|
|
+
|
|
|
+ def time_scan(self):
|
|
|
+ '''Method to run in the thread that does the timescan'''
|
|
|
+ Elements.setEnabled('acquire_{}'.format(board_id), False, exclude=Elements.getElements('start_time_scan_{}'.format(board_id)))
|
|
|
+ if orbits_observe:
|
|
|
+ if not hasattr(storage.storage, 'orbits_observe_before_timescan'):
|
|
|
+ storage.storage.orbits_observe_before_timescan = {}
|
|
|
+ storage.storage.orbits_observe_before_timescan[board_id] = board.get_board_config(board_id).get("orbits_observe") # save old values to restore after timescan
|
|
|
+ board.get_board_config(board_id).update("orbits_observe", orbits_observe)
|
|
|
+ bk_change_num_of_orbits(board_id, orbits_observe)
|
|
|
+ if orbits_skip is not None:
|
|
|
+ if not hasattr(storage.storage, 'orbits_skip_before_timescan'):
|
|
|
+ storage.storage.orbits_skip_before_timescan = {}
|
|
|
+ storage.storage.orbits_skip_before_timescan[board_id] = board.get_board_config(board_id).get("orbits_skip")
|
|
|
+ board.get_board_config(board_id).update("orbits_skip", orbits_skip)
|
|
|
+ bk_change_num_of_skipped_orbits(board_id, orbits_skip)
|
|
|
+
|
|
|
+ c_step = 0
|
|
|
+ for coarse in range(self.c_frm, self.c_to + 1):
|
|
|
+ try:
|
|
|
+ board.get_board_config(board_id).set_delay(coarse)
|
|
|
+ except board.BoardError as e:
|
|
|
+ self.stopSignal.emit()
|
|
|
+ self.finished.emit()
|
|
|
+ return
|
|
|
+
|
|
|
+ f_step = 0
|
|
|
+ for fine in range(self.f_frm, self.f_to + 1):
|
|
|
+ board.get_board_config(board_id).set_chip_delay([0, 1, 2, 3], [fine, fine, fine, fine])
|
|
|
+
|
|
|
+ try:
|
|
|
+ if bk_get_config(board_id, 'pilot_bunch') is True:
|
|
|
+ board.start_pilot_bunch_emulator(board_id)
|
|
|
+
|
|
|
+ board.start_acquisition(board_id)
|
|
|
+ try:
|
|
|
+ board.wait_for_revolutions(board_id) # Wait before asking for data
|
|
|
+ except IndexError:
|
|
|
+ error(0x002, "Unexpected output of pci for number of orbits to observe. Stopping Timescan")
|
|
|
+ self.stopSignal.emit()
|
|
|
+ return
|
|
|
+ board.stop_acquisition(board_id)
|
|
|
+ board.enable_transfer(board_id)
|
|
|
+
|
|
|
+ # -----------[ IMPORTANT ]---------------------
|
|
|
+ if not kcgw.testing:
|
|
|
+ data_raw = board.pci.read_data_to_variable(board_id)
|
|
|
+ board.flush_dma(board_id)
|
|
|
+ # ----------------------------------------------
|
|
|
+ else:
|
|
|
+ f_name = "{InsertPathToPreAcquiredTimscanDataHere}" + str(
|
|
|
+ coarse) + "_" + str(fine) + ".str"
|
|
|
+ f = open(f_name, 'r')
|
|
|
+ data_raw = f.read()
|
|
|
+
|
|
|
+ # The PCI software not only prints the desired data but also some additional information.
|
|
|
+ # This information has to be removed here.
|
|
|
+ # To do so we split the output string from PCI at "Writting" (Note: Writting is correct as
|
|
|
+ # this is a typo in the PCI driver)
|
|
|
+ data = io.read_from_string(data_raw, force=True, cache=False)
|
|
|
+ except board.BoardError as e:
|
|
|
+ self.stopSignal.emit()
|
|
|
+ self.finished.emit()
|
|
|
+ return
|
|
|
+
|
|
|
+ for adc in range(4):
|
|
|
+ if self.bucket_to_use is None:
|
|
|
+ buckets = data.array[:, adc]
|
|
|
+ else:
|
|
|
+ buckets = data.array[self.bucket_to_use::config.bunches_per_turn, adc]
|
|
|
+ heatmap[adc, f_step, c_step] = float(buckets.sum()) / buckets.shape[0]
|
|
|
+ if heatmap[adc, f_step, c_step] > maximum[adc, 0]:
|
|
|
+ maximum[adc, 0] = heatmap[adc, f_step, c_step]
|
|
|
+ maximum[adc, 1] = coarse
|
|
|
+ maximum[adc, 2] = fine
|
|
|
+ if minimum[adc] is None or minimum[adc] > heatmap[adc, f_step, c_step]:
|
|
|
+ minimum[adc] = heatmap[adc, f_step, c_step]
|
|
|
+
|
|
|
+ self.pbarSignal.emit(((c_step * (f_to - f_frm + 1)) + f_step) + 1)
|
|
|
+
|
|
|
+ #GUI is blocked in our tight loop. Give it an opportunity to handle events
|
|
|
+ # QtGui.QApplication.processEvents() # remove this if moved to thread again
|
|
|
+ if board.get_board_status(board_id).time_scan is False:
|
|
|
+ # Time Scan Stop is already performed by button press. Nothing else to do but leave
|
|
|
+ self.finished.emit()
|
|
|
+ return
|
|
|
+ f_step += 1
|
|
|
+ c_step += 1
|
|
|
+ self.finished.emit()
|
|
|
+
|
|
|
+ def finished(timescan_progressbar):
|
|
|
+ '''Method to handle the end of the thread'''
|
|
|
+ thread.stop()
|
|
|
+ _bif_stop_time_scan(board_id, timescan_progressbar)
|
|
|
+ Elements.setEnabled('acquire_{}'.format(board_id), True, exclude=Elements.getElements('start_time_scan_{}'.format(board_id)))
|
|
|
+ if orbits_observe:
|
|
|
+ board.get_board_config(board_id).update("orbits_observe", storage.storage.orbits_observe_before_timescan[board_id]) # restore values
|
|
|
+ bk_change_num_of_orbits(board_id, storage.storage.orbits_observe_before_timescan[board_id])
|
|
|
+ if orbits_skip:
|
|
|
+ board.get_board_config(board_id).update("orbits_skip", storage.storage.orbits_skip_before_timescan[board_id])
|
|
|
+ bk_change_num_of_skipped_orbits(board_id, storage.storage.orbits_skip_before_timescan[board_id])
|
|
|
+ board.get_board_config(board_id).set_delay(storage.storage.th_old[board_id])
|
|
|
+
|
|
|
+ board.get_board_config(board_id).set_chip_delay(
|
|
|
+ [0, 1, 2, 3],
|
|
|
+ [
|
|
|
+ storage.storage.chip_1_old[board_id],
|
|
|
+ storage.storage.chip_2_old[board_id],
|
|
|
+ storage.storage.chip_3_old[board_id],
|
|
|
+ storage.storage.chip_4_old[board_id]
|
|
|
+ ]
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+ m = [np.min(heatmap[heatmap != 0]), np.max(heatmap)] # this gives the same levels for all 4 adcs
|
|
|
+ plot_func(heatmap, levels=m, ranges=[c_frm,c_to,f_frm,f_to], newTitle=str(tr("sw", "Coarserange:{c_f}-{c_t} ; Finerange:{f_f}-{f_t}")).format(
|
|
|
+ c_f=c_frm,
|
|
|
+ c_t=c_to,
|
|
|
+ f_f=f_frm,
|
|
|
+ f_t=f_to),
|
|
|
+ maxima=maximum
|
|
|
+ )
|
|
|
+
|
|
|
+ now = time.time()
|
|
|
+ if not os.path.isdir(str(storage.storage.save_location + '/' + storage.storage.subdirname + '/timescan')):
|
|
|
+ os.makedirs((storage.storage.save_location + '/' + storage.storage.subdirname + '/timescan'))
|
|
|
+ filename = storage.storage.save_location + '/' + storage.storage.subdirname + '/timescan/timescan_{:0.3f}.out'.format(
|
|
|
+ now)
|
|
|
+ f = open(filename, 'wr')
|
|
|
+
|
|
|
+ for adc in range(4):
|
|
|
+ f.write("#ADC_%s\n" % adc)
|
|
|
+ for coarse, curr_cor in enumerate(np.transpose(heatmap[adc])):
|
|
|
+ for fine, value in enumerate(curr_cor):
|
|
|
+ f.write("%i;%i;%f\n" % ((coarse + c_frm), (fine + f_frm), value))
|
|
|
+ f.write('\n')
|
|
|
+
|
|
|
+ f.close()
|
|
|
+ f = open(filename + '.gnuplot', 'wr')
|
|
|
+ f.write('set datafile separator ";"\n')
|
|
|
+ f.write('set multiplot layout 2,2\n')
|
|
|
+ f.write('unset key\n')
|
|
|
+ for i in range(4):
|
|
|
+ f.write('set label 1 "ADC_%i" at graph 0.7,0.95 font ",8"\n' % (i + 1))
|
|
|
+ f.write('plot "%s" every :::%i::%i using 3 with lines\n' % (filename, i, i))
|
|
|
+ f.write('unset multiplot\n')
|
|
|
+ f.close()
|
|
|
+
|
|
|
+ return
|
|
|
+
|
|
|
+ tst = thread_time_scan(c_frm, c_to, f_frm, f_to, timescan_progressbar, bucket_to_use)
|
|
|
+ thread.register(tst)
|
|
|
+ thread.connect('pbarSignal', timescan_progressbar.setValue)
|
|
|
+ thread.connect('finished', lambda: finished(timescan_progressbar))
|
|
|
+ thread.connect('stopSignal', lambda: _bif_stop_time_scan(board_id, timescan_progressbar))
|
|
|
+ thread.start('time_scan')
|
|
|
+
|
|
|
+
|
|
|
+def 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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ # global bk_status_readout, bk_get_temperature
|
|
|
+ board_status = bk_board_connected(board_id)
|
|
|
+ if board_status:
|
|
|
+ if not hasattr(board.get_board_status(board_id), 'board_connected') or \
|
|
|
+ not board.get_board_status(board_id).board_connected:
|
|
|
+ globals()['bk_status_readout'] = backup_readout
|
|
|
+ globals()['bk_get_temperature'] = backup_get_temp
|
|
|
+ board.get_board_status(board_id).board_connected = True
|
|
|
+
|
|
|
+ else:
|
|
|
+ Elements.setEnabled('no_board_{}'.format(board_id), False)
|
|
|
+
|
|
|
+ def do_nothing():
|
|
|
+ pass
|
|
|
+
|
|
|
+ def no_temp(board_id):
|
|
|
+ return "-"
|
|
|
+
|
|
|
+ globals()['bk_status_readout'] = do_nothing
|
|
|
+ globals()['bk_get_temperature'] = no_temp
|
|
|
+ board.get_board_status(board_id).board_connected = False
|
|
|
+ if board_status == False:
|
|
|
+ board.get_board_status(board_id).status_text = tr("sw", "Board {} not connected".format(board_id))
|
|
|
+ elif board_status == None:
|
|
|
+ board.get_board_status(board_id).status_text = tr("sw", "Software Interface not found")
|
|
|
+
|
|
|
+
|
|
|
+def 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
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ thread = storage.get_board_specific_storage(board_id).setdefault('TriggerThread', storage.ThreadStorage())
|
|
|
+ if thread.running:
|
|
|
+ Elements.getElements("acquireTrigger_{}".format(board_id))[0].setText(tr("Button", "Stopping Acquisition"))
|
|
|
+ # FIXME: Button not updated otherwise:
|
|
|
+ QtGui.qApp.processEvents()
|
|
|
+ log(board_id=board_id, additional="Stop wait on trigger on board {}".format(board_id))
|
|
|
+ thread.quit()
|
|
|
+ thread.stop()
|
|
|
+ # for elem in Elements.getElements("acquire_{}".format(board_id)):
|
|
|
+ # if isinstance(elem, QtGui.QShortcut):
|
|
|
+ # continue
|
|
|
+ # elem.setText(tr("Button", "Stopping Acquisition"))
|
|
|
+ # elem.setEnabled(False)
|
|
|
+ else:
|
|
|
+ log(board_id=board_id, additional="Start wait on trigger on board {}".format(board_id))
|
|
|
+ # for elem in Elements.getElements("acquireTrigger_{}".format(board_id)):
|
|
|
+ # if isinstance(elem, QtGui.QShortcut):
|
|
|
+ # continue
|
|
|
+ # elem.setIcon(QtGui.QIcon(config.install_path + config.stopIcon))
|
|
|
+ # elem.setText(tr("Button", "Stop Acquisition"))
|
|
|
+ Elements.setEnabled('acquire_{}'.format(board_id), False)
|
|
|
+ callbacks.callback('acquisition_started', board_id)
|
|
|
+ _bif_start_wait_on_trigger(board_id, num_of_acquisitions, skip, timeout, method)
|
|
|
+
|
|
|
+
|
|
|
+def _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
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+
|
|
|
+ # FIXme: This is a work around, for method 2 to work everytime a standard single read needs to be perform before acquisition is started
|
|
|
+ board.acquire_data(board_id, '/dev/null')
|
|
|
+ #with workaround no flush dema need, because it is done at end of board.acquire_data() anyway.
|
|
|
+ #board.flush_dma(board_id) # TODO: really at begining and end of function necessary?
|
|
|
+ thread = storage.get_board_specific_storage(board_id).setdefault('TriggerThread', storage.ThreadStorage())
|
|
|
+ if thread.running:
|
|
|
+ logging.info("Wait already running on board {}".format(board_id))
|
|
|
+ return
|
|
|
+ log(board_id=board_id, additional="Start wait on trigger")
|
|
|
+ board.get_board_status(board_id).wait_on_trigger = True
|
|
|
+ if not os.path.isdir(str(storage.storage.save_location + '/' + storage.storage.subdirname)):
|
|
|
+ os.makedirs(str(storage.storage.save_location + '/' + storage.storage.subdirname))
|
|
|
+
|
|
|
+ if not num_of_acquisitions:
|
|
|
+ num_of_acquisitions = bk_get_config(board_id, 'acquisition_count')
|
|
|
+ if not skip:
|
|
|
+ skip = bk_get_config(board_id, 'trigger_skip')
|
|
|
+ if not timeout:
|
|
|
+ timeout = bk_get_config(board_id, 'trigger_timeout')
|
|
|
+ if not method:
|
|
|
+ method = bk_get_config(board_id, 'trigger_method')
|
|
|
+
|
|
|
+ storage.get_board_specific_storage(board_id).trigger_progressbar = \
|
|
|
+ _bif_ProgressBar(0, num_of_acquisitions, tr("sw", "Acquiring with board ")+str(board_id))
|
|
|
+ board.pci.write(board_id, hex(num_of_acquisitions), "9024")
|
|
|
+ time.sleep(0.1)
|
|
|
+ board.pci.write(board_id, hex(skip), "902C")
|
|
|
+ # time.sleep(0.1)
|
|
|
+ # board.pci.write(board_id, 'ff0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
|
|
|
+
|
|
|
+ # 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
|
|
|
+ # I don't have an idea why it crashes.
|
|
|
+ # A possible reason could the os.rename be (or even the board.safe_call as that saves data to the disk) But I think
|
|
|
+ # this is rather unlikely
|
|
|
+ # ~~NOTE~~: the thread of calibration also triggered segfaults sometimes. But this seems to be miraculously solved.
|
|
|
+ # Something that is likely to cause the problem is the log.debug in board.safe_call
|
|
|
+ # Logging (using the logging module) is directly connected to the main thread and could cause problems
|
|
|
+ class thread_wait_on_signal(QtCore.QObject):
|
|
|
+ '''Class to run the wait on signal functionality in a thread'''
|
|
|
+ countUpdate = QtCore.pyqtSignal(int)
|
|
|
+ stopSignal = QtCore.pyqtSignal()
|
|
|
+ finished = QtCore.pyqtSignal()
|
|
|
+ liveplot = QtCore.pyqtSignal(int, str) # This has to be changed if board_id is no integer
|
|
|
+
|
|
|
+ def __init__(self):
|
|
|
+ super(thread_wait_on_signal, self).__init__()
|
|
|
+ self.noa = None
|
|
|
+ self.path = None
|
|
|
+ self.timeout = None
|
|
|
+ self._quit = False
|
|
|
+
|
|
|
+ def init(self, num_of_acquisitions, path, timeout):
|
|
|
+ '''initialise a new run'''
|
|
|
+ self.noa = num_of_acquisitions
|
|
|
+ self.path = path
|
|
|
+ self.timeout = timeout
|
|
|
+ self._quit = False
|
|
|
+
|
|
|
+ # Elements.setEnabled('acquireTrigger_{}'.format(board_id), False) # exclude=Elements.getElements('wait_on_trigger_{}'.format(board_id)))
|
|
|
+
|
|
|
+ def wait_rw_simul(self): # Method 1
|
|
|
+ '''Wait simultaniously (with the pci command) for a trigger signal'''
|
|
|
+ board.pci.write(board_id, 'ff0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
|
|
|
+ for num_of_acq in xrange(self.noa):
|
|
|
+ # def step():
|
|
|
+ if self._quit:
|
|
|
+ break
|
|
|
+ filename = self.path +'/{:0.3f}.out'.format(time.time())
|
|
|
+ board.pci.read_data_to_file(board_id, filename=filename, timeout=(self.timeout*1000000))
|
|
|
+ # rename with correct timestamp - last modified time
|
|
|
+ self.countUpdate.emit(num_of_acq + 1)
|
|
|
+
|
|
|
+ # file operations
|
|
|
+ if not os.path.isfile(filename):
|
|
|
+ error(0x001, "No File Created")
|
|
|
+ continue
|
|
|
+
|
|
|
+ newfile = '{path}/trigger_{num:05}_{htime}_{unixtime}.out'.format(
|
|
|
+ num=num_of_acq,
|
|
|
+ htime=dt.fromtimestamp(os.path.getmtime(filename)).strftime('%Y-%m-%dT%Hh%Mm%Ss%f'),
|
|
|
+ unixtime=int(os.path.getmtime(filename)),
|
|
|
+ path=self.path
|
|
|
+ )
|
|
|
+ os.rename(filename, newfile)
|
|
|
+ if os.path.getsize(newfile) > 0:
|
|
|
+ self.liveplot.emit(board_id, newfile)
|
|
|
+ else:
|
|
|
+ logging.info("Acquired 0b, possible trigger timeout.")
|
|
|
+
|
|
|
+ self.finished.emit()
|
|
|
+
|
|
|
+ def wait_rw_seq(self): # Method 2
|
|
|
+ '''Wait sequentially (in the gui) for a trigger signal'''
|
|
|
+ for num_of_acq in xrange(self.noa):
|
|
|
+ board.pci.write(board_id, '00bf0', hex_mask='CF0') # enable readout
|
|
|
+ pre_acq_num = board.pci.read(board_id, 1, '9034')[0]
|
|
|
+ time_a = time.time()
|
|
|
+ timeout = False
|
|
|
+ while pre_acq_num == board.pci.read(board_id, 1, '9034')[0]:
|
|
|
+ if time.time() - time_a > self.timeout:
|
|
|
+ timeout = True
|
|
|
+ break
|
|
|
+ if self._quit:
|
|
|
+ self.finished.emit()
|
|
|
+ return
|
|
|
+ if not timeout:
|
|
|
+ board.pci.write(board_id, '000f0', hex_mask='8F0') # disable readout
|
|
|
+ board.pci.write(board_id, '007f0', hex_mask='CF0') # enable transfer
|
|
|
+ filename = self.path +'/{:0.3f}.out'.format(time.time())
|
|
|
+ board.pci.read_data_to_file(board_id, filename=filename, timeout=(self.timeout*1000000))
|
|
|
+ # board.pci.write(board_id, '000f0', hex_mask='4F0') # disable transfer
|
|
|
+ self.countUpdate.emit(copy.deepcopy(num_of_acq+1))
|
|
|
+ if self._quit: # is this really the correct position? file is taken but not renamed!
|
|
|
+ self.finished.emit()
|
|
|
+ break
|
|
|
+
|
|
|
+ if not os.path.isfile(filename):
|
|
|
+ error(0x001, "No File Created")
|
|
|
+ continue
|
|
|
+
|
|
|
+ newfile = '{path}/trigger_{num:05}_{htime}_{unixtime}.out'.format(
|
|
|
+ num=num_of_acq,
|
|
|
+ htime=dt.fromtimestamp(os.path.getmtime(filename)).strftime('%Y-%m-%dT%Hh%Mm%Ss%f'),
|
|
|
+ unixtime=int(os.path.getmtime(filename)),
|
|
|
+ path=self.path
|
|
|
+ )
|
|
|
+ os.rename(filename, newfile)
|
|
|
+ self.liveplot.emit(board_id, newfile)
|
|
|
+ else:
|
|
|
+ logging.info("Trigger timeout.")
|
|
|
+
|
|
|
+
|
|
|
+ self.finished.emit()
|
|
|
+
|
|
|
+ def quit(self):
|
|
|
+ '''quit this thread'''
|
|
|
+ self._quit = True
|
|
|
+
|
|
|
+ def __del__(self):
|
|
|
+ print ('quite')
|
|
|
+ board.pci.write(board_id, '0', '9024')
|
|
|
+ time.sleep(0.1)
|
|
|
+ board.pci.write(board_id, '0', '902C')
|
|
|
+ time.sleep(0.1)
|
|
|
+ board.pci.write(board_id, '3f0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
|
|
|
+ board.flush_dma(board_id)
|
|
|
+
|
|
|
+ def finished():
|
|
|
+ '''Handle the end of the thread'''
|
|
|
+ board.pci.write(board_id, '0', '9024')
|
|
|
+ time.sleep(0.1)
|
|
|
+ board.pci.write(board_id, '0', '902C')
|
|
|
+ time.sleep(0.1)
|
|
|
+ board.pci.write(board_id, '3f0', hex_mask='ff0') # TODO: This writes t/h 3/4 but enable_transfer etc do not
|
|
|
+ board.flush_dma(board_id)
|
|
|
+
|
|
|
+ thread.stop()
|
|
|
+ board.get_board_status(board_id).wait_on_trigger = False
|
|
|
+ storage.get_board_specific_storage(board_id).trigger_progressbar.remove(0)
|
|
|
+ log(board_id=board_id, additional="Stop wait on trigger")
|
|
|
+ Elements.setEnabled('acquire_{}'.format(board_id), True)
|
|
|
+ callbacks.callback('acquisition_stopped', board_id)
|
|
|
+
|
|
|
+ # for elem in Elements.getElements("acquire_{}".format(board_id)):
|
|
|
+ # if isinstance(elem, QtGui.QShortcut):
|
|
|
+ # continue
|
|
|
+ # elem.setIcon(QtGui.QIcon(config.install_path + config.startIcon))
|
|
|
+ # elem.setText(tr("Button", "Start Acquisition"))
|
|
|
+ # elem.setEnabled(True)
|
|
|
+
|
|
|
+ return
|
|
|
+
|
|
|
+ # twt = thread_wait_on_signal(num_of_acquisitions, storage.storage.save_location + '/' + storage.storage.subdirname,
|
|
|
+ # timeout)
|
|
|
+ if not thread.is_registered():
|
|
|
+ twt = thread_wait_on_signal()
|
|
|
+ thread.register(twt)
|
|
|
+ else:
|
|
|
+ thread.disconnect('countUpdate', 'finished', 'liveplot')
|
|
|
+ thread.init(num_of_acquisitions, storage.storage.save_location + '/' + storage.storage.subdirname, timeout)
|
|
|
+ # reconnect signals to make sure the correct versions of methods are called
|
|
|
+ thread.connect('countUpdate', storage.get_board_specific_storage(board_id).trigger_progressbar.setValue)
|
|
|
+ thread.connect('finished', finished)
|
|
|
+ thread.connect('liveplot', _bif_read_and_update_data_from_file)
|
|
|
+ if method == 1:
|
|
|
+ thread.start('wait_rw_simul')
|
|
|
+ elif method == 2:
|
|
|
+ thread.start('wait_rw_seq')
|
|
|
+ else:
|
|
|
+ raise ValueError("Wrong method")
|