From c223f005112c941ee69ca266d3230ae94f8152b9 Mon Sep 17 00:00:00 2001 From: Erik Frojdh Date: Wed, 8 Jan 2020 14:55:16 +0100 Subject: [PATCH] Eiger --- CMakeLists.txt | 1 - python/CMakeLists.txt | 2 +- python/scripts/basic.py | 9 +- python/sls_detector/__init__.py | 3 +- python/sls_detector/dacs.py | 62 +-- python/sls_detector/detector_property.py | 18 +- python/sls_detector/eiger.py | 625 +++++++++-------------- python/sls_detector/experimental.py | 58 ++- 8 files changed, 347 insertions(+), 431 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c42193f4d..45649687e 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,6 @@ cmake_minimum_required(VERSION 3.11) project(slsDetectorPackage) set(PROJECT_VERSION 5.0.0) - include(CheckIPOSupported) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 3a8b49058..9bd69e94b 100755 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -26,7 +26,7 @@ set( PYTHON_FILES decorators.py detector_property.py # detector.py - # eiger.py + eiger.py errors.py experimental.py # jungfrau_ctb.py diff --git a/python/scripts/basic.py b/python/scripts/basic.py index 4400961f3..54911fb88 100755 --- a/python/scripts/basic.py +++ b/python/scripts/basic.py @@ -3,8 +3,13 @@ import sys import numpy as np sys.path.append(os.path.join(os.getcwd(), 'bin')) # from sls_detector import Eiger, Jungfrau, Detector, defs -from sls_detector import Detector + +from sls_detector import Detector, Eiger, DetectorDacs, Dac from sls_detector import dacIndex + + d = Detector() +e = Eiger() - +# from sls_detector.eiger import EigerVcmp +# v = EigerVcmp(d) \ No newline at end of file diff --git a/python/sls_detector/__init__.py b/python/sls_detector/__init__.py index af70e9224..e11a3dfe7 100755 --- a/python/sls_detector/__init__.py +++ b/python/sls_detector/__init__.py @@ -1,5 +1,6 @@ # from .detector import Detector, DetectorError, free_shared_memory -# from .eiger import Eiger +from .eiger import Eiger +from .dacs import DetectorDacs, Dac from .experimental import Detector # from .jungfrau import Jungfrau diff --git a/python/sls_detector/dacs.py b/python/sls_detector/dacs.py index 50ea8a1a7..d306970f7 100755 --- a/python/sls_detector/dacs.py +++ b/python/sls_detector/dacs.py @@ -1,7 +1,8 @@ from .detector_property import DetectorProperty from functools import partial import numpy as np - +import _sls_detector +dacIndex = _sls_detector.slsDetectorDefs.dacIndex class Dac(DetectorProperty): """ This class represents a dac on the detector. One instance handles all @@ -14,11 +15,11 @@ class Dac(DetectorProperty): """ - def __init__(self, name, low, high, default, detector): + def __init__(self, name, enum, low, high, default, detector): - super().__init__(partial(detector._api.getDac, name), - partial(detector._api.setDac, name), - detector._api.getNumberOfDetectors, + super().__init__(partial(detector.getDAC, enum, False), + lambda x, y : detector.setDAC(enum, x, False, y), + detector.size, name) self.min_value = low @@ -29,29 +30,28 @@ class Dac(DetectorProperty): def __repr__(self): """String representation for a single dac in all modules""" - r_str = ['{:10s}: '.format(self.__name__)] - r_str += ['{:5d}, '.format(self.get(i)) for i in range(self.get_nmod())] - return ''.join(r_str).strip(', ') - + dacstr = ''.join([f'{item:5d}' for item in self.get()]) + return f'{self.__name__:10s}:{dacstr}' +# a = Dac('vrf', dacIndex.VRF, 0, 4000, 2500, d ) class DetectorDacs: - _dacs = [('vsvp', 0, 4000, 0), - ('vtr', 0, 4000, 2500), - ('vrf', 0, 4000, 3300), - ('vrs', 0, 4000, 1400), - ('vsvn', 0, 4000, 4000), - ('vtgstv', 0, 4000, 2556), - ('vcmp_ll', 0, 4000, 1500), - ('vcmp_lr', 0, 4000, 1500), - ('vcall', 0, 4000, 4000), - ('vcmp_rl', 0, 4000, 1500), - ('rxb_rb', 0, 4000, 1100), - ('rxb_lb', 0, 4000, 1100), - ('vcmp_rr', 0, 4000, 1500), - ('vcp', 0, 4000, 200), - ('vcn', 0, 4000, 2000), - ('vis', 0, 4000, 1550), - ('iodelay', 0, 4000, 660)] + _dacs = [('vsvp', dacIndex.SVP,0, 4000, 0), + ('vtr', dacIndex.VTR,0, 4000, 2500), + ('vrf', dacIndex.VRF,0, 4000, 3300), + ('vrs', dacIndex.VRS,0, 4000, 1400), + ('vsvn', dacIndex.SVN,0, 4000, 4000), + ('vtgstv', dacIndex.VTGSTV,0, 4000, 2556), + ('vcmp_ll', dacIndex.VCMP_LL,0, 4000, 1500), + ('vcmp_lr', dacIndex.VCMP_LR,0, 4000, 1500), + ('vcall', dacIndex.CAL,0, 4000, 4000), + ('vcmp_rl', dacIndex.VCMP_RL,0, 4000, 1500), + ('rxb_rb', dacIndex.RXB_RB,0, 4000, 1100), + ('rxb_lb', dacIndex.RXB_LB,0, 4000, 1100), + ('vcmp_rr', dacIndex.VCMP_RR,0, 4000, 1500), + ('vcp', dacIndex.VCP,0, 4000, 200), + ('vcn', dacIndex.VCN,0, 4000, 2000), + ('vis', dacIndex.VIS,0, 4000, 1550), + ('iodelay', dacIndex.IO_DELAY,0, 4000, 660)] _dacnames = [_d[0] for _d in _dacs] def __init__(self, detector): @@ -95,7 +95,7 @@ class DetectorDacs: """ Read the dacs into a numpy array with dimensions [ndacs, nmodules] """ - dac_array = np.zeros((len(self._dacs), self._detector.n_modules)) + dac_array = np.zeros((len(self._dacs), len(self._detector))) for i, _d in enumerate(self): dac_array[i,:] = _d[:] return dac_array @@ -115,11 +115,3 @@ class DetectorDacs: for _d in self: _d[:] = _d.default - def update_nmod(self): - """ - Update the cached value of nmod, needs to be run after adding or - removing detectors - """ - for _d in self: - _d._n_modules = self._detector.n_modules - diff --git a/python/sls_detector/detector_property.py b/python/sls_detector/detector_property.py index 3b86b1531..3ca69ed36 100755 --- a/python/sls_detector/detector_property.py +++ b/python/sls_detector/detector_property.py @@ -14,21 +14,20 @@ class DetectorProperty: def __getitem__(self, key): if key == slice(None, None, None): - return [self.get(i) for i in range(self.get_nmod())] + return self.get() elif isinstance(key, Iterable): - return [self.get(k) for k in key] + return self.get(list(key)) else: - return self.get(key) + return self.get([key])[0] #No list for single value def __setitem__(self, key, value): #operate on all values if key == slice(None, None, None): if isinstance(value, (np.integer, int)): - for i in range(self.get_nmod()): - self.set(i, value) + self.set(value, []) elif isinstance(value, Iterable): for i in range(self.get_nmod()): - self.set(i, value[i]) + self.set(value[i], [i]) else: raise ValueError('Value should be int or np.integer not', type(value)) @@ -36,15 +35,14 @@ class DetectorProperty: elif isinstance(key, Iterable): if isinstance(value, Iterable): for k,v in zip(key, value): - self.set(k,v) + self.set(v, [k]) elif isinstance(value, int): - for k in key: - self.set(k, value) + self.set(value, list(key)) #Set single value elif isinstance(key, int): - self.set(key, value) + self.set(value, [key]) def __repr__(self): s = ', '.join(str(v) for v in self[:]) diff --git a/python/sls_detector/eiger.py b/python/sls_detector/eiger.py index e5b85338b..b09b083a5 100755 --- a/python/sls_detector/eiger.py +++ b/python/sls_detector/eiger.py @@ -6,17 +6,20 @@ Created on Wed Dec 6 11:51:18 2017 @author: l_frojdh """ -import socket -from collections.abc import Iterable -from collections import namedtuple -from functools import partial -from .adcs import Adc, DetectorAdcs +from .experimental import Detector +# import socket +# from collections.abc import Iterable +# from collections import namedtuple +# from functools import partial + +# from .adcs import Adc, DetectorAdcs from .dacs import DetectorDacs -from .detector import Detector +import _sls_detector +dacIndex = _sls_detector.slsDetectorDefs.dacIndex from .detector_property import DetectorProperty -from .utils import element_if_equal -from sls_detector.errors import DetectorValueError, DetectorError +# from .utils import element_if_equal +# from sls_detector.errors import DetectorValueError, DetectorError class EigerVcmp: """ @@ -30,20 +33,21 @@ class EigerVcmp: """ def __init__(self, detector): - _names = ['vcmp_ll', - 'vcmp_lr', - 'vcmp_rl', - 'vcmp_rr'] + _dacs = [ dacIndex.VCMP_LL, + dacIndex.VCMP_LR, + dacIndex.VCMP_RL, + dacIndex.VCMP_RR] self.set = [] self.get = [] - for i in range(detector.n_modules): + for i in range(detector.size()): if i % 2 == 0: - name = _names + dacs = _dacs else: - name = _names[::-1] - for n in name: - self.set.append(partial(detector._api.setDac, n, i)) - self.get.append(partial(detector._api.getDac, n, i)) + dacs = _dacs[::-1] + for d in dacs: + print(d, i) + self.set.append(lambda x, d=d, i=i : detector.setDAC(d, x, False, [i])) + self.get.append(lambda d=d, i=i : detector.getDAC(d, False, [i])[0]) def __getitem__(self, key): if key == slice(None, None, None): @@ -58,80 +62,84 @@ class EigerVcmp: class EigerDacs(DetectorDacs): - _dacs = [('vsvp', 0, 4000, 0), - ('vtr', 0, 4000, 2500), - ('vrf', 0, 4000, 3300), - ('vrs', 0, 4000, 1400), - ('vsvn', 0, 4000, 4000), - ('vtgstv', 0, 4000, 2556), - ('vcmp_ll', 0, 4000, 1500), - ('vcmp_lr', 0, 4000, 1500), - ('vcall', 0, 4000, 4000), - ('vcmp_rl', 0, 4000, 1500), - ('rxb_rb', 0, 4000, 1100), - ('rxb_lb', 0, 4000, 1100), - ('vcmp_rr', 0, 4000, 1500), - ('vcp', 0, 4000, 200), - ('vcn', 0, 4000, 2000), - ('vis', 0, 4000, 1550), - ('iodelay', 0, 4000, 660)] + """ + Eiger specific dacs + """ + _dacs = [('vsvp', dacIndex.SVP,0, 4000, 0), + ('vtr', dacIndex.VTR,0, 4000, 2500), + ('vrf', dacIndex.VRF,0, 4000, 3300), + ('vrs', dacIndex.VRS,0, 4000, 1400), + ('vsvn', dacIndex.SVN,0, 4000, 4000), + ('vtgstv', dacIndex.VTGSTV,0, 4000, 2556), + ('vcmp_ll', dacIndex.VCMP_LL,0, 4000, 1500), + ('vcmp_lr', dacIndex.VCMP_LR,0, 4000, 1500), + ('vcall', dacIndex.CAL,0, 4000, 4000), + ('vcmp_rl', dacIndex.VCMP_RL,0, 4000, 1500), + ('rxb_rb', dacIndex.RXB_RB,0, 4000, 1100), + ('rxb_lb', dacIndex.RXB_LB,0, 4000, 1100), + ('vcmp_rr', dacIndex.VCMP_RR,0, 4000, 1500), + ('vcp', dacIndex.VCP,0, 4000, 200), + ('vcn', dacIndex.VCN,0, 4000, 2000), + ('vis', dacIndex.VIS,0, 4000, 1550), + ('iodelay', dacIndex.IO_DELAY,0, 4000, 660)] _dacnames = [_d[0] for _d in _dacs] +# # noinspection PyProtectedMember +# class DetectorDelays: +# _delaynames = ['frame', 'left', 'right'] -# noinspection PyProtectedMember -class DetectorDelays: - _delaynames = ['frame', 'left', 'right'] - - def __init__(self, detector): - # We need to at least initially know which detector we are connected to - self._detector = detector +# def __init__(self, detector): +# # We need to at least initially know which detector we are connected to +# self._detector = detector - setattr(self, '_frame', DetectorProperty(detector._api.getDelayFrame, - detector._api.setDelayFrame, - detector._api.getNumberOfDetectors, - 'frame')) +# setattr(self, '_frame', DetectorProperty(detector._api.getDelayFrame, +# detector._api.setDelayFrame, +# detector._api.getNumberOfDetectors, +# 'frame')) - setattr(self, '_left', DetectorProperty(detector._api.getDelayLeft, - detector._api.setDelayLeft, - detector._api.getNumberOfDetectors, - 'left')) +# setattr(self, '_left', DetectorProperty(detector._api.getDelayLeft, +# detector._api.setDelayLeft, +# detector._api.getNumberOfDetectors, +# 'left')) - setattr(self, '_right', DetectorProperty(detector._api.getDelayRight, - detector._api.setDelayRight, - detector._api.getNumberOfDetectors, - 'right')) - # Index to support iteration - self._current = 0 +# setattr(self, '_right', DetectorProperty(detector._api.getDelayRight, +# detector._api.setDelayRight, +# detector._api.getNumberOfDetectors, +# 'right')) +# # Index to support iteration +# self._current = 0 - def __getattr__(self, name): - return self.__getattribute__('_' + name) +# def __getattr__(self, name): +# return self.__getattribute__('_' + name) - def __setattr__(self, name, value): - if name in self._delaynames: - return self.__getattribute__('_' + name).__setitem__(slice(None, None, None), value) - else: - super().__setattr__(name, value) +# def __setattr__(self, name, value): +# if name in self._delaynames: +# return self.__getattribute__('_' + name).__setitem__(slice(None, None, None), value) +# else: +# super().__setattr__(name, value) - def __next__(self): - if self._current >= len(self._delaynames): - self._current = 0 - raise StopIteration - else: - self._current += 1 - return self.__getattr__(self._delaynames[self._current-1]) +# def __next__(self): +# if self._current >= len(self._delaynames): +# self._current = 0 +# raise StopIteration +# else: +# self._current += 1 +# return self.__getattr__(self._delaynames[self._current-1]) - def __iter__(self): - return self +# def __iter__(self): +# return self - def __repr__(self): - hn = self._detector.hostname - r_str = ['Transmission delay [ns]\n' - '{:11s}{:>8s}{:>8s}{:>8s}'.format('', 'left', 'right', 'frame')] - for i in range(self._detector.n_modules): - r_str.append('{:2d}:{:8s}{:>8d}{:>8d}{:>8d}'.format(i, hn[i], self.left[i], self.right[i], self.frame[i])) - return '\n'.join(r_str) +# def __repr__(self): +# hn = self._detector.hostname +# r_str = ['Transmission delay [ns]\n' +# '{:11s}{:>8s}{:>8s}{:>8s}'.format('', 'left', 'right', 'frame')] +# for i in range(self._detector.n_modules): +# r_str.append('{:2d}:{:8s}{:>8d}{:>8d}{:>8d}'.format(i, hn[i], self.left[i], self.right[i], self.frame[i])) +# return '\n'.join(r_str) +from .experimental import freeze +@freeze class Eiger(Detector): """ Subclassing Detector to set up correct dacs and detector specific @@ -145,79 +153,80 @@ class Eiger(Detector): def __init__(self, id=0): super().__init__(id) - - self._active = DetectorProperty(self._api.getActive, - self._api.setActive, - self._api.getNumberOfDetectors, - 'active') - - self._vcmp = EigerVcmp(self) + self._frozen = False self._dacs = EigerDacs(self) - self._trimbit_limits = namedtuple('trimbit_limits', ['min', 'max'])(0, 63) - self._delay = DetectorDelays(self) - - # Eiger specific adcs - self._temp = DetectorAdcs() - self._temp.fpga = Adc('temp_fpga', self) - self._temp.fpgaext = Adc('temp_fpgaext', self) - self._temp.t10ge = Adc('temp_10ge', self) - self._temp.dcdc = Adc('temp_dcdc', self) - self._temp.sodl = Adc('temp_sodl', self) - self._temp.sodr = Adc('temp_sodr', self) - self._temp.fpgafl = Adc('temp_fpgafl', self) - self._temp.fpgafr = Adc('temp_fpgafr', self) + self._vcmp = EigerVcmp(self) - @property - def active(self): - """ - Is the detector active? Can be used to enable or disable a detector - module + # self._active = DetectorProperty(self.getActive, + # self.setActive, + # self.size, + # 'active') + +# self._trimbit_limits = namedtuple('trimbit_limits', ['min', 'max'])(0, 63) +# self._delay = DetectorDelays(self) - Examples - ---------- +# # Eiger specific adcs +# self._temp = DetectorAdcs() +# self._temp.fpga = Adc('temp_fpga', self) +# self._temp.fpgaext = Adc('temp_fpgaext', self) +# self._temp.t10ge = Adc('temp_10ge', self) +# self._temp.dcdc = Adc('temp_dcdc', self) +# self._temp.sodl = Adc('temp_sodl', self) +# self._temp.sodr = Adc('temp_sodr', self) +# self._temp.fpgafl = Adc('temp_fpgafl', self) +# self._temp.fpgafr = Adc('temp_fpgafr', self) + + # @property + # def active(self): + # """ + # Is the detector active? Can be used to enable or disable a detector + # module - :: + # Examples + # ---------- + + # :: - d.active - >> active: [True, True] + # d.active + # >> active: [True, True] - d.active[1] = False - >> active: [True, False] - """ - return self._active + # d.active[1] = False + # >> active: [True, False] + # """ + # return self._active - @active.setter - def active(self, value): - self._active[:] = value + # @active.setter + # def active(self, value): + # self._active[:] = value - @property - def measured_period(self): - return self._api.getMeasuredPeriod() +# @property +# def measured_period(self): +# return self._api.getMeasuredPeriod() - @property - def measured_subperiod(self): - return self._api.getMeasuredSubPeriod() +# @property +# def measured_subperiod(self): +# return self._api.getMeasuredSubPeriod() - @property - def add_gappixels(self): - """Enable or disable the (virual) pixels between ASICs +# @property +# def add_gappixels(self): +# """Enable or disable the (virual) pixels between ASICs - Examples - ---------- +# Examples +# ---------- - :: +# :: - d.add_gappixels = True +# d.add_gappixels = True - d.add_gappixels - >> True +# d.add_gappixels +# >> True - """ - return self._api.getGapPixels() +# """ +# return self._api.getGapPixels() - @add_gappixels.setter - def add_gappixels(self, value): - self._api.setGapPixels(value) +# @add_gappixels.setter +# def add_gappixels(self, value): +# self._api.setGapPixels(value) @property def dacs(self): @@ -280,114 +289,68 @@ class Eiger(Detector): """ return self._dacs - @property - def tx_delay(self): - """ - Transmission delay of the modules to allow running the detector - in a network not supporting the full speed of the detector. +# @property +# def tx_delay(self): +# """ +# Transmission delay of the modules to allow running the detector +# in a network not supporting the full speed of the detector. - :: +# :: - d.tx_delay - >> - Transmission delay [ns] - left right frame - 0:beb048 0 15000 0 - 1:beb049 100 190000 100 +# d.tx_delay +# >> +# Transmission delay [ns] +# left right frame +# 0:beb048 0 15000 0 +# 1:beb049 100 190000 100 - d.tx_delay.left = [2000,5000] - """ - return self._delay +# d.tx_delay.left = [2000,5000] +# """ +# return self._delay - def default_settings(self): - """ - reset the detector to some type of standard settings - mostly used when testing - """ - self.n_frames = 1 - self.exposure_time = 1 - self.period = 0 - self.n_cycles = 1 - self.n_measurements = 1 - self.dynamic_range = 16 - - @property - def eiger_matrix_reset(self): - """ - Matrix reset bit for Eiger. - - :py:obj:`True` : Normal operation, the matrix is reset before each acq. - :py:obj:`False` : Matrix reset disabled. Used to not reset before - reading out analog test pulses. - """ - return self._api.getCounterBit() - - @eiger_matrix_reset.setter - def eiger_matrix_reset(self, value): - self._api.setCounterBit(value) - - @property - def flowcontrol_10g(self): - """ - :py:obj:`True` - Flow control enabled :py:obj:`False` flow control disabled. - Sets for all moduels, if for some reason access to a single module is needed - this can be done trough the C++ API. - - """ - fc = self._api.getNetworkParameter('flow_control_10g') - return element_if_equal([bool(int(e)) for e in fc]) - - @flowcontrol_10g.setter - def flowcontrol_10g(self, value): - if value is True: - v = '1' - else: - v = '0' - self._api.setNetworkParameter('flow_control_10g', v, -1) - - def pulse_all_pixels(self, n): - """ - Pulse each pixel of the chip **n** times using the analog test pulses. - The pulse height is set using d.dacs.vcall with 4000 being 0 and 0 being - the highest pulse. +# def pulse_all_pixels(self, n): +# """ +# Pulse each pixel of the chip **n** times using the analog test pulses. +# The pulse height is set using d.dacs.vcall with 4000 being 0 and 0 being +# the highest pulse. - :: +# :: - #Pulse all pixels ten times - d.pulse_all_pixels(10) +# #Pulse all pixels ten times +# d.pulse_all_pixels(10) - #Avoid resetting before acq - d.eiger_matrix_reset = False +# #Avoid resetting before acq +# d.eiger_matrix_reset = False - d.acq() #take frame +# d.acq() #take frame - #Restore normal behaviour - d.eiger_matrix_reset = True +# #Restore normal behaviour +# d.eiger_matrix_reset = True - """ - self._api.pulseAllPixels(n) +# """ +# self._api.pulseAllPixels(n) - def pulse_diagonal(self, n): - """ - Pulse pixels in super colums in a diagonal fashion. Used for calibration - of vcall. Saves time compared to pulsing all pixels. - """ - self._api.pulseDiagonal(n) +# def pulse_diagonal(self, n): +# """ +# Pulse pixels in super colums in a diagonal fashion. Used for calibration +# of vcall. Saves time compared to pulsing all pixels. +# """ +# self._api.pulseDiagonal(n) - def pulse_chip(self, n): - """ - Advance the counter by toggling enable. Gives 2*n+2 int the counter +# def pulse_chip(self, n): +# """ +# Advance the counter by toggling enable. Gives 2*n+2 int the counter - """ - n = int(n) - if n >= -1: - self._api.pulseChip(n) - else: - raise ValueError('n must be equal or larger than -1') +# """ +# n = int(n) +# if n >= -1: +# self._api.pulseChip(n) +# else: +# raise ValueError('n must be equal or larger than -1') @property def vcmp(self): @@ -420,177 +383,99 @@ class Eiger(Detector): else: raise ValueError('vcmp only compatible with setting all') - @property - def rx_udpport(self): - """ - UDP port for the receiver. Each module has two ports referred to - as rx_udpport and rx_udpport2 in the command line interface - here they are grouped for each detector +# @property +# def rx_udpport(self): +# """ +# UDP port for the receiver. Each module has two ports referred to +# as rx_udpport and rx_udpport2 in the command line interface +# here they are grouped for each detector - :: +# :: - [0:rx_udpport, 0:rx_udpport2, 1:rx_udpport ...] +# [0:rx_udpport, 0:rx_udpport2, 1:rx_udpport ...] - Examples - ----------- +# Examples +# ----------- - :: +# :: - d.rx_udpport - >> [50010, 50011, 50004, 50005] +# d.rx_udpport +# >> [50010, 50011, 50004, 50005] - d.rx_udpport = [50010, 50011, 50012, 50013] +# d.rx_udpport = [50010, 50011, 50012, 50013] - """ - p0 = self._api.getReceiverUDPPort() - p1 = self._api.getReceiverUDPPort2() - return [int(val) for pair in zip(p0, p1) for val in pair] +# """ +# p0 = self._api.getReceiverUDPPort() +# p1 = self._api.getReceiverUDPPort2() +# return [int(val) for pair in zip(p0, p1) for val in pair] - @rx_udpport.setter - def rx_udpport(self, ports): - """Requires iterating over elements two and two for setting ports""" - a = iter(ports) - for i, p in enumerate(zip(a, a)): - self._api.setReceiverUDPPort(p[0], i) - self._api.setReceiverUDPPort2(p[1], i) +# @rx_udpport.setter +# def rx_udpport(self, ports): +# """Requires iterating over elements two and two for setting ports""" +# a = iter(ports) +# for i, p in enumerate(zip(a, a)): +# self._api.setReceiverUDPPort(p[0], i) +# self._api.setReceiverUDPPort2(p[1], i) @property def rx_zmqport(self): """ Return the receiver zmq ports. Note that Eiger has two ports per receiver! + This functions therefore differ from the base class. :: - detector.rx_zmqport + e.rx_zmqport >> [30001, 30002, 30003, 30004] """ - _s = self._api.getReceiverStreamingPort() - if _s == '': - return [] - else: - return [int(_p) + i for _p in _s for i in range(2)] - - @rx_zmqport.setter - def rx_zmqport(self, port): - if isinstance(port, Iterable): - for i, p in enumerate(port): - self._api.setReceiverStreamingPort(p, i) - else: - self._api.setReceiverStreamingPort(port, -1) + ports = self.getRxZmqPort() + return [p + i for p in ports for i in range(2)] - @property - def sub_exposure_time(self): - """ - Sub frame exposure time in *seconds* for Eiger in 32bit autosumming mode +# @rx_zmqport.setter +# def rx_zmqport(self, port): +# if isinstance(port, Iterable): +# for i, p in enumerate(port): +# self._api.setReceiverStreamingPort(p, i) +# else: +# self._api.setReceiverStreamingPort(port, -1) - :: +# @property +# def temp(self): +# """ +# An instance of DetectorAdcs used to read the temperature +# of different components - d.sub_exposure_time - >> 0.0023 +# Examples +# ----------- - d.sub_exposure_time = 0.002 +# :: - """ - return self._api.getSubExposureTime() / 1e9 +# detector.temp +# >> +# temp_fpga : 36.90°C, 45.60°C +# temp_fpgaext : 31.50°C, 32.50°C +# temp_10ge : 0.00°C, 0.00°C +# temp_dcdc : 36.00°C, 36.00°C +# temp_sodl : 33.00°C, 34.50°C +# temp_sodr : 33.50°C, 34.00°C +# temp_fpgafl : 33.81°C, 30.93°C +# temp_fpgafr : 27.88°C, 29.15°C - - @sub_exposure_time.setter - def sub_exposure_time(self, t): - #TODO! checking here or in the detector? - ns_time = int(t * 1e9) - if ns_time > 0: - self._api.setSubExposureTime(ns_time) - else: - raise DetectorValueError('Sub exposure time must be larger than 0') - - @property - def sub_deadtime(self): - """ - Deadtime between subexposures. Used to mimize noise by delaying the start of the next - subexposure. - """ - return self._api.getSubExposureDeadTime() / 1e9 - - - @sub_deadtime.setter - def sub_deadtime(self, t): - ns_time = int(t * 1e9) - if ns_time >= 0: - self._api.setSubExposureDeadTime(ns_time) - else: - raise ValueError('Sub deadtime time must be larger or equal to 0') - - @property - def temp(self): - """ - An instance of DetectorAdcs used to read the temperature - of different components - - Examples - ----------- - - :: - - detector.temp - >> - temp_fpga : 36.90°C, 45.60°C - temp_fpgaext : 31.50°C, 32.50°C - temp_10ge : 0.00°C, 0.00°C - temp_dcdc : 36.00°C, 36.00°C - temp_sodl : 33.00°C, 34.50°C - temp_sodr : 33.50°C, 34.00°C - temp_fpgafl : 33.81°C, 30.93°C - temp_fpgafr : 27.88°C, 29.15°C - - a = detector.temp.fpga[:] - a - >> [36.568, 45.542] +# a = detector.temp.fpga[:] +# a +# >> [36.568, 45.542] - """ - return self._temp - - @property - def tengiga(self): - """Enable 10Gbit/s data output - - Examples - ---------- - - :: - - d.tengiga - >> False - - d.tengiga = True - - """ - return self._api.getTenGigabitEthernet() - - @tengiga.setter - def tengiga(self, value): - self._api.setTenGigabitEthernet(value) - - def set_delays(self, delta): - self.tx_delay.left = [delta*(i*2) for i in range(self.n_modules)] - self.tx_delay.right = [delta*(i*2+1) for i in range(self.n_modules)] +# """ +# return self._temp + + + +# def set_delays(self, delta): +# self.tx_delay.left = [delta*(i*2) for i in range(self.n_modules)] +# self.tx_delay.right = [delta*(i*2+1) for i in range(self.n_modules)] - def setup500k(self, hostnames): - """ - Setup the Eiger detector to run on the local machine - """ - - self.hostname = hostnames - self.file_write = False - self.image_size = (512, 1024) - self.rx_tcpport = [1954, 1955] - self.rx_udpport = [50010, 50011, 50004, 50005] - self.rx_hostname = socket.gethostname().split('.')[0] - self.rx_datastream = False - self.file_write = False - self.online = True - self.receiver_online = True diff --git a/python/sls_detector/experimental.py b/python/sls_detector/experimental.py index c53c0b743..50727e2c6 100755 --- a/python/sls_detector/experimental.py +++ b/python/sls_detector/experimental.py @@ -28,10 +28,10 @@ class Register: def freeze(cls): - cls.__frozen = False + cls._frozen = False def frozensetattr(self, key, value): - if self.__frozen and not hasattr(self, key): + if self._frozen and not hasattr(self, key): raise AttributeError( "Class {} is frozen. Cannot set {} = {}".format( cls.__name__, key, value @@ -44,7 +44,7 @@ def freeze(cls): @wraps(func) def wrapper(self, *args, **kwargs): func(self, *args, **kwargs) - self.__frozen = True + self._frozen = True return wrapper @@ -70,6 +70,8 @@ class Detector(CppDetectorApi): super().__init__(multi_id) self._register = Register(self) + + # CONFIGURATION def __len__(self): return self.size() @@ -197,6 +199,18 @@ class Detector(CppDetectorApi): else: self.setSubExptime(dt.timedelta(seconds=t)) + @property + def subdeadtime(self): + res = self.getSubDeadTime() + return element_if_equal([it.total_seconds() for it in res]) + + @subdeadtime.setter + def subdeadtime(self, t): + if isinstance(t, dt.timedelta): + self.setSubDeadTime(t) + else: + self.setSubDeadTime(dt.timedelta(seconds=t)) + @property def period(self): @@ -232,14 +246,7 @@ class Detector(CppDetectorApi): def startingfnum(self, value): self.setStartingFrameNumber(value) - #TODO! testing switches on automatically? - @property - def flowcontrol_10g(self): - return element_if_equal(self.getTenGigaFlowControl()) - @flowcontrol_10g.setter - def flowcontrol_10g(self, enable): - self.setTenGigaFlowControl(enable) #TODO! add txdelay @@ -646,4 +653,33 @@ class Detector(CppDetectorApi): @dsamples.setter def dsamples(self, N): - self.setNumberOfDigitalSamples(N) \ No newline at end of file + self.setNumberOfDigitalSamples(N) + + + """ + Some Eiger stuff, does this have to be here or can we move it to subclass? + """ + @property + def partialreset(self): + return element_if_equal(self.getPartialReset()) + + @partialreset.setter + def partialreset(self, value): + self.setPartialReset(value) + + @property + def tengiga(self): + return element_if_equal(self.getTenGiga()) + + @tengiga.setter + def tengiga(self, value): + self.setTenGiga(value) + + + @property + def flowcontrol10g(self): + return element_if_equal(self.getTenGigaFlowControl()) + + @flowcontrol10g.setter + def flowcontrol10g(self, enable): + self.setTenGigaFlowControl(enable) \ No newline at end of file