from _sls_detector import CppDetectorApi from _sls_detector import slsDetectorDefs runStatus = slsDetectorDefs.runStatus speedLevel = slsDetectorDefs.speedLevel dacIndex = slsDetectorDefs.dacIndex from .utils import element_if_equal, all_equal from .utils import Geometry, to_geo import datetime as dt from functools import wraps from collections import namedtuple class Register: """ Helper class to read and write to registers using a more Pythonic syntax """ 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) def freeze(cls): cls.__frozen = False def frozensetattr(self, key, value): if self.__frozen and not hasattr(self, key): raise AttributeError( "Class {} is frozen. Cannot set {} = {}".format( cls.__name__, key, value ) ) else: object.__setattr__(self, key, value) def init_decorator(func): @wraps(func) def wrapper(self, *args, **kwargs): func(self, *args, **kwargs) self.__frozen = True return wrapper cls.__setattr__ = frozensetattr cls.__init__ = init_decorator(cls.__init__) return cls @freeze class Detector(CppDetectorApi): """ This class is the base for detector specific interfaces. Most functions exists in two versions like the getExptime() function that uses the C++ API directly and the simplified exptime property. """ def __init__(self, multi_id=0): """ multi_id refers to the shared memory id of the slsDetectorPackage. Default value is 0. """ super().__init__(multi_id) self._register = Register(self) # CONFIGURATION def __len__(self): return self.size() def __repr__(self): return '{}(id = {})'.format(self.__class__.__name__, self.getShmId()) def free(self): self.freeSharedMemory() @property def config(self): return NotImplementedError("config is set only") @config.setter def config(self, fname): self.loadConfig(fname) @property def parameters(self): return NotImplementedError("parameters is set only") @parameters.setter def parameters(self, fname): self.loadParameters(fname) @property def hostname(self): return self.getHostname() @hostname.setter def hostname(self, hostnames): if isinstance(hostnames, str): hostnames = [hostnames] if isinstance(hostnames, list): self.setHostname(hostnames) else: raise ValueError("hostname needs to be string or list of strings") @property def fw_version(self): return element_if_equal(self.getFirmwareVersion()) @property def server_version(self): #TODO! handle hex print return element_if_equal(self.getDetectorServerVersion()) @property def client_version(self): return element_if_equal(self.getClientVersion()) @property def rx_version(self): return element_if_equal(self.getReceiverVersion()) @property def detector_type(self): return element_if_equal(self.getDetectorType()) @property def dr(self): return element_if_equal(self.getDynamicRange()) @dr.setter def dr(self, dr): self.setDynamicRange(dr) @property def module_geometry(self): return to_geo(self.getModuleGeometry()) @property def module_size(self): ms = [to_geo(item) for item in self.getModuleSize()] return element_if_equal(ms) @property def detector_size(self): return to_geo(self.getDetectorSize()) @property def settings(self): return element_if_equal(self.getSettings()) @settings.setter def settings(self, value): self.setSettings(value) @property def frames(self): return element_if_equal(self.getNumberOfFrames()) @frames.setter def frames(self, n_frames): self.setNumberOfFrames(n_frames) @property def exptime(self): res = self.getExptime() return element_if_equal([it.total_seconds() for it in res]) @exptime.setter def exptime(self, t): if isinstance(t, dt.timedelta): self.setExptime(t) else: self.setExptime(dt.timedelta(seconds=t)) @property def subexptime(self): res = self.getSubExptime() return element_if_equal([it.total_seconds() for it in res]) @subexptime.setter def subexptime(self, t): if isinstance(t, dt.timedelta): self.setSubExptime(t) else: self.setSubExptime(dt.timedelta(seconds=t)) @property def period(self): res = self.getPeriod() return element_if_equal([it.total_seconds() for it in res]) @period.setter def period(self, t): if isinstance(t, dt.timedelta): self.setPeriod(t) else: self.setPeriod(dt.timedelta(seconds=t)) # Time #TODO! Rename to rx_framescaught @property def framescaught(self): return element_if_equal(self.getFramesCaught()) @property def startingfnum(self): return element_if_equal(self.getStartingFrameNumber()) @startingfnum.setter def startingfnum(self, value): self.setStartingFrameNumber(value) #TODO! testing switches on automatically? @property def flowcontrol_10g(self): return element_if_equal(self.getTenGigaFlowControl()) @flowcontrol_10g.setter def flowcontrol_10g(self, enable): self.setTenGigaFlowControl(enable) #TODO! add txdelay @property def use_receiver(self): return element_if_equal(self.getUseReceiverFlag()) @property def rx_hostname(self): return element_if_equal(self.getRxHostname()) @rx_hostname.setter def rx_hostname(self, hostname): self.setRxHostname(hostname) @property def rx_tcpport(self): return element_if_equal(self.getRxPort()) @rx_tcpport.setter def rx_tcpport(self, port): self.setRxPort(port) @property def rx_fifodepth(self): return element_if_equal(self.getRxFifoDepth()) @rx_fifodepth.setter def rx_fifodepth(self, frames): self.setRxFifoDepth(frames) @property def rx_silent(self): return element_if_equal(self.getRxSilentMode()) @rx_silent.setter def rx_silent(self, value): self.setRxSilentMode(value) @property def rx_discardpolicy(self): return element_if_equal(self.getRxFrameDiscardPolicy()) @rx_discardpolicy.setter def rx_discardpolicy(self, policy): self.setRxFrameDiscardPolicy() @property def rx_padding(self): return element_if_equal(self.getPartialFramesPadding()) @rx_padding.setter def rx_padding(self, policy): self.setPartialFramesPadding(policy) @property def rx_lock(self): """Lock the receiver to a specific IP""" return element_if_equal(self.getRxLock()) @rx_lock.setter def rx_lock(self, value): self.setRxLock(value) @property def rx_lastclient(self): return element_if_equal(self.getRxLastClientIP()) #FILE @property def fformat(self): return element_if_equal(self.getFileFormat()) @fformat.setter def fformat(self, format): self.setFileFormat(format) @property def findex(self): return element_if_equal(self.getAcquisitionIndex()) @findex.setter def findex(self, index): self.setAcquisitionIndex(index) @property def fname(self): return element_if_equal(self.getFileNamePrefix()) @fname.setter def fname(self, file_name): self.setFileNamePrefix(file_name) @property def fpath(self): return element_if_equal(self.getFilePath()) @fpath.setter def fpath(self, path): self.setFilePath(path) @property def fwrite(self): return element_if_equal(self.getFileWrite()) @fwrite.setter def fwrite(self, value): self.setFileWrite(value) @property def foverwrite(self): return element_if_equal(self.getFileOverWrite()) @foverwrite.setter def foverwrite(self, value): self.setFileOverWrite(value) @property def fmaster(self): return element_if_equal(self.getMasterFileWrite()) @fmaster.setter def fmaster(self, enable): self.setMasterFileWrite(enable) @property def rx_framesperfile(self): return element_if_equal(self.getFramesPerFile()) @rx_framesperfile.setter def rx_framesperfile(self, n_frames): self.setFramesPerFile(n_frames) # ZMQ Streaming Parameters (Receiver<->Client) @property def rx_datastream(self): return element_if_equal(self.getRxZmqDataStream()) @rx_datastream.setter def rx_zmqdatastream(self, enable): self.setRxZmqDataStream(enable) @property def rx_readfreq(self): return element_if_equal(self.getRxZmqFrequency()) @rx_readfreq.setter def rx_readfreq(self, nth_frame): self.setRxZmqFrequency(nth_frame) @property def rx_zmqport(self): return element_if_equal(self.getRxZmqPort()) @rx_zmqport.setter def rx_zmqport(self, port): self.setRxZmqPort(port) @property def zmqport(self): return element_if_equal(self.getClientZmqPort()) @zmqport.setter def zmqport(self, port): self.setClientZmqPort(port) @property def rx_zmqip(self): return element_if_equal(self.getRxZmqIP()) @rx_zmqip.setter def rx_zmqip(self, ip): self.setRxZmqIP(ip) @property def zmqip(self): return element_if_equal(self.getClientZmqIp()) @zmqip.setter def zmqip(self, ip): self.setClientZmqIp(ip) @property def udp_dstip(self): return element_if_equal(self.getDestinationUDPIP()) @udp_dstip.setter def udp_dstip(self, ip): self.getDestinationUDPIP(ip) @property def udp_dstip2(self): return element_if_equal(self.getDestinationUDPIP2()) @udp_dstip2.setter def udp_dstip2(self, ip): self.getDestinationUDPIP2(ip) @property def udp_dstmac(self): return element_if_equal(self.getDestinationUDPMAC()) @udp_dstmac.setter def udp_dstmac(self, mac): self.getDestinationUDPMAC2(mac) @property def udp_dstmac2(self): return element_if_equal(self.getDestinationUDPMAC2()) @udp_dstmac2.setter def udp_dstmac2(self, mac): self.getDestinationUDPMAC2(mac) @property def udp_dstport(self): return element_if_equal(self.getDestinationUDPPort()) @udp_dstport.setter def udp_dstport(self, port): self.setDestinationUDPPort(port) @property def udp_dstport2(self): return element_if_equal(self.getDestinationUDPPort2()) @udp_dstport2.setter def udp_dstport2(self, port): self.setDestinationUDPPort2(port) @property def src_udpmac(self): return element_if_equal(self.getSourceUDPMAC()) @src_udpmac.setter def src_udpmac(self, mac): self.setSourceUDPMAC(mac) @property def src_udpip2(self): return element_if_equal(self.getSourceUDPIP()) @src_udpip2.setter def src_udpip2(self, ip): self.setSourceUDPIP(ip) @property def src_udpip(self): return element_if_equal(self.getSourceUDPIP()) @src_udpip.setter def src_udpip(self, ip): self.setSourceUDPIP(ip) @property def src_udpmac2(self): return element_if_equal(self.getSourceUDPMAC2()) @src_udpmac2.setter def src_udpmac2(self, mac): self.setSourceUDPMAC2(mac) @property def vhighvoltage(self): return element_if_equal(self.getHighVoltage()) @vhighvoltage.setter def vhighvoltage(self, v): self.setHighVoltage(v) @property def user(self): return self.getUserDetails() @property def settingspath(self): return element_if_equal(self.getSettingsPath()) @settingspath.setter def settingspath(self, path): self.setSettingsPath(path) @property def status(self): return element_if_equal(self.getDetectorStatus()) @property def rx_status(self): return element_if_equal(self.getReceiverStatus()) @property def rx_udpsocksize(self): return element_if_equal(self.getRxUDPSocketBufferSize()) @rx_udpsocksize.setter def rx_udpsocksize(self, buffer_size): self.setRxUDPSocketBufferSize(buffer_size) @property def rx_realudpsocksize(self): return element_if_equal(self.getRxRealUDPSocketBufferSize()) @property def trimbits(self): return NotImplementedError('trimbits are set only') @trimbits.setter def trimbits(self, fname): self.loadTrimbits(fname) @property def lock(self): return element_if_equal(self.getDetectorLock()) @lock.setter def lock(self, value): self.setDetectorLock(value) @property def rx_lock(self): return element_if_equal(self.getRxLock()) @rx_lock.setter def rx_lock(self, value): self.setRxLock(value) @property def lastclient(self): return element_if_equal(self.getLastClientIP()) @property def reg(self): return self._register @property def ratecorr(self): """ tau in ns """ return element_if_equal(self.getRateCorrection()) @ratecorr.setter def ratecorr(self, tau): self.setRateCorrection(tau) @property def clkdivider(self): res = [int(value) for value in self.getSpeed()] return element_if_equal(res) @clkdivider.setter def clkdivider(self, value): self.setSpeed(speedLevel(value)) @property def frameindex(self): return self.getRxCurrentFrameIndex() @property def threshold(self): return element_if_equal(self.getThresholdEnergy()) @threshold.setter def threshold(self, eV): self.setThresholdEnergy(eV) @property def timing(self): return element_if_equal(self.getTimingMode()) @timing.setter def timing(self, mode): self.setTimingMode(mode) @property def trimen(self): return element_if_equal(self.getTrimEnergies()) @trimen.setter def trimen(self, energies): self.setTrimEnergies(energies) @property def vthreshold(self): return element_if_equal(self.getDAC(dacIndex.THRESHOLD))