diff --git a/RELEASE.txt b/RELEASE.txt index decdbefab..1a98d6911 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -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 diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 51bb92de7..ae05bbf99 100755 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -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 diff --git a/python/slsdet/__init__.py b/python/slsdet/__init__.py index cf03a8a4e..09568cbd1 100755 --- a/python/slsdet/__init__.py +++ b/python/slsdet/__init__.py @@ -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 diff --git a/python/slsdet/detector.py b/python/slsdet/detector.py index c4a30370a..daa16cc69 100755 --- a/python/slsdet/detector.py +++ b/python/slsdet/detector.py @@ -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): diff --git a/python/slsdet/gaincaps.py b/python/slsdet/gaincaps.py new file mode 100644 index 000000000..ab3acd381 --- /dev/null +++ b/python/slsdet/gaincaps.py @@ -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") \ No newline at end of file diff --git a/python/slsdet/mythen3.py b/python/slsdet/mythen3.py index b018699df..369d6ac99 100644 --- a/python/slsdet/mythen3.py +++ b/python/slsdet/mythen3.py @@ -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 @@ -62,4 +63,6 @@ class Mythen3(Detector): @property def dacs(self): - return self._dacs \ No newline at end of file + return self._dacs + + diff --git a/python/slsdet/proxy.py b/python/slsdet/proxy.py index a02a3267a..90c9f4523 100644 --- a/python/slsdet/proxy.py +++ b/python/slsdet/proxy.py @@ -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) diff --git a/python/tests/test_m3gaincaps.py b/python/tests/test_m3gaincaps.py new file mode 100644 index 000000000..d1e5e4bcc --- /dev/null +++ b/python/tests/test_m3gaincaps.py @@ -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 + diff --git a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c index 943018db6..577460c6a 100644 --- a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c +++ b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c @@ -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) { diff --git a/slsDetectorSoftware/src/CmdProxy.cpp b/slsDetectorSoftware/src/CmdProxy.cpp index 5fa8adeee..b40c48ff7 100644 --- a/slsDetectorSoftware/src/CmdProxy.cpp +++ b/slsDetectorSoftware/src/CmdProxy.cpp @@ -287,13 +287,12 @@ std::string CmdProxy::Versions(int action) { os << OutStringHex(t); } os << "\nServer : " - << OutString( - det->getDetectorServerVersion(std::vector{det_id})); + << OutString(det->getDetectorServerVersion(std::vector{det_id})) + << "\nKernel : " + << OutString(det->getKernelVersion({std::vector{det_id}})); if (!eiger) os << "\nHardware : " << OutString(det->getHardwareVersion(std::vector{det_id})); - os << "\nKernel : " - << OutString(det->getKernelVersion({std::vector{det_id}})); if (det->getUseReceiverFlag().squash(true)) { os << "\nReceiver : " << OutString(det->getReceiverVersion(std::vector{det_id}));