Compare commits

...

18 Commits

Author SHA1 Message Date
228d7a5720 removed tests for eiger
All checks were successful
Build on RHEL9 / build (push) Successful in 4m7s
Build on RHEL8 / build (push) Successful in 5m46s
2025-11-19 17:19:51 +01:00
465a9d9ebc rx_roi also accepts sequence of 2 ints 2025-11-19 16:01:17 +01:00
706fc919c7 another bug for xilinx in test script 2025-11-19 12:21:18 +01:00
c8d82909fc Code Review 2025-11-19 11:58:46 +01:00
2eca0cf117 fixed virtual detector test scripts 2025-11-19 11:08:15 +01:00
a0bd26fa7c resolved merge conflict
All checks were successful
Build on RHEL9 / build (push) Successful in 3m33s
Build on RHEL8 / build (push) Successful in 5m48s
2025-11-18 12:06:23 +01:00
e4f47cedf7 Merge pull request #1333 from slsdetectorgroup/1001/fix_format
Some checks failed
Build on RHEL9 / build (push) Failing after 3m39s
Build on RHEL8 / build (push) Failing after 5m48s
changed format to clang-format 17
2025-11-18 12:02:47 +01:00
e92fafbb4b formatted with clang format 12 2025-11-18 12:02:13 +01:00
4730236170 changed format to clang-format 17 2025-11-18 11:31:17 +01:00
85edf98133 disable user id and port test
All checks were successful
Build on RHEL9 / build (push) Successful in 3m20s
Build on RHEL8 / build (push) Successful in 5m25s
2025-11-17 11:00:37 +01:00
ea07eb36d0 added colorama in github workflows
Some checks failed
Build on RHEL9 / build (push) Failing after 2m54s
Build on RHEL8 / build (push) Failing after 5m40s
2025-11-17 09:37:58 +01:00
7d1809642e updated release 2025-11-14 14:58:39 +01:00
c5357a4d73 wrapped virtual detector setup in a test fixture 2025-11-14 14:51:09 +01:00
e6c6b8f4c5 release notes is a markdown file 2025-11-14 12:31:42 +01:00
6474029c42 added tests 2025-11-14 12:29:42 +01:00
f2ee88ba68 clear_rx_roi accessible from python API 2025-11-14 11:15:20 +01:00
f1736b5e7f API also allows single sequence for single ROI 2025-11-14 11:12:34 +01:00
e471b81b84 added typecaster for slsdefs::ROI and added setter and getter for ROI 2025-11-14 10:20:56 +01:00
13 changed files with 569 additions and 572 deletions

View File

@@ -19,7 +19,7 @@ jobs:
with:
python-version: 3.12
cache: 'pip'
- run: pip install pytest numpy
- run: pip install pytest numpy colorama
- uses: awalsh128/cache-apt-pkgs-action@latest
with:

245
RELEASE.md Normal file
View File

