2019-09-17 09:32:22 +02:00

1487 lines
36 KiB
Python
Executable File

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Python - sls
=============
"""
import os
from collections.abc import Iterable
from collections import namedtuple
from _sls_detector import DetectorApi
from .detector_property import DetectorProperty
from .errors import DetectorError, DetectorValueError
from .registers import Register
from .utils import element_if_equal
import numpy as np
class Detector:
"""
Base class used as interface with the slsDetectorSoftware. To control a specific detector use the
derived classes such as Eiger and Jungfrau. Functions as an interface to the C++ API and provides a
more Pythonic interface
"""
_speed_names = {0: 'Full Speed', 1: 'Half Speed', 2: 'Quarter Speed', 3: 'Super Slow Speed'}
_speed_int = {'Full Speed': 0, 'Half Speed': 1, 'Quarter Speed': 2, 'Super Slow Speed': 3}
_settings = []
def __init__(self, multi_id=0):
self._api = DetectorApi(multi_id)
self._register = Register(self)
self._flippeddatax = DetectorProperty(self._api.getFlippedDataX,
self._api.setFlippedDataX,
self._api.getNumberOfDetectors,
'flippeddatax')
def __len__(self):
return self._api.getNumberOfDetectors()
def __repr__(self):
return '{}(id = {})'.format(self.__class__.__name__,
self._api.getMultiDetectorId())
def acq(self):
"""
Blocking command to launch the programmed measurement. Number of frames specified by frames, cycles etc.
"""
self._api.acq()
@property
def busy(self):
"""
Checks the detector is acquiring. Can also be set but should only be used if the acquire fails and
leaves the detector with busy == True
.. note ::
Only works when the measurement is launched using acquire, not with status start!
Returns
--------
bool
:py:obj:`True` if the detector is acquiring otherwise :py:obj:`False`
Examples
----------
::
d.busy
>> True
#If the detector is stuck reset by:
d.busy = False
"""
return self._api.getAcquiringFlag()
@busy.setter
def busy(self, value):
self._api.setAcquiringFlag(value)
@property
def client_version(self):
"""
:py:obj:`str` The date of commit for the client API version
Examples
----------
::
d.client_version
>> '20180327'
"""
v = hex(self._api.getClientVersion())
return v[2:]
@property
def detectornumber(self):
"""
Get all detector numbers as a list. For Eiger the detector numbers
correspond to the beb numbers.
Examples
---------
::
#for beb083 and beb098
detector.detector_number
>> [83, 98]
"""
return self._api.getDetectorNumber()
@property
def detector_type(self):
"""
Return either a string or list of strings with the detector type.
* Eiger
* Jungfrau
* etc.
Examples
----------
::
detector.detector_type
>> 'Eiger'
detector.detector_type
>> ['Eiger', 'Jungfrau']
"""
return element_if_equal(self._api.getDetectorType())
@property
def dynamic_range(self):
"""
:obj:`int`: Dynamic range of the detector.
+----+-------------+------------------------------+
| dr | max counts | comments |
+====+=============+==============================+
| 4 | 15 | |
+----+-------------+------------------------------+
| 8 | 255 | |
+----+-------------+------------------------------+
|16 | 4095 | 12 bit internally |
+----+-------------+------------------------------+
|32 | 4294967295 | Autosumming of 12 bit frames |
+----+-------------+------------------------------+
Raises
-------
ValueError
If the dynamic range is not available in the detector
"""
return self._api.getDynamicRange()
@dynamic_range.setter
def dynamic_range(self, dr):
if dr in self._detector_dynamic_range:
self._api.setDynamicRange(dr)
return
else:
raise DetectorValueError('Cannot set dynamic range to: {:d} availble options: '.format(dr),
self._detector_dynamic_range)
@property
def exposure_time(self):
"""
:obj:`double` Exposure time in [s] of a single frame.
"""
return self._api.getExposureTime() / 1e9
@exposure_time.setter
def exposure_time(self, t):
ns_time = int(t * 1e9)
if ns_time <= 0:
raise DetectorValueError('Exposure time must be larger than 0')
self._api.setExposureTime(ns_time)
@property
def file_index(self):
"""
:obj:`int` Index for frames and file names
Raises
-------
ValueError
If the user tries to set an index less than zero
Examples
---------
::
detector.file_index
>> 0
detector.file_index = 10
detector.file_index
>> 10
"""
return self._api.getFileIndex()
@file_index.setter
def file_index(self, i):
if i < 0:
raise ValueError('Index needs to be positive')
self._api.setFileIndex(i)
@property
def file_name(self):
"""
:obj:`str`: Base file name for writing images
Examples
---------
::
detector.file_name
>> 'run'
detector.file_name = 'myrun'
#For a single acquisition the detector now writes
# myrun_master_0.raw
# myrun_d0_0.raw
# myrun_d1_0.raw
# myrun_d2_0.raw
# myrun_d3_0.raw
"""
return self._api.getFileName()
@file_name.setter
def file_name(self, fname):
self._api.setFileName(fname)
@property
def file_path(self):
"""
:obj:`str`: Path where images are written
Raises
-------
FileNotFoundError
If path does not exists
Examples
---------
::
detector.file_path
>> '/path/to/files'
detector.file_path = '/new/path/to/other/files'
"""
fp = self._api.getFilePath()
if fp == '':
return [self._api.getFilePath(i) for i in range(len(self))]
else:
return fp
@file_path.setter
def file_path(self, path):
if os.path.exists(path) is True:
self._api.setFilePath(path)
else:
raise FileNotFoundError('File path does not exists')
@property
def file_write(self):
"""
:obj:`bool` If True write files to disk
"""
return self._api.getFileWrite()
@file_write.setter
def file_write(self, fwrite):
self._api.setFileWrite(fwrite)
@property
def file_overwrite(self):
"""
:obj:`bool` If true overwrite files on disk
"""
return self._api.getFileOverWrite()
@file_overwrite.setter
def file_overwrite(self, value):
self._api.setFileOverWrite(value)
@property
def file_padding(self):
"""
Pad files in the receiver
:obj:`bool` If true pads partial frames
"""
return self._api.getReceiverPartialFramesPadding()
@file_padding.setter
def file_padding(self, value):
self._api.getReceiverPartialFramesPadding(value)
@property
def firmware_version(self):
"""
:py:obj:`int` Firmware version of the detector
"""
return self._api.getFirmwareVersion()
# @property
# def flags(self):
# """Read and set flags. Accepts both single flag as
# string or list of flags.
# Raises
# --------
# RuntimeError
# If flag not recognized
# Examples
# ----------
# ::
# #Eiger
# detector.flags
# >> ['storeinram', 'parallel']
# detector.flags = 'nonparallel'
# detector.flags
# >> ['storeinram', 'nonparallel']
# detector.flags = ['continous', 'parallel']
# """
# return self._api.getReadoutFlags()
# @flags.setter
# def flags(self, flags):
# if isinstance(flags, str):
# self._api.setReadoutFlag(flags)
# elif isinstance(flags, Iterable):
# for f in flags:
# self._api.setReadoutFlag(f)
@property
def frames_caught(self):
"""
Number of frames caught by the receiver. Can be used to check for
package loss.
"""
return self._api.getFramesCaughtByReceiver()
@property
def frame_discard_policy(self):
"""
Decides what the receiver does when packet loss occurs.
nodiscard - keep all frames
discardempty - discard only empty frames
discardpartial - discard partial and empty frames
"""
return self._api.getReceiverFrameDiscardPolicy()
@frame_discard_policy.setter
def frame_discard_policy(self, policy):
self._api.setReceiverFramesDiscardPolicy(policy)
@property
def api_compatibility(self):
Compatibility = namedtuple('Compatibility', ['client_detector', 'client_receiver'])
c = Compatibility(self._api.isClientAndDetectorCompatible(), self._api.isClientAndReceiverCompatible())
return c
@property
def frame_padding(self):
"""
Padd partial frames in the receiver
"""
return self._api.getPartialFramesPadding()
@frame_padding.setter
def frame_padding(self, padding):
self._api.setPartialFramesPadding(padding)
def free_shared_memory(self):
"""
Free the shared memory that contains the detector settings
and reinitialized with 0 detectors so that you can keep
using the same object.
"""
self._api.freeSharedMemory()
self.__init__(self._api.getMultiDetectorId())
@property
def flipped_data_x(self):
"""Flips data on x axis. Set for eiger bottom modules"""
return self._flippeddatax
@property
def high_voltage(self):
"""
High voltage applied to the sensor
"""
return self._api.getDac('vhighvoltage', -1)
@high_voltage.setter
def high_voltage(self, voltage):
voltage = int(voltage)
if voltage < 0 or voltage > 200:
raise DetectorValueError('High voltage {:d}V is out of range. Should be between 0-200V'.format(voltage))
self._api.setDac('vhighvoltage', -1, voltage)
@property
def hostname(self):
"""
:obj:`list` of :obj:`str`: hostnames of all connected detectors
Examples
---------
::
detector.hostname
>> ['beb059', 'beb058']
"""
_hm = self._api.getHostname()
if _hm == '':
return []
return _hm.strip('+').split('+')
@hostname.setter
def hostname(self, hn):
if isinstance(hn, str):
self._api.setHostname(hn)
else:
name = ''.join([''.join((h, '+')) for h in hn])
self._api.setHostname(name)
@property
def image_size(self):
"""
:py:obj:`collections.namedtuple` with the image size of the detector
Also works setting using a normal tuple
.. note ::
Follows the normal convention in Python of (rows, cols)
Examples
----------
::
d.image_size = (512, 1024)
d.image_size
>> ImageSize(rows=512, cols=1024)
d.image_size.rows
>> 512
d.image_size.cols
>> 1024
"""
size = namedtuple('ImageSize', ['rows', 'cols'])
return size(*self._api.getImageSize())
@image_size.setter
def image_size(self, size):
self._api.setImageSize(*size)
def load_config(self, fname):
"""
Load detector configuration from a configuration file
Raises
--------
FileNotFoundError
If the file does not exists
"""
if os.path.isfile(fname):
self._api.readConfigurationFile(fname)
else:
raise FileNotFoundError('Cannot find configuration file')
def load_parameters(self, fname):
"""
Setup detector by executing commands in a parameters file
.. note ::
If you are relying mainly on the Python API it is probably
better to track the settings from Python. This function uses
parameters stored in a text file and the command line commands.
Raises
--------
FileNotFoundError
If the file does not exists
"""
if os.path.isfile(fname):
self._api.readParametersFile(fname)
else:
raise FileNotFoundError('Cannot find parameters file')
def load_trimbits(self, fname, idet=-1):
"""
Load trimbit file or files. Either called with detector number or -1
to try to load detector specific trimbit files
Parameters
-----------
fname:
:py:obj:`str` Filename (including path) to the trimbit files
idet
:py:obj:`int` Detector to load trimbits to, -1 for all
::
#Assuming 500k consisting of beb049 and beb048
# 0 is beb049
# 1 is beb048
#Load name.sn049 to beb049 and name.sn048 to beb048
detector.load_trimbits('/path/to/dir/name')
#Load one file to a specific detector
detector.load_trimbits('/path/to/dir/name.sn049', 0)
"""
self._api.loadTrimbitFile(fname, idet)
@property
def lock(self):
"""Lock the detector to this client
::
detector.lock = True
"""
return self._api.getServerLock()
@lock.setter
def lock(self, value):
self._api.setServerLock(value)
@property
def lock_receiver(self):
"""Lock the receivers to this client
::
detector.lock_receiver = True
"""
return self._api.getReceiverLock()
@lock_receiver.setter
def lock_receiver(self, value):
self._api.setReceiverLock(value)
@property
def module_geometry(self):
"""
:obj:`namedtuple` Geometry(horizontal=nx, vertical=ny)
of the detector modules.
Examples
---------
::
detector.module_geometry
>> Geometry(horizontal=1, vertical=2)
detector.module_geometry.vertical
>> 2
detector.module_geometry[0]
>> 1
"""
_t = self._api.getDetectorGeometry()
Geometry = namedtuple('Geometry', ['horizontal', 'vertical'])
return Geometry(horizontal=_t[0], vertical=_t[1])
@property
def n_frames(self):
"""
:obj:`int` Number of frames per acquisition
"""
return self._api.getNumberOfFrames()
@n_frames.setter
def n_frames(self, n):
if n >= 1:
self._api.setNumberOfFrames(n)
else:
raise DetectorValueError('Invalid value for n_frames: {:d}. Number of'\
' frames should be an integer greater than 0'.format(n))
@property
def frames_per_file(self):
return self._api.getFramesPerFile()
@frames_per_file.setter
def frames_per_file(self, n):
self._api.setFramesPerFile(n)
@property
def n_cycles(self):
"""Number of cycles for the measurement (exp*n_frames)*n_cycles"""
return self._api.getCycles()
@n_cycles.setter
def n_cycles(self, n_cycles):
if n_cycles > 0:
self._api.setCycles(n_cycles)
else:
raise DetectorValueError('Number of cycles must be positive')
@property
def n_measurements(self):
"""
Number of times to repeat the programmed measurement.
This is the outer most part. Real time operation is not
guaranteed since this is software controlled.
Examples
----------
::
detector.n_frames = 1
detector.n_cycles = 1
detector.n_measurements = 3
detector.acq() # 1 frame 3 times
detector.n_frames = 5
detector.n_cycles = 3
detector.n_measurements = 2
detector.acq() # 5x3 frames 2 times total 30 frames
"""
return self._api.getNumberOfMeasurements()
@n_measurements.setter
def n_measurements(self, value):
if value > 0:
self._api.setNumberOfMeasurements(value)
else:
raise DetectorValueError('Number of measurements must be positive')
@property
def n_modules(self):
"""
:obj:`int` Number of (half)modules in the detector
Examples
---------
::
detector.n_modules
>> 2
"""
return self._api.getNumberOfDetectors()
@property
def last_client_ip(self):
"""Returns the ip address of the last client
that accessed the detector
Returns
-------
:obj:`str` last client ip
Examples
----------
::
detector.last_client_ip
>> '129.129.202.117'
"""
return self._api.getLastClientIP()
@property
def receiver_last_client_ip(self):
"""Returns the ip of the client last talking to the receiver"""
return self._api.getReceiverLastClientIP()
@property
def receiver_online(self):
"""
Online flag for the receiver. Is set together with detector.online when creating the detector object
Examples
---------
::
d.receiver_online
>> True
d.receiver_online = False
"""
return self._api.getReceiverOnline()
@property
def receiver_version(self):
"""
:py:obj:`str` Receiver version as a string. [yearmonthday]
Examples
----------
::
d.receiver_version
>> '20180327'
"""
v = hex(self._api.getReceiverVersion())
return v[2:]
#When returning instance error hadling needs to be done in the
#class that is returned
@property
def register(self):
"""Directly manipulate registers on the readout board
Examples
---------
::
d.register[0x5d] = 0xf00
"""
return self._register
def reset_frames_caught(self):
"""
Reset the number of frames caught by the receiver.
.. note ::
Automatically done when using d.acq()
"""
self._api.resetFramesCaught()
@property
def period(self):
"""
:obj:`double` Period between start of frames. Set to 0 for the detector
to choose the shortest possible
"""
_t = self._api.getPeriod()
return _t / 1e9
@period.setter
def period(self, t):
ns_time = int(t * 1e9)
if ns_time < 0:
raise ValueError('Period must be 0 or larger')
self._api.setPeriod(ns_time)
@property
def rate_correction(self):
"""
:obj:`list` of :obj:`double` Rate correction for all modules.
Set to 0 for **disabled**
.. todo ::
Should support individual assignments
Raises
-------
ValueError
If the passed list is not of the same length as the number of
detectors
Examples
---------
::
detector.rate_correction
>> [125.0, 155.0]
detector.rate_correction = [125, 155]
"""
return self._api.getRateCorrection()
@rate_correction.setter
def rate_correction(self, tau_list):
if len(tau_list) != self.n_modules:
raise ValueError('List of tau needs the same length')
self._api.setRateCorrection(tau_list)
@property
def readout_clock(self):
"""
Speed of the readout clock relative to the full speed
* Full Speed
* Half Speed
* Quarter Speed
* Super Slow Speed
Examples
---------
::
d.readout_clock
>> 'Half Speed'
d.readout_clock = 'Full Speed'
"""
speed = self._api.getReadoutClockSpeed()
return self._speed_names[speed]
@readout_clock.setter
def readout_clock(self, value):
speed = self._speed_int[value]
self._api.setReadoutClockSpeed(speed)
@property
def receiver_frame_index(self):
return self._api.getReceiverCurrentFrameIndex()
@property
def rx_datastream(self):
"""
Zmq datastream from receiver. :py:obj:`True` if enabled and :py:obj:`False`
otherwise
::
#Enable data streaming from receiver
detector.rx_datastream = True
#Check data streaming
detector.rx_datastream
>> True
"""
return self._api.getRxDataStreamStatus()
@rx_datastream.setter
def rx_datastream(self, status):
self._api.setRxDataStreamStatus(status)
@property
def rx_hostname(self):
"""
Receiver hostname
TODO! setting of individual hostnames, now done with API call
"""
return self._api.getReceiverHostname()
@rx_hostname.setter
def rx_hostname(self, name):
self._api.setReceiverHostname(name)
@property
def rx_udpip(self):
"""
Receiver UDP ip
"""
return self._api.getReceiverUDPIP(-1)
@rx_udpip.setter
def rx_udpip(self, ip):
if isinstance(ip, list):
for i, addr in enumerate(ip):
self._api.setReceiverUDPIP(addr, i)
else:
self._api.setReceiverUDPIP(ip, -1)
@property
def rx_udpmac(self):
return self._api.getReceiverUDPMAC(-1)
@rx_udpmac.setter
def rx_udpmac(self, mac):
if isinstance(mac, list):
for i, m in enumerate(mac):
self._api.setReceiverUDPMAC(m, i)
else:
self._api.setReceiverUDPMAC(mac, -1)
@property
def rx_tcpport(self):
return self._api.getReceiverPort()
@rx_tcpport.setter
def rx_tcpport(self, ports):
if len(ports) != len(self):
raise ValueError('Number of ports: {} not equal to number of '
'detectors: {}'.format(len(ports), len(self)))
else:
for i, p in enumerate(ports):
self._api.setReceiverPort(i, p)
@property
def rx_zmqip(self):
"""
ip where the receiver streams data
"""
ip = self._api.getNetworkParameter('rx_zmqip')
return element_if_equal(ip)
@rx_zmqip.setter
def rx_zmqip(self, ip):
self._api.setNetworkParameter('rx_zmqip', ip, -1)
@property
def syncclk(self):
return self._api.getSyncClkSpeed(-1)
@property
def detectormac(self):
"""
Read detector mac address
"""
mac = self._api.getNetworkParameter('detectormac')
return element_if_equal(mac)
@property
def detectorip(self):
"""
Read detector ip address
"""
return self._api.getDetectorIp(-1)
# @detectorip.setter
# def detectorip(self, ip):
@property
def client_zmqip(self):
"""
Ip address where the client listens to zmq stream
"""
ip = self._api.getNetworkParameter('client_zmqip')
return element_if_equal(ip)
@client_zmqip.setter
def client_zmqip(self, ip):
self._api.setNetworkParameter('client_zmqip', ip, -1)
@property
def rx_fifodepth(self):
"""
Fifo depth of receiver in number of frames
"""
return self._api.getReceiverFifoDepth()
@rx_fifodepth.setter
def rx_fifodepth(self, n_frames):
self._api.setReceiverFifoDepth(n_frames)
@property
def rx_udpsocksize(self):
"""
UDP buffer size
"""
buffer_size = [int(s) for s in self._api.getNetworkParameter('rx_udpsocksize')]
return element_if_equal(buffer_size)
@property
def rx_jsonaddheader(self):
"""
UDP buffer size
"""
header = self._api.getNetworkParameter('rx_jsonaddheader')
return element_if_equal(header)
@rx_jsonaddheader.setter
def rx_jsonaddheader(self, header):
self._api.setNetworkParameter('rx_jsonaddheader', header, -1)
@rx_udpsocksize.setter
def rx_udpsocksize(self, buffer_size):
self._api.setNetworkParameter('rx_udpsocksize', str(buffer_size), -1)
@property
def rx_realudpsocksize(self):
"""
UDP buffer size
"""
buffer_size = [int(s) for s in self._api.getNetworkParameter('rx_realudpsocksize')]
return element_if_equal(buffer_size)
@property
def rx_zmqport(self):
"""
Return the receiver zmq ports.
::
detector.rx_zmqport
>> [30001, 30002]
"""
_s = self._api.getNetworkParameter('rx_zmqport')
if _s == '':
return []
else:
return [int(_p) for _p in _s]
@rx_zmqport.setter
def rx_zmqport(self, port):
if isinstance(port, Iterable):
for i, p in enumerate(port):
self._api.setNetworkParameter('rx_zmqport', str(p), i)
else:
self._api.setNetworkParameter('rx_zmqport', str(port), -1)
# Add back when versioning is defined
# @property
# def software_version(self):
# return self._api.getSoftwareVersion();
@property
def user(self):
return self._api.getUserDetails()
@property
def server_version(self):
"""
:py:obj:`int` On-board server version of the detector
"""
return hex(self._api.getServerVersion())
@property
def settings(self):
"""
Detector settings used to control for example calibration or gain
switching. For EIGER almost always standard standard.
.. warning ::
For Eiger setting settings should be followed by setting the threshold
otherwise reading of the settings will overwrite the set value
"""
return self._api.getSettings()
@settings.setter
def settings(self, s):
if s in self._settings:
self._api.setSettings(s)
else:
raise DetectorValueError('Settings: {:s}, not defined for {:s}. '
'Valid options are: [{:s}]'.format(s, self.detector_type, ', '.join(self._settings)))
@property
def settings_path(self):
"""
The path where the slsDetectorSoftware looks for settings/trimbit files
"""
return self._api.getSettingsDir()
@settings_path.setter
def settings_path(self, path):
if os.path.isdir(path):
self._api.setSettingsDir(path)
else:
raise FileNotFoundError('Settings path does not exist')
@property
def status(self):
"""
:py:obj:`str` Status of the detector: idle, running,
.. todo ::
Check possible values
"""
return self._api.getRunStatus()
def start_detector(self):
"""
Non blocking command to star acquisition. Needs to be used in combination
with receiver start.
"""
self._api.startAcquisition()
def stop_detector(self):
"""
Stop acquisition early or if the detector hangs
"""
self._api.stopAcquisition()
def start_receiver(self):
self._api.startReceiver()
def stop_receiver(self):
self._api.stopReceiver()
@property
def threaded(self):
"""
Enable parallel execution of commands to the different detector modules
Examples
----------
::
d.threaded
>> True
d.threaded = False
"""
return self._api.getThreadedProcessing()
@threaded.setter
def threaded(self, value):
self._api.setThreadedProcessing(value)
@property
def threshold(self):
"""
Detector threshold in eV
"""
return self._api.getThresholdEnergy()
@threshold.setter
def threshold(self, eV):
self._api.setThresholdEnergy(eV)
@property
def timing_mode(self):
"""
:py:obj:`str` Timing mode of the detector
* **auto** Something
* **trigger** Something else
"""
return self._api.getTimingMode()
@timing_mode.setter
def timing_mode(self, mode):
self._api.setTimingMode(mode)
@property
def trimmed_energies(self):
"""
EIGER: the energies at which the detector was trimmed. This also sets
the range for which the calibration of the detector is valid.
::
detector.trimmed_energies = [5400, 6400, 8000]
detector.trimmed_energies
>> [5400, 6400, 8000]
"""
return self._api.getTrimEnergies()
@trimmed_energies.setter
def trimmed_energies(self, energy_list):
self._api.setTrimEnergies(energy_list)
@property
def vthreshold(self):
"""
Threshold in DAC units for the detector. Sets the individual vcmp of
all chips in the detector.
"""
return self._api.getDac('vthreshold', -1)
@vthreshold.setter
def vthreshold(self, th):
self._api.setDac('vthreshold', -1, th)
@property
def trimbits(self):
"""
Set or read trimbits of the detector.
Examples
---------
::
#Set all to 32
d.trimbits = 32
d.trimbits
>> 32
#if undefined or different
d.trimbits
>> -1
"""
return self._api.getAllTrimbits()
@trimbits.setter
def trimbits(self, value):
if self._trimbit_limits.min <= value <= self._trimbit_limits.max:
self._api.setAllTrimbits(value)
else:
raise DetectorValueError('Trimbit setting {:d} is outside of range:'\
'{:d}-{:d}'.format(value, self._trimbit_limits.min, self._trimbit_limits.max))
@property
def client_zmqport(self):
"""zmq port of the client"""
_s = self._api.getNetworkParameter('client_zmqport')
if _s == '':
return []
return [int(_p)+i for _p in _s for i in range(2)]
def _provoke_error(self):
self._api.setErrorMask(1)
def config_network(self):
"""
Configures the detector source and destination MAC addresses, IP addresses
and UDP ports, and computes the IP header checksum for such parameters
"""
self._api.configureNetworkParameters()
#TODO! can we make this one function?
@property
def patnloop0(self):
return self._api.getPatternLoops(0, -1)[2]
@patnloop0.setter
def patnloop0(self, n):
self._api.setPatternLoops(0, -1, -1, n, -1)
@property
def patnloop1(self):
return self._api.getPatternLoops(1, -1)[2]
@patnloop1.setter
def patnloop1(self, n):
self._api.setPatternLoops(1, -1, -1, n, -1)
@property
def patnloop2(self):
return self._api.getPatternLoops(2, -1)[2]
@patnloop2.setter
def patnloop2(self, n):
self._api.setPatternLoops(2, -1, -1, n, -1)
@property
def patloop0(self):
return self._api.getPatternLoops(0)[0:2]
@patloop0.setter
def patloop0(self, value):
start, stop = value
self._api.setPatternLoops(0, start, stop, -1)
@property
def patloop1(self):
return self._api.getPatternLoops(1)[0:2]
@patloop1.setter
def patloop1(self, value):
start, stop = value
self._api.setPatternLoops(1, start, stop, -1)
@property
def patloop2(self):
return self._api.getPatternLoops(2)[0:2]
@patloop2.setter
def patloop2(self, value):
start, stop = value
self._api.setPatternLoops(2, start, stop, -1)
def setPatternWord(self, addr, word, det_id = -1):
self._api.setPatternWord(addr, word, det_id)
def setPatternLoops(self, level, start, stop, n, det_id=-1):
self._api.setPatternLoops(level, start, stop, n, det_id)
def getPatternLoops(self, level):
return self._api.getPatternLoops(level)
def getPatternWaitAddr(self, level):
return self._api.getPatternWaitAddr(level)
def setPatternWaitAddr(self, level, addr):
self._api.setPatternWaitAddr(level, addr)
@property
def patwait0(self):
return self._api.getPatternWaitAddr(0)
@patwait0.setter
def patwait0(self, addr):
self._api.setPatternWaitAddr(0, addr)
@property
def patwait1(self):
return self._api.getPatternWaitAddr(1)
@patwait1.setter
def patwait1(self, addr):
self._api.setPatternWaitAddr(1, addr)
@property
def patwait2(self):
return self._api.getPatternWaitAddr(0)
@patwait2.setter
def patwait2(self, addr):
self._api.setPatternWaitAddr(2, addr)
def setPatternWaitTime(self, level, duration):
self._api.setPatternWaitTime(level, duration)
def getPatternWaitTime(self, level):
return self._api.getPatternWaitTime(level)
@property
def patwaittime0(self):
return self._api.getPatternWaitTime(0)
@patwaittime0.setter
def patwaittime0(self, duration):
self._api.setPatternWaitTime(0, duration)
@property
def patwaittime1(self):
return self._api.getPatternWaitTime(1)
@patwaittime1.setter
def patwaittime1(self, duration):
self._api.setPatternWaitTime(1, duration)
@property
def patwaittime2(self):
return self._api.getPatternWaitTime(2)
@patwaittime2.setter
def patwaittime2(self, duration):
self._api.setPatternWaitTime(2, duration)
@property
def patioctrl(self):
return self._api.setPatternIOControl(np.uint64(-1))
@patioctrl.setter
def patioctrl(self, word):
self._api.setPatternIOControl(np.uint64(word))
@property
def patlimits(self):
return self._api.getPatternLoops(-1,-1)[0:2]
@patlimits.setter
def patlimits(self, value):
start, stop = value
self._api.setPatternLoops(-1, start, stop, -1)
@property
def patword(self):
print('Can\'t read')
@patword.setter
def patword(self, value):
addr, word = value
self._api.setPatternWord(addr, word)
@property
def patclkctrl(self):
return self._api.setPatternClockControl(np.uint64(-1))
@patclkctrl.setter
def patclkctrl(self, value):
self._api.setPatternClockControl(value)
def free_shared_memory(multi_id=0):
"""
Function to free the shared memory but do not initialize with new
0 size detector
"""
api = DetectorApi(multi_id)
api.freeSharedMemory()