From 9b26f5a6c8afbe88f1b909627590d4b09ffa0c59 Mon Sep 17 00:00:00 2001 From: Erik Frojdh Date: Thu, 20 Aug 2020 09:21:59 +0200 Subject: [PATCH 1/5] added python examples in source --- docs/src/pyexamples.rst | 56 +++++++++---------- .../examples/non-blocking-acquire-process.py | 21 +++++++ python/examples/non-blocking-acquire.py | 33 +++++++++++ 3 files changed, 80 insertions(+), 30 deletions(-) create mode 100644 python/examples/non-blocking-acquire-process.py create mode 100644 python/examples/non-blocking-acquire.py diff --git a/docs/src/pyexamples.rst b/docs/src/pyexamples.rst index ad3f67865..781145c12 100755 --- a/docs/src/pyexamples.rst +++ b/docs/src/pyexamples.rst @@ -74,34 +74,38 @@ But lets start looking at the at the manual way: :: import time - from slsdet import Eiger, runStatus - d = Eiger() - - n = 10 - t = 1 - - d.exptime = t - d.frames = n + from slsdet import Detector, runStatus - #Start the measurement + n_frames = 10 + t_exp = 1 + + # Set exposure time and number of frames + d = Detector() + d.exptime = t_exp + d.frames = n_frames + + # Start the measurement t0 = time.time() d.startDetector() d.startReceiver() - #Wait for the detector to be ready or do other important stuff - time.sleep(t*n) + # Wait for the detector to be ready or do other important stuff + time.sleep(t_exp * n_frames) - #check if the detector is ready otherwise wait a bit longer + # check if the detector is ready otherwise wait a bit longer while d.status != runStatus.IDLE: time.sleep(0.1) - #Stop the receiver after we got the frames - #Detector is already idle so we don't need to stop it + # Stop the receiver after we got the frames + # Detector is already idle so we don't need to stop it d.stopReceiver() - lost = d.rx_framescaught - n - print(f'{n} frames of {t}s took {time.time()-t0:{.3}}s with {lost} frames lost ') + lost = d.rx_framescaught - n_frames + print( + f"{n_frames} frames of {t_exp}s took {time.time()-t0:{.3}}s with {lost} frames lost " + ) + Instead launching d.acq() from a different process is a bit easier since the control of receiver and detector @@ -112,29 +116,21 @@ hang around until the main process exits. import time from multiprocessing import Process - from slsdet import Eiger + from slsdet import Detector, runStatus - def acquire(): - """ - Create a new Eiger object that still referes to the same actual detector - and same shared memory. Then launch acq. - """ - detector = Eiger() - detector.acq() - #This is the detector we use throughout the session - d = Eiger() + d = Detector() - #Process to run acquire - p = Process(target=acquire) + #Create a separate process to run acquire in + p = Process(target=d.acquire) #Start the thread and short sleep to allow the acq to start p.start() time.sleep(0.01) #Do some other work - while d.busy is True: - print(d.busy) + while d.status != runStatus.IDLE: + print("Working") time.sleep(0.1) #Join the process diff --git a/python/examples/non-blocking-acquire-process.py b/python/examples/non-blocking-acquire-process.py new file mode 100644 index 000000000..486a3dd93 --- /dev/null +++ b/python/examples/non-blocking-acquire-process.py @@ -0,0 +1,21 @@ +import time +from multiprocessing import Process +from slsdet import Detector, runStatus + + +d = Detector() + +#Create a separate process to run acquire in +p = Process(target=d.acquire) + +#Start the thread and short sleep to allow the acq to start +p.start() +time.sleep(0.01) + +#Do some other work +while d.status != runStatus.IDLE: + print("Working") + time.sleep(0.1) + +#Join the process +p.join() \ No newline at end of file diff --git a/python/examples/non-blocking-acquire.py b/python/examples/non-blocking-acquire.py new file mode 100644 index 000000000..dd434b2a0 --- /dev/null +++ b/python/examples/non-blocking-acquire.py @@ -0,0 +1,33 @@ +import time +from slsdet import Detector, runStatus + + +n_frames = 10 +t_exp = 1 + +# Set exposure time and number of frames +d = Detector() +d.exptime = t_exp +d.frames = n_frames + +# Start the measurement +t0 = time.time() +d.startDetector() +d.startReceiver() + +# Wait for the detector to be ready or do other important stuff +time.sleep(t_exp * n_frames) + +# check if the detector is ready otherwise wait a bit longer +while d.status != runStatus.IDLE: + time.sleep(0.1) + +# Stop the receiver after we got the frames +# Detector is already idle so we don't need to stop it +d.stopReceiver() + +lost = d.rx_framescaught - n_frames +print( + f"{n_frames} frames of {t_exp}s took {time.time()-t0:{.3}}s with {lost} frames lost " +) + From a7cc2b38d86cc1c0279cb0dd5dbcaaddee956ee1 Mon Sep 17 00:00:00 2001 From: Erik Frojdh Date: Thu, 20 Aug 2020 11:46:35 +0200 Subject: [PATCH 2/5] temperature reading for eiger --- python/CMakeLists.txt | 1 + python/examples/threshold_scan.py | 8 + python/scripts/basic.py | 2 +- python/slsdet/adcs.py | 30 ++-- python/slsdet/dacs.py | 3 +- python/slsdet/eiger.py | 247 ++++-------------------------- python/slsdet/temperature.py | 49 ++++++ 7 files changed, 114 insertions(+), 226 deletions(-) create mode 100644 python/examples/threshold_scan.py create mode 100644 python/slsdet/temperature.py diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index a6478c3d1..53e82dd55 100755 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -35,6 +35,7 @@ set( PYTHON_FILES jungfrau.py mythen3.py registers.py + temperature.py lookup.py utils.py diff --git a/python/examples/threshold_scan.py b/python/examples/threshold_scan.py new file mode 100644 index 000000000..6505b64b3 --- /dev/null +++ b/python/examples/threshold_scan.py @@ -0,0 +1,8 @@ +from slsdet import Eiger + +d = Eiger() +threshold = range(0, 2000, 200) +for th in threshold: + print(f'{th=}') + d.vthreshold = th + d.acquire() \ No newline at end of file diff --git a/python/scripts/basic.py b/python/scripts/basic.py index 5c92b32c3..e7feeced0 100755 --- a/python/scripts/basic.py +++ b/python/scripts/basic.py @@ -8,7 +8,7 @@ from slsdet import dacIndex, readoutMode from slsdet.lookup import view, find d = Detector() -# e = Eiger() +e = Eiger() c = Ctb() # j = Jungfrau() # m = Mythen3() diff --git a/python/slsdet/adcs.py b/python/slsdet/adcs.py index f8df51b37..9534a38cb 100755 --- a/python/slsdet/adcs.py +++ b/python/slsdet/adcs.py @@ -1,23 +1,33 @@ from functools import partial class Adc: - def __init__(self, name, detector): + def __init__(self, name, enum, detector): self.name = name + self.enum = enum self._detector = detector - self.get_nmod = self._detector._api.getNumberOfDetectors + self.get_nmod = self._detector.size # Bind functions to get and set the dac - self.get = partial(self._detector._api.getAdc, self.name) - + self.get = partial(self._detector.getAdc, self.enum) + 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())] + return self.get() elif isinstance(key, Iterable): - return [self.get(k) / 1000 for k in key] + return self.get(list(key)) else: - return self.get(key) / 1000 + return self.get([key])[0] #No list for single value + + + # 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""" diff --git a/python/slsdet/dacs.py b/python/slsdet/dacs.py index a6d6142ae..2a083b727 100755 --- a/python/slsdet/dacs.py +++ b/python/slsdet/dacs.py @@ -34,8 +34,7 @@ class Dac(DetectorProperty): 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] diff --git a/python/slsdet/eiger.py b/python/slsdet/eiger.py index c19213cb1..a6304dd61 100755 --- a/python/slsdet/eiger.py +++ b/python/slsdet/eiger.py @@ -9,7 +9,7 @@ Created on Wed Dec 6 11:51:18 2017 from .detector import Detector -# from .adcs import Adc, DetectorAdcs +from .temperature import Temperature, DetectorTemperature from .dacs import DetectorDacs import _slsdet dacIndex = _slsdet.slsDetectorDefs.dacIndex @@ -79,58 +79,6 @@ class EigerDacs(DetectorDacs): ('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 @@ -152,76 +100,18 @@ class Eiger(Detector): self._dacs = EigerDacs(self) self._vcmp = EigerVcmp(self) - # self._active = DetectorProperty(self.getActive, - # self.setActive, - # self.size, - # 'active') + # Eiger specific adcs + self._temp = DetectorTemperature() + self._temp.fpga = Temperature('temp_fpga', dacIndex.TEMPERATURE_FPGA, self) + self._temp.fpgaext = Temperature('temp_fpgaext', dacIndex.TEMPERATURE_FPGAEXT, self) + self._temp.t10ge = Temperature('temp_10ge', dacIndex.TEMPERATURE_10GE, self) + self._temp.dcdc = Temperature('temp_dcdc', dacIndex.TEMPERATURE_DCDC, self) + self._temp.sodl = Temperature('temp_sodl', dacIndex.TEMPERATURE_SODL, self) + self._temp.sodr = Temperature('temp_sodl', dacIndex.TEMPERATURE_SODR, self) + self._temp.temp_fpgafl = Temperature('temp_fpgafl', dacIndex.TEMPERATURE_FPGA2, self) + self._temp.temp_fpgafr = Temperature('temp_fpgafr', dacIndex.TEMPERATURE_FPGA3, 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) - # @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): @@ -284,68 +174,6 @@ 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. - - -# :: - -# 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): @@ -437,40 +265,33 @@ class Eiger(Detector): # else: # self._api.setReceiverStreamingPort(port, -1) -# @property -# def temp(self): -# """ -# An instance of DetectorAdcs used to read the temperature -# of different components + @property + def temp(self): + """ + An instance of DetectorAdcs used to read the temperature + of different components -# Examples -# ----------- + 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 + 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 - - - -# 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 diff --git a/python/slsdet/temperature.py b/python/slsdet/temperature.py new file mode 100644 index 000000000..08d1b5f47 --- /dev/null +++ b/python/slsdet/temperature.py @@ -0,0 +1,49 @@ +from functools import partial +from collections.abc import Iterable +class Temperature: + def __init__(self, name, enum, detector): + self.name = name + self.enum = enum + self._detector = detector + self.get_nmod = self._detector.size + # Bind functions to get and set the dac + self.get = partial(self._detector.getTemperature, self.enum) + + 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 __repr__(self): + """String representation for a single temperature 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()) + # ] + tempstr = ''.join([f'{item:5d}{degree_sign}C' for item in self.get()]) + return f'{self.name:15s}:{tempstr}' + # return "".join(r_str).strip(", ") + + +class DetectorTemperature: + """ + Interface to temperatures on the readout board + """ + + def __iter__(self): + for attr, value in self.__dict__.items(): + yield value + + def __repr__(self): + """String representation of all temps all mods""" + r_str = '\n'.join([repr(temp) for temp in self]) + return r_str + # dacstr = ''.join([f'{item:5d}' for item in self.get()]) + # return f'{self.__name__:10s}:{dacstr}' + # return "\n".join([str(t) for t in self]) + From 8ef6f32be6ff9606b21577b5ce85495d97f030ad Mon Sep 17 00:00:00 2001 From: Erik Frojdh Date: Thu, 20 Aug 2020 12:19:35 +0200 Subject: [PATCH 3/5] example and updated python bindings --- docs/src/pyexamples.rst | 33 ++++++++++++++- python/src/detector.cpp | 92 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 113 insertions(+), 12 deletions(-) diff --git a/docs/src/pyexamples.rst b/docs/src/pyexamples.rst index 781145c12..5685040e6 100755 --- a/docs/src/pyexamples.rst +++ b/docs/src/pyexamples.rst @@ -134,4 +134,35 @@ hang around until the main process exits. time.sleep(0.1) #Join the process - p.join() \ No newline at end of file + p.join() + + +------------------------------ +Setting and getting times +------------------------------ + +:: + + import datetime as dt + from slsdet import Detector + + d = Detector() + + # The simplest way is to set the exposure time in + # seconds by using the exptime property + # This sets the exposure time for all modules + d.exptime = 0.5 + + # exptime also accepts a python datetime.timedelta + # which can be used to set the time in almost any unit + + t = dt.timedelta(milliseconds = 2.3) + d.exptime = t + + # or combination of units + t = dt.timedelta(minutes = 3, seconds = 1.23) + d.exptime = t + + #exptime however always returns the time in seconds + >>> d.exptime + 181.23 \ No newline at end of file diff --git a/python/src/detector.cpp b/python/src/detector.cpp index 00300df96..022d0b479 100644 --- a/python/src/detector.cpp +++ b/python/src/detector.cpp @@ -180,6 +180,14 @@ void init_det(py::module &m) { (Result(Detector::*)(sls::Positions) const) & Detector::getDelayAfterTriggerLeft, py::arg() = Positions{}) + .def("getDynamicRange", + (Result(Detector::*)(sls::Positions) const) & + Detector::getDynamicRange, + py::arg() = Positions{}) + .def("setDynamicRange", + (void (Detector::*)(int)) & Detector::setDynamicRange, py::arg()) + .def("getDynamicRangeList", (std::vector(Detector::*)() const) & + Detector::getDynamicRangeList) .def("getTimingMode", (Result(Detector::*)(sls::Positions) const) & Detector::getTimingMode, @@ -188,6 +196,9 @@ void init_det(py::module &m) { (void (Detector::*)(defs::timingMode, sls::Positions)) & Detector::setTimingMode, py::arg(), py::arg() = Positions{}) + .def("getTimingModeList", + (std::vector(Detector::*)() const) & + Detector::getTimingModeList) .def("getSpeed", (Result(Detector::*)(sls::Positions) const) & Detector::getSpeed, @@ -364,6 +375,18 @@ void init_det(py::module &m) { (void (Detector::*)(sls::Positions)) & Detector::sendSoftwareTrigger, py::arg() = Positions{}) + .def("getScan", + (Result(Detector::*)(sls::Positions) const) & + Detector::getScan, + py::arg() = Positions{}) + .def("setScan", + (void (Detector::*)(const defs::scanParameters)) & + Detector::setScan, + py::arg()) + .def("getScanErrorMessage", + (Result(Detector::*)(sls::Positions) const) & + Detector::getScanErrorMessage, + py::arg() = Positions{}) .def("getNumberofUDPInterfaces", (Result(Detector::*)(sls::Positions) const) & Detector::getNumberofUDPInterfaces, @@ -458,6 +481,14 @@ void init_det(py::module &m) { .def("setDestinationUDPPort2", (void (Detector::*)(int, int)) & Detector::setDestinationUDPPort2, py::arg(), py::arg()) + .def("reconfigureUDPDestination", + (void (Detector::*)(sls::Positions)) & + Detector::reconfigureUDPDestination, + py::arg() = Positions{}) + .def("validateUDPConfiguration", + (void (Detector::*)(sls::Positions)) & + Detector::validateUDPConfiguration, + py::arg() = Positions{}) .def("printRxConfiguration", (Result(Detector::*)(sls::Positions) const) & Detector::printRxConfiguration, @@ -670,6 +701,14 @@ void init_det(py::module &m) { (void (Detector::*)(int, sls::Positions)) & Detector::setRxZmqTimer, py::arg(), py::arg() = Positions{}) + .def("getRxZmqStartingFrame", + (Result(Detector::*)(sls::Positions) const) & + Detector::getRxZmqStartingFrame, + py::arg() = Positions{}) + .def("setRxZmqStartingFrame", + (void (Detector::*)(int, sls::Positions)) & + Detector::setRxZmqStartingFrame, + py::arg(), py::arg() = Positions{}) .def("getRxZmqPort", (Result(Detector::*)(sls::Positions) const) & Detector::getRxZmqPort, @@ -700,12 +739,6 @@ void init_det(py::module &m) { (void (Detector::*)(const sls::IpAddr, sls::Positions)) & Detector::setClientZmqIp, py::arg(), py::arg() = Positions{}) - .def("getDynamicRange", - (Result(Detector::*)(sls::Positions) const) & - Detector::getDynamicRange, - py::arg() = Positions{}) - .def("setDynamicRange", - (void (Detector::*)(int)) & Detector::setDynamicRange, py::arg()) .def("getSubExptime", (Result(Detector::*)(sls::Positions) const) & Detector::getSubExptime, @@ -939,11 +972,11 @@ void init_det(py::module &m) { (void (Detector::*)(const int, const int, sls::Positions)) & Detector::setInjectChannel, py::arg(), py::arg(), py::arg() = Positions{}) - .def( - "getVetoPhoton", - (Result>(Detector::*)(const int, sls::Positions)) & - Detector::getVetoPhoton, - py::arg(), py::arg() = Positions{}) + .def("getVetoPhoton", + (void (Detector::*)(const int, const std::string &, + sls::Positions)) & + Detector::getVetoPhoton, + py::arg(), py::arg(), py::arg() = Positions{}) .def("setVetoPhoton", (void (Detector::*)(const int, const int, const int, const std::string &, sls::Positions)) & @@ -954,6 +987,11 @@ void init_det(py::module &m) { (void (Detector::*)(const int, const int, sls::Positions)) & Detector::setVetoReference, py::arg(), py::arg(), py::arg() = Positions{}) + .def("setVetoFile", + (void (Detector::*)(const int, const std::string &, + sls::Positions)) & + Detector::setVetoFile, + py::arg(), py::arg(), py::arg() = Positions{}) .def("getBurstMode", (Result(Detector::*)(sls::Positions)) & Detector::getBurstMode, @@ -962,6 +1000,20 @@ void init_det(py::module &m) { (void (Detector::*)(defs::burstMode, sls::Positions)) & Detector::setBurstMode, py::arg(), py::arg() = Positions{}) + .def("getCDSGain", + (Result(Detector::*)(sls::Positions) const) & + Detector::getCDSGain, + py::arg() = Positions{}) + .def("setCDSGain", + (void (Detector::*)(bool, sls::Positions)) & Detector::setCDSGain, + py::arg(), py::arg() = Positions{}) + .def("getFilter", + (Result(Detector::*)(sls::Positions) const) & + Detector::getFilter, + py::arg() = Positions{}) + .def("setFilter", + (void (Detector::*)(int, sls::Positions)) & Detector::setFilter, + py::arg(), py::arg() = Positions{}) .def("getCurrentSource", (Result(Detector::*)(sls::Positions) const) & Detector::getCurrentSource, @@ -987,6 +1039,24 @@ void init_det(py::module &m) { (void (Detector::*)(const bool, sls::Positions)) & Detector::setVeto, py::arg(), py::arg() = Positions{}) + .def("getADCConfiguration", + (Result(Detector::*)(const int, const int, sls::Positions) + const) & + Detector::getADCConfiguration, + py::arg(), py::arg(), py::arg() = Positions{}) + .def("setADCConfiguration", + (void (Detector::*)(const int, const int, const int, + sls::Positions)) & + Detector::setADCConfiguration, + py::arg(), py::arg(), py::arg(), py::arg() = Positions{}) + .def("getBadChannels", + (void (Detector::*)(const std::string &, sls::Positions) const) & + Detector::getBadChannels, + py::arg(), py::arg() = Positions{}) + .def("setBadChannels", + (void (Detector::*)(const std::string &, sls::Positions)) & + Detector::setBadChannels, + py::arg(), py::arg() = Positions{}) .def("getCounterMask", (Result(Detector::*)(sls::Positions) const) & Detector::getCounterMask, From 1f811dfabd562b2993935002f24396bbda29aea2 Mon Sep 17 00:00:00 2001 From: Erik Frojdh Date: Thu, 20 Aug 2020 12:22:49 +0200 Subject: [PATCH 4/5] added examples --- python/examples/exposure_time.py | 30 ++++++++++++++++++++++++++ python/examples/reading_temperature.py | 13 +++++++++++ 2 files changed, 43 insertions(+) create mode 100644 python/examples/exposure_time.py create mode 100644 python/examples/reading_temperature.py diff --git a/python/examples/exposure_time.py b/python/examples/exposure_time.py new file mode 100644 index 000000000..05ad9b14f --- /dev/null +++ b/python/examples/exposure_time.py @@ -0,0 +1,30 @@ +""" +Example showing how to set and get exposure times +""" + +import datetime as dt +from slsdet import Detector + + + +d = Detector() + + +# The simplest way is to set the exposure time in +# seconds by using the exptime property +# This sets the exposure time for all modules +d.exptime = 0.5 + +# exptime also accepts a python datetime.timedelta +# which can be used to set the time in almost any unit + +t = dt.timedelta(milliseconds = 2.3) +d.exptime = t + +# or combination of units +t = dt.timedelta(minutes = 3, seconds = 1.23) +d.exptime = t + +#exptime however always returns the time in seconds +# >>> d.exptime +# 181.23 \ No newline at end of file diff --git a/python/examples/reading_temperature.py b/python/examples/reading_temperature.py new file mode 100644 index 000000000..d3afb32eb --- /dev/null +++ b/python/examples/reading_temperature.py @@ -0,0 +1,13 @@ +from slsdet import Detector, Eiger, dacIndex + + + +#Using the general detector class and calling with an index +d = Detector() +fpga_temp = d.getTemperature(dacIndex.TEMPERATURE_FPGA) +print(f'fpga_temp: {fpga_temp}\n') + +#Using the specialized detector class +e = Eiger() +print("All temperatures for Eiger\n") +print(e.temp) From f6cde374c4aab5c69eb61c6d949d122df5b349fb Mon Sep 17 00:00:00 2001 From: Erik Frojdh Date: Thu, 20 Aug 2020 12:27:30 +0200 Subject: [PATCH 5/5] WIP --- python/slsdet/eiger.py | 5 ----- python/slsdet/temperature.py | 17 +++++------------ 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/python/slsdet/eiger.py b/python/slsdet/eiger.py index a6304dd61..3e45b1e1d 100755 --- a/python/slsdet/eiger.py +++ b/python/slsdet/eiger.py @@ -6,22 +6,17 @@ Created on Wed Dec 6 11:51:18 2017 @author: l_frojdh """ - from .detector import Detector - from .temperature import Temperature, DetectorTemperature 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 diff --git a/python/slsdet/temperature.py b/python/slsdet/temperature.py index 08d1b5f47..ed30e70fe 100644 --- a/python/slsdet/temperature.py +++ b/python/slsdet/temperature.py @@ -1,6 +1,8 @@ from functools import partial from collections.abc import Iterable class Temperature: + degree_sign = u"\N{DEGREE SIGN}" + def __init__(self, name, enum, detector): self.name = name self.enum = enum @@ -19,16 +21,9 @@ class Temperature: def __repr__(self): """String representation for a single temperature 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()) - # ] - tempstr = ''.join([f'{item:5d}{degree_sign}C' for item in self.get()]) + + tempstr = ''.join([f'{item:5d}{self.degree_sign}C' for item in self.get()]) return f'{self.name:15s}:{tempstr}' - # return "".join(r_str).strip(", ") - class DetectorTemperature: """ @@ -43,7 +38,5 @@ class DetectorTemperature: """String representation of all temps all mods""" r_str = '\n'.join([repr(temp) for temp in self]) return r_str - # dacstr = ''.join([f'{item:5d}' for item in self.get()]) - # return f'{self.__name__:10s}:{dacstr}' - # return "\n".join([str(t) for t in self]) +