@@ -0,0 +1,245 @@
SLS Detector Package Minor Release 10.0.1 released on ?
================================================================
This document describes the differences between v10.0.1 and v10.0.0
CONTENTS
--------
1 Changes
1.1 Compilation Changes
1.2 New or Changed Features
1.2.1 Breaking API
1.2.2 Resolved or Changed Features
1.2.3 New Features
3 On-board Detector Server Compatibility
4 Firmware Requirements
5 Kernel Requirements
6 Download, Documentation & Support
1 Changes
==========
1.1 Compilation Changes
========================
1.2 New or Changed Features
============================
Python
-------
* receiver ROI can be set from Python using command ``rx_roi``(it supports any sequence of four or two (for mythen3 and gotthard) ints e.g. a tuple (xmin, xmax, ymin, ymax) or a sequence of such for multiple ROIS)
* one can clear all ROI's from Python using command ``rx_clearroi``
1.2.1 Breaking API
===================
1.2.2 Resolved or Changed Features
===================================
1.2.3 New Features
===================
2 On-board Detector Server Compatibility
==========================================
Eiger 10.0.0
Jungfrau 10.0.0
Mythen3 10.0.0
Gotthard2 10.0.0
Moench 10.0.0
On-board Detector Server Upgrade
--------------------------------
From v6.1.0 (without tftp):
update only on-board detector server
Using command 'updatedetectorserver'
udpate both on-board detector server and firmware simultaneously
Using command 'update'
Instructions available at
https://slsdetectorgroup.github.io/devdoc/serverupgrade.html
3 Firmware Requirements
========================
Eiger 02.10.2023 (v32) (updated in 7.0.3)
Jungfrau 09.02.2025 (v1.6, HW v1.0) (updated in 9.1.0)
08.02.2025 (v2.6, HW v2.0) (updated in 9.1.0)
Mythen3 13.11.2024 (v2.0) (updated in 9.0.0)
Gotthard2 03.10.2024 (v1.0) (updated in 9.0.0)
Moench 26.10.2023 (v2.0) (updated in 8.0.2)
Detector Upgrade
----------------
The following can be upgraded remotely:
Eiger via bit files
Jungfrau via command <.pof>
Mythen3 via command <.rbf>
Gotthard2 via command <.rbf>
Moench via command <.pof>
Except Eiger,
upgrade
Using command 'programfpga' or
udpate both on-board detector server and firmware simultaneously
Using command 'update'
Instructions available at
https://slsdetectorgroup.github.io/devdoc/firmware.html
4 Kernel Requirements
======================
Blackfin
--------
Latest version: Fri Oct 29 00:00:00 2021
Older ones will work, but might have issues with programming firmware via
the package.
Nios
-----
Compatible version: Mon May 10 18:00:21 CEST 2021
Kernel Upgrade
---------------
Eiger via bit files
Others via command
Commands: udpatekernel, kernelversion
Instructions available at
https://slsdetectorgroup.github.io/devdoc/commandline.html
https://slsdetectorgroup.github.io/devdoc/detector.html
https://slsdetectorgroup.github.io/devdoc/pydetector.html
5 Download, Documentation & Support
====================================
Download
--------
The Source Code:
https://github.com/slsdetectorgroup/slsDetectorPackage
Documentation
-------------
Installation:
https://slsdetectorgroup.github.io/devdoc/installation.html
Quick Start Guide:
https://slsdetectorgroup.github.io/devdoc/quick_start_guide.html
Firmware Upgrade:
https://slsdetectorgroup.github.io/devdoc/firmware.html
Detector Server upgrade:
https://slsdetectorgroup.github.io/devdoc/serverupgrade.html
Detector Simulators:
https://slsdetectorgroup.github.io/devdoc/virtualserver.html
Consuming slsDetectorPackage:
https://slsdetectorgroup.github.io/devdoc/consuming.html
Software Architecture
https://slsdetectorgroup.github.io/devdoc/softwarearchitecture.html
Set up commands in config file
https://slsdetectorgroup.github.io/devdoc/configcommands.html
Image Size and Output Characteristics
https://slsdetectorgroup.github.io/devdoc/dataformat.html
API Examples:
https://github.com/slsdetectorgroup/api-examples
Command Line Documentation:
https://slsdetectorgroup.github.io/devdoc/commandline.html
C++ API Documentation:
https://slsdetectorgroup.github.io/devdoc/detector.html
C++ API Example:
https://slsdetectorgroup.github.io/devdoc/examples.html#
Python API Documentation:
https://slsdetectorgroup.github.io/devdoc/pygettingstarted.html
Python API Example:
https://slsdetectorgroup.github.io/devdoc/pyexamples.html
Receivers (including custom receiver):
https://slsdetectorgroup.github.io/devdoc/receivers.html
https://slsdetectorgroup.github.io/devdoc/slsreceiver.html
Detector UDP Header:
https://slsdetectorgroup.github.io/devdoc/udpheader.html
https://slsdetectorgroup.github.io/devdoc/udpdetspec.html
Output Data:
https://slsdetectorgroup.github.io/devdoc/dataformat.html
https://slsdetectorgroup.github.io/devdoc/fileformat.html
https://slsdetectorgroup.github.io/devdoc/slsreceiverheaderformat.html
https://slsdetectorgroup.github.io/devdoc/masterfileattributes.html
https://slsdetectorgroup.github.io/devdoc/binaryfileformat.html
https://slsdetectorgroup.github.io/devdoc/hdf5fileformat.html
slsReceiver Zmq Format:
https://slsdetectorgroup.github.io/devdoc/slsreceiver.html#zmq-json-header-format
TroubleShooting:
https://slsdetectorgroup.github.io/devdoc/troubleshooting.html
https://slsdetectorgroup.github.io/devdoc/troubleshooting.html#receiver-pc-tuning-options
Further Documentation:
https://www.psi.ch/en/detectors/documentation
Info on Releases:
https://www.psi.ch/en/detectors/software
Support
-------
dhanya.thattil@psi.ch
erik.frojdh@psi.ch
alice.mazzoleni@psi.ch

View File

