mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-06-13 05:17:13 +02:00
merged developer into feature and solved merge conflicts
This commit is contained in:
@ -20,13 +20,14 @@ target_link_libraries(_slsdet PUBLIC
|
||||
|
||||
|
||||
set_target_properties(_slsdet PROPERTIES
|
||||
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
|
||||
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/slsdet
|
||||
)
|
||||
|
||||
#Copy Python code
|
||||
set( PYTHON_FILES
|
||||
slsdet/__init__.py
|
||||
slsdet/adcs.py
|
||||
slsdet/bits.py
|
||||
slsdet/dacs.py
|
||||
slsdet/powers.py
|
||||
slsdet/decorators.py
|
||||
@ -38,6 +39,7 @@ set( PYTHON_FILES
|
||||
slsdet/errors.py
|
||||
slsdet/gaincaps.py
|
||||
slsdet/pattern.py
|
||||
slsdet/PatternGenerator.py
|
||||
slsdet/gotthard2.py
|
||||
slsdet/moench.py
|
||||
slsdet/proxy.py
|
||||
@ -70,9 +72,18 @@ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/../VERSION
|
||||
if(SLS_INSTALL_PYTHONEXT)
|
||||
install(TARGETS _slsdet
|
||||
EXPORT "${TARGETS_EXPORT_NAME}"
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/python
|
||||
LIBRARY DESTINATION slsdet
|
||||
COMPONENT python
|
||||
)
|
||||
install(
|
||||
FILES ${PYTHON_FILES}
|
||||
DESTINATION slsdet
|
||||
COMPONENT python
|
||||
)
|
||||
install(
|
||||
FILES ../VERSION
|
||||
DESTINATION slsdet
|
||||
COMPONENT python
|
||||
)
|
||||
|
||||
install(FILES ${PYTHON_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/python/slsdet)
|
||||
install(FILES ../VERSION DESTINATION ${CMAKE_INSTALL_PREFIX}/python/slsdet)
|
||||
endif()
|
@ -1,77 +0,0 @@
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
# Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
"""
|
||||
Setup file for slsdet
|
||||
Build upon the pybind11 example found here: https://github.com/pybind/python_example
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from setuptools import setup, find_packages
|
||||
from pybind11.setup_helpers import Pybind11Extension, build_ext
|
||||
|
||||
def read_version():
|
||||
try:
|
||||
version_file = os.path.join(os.path.dirname(__file__), 'slsdet', 'VERSION')
|
||||
with open(version_file, "r") as f:
|
||||
return f.read().strip()
|
||||
except:
|
||||
raise RuntimeError("VERSION file not found in slsdet package from setup.py.")
|
||||
|
||||
__version__ = read_version()
|
||||
|
||||
|
||||
def get_conda_path():
|
||||
"""
|
||||
Keep this a function if we need some fancier logic later
|
||||
"""
|
||||
print('Prefix: ', os.environ['CONDA_PREFIX'])
|
||||
return os.environ['CONDA_PREFIX']
|
||||
|
||||
|
||||
#TODO migrate to CMake build or fetch files from cmake?
|
||||
ext_modules = [
|
||||
Pybind11Extension(
|
||||
'_slsdet',
|
||||
['src/main.cpp',
|
||||
'src/enums.cpp',
|
||||
'src/current.cpp',
|
||||
'src/detector.cpp',
|
||||
'src/network.cpp',
|
||||
'src/pattern.cpp',
|
||||
'src/scan.cpp',
|
||||
'src/duration.cpp',
|
||||
'src/DurationWrapper.cpp',
|
||||
'src/pedestal.cpp',
|
||||
]
|
||||
|
||||
|
||||
,
|
||||
include_dirs=[
|
||||
os.path.join(get_conda_path(), 'include'),
|
||||
|
||||
],
|
||||
libraries=['SlsDetector', 'SlsSupport', 'SlsReceiver'],
|
||||
library_dirs=[
|
||||
os.path.join(get_conda_path(), 'lib'),
|
||||
],
|
||||
language='c++'
|
||||
),
|
||||
]
|
||||
|
||||
setup(
|
||||
name='slsdet',
|
||||
version=__version__,
|
||||
author='Erik Frojdh',
|
||||
author_email='erik.frojdh@psi.ch',
|
||||
url='https://github.com/slsdetectorgroup/slsDetectorPackage',
|
||||
description='Detector API for SLS Detector Group detectors',
|
||||
long_description='',
|
||||
packages=find_packages(exclude=['contrib', 'docs', 'tests']),
|
||||
package_data={
|
||||
'slsdet': ['VERSION'],
|
||||
},
|
||||
ext_modules=ext_modules,
|
||||
cmdclass={"build_ext": build_ext},
|
||||
zip_safe=False,
|
||||
)
|
226
python/slsdet/PatternGenerator.py
Normal file
226
python/slsdet/PatternGenerator.py
Normal file
@ -0,0 +1,226 @@
|
||||
from . import Detector, Pattern
|
||||
from .bits import setbit, clearbit
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class PatternGenerator:
|
||||
"""
|
||||
Class to generate a pattern for the SLS detector. Intents to as closely as possible
|
||||
mimic the old pattern generation in the C code.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.pattern = Pattern()
|
||||
self.iaddr = 0
|
||||
|
||||
def SB(self, *bits):
|
||||
"""
|
||||
Set one or several bits. Change will take affect with the next PW.
|
||||
"""
|
||||
for bit in bits:
|
||||
self.pattern.word[self.iaddr] = setbit(bit, self.pattern.word[self.iaddr])
|
||||
return self.pattern.word[self.iaddr]
|
||||
|
||||
def CB(self, *bits):
|
||||
"""
|
||||
Clear one or several bits. Change will take affect with the next PW.
|
||||
"""
|
||||
for bit in bits:
|
||||
self.pattern.word[self.iaddr] = clearbit(bit, self.pattern.word[self.iaddr])
|
||||
return self.pattern.word[self.iaddr]
|
||||
|
||||
|
||||
def _pw(self, verbose = False):
|
||||
if verbose:
|
||||
print(f'{self.iaddr:#06x} {self.pattern.word[self.iaddr]:#018x}')
|
||||
|
||||
#Limits are inclusive so we need to increment the address before writing the next word
|
||||
self.pattern.limits[1] = self.iaddr
|
||||
self.iaddr += 1
|
||||
self.pattern.word[self.iaddr] = self.pattern.word[self.iaddr-1]
|
||||
|
||||
def PW(self, x = 1, verbose = False):
|
||||
for i in range(x):
|
||||
self._pw(verbose)
|
||||
|
||||
# def REPEAT(self, x, verbose = False):
|
||||
# for i in range(x):
|
||||
# self._pw(verbose)
|
||||
|
||||
# def PW2(self, verbose = 0):
|
||||
# self.REPEAT(2, verbose)
|
||||
|
||||
|
||||
def CLOCKS(self, bit, times = 1, length = 1, verbose = False):
|
||||
"""
|
||||
clocks "bit" n "times", every half clock is long "length"
|
||||
length is optional, default value is 1
|
||||
"""
|
||||
for i in range(0, times):
|
||||
self.SB(bit); self.PW(length, verbose)
|
||||
self.CB(bit); self.PW(length, verbose)
|
||||
|
||||
def CLOCK(self, bit, length = 1, verbose = 0):
|
||||
self.CLOCKS(bit, 1, length ,verbose)
|
||||
|
||||
def serializer(self, value, serInBit, clkBit, nbits, msbfirst = True, length = 1):
|
||||
"""serializer(value,serInBit,clkBit,nbits,msbfirst=1,length=1)
|
||||
Produces the .pat file needed to serialize a word into a shift register.
|
||||
value: value to be serialized
|
||||
serInBit: control bit corresponding to serial in
|
||||
clkBit: control bit corresponding to the clock
|
||||
nbits: number of bits of the target register to load
|
||||
msbfirst: if 1 pushes in the MSB first (default),
|
||||
if 0 pushes in the LSB first
|
||||
length: length of all the PWs in the pattern
|
||||
It produces no output because it modifies directly the members of the class pat via SB and CB"""
|
||||
|
||||
c = value
|
||||
self.CB(serInBit, clkBit)
|
||||
self.PW(length) #generate initial line with clk and serIn to 0
|
||||
|
||||
start = 0
|
||||
stop = nbits
|
||||
step = 1
|
||||
|
||||
if msbfirst:
|
||||
start = nbits - 1
|
||||
stop = -1
|
||||
step =- 1 #reverts loop if msb has to be pushed in first
|
||||
|
||||
for i in range(start, stop, step):
|
||||
if c & (1<<i):
|
||||
self.SB(serInBit)
|
||||
self.PW(length)
|
||||
else:
|
||||
self.CB(serInBit)
|
||||
self.PW(length)
|
||||
self.SB(clkBit)
|
||||
self.PW(length)
|
||||
self.CB(clkBit)
|
||||
self.PW(length)
|
||||
|
||||
self.CB(serInBit, clkBit)
|
||||
self.PW(length) #generate final line with clk and serIn to 0
|
||||
|
||||
|
||||
#NOT IMPLEMENTED YET
|
||||
#TODO! What should setstop do? Or can we remove it?
|
||||
#def setstop():
|
||||
#
|
||||
|
||||
def setoutput(self, bit):
|
||||
self.pattern.ioctrl = setbit(bit, self.pattern.ioctrl)
|
||||
|
||||
def setinput(self, bit):
|
||||
self.pattern.ioctrl= clearbit(bit, self.pattern.ioctrl)
|
||||
|
||||
#TODO! What should setclk do? Or can we remove it?
|
||||
# def setclk(bit):
|
||||
# self.clkctrl=self.setbit(bit,self.clkctrl)
|
||||
|
||||
def setinputs(self, *args):
|
||||
for i in args:
|
||||
self.setinput(i)
|
||||
|
||||
def setoutputs(self, *args):
|
||||
for i in args:
|
||||
self.setoutput(i)
|
||||
|
||||
#def setclks(self, *args):
|
||||
# for i in args:
|
||||
# self.setclk(i)
|
||||
|
||||
def setnloop(self, i, reps):
|
||||
self.pattern.nloop[i] = reps
|
||||
|
||||
def setstartloop(self, i):
|
||||
"""
|
||||
Set startloop[i] to the current address.
|
||||
"""
|
||||
self.pattern.startloop[i] = self.iaddr
|
||||
|
||||
def setstoploop(self, i):
|
||||
"""
|
||||
Set stoploop[i] to the current address.
|
||||
"""
|
||||
self.pattern.stoploop[i] = self.iaddr
|
||||
|
||||
|
||||
def setstart(self):
|
||||
"""
|
||||
Set start of pattern to the current address.
|
||||
"""
|
||||
self.pattern.limits[0]=self.iaddr
|
||||
|
||||
|
||||
def setstop(self,l):
|
||||
"""
|
||||
Set stop of pattern to the current address.
|
||||
"""
|
||||
self.pattern.limits[1] = self.iaddr
|
||||
|
||||
|
||||
def setwaitpoint(self, i):
|
||||
"""
|
||||
Set wait[i] to the current address.
|
||||
"""
|
||||
self.pattern.wait[i] = self.iaddr
|
||||
|
||||
|
||||
def setwaittime(self, i, t):
|
||||
"""
|
||||
Set waittime[i] to t.
|
||||
"""
|
||||
self.pattern.waittime[i] = t
|
||||
|
||||
|
||||
def setwait(self, i, t):
|
||||
"""
|
||||
Set wait[i] to the current address and waittime[i] to t.
|
||||
"""
|
||||
self.setwait(i)
|
||||
self.setwaittime(i, t)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return textwrap.dedent(f"""\
|
||||
PatternBuilder:
|
||||
patlimits: {self.pattern.limits}
|
||||
startloop: {self.pattern.startloop}
|
||||
stoploop: {self.pattern.stoploop}
|
||||
nloop: {self.pattern.nloop}
|
||||
wait: {self.pattern.wait}
|
||||
waittime: {self.pattern.waittime}""")
|
||||
|
||||
def __str__(self):
|
||||
return self.pattern.str()
|
||||
|
||||
def print(self):
|
||||
print(self)
|
||||
|
||||
def save(self, fname):
|
||||
"""Save pattern to text file"""
|
||||
fname = str(fname) #Accept also Path objects, but C++ code needs a string
|
||||
self.pattern.save(fname)
|
||||
|
||||
def load(self, fname):
|
||||
"""Load pattern from text file"""
|
||||
fname = str(fname) #Accept also Path objects, but C++ code needs a string
|
||||
n = self.pattern.load(fname)
|
||||
|
||||
#If the firs and only word is 0 we assume an empty pattern
|
||||
if n == 1 and self.pattern.word[0] == 0:
|
||||
n = 0
|
||||
self.iaddr = n
|
||||
|
||||
#To make PW work as expected we need to set 1+last word to the last word
|
||||
if n > 0:
|
||||
self.pattern.word[n] = self.pattern.word[n-1]
|
||||
|
||||
|
||||
def send_to_detector(self, det):
|
||||
"""
|
||||
Load the pattern into the detector.
|
||||
"""
|
||||
det.setPattern(self.pattern)
|
@ -12,8 +12,9 @@ from .gotthard2 import Gotthard2
|
||||
from .moench import Moench
|
||||
from .pattern import Pattern, patternParameters
|
||||
from .gaincaps import Mythen3GainCapsWrapper
|
||||
from .PatternGenerator import PatternGenerator
|
||||
|
||||
import _slsdet
|
||||
from . import _slsdet
|
||||
xy = _slsdet.xy
|
||||
defs = _slsdet.slsDetectorDefs
|
||||
|
||||
@ -40,3 +41,6 @@ def read_version():
|
||||
|
||||
__version__ = read_version()
|
||||
|
||||
|
||||
|
||||
|
||||
|
31
python/slsdet/bits.py
Normal file
31
python/slsdet/bits.py
Normal file
@ -0,0 +1,31 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
def setbit(bit, word):
|
||||
if isinstance(word, np.generic):
|
||||
mask = word.dtype.type(1)
|
||||
mask = mask << bit
|
||||
else:
|
||||
mask = 1 << bit
|
||||
return word | mask
|
||||
|
||||
|
||||
def setbit_arr(bit, arr):
|
||||
arr |= arr.dtype.type(1 << bit)
|
||||
|
||||
|
||||
def clearbit(bit, word):
|
||||
"""
|
||||
Clear the bit at position bit in word.
|
||||
Two paths to avoid converting the types.
|
||||
"""
|
||||
if isinstance(word, np.generic):
|
||||
mask = word.dtype.type(1)
|
||||
mask = ~(mask << bit)
|
||||
else:
|
||||
mask = ~(1 << bit)
|
||||
return word & mask
|
||||
|
||||
|
||||
def clearbit_arr(bit, arr):
|
||||
arr &= arr.dtype.type(~(1 << bit))
|
@ -4,7 +4,7 @@ from .detector import Detector, freeze
|
||||
from .utils import element_if_equal
|
||||
from .dacs import DetectorDacs, NamedDacs
|
||||
from .powers import DetectorPowers, NamedPowers
|
||||
import _slsdet
|
||||
from . import _slsdet
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
from .detector_property import DetectorProperty
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
from .detector_property import DetectorProperty
|
||||
from functools import partial
|
||||
import numpy as np
|
||||
import _slsdet
|
||||
from . import _slsdet
|
||||
from .detector import freeze
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
class Dac(DetectorProperty):
|
||||
|
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
# Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
from _slsdet import CppDetectorApi
|
||||
from _slsdet import slsDetectorDefs
|
||||
from _slsdet import IpAddr, MacAddr
|
||||
from ._slsdet import CppDetectorApi
|
||||
from ._slsdet import slsDetectorDefs
|
||||
from ._slsdet import IpAddr, MacAddr
|
||||
|
||||
runStatus = slsDetectorDefs.runStatus
|
||||
timingMode = slsDetectorDefs.timingMode
|
||||
@ -15,7 +15,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 ._slsdet import xy
|
||||
from .gaincaps import Mythen3GainCapsWrapper
|
||||
from . import utils as ut
|
||||
from .proxy import JsonProxy, SlowAdcProxy, ClkDivProxy, MaxPhaseProxy, ClkFreqProxy, PatLoopProxy, PatNLoopProxy, PatWaitProxy, PatWaitTimeProxy
|
||||
|
@ -11,7 +11,7 @@ Created on Wed Dec 6 11:51:18 2017
|
||||
from .detector import Detector
|
||||
from .temperature import Temperature, DetectorTemperature
|
||||
from .dacs import DetectorDacs
|
||||
import _slsdet
|
||||
from . import _slsdet
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
from .detector_property import DetectorProperty
|
||||
|
||||
|
@ -15,8 +15,8 @@ if dt === detectorType.EIGER:
|
||||
"""
|
||||
|
||||
|
||||
import _slsdet
|
||||
from . import _slsdet
|
||||
for name, cls in _slsdet.slsDetectorDefs.__dict__.items():
|
||||
if isinstance(cls, type):
|
||||
exec(f'{name} = {cls.__module__}.{cls.__qualname__}')
|
||||
exec(f'{name} = _slsdet.{cls.__qualname__}')
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
|
||||
import _slsdet
|
||||
from . import _slsdet
|
||||
gc = _slsdet.slsDetectorDefs.M3_GainCaps
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@ from .detector import Detector, freeze
|
||||
|
||||
# from .adcs import Adc, DetectorAdcs
|
||||
from .dacs import DetectorDacs
|
||||
import _slsdet
|
||||
from . import _slsdet
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
from .detector_property import DetectorProperty
|
||||
|
||||
|
@ -11,7 +11,7 @@ from .detector import Detector, freeze
|
||||
|
||||
# from .adcs import Adc, DetectorAdcs
|
||||
from .dacs import DetectorDacs
|
||||
import _slsdet
|
||||
from . import _slsdet
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
from .detector_property import DetectorProperty
|
||||
|
||||
|
@ -9,7 +9,7 @@ This file contains the specialization for the Moench detector
|
||||
|
||||
from .detector import Detector, freeze
|
||||
from .dacs import DetectorDacs
|
||||
import _slsdet
|
||||
from . import _slsdet
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
from .detector_property import DetectorProperty
|
||||
|
||||
|
@ -11,7 +11,7 @@ from .detector import Detector, freeze
|
||||
|
||||
# from .adcs import Adc, DetectorAdcs
|
||||
from .dacs import DetectorDacs
|
||||
import _slsdet
|
||||
from . import _slsdet
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
gc_enums = _slsdet.slsDetectorDefs.M3_GainCaps
|
||||
from .detector_property import DetectorProperty
|
||||
|
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
# Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
import _slsdet
|
||||
from . import _slsdet
|
||||
|
||||
from _slsdet import Pattern
|
||||
from ._slsdet import Pattern
|
||||
|
||||
|
||||
class patternParameters(_slsdet.patternParameters):
|
||||
|
@ -3,7 +3,7 @@
|
||||
from .detector_property import DetectorProperty
|
||||
from functools import partial
|
||||
import numpy as np
|
||||
import _slsdet
|
||||
from . import _slsdet
|
||||
from .detector import freeze
|
||||
dacIndex = _slsdet.slsDetectorDefs.dacIndex
|
||||
class Power(DetectorProperty):
|
||||
|
@ -3,7 +3,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
|
||||
from ._slsdet import slsDetectorDefs
|
||||
detectorType = slsDetectorDefs.detectorType
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@ but not directly used in controlling the detector
|
||||
"""
|
||||
|
||||
from collections import namedtuple
|
||||
import _slsdet #C++ lib
|
||||
from . import _slsdet #C++ lib
|
||||
import functools
|
||||
import datetime as dt
|
||||
import pathlib
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <chrono>
|
||||
#include "py_headers.h"
|
||||
|
||||
#include "DurationWrapper.h"
|
||||
@ -19,4 +20,25 @@ void init_duration(py::module &m) {
|
||||
<< " count: " << self.count() << ")";
|
||||
return ss.str();
|
||||
});
|
||||
|
||||
m.def(
|
||||
"test_return_DurationWrapper",
|
||||
[]() {
|
||||
DurationWrapper t(1.3);
|
||||
return t;
|
||||
},
|
||||
R"(
|
||||
Test function to return a DurationWrapper object. Ensures that the automatic conversion in typecaster.h works.
|
||||
)");
|
||||
|
||||
m.def(
|
||||
"test_duration_to_ns",
|
||||
[](const std::chrono::nanoseconds t) {
|
||||
//Duration wrapper is used to be able to convert from time in python to chrono::nanoseconds
|
||||
//return count to have something to test
|
||||
return t.count();
|
||||
},
|
||||
R"(
|
||||
Test function convert DurationWrapper or number to chrono::ns. Ensures that the automatic conversion in typecaster.h works.
|
||||
)"); // default value to test the default constructor
|
||||
}
|
||||
|
@ -20,8 +20,10 @@ void init_pattern(py::module &m) {
|
||||
});
|
||||
|
||||
py::class_<sls::Pattern> Pattern(m, "Pattern");
|
||||
Pattern.def(py::init());
|
||||
Pattern.def("load", &sls::Pattern::load);
|
||||
Pattern.def("data", (pat * (sls::Pattern::*)()) & sls::Pattern::data,
|
||||
Pattern.def(py::init())
|
||||
.def("load", &sls::Pattern::load)
|
||||
.def("save", &sls::Pattern::save)
|
||||
.def("str", &sls::Pattern::str)
|
||||
.def("data", (pat * (sls::Pattern::*)()) & sls::Pattern::data,
|
||||
py::return_value_policy::reference);
|
||||
}
|
||||
|
@ -54,11 +54,16 @@ template <> struct type_caster<std::chrono::nanoseconds> {
|
||||
value = duration_cast<nanoseconds>(duration<double>(PyFloat_AsDouble(src.ptr())));
|
||||
return true;
|
||||
}
|
||||
// If invoked with an int we assume it is nanoseconds and convert, same as in chrono.h
|
||||
if (PyLong_Check(src.ptr())) {
|
||||
value = duration_cast<nanoseconds>(duration<int64_t>(PyLong_AsLongLong(src.ptr())));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Lastly if we were actually called with a DurationWrapper object we get
|
||||
// the number of nanoseconds and create a std::chrono::nanoseconds from it
|
||||
py::object py_cls = py::module::import("_slsdet").attr("DurationWrapper");
|
||||
py::object py_cls = py::module::import("slsdet._slsdet").attr("DurationWrapper");
|
||||
if (py::isinstance(src, py_cls)){
|
||||
sls::DurationWrapper *cls = src.cast<sls::DurationWrapper *>();
|
||||
value = nanoseconds(cls->count());
|
||||
@ -77,7 +82,7 @@ template <> struct type_caster<std::chrono::nanoseconds> {
|
||||
* set the count from chrono::nanoseconds and return
|
||||
*/
|
||||
static handle cast(std::chrono::nanoseconds src, return_value_policy /* policy */, handle /* parent */) {
|
||||
py::object py_cls = py::module::import("_slsdet").attr("DurationWrapper");
|
||||
py::object py_cls = py::module::import("slsdet._slsdet").attr("DurationWrapper");
|
||||
py::object* obj = new py::object;
|
||||
*obj = py_cls();
|
||||
sls::DurationWrapper *dur = obj->cast<sls::DurationWrapper *>();
|
||||
|
58
python/tests/test_DurationWrapper.py
Normal file
58
python/tests/test_DurationWrapper.py
Normal file
@ -0,0 +1,58 @@
|
||||
import pytest
|
||||
|
||||
from slsdet import DurationWrapper
|
||||
|
||||
#import the compiled extension to use test functions for the automatic conversion
|
||||
from slsdet import _slsdet
|
||||
|
||||
|
||||
def test_default_construction_of_DurationWrapper():
|
||||
"""Test default construction of DurationWrapper"""
|
||||
t = DurationWrapper()
|
||||
assert t.count() == 0
|
||||
assert t.total_seconds() == 0
|
||||
|
||||
def test_construction_of_DurationWrapper():
|
||||
"""Test construction of DurationWrapper with total_seconds"""
|
||||
t = DurationWrapper(5)
|
||||
assert t.count() == 5e9
|
||||
assert t.total_seconds() == 5
|
||||
|
||||
def test_set_count_on_DurationWrapper():
|
||||
"""Test set_count on DurationWrapper"""
|
||||
t = DurationWrapper()
|
||||
t.set_count(10)
|
||||
assert t.count() == 10
|
||||
assert t.total_seconds() == 10e-9
|
||||
t.set_count(0)
|
||||
assert t.count() == 0
|
||||
assert t.total_seconds() == 0
|
||||
|
||||
|
||||
def test_return_a_DurationWrapper_from_cpp():
|
||||
"""Test returning a DurationWrapper from C++"""
|
||||
t = _slsdet.test_return_DurationWrapper()
|
||||
assert t.count() == 1.3e9
|
||||
assert t.total_seconds() == 1.3
|
||||
|
||||
def test_call_a_cpp_function_with_a_duration_wrapper():
|
||||
"""C++ functions can accept a DurationWrapper"""
|
||||
t = DurationWrapper(5)
|
||||
assert _slsdet.test_duration_to_ns(t) == 5e9
|
||||
|
||||
def test_call_a_cpp_function_converting_number_to_DurationWrapper():
|
||||
"""int and float can be converted to std::chrono::nanoseconds"""
|
||||
assert _slsdet.test_duration_to_ns(0) == 0
|
||||
assert _slsdet.test_duration_to_ns(3) == 3e9
|
||||
assert _slsdet.test_duration_to_ns(1.3) == 1.3e9
|
||||
assert _slsdet.test_duration_to_ns(10e-9) == 10
|
||||
|
||||
def test_call_a_cpp_function_with_datetime_timedelta():
|
||||
"""datetime.timedelta can be converted to std::chrono::nanoseconds"""
|
||||
import datetime
|
||||
t = datetime.timedelta(seconds=5)
|
||||
assert _slsdet.test_duration_to_ns(t) == 5e9
|
||||
t = datetime.timedelta(seconds=0)
|
||||
assert _slsdet.test_duration_to_ns(t) == 0
|
||||
t = datetime.timedelta(seconds=1.3)
|
||||
assert _slsdet.test_duration_to_ns(t) == 1.3e9
|
152
python/tests/test_PatternGenerator.py
Normal file
152
python/tests/test_PatternGenerator.py
Normal file
@ -0,0 +1,152 @@
|
||||
import pytest
|
||||
from slsdet import PatternGenerator
|
||||
|
||||
|
||||
def apply_detconf(p):
|
||||
"""
|
||||
Hacky workaround to apply detConf_mh02 to a pattern
|
||||
"""
|
||||
DACMON = 0
|
||||
cnt_en_3 = 1
|
||||
pulse_counter_en = 2
|
||||
cnt_en_1 = 3
|
||||
par_load = 4
|
||||
pulse_mux_ctr = 5
|
||||
reset_cnt = 6
|
||||
reset_periphery = 7
|
||||
config_load = 8
|
||||
cnt_en_0 = 9
|
||||
tbl = 10
|
||||
clk_ext = 11
|
||||
trimbit_load_reg = 12
|
||||
store = 13
|
||||
data_in = 14
|
||||
en_pll_clk = 15
|
||||
cnt_en_2 = 16
|
||||
DACINT = 17
|
||||
data_out_slow = 18 #IN
|
||||
COMP2_MON = 19 #IN
|
||||
start_read = 20
|
||||
dac_store = 21
|
||||
CNT3_MON = 22 #IN
|
||||
EN_PIX_DIG_MON = 23
|
||||
clk_sel = 24
|
||||
BUSY = 25 #IN
|
||||
COMP3_MON = 26 #IN
|
||||
CNT2_MON = 27 #IN
|
||||
|
||||
dbit_ena=62 #FIFO LATCH
|
||||
adc_ena=63 #ADC ENABLE
|
||||
|
||||
#FPGA input/ouutputs
|
||||
p.setoutput(DACMON)
|
||||
p.setoutput(cnt_en_3)
|
||||
p.setoutput(pulse_counter_en)
|
||||
p.setoutput(cnt_en_1)
|
||||
p.setoutput(par_load)
|
||||
p.setoutput(pulse_mux_ctr)
|
||||
p.setoutput(reset_cnt)
|
||||
p.setoutput(reset_periphery)
|
||||
p.setoutput(cnt_en_0)
|
||||
p.setoutput(tbl)
|
||||
p.setoutput(clk_ext)
|
||||
p.setoutput(config_load)
|
||||
p.setoutput(trimbit_load_reg)
|
||||
p.setoutput(store)
|
||||
p.setoutput(data_in)
|
||||
p.setoutput(en_pll_clk)
|
||||
p.setoutput(cnt_en_2)
|
||||
p.setoutput(DACINT)
|
||||
p.setinput(data_out_slow)
|
||||
p.setinput(COMP2_MON)
|
||||
p.setoutput(start_read)
|
||||
p.setoutput(dac_store)
|
||||
p.setinput(CNT3_MON)
|
||||
p.setoutput(EN_PIX_DIG_MON)
|
||||
p.setoutput(clk_sel)
|
||||
p.setinput(BUSY)
|
||||
p.setinput(COMP3_MON)
|
||||
p.setinput(CNT2_MON)
|
||||
|
||||
#system signals
|
||||
p.setoutput(adc_ena)
|
||||
# FIFO LATCH
|
||||
p.setoutput(dbit_ena)
|
||||
return p
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def test_first_two_PW():
|
||||
p = PatternGenerator()
|
||||
|
||||
#The pattern is created with a single empty word
|
||||
assert p.pattern.limits[0] == 0
|
||||
assert p.pattern.limits[1] == 0
|
||||
|
||||
p.SB(8)
|
||||
p.PW()
|
||||
|
||||
#When doing the first PW the empty word is overwritten
|
||||
assert p.pattern.limits[0] == 0
|
||||
assert p.pattern.limits[1] == 0
|
||||
assert p.pattern.word[0] == 256
|
||||
|
||||
p.SB(9)
|
||||
p.PW()
|
||||
|
||||
#When doing the second PW we add a new word
|
||||
assert p.pattern.limits[0] == 0
|
||||
assert p.pattern.limits[1] == 1
|
||||
assert p.pattern.word[0] == 256
|
||||
assert p.pattern.word[1] == 768
|
||||
|
||||
def test_simple_pattern():
|
||||
"""
|
||||
Using enable pll pattern for MH02
|
||||
"""
|
||||
en_pll_clk = 15
|
||||
p = PatternGenerator()
|
||||
p = apply_detconf(p)
|
||||
p.SB(en_pll_clk)
|
||||
p.PW()
|
||||
p.PW()
|
||||
|
||||
lines = str(p).split("\n")
|
||||
|
||||
enable_pll_pattern = [
|
||||
"patword 0x0000 0x0000000000008000",
|
||||
"patword 0x0001 0x0000000000008000",
|
||||
"patioctrl 0xc000000001b3ffff",
|
||||
"patlimits 0x0000 0x0001",
|
||||
"patloop 0 0x1fff 0x1fff",
|
||||
"patnloop 0 0",
|
||||
"patloop 1 0x1fff 0x1fff",
|
||||
"patnloop 1 0",
|
||||
"patloop 2 0x1fff 0x1fff",
|
||||
"patnloop 2 0",
|
||||
"patloop 3 0x1fff 0x1fff",
|
||||
"patnloop 3 0",
|
||||
"patloop 4 0x1fff 0x1fff",
|
||||
"patnloop 4 0",
|
||||
"patloop 5 0x1fff 0x1fff",
|
||||
"patnloop 5 0",
|
||||
"patwait 0 0x1fff",
|
||||
"patwaittime 0 0",
|
||||
"patwait 1 0x1fff",
|
||||
"patwaittime 1 0",
|
||||
"patwait 2 0x1fff",
|
||||
"patwaittime 2 0",
|
||||
"patwait 3 0x1fff",
|
||||
"patwaittime 3 0",
|
||||
"patwait 4 0x1fff",
|
||||
"patwaittime 4 0",
|
||||
"patwait 5 0x1fff",
|
||||
"patwaittime 5 0",
|
||||
]
|
||||
|
||||
assert len(lines) == len(enable_pll_pattern)
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
assert line == enable_pll_pattern[i]
|
50
python/tests/test_bits.py
Normal file
50
python/tests/test_bits.py
Normal file
@ -0,0 +1,50 @@
|
||||
from slsdet.bits import clearbit, clearbit_arr, setbit, setbit_arr
|
||||
import numpy as np
|
||||
|
||||
|
||||
def test_clearbit_on_python_int():
|
||||
val = 5 # 0b101
|
||||
r = clearbit(0, val)
|
||||
assert r == 4
|
||||
assert val == 5
|
||||
|
||||
def test_setbit_on_python_int():
|
||||
val = 5 # 0b101
|
||||
r = setbit(1, val)
|
||||
assert r == 7
|
||||
assert val == 5
|
||||
|
||||
|
||||
def test_setbit_doesnt_change_type():
|
||||
word = np.int32(5)
|
||||
ret = setbit(0, word)
|
||||
assert isinstance(ret, np.int32)
|
||||
|
||||
|
||||
def test_clearbit_doesnt_change_type():
|
||||
word = np.uint8(5)
|
||||
ret = clearbit(0, word)
|
||||
assert isinstance(ret, np.uint8)
|
||||
|
||||
|
||||
|
||||
def test_setbit_on_array_element():
|
||||
arr = np.zeros(10, dtype=np.uint64)
|
||||
arr[5] = setbit(0, arr[5])
|
||||
arr[5] = setbit(1, arr[5])
|
||||
arr[5] = setbit(4, arr[5])
|
||||
assert arr[4] == 0
|
||||
assert arr[5] == 19 # 0b10011
|
||||
assert arr[6] == 0
|
||||
|
||||
|
||||
def test_setbit_arr():
|
||||
arr = np.zeros(10, dtype=np.int32)
|
||||
setbit_arr(3, arr[3:9])
|
||||
assert all(arr == np.array((0, 0, 0, 8, 8, 8, 8, 8, 8, 0), dtype=np.int32))
|
||||
|
||||
|
||||
def test_clearbit_arr():
|
||||
arr = np.array((5, 5, 5), dtype=np.int8)
|
||||
clearbit_arr(0, arr)
|
||||
assert all(arr == (4, 4, 4))
|
Reference in New Issue
Block a user