mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-06-12 21:07:13 +02:00
replaced udp socket
This commit is contained in:
23
python/slsdet/__init__.py
Executable file
23
python/slsdet/__init__.py
Executable file
@ -0,0 +1,23 @@
|
||||
# from .detector import Detector, DetectorError, free_shared_memory
|
||||
from .eiger import Eiger
|
||||
from .ctb import Ctb
|
||||
from .dacs import DetectorDacs, Dac
|
||||
from .detector import Detector
|
||||
from .jungfrau import Jungfrau
|
||||
from .mythen3 import Mythen3
|
||||
# from .jungfrau_ctb import JungfrauCTB
|
||||
# from _slsdet import DetectorApi
|
||||
|
||||
import _slsdet
|
||||
|
||||
defs = _slsdet.slsDetectorDefs
|
||||
runStatus = _slsdet.slsDetectorDefs.runStatus
|
||||
speedLevel = _slsdet.slsDetectorDefs.speedLevel
|
||||
timingMode = _slsdet.slsDetectorDefs.timingMode
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
detectorType = _slsdet.slsDetectorDefs.detectorType
|
||||
detectorSettings = _slsdet.slsDetectorDefs.detectorSettings
|
||||
readoutMode = _slsdet.slsDetectorDefs.readoutMode
|
||||
|
||||
IpAddr = _slsdet.IpAddr
|
||||
MacAddr = _slsdet.MacAddr
|
40
python/slsdet/adcs.py
Executable file
40
python/slsdet/adcs.py
Executable file
@ -0,0 +1,40 @@
|
||||
from functools import partial
|
||||
class Adc:
|
||||
def __init__(self, name, detector):
|
||||
self.name = name
|
||||
self._detector = detector
|
||||
self.get_nmod = self._detector._api.getNumberOfDetectors
|
||||
# Bind functions to get and set the dac
|
||||
self.get = partial(self._detector._api.getAdc, self.name)
|
||||
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""
|
||||
Get dacs either by slice, key or list
|
||||
"""
|
||||
if key == slice(None, None, None):
|
||||
return [self.get(i) / 1000 for i in range(self.get_nmod())]
|
||||
elif isinstance(key, Iterable):
|
||||
return [self.get(k) / 1000 for k in key]
|
||||
else:
|
||||
return self.get(key) / 1000
|
||||
|
||||
def __repr__(self):
|
||||
"""String representation for a single adc in all modules"""
|
||||
degree_sign = u'\N{DEGREE SIGN}'
|
||||
r_str = ['{:14s}: '.format(self.name)]
|
||||
r_str += ['{:6.2f}{:s}C, '.format(self.get(i)/1000, degree_sign) for i in range(self.get_nmod())]
|
||||
return ''.join(r_str).strip(', ')
|
||||
|
||||
|
||||
|
||||
class DetectorAdcs:
|
||||
"""
|
||||
Interface to the ADCs on the readout board
|
||||
"""
|
||||
def __iter__(self):
|
||||
for attr, value in self.__dict__.items():
|
||||
yield value
|
||||
|
||||
def __repr__(self):
|
||||
return '\n'.join([str(t) for t in self])
|
43
python/slsdet/ctb.py
Normal file
43
python/slsdet/ctb.py
Normal file
@ -0,0 +1,43 @@
|
||||
from .detector import Detector
|
||||
from .utils import element_if_equal
|
||||
from .dacs import DetectorDacs
|
||||
import _slsdet
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
from .detector_property import DetectorProperty
|
||||
|
||||
class CtbDacs(DetectorDacs):
|
||||
"""
|
||||
Ctb dacs
|
||||
"""
|
||||
_dacs = [('dac0', dacIndex(0), 0, 4000, 1400),
|
||||
('dac1', dacIndex(1), 0, 4000, 1200),
|
||||
('dac2', dacIndex(2), 0, 4000, 900),
|
||||
('dac3', dacIndex(3), 0, 4000, 1050),
|
||||
('dac4', dacIndex(4), 0, 4000, 1400),
|
||||
('dac5', dacIndex(5), 0, 4000, 655),
|
||||
('dac6', dacIndex(6), 0, 4000, 2000),
|
||||
('dac7', dacIndex(7), 0, 4000, 1400),
|
||||
('dac8', dacIndex(8), 0, 4000, 850),
|
||||
('dac9', dacIndex(9), 0, 4000, 2000),
|
||||
('dac10', dacIndex(10), 0, 4000, 2294),
|
||||
('dac11', dacIndex(11), 0, 4000, 983),
|
||||
('dac12', dacIndex(12), 0, 4000, 1475),
|
||||
('dac13', dacIndex(13), 0, 4000, 1200),
|
||||
('dac14', dacIndex(14), 0, 4000, 1600),
|
||||
('dac15', dacIndex(15), 0, 4000, 1455),
|
||||
('dac16', dacIndex(16), 0, 4000, 0),
|
||||
('dac17', dacIndex(17), 0, 4000, 1000),
|
||||
]
|
||||
_dacnames = [_d[0] for _d in _dacs]
|
||||
|
||||
from .utils import element
|
||||
class Ctb(Detector):
|
||||
def __init__(self, id = 0):
|
||||
super().__init__(id)
|
||||
self._frozen = False
|
||||
self._dacs = CtbDacs(self)
|
||||
|
||||
@property
|
||||
def dacs(self):
|
||||
return self._dacs
|
||||
|
110
python/slsdet/dacs.py
Executable file
110
python/slsdet/dacs.py
Executable file
@ -0,0 +1,110 @@
|
||||
from .detector_property import DetectorProperty
|
||||
from functools import partial
|
||||
import numpy as np
|
||||
import _slsdet
|
||||
from .detector import freeze
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
class Dac(DetectorProperty):
|
||||
"""
|
||||
This class represents a dac on the detector. One instance handles all
|
||||
dacs with the same name for a multi detector instance.
|
||||
|
||||
.. note ::
|
||||
|
||||
This class is used to build up DetectorDacs and is in general
|
||||
not directly accessed to the user.
|
||||
|
||||
|
||||
"""
|
||||
def __init__(self, name, enum, low, high, default, detector):
|
||||
|
||||
super().__init__(partial(detector.getDAC, enum, False),
|
||||
lambda x, y : detector.setDAC(enum, x, False, y),
|
||||
detector.size,
|
||||
name)
|
||||
|
||||
self.min_value = low
|
||||
self.max_value = high
|
||||
self.default = default
|
||||
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
"""String representation for a single dac in all modules"""
|
||||
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 )
|
||||
# @freeze
|
||||
class DetectorDacs:
|
||||
_dacs = []
|
||||
_dacnames = [_d[0] for _d in _dacs]
|
||||
_allowed_attr = ['_detector', '_current']
|
||||
_frozen = False
|
||||
|
||||
def __init__(self, detector):
|
||||
# We need to at least initially know which detector we are connected to
|
||||
self._detector = detector
|
||||
|
||||
# Index to support iteration
|
||||
self._current = 0
|
||||
|
||||
# Populate the dacs
|
||||
for _d in self._dacs:
|
||||
setattr(self, '_'+_d[0], Dac(*_d, detector))
|
||||
|
||||
self._frozen = True
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self.__getattribute__('_' + name)
|
||||
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name in self._dacnames:
|
||||
return self.__getattribute__('_' + name).__setitem__(slice(None, None, None), value)
|
||||
else:
|
||||
if self._frozen == True and name not in self._allowed_attr:
|
||||
raise AttributeError(f'Dac not found: {name}')
|
||||
super().__setattr__(name, value)
|
||||
|
||||
|
||||
def __next__(self):
|
||||
if self._current >= len(self._dacs):
|
||||
self._current = 0
|
||||
raise StopIteration
|
||||
else:
|
||||
self._current += 1
|
||||
return self.__getattr__(self._dacnames[self._current-1])
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __repr__(self):
|
||||
r_str = ['========== DACS =========']
|
||||
r_str += [repr(dac) for dac in self]
|
||||
return '\n'.join(r_str)
|
||||
|
||||
def get_asarray(self):
|
||||
"""
|
||||
Read the dacs into a numpy array with dimensions [ndacs, nmodules]
|
||||
"""
|
||||
dac_array = np.zeros((len(self._dacs), len(self._detector)))
|
||||
for i, _d in enumerate(self):
|
||||
dac_array[i,:] = _d[:]
|
||||
return dac_array
|
||||
|
||||
def set_from_array(self, dac_array):
|
||||
"""
|
||||
Set the dacs from an numpy array with dac values. [ndacs, nmodules]
|
||||
"""
|
||||
dac_array = dac_array.astype(np.int)
|
||||
for i, _d in enumerate(self):
|
||||
_d[:] = dac_array[i]
|
||||
|
||||
def set_default(self):
|
||||
"""
|
||||
Set all dacs to their default values
|
||||
"""
|
||||
for _d in self:
|
||||
_d[:] = _d.default
|
||||
|
9
python/slsdet/decorators.py
Executable file
9
python/slsdet/decorators.py
Executable file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Function decorators for the sls_detector.
|
||||
"""
|
||||
from .errors import DetectorError
|
||||
import functools
|
||||
|
||||
|
1088
python/slsdet/detector.py
Executable file
1088
python/slsdet/detector.py
Executable file
File diff suppressed because it is too large
Load Diff
49
python/slsdet/detector_property.py
Executable file
49
python/slsdet/detector_property.py
Executable file
@ -0,0 +1,49 @@
|
||||
from collections.abc import Iterable
|
||||
import numpy as np
|
||||
|
||||
class DetectorProperty:
|
||||
"""
|
||||
Base class for a detector property that should be accessed by name and index
|
||||
TODO! Calls are not in parallel and exposes object that can be passes around
|
||||
"""
|
||||
def __init__(self, get_func, set_func, nmod_func, name):
|
||||
self.get = get_func
|
||||
self.set = set_func
|
||||
self.get_nmod = nmod_func
|
||||
self.__name__ = name
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key == slice(None, None, None):
|
||||
return self.get()
|
||||
elif isinstance(key, Iterable):
|
||||
return self.get(list(key))
|
||||
else:
|
||||
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)):
|
||||
self.set(value, [])
|
||||
elif isinstance(value, Iterable):
|
||||
for i in range(self.get_nmod()):
|
||||
self.set(value[i], [i])
|
||||
else:
|
||||
raise ValueError('Value should be int or np.integer not', type(value))
|
||||
|
||||
#Iterate over some
|
||||
elif isinstance(key, Iterable):
|
||||
if isinstance(value, Iterable):
|
||||
for k,v in zip(key, value):
|
||||
self.set(v, [k])
|
||||
|
||||
elif isinstance(value, int):
|
||||
self.set(value, list(key))
|
||||
|
||||
#Set single value
|
||||
elif isinstance(key, int):
|
||||
self.set(value, [key])
|
||||
|
||||
def __repr__(self):
|
||||
s = ', '.join(str(v) for v in self[:])
|
||||
return '{}: [{}]'.format(self.__name__, s)
|
476
python/slsdet/eiger.py
Executable file
476
python/slsdet/eiger.py
Executable file
@ -0,0 +1,476 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Wed Dec 6 11:51:18 2017
|
||||
|
||||
@author: l_frojdh
|
||||
"""
|
||||
|
||||
|
||||
from .detector import Detector
|
||||
|
||||
# from .adcs import Adc, DetectorAdcs
|
||||
from .dacs import DetectorDacs
|
||||
import _slsdet
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
from .detector_property import DetectorProperty
|
||||
# from .utils import element_if_equal
|
||||
# from sls_detector.errors import DetectorValueError, DetectorError
|
||||
|
||||
class EigerVcmp:
|
||||
"""
|
||||
Convenience class to be able to loop over vcmp for Eiger
|
||||
|
||||
|
||||
.. todo::
|
||||
|
||||
Support single assignment and perhaps unify with Dac class
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, detector):
|
||||
_dacs = [ dacIndex.VCMP_LL,
|
||||
dacIndex.VCMP_LR,
|
||||
dacIndex.VCMP_RL,
|
||||
dacIndex.VCMP_RR]
|
||||
self.set = []
|
||||
self.get = []
|
||||
for i in range(detector.size()):
|
||||
if i % 2 == 0:
|
||||
dacs = _dacs
|
||||
else:
|
||||
dacs = _dacs[::-1]
|
||||
for d in dacs:
|
||||
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):
|
||||
return [_d() for _d in self.get]
|
||||
return self.get[key]()
|
||||
|
||||
def __setitem__(self, i, value):
|
||||
self.set[i](value)
|
||||
|
||||
def __repr__(self):
|
||||
return 'vcmp: '+ str(self[:])
|
||||
|
||||
|
||||
class EigerDacs(DetectorDacs):
|
||||
"""
|
||||
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']
|
||||
|
||||
# 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, '_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
|
||||
|
||||
# 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 __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 __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 .detector import freeze
|
||||
|
||||
@freeze
|
||||
class Eiger(Detector):
|
||||
"""
|
||||
Subclassing Detector to set up correct dacs and detector specific
|
||||
functions.
|
||||
"""
|
||||
_detector_dynamic_range = [4, 8, 16, 32]
|
||||
|
||||
|
||||
_settings = ['standard', 'highgain', 'lowgain', 'veryhighgain', 'verylowgain']
|
||||
"""available settings for Eiger, note almost always standard"""
|
||||
|
||||
def __init__(self, id=0):
|
||||
super().__init__(id)
|
||||
self._frozen = False
|
||||
self._dacs = EigerDacs(self)
|
||||
self._vcmp = EigerVcmp(self)
|
||||
|
||||
# self._active = DetectorProperty(self.getActive,
|
||||
# self.setActive,
|
||||
# self.size,
|
||||
# 'active')
|
||||
|
||||
# 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)
|
||||
|
||||
# @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[1] = False
|
||||
# >> active: [True, False]
|
||||
# """
|
||||
# return self._active
|
||||
|
||||
# @active.setter
|
||||
# def active(self, value):
|
||||
# self._active[:] = value
|
||||
|
||||
# @property
|
||||
# def measured_period(self):
|
||||
# return self._api.getMeasuredPeriod()
|
||||
|
||||
# @property
|
||||
# def measured_subperiod(self):
|
||||
# return self._api.getMeasuredSubPeriod()
|
||||
|
||||
# @property
|
||||
# def add_gappixels(self):
|
||||
# """Enable or disable the (virual) pixels between ASICs
|
||||
|
||||
# Examples
|
||||
# ----------
|
||||
|
||||
# ::
|
||||
|
||||
# d.add_gappixels = True
|
||||
|
||||
# d.add_gappixels
|
||||
# >> True
|
||||
|
||||
# """
|
||||
# return self._api.getGapPixels()
|
||||
|
||||
# @add_gappixels.setter
|
||||
# def add_gappixels(self, value):
|
||||
# self._api.setGapPixels(value)
|
||||
|
||||
@property
|
||||
def dacs(self):
|
||||
"""
|
||||
|
||||
An instance of DetectorDacs used for accessing the dacs of a single
|
||||
or multi detector.
|
||||
|
||||
Examples
|
||||
---------
|
||||
|
||||
::
|
||||
|
||||
d = Eiger()
|
||||
|
||||
#Set all vrf to 1500
|
||||
d.dacs.vrf = 1500
|
||||
|
||||
#Check vrf
|
||||
d.dacs.vrf
|
||||
>> vrf : 1500, 1500
|
||||
|
||||
#Set a single vtr
|
||||
d.dacs.vtr[0] = 1800
|
||||
|
||||
#Set vrf with multiple values
|
||||
d.dacs.vrf = [3500,3700]
|
||||
d.dacs.vrf
|
||||
>> vrf : 3500, 3700
|
||||
|
||||
#read into a variable
|
||||
var = d.dacs.vrf[:]
|
||||
|
||||
#set multiple with multiple values, mostly used for large systems
|
||||
d.dacs.vcall[0,1] = [3500,3600]
|
||||
d.dacs.vcall
|
||||
>> vcall : 3500, 3600
|
||||
|
||||
d.dacs
|
||||
>>
|
||||
========== DACS =========
|
||||
vsvp : 0, 0
|
||||
vtr : 4000, 4000
|
||||
vrf : 1900, 1900
|
||||
vrs : 1400, 1400
|
||||
vsvn : 4000, 4000
|
||||
vtgstv : 2556, 2556
|
||||
vcmp_ll : 1500, 1500
|
||||
vcmp_lr : 1500, 1500
|
||||
vcall : 4000, 4000
|
||||
vcmp_rl : 1500, 1500
|
||||
rxb_rb : 1100, 1100
|
||||
rxb_lb : 1100, 1100
|
||||
vcmp_rr : 1500, 1500
|
||||
vcp : 1500, 1500
|
||||
vcn : 2000, 2000
|
||||
vis : 1550, 1550
|
||||
iodelay : 660, 660
|
||||
|
||||
"""
|
||||
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.
|
||||
|
||||
|
||||
# ::
|
||||
|
||||
# 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
|
||||
|
||||
# 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)
|
||||
|
||||
# #Avoid resetting before acq
|
||||
# d.eiger_matrix_reset = False
|
||||
|
||||
# d.acq() #take frame
|
||||
|
||||
# #Restore normal behaviour
|
||||
# d.eiger_matrix_reset = True
|
||||
|
||||
|
||||
# """
|
||||
# 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_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')
|
||||
|
||||
@property
|
||||
def vcmp(self):
|
||||
"""
|
||||
Convenience function to get and set the individual vcmp of chips
|
||||
Used mainly in the calibration code.
|
||||
|
||||
Examples
|
||||
---------
|
||||
|
||||
::
|
||||
|
||||
#Reading
|
||||
d.vcmp[:]
|
||||
>> [500, 500, 500, 500, 500, 500, 500, 500]
|
||||
|
||||
#Setting
|
||||
d.vcmp = [500, 500, 500, 500, 500, 500, 500, 500]
|
||||
|
||||
|
||||
"""
|
||||
|
||||
return self._vcmp
|
||||
|
||||
@vcmp.setter
|
||||
def vcmp(self, values):
|
||||
if len(values) == len(self._vcmp.set):
|
||||
for i, v in enumerate(values):
|
||||
self._vcmp.set[i](v)
|
||||
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
|
||||
|
||||
# ::
|
||||
|
||||
# [0:rx_udpport, 0:rx_udpport2, 1:rx_udpport ...]
|
||||
|
||||
# Examples
|
||||
# -----------
|
||||
|
||||
# ::
|
||||
|
||||
# d.rx_udpport
|
||||
# >> [50010, 50011, 50004, 50005]
|
||||
|
||||
# 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]
|
||||
|
||||
# @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.
|
||||
|
||||
::
|
||||
|
||||
e.rx_zmqport
|
||||
>> [30001, 30002, 30003, 30004]
|
||||
|
||||
|
||||
"""
|
||||
ports = self.getRxZmqPort()
|
||||
return [p + i for p in ports 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)
|
||||
|
||||
# @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]
|
||||
|
||||
|
||||
# """
|
||||
# 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)]
|
||||
|
||||
|
25
python/slsdet/errors.py
Executable file
25
python/slsdet/errors.py
Executable file
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Thu Dec 14 17:13:55 2017
|
||||
|
||||
@author: l_frojdh
|
||||
"""
|
||||
|
||||
|
||||
class DetectorError(Exception):
|
||||
"""
|
||||
This error should be used when something fails
|
||||
on the detector side
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class DetectorSettingDoesNotExist(Exception):
|
||||
"""This error should be used when the setting does not exist"""
|
||||
pass
|
||||
|
||||
|
||||
class DetectorValueError(Exception):
|
||||
"""This error should be used when the set value is outside the allowed range"""
|
||||
pass
|
54
python/slsdet/jungfrau.py
Normal file
54
python/slsdet/jungfrau.py
Normal file
@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
This file contains the specialization for the Jungfrau detector
|
||||
"""
|
||||
|
||||
|
||||
from .detector import Detector, freeze
|
||||
|
||||
# from .adcs import Adc, DetectorAdcs
|
||||
from .dacs import DetectorDacs
|
||||
import _slsdet
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
from .detector_property import DetectorProperty
|
||||
|
||||
# @freeze
|
||||
class JungfrauDacs(DetectorDacs):
|
||||
"""
|
||||
Jungfrau specific DACs
|
||||
"""
|
||||
_dacs = [('vb_comp', dacIndex.VB_COMP, 0, 4000, 1220),
|
||||
('vdd_prot', dacIndex.VDD_PROT, 0, 4000, 3000),
|
||||
('vin_com', dacIndex.VIN_COM, 0, 4000, 1053),
|
||||
('vref_prech', dacIndex.VREF_PRECH, 0, 4000, 1450),
|
||||
('vb_pixbuff', dacIndex.VB_PIXBUF, 0, 4000, 750),
|
||||
('vb_ds', dacIndex.VB_DS, 0, 4000, 1000),
|
||||
('vref_ds', dacIndex.VREF_DS, 0, 4000, 480),
|
||||
('vref_comp', dacIndex.VREF_COMP, 0, 4000, 420),
|
||||
]
|
||||
_dacnames = [_d[0] for _d in _dacs]
|
||||
|
||||
|
||||
|
||||
|
||||
@freeze
|
||||
class Jungfrau(Detector):
|
||||
"""
|
||||
Subclassing Detector to set up correct dacs and detector specific
|
||||
functions.
|
||||
"""
|
||||
_detector_dynamic_range = [4, 8, 16, 32]
|
||||
|
||||
|
||||
_settings = ['standard', 'highgain', 'lowgain', 'veryhighgain', 'verylowgain']
|
||||
"""available settings for Eiger, note almost always standard"""
|
||||
|
||||
def __init__(self, id=0):
|
||||
super().__init__(id)
|
||||
self._frozen = False
|
||||
self._dacs = JungfrauDacs(self)
|
||||
|
||||
@property
|
||||
def dacs(self):
|
||||
return self._dacs
|
9
python/slsdet/lookup.py
Normal file
9
python/slsdet/lookup.py
Normal file
@ -0,0 +1,9 @@
|
||||
from .detector import Detector
|
||||
|
||||
def view(name):
|
||||
names = find(name)
|
||||
for n in names:
|
||||
print(n)
|
||||
|
||||
def find(name):
|
||||
return [n for n in dir(Detector) if name in n]
|
80
python/slsdet/mythen3.py
Normal file
80
python/slsdet/mythen3.py
Normal file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
This file contains the specialization for the Jungfrau detector
|
||||
"""
|
||||
|
||||
|
||||
from .detector import Detector, freeze
|
||||
|
||||
# from .adcs import Adc, DetectorAdcs
|
||||
from .dacs import DetectorDacs
|
||||
import _slsdet
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
from .detector_property import DetectorProperty
|
||||
|
||||
# vcassh 1200,
|
||||
# vth2 2800,
|
||||
# vshaper 1280,
|
||||
# vshaperneg 2800,
|
||||
# vipre_out 1220,
|
||||
# vth3 2800,
|
||||
# vth1 2800,
|
||||
# vicin 1708,
|
||||
# vcas 1800,
|
||||
# vpreamp 1100,
|
||||
# vpl 1100,
|
||||
# vipre 2624,
|
||||
# viinsh 1708,
|
||||
# vph 1712,
|
||||
# vtrim 2800,
|
||||
# vdcsh 800
|
||||
|
||||
|
||||
# @freeze
|
||||
class Mythen3Dacs(DetectorDacs):
|
||||
"""
|
||||
Jungfrau specific DACs
|
||||
"""
|
||||
_dacs = [('vcassh', dacIndex.CASSH, 0, 4000, 1220),
|
||||
('vth2', dacIndex.VTH2, 0, 4000, 2800),
|
||||
('vshaper', dacIndex.SHAPER1, 0, 4000, 1280),
|
||||
('vshaperneg', dacIndex.SHAPER2, 0, 4000, 2800),
|
||||
('vipre_out', dacIndex.VIPRE_OUT, 0, 4000, 1220),
|
||||
('vth3', dacIndex.VTH3, 0, 4000, 2800),
|
||||
('vth1', dacIndex.THRESHOLD, 0, 4000, 2800),
|
||||
('vicin', dacIndex.VICIN, 0, 4000, 1708),
|
||||
('vcas', dacIndex.CAS, 0, 4000, 1800),
|
||||
('vpreamp', dacIndex.PREAMP, 0, 4000, 1100),
|
||||
('vpl', dacIndex.VPL, 0, 4000, 1100),
|
||||
('vipre', dacIndex.VIPRE, 0, 4000, 2624),
|
||||
('viinsh', dacIndex.VIINSH, 0, 4000, 1708),
|
||||
('vph', dacIndex.CALIBRATION_PULSE, 0, 4000, 1712),
|
||||
('vtrim', dacIndex.TRIMBIT_SIZE, 0, 4000, 2800),
|
||||
('vdcsh', dacIndex.VDCSH, 0, 4000, 800),
|
||||
]
|
||||
_dacnames = [_d[0] for _d in _dacs]
|
||||
|
||||
|
||||
|
||||
|
||||
@freeze
|
||||
class Mythen3(Detector):
|
||||
"""
|
||||
Subclassing Detector to set up correct dacs and detector specific
|
||||
functions.
|
||||
"""
|
||||
_detector_dynamic_range = [4, 8, 16, 32]
|
||||
|
||||
|
||||
_settings = ['standard', 'highgain', 'lowgain', 'veryhighgain', 'verylowgain']
|
||||
"""available settings for Eiger, note almost always standard"""
|
||||
|
||||
def __init__(self, id=0):
|
||||
super().__init__(id)
|
||||
self._frozen = False
|
||||
self._dacs = Mythen3Dacs(self)
|
||||
|
||||
@property
|
||||
def dacs(self):
|
||||
return self._dacs
|
19
python/slsdet/registers.py
Executable file
19
python/slsdet/registers.py
Executable file
@ -0,0 +1,19 @@
|
||||
class Register:
|
||||
def __init__(self, detector):
|
||||
self._detector = detector
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._detector.readRegister(key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._detector.writeRegister(key, value)
|
||||
|
||||
class Adc_register:
|
||||
def __init__(self, detector):
|
||||
self._detector = detector
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._detector.writeAdcRegister(key, value)
|
||||
|
||||
def __getitem__(self, key):
|
||||
raise ValueError('Adc registers cannot be read back')
|
71
python/slsdet/utils.py
Executable file
71
python/slsdet/utils.py
Executable file
@ -0,0 +1,71 @@
|
||||
"""
|
||||
Utility functions that are useful for testing and troubleshooting
|
||||
but not directly used in controlling the detector
|
||||
"""
|
||||
|
||||
|
||||
from collections import namedtuple
|
||||
import _slsdet #C++ lib
|
||||
import functools
|
||||
|
||||
|
||||
Geometry = namedtuple('Geometry', ['x', 'y'])
|
||||
|
||||
def get_set_bits(mask):
|
||||
"""
|
||||
Return a list of the set bits in a python integer
|
||||
"""
|
||||
return [i for i in range(mask.bit_length()) if (mask>>i)&1]
|
||||
|
||||
def list_to_bitmask(values):
|
||||
"""
|
||||
Convert a list of integers to a bitmask with set bits
|
||||
where the list indicates
|
||||
"""
|
||||
mask = int(0)
|
||||
values = list(set(values)) #Remove duplicates
|
||||
for v in values:
|
||||
mask += 1 << v
|
||||
return mask
|
||||
|
||||
def to_geo(value):
|
||||
if isinstance(value, _slsdet.xy):
|
||||
return Geometry(x = value.x, y = value.y)
|
||||
else:
|
||||
raise ValueError("Can only convert sls_detector.xy")
|
||||
|
||||
def all_equal(mylist):
|
||||
"""If all elements are equal return true otherwise false"""
|
||||
return all(x == mylist[0] for x in mylist)
|
||||
|
||||
|
||||
def element_if_equal(mylist):
|
||||
"""If all elements are equal return only one element"""
|
||||
if all_equal(mylist):
|
||||
if len(mylist) == 0:
|
||||
return None
|
||||
else:
|
||||
return mylist[0]
|
||||
else:
|
||||
return mylist
|
||||
|
||||
def element(func):
|
||||
"""
|
||||
Wrapper to return either list or element
|
||||
"""
|
||||
@functools.wraps(func)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
return element_if_equal(func(self, *args, **kwargs))
|
||||
return wrapper
|
||||
|
||||
def eiger_register_to_time(register):
|
||||
"""
|
||||
Decode register value and return time in s. Values are stored in
|
||||
a 32bit register with bits 2->0 containing the exponent and bits
|
||||
31->3 containing the significand (int value)
|
||||
|
||||
"""
|
||||
clocks = register >> 3
|
||||
exponent = register & 0b111
|
||||
return clocks*10**exponent / 100e6
|
||||
|
Reference in New Issue
Block a user