@@ -1,452 +0,0 @@
SLS Detector Package Major Release 10.0.0 released on 10.09.2025
================================================================
This document describes the differences between v10.0.0 and v9.2.0
CONTENTS
--------
1 Changes
1.1 Compilation Changes
1.2 New or Changed Features
1.2.1 Breaking API
1.2.2 Resolved or Changed Features
1.2.3 New Features
3 On-board Detector Server Compatibility
4 Firmware Requirements
5 Kernel Requirements
6 Download, Documentation & Support
1 Changes
==========
1.1 Compilation Changes
========================
* C++ standard
Bumped up C++ standard from 11 (gcc4.8+) to 17 (gcc8+).
* GotthardI
Dropped support for GotthardI from v10.0.0.
* PATCH
Find PATCH command required for compilation. Needed for lib zeromq patching.
* pmodules support discontinued
1.2 New or Changed Features
============================
1.2.1 Breaking API
===================
Client
------
* Shared Memory Version
Version has changed and will throw when using an earlier version of
shared memory without freeing it first.
* [Mythen3] patternX
This command has been changed back to 'pattern' as before.
* TCP API Incompatibility
The size of the expected structure has changed when setting rx_hostname compared to previous versions. This change makes it incompatible.
* User details
One can get user or detector details directly from shared memory without
creating the Detector class. It is now a free function.
C++ API: getUserDetails
python/ command line: user
Receiver
--------
* Multiple ROIs
Previously, only one ROI was allowed per detector.
Now, multiple ROIs are allowed, but restricted to a single ROI per
UDP port. More details on its help.
As before, this ROI is cut out at the receiver level before
writing to file. It does not affect network load, but reduces file size.
Please note that the signature has changed in the Detector API as it now expects a vector. getRxROI returns detector level vector of ROIs for
the entire detector or port level vector of ROIs for the module index
provided.
Command line: rx_roi, rx_clearroi
C++ API: get/setRxROI, clearRxROI
* Master File Version
Binary Master Version: 7.3 => 8.0
HDF5 Master Version: 6.7 => 7.0
* Master File Attributes
- Fixed master file inconsistencies between binary and hdf5 format.
So the parameter names might differ in master file.
- Fixed time inconsistencies due to tolerance for gotthardII.
- Replaced many of the values that was simply writted usign 'toString'
with array-based output.
- JSON additional header always written.
- HDF5 master file reads 'Version', instead of 'version'.
1.2.2 Resolved or Changed Features
===================================
Python
------
* Shared Memory outliving free
Depending on a variables scope, it was possible to access an invalid
object and its shared memory even after calling free, since resources
were not fully released. Shared memory structures now include a flag
indicating invalidity and will throw an error if accessed after being
freed.
Client
------
* UDP Destination List
CLI: udp_dstlist
C++ API: getDestinationUDPList
Was returning incorrect values. Fixed.
Receiver
--------
* [Mythen3] Master File Attributes
Previously, did not create HDF5 Master file without crashing. Fixed now.
* Default File Path
It used to be '/'. Now, changed to empty and will throw if still
unchanged before an acquisition.
* Command Line Arguments
They have been refactored for slsReceiver, slsMultiReceiver and
slsFrameSynchronizer. Existing commands remain fully supported for now.
Usage: slsReceiver Options:
-v, --version : Version.
-p, --port : TCP port to communicate with client for configuration. Non-zero and 16 bit.
-u, --uid : Set effective user id if receiver started with privileges.
Usage: slsMultiReceiver Options:
-v, --version : Version.
-n, --num-receivers : Number of receivers.
-p, --port : TCP port to communicate with client for configuration. Non-zero and 16 bit.
-c, --callback : Enable dummy callbacks for debugging. Disabled by default.
-u, --uid : Set effective user id if receiver started with privileges.
Usage: slsFrameSynchronizer Options:
-v, --version : Version.
-n, --num-receivers : Number of receivers.
-p, --port : TCP port to communicate with client for configuration. Non-zero and 16 bit.
-c, --print-headers : Print callback headers for debugging. Disabled by default.
-u, --uid : Set effective user id if receiver started with privileges.
* [Moench] No intertpolation
Fixed no interpolation for Moench03.
1.2.3 New Features
===================
Compilation
-----------
* Conda and pypi
Automatic release on both upon release.
Python
------
* Exposing Free Shared Memory
One can do either `slsdet.freeSharedMemory()` or `d.free()`
Client
------
* Port size and Port per Module Geometry in Detector class
C++ API: getPortSize, getPortPerModuleGeometry
* ROI structure
Added 'overlap' function to check if it overlaps with another.
Receiver
--------
* HDF5 Virtual File with ROI
Previously, virtual file was not created with ROI. It is now.
* Readout speed added to Master File
Documentation
-------------
* Multi Detector and Multi user
Documentation on multi detector index and multi user considerations for
using the same client system.
https://slsdetectorgroup.github.io/devdoc/multidet.html
* 10GbE PC tuning
Further information for permanent ethtool settings updated.
https://slsdetectorgroup.github.io/devdoc/troubleshooting.html#receiver-pc-tuning-options
* Image Size and Output Characteristics
Information for different detector types and different parameters that
affect image size and characteristics have been added.
https://slsdetectorgroup.github.io/devdoc/dataformat.html
* 'How To' section added
Software Architecture
https://slsdetectorgroup.github.io/devdoc/softwarearchitecture.html
Set up commands most often used in the config file
https://slsdetectorgroup.github.io/devdoc/configcommands.html
Quick start guide has been updated
https://slsdetectorgroup.github.io/devdoc/quick_start_guide.html
2 On-board Detector Server Compatibility
==========================================
Eiger 10.0.0
Jungfrau 10.0.0
Mythen3 10.0.0
Gotthard2 10.0.0
Moench 10.0.0
On-board Detector Server Upgrade
--------------------------------
From v6.1.0 (without tftp):
update only on-board detector server
Using command 'updatedetectorserver'
udpate both on-board detector server and firmware simultaneously
Using command 'update'
Instructions available at
https://slsdetectorgroup.github.io/devdoc/serverupgrade.html
3 Firmware Requirements
========================
Eiger 02.10.2023 (v32) (updated in 7.0.3)
Jungfrau 09.02.2025 (v1.6, HW v1.0) (updated in 9.1.0)
08.02.2025 (v2.6, HW v2.0) (updated in 9.1.0)
Mythen3 13.11.2024 (v2.0) (updated in 9.0.0)
Gotthard2 03.10.2024 (v1.0) (updated in 9.0.0)
Moench 26.10.2023 (v2.0) (updated in 8.0.2)
Detector Upgrade
----------------
The following can be upgraded remotely:
Eiger via bit files
Jungfrau via command <.pof>
Mythen3 via command <.rbf>
Gotthard2 via command <.rbf>
Moench via command <.pof>
Except Eiger,
upgrade
Using command 'programfpga' or
udpate both on-board detector server and firmware simultaneously
Using command 'update'
Instructions available at
https://slsdetectorgroup.github.io/devdoc/firmware.html
4 Kernel Requirements
======================
Blackfin
--------
Latest version: Fri Oct 29 00:00:00 2021
Older ones will work, but might have issues with programming firmware via
the package.
Nios
-----
Compatible version: Mon May 10 18:00:21 CEST 2021
Kernel Upgrade
---------------
Eiger via bit files
Others via command
Commands: udpatekernel, kernelversion
Instructions available at
https://slsdetectorgroup.github.io/devdoc/commandline.html
https://slsdetectorgroup.github.io/devdoc/detector.html
https://slsdetectorgroup.github.io/devdoc/pydetector.html
5 Download, Documentation & Support
====================================
Download
--------
The Source Code:
https://github.com/slsdetectorgroup/slsDetectorPackage
Documentation
-------------
Installation:
https://slsdetectorgroup.github.io/devdoc/installation.html
Quick Start Guide:
https://slsdetectorgroup.github.io/devdoc/quick_start_guide.html
Firmware Upgrade:
https://slsdetectorgroup.github.io/devdoc/firmware.html
Detector Server upgrade:
https://slsdetectorgroup.github.io/devdoc/serverupgrade.html
Detector Simulators:
https://slsdetectorgroup.github.io/devdoc/virtualserver.html
Consuming slsDetectorPackage:
https://slsdetectorgroup.github.io/devdoc/consuming.html
Software Architecture
https://slsdetectorgroup.github.io/devdoc/softwarearchitecture.html
Set up commands in config file
https://slsdetectorgroup.github.io/devdoc/configcommands.html
Image Size and Output Characteristics
https://slsdetectorgroup.github.io/devdoc/dataformat.html
API Examples:
https://github.com/slsdetectorgroup/api-examples
Command Line Documentation:
https://slsdetectorgroup.github.io/devdoc/commandline.html
C++ API Documentation:
https://slsdetectorgroup.github.io/devdoc/detector.html
C++ API Example:
https://slsdetectorgroup.github.io/devdoc/examples.html#
Python API Documentation:
https://slsdetectorgroup.github.io/devdoc/pygettingstarted.html
Python API Example:
https://slsdetectorgroup.github.io/devdoc/pyexamples.html
Receivers (including custom receiver):
https://slsdetectorgroup.github.io/devdoc/receivers.html
https://slsdetectorgroup.github.io/devdoc/slsreceiver.html
Detector UDP Header:
https://slsdetectorgroup.github.io/devdoc/udpheader.html
https://slsdetectorgroup.github.io/devdoc/udpdetspec.html
Output Data:
https://slsdetectorgroup.github.io/devdoc/dataformat.html
https://slsdetectorgroup.github.io/devdoc/fileformat.html
https://slsdetectorgroup.github.io/devdoc/slsreceiverheaderformat.html
https://slsdetectorgroup.github.io/devdoc/masterfileattributes.html
https://slsdetectorgroup.github.io/devdoc/binaryfileformat.html
https://slsdetectorgroup.github.io/devdoc/hdf5fileformat.html
slsReceiver Zmq Format:
https://slsdetectorgroup.github.io/devdoc/slsreceiver.html#zmq-json-header-format
TroubleShooting:
https://slsdetectorgroup.github.io/devdoc/troubleshooting.html
https://slsdetectorgroup.github.io/devdoc/troubleshooting.html#receiver-pc-tuning-options
Further Documentation:
https://www.psi.ch/en/detectors/documentation
Info on Releases:
https://www.psi.ch/en/detectors/software
Support
-------
dhanya.thattil@psi.ch
erik.frojdh@psi.ch
alice.mazzoleni@psi.ch

