|
@@ -1,878 +1,878 @@
|
|
|
-"""
|
|
|
-Configuration for each board
|
|
|
-"""
|
|
|
-
|
|
|
-import os
|
|
|
-import sys
|
|
|
-if sys.version_info[:3] < (3,0):
|
|
|
- import ConfigParser as configparser
|
|
|
-else:
|
|
|
- import configparser
|
|
|
-import numpy as np
|
|
|
-import logging
|
|
|
-from PyQt4 import QtGui, QtCore
|
|
|
-from time import sleep
|
|
|
-
|
|
|
-from .communication import *
|
|
|
-from .... import config as kcg_config
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-class BoardConfiguration(QtGui.QWidget):
|
|
|
- """
|
|
|
- The Main configuration class for boards.
|
|
|
- """
|
|
|
- callback_signal = QtCore.pyqtSignal(str, list)
|
|
|
-
|
|
|
- def __init__(self, identifier, config_file=None):
|
|
|
- from . import sequences
|
|
|
- super(BoardConfiguration, self).__init__()
|
|
|
- self.callback_signal.connect(self._notify_observers_receiver)
|
|
|
- self.identifier = identifier
|
|
|
- self._config = {}
|
|
|
- self._observers = {}
|
|
|
- self._observers_for_all = []
|
|
|
- self._observers_write = {}
|
|
|
- self._set_defaults()
|
|
|
- self._get_board_version()
|
|
|
- if self._config['board_version'] > 10:
|
|
|
- logging.critical('Unknown Board Version - gui not working! - restart with active board')
|
|
|
- print('Unknown Board Version - gui not working! - restart with active board')
|
|
|
- else:
|
|
|
- logging.info('Detected Board Version: {}'.format(self._config["board_version"]))
|
|
|
- print('Detected Board Version: {}'.format(self._config["board_version"]))
|
|
|
-
|
|
|
- self._sequences = sequences.read_sequence(self._config["board_version"])
|
|
|
- self.set_default_observers()
|
|
|
-
|
|
|
- if self.is_KAPTURE2():
|
|
|
- self.update('bunches_per_turn', kcg_config.bunches_per_turn)
|
|
|
- else:
|
|
|
- self._config['delay_330_factor'] = 150
|
|
|
- self._config['delay_330_max'] = 15
|
|
|
- self._config['chip_delay'] = [3,3,3,3]
|
|
|
-
|
|
|
- if config_file:
|
|
|
- self.load_config(config_file)
|
|
|
-
|
|
|
- #self.notify_all_observers(True)
|
|
|
-
|
|
|
- def _set_defaults(self):
|
|
|
- """
|
|
|
- Set default values
|
|
|
- """
|
|
|
- self._config = {
|
|
|
- 'board_version' : 7,
|
|
|
- 'lastDataSet': None,
|
|
|
-
|
|
|
- 'adc_number': 8,
|
|
|
- 'samplingrate': 1,
|
|
|
-
|
|
|
- 'bunches_per_turn': 184,
|
|
|
- 'header_byte_size': 32,
|
|
|
-
|
|
|
- 'chip_delay_max': 31,
|
|
|
- 'chip_delay' : [0,0,0,0,0,0,0,0],
|
|
|
- 'bunch_shift' : [2,2,2,2,2,2,2,2], #Offset by +2 to encode -2 to +2 range
|
|
|
- 'chip_delay_factor': 3,
|
|
|
-
|
|
|
-
|
|
|
- 'delay_330_max': 20, #technical 522 #be aware: changing this makes the Delay Calibration invalid!
|
|
|
- 'delay_330_factor': 330,
|
|
|
- 'delay_330_th': 0,
|
|
|
- 'delay_330_adc': 1,
|
|
|
- 'delay_330_fpga': 1,
|
|
|
-
|
|
|
- #-Kapture 2 only--------------------
|
|
|
- 'delay_25_max' : 23, #be aware: changing this makes the Delay Calibration invalid!
|
|
|
- 'delay_25_factor': 25,
|
|
|
- 'delay_25_th': 0,
|
|
|
- 'delay_25_adc': 10,
|
|
|
- 'delay_25_fpga': 0,
|
|
|
-
|
|
|
- #-Second FMC------------------
|
|
|
- 'delay_330_th_2': 0,
|
|
|
- 'delay_330_adc_2': 1,
|
|
|
- #'delay_330_fpga_2': 0,
|
|
|
- 'delay_25_th_2': 4,
|
|
|
- 'delay_25_adc_2': 10,
|
|
|
- #'delay_25_fpga_2': 0,
|
|
|
- 'default_25_th_2': 4,
|
|
|
-
|
|
|
- 'delay_cascade_max': 20,
|
|
|
- 'delay_cascade_factor': 330,
|
|
|
- 'delay_cascade': 0,
|
|
|
- 'delay_cascade_25': 14,
|
|
|
-
|
|
|
- #-Clock Division--------------
|
|
|
- 'clk_div': 6,
|
|
|
- 'clk_div_th': 6,
|
|
|
- 'clk_div_adc': 6,
|
|
|
- 'clk_div_fpga': 6,
|
|
|
- 'clk_div_cascade': 24,
|
|
|
-
|
|
|
- #-Kapture 1 only-------------------
|
|
|
- 'th_to_adc_cycles': 7,
|
|
|
- #'adc_1_delay_individual': -1,
|
|
|
- #----------------------------------
|
|
|
-
|
|
|
- 'turns_observe': 1000,
|
|
|
- 'turns_skip': 0,
|
|
|
- 'acquisition_count': 10,
|
|
|
- 'turns_wait_time': 15,
|
|
|
-
|
|
|
- 'trigger_skip': 0,
|
|
|
- 'trigger_timeout': 12,
|
|
|
- 'trigger_method': 1,
|
|
|
- 'use_trigger': False,
|
|
|
-
|
|
|
- 'build_spectrograms': False,
|
|
|
- 'pilot_bunch': True,
|
|
|
- 'header': True if kcg_config.save_header is True else False,
|
|
|
-
|
|
|
- #Kapture 2
|
|
|
- 'adc_offset': [0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000],
|
|
|
- 'adc_gain': [0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000]
|
|
|
- }
|
|
|
-
|
|
|
- def _get_board_version(self):
|
|
|
- try:
|
|
|
- self._config["board_version"] = int(pci.read(self.identifier, reg='0x9030')[0])
|
|
|
- if self._config["board_version"] == 6:
|
|
|
- self._config["board_version"] = 5
|
|
|
- elif self._config["board_version"] == 7:
|
|
|
- self._config["adc_number"] = 8
|
|
|
-
|
|
|
- except Exception as e:
|
|
|
- self._config["board_version"] = 0xDEAD
|
|
|
-
|
|
|
-
|
|
|
- def is_KAPTURE2(self):
|
|
|
- return self._config["board_version"] >4
|
|
|
-
|
|
|
- ##########################################################################
|
|
|
- # .d8888b.
|
|
|
- # d88P Y88b
|
|
|
- # Y88b.
|
|
|
- # "Y888b. .d88b. .d88888888 888 .d88b. 88888b. .d8888b .d88b.
|
|
|
- # "Y88b.d8P Y8bd88" 888888 888d8P Y8b888 "88bd88P" d8P Y8b
|
|
|
- # "88888888888888 888888 88888888888888 888888 88888888
|
|
|
- # Y88b d88PY8b. Y88b 888Y88b 888Y8b. 888 888Y88b. Y8b.
|
|
|
- # "Y8888P" "Y8888 "Y88888 "Y88888 "Y8888 888 888 "Y8888P "Y8888
|
|
|
- # 888
|
|
|
- # 888
|
|
|
- # 888
|
|
|
- #
|
|
|
-
|
|
|
- def get_sequence_list(self):
|
|
|
- if self._sequences =={}:
|
|
|
- return "No Sequences"
|
|
|
- return self._sequences["sequence_names"]
|
|
|
-
|
|
|
- def get_init_order(self):
|
|
|
- if self._sequences =={}:
|
|
|
- return "No Sequences"
|
|
|
- return self._sequences["initialization_sequence_order"]
|
|
|
-
|
|
|
- def get_sequence_comment(self, sequence_name):
|
|
|
- if self._sequences =={}:
|
|
|
- return "No Sequences"
|
|
|
- return self._sequences[sequence_name]["Comment"]
|
|
|
-
|
|
|
- def get_sequence_status(self, sequence_name):
|
|
|
- if self._sequences =={}:
|
|
|
- return "No Sequences"
|
|
|
- return self._sequences[sequence_name]["status_val"]
|
|
|
-
|
|
|
- def run_sequence(self, name, progressbar=None):
|
|
|
- if self._sequences == {}:
|
|
|
- return False
|
|
|
- from . import sequences
|
|
|
- return sequences.run_sequence(self.identifier, self._sequences[name]["sequence"], progressbar)
|
|
|
-
|
|
|
-
|
|
|
- ##########################################################################
|
|
|
- ##########################################################################
|
|
|
- def load_config(self, filename):
|
|
|
- """
|
|
|
- Load a config from a file
|
|
|
- :param filename: the configuration file
|
|
|
- :return:
|
|
|
- """
|
|
|
- if filename:
|
|
|
- config = configparser.RawConfigParser()
|
|
|
- if not config.read(str(filename)):
|
|
|
- return False
|
|
|
-
|
|
|
- for key in list(self._config.keys()):
|
|
|
- try:
|
|
|
- if type(self._config[key]) == int:
|
|
|
- self._config[key] = config.getint('Config', key)
|
|
|
- elif type(self._config[key]) == bool:
|
|
|
- self._config[key] = config.getboolean('Config', key)
|
|
|
- logging.vinfo("Read '%s' for '%s' from '%s'"%(str(self._config[key]), key, str(filename)))
|
|
|
- except configparser.NoOptionError as e:
|
|
|
- pass
|
|
|
- except configparser.NoSectionError as e:
|
|
|
- pass
|
|
|
- return True
|
|
|
- else:
|
|
|
- return False
|
|
|
-
|
|
|
- def save_config(self, filename):
|
|
|
- """
|
|
|
- Save the current configuration to a file
|
|
|
- :param filename: the file to write to
|
|
|
- """
|
|
|
- if filename:
|
|
|
- # with open(filename, 'w') as f:
|
|
|
- try:
|
|
|
- f = open(filename, 'w')
|
|
|
- cp = configparser.RawConfigParser()
|
|
|
- cp.add_section('Config')
|
|
|
- for key in list(self._config.keys()):
|
|
|
- cp.set('Config', key, self._config[key])
|
|
|
- f.write('#\n'
|
|
|
- '# KCG (KAPTURE Control Gui) Configuration file\n'
|
|
|
- '#\n'
|
|
|
- '# (c) Karlsruhe Institute of Technology, 2015\n'
|
|
|
- '# All rights reserved.\n'
|
|
|
- '#\n'
|
|
|
- '# Applicable Gui Version(s): 1.0 - 1.0.2\n'
|
|
|
- '#\n'
|
|
|
- '# Saved at: ' + time.asctime() + '\n'
|
|
|
- '#\n\n')
|
|
|
- cp.write(f)
|
|
|
- except (IOError, TypeError):
|
|
|
- return False
|
|
|
- return True
|
|
|
- else:
|
|
|
- return False
|
|
|
-
|
|
|
- def get(self, key):
|
|
|
- """
|
|
|
- Get the configuration value for key
|
|
|
- :param key: the key to get the value for
|
|
|
- :return: the value of the configuration for key
|
|
|
- """
|
|
|
- if not key in self._config:
|
|
|
- raise NoSuchKeyError(key+" is not registered in BoardConfiguration for board "+str(self.identifier))
|
|
|
- return self._config.get(key, None)
|
|
|
-
|
|
|
- def dump(self):
|
|
|
- """
|
|
|
- Dump all configuration values
|
|
|
- :return: all configuration values as list
|
|
|
- """
|
|
|
- s = ""
|
|
|
- for key in list(self._config.keys()):
|
|
|
- s += key + ": " + str(self.get(key)) + ", "
|
|
|
- return s[:-1]
|
|
|
-
|
|
|
-
|
|
|
- ##########################################################################
|
|
|
- # .d88888b. 888
|
|
|
- # d88P" "Y88b888
|
|
|
- # 888 888888
|
|
|
- # 888 88888888b. .d8888b .d88b. 888d888888 888 .d88b. 888d888.d8888b
|
|
|
- # 888 888888 "88b88K d8P Y8b888P" 888 888d8P Y8b888P" 88K
|
|
|
- # 888 888888 888"Y8888b.88888888888 Y88 88P88888888888 "Y8888b.
|
|
|
- # Y88b. .d88P888 d88P X88Y8b. 888 Y8bd8P Y8b. 888 X88
|
|
|
- # "Y88888P" 88888P" 88888P' "Y8888 888 Y88P "Y8888 888 88888P'
|
|
|
-
|
|
|
-
|
|
|
- def set_default_observers(self):
|
|
|
- """
|
|
|
- Set observers that are always used
|
|
|
- """
|
|
|
- #def obsprint(x,y):
|
|
|
- # print(x, y)
|
|
|
- #self.observe_all(obsprint)
|
|
|
- self.observe_write(self._update_header, 'header')
|
|
|
- self.observe_write(self._update_pilot_bunch, 'pilot_bunch')
|
|
|
-
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x9020'), 'turns_observe')
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x9028'), 'turns_skip')
|
|
|
- if self._config['board_version'] > 4: # everything for KAPTURE 2
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex(x-2), '0x90E0'), 'bunches_per_turn')
|
|
|
- self.observe_write(self._set_adc_gain, 'adc_gain')
|
|
|
- self.observe_write(self._set_adc_offset, 'adc_offset')
|
|
|
-
|
|
|
- #Attention: the th delays are inverted! Means: due to the internal setup by increasing the value the sampling
|
|
|
- #would be earlier. This is not intuitive therefore the gui inverts the value by using the delay_max as offset.
|
|
|
- #Setup Long delay 330ps. Value needs to be shifted to the left because first bit is used to set halfstep
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex((x+5)<<1), '0x9090'), 'delay_330_adc')
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex((self._config['delay_330_max']-x+5)<<1), '0x90B0'), 'delay_330_th')
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex((x+5)<<1), '0x90C0'), 'delay_330_fpga')
|
|
|
-
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex((x+5)<<1), '0x90D0'), 'delay_cascade')
|
|
|
-
|
|
|
- #Setup short Delay 25ps.
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x9094'), 'delay_25_adc')
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex(self._config['delay_25_max']-x), '0x90B4'), 'delay_25_th')
|
|
|
- #self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90C4'), 'delay_25_fpga')
|
|
|
-
|
|
|
- #Setup Clock Div
|
|
|
- self.observe_write(self._set_clk_div_all , 'clk_div') #one to set it all - normaly they should be all the same
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x9098'), 'clk_div_adc')
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90B8'), 'clk_div_th')
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90C8'), 'clk_div_fpga')
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90D8'), 'clk_div_cascade')
|
|
|
-
|
|
|
- self.observe_write(self._set_chip_delay, 'chip_delay')
|
|
|
- self.observe_write(self._set_samplingrate, 'samplingrate')
|
|
|
- self.observe_write(self._set_bunch_shift, 'bunch_shift')
|
|
|
-
|
|
|
- if self._config['adc_number'] > 4:
|
|
|
- #Setup Long delay 330ps. Value needs to be shifted to the left because first bit is used vor halfstep
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex((x+5)<<1), '0x90A0'), 'delay_330_adc_2')
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex((self._config['delay_330_max']-x+5)<<1), '0x90A8'), 'delay_330_th_2')
|
|
|
-
|
|
|
- #Setup short Delay 25ps
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90A4'), 'delay_25_adc_2')
|
|
|
- self.observe_write(lambda x: pci.write(self.identifier, hex(self._config['delay_25_max']-x), '0x90AC'), 'delay_25_th_2')
|
|
|
-
|
|
|
-
|
|
|
- else:
|
|
|
- self.observe_write(self._set_fpga_delay, 'delay_330_fpga')
|
|
|
- self.observe_write(self._set_chip_delay, 'chip_delay')
|
|
|
- self.observe_write(self._set_th_delay, 'delay_330_th')
|
|
|
- self.observe_write(self._set_adc_delay, 'delay_330_adc')
|
|
|
-
|
|
|
- def notify_all_observers(self, write=False):
|
|
|
- """
|
|
|
- Notify all observers not only the ones that are affected by a change
|
|
|
- """
|
|
|
- for key, value in list(self._config.items()):
|
|
|
- self._notify_observers(key, value, write)
|
|
|
-
|
|
|
- # observers = self._observers.get(key, None)
|
|
|
- # if observers:
|
|
|
- # for (who, callback) in observers:
|
|
|
- # callback(self.get(key))
|
|
|
-
|
|
|
-
|
|
|
- def update(self, key, value, entry=None, write=True):
|
|
|
- """
|
|
|
- Update the value for key in the configuration
|
|
|
- :param key: the key to update
|
|
|
- :param value: the value to set the configuration for key to
|
|
|
- :param entry: if key is array to select the array index.
|
|
|
- """
|
|
|
- if entry is not None:
|
|
|
- self._config[key][entry] = value
|
|
|
- else:
|
|
|
- self._config[key] = value
|
|
|
- self._notify_observers(key, self._config[key], write)
|
|
|
-
|
|
|
- def updateSilent(self, key, value, entry=None):
|
|
|
- """
|
|
|
- Update the configuration without notifying observers
|
|
|
- :param key: the key to updae
|
|
|
- :param value: the value to set the configuration of key to
|
|
|
- :param entry: if key is array to select the array index.
|
|
|
- """
|
|
|
- if entry is not None:
|
|
|
- self._config[key][entry] = value
|
|
|
- else:
|
|
|
- self._config[key] = value
|
|
|
-
|
|
|
- def observe(self, who, callback, key):
|
|
|
- """
|
|
|
- Register an observer. (A callback that is called when the according configuration value changes)
|
|
|
- :param who: who is observing
|
|
|
- :param callback: the callback to call on change of the configuration value
|
|
|
- :param key: the key to observe
|
|
|
- """
|
|
|
- if key not in list(self._config.keys()):
|
|
|
- raise ObserverError(str("Key '%s' is unknown." % key))
|
|
|
-
|
|
|
- if self._observers.get(key, None) is None:
|
|
|
- self._observers[key] = []
|
|
|
-
|
|
|
- self._observers[key].append([who, callback])
|
|
|
-
|
|
|
- def observe_all(self, callback):
|
|
|
- """
|
|
|
- Register a observer that is called when any key changes
|
|
|
- :param callback: the callback to register
|
|
|
- """
|
|
|
- if callback not in self._observers_for_all:
|
|
|
- self._observers_for_all.append(callback)
|
|
|
- else:
|
|
|
- raise ObserverError("Observer already registered")
|
|
|
-
|
|
|
- def observe_write(self, callback, key):
|
|
|
- """
|
|
|
- Register an observer that writes the value for Key on the Board
|
|
|
- :param callback: the callback to call on change of the configuration value
|
|
|
- :param key: the key to observe
|
|
|
- """
|
|
|
- if key not in list(self._config.keys()):
|
|
|
- raise ObserverError(str("Key '%s' is unknown." % key))
|
|
|
-
|
|
|
- if self._observers_write.get(key, None) is None:
|
|
|
- self._observers_write[key] = []
|
|
|
-
|
|
|
- self._observers_write[key].append(callback)
|
|
|
-
|
|
|
- def unobserve(self, who, key=None):
|
|
|
- """
|
|
|
- Remove an observer
|
|
|
- :param who: the observing entity
|
|
|
- :param key: the key to remove it from
|
|
|
- """
|
|
|
- if key is not None:
|
|
|
- observers = np.array(self._observers.get(key, None))
|
|
|
- if observers is None:
|
|
|
- return
|
|
|
- if who not in observers[:, 0]:
|
|
|
- return
|
|
|
- for i, _obs in enumerate(self._observers[key]):
|
|
|
- if _obs[0] is who:
|
|
|
- del self._observers[key][i]
|
|
|
- if not self._observers[key]:
|
|
|
- del self._observers[key]
|
|
|
- return
|
|
|
-
|
|
|
- for _key in list(self._observers.keys()):
|
|
|
- for i, _obs in enumerate(self._observers[_key]):
|
|
|
- if _obs[0] is who:
|
|
|
- del self._observers[_key][i]
|
|
|
- if not self._observers[_key]:
|
|
|
- del self._observers[_key]
|
|
|
-
|
|
|
- def unobserve_all_observer(self, callback):
|
|
|
- """
|
|
|
- Unobserve an observer that observes all keys.
|
|
|
- :param callback: the callback to unobserve
|
|
|
- """
|
|
|
- if callback in self._observers_for_all:
|
|
|
- del self._observers_for_all[self._observers_for_all.index(callback)]
|
|
|
-
|
|
|
- def _notify_observers_receiver(self, key, args):
|
|
|
- """
|
|
|
- The pyqt signal slot for notifications of observers
|
|
|
- :param key: the key that changed
|
|
|
- :param value: the new value
|
|
|
- """
|
|
|
- observers = self._observers.get(str(key), None)
|
|
|
-
|
|
|
- value = args[0]
|
|
|
- write = args[1]
|
|
|
- if observers is not None:
|
|
|
- for (who, callback) in observers:
|
|
|
- try:
|
|
|
- callback(value)
|
|
|
- except Exception as e:
|
|
|
- log.error('Observer Callback error: {}'.format(e))
|
|
|
-
|
|
|
- for cb in self._observers_for_all:
|
|
|
- try:
|
|
|
- cb(key, value)
|
|
|
- except:
|
|
|
- pass
|
|
|
-
|
|
|
- if write:
|
|
|
- observers = self._observers_write.get(str(key), None)
|
|
|
- if observers is not None:
|
|
|
- for callback in observers:
|
|
|
- try:
|
|
|
- #log.debug('write ' + key , args)
|
|
|
- callback(value)
|
|
|
- except Exception as e:
|
|
|
- log.error('Observer Callback error: {}'.format(e))
|
|
|
- time.sleep(0.025)
|
|
|
-
|
|
|
- def _notify_observers(self, key, value, write=True):
|
|
|
- """
|
|
|
- Notify observers. This emits a pyqt signal to make it thread save
|
|
|
- :param key: the key that changed
|
|
|
- :param value: the new value
|
|
|
- """
|
|
|
- #print("_notify_observers", key, value, write)
|
|
|
- self.callback_signal.emit(key, [value, write])
|
|
|
-
|
|
|
- def make_uint(self, value, maximum, name=None):
|
|
|
- """
|
|
|
- Convert a value to an uint
|
|
|
- :param value: the value
|
|
|
- :param maximum: the maximum of the returned value
|
|
|
- :param name: the name of this value
|
|
|
- :return: the converted value
|
|
|
- """
|
|
|
- if value is None:
|
|
|
- raise ValueError(str("%s Value is invalid (None)" % name))
|
|
|
-
|
|
|
- val = None
|
|
|
- try:
|
|
|
- val = int(value)
|
|
|
- except ValueError:
|
|
|
- raise ValueError(str("%s Value is not a valid number" % name))
|
|
|
-
|
|
|
- if maximum is not None:
|
|
|
- if val > maximum:
|
|
|
- raise ValueError(str("%s Value is too large (>%i)" % (name, maximum)))
|
|
|
-
|
|
|
- if val < 0:
|
|
|
- raise ValueError(str("%s Values below 0 are not allowed" % name))
|
|
|
-
|
|
|
- return val
|
|
|
-
|
|
|
- def _set_clk_div_all(self, value):
|
|
|
- self.update('clk_div_adc', value)
|
|
|
- self.update('clk_div_th', value)
|
|
|
- self.update('clk_div_fpga', value)
|
|
|
- self.update('clk_div_cascade', value)
|
|
|
-
|
|
|
-
|
|
|
- def _set_chip_delay(self, values):
|
|
|
- """
|
|
|
- Set the chip_delays on the board
|
|
|
- :param values: the value to set the delays to
|
|
|
- """
|
|
|
-
|
|
|
- _values = []
|
|
|
- for value in values[:4]:
|
|
|
- _values.append(self.make_uint(value, self.get('chip_delay_max'), 'ADC_Value'))
|
|
|
- #print("ADC1: ", values, _values)
|
|
|
- reg_value = ''
|
|
|
- mask = ''
|
|
|
- # Chip Delays are stored as 'ADC_4 ADC_3 ADC_2 ADC_1' in the register.
|
|
|
- # Therefore, we need to traverse the factors array in reverse order
|
|
|
- for value in _values: #reversed(_values): # not for Kapture 2
|
|
|
- if value is not None:
|
|
|
- reg_value += '{0:02x}'.format(value)
|
|
|
- mask += 'ff'
|
|
|
- else:
|
|
|
- reg_value += '00'
|
|
|
- mask += '00'
|
|
|
-
|
|
|
- if self._config['adc_number'] > 4:
|
|
|
- pci.write(self.identifier, reg_value, '0x9084', hex_mask=mask)
|
|
|
- else:
|
|
|
- pci.write(self.identifier, reg_value, '0x9080', hex_mask=mask)
|
|
|
-
|
|
|
- s = "Setting ADC Delays:"
|
|
|
- for (adc, value) in enumerate(_values):
|
|
|
- s += ' ADC_%i Fine Delay: %i,' % (adc, value)
|
|
|
- s = s[:-1] # cut away the last dangling ','
|
|
|
- logging.vinfo(s)
|
|
|
-
|
|
|
- if self._config['adc_number'] > 4:
|
|
|
- _values = []
|
|
|
- for value in values[4:]:
|
|
|
- _values.append(self.make_uint(value, self.get('chip_delay_max'), 'ADC_Value'))
|
|
|
- #print("ADC 2", values, _values)
|
|
|
- reg_value = ''
|
|
|
- mask = ''
|
|
|
- # Chip Delays are stored as 'ADC_4 ADC_3 ADC_2 ADC_1' in the register.
|
|
|
- # Therefore, we need to traverse the factors array in reverse order
|
|
|
- for value in _values: #reversed(_values): # not for Kapture 2
|
|
|
- if value is not None:
|
|
|
- reg_value += '{0:02x}'.format(value)
|
|
|
- mask += 'ff'
|
|
|
- else:
|
|
|
- reg_value += '00'
|
|
|
- mask += '00'
|
|
|
-
|
|
|
- pci.write(self.identifier, reg_value, '0x9080', hex_mask=mask)
|
|
|
-
|
|
|
- s = "Setting ADC Delays:"
|
|
|
- for (adc, value) in enumerate(_values):
|
|
|
- s += ' ADC_%i Fine Delay: %i,' % (adc+4, value)
|
|
|
- s = s[:-1] # cut away the last dangling ','
|
|
|
- logging.vinfo(s)
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- def _set_bunch_shift(self, values):
|
|
|
- #print("Setting bunch shifts: ", values)
|
|
|
-
|
|
|
- #Banks are flipped!
|
|
|
- #0x9320: 5,6,7,8
|
|
|
- #0x9330: 1,2,3,4
|
|
|
-
|
|
|
- bank1 = values[4:8]
|
|
|
- bank2 = values[0:4]
|
|
|
- adcs = bank1 + bank2
|
|
|
-
|
|
|
- base_reg = 0x9320
|
|
|
-
|
|
|
- for i, val in enumerate(adcs):
|
|
|
- reg = hex(base_reg+(i*4))
|
|
|
- set = "0x{0:08x}".format(val)
|
|
|
-
|
|
|
- logging.vinfo("Setting %s to %s"%(reg,set))
|
|
|
- pci.write(self.identifier, set, reg)
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- def _update_header(self, state):
|
|
|
- """
|
|
|
- Set the flag to write Header to files when acquiring.
|
|
|
- :param state: True to enabling header and False to disable
|
|
|
- :return: -
|
|
|
- """
|
|
|
- try:
|
|
|
- control = pci.read(self.identifier, 1, '0x9040')[0]
|
|
|
- control_bits = '{0:032b}'.format(int(control, 16))
|
|
|
- if state:
|
|
|
- control_bits = control_bits[:3] + '1' + control_bits[4:]
|
|
|
- else:
|
|
|
- control_bits = control_bits[:3] + '0' + control_bits[4:]
|
|
|
- dec_val_bits = int(control_bits, 2)
|
|
|
- pci.write(self.identifier, hex(dec_val_bits), '0x9040')
|
|
|
- except BoardError as e:
|
|
|
- reason = str(e) if str(e) != '' else "Unknown"
|
|
|
- logging.error("Error in Board Communication, was unable to write value to board "+reason)
|
|
|
-
|
|
|
- def _update_pilot_bunch(self, state):
|
|
|
- """
|
|
|
- Set the flag to write Header to files when acquiring.
|
|
|
- :param state: True to enabling header and False to disable
|
|
|
- :return: -
|
|
|
- """
|
|
|
- try:
|
|
|
- control = pci.read(self.identifier, 1, '0x9040')[0]
|
|
|
- control_bits = '{0:032b}'.format(int(control, 16))
|
|
|
- if state:
|
|
|
- control_bits = control_bits[:1] + '1' + control_bits[2:]
|
|
|
- else:
|
|
|
- control_bits = control_bits[:1] + '0' + control_bits[2:]
|
|
|
- dec_val_bits = int(control_bits, 2)
|
|
|
- pci.write(self.identifier, hex(dec_val_bits), '0x9040')
|
|
|
- except BoardError as e:
|
|
|
- reason = str(e) if str(e) != '' else "Unknown"
|
|
|
- logging.error("Error in Board Communication, was unable to write value to board "+reason)
|
|
|
-
|
|
|
- def _set_adc_gain(self, x):
|
|
|
- self._select_adc(1)
|
|
|
- pci.write(self.identifier, '46{:04x}'.format(int(x[0])), '0x9064')
|
|
|
- pci.write(self.identifier, '56{:04x}'.format(int(x[1])), '0x9064')
|
|
|
-
|
|
|
- self._select_adc(3)
|
|
|
- pci.write(self.identifier, '46{:04x}'.format(int(x[2])), '0x9064')
|
|
|
- pci.write(self.identifier, '56{:04x}'.format(int(x[3])), '0x9064')
|
|
|
-
|
|
|
- if len(x) > 4:
|
|
|
- logging.vinfo("Gain update not defined for more than 4 adc")
|
|
|
-
|
|
|
- def _set_adc_offset(self, x):
|
|
|
- #ADC1
|
|
|
- self._select_adc(1)
|
|
|
- pci.write(self.identifier, '44{:04x}'.format(int(x[0])), '0x9064')
|
|
|
- pci.write(self.identifier, '54{:04x}'.format(int(x[1])), '0x9064')
|
|
|
-
|
|
|
- self._select_adc(3)
|
|
|
- pci.write(self.identifier, '44{:04x}'.format(int(x[2])), '0x9064')
|
|
|
- pci.write(self.identifier, '54{:04x}'.format(int(x[3])), '0x9064')
|
|
|
-
|
|
|
- if len(x) > 4:
|
|
|
- logging.vinfo("Offset update not defined for more than 4 adc")
|
|
|
-
|
|
|
- def _select_adc(self, nr):
|
|
|
- val = 0
|
|
|
- if nr == 0:
|
|
|
- val = 0
|
|
|
- if nr < 3:
|
|
|
- val = 4
|
|
|
- elif nr < 5:
|
|
|
- val = 2
|
|
|
- pci.write(self.identifier, hex(val), '0x9044')
|
|
|
-
|
|
|
- def _set_samplingrate(self, rate):
|
|
|
- return
|
|
|
- if rate == 1:
|
|
|
- #500 MHz
|
|
|
- self.update('delay_25_adc', 10)
|
|
|
- self.update('delay_330_adc', 1)
|
|
|
- self.update('delay_25_adc_2', 10)
|
|
|
- self.update('delay_330_adc_2', 1)
|
|
|
- elif rate == 2:
|
|
|
- #1 GHz
|
|
|
- self.update('delay_25_adc', 10)
|
|
|
- self.update('delay_330_adc', 0)
|
|
|
- self.update('delay_25_adc_2', 10)
|
|
|
- self.update('delay_330_adc_2', 0)
|
|
|
-
|
|
|
- def set_startup(self):
|
|
|
- #print('board_config setting startup')
|
|
|
- #self.update('delay_330_th', 0)
|
|
|
- #sleep(0.1)
|
|
|
- #self.update('delay_25_th', 0)
|
|
|
- #sleep(0.1)
|
|
|
- self.update('delay_330_th_2', 0)
|
|
|
- sleep(0.1)
|
|
|
- self.update('delay_25_th_2', 3)
|
|
|
- sleep(0.1)
|
|
|
- self.update('delay_25_th_2', 4)
|
|
|
- sleep(0.1)
|
|
|
- self.update('chip_delay', [0,0,0,0, 0,0,0,0])
|
|
|
- sleep(0.1)
|
|
|
- #Bunch Shifts are offset by +2 to encode -2 to +2 as 0x0 to 0x4 in hardware
|
|
|
- self.update('bunch_shift', [2,2,2,2, 2,2,2,2])
|
|
|
- sleep(0.1)
|
|
|
- self.update('adc_gain', [0,0,0,0, 0,0,0,0])
|
|
|
- sleep(0.1)
|
|
|
- self.update('header', 1)
|
|
|
- sleep(0.1)
|
|
|
- self.update('pilot_bunch', 1)
|
|
|
- logging.vinfo('Startup Config Set')
|
|
|
- def read_from_board(self):
|
|
|
- """
|
|
|
- Read values from board and update them in the configuration (Mainly used for skip init functionality)
|
|
|
- """
|
|
|
- try:
|
|
|
- #settings = ['chip_1_delay','chip_2_delay','chip_3_delay','chip_4_delay']
|
|
|
- # --[ read fine/chip delays ]
|
|
|
- adc_number = self._config["adc_number"]
|
|
|
-
|
|
|
- val = pci.read(self.identifier, reg='9080')[0]
|
|
|
-
|
|
|
- if adc_number > 4:
|
|
|
- val = val + pci.read(self.identifier, reg='9084')[0]
|
|
|
- tmp = np.zeros(adc_number)
|
|
|
-
|
|
|
- for i in range(adc_number):
|
|
|
- selector = [3,2,1,0,7,6,5,4]
|
|
|
- tmp[selector[i]] = int(val[(adc_number-1-i)*2:(adc_number-i)*2], 16)
|
|
|
- self.update('chip_delay', tmp , write=False)
|
|
|
-
|
|
|
- # --[ read bunch shifts ] --
|
|
|
- #Banks are flipped!
|
|
|
- #0x9320: 5,6,7,8
|
|
|
- #0x9330: 1,2,3,4
|
|
|
- bunch_shifts = pci.read(self.identifier, reg='9330', amount=4, decimal=True)
|
|
|
-
|
|
|
- if adc_number > 4:
|
|
|
- bunch_shifts = bunch_shifts + pci.read(self.identifier, reg='9320', amount=4, decimal=True)
|
|
|
- self.update('bunch_shift', bunch_shifts, write=False)
|
|
|
-
|
|
|
- # --[ read and set th delay ]--
|
|
|
- val = pci.read(self.identifier, reg='90B0')[0]
|
|
|
- self.update('delay_330_th', self._config['delay_330_max'] - ((int(val, 16)>>1)-5), write=False)
|
|
|
- val = pci.read(self.identifier, reg='90B4')[0]
|
|
|
- self.update('delay_25_th', self._config['delay_25_max'] - int(val, 16), write=False)
|
|
|
- val = pci.read(self.identifier, reg='90B8')[0]
|
|
|
- self.update('clk_div_th', int(val, 16), write=False)
|
|
|
-
|
|
|
- # --[ read and set adc delay ]--
|
|
|
- val = pci.read(self.identifier, reg='9090')[0]
|
|
|
- self.update('delay_330_adc', (int(val, 16)>>1)-5, write=False)
|
|
|
- val = pci.read(self.identifier, reg='9094')[0]
|
|
|
- self.update('delay_25_adc', int(val, 16), write=False)
|
|
|
- val = pci.read(self.identifier, reg='9098')[0]
|
|
|
- self.update('clk_div_adc', int(val, 16), write=False)
|
|
|
-
|
|
|
- # --[ read and set fpga delay ]--
|
|
|
- val = pci.read(self.identifier, reg='90C0')[0]
|
|
|
- self.update('delay_330_fpga', (int(val, 16)>>1)-5, write=False)
|
|
|
- #val = pci.read(self.identifier, reg='90C4')[0]
|
|
|
- #self.update('delay_25_fpga', int(val, 16), write=False)
|
|
|
- val = pci.read(self.identifier, reg='90C8')[0]
|
|
|
- self.update('clk_div_fpga', int(val, 16), write=False)
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- # --[ read and set number of turns to acquire ]--
|
|
|
- val = pci.read(self.identifier, reg='9020')[0]
|
|
|
- self.update('turns_observe', int(val, 16), write=False)
|
|
|
-
|
|
|
- # --[ read and set number of turns to skip ]--
|
|
|
- val = pci.read(self.identifier, reg='9028')[0]
|
|
|
- self.update('turns_skip', int(val, 16), write=False)
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- # --[ read FMC 2 ] --
|
|
|
- # --[ FMC2 read and set th delay ]--
|
|
|
- val = pci.read(self.identifier, reg='90A8')[0]
|
|
|
- self.update('delay_330_th_2', ((int(val, 16)>>1)-5), write=False)
|
|
|
- val = pci.read(self.identifier, reg='90AC')[0]
|
|
|
- self.update('delay_25_th_2', int(val, 16), write=False)
|
|
|
-
|
|
|
-
|
|
|
- # --[ FCM 2 read and set adc delay ]--
|
|
|
- val = pci.read(self.identifier, reg='90A0')[0]
|
|
|
- self.update('delay_330_adc_2', ((int(val, 16)>>1)-5), write=False)
|
|
|
- val = pci.read(self.identifier, reg='90A4')[0]
|
|
|
- self.update('delay_25_adc_2', int(val, 16), write=False)
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- # --[ read and update header ]--
|
|
|
- control = pci.read(self.identifier, 1, '0x9040')[0]
|
|
|
- control_bits = '{0:032b}'.format(int(control, 16))
|
|
|
- if control_bits[3] == '1':
|
|
|
- self.update('header', True, write=False)
|
|
|
- else:
|
|
|
- self.update('header', False, write=False)
|
|
|
- except IndexError:
|
|
|
- error(0x002, "Could not Read data from Board. Pci returned wrong amount of data.")
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- # 888 d8P d8888 8888888b. 88888888888 888 888 8888888b. 8888888888 d888
|
|
|
- # 888 d8P d88888 888 Y88b 888 888 888 888 Y88b 888 d8888
|
|
|
- # 888 d8P d88P888 888 888 888 888 888 888 888 888 888
|
|
|
- # 888d88K d88P 888 888 d88P 888 888 888 888 d88P 8888888 888
|
|
|
- # 8888888b d88P 888 8888888P" 888 888 888 8888888P" 888 888
|
|
|
- # 888 Y88b d88P 888 888 888 888 888 888 T88b 888 888888 888
|
|
|
- # 888 Y88b d8888888888 888 888 Y88b. .d88P 888 T88b 888 888
|
|
|
- # 888 Y88b d88P 888 888 888 "Y88888P" 888 T88b 8888888888 8888888
|
|
|
- #
|
|
|
- #
|
|
|
- #
|
|
|
- def _set_fpga_delay(self, value):
|
|
|
- """
|
|
|
- observer function to set the fpga_delays on the board
|
|
|
- :param value: the value to set the delays to
|
|
|
- """
|
|
|
- time_factor = self.make_uint(value, self.get('delay_330_max'), 'FPGA_Delay')
|
|
|
- reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "0"
|
|
|
- pci.write(self.identifier, reg_value, '0x9060')
|
|
|
- logging.vinfo("Set FPGA clock delay %i * %i --> %i picoseconds" % (time_factor, self.get('delay_330_factor'), time_factor*self.get('delay_330_factor')))
|
|
|
- #self.update('fpga_delay', value)
|
|
|
-
|
|
|
-
|
|
|
- def _set_th_delay(self, value):
|
|
|
- """
|
|
|
- Set the track and hold delay on the board
|
|
|
- :param value: the value to set the delay to
|
|
|
- """
|
|
|
- time_factor = self.make_uint(value, self.get('delay_330_max'), 'TH_Delay')
|
|
|
- reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "3"
|
|
|
- pci.write(self.identifier, reg_value, '0x9060')
|
|
|
- logging.vinfo("Set T/H Signal delay %i * %i --> %i picoseconds" % (time_factor, self.get('delay_330_factor'), time_factor*self.get('delay_330_factor')))
|
|
|
-
|
|
|
- self.update('delay_330_adc', time_factor)
|
|
|
-
|
|
|
- def _set_adc_delay(self, value):
|
|
|
- """
|
|
|
- Set the adc delay for the given adc on the board
|
|
|
- :param value: the value to set the delay to
|
|
|
- """
|
|
|
- def write_delay(value, channel):
|
|
|
- '''write the delays to the board'''
|
|
|
- value = self.make_uint(value, self.get('delay_330_max'), 'ADC Delay')
|
|
|
- cmd = '00501' + '%01x' % value + str(channel+4)
|
|
|
- pci.write(self.identifier, cmd, reg='0x9060')
|
|
|
- time.sleep(0.005)
|
|
|
-
|
|
|
- delay = value + self.get('th_to_adc_cycles')
|
|
|
-
|
|
|
- if delay > self.get('delay_330_max'):
|
|
|
- delay -= self.get('delay_330_max') + 1
|
|
|
-
|
|
|
- if self._config['adc_number'] == 4:
|
|
|
- for adc in range(self._config['adc_number']):
|
|
|
- write_delay(delay, adc)
|
|
|
- s = "Setting ADC_%i delay %i * %i --> %i picoseconds" % ((adc+1), delay, self.get('delay_330_factor'), delay*self.get('delay_330_factor'))
|
|
|
- logging.vinfo(s)
|
|
|
-
|
|
|
- else:
|
|
|
- logging.vinfo("adc_delay update not defined for more than 4 adc")
|
|
|
-
|
|
|
+"""
|
|
|
+Configuration for each board
|
|
|
+"""
|
|
|
+
|
|
|
+import os
|
|
|
+import sys
|
|
|
+if sys.version_info[:3] < (3,0):
|
|
|
+ import ConfigParser as configparser
|
|
|
+else:
|
|
|
+ import configparser
|
|
|
+import numpy as np
|
|
|
+import logging
|
|
|
+from PyQt4 import QtGui, QtCore
|
|
|
+from time import sleep
|
|
|
+
|
|
|
+from .communication import *
|
|
|
+from .... import config as kcg_config
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+class BoardConfiguration(QtGui.QWidget):
|
|
|
+ """
|
|
|
+ The Main configuration class for boards.
|
|
|
+ """
|
|
|
+ callback_signal = QtCore.pyqtSignal(str, list)
|
|
|
+
|
|
|
+ def __init__(self, identifier, config_file=None):
|
|
|
+ from . import sequences
|
|
|
+ super(BoardConfiguration, self).__init__()
|
|
|
+ self.callback_signal.connect(self._notify_observers_receiver)
|
|
|
+ self.identifier = identifier
|
|
|
+ self._config = {}
|
|
|
+ self._observers = {}
|
|
|
+ self._observers_for_all = []
|
|
|
+ self._observers_write = {}
|
|
|
+ self._set_defaults()
|
|
|
+ self._get_board_version()
|
|
|
+ if self._config['board_version'] > 10:
|
|
|
+ logging.critical('Unknown Board Version - gui not working! - restart with active board')
|
|
|
+ print('Unknown Board Version - gui not working! - restart with active board')
|
|
|
+ else:
|
|
|
+ logging.info('Detected Board Version: {}'.format(self._config["board_version"]))
|
|
|
+ print('Detected Board Version: {}'.format(self._config["board_version"]))
|
|
|
+
|
|
|
+ self._sequences = sequences.read_sequence(self._config["board_version"])
|
|
|
+ self.set_default_observers()
|
|
|
+
|
|
|
+ if self.is_KAPTURE2():
|
|
|
+ self.update('bunches_per_turn', kcg_config.bunches_per_turn)
|
|
|
+ else:
|
|
|
+ self._config['delay_330_factor'] = 150
|
|
|
+ self._config['delay_330_max'] = 15
|
|
|
+ self._config['chip_delay'] = [3,3,3,3]
|
|
|
+
|
|
|
+ if config_file:
|
|
|
+ self.load_config(config_file)
|
|
|
+
|
|
|
+ #self.notify_all_observers(True)
|
|
|
+
|
|
|
+ def _set_defaults(self):
|
|
|
+ """
|
|
|
+ Set default values
|
|
|
+ """
|
|
|
+ self._config = {
|
|
|
+ 'board_version' : 7,
|
|
|
+ 'lastDataSet': None,
|
|
|
+
|
|
|
+ 'adc_number': 8,
|
|
|
+ 'samplingrate': 1,
|
|
|
+
|
|
|
+ 'bunches_per_turn': 184,
|
|
|
+ 'header_byte_size': 32,
|
|
|
+
|
|
|
+ 'chip_delay_max': 31,
|
|
|
+ 'chip_delay' : [0,0,0,0,0,0,0,0],
|
|
|
+ 'bunch_shift' : [2,2,2,2,2,2,2,2], #Offset by +2 to encode -2 to +2 range
|
|
|
+ 'chip_delay_factor': 3,
|
|
|
+
|
|
|
+
|
|
|
+ 'delay_330_max': 20, #technical 522 #be aware: changing this makes the Delay Calibration invalid!
|
|
|
+ 'delay_330_factor': 330,
|
|
|
+ 'delay_330_th': 0,
|
|
|
+ 'delay_330_adc': 1,
|
|
|
+ 'delay_330_fpga': 1,
|
|
|
+
|
|
|
+ #-Kapture 2 only--------------------
|
|
|
+ 'delay_25_max' : 23, #be aware: changing this makes the Delay Calibration invalid!
|
|
|
+ 'delay_25_factor': 25,
|
|
|
+ 'delay_25_th': 0,
|
|
|
+ 'delay_25_adc': 10,
|
|
|
+ 'delay_25_fpga': 0,
|
|
|
+
|
|
|
+ #-Second FMC------------------
|
|
|
+ 'delay_330_th_2': 0,
|
|
|
+ 'delay_330_adc_2': 1,
|
|
|
+ #'delay_330_fpga_2': 0,
|
|
|
+ 'delay_25_th_2': 4,
|
|
|
+ 'delay_25_adc_2': 10,
|
|
|
+ #'delay_25_fpga_2': 0,
|
|
|
+ 'default_25_th_2': 4,
|
|
|
+
|
|
|
+ 'delay_cascade_max': 20,
|
|
|
+ 'delay_cascade_factor': 330,
|
|
|
+ 'delay_cascade': 0,
|
|
|
+ 'delay_cascade_25': 14,
|
|
|
+
|
|
|
+ #-Clock Division--------------
|
|
|
+ 'clk_div': 6,
|
|
|
+ 'clk_div_th': 6,
|
|
|
+ 'clk_div_adc': 6,
|
|
|
+ 'clk_div_fpga': 6,
|
|
|
+ 'clk_div_cascade': 24,
|
|
|
+
|
|
|
+ #-Kapture 1 only-------------------
|
|
|
+ 'th_to_adc_cycles': 7,
|
|
|
+ #'adc_1_delay_individual': -1,
|
|
|
+ #----------------------------------
|
|
|
+
|
|
|
+ 'turns_observe': 1000,
|
|
|
+ 'turns_skip': 0,
|
|
|
+ 'acquisition_count': 10,
|
|
|
+ 'turns_wait_time': 15,
|
|
|
+
|
|
|
+ 'trigger_skip': 0,
|
|
|
+ 'trigger_timeout': 12,
|
|
|
+ 'trigger_method': 1,
|
|
|
+ 'use_trigger': False,
|
|
|
+
|
|
|
+ 'build_spectrograms': False,
|
|
|
+ 'pilot_bunch': True,
|
|
|
+ 'header': True if kcg_config.save_header is True else False,
|
|
|
+
|
|
|
+ #Kapture 2
|
|
|
+ 'adc_offset': [0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000],
|
|
|
+ 'adc_gain': [0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000]
|
|
|
+ }
|
|
|
+
|
|
|
+ def _get_board_version(self):
|
|
|
+ try:
|
|
|
+ self._config["board_version"] = int(pci.read(self.identifier, reg='0x9030')[0])
|
|
|
+ if self._config["board_version"] == 6:
|
|
|
+ self._config["board_version"] = 5
|
|
|
+ elif self._config["board_version"] == 7:
|
|
|
+ self._config["adc_number"] = 8
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ self._config["board_version"] = 0xDEAD
|
|
|
+
|
|
|
+
|
|
|
+ def is_KAPTURE2(self):
|
|
|
+ return self._config["board_version"] >4
|
|
|
+
|
|
|
+ ##########################################################################
|
|
|
+ # .d8888b.
|
|
|
+ # d88P Y88b
|
|
|
+ # Y88b.
|
|
|
+ # "Y888b. .d88b. .d88888888 888 .d88b. 88888b. .d8888b .d88b.
|
|
|
+ # "Y88b.d8P Y8bd88" 888888 888d8P Y8b888 "88bd88P" d8P Y8b
|
|
|
+ # "88888888888888 888888 88888888888888 888888 88888888
|
|
|
+ # Y88b d88PY8b. Y88b 888Y88b 888Y8b. 888 888Y88b. Y8b.
|
|
|
+ # "Y8888P" "Y8888 "Y88888 "Y88888 "Y8888 888 888 "Y8888P "Y8888
|
|
|
+ # 888
|
|
|
+ # 888
|
|
|
+ # 888
|
|
|
+ #
|
|
|
+
|
|
|
+ def get_sequence_list(self):
|
|
|
+ if self._sequences =={}:
|
|
|
+ return "No Sequences"
|
|
|
+ return self._sequences["sequence_names"]
|
|
|
+
|
|
|
+ def get_init_order(self):
|
|
|
+ if self._sequences =={}:
|
|
|
+ return "No Sequences"
|
|
|
+ return self._sequences["initialization_sequence_order"]
|
|
|
+
|
|
|
+ def get_sequence_comment(self, sequence_name):
|
|
|
+ if self._sequences =={}:
|
|
|
+ return "No Sequences"
|
|
|
+ return self._sequences[sequence_name]["Comment"]
|
|
|
+
|
|
|
+ def get_sequence_status(self, sequence_name):
|
|
|
+ if self._sequences =={}:
|
|
|
+ return "No Sequences"
|
|
|
+ return self._sequences[sequence_name]["status_val"]
|
|
|
+
|
|
|
+ def run_sequence(self, name, progressbar=None):
|
|
|
+ if self._sequences == {}:
|
|
|
+ return False
|
|
|
+ from . import sequences
|
|
|
+ return sequences.run_sequence(self.identifier, self._sequences[name]["sequence"], progressbar)
|
|
|
+
|
|
|
+
|
|
|
+ ##########################################################################
|
|
|
+ ##########################################################################
|
|
|
+ def load_config(self, filename):
|
|
|
+ """
|
|
|
+ Load a config from a file
|
|
|
+ :param filename: the configuration file
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ if filename:
|
|
|
+ config = configparser.RawConfigParser()
|
|
|
+ if not config.read(str(filename)):
|
|
|
+ return False
|
|
|
+
|
|
|
+ for key in list(self._config.keys()):
|
|
|
+ try:
|
|
|
+ if type(self._config[key]) == int:
|
|
|
+ self._config[key] = config.getint('Config', key)
|
|
|
+ elif type(self._config[key]) == bool:
|
|
|
+ self._config[key] = config.getboolean('Config', key)
|
|
|
+ logging.vinfo("Read '%s' for '%s' from '%s'"%(str(self._config[key]), key, str(filename)))
|
|
|
+ except configparser.NoOptionError as e:
|
|
|
+ pass
|
|
|
+ except configparser.NoSectionError as e:
|
|
|
+ pass
|
|
|
+ return True
|
|
|
+ else:
|
|
|
+ return False
|
|
|
+
|
|
|
+ def save_config(self, filename):
|
|
|
+ """
|
|
|
+ Save the current configuration to a file
|
|
|
+ :param filename: the file to write to
|
|
|
+ """
|
|
|
+ if filename:
|
|
|
+ # with open(filename, 'w') as f:
|
|
|
+ try:
|
|
|
+ f = open(filename, 'w')
|
|
|
+ cp = configparser.RawConfigParser()
|
|
|
+ cp.add_section('Config')
|
|
|
+ for key in list(self._config.keys()):
|
|
|
+ cp.set('Config', key, self._config[key])
|
|
|
+ f.write('#\n'
|
|
|
+ '# KCG (KAPTURE Control Gui) Configuration file\n'
|
|
|
+ '#\n'
|
|
|
+ '# (c) Karlsruhe Institute of Technology, 2015\n'
|
|
|
+ '# All rights reserved.\n'
|
|
|
+ '#\n'
|
|
|
+ '# Applicable Gui Version(s): 1.0 - 1.0.2\n'
|
|
|
+ '#\n'
|
|
|
+ '# Saved at: ' + time.asctime() + '\n'
|
|
|
+ '#\n\n')
|
|
|
+ cp.write(f)
|
|
|
+ except (IOError, TypeError):
|
|
|
+ return False
|
|
|
+ return True
|
|
|
+ else:
|
|
|
+ return False
|
|
|
+
|
|
|
+ def get(self, key):
|
|
|
+ """
|
|
|
+ Get the configuration value for key
|
|
|
+ :param key: the key to get the value for
|
|
|
+ :return: the value of the configuration for key
|
|
|
+ """
|
|
|
+ if not key in self._config:
|
|
|
+ raise NoSuchKeyError(key+" is not registered in BoardConfiguration for board "+str(self.identifier))
|
|
|
+ return self._config.get(key, None)
|
|
|
+
|
|
|
+ def dump(self):
|
|
|
+ """
|
|
|
+ Dump all configuration values
|
|
|
+ :return: all configuration values as list
|
|
|
+ """
|
|
|
+ s = ""
|
|
|
+ for key in list(self._config.keys()):
|
|
|
+ s += key + ": " + str(self.get(key)) + ", "
|
|
|
+ return s[:-1]
|
|
|
+
|
|
|
+
|
|
|
+ ##########################################################################
|
|
|
+ # .d88888b. 888
|
|
|
+ # d88P" "Y88b888
|
|
|
+ # 888 888888
|
|
|
+ # 888 88888888b. .d8888b .d88b. 888d888888 888 .d88b. 888d888.d8888b
|
|
|
+ # 888 888888 "88b88K d8P Y8b888P" 888 888d8P Y8b888P" 88K
|
|
|
+ # 888 888888 888"Y8888b.88888888888 Y88 88P88888888888 "Y8888b.
|
|
|
+ # Y88b. .d88P888 d88P X88Y8b. 888 Y8bd8P Y8b. 888 X88
|
|
|
+ # "Y88888P" 88888P" 88888P' "Y8888 888 Y88P "Y8888 888 88888P'
|
|
|
+
|
|
|
+
|
|
|
+ def set_default_observers(self):
|
|
|
+ """
|
|
|
+ Set observers that are always used
|
|
|
+ """
|
|
|
+ #def obsprint(x,y):
|
|
|
+ # print(x, y)
|
|
|
+ #self.observe_all(obsprint)
|
|
|
+ self.observe_write(self._update_header, 'header')
|
|
|
+ self.observe_write(self._update_pilot_bunch, 'pilot_bunch')
|
|
|
+
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x9020'), 'turns_observe')
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x9028'), 'turns_skip')
|
|
|
+ if self._config['board_version'] > 4: # everything for KAPTURE 2
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex(x-2), '0x90E0'), 'bunches_per_turn')
|
|
|
+ self.observe_write(self._set_adc_gain, 'adc_gain')
|
|
|
+ self.observe_write(self._set_adc_offset, 'adc_offset')
|
|
|
+
|
|
|
+ #Attention: the th delays are inverted! Means: due to the internal setup by increasing the value the sampling
|
|
|
+ #would be earlier. This is not intuitive therefore the gui inverts the value by using the delay_max as offset.
|
|
|
+ #Setup Long delay 330ps. Value needs to be shifted to the left because first bit is used to set halfstep
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex((x+5)<<1), '0x9090'), 'delay_330_adc')
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex((self._config['delay_330_max']-x+5)<<1), '0x90B0'), 'delay_330_th')
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex((x+5)<<1), '0x90C0'), 'delay_330_fpga')
|
|
|
+
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex((x+5)<<1), '0x90D0'), 'delay_cascade')
|
|
|
+
|
|
|
+ #Setup short Delay 25ps.
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x9094'), 'delay_25_adc')
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex(self._config['delay_25_max']-x), '0x90B4'), 'delay_25_th')
|
|
|
+ #self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90C4'), 'delay_25_fpga')
|
|
|
+
|
|
|
+ #Setup Clock Div
|
|
|
+ self.observe_write(self._set_clk_div_all , 'clk_div') #one to set it all - normaly they should be all the same
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x9098'), 'clk_div_adc')
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90B8'), 'clk_div_th')
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90C8'), 'clk_div_fpga')
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90D8'), 'clk_div_cascade')
|
|
|
+
|
|
|
+ self.observe_write(self._set_chip_delay, 'chip_delay')
|
|
|
+ self.observe_write(self._set_samplingrate, 'samplingrate')
|
|
|
+ self.observe_write(self._set_bunch_shift, 'bunch_shift')
|
|
|
+
|
|
|
+ if self._config['adc_number'] > 4:
|
|
|
+ #Setup Long delay 330ps. Value needs to be shifted to the left because first bit is used vor halfstep
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex((x+5)<<1), '0x90A0'), 'delay_330_adc_2')
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex((self._config['delay_330_max']-x+5)<<1), '0x90A8'), 'delay_330_th_2')
|
|
|
+
|
|
|
+ #Setup short Delay 25ps
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex(x), '0x90A4'), 'delay_25_adc_2')
|
|
|
+ self.observe_write(lambda x: pci.write(self.identifier, hex(self._config['delay_25_max']-x), '0x90AC'), 'delay_25_th_2')
|
|
|
+
|
|
|
+
|
|
|
+ else:
|
|
|
+ self.observe_write(self._set_fpga_delay, 'delay_330_fpga')
|
|
|
+ self.observe_write(self._set_chip_delay, 'chip_delay')
|
|
|
+ self.observe_write(self._set_th_delay, 'delay_330_th')
|
|
|
+ self.observe_write(self._set_adc_delay, 'delay_330_adc')
|
|
|
+
|
|
|
+ def notify_all_observers(self, write=False):
|
|
|
+ """
|
|
|
+ Notify all observers not only the ones that are affected by a change
|
|
|
+ """
|
|
|
+ for key, value in list(self._config.items()):
|
|
|
+ self._notify_observers(key, value, write)
|
|
|
+
|
|
|
+ # observers = self._observers.get(key, None)
|
|
|
+ # if observers:
|
|
|
+ # for (who, callback) in observers:
|
|
|
+ # callback(self.get(key))
|
|
|
+
|
|
|
+
|
|
|
+ def update(self, key, value, entry=None, write=True):
|
|
|
+ """
|
|
|
+ Update the value for key in the configuration
|
|
|
+ :param key: the key to update
|
|
|
+ :param value: the value to set the configuration for key to
|
|
|
+ :param entry: if key is array to select the array index.
|
|
|
+ """
|
|
|
+ if entry is not None:
|
|
|
+ self._config[key][entry] = value
|
|
|
+ else:
|
|
|
+ self._config[key] = value
|
|
|
+ self._notify_observers(key, self._config[key], write)
|
|
|
+
|
|
|
+ def updateSilent(self, key, value, entry=None):
|
|
|
+ """
|
|
|
+ Update the configuration without notifying observers
|
|
|
+ :param key: the key to updae
|
|
|
+ :param value: the value to set the configuration of key to
|
|
|
+ :param entry: if key is array to select the array index.
|
|
|
+ """
|
|
|
+ if entry is not None:
|
|
|
+ self._config[key][entry] = value
|
|
|
+ else:
|
|
|
+ self._config[key] = value
|
|
|
+
|
|
|
+ def observe(self, who, callback, key):
|
|
|
+ """
|
|
|
+ Register an observer. (A callback that is called when the according configuration value changes)
|
|
|
+ :param who: who is observing
|
|
|
+ :param callback: the callback to call on change of the configuration value
|
|
|
+ :param key: the key to observe
|
|
|
+ """
|
|
|
+ if key not in list(self._config.keys()):
|
|
|
+ raise ObserverError(str("Key '%s' is unknown." % key))
|
|
|
+
|
|
|
+ if self._observers.get(key, None) is None:
|
|
|
+ self._observers[key] = []
|
|
|
+
|
|
|
+ self._observers[key].append([who, callback])
|
|
|
+
|
|
|
+ def observe_all(self, callback):
|
|
|
+ """
|
|
|
+ Register a observer that is called when any key changes
|
|
|
+ :param callback: the callback to register
|
|
|
+ """
|
|
|
+ if callback not in self._observers_for_all:
|
|
|
+ self._observers_for_all.append(callback)
|
|
|
+ else:
|
|
|
+ raise ObserverError("Observer already registered")
|
|
|
+
|
|
|
+ def observe_write(self, callback, key):
|
|
|
+ """
|
|
|
+ Register an observer that writes the value for Key on the Board
|
|
|
+ :param callback: the callback to call on change of the configuration value
|
|
|
+ :param key: the key to observe
|
|
|
+ """
|
|
|
+ if key not in list(self._config.keys()):
|
|
|
+ raise ObserverError(str("Key '%s' is unknown." % key))
|
|
|
+
|
|
|
+ if self._observers_write.get(key, None) is None:
|
|
|
+ self._observers_write[key] = []
|
|
|
+
|
|
|
+ self._observers_write[key].append(callback)
|
|
|
+
|
|
|
+ def unobserve(self, who, key=None):
|
|
|
+ """
|
|
|
+ Remove an observer
|
|
|
+ :param who: the observing entity
|
|
|
+ :param key: the key to remove it from
|
|
|
+ """
|
|
|
+ if key is not None:
|
|
|
+ observers = np.array(self._observers.get(key, None))
|
|
|
+ if observers is None:
|
|
|
+ return
|
|
|
+ if who not in observers[:, 0]:
|
|
|
+ return
|
|
|
+ for i, _obs in enumerate(self._observers[key]):
|
|
|
+ if _obs[0] is who:
|
|
|
+ del self._observers[key][i]
|
|
|
+ if not self._observers[key]:
|
|
|
+ del self._observers[key]
|
|
|
+ return
|
|
|
+
|
|
|
+ for _key in list(self._observers.keys()):
|
|
|
+ for i, _obs in enumerate(self._observers[_key]):
|
|
|
+ if _obs[0] is who:
|
|
|
+ del self._observers[_key][i]
|
|
|
+ if not self._observers[_key]:
|
|
|
+ del self._observers[_key]
|
|
|
+
|
|
|
+ def unobserve_all_observer(self, callback):
|
|
|
+ """
|
|
|
+ Unobserve an observer that observes all keys.
|
|
|
+ :param callback: the callback to unobserve
|
|
|
+ """
|
|
|
+ if callback in self._observers_for_all:
|
|
|
+ del self._observers_for_all[self._observers_for_all.index(callback)]
|
|
|
+
|
|
|
+ def _notify_observers_receiver(self, key, args):
|
|
|
+ """
|
|
|
+ The pyqt signal slot for notifications of observers
|
|
|
+ :param key: the key that changed
|
|
|
+ :param value: the new value
|
|
|
+ """
|
|
|
+ observers = self._observers.get(str(key), None)
|
|
|
+
|
|
|
+ value = args[0]
|
|
|
+ write = args[1]
|
|
|
+ if observers is not None:
|
|
|
+ for (who, callback) in observers:
|
|
|
+ try:
|
|
|
+ callback(value)
|
|
|
+ except Exception as e:
|
|
|
+ log.error('Observer Callback error: {}'.format(e))
|
|
|
+
|
|
|
+ for cb in self._observers_for_all:
|
|
|
+ try:
|
|
|
+ cb(key, value)
|
|
|
+ except:
|
|
|
+ pass
|
|
|
+
|
|
|
+ if write:
|
|
|
+ observers = self._observers_write.get(str(key), None)
|
|
|
+ if observers is not None:
|
|
|
+ for callback in observers:
|
|
|
+ try:
|
|
|
+ #log.debug('write ' + key , args)
|
|
|
+ callback(value)
|
|
|
+ except Exception as e:
|
|
|
+ log.error('Observer Callback error: {}'.format(e))
|
|
|
+ time.sleep(0.025)
|
|
|
+
|
|
|
+ def _notify_observers(self, key, value, write=True):
|
|
|
+ """
|
|
|
+ Notify observers. This emits a pyqt signal to make it thread save
|
|
|
+ :param key: the key that changed
|
|
|
+ :param value: the new value
|
|
|
+ """
|
|
|
+ #print("_notify_observers", key, value, write)
|
|
|
+ self.callback_signal.emit(key, [value, write])
|
|
|
+
|
|
|
+ def make_uint(self, value, maximum, name=None):
|
|
|
+ """
|
|
|
+ Convert a value to an uint
|
|
|
+ :param value: the value
|
|
|
+ :param maximum: the maximum of the returned value
|
|
|
+ :param name: the name of this value
|
|
|
+ :return: the converted value
|
|
|
+ """
|
|
|
+ if value is None:
|
|
|
+ raise ValueError(str("%s Value is invalid (None)" % name))
|
|
|
+
|
|
|
+ val = None
|
|
|
+ try:
|
|
|
+ val = int(value)
|
|
|
+ except ValueError:
|
|
|
+ raise ValueError(str("%s Value is not a valid number" % name))
|
|
|
+
|
|
|
+ if maximum is not None:
|
|
|
+ if val > maximum:
|
|
|
+ raise ValueError(str("%s Value is too large (>%i)" % (name, maximum)))
|
|
|
+
|
|
|
+ if val < 0:
|
|
|
+ raise ValueError(str("%s Values below 0 are not allowed" % name))
|
|
|
+
|
|
|
+ return val
|
|
|
+
|
|
|
+ def _set_clk_div_all(self, value):
|
|
|
+ self.update('clk_div_adc', value)
|
|
|
+ self.update('clk_div_th', value)
|
|
|
+ self.update('clk_div_fpga', value)
|
|
|
+ self.update('clk_div_cascade', value)
|
|
|
+
|
|
|
+
|
|
|
+ def _set_chip_delay(self, values):
|
|
|
+ """
|
|
|
+ Set the chip_delays on the board
|
|
|
+ :param values: the value to set the delays to
|
|
|
+ """
|
|
|
+
|
|
|
+ _values = []
|
|
|
+ for value in values[:4]:
|
|
|
+ _values.append(self.make_uint(value, self.get('chip_delay_max'), 'ADC_Value'))
|
|
|
+ #print("ADC1: ", values, _values)
|
|
|
+ reg_value = ''
|
|
|
+ mask = ''
|
|
|
+ # Chip Delays are stored as 'ADC_4 ADC_3 ADC_2 ADC_1' in the register.
|
|
|
+ # Therefore, we need to traverse the factors array in reverse order
|
|
|
+ for value in _values: #reversed(_values): # not for Kapture 2
|
|
|
+ if value is not None:
|
|
|
+ reg_value += '{0:02x}'.format(value)
|
|
|
+ mask += 'ff'
|
|
|
+ else:
|
|
|
+ reg_value += '00'
|
|
|
+ mask += '00'
|
|
|
+
|
|
|
+ if self._config['adc_number'] > 4:
|
|
|
+ pci.write(self.identifier, reg_value, '0x9084', hex_mask=mask)
|
|
|
+ else:
|
|
|
+ pci.write(self.identifier, reg_value, '0x9080', hex_mask=mask)
|
|
|
+
|
|
|
+ s = "Setting ADC Delays:"
|
|
|
+ for (adc, value) in enumerate(_values):
|
|
|
+ s += ' ADC_%i Fine Delay: %i,' % (adc, value)
|
|
|
+ s = s[:-1] # cut away the last dangling ','
|
|
|
+ logging.vinfo(s)
|
|
|
+
|
|
|
+ if self._config['adc_number'] > 4:
|
|
|
+ _values = []
|
|
|
+ for value in values[4:]:
|
|
|
+ _values.append(self.make_uint(value, self.get('chip_delay_max'), 'ADC_Value'))
|
|
|
+ #print("ADC 2", values, _values)
|
|
|
+ reg_value = ''
|
|
|
+ mask = ''
|
|
|
+ # Chip Delays are stored as 'ADC_4 ADC_3 ADC_2 ADC_1' in the register.
|
|
|
+ # Therefore, we need to traverse the factors array in reverse order
|
|
|
+ for value in _values: #reversed(_values): # not for Kapture 2
|
|
|
+ if value is not None:
|
|
|
+ reg_value += '{0:02x}'.format(value)
|
|
|
+ mask += 'ff'
|
|
|
+ else:
|
|
|
+ reg_value += '00'
|
|
|
+ mask += '00'
|
|
|
+
|
|
|
+ pci.write(self.identifier, reg_value, '0x9080', hex_mask=mask)
|
|
|
+
|
|
|
+ s = "Setting ADC Delays:"
|
|
|
+ for (adc, value) in enumerate(_values):
|
|
|
+ s += ' ADC_%i Fine Delay: %i,' % (adc+4, value)
|
|
|
+ s = s[:-1] # cut away the last dangling ','
|
|
|
+ logging.vinfo(s)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ def _set_bunch_shift(self, values):
|
|
|
+ #print("Setting bunch shifts: ", values)
|
|
|
+
|
|
|
+ #Banks are flipped!
|
|
|
+ #0x9320: 5,6,7,8
|
|
|
+ #0x9330: 1,2,3,4
|
|
|
+
|
|
|
+ bank1 = values[4:8]
|
|
|
+ bank2 = values[0:4]
|
|
|
+ adcs = bank1 + bank2
|
|
|
+
|
|
|
+ base_reg = 0x9320
|
|
|
+
|
|
|
+ for i, val in enumerate(adcs):
|
|
|
+ reg = hex(base_reg+(i*4))
|
|
|
+ set = "0x{0:08x}".format(val)
|
|
|
+
|
|
|
+ logging.vinfo("Setting %s to %s"%(reg,set))
|
|
|
+ pci.write(self.identifier, set, reg)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ def _update_header(self, state):
|
|
|
+ """
|
|
|
+ Set the flag to write Header to files when acquiring.
|
|
|
+ :param state: True to enabling header and False to disable
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ control = pci.read(self.identifier, 1, '0x9040')[0]
|
|
|
+ control_bits = '{0:032b}'.format(int(control, 16))
|
|
|
+ if state:
|
|
|
+ control_bits = control_bits[:3] + '1' + control_bits[4:]
|
|
|
+ else:
|
|
|
+ control_bits = control_bits[:3] + '0' + control_bits[4:]
|
|
|
+ dec_val_bits = int(control_bits, 2)
|
|
|
+ pci.write(self.identifier, hex(dec_val_bits), '0x9040')
|
|
|
+ except BoardError as e:
|
|
|
+ reason = str(e) if str(e) != '' else "Unknown"
|
|
|
+ logging.error("Error in Board Communication, was unable to write value to board "+reason)
|
|
|
+
|
|
|
+ def _update_pilot_bunch(self, state):
|
|
|
+ """
|
|
|
+ Set the flag to write Header to files when acquiring.
|
|
|
+ :param state: True to enabling header and False to disable
|
|
|
+ :return: -
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ control = pci.read(self.identifier, 1, '0x9040')[0]
|
|
|
+ control_bits = '{0:032b}'.format(int(control, 16))
|
|
|
+ if state:
|
|
|
+ control_bits = control_bits[:1] + '1' + control_bits[2:]
|
|
|
+ else:
|
|
|
+ control_bits = control_bits[:1] + '0' + control_bits[2:]
|
|
|
+ dec_val_bits = int(control_bits, 2)
|
|
|
+ pci.write(self.identifier, hex(dec_val_bits), '0x9040')
|
|
|
+ except BoardError as e:
|
|
|
+ reason = str(e) if str(e) != '' else "Unknown"
|
|
|
+ logging.error("Error in Board Communication, was unable to write value to board "+reason)
|
|
|
+
|
|
|
+ def _set_adc_gain(self, x):
|
|
|
+ self._select_adc(1)
|
|
|
+ pci.write(self.identifier, '46{:04x}'.format(int(x[0])), '0x9064')
|
|
|
+ pci.write(self.identifier, '56{:04x}'.format(int(x[1])), '0x9064')
|
|
|
+
|
|
|
+ self._select_adc(3)
|
|
|
+ pci.write(self.identifier, '46{:04x}'.format(int(x[2])), '0x9064')
|
|
|
+ pci.write(self.identifier, '56{:04x}'.format(int(x[3])), '0x9064')
|
|
|
+
|
|
|
+ if len(x) > 4:
|
|
|
+ logging.vinfo("Gain update not defined for more than 4 adc")
|
|
|
+
|
|
|
+ def _set_adc_offset(self, x):
|
|
|
+ #ADC1
|
|
|
+ self._select_adc(1)
|
|
|
+ pci.write(self.identifier, '44{:04x}'.format(int(x[0])), '0x9064')
|
|
|
+ pci.write(self.identifier, '54{:04x}'.format(int(x[1])), '0x9064')
|
|
|
+
|
|
|
+ self._select_adc(3)
|
|
|
+ pci.write(self.identifier, '44{:04x}'.format(int(x[2])), '0x9064')
|
|
|
+ pci.write(self.identifier, '54{:04x}'.format(int(x[3])), '0x9064')
|
|
|
+
|
|
|
+ if len(x) > 4:
|
|
|
+ logging.vinfo("Offset update not defined for more than 4 adc")
|
|
|
+
|
|
|
+ def _select_adc(self, nr):
|
|
|
+ val = 0
|
|
|
+ if nr == 0:
|
|
|
+ val = 0
|
|
|
+ if nr < 3:
|
|
|
+ val = 4
|
|
|
+ elif nr < 5:
|
|
|
+ val = 2
|
|
|
+ pci.write(self.identifier, hex(val), '0x9044')
|
|
|
+
|
|
|
+ def _set_samplingrate(self, rate):
|
|
|
+ return
|
|
|
+ if rate == 1:
|
|
|
+ #500 MHz
|
|
|
+ self.update('delay_25_adc', 10)
|
|
|
+ self.update('delay_330_adc', 1)
|
|
|
+ self.update('delay_25_adc_2', 10)
|
|
|
+ self.update('delay_330_adc_2', 1)
|
|
|
+ elif rate == 2:
|
|
|
+ #1 GHz
|
|
|
+ self.update('delay_25_adc', 10)
|
|
|
+ self.update('delay_330_adc', 0)
|
|
|
+ self.update('delay_25_adc_2', 10)
|
|
|
+ self.update('delay_330_adc_2', 0)
|
|
|
+
|
|
|
+ def set_startup(self):
|
|
|
+ #print('board_config setting startup')
|
|
|
+ #self.update('delay_330_th', 0)
|
|
|
+ #sleep(0.1)
|
|
|
+ #self.update('delay_25_th', 0)
|
|
|
+ #sleep(0.1)
|
|
|
+ self.update('delay_330_th_2', 0)
|
|
|
+ sleep(0.1)
|
|
|
+ self.update('delay_25_th_2', 3)
|
|
|
+ sleep(0.1)
|
|
|
+ self.update('delay_25_th_2', 4)
|
|
|
+ sleep(0.1)
|
|
|
+ self.update('chip_delay', [0,0,0,0, 0,0,0,0])
|
|
|
+ sleep(0.1)
|
|
|
+ #Bunch Shifts are offset by +2 to encode -2 to +2 as 0x0 to 0x4 in hardware
|
|
|
+ self.update('bunch_shift', [2,2,2,2, 2,2,2,2])
|
|
|
+ sleep(0.1)
|
|
|
+ self.update('adc_gain', [0,0,0,0, 0,0,0,0])
|
|
|
+ sleep(0.1)
|
|
|
+ self.update('header', 1)
|
|
|
+ sleep(0.1)
|
|
|
+ self.update('pilot_bunch', 1)
|
|
|
+ logging.vinfo('Startup Config Set')
|
|
|
+ def read_from_board(self):
|
|
|
+ """
|
|
|
+ Read values from board and update them in the configuration (Mainly used for skip init functionality)
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ #settings = ['chip_1_delay','chip_2_delay','chip_3_delay','chip_4_delay']
|
|
|
+ # --[ read fine/chip delays ]
|
|
|
+ adc_number = self._config["adc_number"]
|
|
|
+
|
|
|
+ val = pci.read(self.identifier, reg='9080')[0]
|
|
|
+
|
|
|
+ if adc_number > 4:
|
|
|
+ val = val + pci.read(self.identifier, reg='9084')[0]
|
|
|
+ tmp = np.zeros(adc_number)
|
|
|
+
|
|
|
+ for i in range(adc_number):
|
|
|
+ selector = [3,2,1,0,7,6,5,4]
|
|
|
+ tmp[selector[i]] = int(val[(adc_number-1-i)*2:(adc_number-i)*2], 16)
|
|
|
+ self.update('chip_delay', tmp , write=False)
|
|
|
+
|
|
|
+ # --[ read bunch shifts ] --
|
|
|
+ #Banks are flipped!
|
|
|
+ #0x9320: 5,6,7,8
|
|
|
+ #0x9330: 1,2,3,4
|
|
|
+ bunch_shifts = pci.read(self.identifier, reg='9330', amount=4, decimal=True)
|
|
|
+
|
|
|
+ if adc_number > 4:
|
|
|
+ bunch_shifts = bunch_shifts + pci.read(self.identifier, reg='9320', amount=4, decimal=True)
|
|
|
+ self.update('bunch_shift', bunch_shifts, write=False)
|
|
|
+
|
|
|
+ # --[ read and set th delay ]--
|
|
|
+ val = pci.read(self.identifier, reg='90B0')[0]
|
|
|
+ self.update('delay_330_th', self._config['delay_330_max'] - ((int(val, 16)>>1)-5), write=False)
|
|
|
+ val = pci.read(self.identifier, reg='90B4')[0]
|
|
|
+ self.update('delay_25_th', self._config['delay_25_max'] - int(val, 16), write=False)
|
|
|
+ val = pci.read(self.identifier, reg='90B8')[0]
|
|
|
+ self.update('clk_div_th', int(val, 16), write=False)
|
|
|
+
|
|
|
+ # --[ read and set adc delay ]--
|
|
|
+ val = pci.read(self.identifier, reg='9090')[0]
|
|
|
+ self.update('delay_330_adc', (int(val, 16)>>1)-5, write=False)
|
|
|
+ val = pci.read(self.identifier, reg='9094')[0]
|
|
|
+ self.update('delay_25_adc', int(val, 16), write=False)
|
|
|
+ val = pci.read(self.identifier, reg='9098')[0]
|
|
|
+ self.update('clk_div_adc', int(val, 16), write=False)
|
|
|
+
|
|
|
+ # --[ read and set fpga delay ]--
|
|
|
+ val = pci.read(self.identifier, reg='90C0')[0]
|
|
|
+ self.update('delay_330_fpga', (int(val, 16)>>1)-5, write=False)
|
|
|
+ #val = pci.read(self.identifier, reg='90C4')[0]
|
|
|
+ #self.update('delay_25_fpga', int(val, 16), write=False)
|
|
|
+ val = pci.read(self.identifier, reg='90C8')[0]
|
|
|
+ self.update('clk_div_fpga', int(val, 16), write=False)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ # --[ read and set number of turns to acquire ]--
|
|
|
+ val = pci.read(self.identifier, reg='9020')[0]
|
|
|
+ self.update('turns_observe', int(val, 16), write=False)
|
|
|
+
|
|
|
+ # --[ read and set number of turns to skip ]--
|
|
|
+ val = pci.read(self.identifier, reg='9028')[0]
|
|
|
+ self.update('turns_skip', int(val, 16), write=False)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ # --[ read FMC 2 ] --
|
|
|
+ # --[ FMC2 read and set th delay ]--
|
|
|
+ val = pci.read(self.identifier, reg='90A8')[0]
|
|
|
+ self.update('delay_330_th_2', ((int(val, 16)>>1)-5), write=False)
|
|
|
+ val = pci.read(self.identifier, reg='90AC')[0]
|
|
|
+ self.update('delay_25_th_2', int(val, 16), write=False)
|
|
|
+
|
|
|
+
|
|
|
+ # --[ FCM 2 read and set adc delay ]--
|
|
|
+ val = pci.read(self.identifier, reg='90A0')[0]
|
|
|
+ self.update('delay_330_adc_2', ((int(val, 16)>>1)-5), write=False)
|
|
|
+ val = pci.read(self.identifier, reg='90A4')[0]
|
|
|
+ self.update('delay_25_adc_2', int(val, 16), write=False)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ # --[ read and update header ]--
|
|
|
+ control = pci.read(self.identifier, 1, '0x9040')[0]
|
|
|
+ control_bits = '{0:032b}'.format(int(control, 16))
|
|
|
+ if control_bits[3] == '1':
|
|
|
+ self.update('header', True, write=False)
|
|
|
+ else:
|
|
|
+ self.update('header', False, write=False)
|
|
|
+ except IndexError:
|
|
|
+ error(0x002, "Could not Read data from Board. Pci returned wrong amount of data.")
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ # 888 d8P d8888 8888888b. 88888888888 888 888 8888888b. 8888888888 d888
|
|
|
+ # 888 d8P d88888 888 Y88b 888 888 888 888 Y88b 888 d8888
|
|
|
+ # 888 d8P d88P888 888 888 888 888 888 888 888 888 888
|
|
|
+ # 888d88K d88P 888 888 d88P 888 888 888 888 d88P 8888888 888
|
|
|
+ # 8888888b d88P 888 8888888P" 888 888 888 8888888P" 888 888
|
|
|
+ # 888 Y88b d88P 888 888 888 888 888 888 T88b 888 888888 888
|
|
|
+ # 888 Y88b d8888888888 888 888 Y88b. .d88P 888 T88b 888 888
|
|
|
+ # 888 Y88b d88P 888 888 888 "Y88888P" 888 T88b 8888888888 8888888
|
|
|
+ #
|
|
|
+ #
|
|
|
+ #
|
|
|
+ def _set_fpga_delay(self, value):
|
|
|
+ """
|
|
|
+ observer function to set the fpga_delays on the board
|
|
|
+ :param value: the value to set the delays to
|
|
|
+ """
|
|
|
+ time_factor = self.make_uint(value, self.get('delay_330_max'), 'FPGA_Delay')
|
|
|
+ reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "0"
|
|
|
+ pci.write(self.identifier, reg_value, '0x9060')
|
|
|
+ logging.vinfo("Set FPGA clock delay %i * %i --> %i picoseconds" % (time_factor, self.get('delay_330_factor'), time_factor*self.get('delay_330_factor')))
|
|
|
+ #self.update('fpga_delay', value)
|
|
|
+
|
|
|
+
|
|
|
+ def _set_th_delay(self, value):
|
|
|
+ """
|
|
|
+ Set the track and hold delay on the board
|
|
|
+ :param value: the value to set the delay to
|
|
|
+ """
|
|
|
+ time_factor = self.make_uint(value, self.get('delay_330_max'), 'TH_Delay')
|
|
|
+ reg_value = "0x000501" + '{0:01x}'.format(time_factor) + "3"
|
|
|
+ pci.write(self.identifier, reg_value, '0x9060')
|
|
|
+ logging.vinfo("Set T/H Signal delay %i * %i --> %i picoseconds" % (time_factor, self.get('delay_330_factor'), time_factor*self.get('delay_330_factor')))
|
|
|
+
|
|
|
+ self.update('delay_330_adc', time_factor)
|
|
|
+
|
|
|
+ def _set_adc_delay(self, value):
|
|
|
+ """
|
|
|
+ Set the adc delay for the given adc on the board
|
|
|
+ :param value: the value to set the delay to
|
|
|
+ """
|
|
|
+ def write_delay(value, channel):
|
|
|
+ '''write the delays to the board'''
|
|
|
+ value = self.make_uint(value, self.get('delay_330_max'), 'ADC Delay')
|
|
|
+ cmd = '00501' + '%01x' % value + str(channel+4)
|
|
|
+ pci.write(self.identifier, cmd, reg='0x9060')
|
|
|
+ time.sleep(0.005)
|
|
|
+
|
|
|
+ delay = value + self.get('th_to_adc_cycles')
|
|
|
+
|
|
|
+ if delay > self.get('delay_330_max'):
|
|
|
+ delay -= self.get('delay_330_max') + 1
|
|
|
+
|
|
|
+ if self._config['adc_number'] == 4:
|
|
|
+ for adc in range(self._config['adc_number']):
|
|
|
+ write_delay(delay, adc)
|
|
|
+ s = "Setting ADC_%i delay %i * %i --> %i picoseconds" % ((adc+1), delay, self.get('delay_330_factor'), delay*self.get('delay_330_factor'))
|
|
|
+ logging.vinfo(s)
|
|
|
+
|
|
|
+ else:
|
|
|
+ logging.vinfo("adc_delay update not defined for more than 4 adc")
|
|
|
+
|