1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093 |
- """
- 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
- import shutil
- from PyQt4 import QtGui, QtCore
- import numpy as np
- from .backend import board
- from .backend.board import available_boards
- from .backend.DataSet import DataSet
- from .backend.CalibrationHandle import theCalibration
- from .groupedelements import Buttons, Elements, live_plot_windows, cuda_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
- from time import sleep
- tr = kcgw.tr
- livePlotData = None
- PRINTDEBUG = False
- 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 = kcgw.PopupDialog(tr("Dialog", "Continuous read is currently active!\nStop continuous read and proceed?"),
- title=popup_title_text)
- else:
- popup = kcgw.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 _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()
- def bk_run_sequence(board_id, name):
- print("________________bk_run_sequence__________________________________________")
- log(board_id=board_id, additional=str(name))
- comment = board.get_board_config(board_id).get_sequence_comment(name)
-
- _bif_enable_wait_cursor()
- if _bif_continuous_read_is_enabled(board_id, tr("Button", "Calibrate Board")):
- _bif_disable_wait_cursor()
- return
- def fin():
- bk_status_readout()
- progressbar.remove(0)
- _bif_disable_wait_cursor()
- board.get_board_config(board_id).update('header', board.get_board_config(board_id)._config['header'])
- board.get_board_config(board_id).update('pilot_bunch', board.get_board_config(board_id)._config['pilot_bunch'])
- progressbar = _bif_ProgressBar(0, 10, tr("sw", comment))
- logging.info('Started ' + comment)
- try:
- if not board.get_board_config(board_id).run_sequence(name, progressbar):
- logging.error(comment + " failed")
- fin()
- return
-
- statval = board.get_board_config(board_id).get_sequence_status(name)
- if statval == "calibrated": board.get_board_status(board_id).calibrated = True
- elif statval == "synced": board.get_board_status(board_id).synced = True
- elif statval == "PLL500M": board.get_board_config(board_id).update('samplingrate', 1)
- elif statval == "PLL1G": board.get_board_config(board_id).update('samplingrate', 2)
- except board.BoardError as e:
- logging.error(comment + " failed: {}".format(str(e)))
- fin()
- return
-
- logging.info(comment + " successful!")
- fin()
- 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
-
- if defaults:
- board.get_board_config(board_id)._set_defaults()
- logging.info("Setting default Values")
- else:
- logging.info("Updating Values")
- try:
- board.get_board_config(board_id).notify_all_observers(write=True)
- except board.BoardError as e:
- logging.error("Updating Values failed: {}".format(str(e)))
- _bif_disable_wait_cursor()
- bk_status_readout()
- return
- board.get_board_status(board_id).defaults_set = True
-
- if defaults:
- logging.info("Default values set successfully!")
- else:
- logging.info("Updated values successfully!")
- _bif_disable_wait_cursor()
- bk_status_readout()
-
- 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)
- #print(key, value)
- except board.BoardError as e:
- logging.error("Setting value of {} failed: {}".format(key, str(e)))
- def bk_get_config(board_id, key,entry=None):
- """
- 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
- """
- if entry == None:
- return board.get_board_config(board_id).get(key)
- else:
- return board.get_board_config(board_id).get(key)[entry]
- 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_change_num_of_turns(board_id, value, silent=False):
- """
- Send new number of turns 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, "turns_observe", value, silent=silent)
- def bk_change_num_of_skipped_turns(board_id, value, silent=False):
- """
- Send new number of turns 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, "turns_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, "turns_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_update_working_dir():
- """
- make Shure the currently set directory exists and a calibration File is present
- """
- path = str(os.path.join(storage.storage.save_location, storage.storage.subdirname))
- print(path)
- if not os.path.isdir(path):
- os.makedirs(path)
- shutil.copy(config.config_path("calibration.hdf"), path)
- theCalibration.openFile(os.path.join(path,'calibration.hdf'))
- return path
- 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: -
- """
- #print('_bif_iterate_spectrograms')
- 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("turns_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:
- """
- if PRINTDEBUG: print(time.time(), '_bif_read_data_and_save start')
- now = time.time()
- _bif_update_working_dir()
- filename = os.path.join(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:
- if PRINTDEBUG: print(time.time(), '_bif_read_data_and_save acquire_data')
- 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 turns 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)))
- if PRINTDEBUG: print(time.time(), '_bif_read_data_and_save stop')
- 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: -
- """
- if kcgw.testing:
- filename = os.path.join(storage.storage.save_location, storage.storage.subdirname,'testing.out')
- _bif_read_and_update(board_id, 1, 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, 0, raw_data)
- def _bif_read_and_update(board_id, read_type, dataOrName):
- """
- 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_type: 0 - from String; 1 - from File
- :param dataOrName: filename or raw_data
- :return: -
- """
- if PRINTDEBUG: print(time.time(), '_bif_read_and_update start')
- _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
- delays = {'c330':board.get_board_config(board_id).get('delay_330_th'), 'c25':board.get_board_config(board_id).get('delay_25_th'),
- 'c25b':board.get_board_config(board_id).get('delay_25_th_2'), 'f':board.get_board_config(board_id).get('chip_delay')}
- if read_type == 0:
- data = DataSet(stringData=dataOrName, delays=delays, tRev=config.tRev, bunchesPerTurn=config.bunches_per_turn, shiftFMC2=config.shiftFMC2)
- else:
- data = DataSet(filename=dataOrName, delays=delays, tRev=config.tRev, bunchesPerTurn=config.bunches_per_turn, shiftFMC2=config.shiftFMC2)
- board.get_board_config(board_id).update('lastDataSet', data)
- QtGui.qApp.processEvents()
- _bif_disable_wait_cursor()
- if PRINTDEBUG: print(time.time(), '_bif_read_and_update stop')
- 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 = os.path.join(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)
- log(board_id=board_id, additional="Acquisition {:3d}\n".format(storage.storage.current_acquisition[board_id]) + "Filename: "+board.get_board_status(board_id).last_file.split('/')[-1])
- 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('turns_wait_time') * 1000)
- def bk_single_read(board_id, info=""):
- """
- Perform a single read of data
- :param board_id: id of the board do manipulate
- :return:
- """
- if info != "":
- info += "\n"
- Elements.setEnabled("acquire_{}".format(board_id), False)
- _bif_read_data_and_save(board_id)
- log(board_id=board_id, additional="Single Read\n" + info + "Filename: "+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("acquireTrigger_{}".format(board_id), False)
- Elements.setEnabled("continuous_read_{}".format(board_id), False)
- 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('continuous_read_{}'.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, returnBack=False):
- """
- Reads data acquired by board.
- :param board_id: id of the board do manipulate
- :return:
- """
- board.pci.start = time.time()
- if PRINTDEBUG: print('{:4.3f} _bif_read_data start'.format(time.time()-board.pci.start))
- 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 turns to observe. Returning")
- return None
- board.stop_acquisition(board_id)
- board.enable_transfer(board_id)
- if PRINTDEBUG: print('{:4.3f} _bif_read_data.read_data_to_variable'.format(time.time()-board.pci.start))
- data_raw = board.pci.read_data_to_variable(board_id)
- if PRINTDEBUG: print('{:4.3f} _bif_read_data.read_data_to_variable done'.format(time.time()-board.pci.start))
-
- if returnBack:
- if PRINTDEBUG: print('{:4.3f} _bif_read_data return data_raw'.format(time.time()-board.pci.start))
- return data_raw
- else:
- if PRINTDEBUG: print('{:4.3f} _bif_read_data call'.format(time.time()-board.pci.start))
- _bif_read_and_update_data_from_string(board_id, data_raw)
- if PRINTDEBUG: print('{:4.3f} _bif_read_data call done'.format(time.time()-board.pci.start))
- except board.BoardError as e:
- logging.error("Reading failed for board {}: {}".format(str(board_id), str(e)))
- if PRINTDEBUG: print('{:4.3f} _bif_read_data return None'.format(time.time()-board.pci.start))
- return None
- 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_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
- _bif_update_working_dir()
- 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'''
- if board.get_board_config(board_id).is_KAPTURE2():
- board.pci.write(board_id, 'f00', hex_mask='f00') # TODO: This writes t/h 3/4 but enable_transfer etc do not
- else:
- 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
- timestamp = time.time()
- filename = os.path.join(self.path, '{:0.3f}.out'.format(timestamp))
- 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 = os.path.join(self.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=np.round(timestamp, 3)
- ))
- os.rename(filename, newfile)
- if os.path.getsize(newfile) > 0:
- self.liveplot.emit(board_id, newfile)
- log(board_id=board_id, additional="Acquisition {:3d}\n".format(num_of_acq) + "Filename: " + newfile.split('/')[-1])
- 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):
- if board.get_board_config(board_id).is_KAPTURE2():
- board.pci.write(board_id, '00b00', hex_mask='C00') # enable readout
- else:
- 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:
- if board.get_board_config(board_id).is_KAPTURE2():
- board.pci.write(board_id, '00000', hex_mask='800') # disable readout
- board.pci.write(board_id, '00700', hex_mask='C00') # enable transfer
- else:
- board.pci.write(board_id, '000f0', hex_mask='8F0') # disable readout
- board.pci.write(board_id, '007f0', hex_mask='CF0') # enable transfer
- filename = os.path.join(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 = os.path.join(self.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))
- ))
- 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):
- board.pci.write(board_id, '0', '9024')
- time.sleep(0.1)
- board.pci.write(board_id, '0', '902C')
- time.sleep(0.1)
- if board.get_board_config(board_id).is_KAPTURE2():
- board.pci.write(board_id, '300', hex_mask='f00') # TODO: This writes t/h 3/4 but enable_transfer etc do not
- else:
- 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)
- if board.get_board_config(board_id).is_KAPTURE2():
- board.pci.write(board_id, '300', hex_mask='f00') # TODO: This writes t/h 3/4 but enable_transfer etc do not
- else:
- 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, os.path.join(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")
|