View File

@@ -24,6 +24,7 @@ import datetime as dt
from functools import wraps
from collections import namedtuple
from collections.abc import Sequence
import socket
import numpy as np
@@ -301,6 +302,46 @@ class Detector(CppDetectorApi):
def rx_arping(self, value):
ut.set_using_dict(self.setRxArping, value)
@property
def rx_roi(self):
"""Gets the list of ROIs configured in the receiver.
Note
-----
Each ROI is represented as a tuple of (x_start, y_start, x_end, y_end). \n
If no ROIs are configured, returns [[-1,-1,-1,-1]].
"""
return self.getRxROI() #vector of Roi structs how represented?
@rx_roi.setter
def rx_roi(self, rois):
"""
Sets the list of ROIs in the receiver.
Can only set multiple ROIs at multi module level without gap pixels. If more than 1 ROI per
UDP port, it will throw. Setting number of udp interfaces will clear the
roi. Cannot be set for CTB or Xilinx CTB.
Note
-----
Each ROI should be represented as a sequence of 4 ints (x_start, y_start, x_end, y_end). \n
For mythen3 or gotthard2 pass a sequence of 2 ints (x_start, x_end) \n
For multiple ROI's pass a sequence of sequence \n
Example: [[0, 100, 50, 100], [260, 270, 50,100]] \n
"""
# TODO: maybe better to accept py::object in setRxROI and handle there?
if not isinstance(rois, Sequence):
raise TypeError(
"setRxROI failed: expected a tuple/list of ints x_min, x_max, y_min, y_max "
"or a sequence of such."
)
if(not isinstance(rois[0], Sequence)):
self.setRxROI([rois])
else:
self.setRxROI(rois)
def rx_clearroi(self):
"""Clears all the ROIs configured in the receiver."""
self.clearRxROI()
@property
@element

