python additions (#686)

* python: fixed versions when no receiver, added clearbusy, serialnumber and readoutspeedlist. commandline: modified versions to look like python versions

* python: added clkphase, fixed clkdiv, maxphase

* python added adcvpp

* gaincaps for python

---------

Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com>
This commit is contained in:
Dhanya Thattil 2023-02-23 16:29:54 +01:00 committed by GitHub
parent a74c9498e2
commit ed2894dafd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 208 additions and 28 deletions

View File

@ -142,8 +142,7 @@ This document describes the differences between v7.0.0 and v6.1.2
Hostnames concatenated using '+' was not split up in Python API. Fixed. Hostnames concatenated using '+' was not split up in Python API. Fixed.
* Fliprows * Added many commands to python API
Added fliprows to python API

View File

@ -34,6 +34,7 @@ set( PYTHON_FILES
slsdet/eiger.py slsdet/eiger.py
slsdet/enums.py slsdet/enums.py
slsdet/errors.py slsdet/errors.py
slsdet/gaincaps.py
slsdet/gotthard.py slsdet/gotthard.py
slsdet/pattern.py slsdet/pattern.py
slsdet/gotthard2.py slsdet/gotthard2.py

View File

@ -11,7 +11,7 @@ from .gotthard2 import Gotthard2
from .gotthard import Gotthard from .gotthard import Gotthard
from .moench import Moench from .moench import Moench
from .pattern import Pattern, patternParameters from .pattern import Pattern, patternParameters
from .gaincaps import Mythen3GainCapsWrapper
import _slsdet import _slsdet
xy = _slsdet.xy xy = _slsdet.xy

View File

@ -16,6 +16,7 @@ defs = slsDetectorDefs
from .utils import element_if_equal, all_equal, get_set_bits, list_to_bitmask from .utils import element_if_equal, all_equal, get_set_bits, list_to_bitmask
from .utils import Geometry, to_geo, element, reduce_time, is_iterable, hostname_list from .utils import Geometry, to_geo, element, reduce_time, is_iterable, hostname_list
from _slsdet import xy from _slsdet import xy
from .gaincaps import Mythen3GainCapsWrapper
from . import utils as ut from . import utils as ut
from .proxy import JsonProxy, SlowAdcProxy, ClkDivProxy, MaxPhaseProxy, ClkFreqProxy, PatLoopProxy, PatNLoopProxy, PatWaitProxy, PatWaitTimeProxy from .proxy import JsonProxy, SlowAdcProxy, ClkDivProxy, MaxPhaseProxy, ClkFreqProxy, PatLoopProxy, PatNLoopProxy, PatWaitProxy, PatWaitTimeProxy
from .registers import Register, Adc_register from .registers import Register, Adc_register
@ -231,7 +232,7 @@ class Detector(CppDetectorApi):
""" """
[Jungfrau][Gotthard2][Myhten3][Gotthard][Ctb][Moench] Hardware version of detector. [Jungfrau][Gotthard2][Myhten3][Gotthard][Ctb][Moench] Hardware version of detector.
""" """
return ut.lhex(self.getHardwareVersion()) return self.getHardwareVersion()
@property @property
@element @element
@ -263,6 +264,12 @@ class Detector(CppDetectorApi):
"""Receiver version """ """Receiver version """
return self.getReceiverVersion() return self.getReceiverVersion()
@property
@element
def serialnumber(self):
"""Jungfrau][Gotthard][Mythen3][Gotthard2][CTB][Moench] Serial number of detector """
return ut.lhex(self.getSerialNumber())
@property @property
@element @element
def rx_threads(self): def rx_threads(self):
@ -462,6 +469,47 @@ class Detector(CppDetectorApi):
def blockingtrigger(self): def blockingtrigger(self):
self.sendSoftwareTrigger(True) self.sendSoftwareTrigger(True)
@property
@element
def gaincaps(self):
"""
[Mythen3] Gain caps. Enum: M3_GainCaps \n
Note
----
Options: M3_GainCaps, M3_C15sh, M3_C30sh, M3_C50sh, M3_C225ACsh, M3_C15pre
Example
-------
>>> d.gaincaps
C15pre, C30sh
>>> d.gaincaps = M3_GainCaps.M3_C30sh
>>> d.gaincaps
C30sh
>>> d.gaincaps = M3_GainCaps.M3_C30sh | M3_GainCaps.M3_C15sh
>>> d.gaincaps
C15sh, C30sh
"""
res = [Mythen3GainCapsWrapper(it) for it in self.getGainCaps()]
return res
@gaincaps.setter
def gaincaps(self, caps):
#convert to int if called with Wrapper
if isinstance(caps, Mythen3GainCapsWrapper):
self.setGainCaps(caps.value)
elif isinstance(caps, dict):
corr = {}
for key, value in caps.items():
if isinstance(value, Mythen3GainCapsWrapper):
corr[key] = value.value
else:
corr[key] = value
ut.set_using_dict(self.setGainCaps, corr)
else:
self.setGainCaps(caps)
@property @property
def exptime(self): def exptime(self):
""" """
@ -656,6 +704,10 @@ class Detector(CppDetectorApi):
"""Start detector acquisition. Status changes to RUNNING or WAITING and automatically returns to idle at the end of acquisition.""" """Start detector acquisition. Status changes to RUNNING or WAITING and automatically returns to idle at the end of acquisition."""
self.startDetector() self.startDetector()
def clearbusy(self):
"""If acquisition aborted during acquire command, use this to clear acquiring flag in shared memory before starting next acquisition"""
self.clearAcquiringFlag()
def rx_start(self): def rx_start(self):
"""Starts receiver listener for detector data packets and create a data file (if file write enabled).""" """Starts receiver listener for detector data packets and create a data file (if file write enabled)."""
self.startReceiver() self.startReceiver()
@ -1732,6 +1784,11 @@ class Detector(CppDetectorApi):
"""Gets the list of timing modes (timingMode) for this detector.""" """Gets the list of timing modes (timingMode) for this detector."""
return self.getTimingModeList() return self.getTimingModeList()
@property
def readoutspeedlist(self):
"""List of readout speed levels implemented for this detector."""
return self.getReadoutSpeedList()
@property @property
def templist(self): def templist(self):
"""List of temperature enums (dacIndex) implemented for this detector.""" """List of temperature enums (dacIndex) implemented for this detector."""
@ -1833,23 +1890,17 @@ class Detector(CppDetectorApi):
@property @property
def versions(self): def versions(self):
if self.type == detectorType.EIGER: version_list = {'type': self.type,
return {'type': self.type,
'package': self.packageversion, 'package': self.packageversion,
'client': self.clientversion, 'client': self.clientversion,
'firmware': self.firmwareversion, 'firmware': self.firmwareversion,
'detectorserver': self.detectorserverversion, 'detectorserver': self.detectorserverversion,
'kernel': self.kernelversion, 'kernel': self.kernelversion}
'receiver': self.rx_version} if self.type != detectorType.EIGER:
version_list ['hardware'] = self.hardwareversion
return {'type': self.type, if self.use_receiver:
'package': self.packageversion, version_list ['receiver'] = self.rx_version
'client': self.clientversion, return version_list
'firmware': self.firmwareversion,
'detectorserver': self.detectorserverversion,
'hardware':self.hardwareversion,
'kernel': self.kernelversion,
'receiver': self.rx_version}
@property @property
def virtual(self): def virtual(self):
@ -3138,6 +3189,17 @@ class Detector(CppDetectorApi):
def dbitclk(self, value): def dbitclk(self, value):
ut.set_using_dict(self.setDBITClock, value) ut.set_using_dict(self.setDBITClock, value)
@property
@element
def adcvpp(self):
"""[Ctb][Moench] Vpp of ADC. [0 -> 1V | 1 -> 1.14V | 2 -> 1.33V | 3 -> 1.6V | 4 -> 2V] \n
Advanced User function!"""
return self.getADCVpp(False)
@adcvpp.setter
def adcvpp(self, value):
ut.set_using_dict(self.setADCVpp, value, False)
@property @property
@element @element
def dbitpipeline(self): def dbitpipeline(self):
@ -3748,6 +3810,23 @@ class Detector(CppDetectorApi):
""" """
return self.getMeasuredCurrent(dacIndex.I_POWER_IO) return self.getMeasuredCurrent(dacIndex.I_POWER_IO)
@property
def clkphase(self):
"""
[Gotthard2][Mythen3] Phase shift of all clocks.
Example
-------
>>> d.clkphase[0] = 20
>>> d.clkphase
0: 20
1: 10
2: 20
3: 10
4: 10
5: 5
"""
return ClkPhaseProxy(self)
@property @property
def clkdiv(self): def clkdiv(self):

42
python/slsdet/gaincaps.py Normal file
View File

@ -0,0 +1,42 @@
import _slsdet
gc = _slsdet.slsDetectorDefs.M3_GainCaps
class Mythen3GainCapsWrapper:
"""Holds M3_GainCaps enums and facilitates printing"""
# 'M3_C10pre', 'M3_C15pre', 'M3_C15sh', 'M3_C225ACsh', 'M3_C30sh', 'M3_C50sh'
all_bits = gc.M3_C10pre | gc.M3_C15pre | gc.M3_C15sh | gc.M3_C225ACsh | gc.M3_C30sh | gc.M3_C50sh
all_caps = (gc.M3_C10pre, gc.M3_C15pre, gc.M3_C15sh, gc.M3_C225ACsh, gc.M3_C30sh, gc.M3_C50sh)
def __init__(self, value = 0):
self._validate(value)
self.value = value
def __eq__(self, other) -> bool:
if isinstance(other, Mythen3GainCapsWrapper):
return self.value == other.value
else:
return self.value == other
def __ne__(self, other) -> bool:
return not self.__eq__(other)
def __str__(self) -> str:
s = ', '.join(str(c).rsplit('_', 1)[1] for c in self.all_caps if self.value & c)
return s
def __repr__(self) -> str:
return self.__str__()
def _validate(self, value):
"""Check that only bits representing real capacitors are set"""
if isinstance(value, gc):
return True
elif isinstance(value, int):
if value & (~self.all_bits):
raise ValueError(f"The value: {value} is not allowed for Mythen3GainCapsWrapper")
else:
raise ValueError("GainCaps can only be initialized from int or M3_GainCaps enum")

View File

@ -13,6 +13,7 @@ from .detector import Detector, freeze
from .dacs import DetectorDacs from .dacs import DetectorDacs
import _slsdet import _slsdet
dacIndex = _slsdet.slsDetectorDefs.dacIndex dacIndex = _slsdet.slsDetectorDefs.dacIndex
gc_enums = _slsdet.slsDetectorDefs.M3_GainCaps
from .detector_property import DetectorProperty from .detector_property import DetectorProperty
@ -62,4 +63,6 @@ class Mythen3(Detector):
@property @property
def dacs(self): def dacs(self):
return self._dacs return self._dacs

View File

@ -4,6 +4,7 @@ from .utils import element_if_equal
from .enums import dacIndex from .enums import dacIndex
from .defines import M3_MAX_PATTERN_LEVELS, MAX_PATTERN_LEVELS from .defines import M3_MAX_PATTERN_LEVELS, MAX_PATTERN_LEVELS
from _slsdet import slsDetectorDefs from _slsdet import slsDetectorDefs
detectorType = slsDetectorDefs.detectorType
def set_proxy_using_dict(func, key, value, unpack = False): def set_proxy_using_dict(func, key, value, unpack = False):
@ -87,7 +88,10 @@ class ClkDivProxy:
def __repr__(self): def __repr__(self):
rstr = '' rstr = ''
for i in range(6): num_clocks = 6
if self.det.type == detectorType.MYTHEN3:
num_clocks = 5
for i in range(num_clocks):
r = element_if_equal(self.__getitem__(i)) r = element_if_equal(self.__getitem__(i))
if isinstance(r, list): if isinstance(r, list):
rstr += ' '.join(f'{item}' for item in r) rstr += ' '.join(f'{item}' for item in r)
@ -96,10 +100,35 @@ class ClkDivProxy:
return rstr.strip('\n') return rstr.strip('\n')
class ClkPhaseProxy:
"""
Proxy class to allow for more intuitive reading clock phase
"""
def __init__(self, det):
self.det = det
def __getitem__(self, key):
return element_if_equal(self.det.getClockPhase(key))
def __setitem__(self, key, value):
set_proxy_using_dict(self.det.setClockPhase, key, value)
def __repr__(self):
rstr = ''
if self.det.type == detectorType.MYTHEN3:
num_clocks = 5
for i in range(num_clocks):
r = element_if_equal(self.__getitem__(i))
if isinstance(r, list):
rstr += ' '.join(f'{item}' for item in r)
else:
rstr += f'{i}: {r}\n'
return rstr.strip('\n')
class MaxPhaseProxy: class MaxPhaseProxy:
""" """
Proxy class to allow for more intuitive reading clockdivider Proxy class to allow for more intuitive reading max clock phase shift
""" """
def __init__(self, det): def __init__(self, det):
self.det = det self.det = det
@ -109,7 +138,9 @@ class MaxPhaseProxy:
def __repr__(self): def __repr__(self):
rstr = '' rstr = ''
for i in range(5): if self.det.type == detectorType.MYTHEN3:
num_clocks = 5
for i in range(num_clocks):
r = element_if_equal(self.__getitem__(i)) r = element_if_equal(self.__getitem__(i))
if isinstance(r, list): if isinstance(r, list):
rstr += ' '.join(f'{item}' for item in r) rstr += ' '.join(f'{item}' for item in r)
@ -120,7 +151,7 @@ class MaxPhaseProxy:
class ClkFreqProxy: class ClkFreqProxy:
""" """
Proxy class to allow for more intuitive reading clockdivider Proxy class to allow for more intuitive reading clock frequency
""" """
def __init__(self, det): def __init__(self, det):
self.det = det self.det = det
@ -130,7 +161,9 @@ class ClkFreqProxy:
def __repr__(self): def __repr__(self):
rstr = '' rstr = ''
for i in range(5): if self.det.type == detectorType.MYTHEN3:
num_clocks = 5
for i in range(num_clocks):
r = element_if_equal(self.__getitem__(i)) r = element_if_equal(self.__getitem__(i))
if isinstance(r, list): if isinstance(r, list):
rstr += ' '.join(f'{item}' for item in r) rstr += ' '.join(f'{item}' for item in r)

View File

@ -0,0 +1,24 @@
import pytest
from slsdet import Mythen3GainCapsWrapper
from slsdet.enums import M3_GainCaps #this is the c++ enum
def test_comapre_with_int():
c = Mythen3GainCapsWrapper(128) #C10pre
assert c == 128
assert c != 5
assert c != 1280
def test_compare_with_other():
a = Mythen3GainCapsWrapper(128)
b = Mythen3GainCapsWrapper(1<<10)
c = Mythen3GainCapsWrapper(128)
assert a!=b
assert (a==b) == False
assert a==c
def test_can_be_default_constructed():
c = Mythen3GainCapsWrapper()
assert c == 0

View File

@ -6013,7 +6013,7 @@ int set_clock_divider(int file_des) {
#endif #endif
modeNotImplemented("clock index (divider set)", args[0]); modeNotImplemented("clock index (divider set)", args[0]);
} }
// TODO: if value between to set and num clocks, msg = "cannot set"
enum CLKINDEX c = 0; enum CLKINDEX c = 0;
int val = args[1]; int val = args[1];
if (ret == OK) { if (ret == OK) {

View File

@ -287,13 +287,12 @@ std::string CmdProxy::Versions(int action) {
os << OutStringHex(t); os << OutStringHex(t);
} }
os << "\nServer : " os << "\nServer : "
<< OutString( << OutString(det->getDetectorServerVersion(std::vector<int>{det_id}))
det->getDetectorServerVersion(std::vector<int>{det_id})); << "\nKernel : "
<< OutString(det->getKernelVersion({std::vector<int>{det_id}}));
if (!eiger) if (!eiger)
os << "\nHardware : " os << "\nHardware : "
<< OutString(det->getHardwareVersion(std::vector<int>{det_id})); << OutString(det->getHardwareVersion(std::vector<int>{det_id}));
os << "\nKernel : "
<< OutString(det->getKernelVersion({std::vector<int>{det_id}}));
if (det->getUseReceiverFlag().squash(true)) { if (det->getUseReceiverFlag().squash(true)) {
os << "\nReceiver : " os << "\nReceiver : "
<< OutString(det->getReceiverVersion(std::vector<int>{det_id})); << OutString(det->getReceiverVersion(std::vector<int>{det_id}));