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.
* Fliprows
Added fliprows to python API
* Added many commands to python API

View File

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

View File

@ -11,7 +11,7 @@ from .gotthard2 import Gotthard2
from .gotthard import Gotthard
from .moench import Moench
from .pattern import Pattern, patternParameters
from .gaincaps import Mythen3GainCapsWrapper
import _slsdet
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 Geometry, to_geo, element, reduce_time, is_iterable, hostname_list
from _slsdet import xy
from .gaincaps import Mythen3GainCapsWrapper
from . import utils as ut
from .proxy import JsonProxy, SlowAdcProxy, ClkDivProxy, MaxPhaseProxy, ClkFreqProxy, PatLoopProxy, PatNLoopProxy, PatWaitProxy, PatWaitTimeProxy
from .registers import Register, Adc_register
@ -231,7 +232,7 @@ class Detector(CppDetectorApi):
"""
[Jungfrau][Gotthard2][Myhten3][Gotthard][Ctb][Moench] Hardware version of detector.
"""
return ut.lhex(self.getHardwareVersion())
return self.getHardwareVersion()
@property
@element
@ -263,6 +264,12 @@ class Detector(CppDetectorApi):
"""Receiver version """
return self.getReceiverVersion()
@property
@element
def serialnumber(self):
"""Jungfrau][Gotthard][Mythen3][Gotthard2][CTB][Moench] Serial number of detector """
return ut.lhex(self.getSerialNumber())
@property
@element
def rx_threads(self):
@ -462,6 +469,47 @@ class Detector(CppDetectorApi):
def blockingtrigger(self):
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
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."""
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):
"""Starts receiver listener for detector data packets and create a data file (if file write enabled)."""
self.startReceiver()
@ -1732,6 +1784,11 @@ class Detector(CppDetectorApi):
"""Gets the list of timing modes (timingMode) for this detector."""
return self.getTimingModeList()
@property
def readoutspeedlist(self):
"""List of readout speed levels implemented for this detector."""
return self.getReadoutSpeedList()
@property
def templist(self):
"""List of temperature enums (dacIndex) implemented for this detector."""
@ -1833,23 +1890,17 @@ class Detector(CppDetectorApi):
@property
def versions(self):
if self.type == detectorType.EIGER:
return {'type': self.type,
version_list = {'type': self.type,
'package': self.packageversion,
'client': self.clientversion,
'firmware': self.firmwareversion,
'detectorserver': self.detectorserverversion,
'kernel': self.kernelversion,
'receiver': self.rx_version}
return {'type': self.type,
'package': self.packageversion,
'client': self.clientversion,
'firmware': self.firmwareversion,
'detectorserver': self.detectorserverversion,
'hardware':self.hardwareversion,
'kernel': self.kernelversion,
'receiver': self.rx_version}
'kernel': self.kernelversion}
if self.type != detectorType.EIGER:
version_list ['hardware'] = self.hardwareversion
if self.use_receiver:
version_list ['receiver'] = self.rx_version
return version_list
@property
def virtual(self):
@ -3138,6 +3189,17 @@ class Detector(CppDetectorApi):
def dbitclk(self, 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
@element
def dbitpipeline(self):
@ -3748,6 +3810,23 @@ class Detector(CppDetectorApi):
"""
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
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
import _slsdet
dacIndex = _slsdet.slsDetectorDefs.dacIndex
gc_enums = _slsdet.slsDetectorDefs.M3_GainCaps
from .detector_property import DetectorProperty
@ -63,3 +64,5 @@ class Mythen3(Detector):
@property
def dacs(self):
return self._dacs

View File

@ -4,6 +4,7 @@ from .utils import element_if_equal
from .enums import dacIndex
from .defines import M3_MAX_PATTERN_LEVELS, MAX_PATTERN_LEVELS
from _slsdet import slsDetectorDefs
detectorType = slsDetectorDefs.detectorType
def set_proxy_using_dict(func, key, value, unpack = False):
@ -87,7 +88,10 @@ class ClkDivProxy:
def __repr__(self):
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))
if isinstance(r, list):
rstr += ' '.join(f'{item}' for item in r)
@ -96,10 +100,35 @@ class ClkDivProxy:
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:
"""
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):
self.det = det
@ -109,7 +138,9 @@ class MaxPhaseProxy:
def __repr__(self):
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))
if isinstance(r, list):
rstr += ' '.join(f'{item}' for item in r)
@ -120,7 +151,7 @@ class MaxPhaseProxy:
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):
self.det = det
@ -130,7 +161,9 @@ class ClkFreqProxy:
def __repr__(self):
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))
if isinstance(r, list):
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
modeNotImplemented("clock index (divider set)", args[0]);
}
// TODO: if value between to set and num clocks, msg = "cannot set"
enum CLKINDEX c = 0;
int val = args[1];
if (ret == OK) {

View File

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