View File

@@ -942,6 +942,7 @@ void init_det(py::module &m) {
(void (Detector::*)(const std::vector<defs::ROI> &)) &
Detector::setRxROI,
py::arg());
CppDetectorApi.def("clearRxROI",
(void (Detector::*)()) & Detector::clearRxROI);
CppDetectorApi.def(

View File

@@ -1,11 +1,12 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#pragma once
#include <pybind11/pybind11.h>
#include <datetime.h>
#include <pybind11/pybind11.h>
#include "sls/Result.h"
#include "DurationWrapper.h"
#include "sls/Result.h"
#include "sls/sls_detector_defs.h"
namespace py = pybind11;
namespace pybind11 {
@@ -14,84 +15,130 @@ template <typename Type, typename Alloc>
struct type_caster<sls::Result<Type, Alloc>>
: list_caster<sls::Result<Type, Alloc>, Type> {};
// Based on the typecaster in pybind11/chrono.h
template <> struct type_caster<std::chrono::nanoseconds> {
public:
PYBIND11_TYPE_CASTER(std::chrono::nanoseconds, const_name("DurationWrapper"));
public:
PYBIND11_TYPE_CASTER(std::chrono::nanoseconds,
const_name("DurationWrapper"));
// signed 25 bits required by the standard.
using days = std::chrono::duration<int_least32_t, std::ratio<86400>>;
// signed 25 bits required by the standard.
using days = std::chrono::duration<int_least32_t, std::ratio<86400>>;
/**
* Conversion part 1 (Python->C++): convert a PyObject into std::chrono::nanoseconds
* try datetime.timedelta, floats and our DurationWrapper wrapper
*/
/**
* Conversion part 1 (Python->C++): convert a PyObject into
* std::chrono::nanoseconds try datetime.timedelta, floats and our
* DurationWrapper wrapper
*/
bool load(handle src, bool) {
using namespace std::chrono;
bool load(handle src, bool) {
using namespace std::chrono;
// Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) {
PyDateTime_IMPORT;
}
// Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) {
PyDateTime_IMPORT;
}
if (!src) {
if (!src) {
return false;
}
// If invoked with datetime.delta object, same as in chrono.h
if (PyDelta_Check(src.ptr())) {
value = duration_cast<nanoseconds>(
days(PyDateTime_DELTA_GET_DAYS(src.ptr())) +
seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr())) +
microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))
);
return true;
}
// If invoked with a float we assume it is seconds and convert, same as
// in chrono.h
if (PyFloat_Check(src.ptr())) {
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._slsdet").attr("DurationWrapper");
if (py::isinstance(src, py_cls)) {
sls::DurationWrapper *cls = src.cast<sls::DurationWrapper *>();
value = nanoseconds(cls->count());
return true;
}
return false;
}
/**
* Conversion part 2 (C++ -> Python)
* import the module to get a handle to the wrapped class
* Default construct an object of (wrapped) DurationWrapper
* 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._slsdet").attr("DurationWrapper");
py::object *obj = new py::object;
*obj = py_cls();
sls::DurationWrapper *dur = obj->cast<sls::DurationWrapper *>();
dur->set_count(src.count());
return *obj;
}
};
// Type caster for sls::defs::ROI from tuple
template <> struct type_caster<sls::defs::ROI> {
PYBIND11_TYPE_CASTER(sls::defs::ROI, _("Sequence[int, int, int, int] or "
"Sequence[int, int]"));
// convert c++ ROI to python tuple
static handle cast(const sls::defs::ROI &roi, return_value_policy, handle) {
return py::make_tuple(roi.xmin, roi.xmax, roi.ymin, roi.ymax).release();
}
// convert from python to c++ ROI
bool load(handle roi, bool /*allow implicit conversion*/) {
// accept tuple, list, numpy array any sequence
py::sequence seq;
try {
seq = py::reinterpret_borrow<py::sequence>(roi);
} catch (...) {
return false;
}
if (seq.size() != 4 && seq.size() != 2)
return false;
// Check if each element is an int
for (auto item : seq) {
if (!py::isinstance<py::int_>(item)) {
return false;
}
// If invoked with datetime.delta object, same as in chrono.h
if (PyDelta_Check(src.ptr())) {
value = duration_cast<nanoseconds>(
days(PyDateTime_DELTA_GET_DAYS(src.ptr())) +
seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr())) +
microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))
);
return true;
}
// If invoked with a float we assume it is seconds and convert, same as in chrono.h
if (PyFloat_Check(src.ptr())) {
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._slsdet").attr("DurationWrapper");
if (py::isinstance(src, py_cls)){
sls::DurationWrapper *cls = src.cast<sls::DurationWrapper *>();
value = nanoseconds(cls->count());
return true;
}
return false;
}
/**
* Conversion part 2 (C++ -> Python)
* import the module to get a handle to the wrapped class
* Default construct an object of (wrapped) DurationWrapper
* 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._slsdet").attr("DurationWrapper");
py::object* obj = new py::object;
*obj = py_cls();
sls::DurationWrapper *dur = obj->cast<sls::DurationWrapper *>();
dur->set_count(src.count());
return *obj;
value.xmin = seq[0].cast<int>();
value.xmax = seq[1].cast<int>();
if (seq.size() == 4) {
value.ymin = seq[2].cast<int>();
value.ymax = seq[3].cast<int>();
}
};
return true;
}
};
} // namespace detail
} // namespace pybind11

85
python/tests/conftest.py Normal file
View File

@@ -0,0 +1,85 @@
import pytest
import sys
import traceback
from pathlib import Path
current_dir = Path(__file__).resolve().parents[2]
scripts_dir = current_dir / "tests" / "scripts"
sys.path.append(str(scripts_dir))
print(sys.path)
from utils_for_test import (
Log,
LogLevel,
cleanup,
startReceiver,
startDetectorVirtualServer,
loadConfig,
loadBasicSettings,
)
def pytest_addoption(parser):
parser.addoption(
"--with-detector-simulators", action="store_true", default=False, help="Run tests that require detector simulators"
)
def pytest_configure(config):
config.addinivalue_line("markers", "withdetectorsimulators: mark test as needing detector simulators to run")
def pytest_collection_modifyitems(config, items):
if config.getoption("--with-detector-simulators"):
return
skip = pytest.mark.skip(reason="need --with-detector-simulators option to run")
for item in items:
if "withdetectorsimulators" in item.keywords:
item.add_marker(skip)
#helper fixture for servers
@pytest.fixture
def servers(request):
try:
return request.param # comes from @pytest.mark.parametrize(..., indirect=True)
except AttributeError:
# fallback default if the test did not parametrize
return ['eiger', 'jungfrau', 'mythen3', 'gotthard2', 'ctb', 'moench', 'xilinx_ctb']
return request.param
@pytest.fixture
def test_with_simulators(servers):
""" Fixture to automatically setup virtual detector servers for testing. """
LOG_PREFIX_FNAME = '/tmp/slsDetectorPackage_virtual_PythonAPI_test'
MAIN_LOG_FNAME = LOG_PREFIX_FNAME + '_log.txt'
with open(MAIN_LOG_FNAME, 'w') as fp:
try:
nmods = 2
for server in servers:
for ninterfaces in range(1,2):
if ninterfaces == 2 and server != 'jungfrau' and server != 'moench':
continue
msg = f'Starting Python API Tests for {server}'
if server == 'jungfrau' or server == 'moench':
msg += f' with {ninterfaces} interfaces'
Log(LogLevel.INFOBLUE, msg, fp)
cleanup(fp)
startDetectorVirtualServer(server, nmods, fp)
startReceiver(nmods, fp)
d = loadConfig(name=server, log_file_fp=fp, num_mods=nmods, num_frames=1, num_interfaces=ninterfaces)
loadBasicSettings(name=server, d=d, fp=fp)
yield # run test
cleanup(fp) # teardown
except Exception as e:
with open(MAIN_LOG_FNAME, 'a') as fp_error:
traceback.print_exc(file=fp_error)
Log(LogLevel.ERROR, f'Tests Failed.', fp)
cleanup(fp)

View File

@@ -0,0 +1,48 @@
import pytest
import sys
from conftest import test_with_simulators
from slsdet import Detector
@pytest.mark.withdetectorsimulators
@pytest.mark.parametrize("servers", [["moench"]], indirect=True)
def test_rx_ROI_moench(test_with_simulators, servers):
""" Test setting and getting rx_ROI property of Detector class for moench. """
d = Detector()
d.rx_roi = (0, 10, 10, 20)
roi = d.rx_roi
assert roi == [(0, 10, 10, 20)]
d.rx_roi = [5,15,15,25]
assert d.rx_roi == [(5,15,15,25)]
d.rx_roi = [[0,10,0,20], [5,20,410,420]]
roi = d.rx_roi
assert roi == [(0,10,0,20), (5,20,410,420)]
d.rx_clearroi()
roi = d.rx_roi
assert roi == [(-1,-1,-1,-1)]
@pytest.mark.withdetectorsimulators
@pytest.mark.parametrize("servers", [["mythen3"]], indirect=True)
def test_rx_ROI_mythen(test_with_simulators, servers):
""" Test setting and getting rx_ROI property of Detector class for mythen. """
d = Detector()
d.rx_roi = (0, 10)
roi = d.rx_roi
assert roi == [(0, 10, -1, -1)]
#d.rx_roi = [[5,15, 0, 1]] # not allowed for mythen3
d.rx_roi = [0,10, -1, -1]
assert d.rx_roi == [(0,10,-1,-1)]

View File

@@ -138,7 +138,8 @@ TEST_CASE("Parse version and help", "[detector]") {
}
}
TEST_CASE("Parse port and uid", "[detector]") {
// TODO: fails on gitea CI due to uid issue, fix later
TEST_CASE("Parse port and uid", "[.failsongitea][detector]") {
uid_t uid = getuid();
std::string uidStr = std::to_string(uid);
uid_t invalidUid = uid + 1000;

View File

@@ -113,7 +113,7 @@ def startTestsForAll(args, fp):
startDetectorVirtualServer(server, args.num_mods, fp)
startFrameSynchronizerPullSocket(server, fp)
startFrameSynchronizer(args.num_mods, fp)
d = loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=args.num_mods, num_frames=args.num_frames)
d = loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, log_file_fp=fp, num_mods=args.num_mods, num_frames=args.num_frames)
loadBasicSettings(name=server, d=d, fp=fp)
acquire(fp, d)
testFramesCaught(server, d, args.num_frames)

View File

@@ -18,9 +18,11 @@ from utils_for_test import (
RuntimeException,
cleanup,
startProcessInBackground,
startReceiver,
startDetectorVirtualServer,
connectToVirtualServers,
loadBasicSettings,
loadConfig,
runProcessWithLogFile
)
@@ -28,45 +30,6 @@ LOG_PREFIX_FNAME = '/tmp/slsDetectorPackage_virtual_roi_test'
MAIN_LOG_FNAME = LOG_PREFIX_FNAME + '_log.txt'
ROI_TEST_FNAME = LOG_PREFIX_FNAME + '_results_'
def startReceiver(num_mods, fp):
if num_mods == 1:
cmd = ['slsReceiver']
else:
cmd = ['slsMultiReceiver', str(DEFAULT_TCP_RX_PORTNO), str(num_mods)]
# in 10.0.0
#cmd = ['slsMultiReceiver', '-p', str(DEFAULT_TCP_RX_PORTNO), '-n', str(num_mods)]
startProcessInBackground(cmd, fp)
time.sleep(1)
def loadConfigForRoi(name, fp, num_mods = 1, num_interfaces = 1):
Log(LogLevel.INFO, 'Loading config')
Log(LogLevel.INFO, 'Loading config', fp)
try:
d = connectToVirtualServers(name, num_mods)
if name == 'jungfrau' or name == 'moench':
d.numinterfaces = num_interfaces
d.udp_dstport = DEFAULT_UDP_DST_PORTNO
if name == 'eiger' or name == 'jungfrau' or name == 'moench':
d.udp_dstport2 = DEFAULT_UDP_DST_PORTNO + 1
d.rx_hostname = 'localhost'
d.udp_dstip = 'auto'
if name != "eiger":
d.udp_srcip = 'auto'
if name == 'jungfrau' or name == 'moench':
d.udp_dstip2 = 'auto'
d.powerchip = 1
d.frames = 5
except Exception as e:
raise RuntimeException(f'Could not load config for {name}. Error: {str(e)}') from e
return d
def startTestsForAll(fp):
servers = [
'eiger',
@@ -89,7 +52,7 @@ def startTestsForAll(fp):
cleanup(fp)
startDetectorVirtualServer(server, nmods, fp)
startReceiver(nmods, fp)
d = loadConfigForRoi(name=server, fp=fp, num_mods=nmods, num_interfaces=ninterfaces)
d = loadConfig(name=server, log_file_fp = fp, num_mods=nmods, num_frames=5, num_interfaces=ninterfaces)
loadBasicSettings(name=server, d=d, fp=fp)
fname = ROI_TEST_FNAME + server + '.txt'

View File

@@ -63,7 +63,7 @@ def startCmdTestsForAll(args, fp):
cleanup(fp)
startDetectorVirtualServer(name=server, num_mods=num_mods, fp=fp)
startReceiver(num_mods, fp)
d = loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=num_mods)
d = loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, log_file_fp=fp, num_mods=num_mods)
loadBasicSettings(name=server, d=d, fp=fp)
runProcessWithLogFile('Cmd Tests (' + args.markers + ') for ' + server, cmd, fp, fname)
except Exception as e:

View File

@@ -16,7 +16,6 @@ SERVER_START_PORTNO=1900
init(autoreset=True)
class LogLevel(Enum):
INFO = 0
INFORED = 1
@@ -193,32 +192,51 @@ def connectToVirtualServers(name, num_mods, ctb_object=False):
return d
def startReceiver(num_mods, fp):
if num_mods == 1:
cmd = ['slsReceiver']
else:
cmd = ['slsMultiReceiver', str(DEFAULT_TCP_RX_PORTNO), str(num_mods)]
# in 10.0.0
#cmd = ['slsMultiReceiver', '-p', str(DEFAULT_TCP_RX_PORTNO), '-n', str(num_mods)]
startProcessInBackground(cmd, fp)
time.sleep(1)
def loadConfig(name, rx_hostname, settingsdir, fp, num_mods = 1, num_frames = 1):
def loadConfig(name, rx_hostname = 'localhost', settingsdir = None, log_file_fp = None, num_mods = 1, num_frames = 1, num_interfaces = 1):
Log(LogLevel.INFO, 'Loading config')
Log(LogLevel.INFO, 'Loading config', fp)
Log(LogLevel.INFO, 'Loading config', log_file_fp)
try:
d = connectToVirtualServers(name, num_mods)
if name == 'jungfrau' or name == 'moench':
d.numinterfaces = num_interfaces
d.udp_dstport = DEFAULT_UDP_DST_PORTNO
if name == 'eiger':
if name == 'eiger' or name == 'jungfrau' or name == 'moench':
d.udp_dstport2 = DEFAULT_UDP_DST_PORTNO + 1
d.rx_hostname = rx_hostname
d.udp_dstip = 'auto'
if name != "eiger":
d.udp_srcip = 'auto'
if name == "jungfrau" or name == "moench":
d.udp_dstip2 = 'auto'
if name == "jungfrau" or name == "moench" or name == "xilinx_ctb":
d.powerchip = 1
if name == "xilinx_ctb":
d.configureTransceiver()
if name == "eiger":
d.trimen = [4500, 5400, 6400]
d.settingspath = settingsdir + '/eiger/'
d.setThresholdEnergy(4500, detectorSettings.STANDARD)
if settingsdir is not None and name in ['eiger', 'mythen3']:
d.settingspath = settingsdir + '/' + name + '/'
d.trimen = [4500, 5400, 6400] if name == 'eiger' else [4000, 6000, 8000, 12000]
d.setThresholdEnergy(4500, detectorSettings.STANDARD)
d.frames = num_frames
except Exception as e: