Compare commits

..

7 Commits

Author SHA1 Message Date
44bf2db168 Merge remote-tracking branch 'origin/developer' into ctb/continuous_RO
All checks were successful
Build on RHEL8 / build (push) Successful in 4m37s
Build on RHEL9 / build (push) Successful in 4m56s
2025-05-01 11:19:23 +02:00
6c329cffe0 ctb: added altchip_id read register
Some checks failed
CMake / Configure and build using cmake (push) Failing after 10s
2025-04-10 13:54:48 +02:00
40dcc1e2cf added register to read the firmware git hash
Some checks failed
CMake / Configure and build using cmake (push) Failing after 9s
2025-03-28 16:01:25 +01:00
91ca6fa0f1 updated ctb RegDefs, increased size of fifo fill level register
Some checks failed
CMake / Configure and build using cmake (push) Failing after 11s
2025-03-25 14:31:35 +01:00
a7111726d9 Merge branch 'developer' into ctb/continuous_RO 2025-03-17 12:26:07 +01:00
e43f1e36fe fix fifo fill level range bug 2025-03-14 12:08:52 +01:00
9c2367e657 update ctb regDefs, included fill level of adc, transceiver and DBit fifos, added enable registers for cont. readout 2025-03-14 11:45:35 +01:00
91 changed files with 1277 additions and 2930 deletions

View File

@ -1,64 +0,0 @@
name: Build wheel
on:
workflow_dispatch:
pull_request:
push:
branches:
- main
release:
types:
- published
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest,]
steps:
- uses: actions/checkout@v4
- name: Build wheels
run: pipx run cibuildwheel==2.23.0
- uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl
build_sdist:
name: Build source distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build sdist
run: pipx run build --sdist
- uses: actions/upload-artifact@v4
with:
name: cibw-sdist
path: dist/*.tar.gz
upload_pypi:
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
if: github.event_name == 'release' && github.event.action == 'published'
# or, alternatively, upload to PyPI on every tag starting with 'v' (remove on: release above to use this)
# if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/download-artifact@v4
with:
# unpacks all CIBW artifacts into dist/
pattern: cibw-*
path: dist
merge-multiple: true
- uses: pypa/gh-action-pypi-publish@release/v1

View File

@ -21,7 +21,6 @@ if (${CMAKE_VERSION} VERSION_GREATER "3.24")
endif()
include(cmake/project_version.cmake)
include(cmake/SlsAddFlag.cmake)
include(cmake/helpers.cmake)
@ -194,9 +193,11 @@ find_package(ClangFormat)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
default_build_type("Release")
set_std_fs_lib()
message(STATUS "Extra linking to fs lib:${STD_FS_LIB}")
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "No build type selected, default to Release")
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type (default Release)" FORCE)
endif()
#Enable LTO if available
include(CheckIPOSupported)

View File

@ -25,9 +25,7 @@ mark_as_advanced(
ClangFormat_BIN)
if(ClangFormat_FOUND)
execute_process(COMMAND ${ClangFormat_BIN} --version
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE CLANG_VERSION_TEXT)
exec_program(${ClangFormat_BIN} ${CMAKE_CURRENT_SOURCE_DIR} ARGS --version OUTPUT_VARIABLE CLANG_VERSION_TEXT)
string(REGEX MATCH "([0-9]+)\\.[0-9]+\\.[0-9]+" CLANG_VERSION ${CLANG_VERSION_TEXT})
if((${CLANG_VERSION} GREATER "9") OR (${CLANG_VERSION} EQUAL "9"))
# A CMake script to find all source files and setup clang-format targets for them

View File

@ -1,46 +0,0 @@
function(default_build_type val)
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "No build type selected, default to Release")
set(CMAKE_BUILD_TYPE ${val} CACHE STRING "Build type (default ${val})" FORCE)
endif()
endfunction()
function(set_std_fs_lib)
# from pybind11
# Check if we need to add -lstdc++fs or -lc++fs or nothing
if(DEFINED CMAKE_CXX_STANDARD AND CMAKE_CXX_STANDARD LESS 17)
set(STD_FS_NO_LIB_NEEDED TRUE)
elseif(MSVC)
set(STD_FS_NO_LIB_NEEDED TRUE)
else()
file(
WRITE ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
"#include <filesystem>\nint main(int argc, char ** argv) {\n std::filesystem::path p(argv[0]);\n return p.string().length();\n}"
)
try_compile(
STD_FS_NO_LIB_NEEDED ${CMAKE_CURRENT_BINARY_DIR}
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
COMPILE_DEFINITIONS -std=c++17)
try_compile(
STD_FS_NEEDS_STDCXXFS ${CMAKE_CURRENT_BINARY_DIR}
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
COMPILE_DEFINITIONS -std=c++17
LINK_LIBRARIES stdc++fs)
try_compile(
STD_FS_NEEDS_CXXFS ${CMAKE_CURRENT_BINARY_DIR}
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
COMPILE_DEFINITIONS -std=c++17
LINK_LIBRARIES c++fs)
endif()
if(${STD_FS_NEEDS_STDCXXFS})
set(STD_FS_LIB stdc++fs PARENT_SCOPE)
elseif(${STD_FS_NEEDS_CXXFS})
set(STD_FS_LIB c++fs PARENT_SCOPE)
elseif(${STD_FS_NO_LIB_NEEDED})
set(STD_FS_LIB "" PARENT_SCOPE)
else()
message(WARNING "Unknown C++17 compiler - not passing -lstdc++fs")
set(STD_FS_LIB "")
endif()
endfunction()

View File

@ -28,8 +28,7 @@ requirements:
- libgl-devel # [linux]
- libtiff
- zlib
- expat
run:
- libstdcxx-ng
- libgcc-ng
@ -58,7 +57,6 @@ outputs:
- {{ compiler('c') }}
- {{compiler('cxx')}}
- {{ pin_subpackage('slsdetlib', exact=True) }}
run:
- {{ pin_subpackage('slsdetlib', exact=True) }}

View File

@ -42,7 +42,6 @@ set(SPHINX_SOURCE_FILES
src/pyexamples.rst
src/pyPatternGenerator.rst
src/servers.rst
src/multidet.rst
src/receiver_api.rst
src/result.rst
src/type_traits.rst

View File

@ -6,8 +6,6 @@ Usage
The syntax is *'[detector index]-[module index]:[command]'*, where the indices are by default '0', when not specified.
.. _cl-module-index-label:
Module index
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Modules are indexed based on their order in the hostname command. They are used to configure a specific module within a detector and are followed by a ':' in syntax.

View File

@ -28,12 +28,6 @@ Welcome to slsDetectorPackage's documentation!
receiver_api
examples
.. toctree::
:caption: how to
:maxdepth: 2
multidet
.. toctree::
:caption: Python API
:maxdepth: 2
@ -87,9 +81,8 @@ Welcome to slsDetectorPackage's documentation!
:caption: Receiver
:maxdepth: 2
slsreceiver
receivers
slsreceiver
.. toctree::
:caption: Receiver Files

View File

@ -6,33 +6,18 @@
Installation
===============
.. contents::
:local:
:depth: 2
:backlinks: top
Overview
--------------
The ``slsDetectorPackage`` provides core detector software implemented in C++, along with Python bindings packaged as the ``slsdet`` Python extension module. Choose the option that best fits your environment and use case.
:ref:`conda pre-built binaries`:
Install pre-built binaries for the C++ client, receiver, GUI and the Python API (``slsdet``), simplifying setup across platforms.
:ref:`pip`:
Install only the Python extension module, either by downloading the pre-built library from PyPI or by building the extension locally from source. Available only from v9.2.0 onwards.
:ref:`build from source`:
Compile the entire package yourself, including both the C++ core and the Python bindings, for maximum control and customization. However, make sure that you have the :doc:`dependencies <../dependencies>` installed. If installing using conda, conda will manage the dependencies. Avoid installing packages with pip and conda simultaneously.
One can either install pre-built binaries using conda or build from source.
.. warning ::
Before building from source make sure that you have the
:doc:`dependencies <../dependencies>` installed. If installing using conda, conda will
manage the dependencies. Avoid also installing packages with pip.
.. _conda pre-built binaries:
1. Install pre-built binaries using conda (Recommended)
--------------------------------------------------------
Install binaries using conda
----------------------------------
Conda is not only useful to manage python environments but can also
be used as a user space package manager. Dates in the tag (for eg. 2020.07.23.dev0)
@ -78,29 +63,12 @@ We have four different packages available:
conda search moenchzmq
.. _pip:
2. Pip
-------
The Python extension module ``slsdet`` can be installed using pip. This is available from v9.2.0 onwards.
.. code-block:: bash
#Install the Python extension module from PyPI
pip install slsdet
# or install the python extension locally from source
git clone https://github.com/slsdetectorgroup/slsDetectorPackage.git --branch 9.2.0
cd slsDetectorPackage
pip install .
.. _build from source:
Build from source
----------------------
3. Build from source
-------------------------
3.1. Download Source Code from github
1. Download Source Code from github
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: bash
@ -115,12 +83,12 @@ The Python extension module ``slsdet`` can be installed using pip. This is avail
3.2. Build from Source
2. Build from Source
^^^^^^^^^^^^^^^^^^^^^^^^^^
One can either build using cmake or use the in-built cmk.sh script.
3.2.1. Build using CMake
Build using CMake
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: bash
@ -167,7 +135,7 @@ Example cmake options Comment
For v7.x.x of slsDetectorPackage and older, refer :ref:`zeromq notes for cmake option to hint library location. <zeromq for different slsDetectorPackage versions>`
3.2.2. Build using in-built cmk.sh script
Build using in-built cmk.sh script
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -217,8 +185,8 @@ Example cmake options Comment
For v7.x.x of slsDetectorPackage and older, refer :ref:`zeromq notes for cmk script option to hint library location. <zeromq for different slsDetectorPackage versions>`
3.3. Build on old distributions using conda
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Build on old distributions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If your linux distribution doesn't come with a C++11 compiler (gcc>4.8) then
it's possible to install a newer gcc using conda and build the slsDetectorPackage
@ -242,7 +210,7 @@ using this compiler
3.4. Build slsDetectorGui (Qt5)
Build slsDetectorGui (Qt5)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1. Using pre-built binary on conda
@ -303,7 +271,7 @@ using this compiler
3.5. Build this documentation
Build this documentation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The documentation for the slsDetectorPackage is build using a combination
@ -326,8 +294,8 @@ is to use conda
make rst # rst only, saves time in case the API did not change
4. Pybind and Zeromq
-------------------------
Pybind and Zeromq
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. _pybind for different slsDetectorPackage versions:

View File

@ -1,228 +0,0 @@
Using multiple detectors
==========================
The slsDetectorPackage supports using several detectors on the same computer.
This can either be two users, that need to use the same computer without interfering
with each other, or the same user that wants to use multiple detectors at the same time.
The detectors in turn can consist of multiple modules. For example, a 9M Jungfrau detector
consists of 18 modules which typically are addressed at once as a single detector.
.. note ::
To address a single module of a multi-module detector you can use the module index.
- Command line: :ref:`cl-module-index-label`
- Python: :ref:`py-module-index-label`
Coming back to multiple detectors we have two tools to our disposal:
#. Detector index
#. The SLSDETNAME environment variable
They can be used together or separately depending on the use case.
Detector index
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When configuring a detector you can specify a detector index. The default is 0.
**Command line**
.. code-block:: bash
# Given that we have two detectors (my-det and my-det2) that we want to use,
# we can configure them with different indices.
# Configure the first detector with index 0
$ sls_detector_put hostname my-det
# Set number of frames for detector 0 to 10
$ sls_detector_put frames 10
#
#Configure the second detector with index 1 (notice the 1- before hostname)
$ sls_detector_put 1-hostname my-det2
# Further configuration
...
# Set number of frames for detector 1 to 19
$ sls_detector_put 1-frames 19
# Note that if we call sls_detector_get without specifying the index,
# it will return the configuration of detector 0
$ sls_detector_get frames
10
The detector index is added to the name of the shared memory segment, so in this case
the shared memory segments would be:
.. code-block:: bash
#First detector
/dev/shm/slsDetectorPackage_detector_0
/dev/shm/slsDetectorPackage_detector_0_module_0
#Second detector
/dev/shm/slsDetectorPackage_detector_1
/dev/shm/slsDetectorPackage_detector_1_module_0
**Python**
The main difference between the command line and the Python API is that you set the index
when you create the detector object and you don't have to repeat it for every call.
The C++ API works int the same way.
.. code-block:: python
from slsdet import Detector
# The same can be achieved in Python by creating a detector object with an index.
# Again we have two detectors (my-det and my-det2) that we want to use:
# Configure detector with index 0
d = Detector()
# If the detector has already been configured and has a shared memory
# segment, you can omit setting the hostname again
d.hostname = 'my-det'
#Further configuration
...
# Configure a second detector with index 1
d2 = Detector(1)
d2.hostname = 'my-det2'
d.frames = 10
d2.frames = 19
$SLSDETNAME
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To avoid interfering with other users on shared PCs it is best to always set the SLSDETNAME environmental variable.
Imagining a fictive user: Anna, we can set SLSDETNAME from the shell before configuring the detector:
**Command line**
.. code-block:: bash
# Set the SLSDETNAME variable
$ export SLSDETNAME=Anna
# You can check that it is set
$ echo $SLSDETNAME
Anna
# Now configures a detector with index 0 and prefixed with the name Anna
# /dev/shm/slsDetectorPackage_detector_0_Anna
$ sls_detector_put hostname my-det
.. tip ::
Set SLSDETNAME in your .bashrc in order to not forget it when opening a new terminal.
**Python**
With python the best way is to set the SLSDETNAME from the command line before starting the python interpreter.
Bash:
.. code-block:: bash
$ export SLSDETNAME=Anna
Python:
.. code-block:: python
from slsdet import Detector
# Now configures a detector with index 0 and prefixed with the name Anna
# /dev/shm/slsDetectorPackage_detector_0_Anna
d = Detector()
d.hostname = 'my-det'
You can also set SLSDETNAME from within the Python interpreter, but you have to be aware that it will only
affect the current process and not the whole shell session.
.. code-block:: python
import os
os.environ['SLSDETNAME'] = 'Anna'
# You can check that it is set
print(os.environ['SLSDETNAME']) # Output: Anna
#Now SLSDETNAME is set to Anna but as soon as you exit the python interpreter
# it will not be set anymore
.. note ::
Python has two ways of reading environment variables: `**os.environ**` as shown above which throws a
KeyError if the variable is not set and `os.getenv('SLSDETNAME')` which returns None if the variable is not set.
For more details see the official python documentation on: https://docs.python.org/3/library/os.html#os.environ
Checking for other detectors
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If using shared accounts on a shared computer (which you anyway should not do), it is good practice to check
if there are other detectors configured by other users before configuring your own detector.
You can do this by listing the files in the shared memory directory `/dev/shm/` that start with `sls`. In this
example we can see that two single module detectors are configured one with index 0 and one with index 1.
SLSDETNAME is set to `Anna` so it makes sense to assume that she is the user that configured these detectors.
.. code-block:: bash
# List the files in /dev/shm that starts with sls
$ ls /dev/shm/sls*
/dev/shm/slsDetectorPackage_detector_0_Anna
/dev/shm/slsDetectorPackage_detector_0_module_0_Anna
/dev/shm/slsDetectorPackage_detector_1_Anna
/dev/shm/slsDetectorPackage_detector_1_module_0_Anna
We also provide a command: user, which gets information about the shared memory segment that
the client points to without doing any changes.
.. code-block:: bash
#in this case 3 simulated Mythen3 modules
$ sls_detector_get user
user
Hostname: localhost+localhost+localhost+
Type: Mythen3
PID: 1226078
User: l_msdetect
Date: Mon Jun 2 05:46:20 PM CEST 2025
Other considerations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The shared memory is not the only way to interfere with other users. You also need to make sure that you are not
using the same:
* rx_tcpport
* Unique combination of udp_dstip and udp_dstport
* rx_zmqport
* zmqport
.. attention ::
The computer that you are using need to have enough resources to run multiple detectors at the same time.
This includes CPU and network bandwidth. Please coordinate with the other users!

View File

@ -123,47 +123,6 @@ in a large detector.
# Set exposure time for module 1, 5 and 7
d.setExptime(0.1, [1,5,7])
.. _py-module-index-label:
----------------------------------
Accessing individual modules
----------------------------------
Using the C++ like API you can access individual modules in a large detector
by passing in the module index as an argument to the function.
::
# Read the UDP destination port for all modules
>>> d.getDestinationUDPPort()
[50001, 50002, 50003]
# Read it for module 0 and 1
>>> d.getDestinationUDPPort([0, 1])
[50001, 50002]
>>> d.setDestinationUDPPort(50010, 1)
>>> d.getDestinationUDPPort()
[50001, 50010, 50003]
From the more pythonic API there is no way to read from only one module but you can read
and then use list slicing to get the values for the modules you are interested in.
::
>>> d.udp_dstport
[50001, 50010, 50003]
>>> d.udp_dstport[0]
50001
#For some but not all properties you can also pass in a dictionary with module index as key
>>> ip = IpAddr('127.0.0.1')
>>> d.udp_dstip = {1:ip}
--------------------
Finding functions
--------------------

View File

@ -1,25 +1,25 @@
Custom Receiver
Receivers
=================
The receiver essentially listens to UDP data packets sent out by the detector.
To know more about detector receiver setup in the config file, please check out :ref:`the detector-receiver UDP configuration in the config file<detector udp header config>` and the :ref:`detector udp format<detector udp header>`.
Receiver processes can be run on same or different machines as the client, receives the data from the detector (via UDP packets).
When using the slsReceiver/ slsMultiReceiver, they can be further configured by the client control software (via TCP/IP) to set file name, file path, progress of acquisition etc.
| Please note the following when using a custom receiver:
To know more about detector receiver configuration, please check out :ref:`detector udp header and udp commands in the config file <detector udp header>`
* **udp_dstmac** must be configured in the config file. This parameter is not required when using an in-built receiver.
Custom Receiver
----------------
* Cannot use "auto" for **udp_dstip**.
| When using custom receiver with our package, ensure that **udp_dstmac** is also configured in the config file. This parameter is not required when using slsReceiver.
* No **rx_** commands in the config file. These commands are for configuring the slsReceiver.
| Cannot use "auto" for **udp_dstip**.
The main difference is the lack of **rx_** commands or file commands (eg. **f**write, **f**path) and the **udp_dstmac** is required in config file.
| Also ensure that there are no **rx_** commands in the config file. These commands are for configuring the slsReceiver.
Example of a custom receiver config file
* The main difference is the lack of **rx_** commands or file commands (eg. fwrite, fpath) and the udp_dstmac is required in config file.
.. code-block:: bash
# detector hostname

View File

@ -1,5 +1,4 @@
.. _Detector Server Upgrade:
Upgrade
========

View File

@ -1,55 +1,16 @@
In-built Receiver
slsReceiver/ slsMultiReceiver
================================
| One has to start the slsReceiver before loading config file or using any receiver commands (prefix: **rx_** )
The receiver essentially listens to UDP data packets sent out by the detector. It's main features are:
- **Listening**: Receives UDP data from the detector.
- **Writing to File**: Optionally writes received data to disk.
- **Streaming via ZMQ**: Optionally streams out the data using ZeroMQ.
Each of these operations runs asynchronously and in parallel for each UDP port.
.. note ::
* Can be run on the same or different machine as the client.
* Can be configured by the client. (set file name/ discard policy, get progress etc.)
* Has to be started before the client runs any receiver specific command.
Receiver Variants
-----------------
There are three main receiver types. How to start them is described :ref:`below<Starting up the Receiver>`.
+----------------------+--------------------+-----------------------------------------+--------------------------------+
| Receiver Type | slsReceiver | slsMultiReceiver |slsFrameSynchronizer |
+======================+====================+=========================================+================================+
| Modules Supported | 1 | Multiple | Multiple |
+----------------------+--------------------+-----------------------------------------+--------------------------------+
| Internal Architecture| Threads per porttt | Multiple child processes of slsReceiver | Multi-threading of slsReceiver |
+----------------------+--------------------+-----------------------------------------+--------------------------------+
| ZMQ Streaming | Disabled by default| Disabled by default | Enabled, not optional |
+----------------------+--------------------+-----------------------------------------+--------------------------------+
| ZMQ Synchronization | No | No | Yes, across ports |
+----------------------+--------------------+-----------------------------------------+--------------------------------+
| Image Reconstruction | No | No | No |
+----------------------+--------------------+-----------------------------------------+--------------------------------+
.. _Starting up the Receiver:
Starting up the Receiver
-------------------------
For a Single Module
.. code-block:: bash
slsReceiver # default port 1954
slsReceiver -t2012 # custom port 2012
# default port 1954
slsReceiver
# custom port 2012
slsReceiver -t2012
For Multiple Modules
@ -57,66 +18,57 @@ For Multiple Modules
# each receiver (for each module) requires a unique tcp port (if all on same machine)
# option 1 (one for each module)
# using slsReceiver in multiple consoles
slsReceiver
slsReceiver -t1955
# option 2
# slsMultiReceiver [starting port] [number of receivers]
slsMultiReceiver 2012 2
# option 3
slsFrameSynchronizer 2012 2
# slsMultiReceiver [starting port] [number of receivers] [print each frame header for debugging]
slsMultiReceiver 2012 2 1
Client Commands
-----------------
* Client commands to the receiver begin with **rx_** or **f_** (file commands).
| One can remove **udp_dstmac** from the config file, as the slsReceiver fetches this from the **udp_ip**.
* **rx_hostname** has to be the first command to the receiver so the client knows which receiver process to communicate with.
| One can use "auto" for **udp_dstip** if one wants to use default ip of **rx_hostname**.
* Can use 'auto' for **udp_dstip** if using 1GbE interface or the :ref:`virtual simulators<Virtual Detector Servers>`.
To know more about detector receiver setup in the config file, please check out :ref:`the detector-receiver UDP configuration in the config file<detector udp header config>` and the :ref:`detector udp format<detector udp header>`.
The following are the different ways to establish contact using **rx_hostname** command.
| The first command to the receiver (**rx_** commands) should be **rx_hostname**. The following are the different ways to establish contact.
.. code-block:: bash
# ---single module---
# default receiver port at 1954
# default receiver tcp port (1954)
rx_hostname xxx
# custom receiver port
rx_hostname xxx:1957 # option 1
rx_tcpport 1957 # option 2
rx_hostname xxx:1957
# custom receiver port
rx_tcpport 1954
rx_hostname xxx
# ---multi module---
# using increasing tcp ports
# multi modules with custom ports
rx_hostname xxx:1955+xxx:1956+
# multi modules using increasing tcp ports when using multi detector command
rx_tcpport 1955
rx_hostname xxx
# custom ports
rx_hostname xxx:1955+xxx:1958+ # option 1
0:rx_tcpport 1954 # option 2
# or specify multi modules with custom ports on same rxr pc
0:rx_tcpport 1954
1:rx_tcpport 1955
2:rx_tcpport 1956
rx_hostname xxx
# custom ports on different receiver machines
# multi modules with custom ports on different rxr pc
0:rx_tcpport 1954
0:rx_hostname xxx
1:rx_tcpport 1955
1:rx_hostname yyyrxr
1:rx_hostname yyy
| Example commands:
@ -139,32 +91,6 @@ The following are the different ways to establish contact using **rx_hostname**
sls_detector_get -h rx_framescaught
Example of a config file using in-built receiver
.. code-block:: bash
# detector hostname
hostname bchip052+bchip053+
# udp destination port (receiver)
# sets increasing destination udp ports starting at 50004
udp_dstport 50004
# udp destination ip (receiver)
0:udp_dstip 10.0.1.100
1:udp_dstip 10.0.2.100
# udp source ip (same subnet as udp_dstip)
0:udp_srcip 10.0.1.184
1:udp_srcip 10.0.2.184
# udp destination mac - not required (picked up from udp_dstip)
#udp_dstmac 22:47:d5:48:ad:ef
# connects to receivers at increasing tcp port starting at 1954
rx_hostname mpc3434
# same as rx_hostname mpc3434:1954+mpc3434:1955+
Performance

View File

@ -1,4 +1,4 @@
.. _detector udp header config:
.. _detector udp header:
Config file

View File

@ -1,5 +1,4 @@
.. _Virtual Detector Servers:
Simulators
===========

View File

@ -13,5 +13,5 @@ slsDetectorPackage/8.0.2_rh7 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/8.0.2_rh8 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/9.0.0_rh8 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/9.1.0_rh8 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/9.1.1_rh8 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/9.2.0_rh8 stable cmake/3.15.5 Qt/5.12.10

View File

@ -11,13 +11,9 @@ build-backend = "scikit_build_core.build"
[project]
name = "slsdet"
dynamic = ["version"]
dependencies = [
"numpy",
]
[tool.cibuildwheel]
before-all = "uname -a"
build = "cp{311,312,313}-manylinux_x86_64"
[tool.scikit-build.build]
verbose = true

View File

@ -65,9 +65,6 @@ configure_file( scripts/test_virtual.py
${CMAKE_BINARY_DIR}/test_virtual.py
)
configure_file(scripts/frameSynchronizerPullSocket.py
${CMAKE_BINARY_DIR}/bin/frameSynchronizerPullSocket.py COPYONLY)
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/../VERSION
${CMAKE_BINARY_DIR}/bin/slsdet/VERSION
)

View File

@ -924,6 +924,17 @@ void init_det(py::module &m) {
(void (Detector::*)(bool, sls::Positions)) &
Detector::setRxArping,
py::arg(), py::arg() = Positions{});
CppDetectorApi.def("getIndividualRxROIs",
(Result<defs::ROI>(Detector::*)(sls::Positions) const) &
Detector::getIndividualRxROIs,
py::arg());
CppDetectorApi.def("getRxROI",
(defs::ROI(Detector::*)() const) & Detector::getRxROI);
CppDetectorApi.def(
"setRxROI", (void (Detector::*)(const defs::ROI)) & Detector::setRxROI,
py::arg());
CppDetectorApi.def("clearRxROI",
(void (Detector::*)()) & Detector::clearRxROI);
CppDetectorApi.def(
"getFileFormat",
(Result<defs::fileFormat>(Detector::*)(sls::Positions) const) &

28
slsDetectorServers/compileAllServers.sh Executable file → Normal file
View File

@ -1,19 +1,16 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package
# empty branch = developer branch in updateAPIVersion.sh
branch=""
det_list=("ctbDetectorServer
gotthard2DetectorServer
jungfrauDetectorServer
mythen3DetectorServer
moenchDetectorServer
xilinx_ctbDetectorServer"
xilinx_ctbDetectorServer"
)
usage="\nUsage: compileAllServers.sh [server|all(opt)] [update_api(opt)]. \n\tNo arguments mean all servers with 'developer' branch. \n\tupdate_api if true updates the api to version in VERSION file"
update_api=true
target=version
usage="\nUsage: compileAllServers.sh [server|all(opt)] [branch(opt)]. \n\tNo arguments mean all servers with 'developer' branch. \n\tNo 'branch' input means 'developer branch'"
# arguments
if [ $# -eq 0 ]; then
@ -37,12 +34,15 @@ elif [ $# -eq 1 ] || [ $# -eq 2 ]; then
declare -a det=("${1}")
#echo "Compiling only $1"
fi
# branch
if [ $# -eq 2 ]; then
update_api=$2
if not $update_api ; then
target=clean
# arg in list
if [[ $det_list == *$2* ]]; then
echo -e "Invalid argument 2: $2. $usage"
return 1
fi
branch+=$2
#echo "with branch $branch"
fi
else
echo -e "Too many arguments.$usage"
@ -53,9 +53,6 @@ declare -a deterror=("OK" "OK" "OK" "OK" "OK" "OK")
echo -e "list is ${det[@]}"
if $update_api; then
echo "updating api to $(cat ../VERSION)"
fi
# compile each server
idet=0
for i in ${det[@]}
@ -65,13 +62,14 @@ do
echo -e "Compiling $dir [$file]"
cd $dir
make clean
if make $target; then
if make version API_BRANCH=$branch; then
deterror[$idet]="OK"
else
deterror[$idet]="FAIL"
fi
mv bin/$dir bin/$file
git add -f bin/$file
cp bin/$file /tftpboot/
cd ..
echo -e "\n\n"
((++idet))

View File

@ -0,0 +1,86 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package
# empty branch = developer branch in updateAPIVersion.sh
branch=""
det_list=("ctbDetectorServer"
"gotthard2DetectorServer"
"jungfrauDetectorServer"
"mythen3DetectorServer"
"moenchDetectorServer"
"xilinx_ctbDetectorServer"
)
usage="\nUsage: compileAllServers.sh [server|all(opt)] [branch(opt)]. \n\tNo arguments mean all servers with 'developer' branch. \n\tNo 'branch' input means 'developer branch'"
# arguments
if [ $# -eq 0 ]; then
# no argument, all servers
declare -a det=${det_list[@]}
echo "Compiling all servers"
elif [ $# -eq 1 ] || [ $# -eq 2 ]; then
# 'all' servers
if [[ $1 == "all" ]]; then
declare -a det=${det_list[@]}
echo "Compiling all servers"
else
# only one server
# arg not in list
if [[ $det_list != *$1* ]]; then
echo -e "Invalid argument 1: $1. $usage"
return -1
fi
declare -a det=("${1}")
#echo "Compiling only $1"
fi
# branch
if [ $# -eq 2 ]; then
# arg in list
if [[ $det_list == *$2* ]]; then
echo -e "Invalid argument 2: $2. $usage"
return -1
fi
branch+=$2
#echo "with branch $branch"
fi
else
echo -e "Too many arguments.$usage"
return -1
fi
declare -a deterror=("OK" "OK" "OK" "OK" "OK" "OK")
echo -e "list is ${det[@]}"
# compile each server
idet=0
for i in ${det[@]}
do
dir=$i
file="${i}_developer"
echo -e "Compiling $dir [$file]"
cd $dir
make clean
if make API_BRANCH=$branch; then
deterror[$idet]="OK"
else
deterror[$idet]="FAIL"
fi
mv bin/$dir bin/$file
git add -f bin/$file
cp bin/$file /tftpboot/
cd ..
echo -e "\n\n"
((++idet))
done
echo -e "Results:"
idet=0
for i in ${det[@]}
do
printf "%s\t\t= %s\n" "$i" "${deterror[$idet]}"
((++idet))
done

23
slsDetectorServers/compileEigerServer.sh Executable file → Normal file
View File

@ -3,31 +3,21 @@
deterror="OK"
dir="eigerDetectorServer"
file="${dir}_developer"
usage="\nUsage: compileAllServers.sh [update_api(opt)]. \n\t update_api if true updates the api to version in VERSION file"
update_api=true
target=version
branch=""
# arguments
if [ $# -eq 1 ]; then
update_api=$1
if not $update_api ; then
target=clean
fi
branch+=$1
#echo "with branch $branch"
elif [ ! $# -eq 0 ]; then
echo -e "Only one optional argument allowed for update_api."
echo -e "Only one optional argument allowed for branch."
return -1
fi
if $update_api; then
echo "updating api to $(cat ../VERSION)"
fi
echo -e "Compiling $dir [$file]"
cd $dir
if make $target; then
make clean
if make version API_BRANCH=$branch; then
deterror="OK"
else
deterror="FAIL"
@ -35,6 +25,7 @@ fi
mv bin/$dir bin/$file
git add -f bin/$file
cp bin/$file /tftpboot/
cd ..
echo -e "\n\n"
printf "Result:\t\t= %s\n" "${deterror}"

View File

@ -25,10 +25,11 @@ version: clean versioning $(PROGS)
boot: $(OBJS)
version_branch=$(API_BRANCH)
version_name=APICTB
version_path=slsDetectorServers/ctbDetectorServer
versioning:
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -65,8 +65,8 @@
(0x000000FF << STATUS_PT_CNTRL_STTS_OFF_OFST)
#define STATUS_IDLE_MSK (0x677FF)
/* Look at me RO register TODO */
#define LOOK_AT_ME_REG (0x03 << MEM_MAP_SHIFT)
/* Register containing the git hash of the FPGA firmware */
#define FIRMWARE_GIT_HASH_REG (0x03 << MEM_MAP_SHIFT)
/* System Status RO register */
#define SYSTEM_STATUS_REG (0x04 << MEM_MAP_SHIFT)
@ -198,12 +198,43 @@
#define FIFO_TIN_STATUS_FIFO_EMPTY_4_MSK (0x00000001 << FIFO_TIN_STATUS_FIFO_EMPTY_4_OFST)
#define FIFO_TIN_STATUS_FIFO_EMPTY_ALL_MSK (0x0000000F << FIFO_TIN_STATUS_FIFO_EMPTY_1_OFST)
/* FIFO Transceiver Fill level RO register */
#define FIFO_TIN_FILL_REG (0x45 << MEM_MAP_SHIFT)
#define FIFO_TIN_FILL_FIFO_1_OFST (0)
#define FIFO_TIN_FILL_FIFO_1_MSK (0x00003FFF << FIFO_TIN_FILL_FIFO__1_OFST)
#define FIFO_TIN_FILL_FIFO_2_OFST (16)
#define FIFO_TIN_FILL_FIFO_2_MSK (0x00003FFF << FIFO_TIN_FILL_FIFO__2_OFST)
/* FIFO ADC Fill level RO register */
#define FIFO_ADC_FILL_REG (0x46 << MEM_MAP_SHIFT)
#define FIFO_ADC_FILL_FIFO_OFST (0)
#define FIFO_ADC_FILL_FIFO_MSK (0x00003FFF << FIFO_ADC_FILL_FIFO_OFST)
/* Enable continuos readout register */
#define CONTINUOUS_RO_ENABLE_REG (0x47 << MEM_MAP_SHIFT)
#define CONTINUOUS_RO_ADC_ENABLE_OFST (0)
#define CONTINUOUS_RO_TIN_ENABLE_OFST (1)
#define CONTINUOUS_RO_DBIT_ENABLE_OFST (2)
#define CONTINUOUS_RO_ADC_ENABLE_MSK (0x00000001 << CONTINUOUS_RO_ADC_ENABLE_OFST)
#define CONTINUOUS_RO_TIN_ENABLE_MSK (0x00000001 << CONTINUOUS_RO_TIN_ENABLE_OFST)
#define CONTINUOUS_RO_DBIT_ENABLE_MSK (0x00000001 << CONTINUOUS_RO_DBIT_ENABLE_OFST)
#define DBIT_INJECT_COUNTER_ENA_OFST (3) // continuously injects fake-data into the dbit fifo when enabled.
#define DBIT_INJECT_COUNTER_ENA_MSK (0x00000001 << DBIT_INJECT_COUNTER_ENA_OFST)
#define DBIT_INJECT_COUNTER_CLKDIV_OFST (8) // Additional clock divider for fake-data injection
#define DBIT_INJECT_COUNTER_CLKDIV_MSK (0x000000FF << DBIT_INJECT_COUNTER_CLKDIV_OFST)
/* 64-bit FPGA chip ID. Unique for every device. read-only */
#define FPGA_chipID_0_REG (0x48 << MEM_MAP_SHIFT)
#define FPGA_chipID_1_REG (0x49 << MEM_MAP_SHIFT)
/* FIFO Transceiver In 64 bit RO register */
#define FIFO_TIN_LSB_REG (0x31 << MEM_MAP_SHIFT)
#define FIFO_TIN_MSB_REG (0x32 << MEM_MAP_SHIFT)
/* FIFO Digital In Status RO register */
#define FIFO_DIN_STATUS_REG (0x3B << MEM_MAP_SHIFT)
#define FIFO_DIN_STATUS_FIFO_FILL_OFST (0)
#define FIFO_DIN_STATUS_FIFO_FILL_MSK (0x00003FFF)
#define FIFO_DIN_STATUS_FIFO_FULL_OFST (30)
#define FIFO_DIN_STATUS_FIFO_FULL_MSK (0x00000001 << FIFO_DIN_STATUS_FIFO_FULL_OFST)
#define FIFO_DIN_STATUS_FIFO_EMPTY_OFST (31)
@ -273,44 +304,6 @@
#define DUMMY_TRNSCVR_FIFO_RD_STRBE_OFST (14)
#define DUMMY_TRNSCVR_FIFO_RD_STRBE_MSK (0x00000001 << DUMMY_TRNSCVR_FIFO_RD_STRBE_OFST)
/* Receiver IP Address RW register */
#define RX_IP_REG (0x45 << MEM_MAP_SHIFT)
/* UDP Port RW register */
#define UDP_PORT_REG (0x46 << MEM_MAP_SHIFT)
#define UDP_PORT_RX_OFST (0)
#define UDP_PORT_RX_MSK (0x0000FFFF << UDP_PORT_RX_OFST)
#define UDP_PORT_TX_OFST (16)
#define UDP_PORT_TX_MSK (0x0000FFFF << UDP_PORT_TX_OFST)
/* Receiver Mac Address 64 bit RW register */
#define RX_MAC_LSB_REG (0x47 << MEM_MAP_SHIFT)
#define RX_MAC_MSB_REG (0x48 << MEM_MAP_SHIFT)
#define RX_MAC_LSB_OFST (0)
#define RX_MAC_LSB_MSK (0xFFFFFFFF << RX_MAC_LSB_OFST)
#define RX_MAC_MSB_OFST (0)
#define RX_MAC_MSB_MSK (0x0000FFFF << RX_MAC_MSB_OFST)
/* Detector/ Transmitter Mac Address 64 bit RW register */
#define TX_MAC_LSB_REG (0x49 << MEM_MAP_SHIFT)
#define TX_MAC_MSB_REG (0x4A << MEM_MAP_SHIFT)
#define TX_MAC_LSB_OFST (0)
#define TX_MAC_LSB_MSK (0xFFFFFFFF << TX_MAC_LSB_OFST)
#define TX_MAC_MSB_OFST (0)
#define TX_MAC_MSB_MSK (0x0000FFFF << TX_MAC_MSB_OFST)
/* Detector/ Transmitter IP Address RW register */
#define TX_IP_REG (0x4B << MEM_MAP_SHIFT)
/* Detector/ Transmitter IP Checksum RW register */
#define TX_IP_CHECKSUM_REG (0x4C << MEM_MAP_SHIFT)
#define TX_IP_CHECKSUM_OFST (0)
#define TX_IP_CHECKSUM_MSK (0x0000FFFF << TX_IP_CHECKSUM_OFST)
/* Configuration RW register */
#define CONFIG_REG (0x4D << MEM_MAP_SHIFT)

View File

@ -15,7 +15,6 @@
#include "loadPattern.h"
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // usleep
@ -94,10 +93,6 @@ void basictests() {
LOG(logINFOBLUE, ("********* Chip Test Board Virtual Server *********\n"));
#else
LOG(logINFOBLUE, ("************* Chip Test Board Server *************\n"));
initError = enableBlackfinAMCExternalAccessExtension(initErrorMessage);
if (initError == FAIL) {
return;
}
initError = defineGPIOpins(initErrorMessage);
if (initError == FAIL) {
return;
@ -443,32 +438,6 @@ uint32_t getDetectorIP() {
return res;
}
int enableBlackfinAMCExternalAccessExtension(char *mess) {
unsigned int value;
const char *file_path = BFIN_AMC_ACCESS_EXTENSION_FNAME;
FILE *file = fopen(file_path, "r");
if (!file) {
strcpy(mess, "Failed to enable blackfin AMC access extension. Could "
"not read EBIU_AMBCTL1\n");
LOG(logERROR, (mess));
return FAIL;
}
fscanf(file, "%x", &value);
fclose(file);
value |= BFIN_AMC_ACCESS_EXTENSION_ENA_VAL;
file = fopen(file_path, "w");
if (!file) {
strcpy(mess, "Failed to enable blackfin AMC access extension. Could "
"not write EBIU_AMBCTL1\n");
LOG(logERROR, (mess));
return FAIL;
}
fprintf(file, "0x%x", value);
fclose(file);
return OK;
}
/* initialization */
void initControlServer() {

View File

@ -25,10 +25,11 @@ version: clean versioning $(PROGS) #hv9m_blackfin_server
boot: $(OBJS)
version_branch=$(API_BRANCH)
version_name=APIEIGER
version_path=slsDetectorServers/eigerDetectorServer
versioning:
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -24,10 +24,11 @@ version: clean versioning $(PROGS)
boot: $(OBJS)
version_branch=$(API_BRANCH)
version_name=APIGOTTHARD2
version_path=slsDetectorServers/gotthard2DetectorServer
versioning:
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -24,10 +24,11 @@ version: clean versioning $(PROGS)
boot: $(OBJS)
version_branch=$(API_BRANCH)
version_name=APIJUNGFRAU
version_path=slsDetectorServers/jungfrauDetectorServer
versioning:
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -24,10 +24,11 @@ version: clean versioning $(PROGS)
boot: $(OBJS)
version_branch=$(API_BRANCH)
version_name=APIMOENCH
version_path=slsDetectorServers/moenchDetectorServer
versioning:
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -25,10 +25,11 @@ version: clean versioning $(PROGS)
boot: $(OBJS)
version_branch=$(API_BRANCH)
version_name=APIMYTHEN3
version_path=slsDetectorServers/mythen3DetectorServer
versioning:
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -5,23 +5,6 @@
#include <inttypes.h>
#include <sys/types.h>
/** enable support for ARDY signal on interface to FPGA
* needed to properly translate avalon_mm_waitrequest in the CTB firmware
* https://www.analog.com/media/en/dsp-documentation/processor-manuals/bf537_hwr_Rev3.2.pdf
* page 274
* */
#define BFIN_EBIU_AMBCTL1_B2_ARDY_ENA_OFST (0)
#define BFIN_EBIU_AMBCTL1_B2_ARDY_ENA_MSK \
(1 << BFIN_EBIU_AMBCTL1_B2_ARDY_ENA_OFST)
#define BFIN_EBIU_AMBCTL1_B2_ARDY_POL_OFST (1)
#define BFIN_EBIU_AMBCTL1_B2_ARDY_POL_MSK \
(1 << BFIN_EBIU_AMBCTL1_B2_ARDY_POL_OFST)
#define BFIN_AMC_ACCESS_EXTENSION_ENA_VAL \
(BFIN_EBIU_AMBCTL1_B2_ARDY_ENA_MSK | BFIN_EBIU_AMBCTL1_B2_ARDY_POL_MSK)
#define BFIN_AMC_ACCESS_EXTENSION_FNAME \
"/sys/kernel/debug/blackfin/ebiu_amc/EBIU_AMBCTL1"
/** I2C defines */
#define I2C_CLOCK_MHZ (131.25)

View File

@ -113,10 +113,6 @@ void setModuleId(int modid);
u_int64_t getDetectorMAC();
u_int32_t getDetectorIP();
#if defined(CHIPTESTBOARDD)
int enableBlackfinAMCExternalAccessExtension(char *mess);
#endif
// initialization
void initControlServer();
void initStopServer();

View File

@ -36,10 +36,11 @@ version: clean versioning $(PROGS)
boot: $(OBJS)
version_branch=$(API_BRANCH)
version_name=APIXILINXCTB
version_path=slsDetectorServers/xilinx_ctbDetectorServer
versioning:
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -1537,12 +1537,8 @@ void *start_timer(void *arg) {
packetSize, packetsPerFrame));
// Generate Data
char *imageData = (char *)malloc(imageSize);
char imageData[imageSize];
memset(imageData, 0, imageSize);
if (imageData == NULL) {
LOG(logERROR, ("Can not allocate image.\n"));
return NULL;
}
for (int i = 0; i < imageSize; i += sizeof(uint16_t)) {
*((uint16_t *)(imageData + i)) = i;
}
@ -1565,7 +1561,6 @@ void *start_timer(void *arg) {
usleep(expUs);
int srcOffset = 0;
int dataSent = 0;
// loop packet
for (int i = 0; i != packetsPerFrame; ++i) {
@ -1582,12 +1577,10 @@ void *start_timer(void *arg) {
header->column = detPos[X];
// fill data
int remaining = imageSize - dataSent;
int dataSize = remaining < maxDataSize ? remaining : maxDataSize;
memcpy(packetData + sizeof(sls_detector_header),
imageData + srcOffset, dataSize);
srcOffset += dataSize;
dataSent += dataSize;
imageData + srcOffset,
(imageSize < maxDataSize ? imageSize : maxDataSize));
srcOffset += maxDataSize;
sendUDPPacket(0, 0, packetData, packetSize);
}

View File

@ -100,6 +100,7 @@ if(SLS_USE_TEXTCLIENT)
target_link_libraries(${val1}
slsDetectorStatic
pthread
rt
)
SET_SOURCE_FILES_PROPERTIES( src/Caller.cpp PROPERTIES COMPILE_FLAGS "-Wno-unused-variable -Wno-unused-but-set-variable")

View File

@ -21,7 +21,6 @@ class Caller {
UdpDestination getUdpEntry();
int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand);
void WrongNumberOfParameters(size_t expected);
std::vector<defs::ROI> parseRoiVector(const std::string &input);
template <typename V> std::string OutStringHex(const V &value) {
if (value.equal())

View File

@ -2598,7 +2598,11 @@ rx_roi:
GET:
argc: 0
PUT:
argc: -1
args:
- argc: 2
arg_types: [ int, int ]
- argc: 4
arg_types: [ int, int, int, int ]
ratecorr:
is_description: true

View File

@ -119,10 +119,6 @@ class Detector {
Result<defs::xy> getModuleSize(Positions pos = {}) const;
defs::xy getPortPerModuleGeometry() const;
Result<defs::xy> getPortSize(Positions pos = {}) const;
/** Gets the actual full detector size. It is the same even if ROI changes
*/
defs::xy getDetectorSize() const;
@ -989,14 +985,13 @@ class Detector {
* every minute. Useful in 10G mode. */
void setRxArping(bool value, Positions pos = {});
/** Returns multi level ROIs */
std::vector<defs::ROI> getRxROI() const;
/** at module level */
Result<defs::ROI> getIndividualRxROIs(Positions pos) const;
/** Returns port level ROIs. Max 2 ports and hence max 2 elements per readout */
Result<std::array<defs::ROI, 2>> getRxROI(int module_id) const;
defs::ROI getRxROI() const;
/** only at multi module level without gap pixels. At most, 1 ROI per UDP port */
void setRxROI(const std::vector<defs::ROI> &args);
/** only at multi module level without gap pixels */
void setRxROI(const defs::ROI value);
void clearRxROI();

View File

@ -21,7 +21,6 @@ class Caller {
UdpDestination getUdpEntry();
int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand);
void WrongNumberOfParameters(size_t expected);
std::vector<defs::ROI> parseRoiVector(const std::string &input);
template <typename V> std::string OutStringHex(const V &value) {
if (value.equal())

View File

@ -719,119 +719,49 @@ std::string Caller::rx_zmqip(int action) {
}
return os.str();
}
std::string Caller::rx_roi(int action) {
std::ostringstream os;
std::string helpMessage =
std::string("[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in "
"receiver.\n\t") +
"For a list of rois, use '[' and ']; ' to distinguish between "
"rois and use comma inside the square brackets.\n\t If one fails to "
"use space after semicolon, please use quotes" +
"For example: [0,100,0,100]; [200,300,0,100] will set two "
"rois.or '[0,100,0,100];[200,300,0,100]' when the vector is a single "
"string\n\n\t" +
"Only allowed to set at multi module level and without gap "
"ixels.\n\n\t" +
"One can get rx_roi also at port level, by specifying the module id "
"and it will return the roi for each port.\n";
if (action == defs::HELP_ACTION) {
os << helpMessage;
os << "[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in "
"receiver.\n\tOnly allowed at multi module level and without gap "
"pixels."
<< '\n';
} else if (action == defs::GET_ACTION) {
if (!args.empty()) {
WrongNumberOfParameters(0);
}
if (det_id != -1) {
auto t = det->getRxROI(det_id);
os << ToString(t) << '\n';
} else {
if (det_id == -1) {
auto t = det->getRxROI();
os << ToString(t) << '\n';
os << t << '\n';
} else {
auto t = det->getIndividualRxROIs(std::vector<int>{det_id});
os << t << '\n';
}
} else if (action == defs::PUT_ACTION) {
std::vector<defs::ROI> rois;
// Support multiple args with bracketed ROIs, or single arg with
// semicolon-separated vector
bool isVectorInput =
std::all_of(args.begin(), args.end(), [](const std::string &a) {
return a.find('[') != std::string::npos &&
a.find(']') != std::string::npos;
});
try {
// previous format: 2 or 4 separate args
if ((args.size() == 2 || args.size() == 4) && !isVectorInput) {
defs::ROI t;
t.xmin = StringTo<int>(args[0]);
t.xmax = StringTo<int>(args[1]);
if (args.size() == 4) {
t.ymin = StringTo<int>(args[2]);
t.ymax = StringTo<int>(args[3]);
}
rois.emplace_back(t);
} else {
if (!isVectorInput)
WrongNumberOfParameters(2);
else {
for (const auto &arg : args) {
auto subRois = parseRoiVector(arg);
rois.insert(rois.end(), subRois.begin(), subRois.end());
}
}
}
} catch (const std::exception &e) {
throw RuntimeError("Could not parse ROI: " + helpMessage);
defs::ROI t;
// 2 or 4 arguments
if (args.size() != 2 && args.size() != 4) {
WrongNumberOfParameters(2);
}
if (args.size() == 2 || args.size() == 4) {
t.xmin = StringTo<int>(args[0]);
t.xmax = StringTo<int>(args[1]);
}
if (args.size() == 4) {
t.ymin = StringTo<int>(args[2]);
t.ymax = StringTo<int>(args[3]);
}
// only multi level
if (det_id != -1) {
throw RuntimeError("Cannot execute receiver ROI at module level");
}
det->setRxROI(rois);
os << ToString(rois) << '\n';
det->setRxROI(t);
os << t << '\n';
} else {
throw RuntimeError("Unknown action");
}
return os.str();
}
std::vector<defs::ROI> Caller::parseRoiVector(const std::string &input) {
std::vector<defs::ROI> rois;
std::stringstream ss(input);
std::string token;
while (std::getline(ss, token, ';')) {
token.erase(std::remove_if(token.begin(), token.end(), ::isspace),
token.end());
if (token.empty())
continue;
if (token.front() != '[' || token.back() != ']') {
throw RuntimeError("Each ROI must be enclosed in square brackets: "
"[xmin,xmax,ymin,ymax]");
}
token = token.substr(1, token.size() - 2); // remove brackets
std::vector<std::string> parts;
std::stringstream inner(token);
std::string num;
while (std::getline(inner, num, ',')) {
parts.push_back(num);
}
if (parts.size() != 4) {
throw RuntimeError("ROI must have 4 comma-separated integers");
}
defs::ROI roi;
roi.xmin = StringTo<int>(parts[0]);
roi.xmax = StringTo<int>(parts[1]);
roi.ymin = StringTo<int>(parts[2]);
roi.ymax = StringTo<int>(parts[3]);
rois.emplace_back(roi);
}
return rois;
}
std::string Caller::ratecorr(int action) {
std::ostringstream os;
if (action == defs::HELP_ACTION) {

View File

@ -201,22 +201,6 @@ Result<defs::xy> Detector::getModuleSize(Positions pos) const {
return pimpl->Parallel(&Module::getNumberOfChannels, pos);
}
defs::xy Detector::getPortPerModuleGeometry() const {
return pimpl->getPortGeometry();
}
Result<defs::xy> Detector::getPortSize(Positions pos) const {
Result<defs::xy> res = pimpl->Parallel(&Module::getNumberOfChannels, pos);
defs::xy portGeometry = getPortPerModuleGeometry();
for (auto &it : res) {
if (portGeometry.x == 2)
it.x /= 2;
if (portGeometry.y == 2)
it.y /= 2;
}
return res;
}
defs::xy Detector::getDetectorSize() const {
return pimpl->getNumberOfChannels();
}
@ -1383,22 +1367,16 @@ void Detector::setRxArping(bool value, Positions pos) {
pimpl->Parallel(&Module::setRxArping, pos, value);
}
std::vector<defs::ROI> Detector::getRxROI() const {
return pimpl->getRxROI();
Result<defs::ROI> Detector::getIndividualRxROIs(Positions pos) const {
return pimpl->Parallel(&Module::getRxROI, pos);
}
Result<std::array<defs::ROI, 2>> Detector::getRxROI(int module_id) const {
return pimpl->Parallel(&Module::getRxROI, {module_id});
}
defs::ROI Detector::getRxROI() const { return pimpl->getRxROI(); }
// RxROIs can be set for all types except CTB. At multi level without gap pixels
void Detector::setRxROI(const std::vector<defs::ROI> &args) {
pimpl->setRxROI(args);
}
void Detector::setRxROI(const defs::ROI value) { pimpl->setRxROI(value); }
void Detector::clearRxROI() { pimpl->clearRxROI(); }
// File
Result<defs::fileFormat> Detector::getFileFormat(Positions pos) const {

View File

@ -130,6 +130,10 @@ void DetectorImpl::initializeDetectorStructure() {
shm()->gapPixels = false;
// zmqlib default
shm()->zmqHwm = -1;
shm()->rx_roi.xmin = -1;
shm()->rx_roi.xmax = -1;
shm()->rx_roi.ymin = -1;
shm()->rx_roi.ymax = -1;
}
void DetectorImpl::initializeMembers(bool verify) {
@ -535,7 +539,7 @@ void DetectorImpl::readFrameFromReceiver() {
bool quadEnable = false;
// to flip image
bool eiger = false;
std::array<int, 4> rxRoi{}; // TODO: get roi from json header
std::array<int, 4> rxRoi = shm()->rx_roi.getIntArray();
std::vector<bool> runningList(zmqSocket.size());
std::vector<bool> connectList(zmqSocket.size());
@ -1544,6 +1548,31 @@ void DetectorImpl::setDefaultDac(defs::dacIndex index, int defaultValue,
Parallel(&Module::setDefaultDac, pos, index, defaultValue, sett);
}
defs::xy DetectorImpl::getPortGeometry() const {
defs::xy portGeometry(1, 1);
switch (shm()->detType) {
case EIGER:
portGeometry.x = modules[0]->getNumberofUDPInterfacesFromShm();
break;
case JUNGFRAU:
case MOENCH:
portGeometry.y = modules[0]->getNumberofUDPInterfacesFromShm();
break;
default:
break;
}
return portGeometry;
}
defs::xy DetectorImpl::calculatePosition(int moduleIndex,
defs::xy geometry) const {
defs::xy pos{};
int maxYMods = shm()->numberOfModules.y;
pos.y = (moduleIndex % maxYMods) * geometry.y;
pos.x = (moduleIndex / maxYMods) * geometry.x;
return pos;
}
void DetectorImpl::verifyUniqueDetHost(const uint16_t port,
std::vector<int> positions) const {
// port for given positions
@ -1667,8 +1696,7 @@ void DetectorImpl::verifyUniqueHost(
}
}
std::vector<defs::ROI> DetectorImpl::getRxROI() const {
defs::ROI DetectorImpl::getRxROI() const {
if (shm()->detType == CHIPTESTBOARD ||
shm()->detType == defs::XILINX_CHIPTESTBOARD) {
throw RuntimeError("RxRoi not implemented for this Detector");
@ -1676,170 +1704,75 @@ std::vector<defs::ROI> DetectorImpl::getRxROI() const {
if (modules.size() == 0) {
throw RuntimeError("No Modules added");
}
// complete detector in roi
auto t = Parallel(&Module::getRxROI, {});
if (t.equal() && t.front().completeRoi()) {
LOG(logDEBUG) << "no roi";
return defs::ROI(0, shm()->numberOfChannels.x - 1, 0,
shm()->numberOfChannels.y - 1);
}
// return std::vector<defs::ROI>{};
return rxRoiTemp;
// TODO
}
defs::xy numChansPerMod = modules[0]->getNumberOfChannels();
bool is2D = (numChansPerMod.y > 1 ? true : false);
defs::xy geometry = getPortGeometry();
bool DetectorImpl::roisOverlap(const defs::ROI &a, const defs::ROI &b) const {
bool xOverlap = !(a.xmax < b.xmin || a.xmin > b.xmax);
bool yOverlap = !(a.ymax < b.ymin || a.ymin > b.ymax);
return xOverlap && yOverlap;
}
defs::ROI retval{};
for (size_t iModule = 0; iModule != modules.size(); ++iModule) {
void DetectorImpl::validateROIs(const std::vector<defs::ROI> &rois) {
for (size_t i = 0; i < rois.size(); ++i) {
const auto &roi = rois[i];
if (roi.noRoi()) {
throw RuntimeError("Invalid Roi of size 0. Roi: " + ToString(roi));
}
bool is2D = (modules[0]->getNumberOfChannels().y > 1 ? true : false);
if (roi.completeRoi()) {
std::ostringstream oss;
oss << "Did you mean the clear roi command (API: clearRxROI, cmd: "
"rx_clearroi) Roi: [ -1, -1 ";
oss << (is2D ? ", -1, -1 ]?" : "]?");
throw RuntimeError(oss.str());
}
if (roi.xmin > roi.xmax || roi.ymin > roi.ymax) {
throw RuntimeError(
"Invalid Roi. xmin/ymin exceeds xmax/ymax. Roi: " +
ToString(roi));
}
if (roi.xmin < 0 || roi.xmax >= shm()->numberOfChannels.x) {
throw RuntimeError(
"ROI x-dimension outside detector bounds. Roi: " +
ToString(roi));
}
if (is2D) {
if (roi.ymin < 0 || roi.ymax >= shm()->numberOfChannels.y) {
throw RuntimeError(
"ROI y-dimension outside detector bounds. Roi: " +
ToString(roi));
}
defs::ROI moduleRoi = modules[iModule]->getRxROI();
if (moduleRoi.noRoi()) {
LOG(logDEBUG) << iModule << ": no roi";
} else {
if ((roi.ymin != -1 && roi.ymin != 0) ||
(roi.ymax != -1 && roi.ymax != 0)) {
throw RuntimeError(
"Invalid Y range for 1D detector: should be -1. Roi: " +
ToString(roi));
}
}
for (size_t j = i + 1; j < rois.size(); ++j) {
if (roisOverlap(rois[i], rois[j])) {
throw RuntimeError("Invalid Overlapping Rois.");
// expand complete roi
if (moduleRoi.completeRoi()) {
moduleRoi.xmin = 0;
moduleRoi.xmax = numChansPerMod.x;
if (is2D) {
moduleRoi.ymin = 0;
moduleRoi.ymax = numChansPerMod.y;
}
}
LOG(logDEBUG) << iModule << ": " << moduleRoi;
// get roi at detector level
defs::xy pos = calculatePosition(iModule, geometry);
defs::ROI moduleFullRoi{};
moduleFullRoi.xmin = numChansPerMod.x * pos.x + moduleRoi.xmin;
moduleFullRoi.xmax = numChansPerMod.x * pos.x + moduleRoi.xmax;
if (is2D) {
moduleFullRoi.ymin = numChansPerMod.y * pos.y + moduleRoi.ymin;
moduleFullRoi.ymax = numChansPerMod.y * pos.y + moduleRoi.ymax;
}
LOG(logDEBUG) << iModule << ": (full roi)" << moduleFullRoi;
// get min and max
if (retval.xmin == -1 || moduleFullRoi.xmin < retval.xmin) {
LOG(logDEBUG) << iModule << ": xmin updated";
retval.xmin = moduleFullRoi.xmin;
}
if (retval.xmax == -1 || moduleFullRoi.xmax > retval.xmax) {
LOG(logDEBUG) << iModule << ": xmax updated";
retval.xmax = moduleFullRoi.xmax;
}
if (retval.ymin == -1 || moduleFullRoi.ymin < retval.ymin) {
LOG(logDEBUG) << iModule << ": ymin updated";
retval.ymin = moduleFullRoi.ymin;
}
if (retval.ymax == -1 || moduleFullRoi.ymax > retval.ymax) {
LOG(logDEBUG) << iModule << ": ymax updated";
retval.ymax = moduleFullRoi.ymax;
}
}
LOG(logDEBUG) << iModule << ": (retval): " << retval;
}
if (retval.ymin == -1) {
retval.ymin = 0;
retval.ymax = 0;
}
return retval;
}
defs::xy DetectorImpl::calculatePosition(size_t moduleIndex,
const defs::xy &geometry) const {
if ((geometry.x != 0 && geometry.x != 1) ||
(geometry.y != 0 && geometry.y != 1)) {
throw RuntimeError("Invalid geometry configuration. Geometry: " +
ToString(geometry));
}
if (moduleIndex >= static_cast<size_t>(geometry.x * geometry.y)) {
throw RuntimeError("Module index " + std::to_string(moduleIndex) +
" out of bounds.");
}
int x = moduleIndex % geometry.x;
int y = moduleIndex / geometry.x;
return defs::xy{x, y};
}
defs::xy DetectorImpl::getPortGeometry() const {
defs::xy portGeometry(1, 1);
switch (shm()->detType) {
case EIGER:
portGeometry.x = modules[0]->getNumberofUDPInterfacesFromShm();
break;
case JUNGFRAU:
case MOENCH:
portGeometry.y = modules[0]->getNumberofUDPInterfacesFromShm();
break;
case GOTTHARD2: // 2nd port if used is for veto, not data
default:
break;
}
return portGeometry;
}
defs::xy DetectorImpl::calculatePosition(int moduleIndex,
defs::xy geometry) const {
int maxYMods = shm()->numberOfModules.y;
int y = (moduleIndex % maxYMods) * geometry.y;
int x = (moduleIndex / maxYMods) * geometry.x;
return defs::xy{x, y};
}
defs::ROI DetectorImpl::getModuleROI(int moduleIndex) const {
const defs::xy modSize = modules[0]->getNumberOfChannels();
// calculate module position (not taking into account port geometry)
const defs::xy modPos = calculatePosition(moduleIndex, defs::xy{1, 1});
return defs::ROI{modSize.x * modPos.x, modSize.x * (modPos.x + 1) - 1,
modSize.y * modPos.y,
modSize.y * (modPos.y + 1) - 1}; // convert y for 1d?
}
void DetectorImpl::convertGlobalRoiToPortLevel(
const defs::ROI &userRoi, const defs::ROI &moduleRoi,
std::array<defs::ROI, 2> &portRois) const {
const defs::xy modSize = modules[0]->getNumberOfChannels();
const defs::xy geometry = getPortGeometry();
const int numPorts = geometry.x * geometry.y;
if (numPorts > 2) {
throw RuntimeError("Only up to 2 ports per module supported.");
}
for (int port = 0; port < numPorts; ++port) {
defs::ROI portRoi = moduleRoi;
// Calculate port ROI boundaries (split vertically or horizontally)
if (geometry.x == 2) {
int midX = (moduleRoi.xmin + moduleRoi.xmax) / 2;
if (port == 0)
portRoi.xmax = midX;
else
portRoi.xmin = midX + 1;
} else if (geometry.y == 2) {
int midY = (moduleRoi.ymin + moduleRoi.ymax) / 2;
if (port == 0)
portRoi.ymax = midY;
else
portRoi.ymin = midY + 1;
}
// Check if user ROI overlaps with this port ROI
if (roisOverlap(userRoi, portRoi)) {
defs::ROI clipped{};
clipped.xmin = std::max(userRoi.xmin, portRoi.xmin);
clipped.xmax = std::min(userRoi.xmax, portRoi.xmax);
if (modSize.y > 1) {
clipped.ymin = std::max(userRoi.ymin, portRoi.ymin);
clipped.ymax = std::min(userRoi.ymax, portRoi.ymax);
}
// Check if port ROI already exists for this port
if (!portRois[port].completeRoi()) {
throw RuntimeError(
"Multiple ROIs specified for the same port " +
std::to_string(port) +
" with ROI: " + ToString(userRoi));
}
portRois[port] = clipped;
}
}
}
void DetectorImpl::setRxROI(const std::vector<defs::ROI> &args) {
void DetectorImpl::setRxROI(const defs::ROI arg) {
if (shm()->detType == CHIPTESTBOARD ||
shm()->detType == defs::XILINX_CHIPTESTBOARD) {
throw RuntimeError("RxRoi not implemented for this Detector");
@ -1847,42 +1780,118 @@ void DetectorImpl::setRxROI(const std::vector<defs::ROI> &args) {
if (modules.size() == 0) {
throw RuntimeError("No Modules added");
}
if (arg.noRoi()) {
throw RuntimeError("Invalid Roi of size 0.");
}
if (arg.completeRoi()) {
throw RuntimeError("Did you mean the clear roi command (API: "
"clearRxROI, cmd: rx_clearroi)?");
}
if (arg.xmin > arg.xmax || arg.ymin > arg.ymax) {
throw RuntimeError(
"Invalid Receiver Roi. xmin/ymin exceeds xmax/ymax.");
}
validateROIs(args);
defs::xy numChansPerMod = modules[0]->getNumberOfChannels();
bool is2D = (numChansPerMod.y > 1 ? true : false);
defs::xy geometry = getPortGeometry();
for (size_t iModule = 0; iModule < modules.size(); ++iModule) {
auto moduleGlobalRoi = getModuleROI(iModule);
if (!is2D && ((arg.ymin != -1 && arg.ymin != 0) ||
(arg.ymax != -1 && arg.ymax != 0))) {
throw RuntimeError(
"Invalid Receiver roi. Cannot set 2d roi for a 1d detector.");
}
// at most 2 rois per module (for each port)
std::array<defs::ROI, 2> portRois{};
if (arg.xmin < 0 || arg.xmax >= shm()->numberOfChannels.x ||
(is2D && (arg.ymin < 0 || arg.ymax >= shm()->numberOfChannels.y))) {
throw RuntimeError("Invalid Receiver Roi. Outside detector range.");
}
for (const auto &arg : args) {
if (roisOverlap(arg, moduleGlobalRoi)) {
convertGlobalRoiToPortLevel(arg, moduleGlobalRoi, portRois);
for (size_t iModule = 0; iModule != modules.size(); ++iModule) {
// default init = complete roi
defs::ROI moduleRoi{};
// incomplete roi
if (!arg.completeRoi()) {
// multi module Gotthard2
if (shm()->detType == GOTTHARD2 && size() > 1) {
moduleRoi.xmin = arg.xmin / 2;
moduleRoi.xmax = arg.xmax / 2;
if (iModule == 0) {
// all should be even
if (arg.xmin % 2 != 0) {
++moduleRoi.xmin;
}
} else if (iModule == 1) {
// all should be odd
if (arg.xmax % 2 == 0) {
--moduleRoi.xmax;
}
} else {
throw RuntimeError("Cannot have more than 2 modules for a "
"Gotthard2 detector");
}
} else {
// get module limits
defs::xy pos = calculatePosition(iModule, geometry);
defs::ROI moduleFullRoi{};
moduleFullRoi.xmin = numChansPerMod.x * pos.x;
moduleFullRoi.xmax = numChansPerMod.x * (pos.x + 1) - 1;
if (is2D) {
moduleFullRoi.ymin = numChansPerMod.y * pos.y;
moduleFullRoi.ymax = numChansPerMod.y * (pos.y + 1) - 1;
}
// no roi
if (arg.xmin > moduleFullRoi.xmax ||
arg.xmax < moduleFullRoi.xmin ||
(is2D && (arg.ymin > moduleFullRoi.ymax ||
arg.ymax < moduleFullRoi.ymin))) {
moduleRoi.setNoRoi();
}
// incomplete module roi
else if (arg.xmin > moduleFullRoi.xmin ||
arg.xmax < moduleFullRoi.xmax ||
(is2D && (arg.ymin > moduleFullRoi.ymin ||
arg.ymax < moduleFullRoi.ymax))) {
moduleRoi.xmin = (arg.xmin <= moduleFullRoi.xmin)
? 0
: (arg.xmin % numChansPerMod.x);
moduleRoi.xmax = (arg.xmax >= moduleFullRoi.xmax)
? numChansPerMod.x - 1
: (arg.xmax % numChansPerMod.x);
if (is2D) {
moduleRoi.ymin = (arg.ymin <= moduleFullRoi.ymin)
? 0
: (arg.ymin % numChansPerMod.y);
moduleRoi.ymax = (arg.ymax >= moduleFullRoi.ymax)
? numChansPerMod.y - 1
: (arg.ymax % numChansPerMod.y);
}
}
}
}
// print the rois for debugging
LOG(logINFOBLUE) << "Module " << iModule << " RxROIs:";
for (size_t iPort = 0; iPort != 2; iPort++) {
LOG(logINFOBLUE)
<< " Port " << iPort << ": " << ToString(portRois[iPort]);
}
modules[iModule]->setRxROI(portRois);
modules[iModule]->setRxROI(moduleRoi);
}
rxRoiTemp = args;
// updating shm rx_roi for gui purposes
shm()->rx_roi = arg;
// metadata
modules[0]->setRxROIMetadata(args);
}
void DetectorImpl::clearRxROI() {
rxRoiTemp.clear();
for (size_t iModule = 0; iModule < modules.size(); ++iModule) {
modules[iModule]->setRxROI(std::array<defs::ROI, 2>{});
if (arg.completeRoi()) {
modules[0]->setRxROIMetadata(defs::ROI(0, shm()->numberOfChannels.x - 1,
0,
shm()->numberOfChannels.y - 1));
} else {
modules[0]->setRxROIMetadata(arg);
}
}
int DetectorImpl::getNumberOfUdpPortsInRxROI() const {
return 0; // TODO
void DetectorImpl::clearRxROI() {
Parallel(&Module::setRxROI, {}, defs::ROI{});
shm()->rx_roi.xmin = -1;
shm()->rx_roi.ymin = -1;
shm()->rx_roi.xmax = -1;
shm()->rx_roi.ymax = -1;
}
void DetectorImpl::getBadChannels(const std::string &fname,

View File

@ -24,7 +24,7 @@ class detectorData;
class Module;
#define DETECTOR_SHMAPIVERSION 0x190809
#define DETECTOR_SHMVERSION 0x250616
#define DETECTOR_SHMVERSION 0x220505
#define SHORT_STRING_LENGTH 50
/**
@ -65,6 +65,8 @@ struct sharedDetector {
bool gapPixels;
/** high water mark of listening tcp port (only data) */
int zmqHwm;
/** in shm for gui purposes */
defs::ROI rx_roi{};
};
class DetectorImpl : public virtual slsDetectorDefs {
@ -301,11 +303,9 @@ class DetectorImpl : public virtual slsDetectorDefs {
std::vector<std::pair<std::string, uint16_t>>
verifyUniqueRxHost(const std::vector<std::string> &names) const;
defs::xy getPortGeometry() const;
std::vector<defs::ROI> getRxROI() const;
void setRxROI(const std::vector<defs::ROI> &args);
defs::ROI getRxROI() const;
void setRxROI(const defs::ROI arg);
void clearRxROI();
int getNumberOfUdpPortsInRxROI() const;
void getBadChannels(const std::string &fname, Positions pos) const;
void setBadChannels(const std::string &fname, Positions pos);
@ -422,19 +422,12 @@ class DetectorImpl : public virtual slsDetectorDefs {
*/
int kbhit();
defs::xy getPortGeometry() const;
defs::xy calculatePosition(int moduleIndex, defs::xy geometry) const;
void verifyUniqueHost(
bool isDet, std::vector<std::pair<std::string, uint16_t>> &hosts) const;
bool roisOverlap(const defs::ROI &a, const defs::ROI &b) const;
void validateROIs(const std::vector<defs::ROI> &rois);
defs::xy calculatePosition(size_t moduleIndex,
const defs::xy &geometry) const;
defs::xy calculatePosition(int moduleIndex, defs::xy geometry) const;
defs::ROI getModuleROI(int moduleIndex) const;
void convertGlobalRoiToPortLevel(
const defs::ROI &userRoi, const defs::ROI &moduleRoi,
std::array<defs::ROI, 2> &portRois) const;
const int detectorIndex{0};
SharedMemory<sharedDetector> shm{0, -1};
SharedMemory<CtbConfig> ctb_shm{0, -1, CtbConfig::shm_tag()};
@ -462,8 +455,6 @@ class DetectorImpl : public virtual slsDetectorDefs {
void (*dataReady)(detectorData *, uint64_t, uint32_t, void *){nullptr};
void *pCallbackArg{nullptr};
std::vector<defs::ROI> rxRoiTemp;
};
} // namespace sls

View File

@ -1521,26 +1521,17 @@ void Module::setRxArping(bool enable) {
sendToReceiver(F_SET_RECEIVER_ARPING, static_cast<int>(enable), nullptr);
}
std::array<defs::ROI, 2> Module::getRxROI() const {
return sendToReceiver<std::array<slsDetectorDefs::ROI, 2>>(F_RECEIVER_GET_RECEIVER_ROI);
defs::ROI Module::getRxROI() const {
return sendToReceiver<slsDetectorDefs::ROI>(F_RECEIVER_GET_RECEIVER_ROI);
}
void Module::setRxROI(const std::array<defs::ROI, 2> &portRois) {
sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI, portRois, nullptr);
void Module::setRxROI(const slsDetectorDefs::ROI arg) {
LOG(logDEBUG) << moduleIndex << ": " << arg;
sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI, arg, nullptr);
}
void Module::setRxROIMetadata(const std::vector<slsDetectorDefs::ROI> &args) {
LOG(logDEBUG) << "Sending to receiver " << moduleIndex
<< " [roi metadata: " << ToString(args) << ']';
auto receiver = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort);
receiver.Send(F_RECEIVER_SET_RECEIVER_ROI_METADATA);
receiver.setFnum(F_RECEIVER_SET_RECEIVER_ROI_METADATA);
receiver.Send(static_cast<int>(args.size()));
receiver.Send(args);
if (receiver.Receive<int>() == FAIL) {
throw ReceiverError("Receiver " + std::to_string(moduleIndex) +
" returned error: " + receiver.readErrorMessage());
}
void Module::setRxROIMetadata(const slsDetectorDefs::ROI arg) {
sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI_METADATA, arg, nullptr);
}
// File

View File

@ -301,9 +301,9 @@ class Module : public virtual slsDetectorDefs {
std::array<pid_t, NUM_RX_THREAD_IDS> getReceiverThreadIds() const;
bool getRxArping() const;
void setRxArping(bool enable);
std::array<defs::ROI, 2> getRxROI() const;
void setRxROI(const std::array<slsDetectorDefs::ROI, 2> &portRois);
void setRxROIMetadata(const std::vector<slsDetectorDefs::ROI> &args);
defs::ROI getRxROI() const;
void setRxROI(const slsDetectorDefs::ROI arg);
void setRxROIMetadata(const slsDetectorDefs::ROI arg);
/**************************************************
* *

View File

@ -17,119 +17,6 @@ namespace sls {
using test::GET;
using test::PUT;
TEST_CASE("ctb_acquire_check_file_size", "[.cmdcall]") {
Detector det;
Caller caller(&det);
auto det_type =
det.getDetectorType().tsquash("Inconsistent detector types to test");
if (det_type == defs::CHIPTESTBOARD ||
det_type == defs::XILINX_CHIPTESTBOARD) {
int num_frames_to_acquire = 2;
// all the test cases
{
testCtbAcquireInfo test_ctb_config;
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
test_ctb_config, num_frames_to_acquire, det, caller));
}
{
testCtbAcquireInfo test_ctb_config;
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
test_ctb_config.dbit_offset = 16;
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
test_ctb_config, num_frames_to_acquire, det, caller));
}
{
testCtbAcquireInfo test_ctb_config;
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
test_ctb_config.dbit_reorder = true;
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
test_ctb_config, num_frames_to_acquire, det, caller));
}
{
testCtbAcquireInfo test_ctb_config;
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
test_ctb_config.dbit_offset = 16;
test_ctb_config.dbit_reorder = true;
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
test_ctb_config, num_frames_to_acquire, det, caller));
}
{
testCtbAcquireInfo test_ctb_config;
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
test_ctb_config.dbit_offset = 16;
test_ctb_config.dbit_list.clear();
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
test_ctb_config, num_frames_to_acquire, det, caller));
}
{
testCtbAcquireInfo test_ctb_config;
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
test_ctb_config.dbit_offset = 16;
test_ctb_config.dbit_list.clear();
test_ctb_config.dbit_reorder = true;
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
test_ctb_config, num_frames_to_acquire, det, caller));
}
{
testCtbAcquireInfo test_ctb_config;
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
test_ctb_config, num_frames_to_acquire, det, caller));
}
{
testCtbAcquireInfo test_ctb_config;
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
test_ctb_config.dbit_offset = 16;
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
test_ctb_config, num_frames_to_acquire, det, caller));
}
{
testCtbAcquireInfo test_ctb_config;
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
test_ctb_config.dbit_list.clear();
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
test_ctb_config, num_frames_to_acquire, det, caller));
}
{
testCtbAcquireInfo test_ctb_config;
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
test_ctb_config.dbit_offset = 16;
test_ctb_config.dbit_list.clear();
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
test_ctb_config, num_frames_to_acquire, det, caller));
}
{
testCtbAcquireInfo test_ctb_config;
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
test_ctb_config.dbit_offset = 16;
test_ctb_config.dbit_list.clear();
test_ctb_config.dbit_reorder = true;
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
test_ctb_config, num_frames_to_acquire, det, caller));
}
{
testCtbAcquireInfo test_ctb_config;
test_ctb_config.readout_mode = defs::TRANSCEIVER_ONLY;
test_ctb_config.dbit_offset = 16;
test_ctb_config.dbit_list.clear();
test_ctb_config.dbit_reorder = true;
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
test_ctb_config, num_frames_to_acquire, det, caller));
}
{
testCtbAcquireInfo test_ctb_config;
test_ctb_config.readout_mode = defs::ANALOG_ONLY;
test_ctb_config.dbit_offset = 16;
test_ctb_config.dbit_list.clear();
test_ctb_config.dbit_reorder = true;
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
test_ctb_config, num_frames_to_acquire, det, caller));
}
}
}
/* dacs */
TEST_CASE("dacname", "[.cmdcall]") {

View File

@ -17,70 +17,6 @@ namespace sls {
using test::GET;
using test::PUT;
TEST_CASE("eiger_acquire_check_file_size", "[.cmdcall]") {
Detector det;
Caller caller(&det);
auto det_type =
det.getDetectorType().tsquash("Inconsistent detector types to test");
if (det_type == defs::EIGER) {
// save previous state
testFileInfo prev_file_info = get_file_state(det);
testCommonDetAcquireInfo prev_det_config_info =
get_common_acquire_config_state(det);
// save previous specific det type config
auto exptime = det.getExptime().tsquash("inconsistent exptime to test");
auto n_rows =
det.getReadNRows().tsquash("inconsistent number of rows to test");
auto dynamic_range =
det.getDynamicRange().tsquash("inconsistent dynamic range to test");
REQUIRE(false ==
det.getTenGiga().tsquash("inconsistent 10Giga to test"));
// defaults
int num_frames_to_acquire = 2;
testFileInfo test_file_info;
set_file_state(det, test_file_info);
testCommonDetAcquireInfo det_config;
det_config.num_frames_to_acquire = num_frames_to_acquire;
set_common_acquire_config_state(det, det_config);
// set default specific det type config
det.setExptime(std::chrono::microseconds{200});
det.setReadNRows(256);
det.setDynamicRange(16);
// acquire
test_acquire_with_receiver(caller, det);
// check frames caught
test_frames_caught(det, num_frames_to_acquire);
// check file size (assuming local pc)
{
detParameters par(det_type);
// data split into half due to 2 udp interfaces per half module
int num_chips = (par.nChipX / 2);
int bytes_per_pixel = (dynamic_range / 8);
size_t expected_image_size =
par.nChanX * par.nChanY * num_chips * bytes_per_pixel;
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
expected_image_size);
}
// restore previous state
set_file_state(det, prev_file_info);
set_common_acquire_config_state(det, prev_det_config_info);
// restore previous specific det type config
det.setExptime(exptime);
det.setReadNRows(n_rows);
det.setDynamicRange(dynamic_range);
}
}
/** temperature */
TEST_CASE("temp_fpgaext", "[.cmdcall]") {

View File

@ -4,7 +4,6 @@
#include "Caller.h"
#include "catch.hpp"
#include "sls/Detector.h"
#include "sls/logger.h"
#include "tests/globals.h"
namespace sls {
@ -89,227 +88,4 @@ void test_onchip_dac_caller(defs::dacIndex index, const std::string &dacname,
}
}
testFileInfo get_file_state(const Detector &det) {
return testFileInfo{
det.getFilePath().tsquash("Inconsistent file path"),
det.getFileNamePrefix().tsquash("Inconsistent file prefix"),
det.getAcquisitionIndex().tsquash(
"Inconsistent file acquisition index"),
det.getFileWrite().tsquash("Inconsistent file write state"),
det.getFileOverWrite().tsquash("Inconsistent file overwrite state"),
det.getFileFormat().tsquash("Inconsistent file format")};
}
void set_file_state(Detector &det, const testFileInfo &file_info) {
if (!file_info.file_path.empty())
det.setFilePath(file_info.file_path);
det.setFileNamePrefix(file_info.file_prefix);
det.setAcquisitionIndex(file_info.file_acq_index);
det.setFileWrite(file_info.file_write);
det.setFileOverWrite(file_info.file_overwrite);
det.setFileFormat(file_info.file_format);
}
void test_acquire_binary_file_size(const testFileInfo &file_info,
uint64_t num_frames_to_acquire,
uint64_t expected_image_size) {
assert(file_info.file_format == defs::BINARY);
std::string fname = file_info.file_path + "/" + file_info.file_prefix +
"_d0_f0_" + std::to_string(file_info.file_acq_index) +
".raw";
uint64_t expected_file_size =
num_frames_to_acquire *
(expected_image_size + sizeof(defs::sls_receiver_header));
auto actual_file_size = std::filesystem::file_size(fname);
REQUIRE(actual_file_size == expected_file_size);
}
void test_frames_caught(const Detector &det, int num_frames_to_acquire) {
auto frames_caught = det.getFramesCaught().tsquash(
"Inconsistent number of frames caught")[0];
REQUIRE(frames_caught == num_frames_to_acquire);
}
void test_acquire_with_receiver(Caller &caller, const Detector &det) {
REQUIRE_NOTHROW(caller.call("rx_start", {}, -1, PUT));
REQUIRE_NOTHROW(caller.call("start", {}, -1, PUT));
bool idle = false;
while (!idle) {
std::ostringstream oss;
REQUIRE_NOTHROW(caller.call("status", {}, -1, GET));
auto statusList = det.getDetectorStatus();
if (statusList.any(defs::ERROR)) {
throw std::runtime_error("error status while acquiring");
}
if (statusList.contains_only(defs::IDLE, defs::STOPPED)) {
idle = true;
}
}
REQUIRE_NOTHROW(caller.call("rx_stop", {}, -1, PUT));
}
testCommonDetAcquireInfo get_common_acquire_config_state(const Detector &det) {
return testCommonDetAcquireInfo{
det.getTimingMode().tsquash("Inconsistent timing mode"),
det.getNumberOfFrames().tsquash("Inconsistent number of frames"),
det.getNumberOfTriggers().tsquash("Inconsistent number of triggers"),
det.getPeriod().tsquash("Inconsistent period")};
}
void set_common_acquire_config_state(
Detector &det, const testCommonDetAcquireInfo &det_config_info) {
det.setTimingMode(det_config_info.timing_mode);
det.setNumberOfFrames(det_config_info.num_frames_to_acquire);
det.setNumberOfTriggers(det_config_info.num_triggers);
det.setPeriod(det_config_info.period);
}
testCtbAcquireInfo get_ctb_config_state(const Detector &det) {
testCtbAcquireInfo ctb_config_info{
det.getReadoutMode().tsquash("inconsistent readout mode to test"),
true,
det.getNumberOfAnalogSamples().tsquash(
"inconsistent number of analog samples to test"),
det.getNumberOfDigitalSamples().tsquash(
"inconsistent number of digital samples to test"),
det.getNumberOfTransceiverSamples().tsquash(
"inconsistent number of transceiver samples to test"),
0,
det.getTenGigaADCEnableMask().tsquash(
"inconsistent ten giga adc enable mask to test"),
det.getRxDbitOffset().tsquash("inconsistent rx dbit offset to test"),
det.getRxDbitList().tsquash("inconsistent rx dbit list to test"),
det.getRxDbitReorder().tsquash("inconsistent rx dbit reorder to test"),
det.getTransceiverEnableMask().tsquash(
"inconsistent transceiver mask to test")};
if (det.getDetectorType().tsquash("inconsistent detector type to test") ==
slsDetectorDefs::CHIPTESTBOARD) {
ctb_config_info.ten_giga =
det.getTenGiga().tsquash("inconsistent ten giga enable to test");
ctb_config_info.adc_enable_1g = det.getADCEnableMask().tsquash(
"inconsistent adc enable mask to test");
}
return ctb_config_info;
}
void set_ctb_config_state(Detector &det,
const testCtbAcquireInfo &ctb_config_info) {
det.setReadoutMode(ctb_config_info.readout_mode);
if (det.getDetectorType().tsquash("inconsistent detector type to test") ==
slsDetectorDefs::CHIPTESTBOARD) {
det.setTenGiga(ctb_config_info.ten_giga);
det.setADCEnableMask(ctb_config_info.adc_enable_1g);
}
det.setNumberOfAnalogSamples(ctb_config_info.num_adc_samples);
det.setNumberOfDigitalSamples(ctb_config_info.num_dbit_samples);
det.setNumberOfTransceiverSamples(ctb_config_info.num_trans_samples);
det.setTenGigaADCEnableMask(ctb_config_info.adc_enable_10g);
det.setRxDbitOffset(ctb_config_info.dbit_offset);
det.setRxDbitList(ctb_config_info.dbit_list);
det.setRxDbitReorder(ctb_config_info.dbit_reorder);
det.setTransceiverEnableMask(ctb_config_info.transceiver_mask);
}
uint64_t calculate_ctb_image_size(const testCtbAcquireInfo &test_info) {
uint64_t num_analog_bytes = 0, num_digital_bytes = 0,
num_transceiver_bytes = 0;
if (test_info.readout_mode == defs::ANALOG_ONLY ||
test_info.readout_mode == defs::ANALOG_AND_DIGITAL) {
uint32_t adc_enable_mask =
(test_info.ten_giga ? test_info.adc_enable_10g
: test_info.adc_enable_1g);
int num_analog_chans = __builtin_popcount(adc_enable_mask);
const int num_bytes_per_sample = 2;
num_analog_bytes =
num_analog_chans * num_bytes_per_sample * test_info.num_adc_samples;
LOG(logDEBUG1) << "[Analog Databytes: " << num_analog_bytes << ']';
}
// digital channels
if (test_info.readout_mode == defs::DIGITAL_ONLY ||
test_info.readout_mode == defs::ANALOG_AND_DIGITAL ||
test_info.readout_mode == defs::DIGITAL_AND_TRANSCEIVER) {
int num_digital_samples = test_info.num_dbit_samples;
if (test_info.dbit_offset > 0) {
uint64_t num_digital_bytes_reserved =
num_digital_samples * sizeof(uint64_t);
num_digital_bytes_reserved -= test_info.dbit_offset;
num_digital_samples = num_digital_bytes_reserved / sizeof(uint64_t);
}
int num_digital_chans = test_info.dbit_list.size();
if (num_digital_chans == 0) {
num_digital_chans = 64;
}
if (!test_info.dbit_reorder) {
uint32_t num_bits_per_sample = num_digital_chans;
if (num_bits_per_sample % 8 != 0) {
num_bits_per_sample += (8 - (num_bits_per_sample % 8));
}
num_digital_bytes = (num_bits_per_sample / 8) * num_digital_samples;
} else {
uint32_t num_bits_per_bit = num_digital_samples;
if (num_bits_per_bit % 8 != 0) {
num_bits_per_bit += (8 - (num_bits_per_bit % 8));
}
num_digital_bytes = num_digital_chans * (num_bits_per_bit / 8);
}
LOG(logDEBUG1) << "[Digital Databytes: " << num_digital_bytes << ']';
}
// transceiver channels
if (test_info.readout_mode == defs::TRANSCEIVER_ONLY ||
test_info.readout_mode == defs::DIGITAL_AND_TRANSCEIVER) {
int num_transceiver_chans =
__builtin_popcount(test_info.transceiver_mask);
const int num_bytes_per_channel = 8;
num_transceiver_bytes = num_transceiver_chans * num_bytes_per_channel *
test_info.num_trans_samples;
LOG(logDEBUG1) << "[Transceiver Databytes: " << num_transceiver_bytes
<< ']';
}
uint64_t image_size =
num_analog_bytes + num_digital_bytes + num_transceiver_bytes;
LOG(logDEBUG1) << "Expected image size: " << image_size;
return image_size;
}
void test_ctb_acquire_with_receiver(const testCtbAcquireInfo &test_info,
int64_t num_frames_to_acquire,
Detector &det, Caller &caller) {
// save previous state
testFileInfo prev_file_info = get_file_state(det);
testCommonDetAcquireInfo prev_det_config_info =
// overwrite exptime if not using virtual ctb server
get_common_acquire_config_state(det);
testCtbAcquireInfo prev_ctb_config_info = get_ctb_config_state(det);
// defaults
testFileInfo test_file_info;
set_file_state(det, test_file_info);
testCommonDetAcquireInfo det_config;
det_config.num_frames_to_acquire = num_frames_to_acquire;
set_common_acquire_config_state(det, det_config);
// set ctb config
set_ctb_config_state(det, test_info);
// acquire
REQUIRE_NOTHROW(test_acquire_with_receiver(caller, det));
// check frames caught
REQUIRE_NOTHROW(test_frames_caught(det, num_frames_to_acquire));
// check file size (assuming local pc)
uint64_t expected_image_size = calculate_ctb_image_size(test_info);
REQUIRE_NOTHROW(test_acquire_binary_file_size(
test_file_info, num_frames_to_acquire, expected_image_size));
// restore previous state
set_file_state(det, prev_file_info);
set_common_acquire_config_state(det, prev_det_config_info);
set_ctb_config_state(det, prev_ctb_config_info);
}
} // namespace sls

View File

@ -1,46 +1,9 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#pragma once
class Caller;
#include "sls/Detector.h"
#include "sls/sls_detector_defs.h"
#include <chrono>
#include <filesystem>
#include <thread>
namespace sls {
struct testFileInfo {
std::string file_path{"/tmp"};
std::string file_prefix{"sls_test"};
int64_t file_acq_index{0};
bool file_write{true};
bool file_overwrite{true};
slsDetectorDefs::fileFormat file_format{slsDetectorDefs::BINARY};
};
struct testCommonDetAcquireInfo {
slsDetectorDefs::timingMode timing_mode{slsDetectorDefs::AUTO_TIMING};
int64_t num_frames_to_acquire{2};
int64_t num_triggers{1};
std::chrono::nanoseconds period{std::chrono::milliseconds{2}};
};
struct testCtbAcquireInfo {
defs::readoutMode readout_mode{defs::ANALOG_AND_DIGITAL};
bool ten_giga{false};
int num_adc_samples{5000};
int num_dbit_samples{6000};
int num_trans_samples{288};
uint32_t adc_enable_1g{0xFFFFFF00};
uint32_t adc_enable_10g{0xFF00FFFF};
int dbit_offset{0};
std::vector<int> dbit_list{0, 12, 2, 43};
bool dbit_reorder{false};
uint32_t transceiver_mask{0x3};
};
void test_valid_port_caller(const std::string &command,
const std::vector<std::string> &arguments,
int detector_id, int action);
@ -50,26 +13,4 @@ void test_dac_caller(slsDetectorDefs::dacIndex index,
void test_onchip_dac_caller(slsDetectorDefs::dacIndex index,
const std::string &dacname, int dacvalue);
testFileInfo get_file_state(const Detector &det);
void set_file_state(Detector &det, const testFileInfo &file_info);
void test_acquire_binary_file_size(const testFileInfo &file_info,
uint64_t num_frames_to_acquire,
uint64_t expected_image_size);
void test_frames_caught(const Detector &det, int num_frames_to_acquire);
void test_acquire_with_receiver(Caller &caller, const Detector &det);
testCommonDetAcquireInfo get_common_acquire_config_state(const Detector &det);
void set_common_acquire_config_state(
Detector &det, const testCommonDetAcquireInfo &det_config_info);
testCtbAcquireInfo get_ctb_config_state(const Detector &det);
void set_ctb_config_state(Detector &det,
const testCtbAcquireInfo &ctb_config_info);
uint64_t calculate_ctb_image_size(const testCtbAcquireInfo &test_info);
void test_ctb_acquire_with_receiver(const testCtbAcquireInfo &test_info,
int64_t num_frames_to_acquire,
Detector &det, Caller &caller);
} // namespace sls

View File

@ -17,69 +17,6 @@ namespace sls {
using test::GET;
using test::PUT;
TEST_CASE("gotthard2_acquire_check_file_size", "[.cmdcall]") {
Detector det;
Caller caller(&det);
auto det_type =
det.getDetectorType().tsquash("Inconsistent detector types to test");
if (det_type == defs::GOTTHARD2) {
// save previous state
testFileInfo prev_file_info = get_file_state(det);
testCommonDetAcquireInfo prev_det_config_info =
get_common_acquire_config_state(det);
// save previous specific det type config
auto exptime = det.getExptime().tsquash("inconsistent exptime to test");
auto burst_mode =
det.getBurstMode().tsquash("inconsistent burst mode to test");
auto number_of_bursts = det.getNumberOfBursts().tsquash(
"inconsistent number of bursts to test");
auto burst_period =
det.getBurstPeriod().tsquash("inconsistent burst period to test");
// defaults
int num_frames_to_acquire = 2;
testFileInfo test_file_info;
set_file_state(det, test_file_info);
testCommonDetAcquireInfo det_config;
det_config.num_frames_to_acquire = num_frames_to_acquire;
set_common_acquire_config_state(det, det_config);
// set default specific det type config
det.setExptime(std::chrono::microseconds{200});
det.setBurstMode(defs::CONTINUOUS_EXTERNAL);
det.setNumberOfBursts(1);
det.setBurstPeriod(std::chrono::milliseconds{0});
// acquire
test_acquire_with_receiver(caller, det);
// check frames caught
test_frames_caught(det, num_frames_to_acquire);
// check file size (assuming local pc)
{
detParameters par(det_type);
int bytes_per_pixel = det.getDynamicRange().squash() / 8;
size_t expected_image_size =
par.nChanX * par.nChipX * bytes_per_pixel;
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
expected_image_size);
}
// restore previous state
set_file_state(det, prev_file_info);
set_common_acquire_config_state(det, prev_det_config_info);
// restore previous specific det type config
det.setExptime(exptime);
det.setBurstMode(burst_mode);
det.setNumberOfBursts(number_of_bursts);
det.setBurstPeriod(burst_period);
}
}
// time specific measurements for gotthard2
TEST_CASE("timegotthard2", "[.cmdcall]") {
Detector det;

View File

@ -15,65 +15,6 @@ namespace sls {
using test::GET;
using test::PUT;
TEST_CASE("jungfrau_acquire_check_file_size", "[.cmdcall]") {
Detector det;
Caller caller(&det);
auto det_type =
det.getDetectorType().tsquash("Inconsistent detector types to test");
if (det_type == defs::JUNGFRAU) {
// save previous state
testFileInfo prev_file_info = get_file_state(det);
testCommonDetAcquireInfo prev_det_config_info =
get_common_acquire_config_state(det);
// save previous specific det type config
auto exptime = det.getExptime().tsquash("inconsistent exptime to test");
auto num_udp_interfaces = det.getNumberofUDPInterfaces().tsquash(
"inconsistent number of udp interfaces");
auto n_rows =
det.getReadNRows().tsquash("inconsistent number of rows to test");
// defaults
int num_frames_to_acquire = 2;
testFileInfo test_file_info;
set_file_state(det, test_file_info);
testCommonDetAcquireInfo det_config;
det_config.num_frames_to_acquire = num_frames_to_acquire;
set_common_acquire_config_state(det, det_config);
// set default specific det type config
det.setExptime(std::chrono::microseconds{200});
det.setReadNRows(512);
// acquire
test_acquire_with_receiver(caller, det);
// check frames caught
test_frames_caught(det, num_frames_to_acquire);
// check file size (assuming local pc)
{
detParameters par(det_type);
int bytes_per_pixel = det.getDynamicRange().squash() / 8;
// if 2 udp interfaces, data split into half
size_t expected_image_size = (par.nChanX * par.nChanY * par.nChipX *
par.nChipY * bytes_per_pixel) /
num_udp_interfaces;
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
expected_image_size);
}
// restore previous state
set_file_state(det, prev_file_info);
set_common_acquire_config_state(det, prev_det_config_info);
// restore previous specific det type config
det.setExptime(exptime);
det.setReadNRows(n_rows);
}
}
/* dacs */
TEST_CASE("Setting and reading back Jungfrau dacs", "[.cmdcall][.dacs]") {

View File

@ -15,66 +15,6 @@ namespace sls {
using test::GET;
using test::PUT;
TEST_CASE("moench_acquire_check_file_size", "[.cmdcall]") {
Detector det;
Caller caller(&det);
auto det_type =
det.getDetectorType().tsquash("Inconsistent detector types to test");
if (det_type == defs::MOENCH) {
// save previous state
testFileInfo prev_file_info = get_file_state(det);
testCommonDetAcquireInfo prev_det_config_info =
get_common_acquire_config_state(det);
// save previous specific det type config
auto exptime = det.getExptime().tsquash("inconsistent exptime to test");
auto num_udp_interfaces = det.getNumberofUDPInterfaces().tsquash(
"inconsistent number of udp interfaces");
auto n_rows =
det.getReadNRows().tsquash("inconsistent number of rows to test");
// defaults
int num_frames_to_acquire = 2;
testFileInfo test_file_info;
set_file_state(det, test_file_info);
testCommonDetAcquireInfo det_config;
det_config.num_frames_to_acquire = num_frames_to_acquire;
set_common_acquire_config_state(det, det_config);
// set default specific det type config
det.setExptime(std::chrono::microseconds{200});
det.setReadNRows(400);
// acquire
test_acquire_with_receiver(caller, det);
// check frames caught
test_frames_caught(det, num_frames_to_acquire);
// check file size (assuming local pc)
{
detParameters par(det_type);
int bytes_per_pixel = det.getDynamicRange().squash() / 8;
// if 2 udp interfaces, data split into half
size_t expected_image_size = (par.nChanX * par.nChanY * par.nChipX *
par.nChipY * bytes_per_pixel) /
num_udp_interfaces;
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
expected_image_size);
}
// restore previous state
set_file_state(det, prev_file_info);
set_common_acquire_config_state(det, prev_det_config_info);
// restore previous specific det type config
det.setExptime(exptime);
det.setReadNRows(n_rows);
}
}
/* dacs */
TEST_CASE("Setting and reading back moench dacs", "[.cmdcall][.dacs]") {

View File

@ -17,74 +17,6 @@ namespace sls {
using test::GET;
using test::PUT;
TEST_CASE("mythen3_acquire_check_file_size", "[.cmdcall]") {
Detector det;
Caller caller(&det);
auto det_type =
det.getDetectorType().tsquash("Inconsistent detector types to test");
if (det_type == defs::MYTHEN3) {
// save previous state
testFileInfo prev_file_info = get_file_state(det);
testCommonDetAcquireInfo prev_det_config_info =
get_common_acquire_config_state(det);
// save previous specific det type config
auto exptime =
det.getExptimeForAllGates().tsquash("inconsistent exptime to test");
auto dynamic_range =
det.getDynamicRange().tsquash("inconsistent dynamic range to test");
uint32_t counter_mask =
det.getCounterMask().tsquash("inconsistent counter mask to test");
// defaults
int num_frames_to_acquire = 2;
testFileInfo test_file_info;
set_file_state(det, test_file_info);
testCommonDetAcquireInfo det_config;
det_config.num_frames_to_acquire = num_frames_to_acquire;
set_common_acquire_config_state(det, det_config);
// set default specific det type config
det.setExptime(-1, std::chrono::microseconds{200});
int test_dynamic_range = 16;
det.setDynamicRange(test_dynamic_range);
int test_counter_mask = 0x3;
int num_counters = __builtin_popcount(test_counter_mask);
det.setCounterMask(test_counter_mask);
// acquire
test_acquire_with_receiver(caller, det);
// check frames caught
test_frames_caught(det, num_frames_to_acquire);
// check file size (assuming local pc)
{
detParameters par(det_type);
int bytes_per_pixel = test_dynamic_range / 8;
int num_channels_per_counter = par.nChanX / 3;
size_t expected_image_size = num_channels_per_counter *
num_counters * par.nChipX *
bytes_per_pixel;
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
expected_image_size);
}
// restore previous state
set_file_state(det, prev_file_info);
set_common_acquire_config_state(det, prev_det_config_info);
// restore previous specific det type config
for (int iGate = 0; iGate < 3; ++iGate) {
det.setExptime(iGate, exptime[iGate]);
}
det.setDynamicRange(dynamic_range);
det.setCounterMask(counter_mask);
}
}
/* dacs */
TEST_CASE("Setting and reading back MYTHEN3 dacs", "[.cmdcall][.dacs]") {

View File

@ -466,6 +466,7 @@ TEST_CASE("rx_arping", "[.cmdcall][.rx]") {
}
}
}
TEST_CASE("rx_roi", "[.cmdcall]") {
Detector det;
Caller caller(&det);
@ -478,69 +479,33 @@ TEST_CASE("rx_roi", "[.cmdcall]") {
defs::xy detsize = det.getDetectorSize();
// 1d
if (det_type == defs::GOTTHARD2 || det_type == defs::MYTHEN3) {
if (det_type == defs::GOTTHARD || det_type == defs::GOTTHARD2 ||
det_type == defs::MYTHEN3) {
{
std::ostringstream oss;
caller.call("rx_roi", {"5", "10"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_roi [[5, 10]]\n");
REQUIRE(oss.str() == "rx_roi [5, 10]\n");
}
{
std::ostringstream oss;
caller.call("rx_roi", {"10", "15"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_roi [[10, 15]]\n");
REQUIRE(oss.str() == "rx_roi [10, 15]\n");
}
REQUIRE_THROWS(caller.call("rx_roi", {"0", "0"}, -1, PUT));
REQUIRE_THROWS(caller.call("rx_roi", {"-1", "-1"}, -1, PUT));
// xmin > xmax
REQUIRE_THROWS(caller.call("rx_roi", {"[12, 8, -1, -1]"}, -1, PUT));
// outside detector bounds
REQUIRE_THROWS(caller.call(
"rx_roi",
{"[95," + std::to_string(detsize.x + 5) + ", -1, -1]"}, -1,
PUT));
// module level not allowed
REQUIRE_THROWS(caller.call(
"rx_roi", {"[5, 10, -1, -1]"}, 0, PUT));
// vector of rois
// square brackets missing
REQUIRE_THROWS(caller.call(
"rx_roi", {"[5, 20, -1, -1; 25, 30, -1, -1]"}, -1, PUT));
// invalid roi, 4 parts expected
REQUIRE_THROWS(caller.call(
"rx_roi", {"[5, 20, -1]; [25, 30, -1, -1]"}, -1, PUT));
// overlapping rois
REQUIRE_THROWS(caller.call(
"rx_roi", {"[0, 10,-1, -1];[5, 15, -1, -1]"}, -1, PUT));
if (det.size() == 2) {
auto moduleSize = det.getModuleSize()[0];
std::string stringMin = std::to_string(moduleSize.x);
std::string stringMax = std::to_string(moduleSize.x + 1);
// separated by space is allowed
REQUIRE_NOTHROW(caller.call(
"rx_roi", {"[5, 10, -1, -1]", "[" + stringMin + ", " + stringMax + ", -1, -1]"}, -1, PUT));
std::ostringstream oss;
// separated by semicolon is allowed
REQUIRE_NOTHROW(caller.call(
"rx_roi", {"[5, 10, -1, -1];[" + stringMin + ", " + stringMax + ", -1, -1]"}, -1, PUT, oss));
REQUIRE(oss.str() ==
"rx_roi [[5, 10], [" + stringMin + ", " + stringMax + "]]\n");
}
REQUIRE_THROWS(
caller.call("rx_roi", {"10", "15", "25", "30"}, -1, PUT));
}
// 2d eiger, jungfrau, moench
// 2d
else {
{
std::ostringstream oss;
caller.call("rx_roi", {"10", "15", "1", "5"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_roi [[10, 15, 1, 5]]\n");
REQUIRE(oss.str() == "rx_roi [10, 15, 1, 5]\n");
}
{
std::ostringstream oss;
caller.call("rx_roi", {"10", "22", "18", "19"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_roi [[10, 22, 18, 19]]\n");
REQUIRE(oss.str() == "rx_roi [10, 22, 18, 19]\n");
}
{
std::ostringstream oss;
@ -548,104 +513,14 @@ TEST_CASE("rx_roi", "[.cmdcall]") {
{"1", std::to_string(detsize.x - 5), "1",
std::to_string(detsize.y - 5)},
-1, PUT, oss);
REQUIRE(oss.str() == std::string("rx_roi [[1, ") +
REQUIRE(oss.str() == std::string("rx_roi [1, ") +
std::to_string(detsize.x - 5) +
std::string(", 1, ") +
std::to_string(detsize.y - 5) +
std::string("]]\n"));
std::string("]\n"));
}
REQUIRE_THROWS(
caller.call("rx_roi", {"0", "0", "0", "0"}, -1, PUT));
REQUIRE_THROWS(
caller.call("rx_roi", {"-1", "-1", "-1", "-1"}, -1, PUT));
// xmin > xmax
REQUIRE_THROWS(caller.call("rx_roi", {"[12, 8, 0, 10]"}, -1, PUT));
// ymin > ymax
REQUIRE_THROWS(caller.call("rx_roi", {"[0, 10, 20, 5]"}, -1, PUT));
// outside detector bounds
REQUIRE_THROWS(caller.call(
"rx_roi", {"[95," + std::to_string(detsize.x + 5) + ", 0, 10]"},
-1, PUT));
REQUIRE_THROWS(caller.call(
"rx_roi",
{"[95, 100, 0, " + std::to_string(detsize.y + 5) + "]"}, -1,
PUT));
// module level not allowed
REQUIRE_THROWS(caller.call(
"rx_roi", {"[5, 10, 20, 30]"}, 0, PUT));
// vector of rois
// square brackets missing
REQUIRE_THROWS(caller.call(
"rx_roi", {"[5, 20, 20, 30; 25, 30, 14, 15]"}, -1, PUT));
// invalid roi, 4 parts expected
REQUIRE_THROWS(caller.call(
"rx_roi", {"[5, 20, 20]; [25, 30, 14, 15]"}, -1, PUT));
// overlapping rois
REQUIRE_THROWS(caller.call(
"rx_roi", {"[0, 10, 0, 10];[5, 15, 0, 10]"}, -1, PUT));
REQUIRE_THROWS(caller.call(
"rx_roi", {"[0, 10, 0, 10];[0, 10, 9, 11]"}, -1, PUT));
auto portSize = det.getPortSize()[0];
if (det_type == defs::EIGER) {
std::string stringMin = std::to_string(portSize.x);
std::string stringMax = std::to_string(portSize.x + 1);
// separated by space is allowed
REQUIRE_NOTHROW(caller.call(
"rx_roi", {"[5, 10, 20, 30]", "[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT));
std::ostringstream oss;
// separated by semicolon is allowed
REQUIRE_NOTHROW(caller.call(
"rx_roi", {"[5, 10, 20, 30];[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT, oss));
REQUIRE(oss.str() ==
"rx_roi [[5, 10, 20, 30], [" + stringMin + ", " + stringMax + ", 20, 30]]\n");
}
if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH) {
// 2 interfaces or 2 modules
if ((det.getNumberofUDPInterfaces().tsquash(
"inconsistent number of interfaces") == 2) || (det.size() == 2)) {
std::string stringMin = std::to_string(portSize.y);
std::string stringMax = std::to_string(portSize.y + 1);
if (det.size() == 2) {
auto moduleSize = det.getModuleSize()[0];
stringMin = std::to_string(moduleSize.y);
stringMax = std::to_string(moduleSize.y + 1);
}
// separated by space is allowed
REQUIRE_NOTHROW(caller.call(
"rx_roi", {"[5, 10, 20, 30]", "[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT));
std::ostringstream oss;
// separated by semicolon is allowed
REQUIRE_NOTHROW(caller.call(
"rx_roi", {"[5, 10, 20, 30];[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT, oss));
REQUIRE(oss.str() ==
"rx_roi [[5, 10, 20, 30], [25, 28, " + stringMin + ", " + stringMax + "]]\n");
// verify individual roi
if (det_type == defs::JUNGFRAU) {
std::ostringstream oss, oss1;
REQUIRE_NOTHROW(caller.call(
"rx_roi", {"[100,500,100,400]"}, -1, PUT, oss));
REQUIRE(oss.str() == "rx_roi [[100, 500, 100, 400]]\n");
REQUIRE_NOTHROW(
caller.call("rx_roi", {}, 0, GET, oss1));
REQUIRE(oss1.str() == "rx_roi [[[100, 500, 100, 255], "
"[100, 500, 256, 400]]]\n");
} else {
std::ostringstream oss, oss1;
REQUIRE_NOTHROW(caller.call(
"rx_roi", {"[100,200,100,300]"}, -1, PUT, oss));
REQUIRE(oss.str() == "rx_roi [[100, 200, 100, 300]]\n");
REQUIRE_NOTHROW(
caller.call("rx_roi", {}, 0, GET, oss1));
REQUIRE(oss1.str() == "rx_roi [[[100, 200, 100, 199], "
"[100, 200, 200, 300]]]\n");
}
}
}
}
for (int i = 0; i != det.size(); ++i) {
@ -654,7 +529,6 @@ TEST_CASE("rx_roi", "[.cmdcall]") {
}
}
TEST_CASE("rx_clearroi", "[.cmdcall]") {
Detector det;
Caller caller(&det);

View File

@ -12,7 +12,6 @@
#include <thread>
#include "tests/globals.h"
#include <filesystem>
namespace sls {

View File

@ -1693,19 +1693,19 @@ int ClientInterface::set_arping(Interface &socket) {
}
int ClientInterface::get_receiver_roi(Interface &socket) {
auto retvals = impl()->getPortROIs();
LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retvals);
return socket.sendResult(retvals);
auto retval = impl()->getReceiverROI();
LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retval);
return socket.sendResult(retval);
}
int ClientInterface::set_receiver_roi(Interface &socket) {
auto args = socket.Receive<std::array<ROI, 2>>();
auto arg = socket.Receive<ROI>();
if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD)
functionNotImplemented();
LOG(logDEBUG1) << "Set Receiver ROI: " << ToString(args);
LOG(logDEBUG1) << "Set Receiver ROI: " << ToString(arg);
verifyIdle(socket);
try {
impl()->setPortROIs(args);
impl()->setReceiverROI(arg);
} catch (const std::exception &e) {
throw RuntimeError("Could not set Receiver ROI [" +
std::string(e.what()) + ']');
@ -1715,22 +1715,18 @@ int ClientInterface::set_receiver_roi(Interface &socket) {
}
int ClientInterface::set_receiver_roi_metadata(Interface &socket) {
auto roiSize = socket.Receive<int>();
LOG(logDEBUG) << "Number of ReceiverROI metadata: " << roiSize;
std::vector<ROI> rois(roiSize);
if (roiSize > 0) {
socket.Receive(rois);
}
auto arg = socket.Receive<ROI>();
if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD)
functionNotImplemented();
LOG(logDEBUG1) << "Set Receiver ROI Metadata: " << ToString(arg);
verifyIdle(socket);
LOG(logINFO) << "Setting ReceiverROI metadata[" << roiSize << ']';
try {
impl()->setMultiROIMetadata(rois);
impl()->setReceiverROIMetadata(arg);
} catch (const std::exception &e) {
throw RuntimeError("Could not set ReceiverROI metadata [" +
std::string(e.what()) + ']');
}
return socket.Send(OK);
}

View File

@ -48,10 +48,10 @@ void DataProcessor::SetUdpPortNumber(const uint16_t portNumber) {
void DataProcessor::SetActivate(bool enable) { activated = enable; }
void DataProcessor::SetPortROI(ROI roi) {
portRoi = roi;
isPartiallyInRoi = portRoi.completeRoi() ? false : true;
isOutsideRoi = portRoi.noRoi();
void DataProcessor::SetReceiverROI(ROI roi) {
receiverRoi = roi;
receiverRoiEnabled = receiverRoi.completeRoi() ? false : true;
receiverNoRoi = receiverRoi.noRoi();
}
void DataProcessor::SetDataStreamEnable(bool enable) {
@ -154,17 +154,17 @@ void DataProcessor::CreateFirstFiles(const std::string &fileNamePrefix,
CloseFiles();
// deactivated (half module/ single port or no roi), dont write file
if (!activated || !detectorDataStream || isOutsideRoi) {
if (!activated || !detectorDataStream || receiverNoRoi) {
return;
}
#ifdef HDF5C
int nx = generalData->nPixelsX;
int ny = generalData->nPixelsY;
if (isPartiallyInRoi) {
nx = portRoi.xmax - portRoi.xmin + 1;
ny = portRoi.ymax - portRoi.ymin + 1;
if (portRoi.ymax == -1 || portRoi.ymin == -1) {
if (receiverRoiEnabled) {
nx = receiverRoi.xmax - receiverRoi.xmin + 1;
ny = receiverRoi.ymax - receiverRoi.ymin + 1;
if (receiverRoi.ymax == -1 || receiverRoi.ymin == -1) {
ny = 1;
}
}
@ -203,7 +203,7 @@ std::string DataProcessor::CreateVirtualFile(
const int modulePos, const int numModX, const int numModY,
std::mutex *hdf5LibMutex) {
if (isPartiallyInRoi) {
if (receiverRoiEnabled) {
throw std::runtime_error(
"Skipping virtual hdf5 file since rx_roi is enabled.");
}
@ -235,7 +235,7 @@ void DataProcessor::LinkFileInMaster(const std::string &masterFileName,
const bool silentMode,
std::mutex *hdf5LibMutex) {
if (isPartiallyInRoi) {
if (receiverRoiEnabled) {
throw std::runtime_error(
"Should not be here, roi with hdf5 virtual should throw.");
}
@ -301,7 +301,7 @@ void DataProcessor::ThreadExecution() {
// stream (if time/freq to stream) or free
if (streamCurrentFrame) {
// copy the complete image back if roi enabled
if (isPartiallyInRoi) {
if (receiverRoiEnabled) {
memImage->size = generalData->imageSize;
memcpy(memImage->data, &completeImageToStreamBeforeCropping[0],
generalData->imageSize);
@ -352,20 +352,16 @@ void DataProcessor::ProcessAnImage(sls_receiver_header &header, size_t &size,
if (framePadding && nump < generalData->packetsPerFrame)
PadMissingPackets(header, data);
if (generalData->readoutType == slsDetectorDefs::DIGITAL_ONLY ||
generalData->readoutType == slsDetectorDefs::ANALOG_AND_DIGITAL ||
generalData->readoutType == slsDetectorDefs::DIGITAL_AND_TRANSCEIVER) {
// rearrange ctb digital bits
if (!generalData->ctbDbitList.empty()) {
ArrangeDbitData(size, data);
} else if (generalData->ctbDbitReorder) {
std::vector<int> ctbDbitList(64);
std::iota(ctbDbitList.begin(), ctbDbitList.end(), 0);
generalData->SetctbDbitList(ctbDbitList);
ArrangeDbitData(size, data);
} else if (generalData->ctbDbitOffset > 0) {
RemoveTrailingBits(size, data);
}
// rearrange ctb digital bits
if (!generalData->ctbDbitList.empty()) {
ArrangeDbitData(size, data);
} else if (generalData->ctbDbitReorder) {
std::vector<int> ctbDbitList(64);
std::iota(ctbDbitList.begin(), ctbDbitList.end(), 0);
generalData->SetctbDbitList(ctbDbitList);
ArrangeDbitData(size, data);
} else if (generalData->ctbDbitOffset > 0) {
RemoveTrailingBits(size, data);
}
// 'stream Image' check has to be done here before crop image
@ -381,7 +377,7 @@ void DataProcessor::ProcessAnImage(sls_receiver_header &header, size_t &size,
streamCurrentFrame = false;
}
if (isPartiallyInRoi) {
if (receiverRoiEnabled) {
// copy the complete image to stream before cropping
if (streamCurrentFrame) {
memcpy(&completeImageToStreamBeforeCropping[0], data,
@ -679,20 +675,20 @@ void DataProcessor::ArrangeDbitData(size_t &size, char *data) {
memcpy(data + nAnalogDataBytes, result.data(),
totalNumBytes * sizeof(uint8_t));
LOG(logDEBUG1) << "nDigitalDataBytes: " << totalNumBytes
LOG(logDEBUG1) << "totalNumBytes: " << totalNumBytes
<< " nAnalogDataBytes:" << nAnalogDataBytes
<< " ctbDbitOffset:" << ctbDbitOffset
<< " nTransceiverDataBytes:" << nTransceiverDataBytes
<< " toal size:" << size;
<< " size:" << size;
}
void DataProcessor::CropImage(size_t &size, char *data) {
LOG(logDEBUG) << "Cropping Image to ROI " << ToString(portRoi);
LOG(logDEBUG) << "Cropping Image to ROI " << ToString(receiverRoi);
int nPixelsX = generalData->nPixelsX;
int xmin = portRoi.xmin;
int xmax = portRoi.xmax;
int ymin = portRoi.ymin;
int ymax = portRoi.ymax;
int xmin = receiverRoi.xmin;
int xmax = receiverRoi.xmax;
int ymin = receiverRoi.ymin;
int ymax = receiverRoi.ymax;
int xwidth = xmax - xmin + 1;
int ywidth = ymax - ymin + 1;
if (ymin == -1 || ymax == -1) {

View File

@ -39,7 +39,7 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
void SetUdpPortNumber(const uint16_t portNumber);
void SetActivate(bool enable);
void SetPortROI(const ROI arg);
void SetReceiverROI(ROI roi);
void SetDataStreamEnable(bool enable);
void SetStreamingFrequency(uint32_t value);
void SetStreamingTimerInMs(uint32_t value);
@ -159,16 +159,16 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
uint16_t udpPortNumber{0};
bool dataStreamEnable;
bool activated{false};
ROI portRoi{};
bool isPartiallyInRoi{false};
bool isOutsideRoi{false};
ROI receiverRoi{};
bool receiverRoiEnabled{false};
bool receiverNoRoi{false};
std::unique_ptr<char[]> completeImageToStreamBeforeCropping;
/** if 0, sending random images with a timer */
uint32_t streamingFrequency;
uint32_t streamingTimerInMs;
uint32_t streamingStartFnum;
uint32_t currentFreqCount{0};
struct timespec timerbegin {};
struct timespec timerbegin{};
bool framePadding;
std::atomic<bool> startedFlag{false};
std::atomic<uint64_t> firstIndex{0};

View File

@ -53,14 +53,7 @@ void DataStreamer::SetAdditionalJsonHeader(
isAdditionalJsonUpdated = true;
}
void DataStreamer::SetPortROI(ROI roi) {
if (roi.completeRoi()) {
portRoi =
ROI(0, generalData->nPixelsX - 1, 0, generalData->nPixelsY - 1);
} else {
portRoi = roi;
}
}
void DataStreamer::SetReceiverROI(ROI roi) { receiverRoi = roi; }
void DataStreamer::ResetParametersforNewAcquisition(const std::string &fname) {
StopRunning();
@ -217,7 +210,7 @@ int DataStreamer::SendDataHeader(sls_detector_header header, uint32_t size,
isAdditionalJsonUpdated = false;
}
zHeader.addJsonHeader = localAdditionalJsonHeader;
zHeader.rx_roi = portRoi.getIntArray();
zHeader.rx_roi = receiverRoi.getIntArray();
return zmqSocket->SendHeader(index, zHeader);
}

View File

@ -38,7 +38,7 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject {
void SetNumberofTotalFrames(uint64_t value);
void
SetAdditionalJsonHeader(const std::map<std::string, std::string> &json);
void SetPortROI(ROI roi);
void SetReceiverROI(ROI roi);
void ResetParametersforNewAcquisition(const std::string &fname);
/**
@ -91,7 +91,7 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject {
uint64_t fileIndex{0};
bool flipRows{false};
std::map<std::string, std::string> additionalJsonHeader;
ROI portRoi{};
ROI receiverRoi{};
/** Used by streamer thread to update local copy (reduce number of locks
* during streaming) */

View File

@ -104,11 +104,11 @@ void zmq_free(void *data, void *hint) { delete[] static_cast<char *>(data); }
void print_frames(const PortFrameMap &frame_port_map) {
LOG(sls::logDEBUG) << "Printing frames";
for (const auto &it : frame_port_map) {
const uint16_t udpPort = it.first;
uint16_t udpPort = it.first;
const auto &frame_map = it.second;
LOG(sls::logDEBUG) << "UDP port: " << udpPort;
for (const auto &frame : frame_map) {
const uint64_t fnum = frame.first;
uint64_t fnum = frame.first;
const auto &msg_list = frame.second;
LOG(sls::logDEBUG)
<< " acq index: " << fnum << '[' << msg_list.size() << ']';
@ -127,26 +127,30 @@ std::set<uint64_t> get_valid_fnums(const PortFrameMap &port_frame_map) {
// collect all unique frame numbers from all ports
std::set<uint64_t> unique_fnums;
for (const auto &it : port_frame_map) {
const FrameMap &frame_map = it.second;
for (const auto &frame : frame_map) {
unique_fnums.insert(frame.first);
for (auto it = port_frame_map.begin(); it != port_frame_map.begin(); ++it) {
const FrameMap &frame_map = it->second;
for (auto frame = frame_map.begin(); frame != frame_map.end();
++frame) {
unique_fnums.insert(frame->first);
}
}
// collect valid frame numbers
for (auto &fnum : unique_fnums) {
bool is_valid = true;
for (const auto &it : port_frame_map) {
const uint16_t port = it.first;
const FrameMap &frame_map = it.second;
for (auto it = port_frame_map.begin(); it != port_frame_map.end();
++it) {
uint16_t port = it->first;
const FrameMap &frame_map = it->second;
auto frame = frame_map.find(fnum);
// invalid: fnum missing in one port
if (frame == frame_map.end()) {
LOG(sls::logDEBUG)
<< "Fnum " << fnum << " is missing in port " << port;
auto upper_frame = frame_map.upper_bound(fnum);
if (upper_frame == frame_map.end()) {
// invalid: fnum greater than all in that port
auto last_frame = std::prev(frame_map.end());
auto last_fnum = last_frame->first;
if (fnum > last_fnum) {
LOG(sls::logDEBUG) << "And no larger fnum found. Fnum "
<< fnum << " is invalid.\n";
is_valid = false;
@ -216,26 +220,18 @@ void Correlate(FrameStatus *stat) {
// sending all valid fnum data packets
for (const auto &fnum : valid_fnums) {
ZmqMsgList msg_list;
for (const auto &it : stat->frames) {
const uint16_t port = it.first;
const FrameMap &frame_map = it.second;
PortFrameMap &port_frame_map = stat->frames;
for (auto it = port_frame_map.begin();
it != port_frame_map.end(); ++it) {
uint16_t port = it->first;
const FrameMap &frame_map = it->second;
auto frame = frame_map.find(fnum);
if (frame != frame_map.end()) {
msg_list.insert(msg_list.end(),
stat->frames[port][fnum].begin(),
stat->frames[port][fnum].end());
}
}
LOG(printHeadersLevel)
<< "Sending data packets for fnum " << fnum;
zmq_send_multipart(socket, msg_list);
// clean up
for (const auto &it : stat->frames) {
const uint16_t port = it.first;
const FrameMap &frame_map = it.second;
auto frame = frame_map.find(fnum);
if (frame != frame_map.end()) {
for (zmq_msg_t *msg : frame->second) {
// clean up
for (zmq_msg_t *msg : stat->frames[port][fnum]) {
if (msg) {
zmq_msg_close(msg);
delete msg;
@ -244,6 +240,9 @@ void Correlate(FrameStatus *stat) {
stat->frames[port].erase(fnum);
}
}
LOG(printHeadersLevel)
<< "Sending data packets for fnum " << fnum;
zmq_send_multipart(socket, msg_list);
}
}
// sending all end packets
@ -257,21 +256,6 @@ void Correlate(FrameStatus *stat) {
}
}
stat->ends.clear();
// clean up old frames
for (auto &it : stat->frames) {
FrameMap &frame_map = it.second;
for (auto &frame : frame_map) {
for (zmq_msg_t *msg : frame.second) {
if (msg) {
zmq_msg_close(msg);
delete msg;
}
}
frame.second.clear();
}
frame_map.clear();
}
stat->frames.clear();
}
}
}

View File

@ -63,8 +63,8 @@ class GeneralData {
slsDetectorDefs::frameDiscardPolicy frameDiscardMode{
slsDetectorDefs::NO_DISCARD};
GeneralData(){};
virtual ~GeneralData(){};
GeneralData() {};
virtual ~GeneralData() {};
// Returns the pixel depth in byte, 4 bits being 0.5 byte
float GetPixelDepth() { return float(dynamicRange) / 8; }

View File

@ -184,7 +184,7 @@ void Implementation::SetupListener(int i) {
listener[i]->SetUdpPortNumber(udpPortNum[i]);
listener[i]->SetEthernetInterface(eth[i]);
listener[i]->SetActivate(activated);
listener[i]->SetIsOutsideRoi(portRois[i].noRoi());
listener[i]->SetNoRoi(portRois[i].noRoi());
listener[i]->SetDetectorDatastream(detectorDataStream[i]);
listener[i]->SetSilentMode(silentMode);
}
@ -194,7 +194,7 @@ void Implementation::SetupDataProcessor(int i) {
dataProcessor[i]->SetGeneralData(generalData);
dataProcessor[i]->SetUdpPortNumber(udpPortNum[i]);
dataProcessor[i]->SetActivate(activated);
dataProcessor[i]->SetPortROI(portRois[i]);
dataProcessor[i]->SetReceiverROI(portRois[i]);
dataProcessor[i]->SetDataStreamEnable(dataStreamEnable);
dataProcessor[i]->SetStreamingFrequency(streamingFrequency);
dataProcessor[i]->SetStreamingTimerInMs(streamingTimerInMs);
@ -216,7 +216,8 @@ void Implementation::SetupDataStreamer(int i) {
dataStreamer[i]->SetFlipRows(flipRows);
dataStreamer[i]->SetNumberofPorts(numPorts);
dataStreamer[i]->SetNumberofTotalFrames(numberOfTotalFrames);
dataStreamer[i]->SetPortROI(portRois[i]);
dataStreamer[i]->SetReceiverROI(
portRois[i].completeRoi() ? GetMaxROIPerPort() : portRois[i]);
}
slsDetectorDefs::xy Implementation::getDetectorSize() const {
@ -232,13 +233,18 @@ const slsDetectorDefs::xy Implementation::GetPortGeometry() const {
return portGeometry;
}
const slsDetectorDefs::ROI Implementation::GetMaxROIPerPort() const {
return slsDetectorDefs::ROI{0, (int)generalData->nPixelsX - 1, 0,
(int)generalData->nPixelsY - 1};
}
void Implementation::setDetectorSize(const slsDetectorDefs::xy size) {
xy portGeometry = GetPortGeometry();
std::string log_message = "Detector Size (ports): (";
numModules = size;
numPorts.x = portGeometry.x * numModules.x;
numPorts.y = portGeometry.y * numModules.y;
numPorts.x = portGeometry.x * size.x;
numPorts.y = portGeometry.y * size.y;
if (quadEnable) {
numPorts.x = 1;
numPorts.y = 2;
@ -395,27 +401,97 @@ void Implementation::setArping(const bool i,
}
}
std::array<slsDetectorDefs::ROI, 2> Implementation::getPortROIs() const {
return portRois;
slsDetectorDefs::ROI Implementation::getReceiverROI() const {
return receiverRoi;
}
void Implementation::setPortROIs(const std::array<defs::ROI, 2> &args) {
portRois = args;
void Implementation::setReceiverROI(const slsDetectorDefs::ROI arg) {
receiverRoi = arg;
for (size_t i = 0; i != listener.size(); ++i)
listener[i]->SetIsOutsideRoi(portRois[i].noRoi());
for (size_t i = 0; i != dataProcessor.size(); ++i)
dataProcessor[i]->SetPortROI(portRois[i]);
for (size_t i = 0; i != dataStreamer.size(); ++i) {
dataStreamer[i]->SetPortROI(portRois[i]);
if (generalData->numUDPInterfaces == 1 ||
generalData->detType == slsDetectorDefs::GOTTHARD2) {
portRois[0] = arg;
} else {
slsDetectorDefs::xy nPortDim(generalData->nPixelsX,
generalData->nPixelsY);
for (int iPort = 0; iPort != generalData->numUDPInterfaces; ++iPort) {
// default init = complete roi
slsDetectorDefs::ROI portRoi{};
// no roi
if (arg.noRoi()) {
portRoi.setNoRoi();
}
// incomplete roi
else if (!arg.completeRoi()) {
// get port limits
slsDetectorDefs::ROI portFullRoi{0, nPortDim.x - 1, 0,
nPortDim.y - 1};
if (iPort == 1) {
// left right (eiger)
if (GetPortGeometry().x == 2) {
portFullRoi.xmin += nPortDim.x;
portFullRoi.xmax += nPortDim.x;
}
// top bottom (jungfrau or moench)
else {
portFullRoi.ymin += nPortDim.y;
portFullRoi.ymax += nPortDim.y;
}
}
LOG(logDEBUG)
<< iPort << ": portfullroi:" << ToString(portFullRoi);
// no roi
if (arg.xmin > portFullRoi.xmax ||
arg.xmax < portFullRoi.xmin ||
arg.ymin > portFullRoi.ymax ||
arg.ymax < portFullRoi.ymin) {
portRoi.setNoRoi();
}
// incomplete module roi
else if (arg.xmin > portFullRoi.xmin ||
arg.xmax < portFullRoi.xmax ||
arg.ymin > portFullRoi.ymin ||
arg.ymax < portFullRoi.ymax) {
portRoi.xmin = (arg.xmin <= portFullRoi.xmin)
? 0
: (arg.xmin % nPortDim.x);
portRoi.xmax = (arg.xmax >= portFullRoi.xmax)
? nPortDim.x - 1
: (arg.xmax % nPortDim.x);
portRoi.ymin = (arg.ymin <= portFullRoi.ymin)
? 0
: (arg.ymin % nPortDim.y);
portRoi.ymax = (arg.ymax >= portFullRoi.ymax)
? nPortDim.y - 1
: (arg.ymax % nPortDim.y);
}
}
portRois[iPort] = portRoi;
}
}
for (size_t i = 0; i != listener.size(); ++i)
listener[i]->SetNoRoi(portRois[i].noRoi());
for (size_t i = 0; i != dataProcessor.size(); ++i)
dataProcessor[i]->SetReceiverROI(portRois[i]);
for (size_t i = 0; i != dataStreamer.size(); ++i) {
dataStreamer[i]->SetReceiverROI(
portRois[i].completeRoi() ? GetMaxROIPerPort() : portRois[i]);
}
LOG(logINFO) << "receiver roi: " << ToString(receiverRoi);
if (generalData->numUDPInterfaces == 2 &&
generalData->detType != slsDetectorDefs::GOTTHARD2) {
LOG(logINFO) << "port rois: " << ToString(portRois);
}
LOG(logINFO) << "Rois (per port): " << ToString(portRois);
}
void Implementation::setMultiROIMetadata(
const std::vector<slsDetectorDefs::ROI> &args) {
multiRoiMetadata = args;
LOG(logINFO) << "Multi ROI Metadata: " << ToString(multiRoiMetadata);
void Implementation::setReceiverROIMetadata(const ROI arg) {
receiverRoiMetadata = arg;
LOG(logINFO) << "receiver roi Metadata: " << ToString(receiverRoiMetadata);
}
/**************************************************
@ -711,7 +787,8 @@ void Implementation::stopReceiver() {
summary = (i == 0 ? "\n\tDeactivated Left Port"
: "\n\tDeactivated Right Port");
} else if (portRois[i].noRoi()) {
summary = "\n\tNo Roi on Port[" + std::to_string(i) + ']';
summary = (i == 0 ? "\n\tNo Roi on Left Port"
: "\n\tNo Roi on Right Port");
} else {
std::ostringstream os;
os << "\n\tMissing Packets\t\t: " << mpMessage
@ -881,19 +958,7 @@ void Implementation::StartMasterWriter() {
masterAttributes.framePadding = framePadding;
masterAttributes.scanParams = scanParams;
masterAttributes.totalFrames = numberOfTotalFrames;
// complete ROI
if (multiRoiMetadata.empty()) {
int nTotalPixelsX = (generalData->nPixelsX * numPorts.x);
int nTotalPixelsY = (generalData->nPixelsY * numPorts.y);
if (nTotalPixelsY == 1) {
masterAttributes.rois.push_back(ROI{0, nTotalPixelsX - 1});
} else {
masterAttributes.rois.push_back(
ROI{0, nTotalPixelsX - 1, 0, nTotalPixelsY - 1});
}
} else {
masterAttributes.rois = multiRoiMetadata;
}
masterAttributes.receiverRoi = receiverRoiMetadata;
masterAttributes.exptime = acquisitionTime;
masterAttributes.period = acquisitionPeriod;
masterAttributes.burstMode = burstMode;
@ -1022,8 +1087,8 @@ void Implementation::setNumberofUDPInterfaces(const int n) {
// fifo
SetupFifoStructure();
// recalculate port rois booleans for listener, processor and streamer
setPortROIs(portRois);
// recalculate port rois
setReceiverROI(receiverRoi);
// create threads
for (int i = 0; i < generalData->numUDPInterfaces; ++i) {

View File

@ -58,9 +58,9 @@ class Implementation : private virtual slsDetectorDefs {
bool getArping() const;
pid_t getArpingProcessId() const;
void setArping(const bool i, const std::vector<std::string> ips);
std::array<defs::ROI, 2> getPortROIs() const;
void setPortROIs(const std::array<defs::ROI, 2> &args);
void setMultiROIMetadata(const std::vector<slsDetectorDefs::ROI> &args);
ROI getReceiverROI() const;
void setReceiverROI(const ROI arg);
void setReceiverROIMetadata(const ROI arg);
/**************************************************
* *
@ -283,6 +283,7 @@ class Implementation : private virtual slsDetectorDefs {
void SetupFifoStructure();
const xy GetPortGeometry() const;
const ROI GetMaxROIPerPort() const;
void ResetParametersforNewAcquisition();
void CreateUDPSockets();
void SetupWriter();
@ -307,8 +308,10 @@ class Implementation : private virtual slsDetectorDefs {
bool framePadding{true};
pid_t parentThreadId;
pid_t tcpThreadId;
ROI receiverRoi{};
std::array<ROI, 2> portRois{};
std::vector<ROI> multiRoiMetadata{};
// receiver roi for complete detector for metadata
ROI receiverRoiMetadata{};
// file parameters
fileFormat fileFormatType{BINARY};

View File

@ -85,17 +85,17 @@ void Listener::SetEthernetInterface(const std::string e) {
void Listener::SetActivate(bool enable) {
activated = enable;
disabledPort = (!activated || !detectorDataStream || isOutsideRoi);
disabledPort = (!activated || !detectorDataStream || noRoi);
}
void Listener::SetDetectorDatastream(bool enable) {
detectorDataStream = enable;
disabledPort = (!activated || !detectorDataStream || isOutsideRoi);
disabledPort = (!activated || !detectorDataStream || noRoi);
}
void Listener::SetIsOutsideRoi(bool enable) {
isOutsideRoi = enable;
disabledPort = (!activated || !detectorDataStream || isOutsideRoi);
void Listener::SetNoRoi(bool enable) {
noRoi = enable;
disabledPort = (!activated || !detectorDataStream || noRoi);
}
void Listener::SetSilentMode(bool enable) { silentMode = enable; }

View File

@ -43,7 +43,7 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject {
void SetEthernetInterface(const std::string e);
void SetActivate(bool enable);
void SetDetectorDatastream(bool enable);
void SetIsOutsideRoi(bool enable);
void SetNoRoi(bool enable);
void SetSilentMode(bool enable);
void ResetParametersforNewAcquisition();
@ -116,7 +116,7 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject {
std::string eth;
bool activated{false};
bool detectorDataStream{true};
bool isOutsideRoi{false};
bool noRoi{false};
bool silentMode;
bool disabledPort{false};

View File

@ -43,30 +43,30 @@ void MasterAttributes::WriteHDF5Attributes(H5::H5File *fd, H5::Group *group) {
WriteCommonHDF5Attributes(fd, group);
switch (detType) {
case slsDetectorDefs::JUNGFRAU:
WriteJungfrauHDF5Attributes(group);
WriteJungfrauHDF5Attributes(fd, group);
break;
case slsDetectorDefs::MOENCH:
WriteMoenchHDF5Attributes(group);
WriteMoenchHDF5Attributes(fd, group);
break;
case slsDetectorDefs::EIGER:
WriteEigerHDF5Attributes(group);
WriteEigerHDF5Attributes(fd, group);
break;
case slsDetectorDefs::MYTHEN3:
WriteMythen3HDF5Attributes(group);
WriteMythen3HDF5Attributes(fd, group);
break;
case slsDetectorDefs::GOTTHARD2:
WriteGotthard2HDF5Attributes(group);
WriteGotthard2HDF5Attributes(fd, group);
break;
case slsDetectorDefs::CHIPTESTBOARD:
WriteCtbHDF5Attributes(group);
WriteCtbHDF5Attributes(fd, group);
break;
case slsDetectorDefs::XILINX_CHIPTESTBOARD:
WriteXilinxCtbHDF5Attributes(group);
WriteXilinxCtbHDF5Attributes(fd, group);
break;
default:
throw RuntimeError("Unknown Detector type to get master attributes");
}
WriteFinalHDF5Attributes(group);
WriteFinalHDF5Attributes(fd, group);
}
#endif
@ -110,6 +110,17 @@ void MasterAttributes::GetCommonBinaryAttributes(
w->String(ToString(scanParams).c_str());
w->Key("Total Frames");
w->Uint64(totalFrames);
w->Key("Receiver Roi");
w->StartObject();
w->Key("xmin");
w->Uint(receiverRoi.xmin);
w->Key("xmax");
w->Uint(receiverRoi.xmax);
w->Key("ymin");
w->Uint(receiverRoi.ymin);
w->Key("ymax");
w->Uint(receiverRoi.ymax);
w->EndObject();
}
void MasterAttributes::GetFinalBinaryAttributes(
@ -276,9 +287,38 @@ void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd,
"Total Frames", H5::PredType::STD_U64LE, dataspace);
dataset.write(&totalFrames, H5::PredType::STD_U64LE);
}
// Receiver Roi xmin
{
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"receiver roi xmin", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&receiverRoi.xmin, H5::PredType::NATIVE_INT);
}
// Receiver Roi xmax
{
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"receiver roi xmax", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&receiverRoi.xmax, H5::PredType::NATIVE_INT);
}
// Receiver Roi ymin
{
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"receiver roi ymin", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&receiverRoi.ymin, H5::PredType::NATIVE_INT);
}
// Receiver Roi ymax
{
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"receiver roi ymax", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&receiverRoi.ymax, H5::PredType::NATIVE_INT);
}
}
void MasterAttributes::WriteFinalHDF5Attributes(H5::Group *group) {
void MasterAttributes::WriteFinalHDF5Attributes(H5::H5File *fd,
H5::Group *group) {
char c[1024]{};
// Total Frames in file
{
@ -299,20 +339,7 @@ void MasterAttributes::WriteFinalHDF5Attributes(H5::Group *group) {
}
}
void MasterAttributes::WriteHDF5ROIs(H5::Group *group) {
hsize_t dims[1] = {rois.size()};
H5::DataSpace dataspace(1, dims);
H5::StrType strdatatype(H5::PredType::C_S1, 1024);
H5::DataSet dataset =
group->createDataSet("Receiver Rois", strdatatype, dataspace);
std::vector<char[1024]> cRois(rois.size());
for (size_t i = 0; i < rois.size(); ++i) {
strcpy_safe(cRois[i], ToString(rois[i]));
}
dataset.write(cRois.data(), strdatatype);
}
void MasterAttributes::WriteHDF5Exptime(H5::Group *group) {
void MasterAttributes::WriteHDF5Exptime(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 256);
H5::DataSet dataset =
@ -322,7 +349,7 @@ void MasterAttributes::WriteHDF5Exptime(H5::Group *group) {
dataset.write(c, strdatatype);
}
void MasterAttributes::WriteHDF5Period(H5::Group *group) {
void MasterAttributes::WriteHDF5Period(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 256);
H5::DataSet dataset =
@ -332,7 +359,7 @@ void MasterAttributes::WriteHDF5Period(H5::Group *group) {
dataset.write(c, strdatatype);
}
void MasterAttributes::WriteHDF5DynamicRange(H5::Group *group) {
void MasterAttributes::WriteHDF5DynamicRange(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Dynamic Range", H5::PredType::NATIVE_INT, dataspace);
@ -345,28 +372,30 @@ void MasterAttributes::WriteHDF5DynamicRange(H5::Group *group) {
attribute.write(strdatatype, c);
}
void MasterAttributes::WriteHDF5TenGiga(H5::Group *group) {
void MasterAttributes::WriteHDF5TenGiga(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Ten Giga Enable", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&tenGiga, H5::PredType::NATIVE_INT);
}
void MasterAttributes::WriteHDF5NumUDPInterfaces(H5::Group *group) {
void MasterAttributes::WriteHDF5NumUDPInterfaces(H5::H5File *fd,
H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Number of UDP Interfaces", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&numUDPInterfaces, H5::PredType::NATIVE_INT);
}
void MasterAttributes::WriteHDF5ReadNRows(H5::Group *group) {
void MasterAttributes::WriteHDF5ReadNRows(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Number of rows", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&readNRows, H5::PredType::NATIVE_INT);
}
void MasterAttributes::WriteHDF5ThresholdEnergy(H5::Group *group) {
void MasterAttributes::WriteHDF5ThresholdEnergy(H5::H5File *fd,
H5::Group *group) {
char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
@ -380,7 +409,8 @@ void MasterAttributes::WriteHDF5ThresholdEnergy(H5::Group *group) {
attribute.write(strdatatype, c);
}
void MasterAttributes::WriteHDF5ThresholdEnergies(H5::Group *group) {
void MasterAttributes::WriteHDF5ThresholdEnergies(H5::H5File *fd,
H5::Group *group) {
char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 1024);
@ -390,7 +420,7 @@ void MasterAttributes::WriteHDF5ThresholdEnergies(H5::Group *group) {
dataset.write(c, strdatatype);
}
void MasterAttributes::WriteHDF5SubExpTime(H5::Group *group) {
void MasterAttributes::WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group) {
char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 256);
@ -400,7 +430,7 @@ void MasterAttributes::WriteHDF5SubExpTime(H5::Group *group) {
dataset.write(c, strdatatype);
}
void MasterAttributes::WriteHDF5SubPeriod(H5::Group *group) {
void MasterAttributes::WriteHDF5SubPeriod(H5::H5File *fd, H5::Group *group) {
char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 256);
@ -410,14 +440,15 @@ void MasterAttributes::WriteHDF5SubPeriod(H5::Group *group) {
dataset.write(c, strdatatype);
}
void MasterAttributes::WriteHDF5SubQuad(H5::Group *group) {
void MasterAttributes::WriteHDF5SubQuad(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset =
group->createDataSet("Quad", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&quad, H5::PredType::NATIVE_INT);
}
void MasterAttributes::WriteHDF5RateCorrections(H5::Group *group) {
void MasterAttributes::WriteHDF5RateCorrections(H5::H5File *fd,
H5::Group *group) {
char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 1024);
@ -427,14 +458,14 @@ void MasterAttributes::WriteHDF5RateCorrections(H5::Group *group) {
dataset.write(c, strdatatype);
}
void MasterAttributes::WriteHDF5CounterMask(H5::Group *group) {
void MasterAttributes::WriteHDF5CounterMask(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Counter Mask", H5::PredType::STD_U32LE, dataspace);
dataset.write(&counterMask, H5::PredType::STD_U32LE);
}
void MasterAttributes::WriteHDF5ExptimeArray(H5::Group *group) {
void MasterAttributes::WriteHDF5ExptimeArray(H5::H5File *fd, H5::Group *group) {
for (int i = 0; i != 3; ++i) {
char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
@ -446,7 +477,8 @@ void MasterAttributes::WriteHDF5ExptimeArray(H5::Group *group) {
}
}
void MasterAttributes::WriteHDF5GateDelayArray(H5::Group *group) {
void MasterAttributes::WriteHDF5GateDelayArray(H5::H5File *fd,
H5::Group *group) {
for (int i = 0; i != 3; ++i) {
char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
@ -458,14 +490,14 @@ void MasterAttributes::WriteHDF5GateDelayArray(H5::Group *group) {
}
}
void MasterAttributes::WriteHDF5Gates(H5::Group *group) {
void MasterAttributes::WriteHDF5Gates(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset =
group->createDataSet("Gates", H5::PredType::STD_U32LE, dataspace);
dataset.write(&gates, H5::PredType::STD_U32LE);
}
void MasterAttributes::WriteHDF5BurstMode(H5::Group *group) {
void MasterAttributes::WriteHDF5BurstMode(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 256);
H5::DataSet dataset =
@ -475,77 +507,82 @@ void MasterAttributes::WriteHDF5BurstMode(H5::Group *group) {
dataset.write(c, strdatatype);
}
void MasterAttributes::WriteHDF5AdcMask(H5::Group *group) {
void MasterAttributes::WriteHDF5AdcMask(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset =
group->createDataSet("ADC Mask", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&adcmask, H5::PredType::NATIVE_INT);
}
void MasterAttributes::WriteHDF5AnalogFlag(H5::Group *group) {
void MasterAttributes::WriteHDF5AnalogFlag(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Analog Flag", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&analog, H5::PredType::NATIVE_INT);
}
void MasterAttributes::WriteHDF5AnalogSamples(H5::Group *group) {
void MasterAttributes::WriteHDF5AnalogSamples(H5::H5File *fd,
H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Analog Samples", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&analogSamples, H5::PredType::NATIVE_INT);
}
void MasterAttributes::WriteHDF5DigitalFlag(H5::Group *group) {
void MasterAttributes::WriteHDF5DigitalFlag(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Digital Flag", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&digital, H5::PredType::NATIVE_INT);
}
void MasterAttributes::WriteHDF5DigitalSamples(H5::Group *group) {
void MasterAttributes::WriteHDF5DigitalSamples(H5::H5File *fd,
H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Digital Samples", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&digitalSamples, H5::PredType::NATIVE_INT);
}
void MasterAttributes::WriteHDF5DbitOffset(H5::Group *group) {
void MasterAttributes::WriteHDF5DbitOffset(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Dbit Offset", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&dbitoffset, H5::PredType::NATIVE_INT);
}
void MasterAttributes::WriteHDF5DbitReorder(H5::Group *group) {
void MasterAttributes::WriteHDF5DbitReorder(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Dbit Reorder", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&dbitreorder, H5::PredType::NATIVE_INT);
}
void MasterAttributes::WriteHDF5DbitList(H5::Group *group) {
void MasterAttributes::WriteHDF5DbitList(H5::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Dbit Bitset List", H5::PredType::STD_U64LE, dataspace);
dataset.write(&dbitlist, H5::PredType::STD_U64LE);
}
void MasterAttributes::WriteHDF5TransceiverMask(H5::Group *group) {
void MasterAttributes::WriteHDF5TransceiverMask(H5::H5File *fd,
H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Transceiver Mask", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&transceiverMask, H5::PredType::NATIVE_INT);
}
void MasterAttributes::WriteHDF5TransceiverFlag(H5::Group *group) {
void MasterAttributes::WriteHDF5TransceiverFlag(H5::H5File *fd,
H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Transceiver Flag", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&transceiver, H5::PredType::NATIVE_INT);
}
void MasterAttributes::WriteHDF5TransceiverSamples(H5::Group *group) {
void MasterAttributes::WriteHDF5TransceiverSamples(H5::H5File *fd,
H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
"Transceiver Samples", H5::PredType::NATIVE_INT, dataspace);
@ -555,13 +592,6 @@ void MasterAttributes::WriteHDF5TransceiverSamples(H5::Group *group) {
void MasterAttributes::GetJungfrauBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
w->Key("Receiver Rois");
w->StartArray();
for (const slsDetectorDefs::ROI &roi : rois) {
std::string roi_str = ToString(roi);
w->String(roi_str.c_str());
}
w->EndArray();
w->Key("Exptime");
w->String(ToString(exptime).c_str());
w->Key("Period");
@ -573,24 +603,17 @@ void MasterAttributes::GetJungfrauBinaryAttributes(
}
#ifdef HDF5C
void MasterAttributes::WriteJungfrauHDF5Attributes(H5::Group *group) {
MasterAttributes::WriteHDF5ROIs(group);
MasterAttributes::WriteHDF5Exptime(group);
MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5NumUDPInterfaces(group);
MasterAttributes::WriteHDF5ReadNRows(group);
void MasterAttributes::WriteJungfrauHDF5Attributes(H5::H5File *fd,
H5::Group *group) {
MasterAttributes::WriteHDF5Exptime(fd, group);
MasterAttributes::WriteHDF5Period(fd, group);
MasterAttributes::WriteHDF5NumUDPInterfaces(fd, group);
MasterAttributes::WriteHDF5ReadNRows(fd, group);
}
#endif
void MasterAttributes::GetMoenchBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
w->Key("Receiver Rois");
w->StartArray();
for (const slsDetectorDefs::ROI &roi : rois) {
std::string roi_str = ToString(roi);
w->String(roi_str.c_str());
}
w->EndArray();
w->Key("Exptime");
w->String(ToString(exptime).c_str());
w->Key("Period");
@ -602,24 +625,17 @@ void MasterAttributes::GetMoenchBinaryAttributes(
}
#ifdef HDF5C
void MasterAttributes::WriteMoenchHDF5Attributes(H5::Group *group) {
MasterAttributes::WriteHDF5ROIs(group);
MasterAttributes::WriteHDF5Exptime(group);
MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5NumUDPInterfaces(group);
MasterAttributes::WriteHDF5ReadNRows(group);
void MasterAttributes::WriteMoenchHDF5Attributes(H5::H5File *fd,
H5::Group *group) {
MasterAttributes::WriteHDF5Exptime(fd, group);
MasterAttributes::WriteHDF5Period(fd, group);
MasterAttributes::WriteHDF5NumUDPInterfaces(fd, group);
MasterAttributes::WriteHDF5ReadNRows(fd, group);
}
#endif
void MasterAttributes::GetEigerBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
w->Key("Receiver Rois");
w->StartArray();
for (const slsDetectorDefs::ROI &roi : rois) {
std::string roi_str = ToString(roi);
w->String(roi_str.c_str());
}
w->EndArray();
w->Key("Dynamic Range");
w->Uint(dynamicRange);
w->Key("Ten Giga");
@ -643,30 +659,23 @@ void MasterAttributes::GetEigerBinaryAttributes(
}
#ifdef HDF5C
void MasterAttributes::WriteEigerHDF5Attributes(H5::Group *group) {
MasterAttributes::WriteHDF5ROIs(group);
MasterAttributes::WriteHDF5DynamicRange(group);
MasterAttributes::WriteHDF5TenGiga(group);
MasterAttributes::WriteHDF5Exptime(group);
MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5ThresholdEnergy(group);
MasterAttributes::WriteHDF5SubExpTime(group);
MasterAttributes::WriteHDF5SubPeriod(group);
MasterAttributes::WriteHDF5SubQuad(group);
MasterAttributes::WriteHDF5ReadNRows(group);
MasterAttributes::WriteHDF5RateCorrections(group);
void MasterAttributes::WriteEigerHDF5Attributes(H5::H5File *fd,
H5::Group *group) {
MasterAttributes::WriteHDF5DynamicRange(fd, group);
MasterAttributes::WriteHDF5TenGiga(fd, group);
MasterAttributes::WriteHDF5Exptime(fd, group);
MasterAttributes::WriteHDF5Period(fd, group);
MasterAttributes::WriteHDF5ThresholdEnergy(fd, group);
MasterAttributes::WriteHDF5SubExpTime(fd, group);
MasterAttributes::WriteHDF5SubPeriod(fd, group);
MasterAttributes::WriteHDF5SubQuad(fd, group);
MasterAttributes::WriteHDF5ReadNRows(fd, group);
MasterAttributes::WriteHDF5RateCorrections(fd, group);
}
#endif
void MasterAttributes::GetMythen3BinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
w->Key("Receiver Rois");
w->StartArray();
for (const slsDetectorDefs::ROI &roi : rois) {
std::string roi_str = ToString(roi);
w->String(roi_str.c_str());
}
w->EndArray();
w->Key("Dynamic Range");
w->Uint(dynamicRange);
w->Key("Ten Giga");
@ -690,28 +699,21 @@ void MasterAttributes::GetMythen3BinaryAttributes(
}
#ifdef HDF5C
void MasterAttributes::WriteMythen3HDF5Attributes(H5::Group *group) {
MasterAttributes::WriteHDF5ROIs(group);
MasterAttributes::WriteHDF5DynamicRange(group);
MasterAttributes::WriteHDF5TenGiga(group);
MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5CounterMask(group);
MasterAttributes::WriteHDF5ExptimeArray(group);
MasterAttributes::WriteHDF5GateDelayArray(group);
MasterAttributes::WriteHDF5Gates(group);
MasterAttributes::WriteHDF5ThresholdEnergies(group);
void MasterAttributes::WriteMythen3HDF5Attributes(H5::H5File *fd,
H5::Group *group) {
MasterAttributes::WriteHDF5DynamicRange(fd, group);
MasterAttributes::WriteHDF5TenGiga(fd, group);
MasterAttributes::WriteHDF5Period(fd, group);
MasterAttributes::WriteHDF5CounterMask(fd, group);
MasterAttributes::WriteHDF5ExptimeArray(fd, group);
MasterAttributes::WriteHDF5GateDelayArray(fd, group);
MasterAttributes::WriteHDF5Gates(fd, group);
MasterAttributes::WriteHDF5ThresholdEnergies(fd, group);
}
#endif
void MasterAttributes::GetGotthard2BinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
w->Key("Receiver Rois");
w->StartArray();
for (const slsDetectorDefs::ROI &roi : rois) {
std::string roi_str = ToString(roi);
w->String(roi_str.c_str());
}
w->EndArray();
w->Key("Exptime");
w->String(ToString(exptime).c_str());
w->Key("Period");
@ -721,11 +723,11 @@ void MasterAttributes::GetGotthard2BinaryAttributes(
}
#ifdef HDF5C
void MasterAttributes::WriteGotthard2HDF5Attributes(H5::Group *group) {
MasterAttributes::WriteHDF5ROIs(group);
MasterAttributes::WriteHDF5Exptime(group);
MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5BurstMode(group);
void MasterAttributes::WriteGotthard2HDF5Attributes(H5::H5File *fd,
H5::Group *group) {
MasterAttributes::WriteHDF5Exptime(fd, group);
MasterAttributes::WriteHDF5Period(fd, group);
MasterAttributes::WriteHDF5BurstMode(fd, group);
}
#endif
@ -762,21 +764,22 @@ void MasterAttributes::GetCtbBinaryAttributes(
}
#ifdef HDF5C
void MasterAttributes::WriteCtbHDF5Attributes(H5::Group *group) {
MasterAttributes::WriteHDF5Exptime(group);
MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5TenGiga(group);
MasterAttributes::WriteHDF5AdcMask(group);
MasterAttributes::WriteHDF5AnalogFlag(group);
MasterAttributes::WriteHDF5AnalogSamples(group);
MasterAttributes::WriteHDF5DigitalFlag(group);
MasterAttributes::WriteHDF5DigitalSamples(group);
MasterAttributes::WriteHDF5DbitOffset(group);
MasterAttributes::WriteHDF5DbitReorder(group);
MasterAttributes::WriteHDF5DbitList(group);
MasterAttributes::WriteHDF5TransceiverMask(group);
MasterAttributes::WriteHDF5TransceiverFlag(group);
MasterAttributes::WriteHDF5TransceiverSamples(group);
void MasterAttributes::WriteCtbHDF5Attributes(H5::H5File *fd,
H5::Group *group) {
MasterAttributes::WriteHDF5Exptime(fd, group);
MasterAttributes::WriteHDF5Period(fd, group);
MasterAttributes::WriteHDF5TenGiga(fd, group);
MasterAttributes::WriteHDF5AdcMask(fd, group);
MasterAttributes::WriteHDF5AnalogFlag(fd, group);
MasterAttributes::WriteHDF5AnalogSamples(fd, group);
MasterAttributes::WriteHDF5DigitalFlag(fd, group);
MasterAttributes::WriteHDF5DigitalSamples(fd, group);
MasterAttributes::WriteHDF5DbitOffset(fd, group);
MasterAttributes::WriteHDF5DbitReorder(fd, group);
MasterAttributes::WriteHDF5DbitList(fd, group);
MasterAttributes::WriteHDF5TransceiverMask(fd, group);
MasterAttributes::WriteHDF5TransceiverFlag(fd, group);
MasterAttributes::WriteHDF5TransceiverSamples(fd, group);
}
#endif
@ -811,20 +814,21 @@ void MasterAttributes::GetXilinxCtbBinaryAttributes(
}
#ifdef HDF5C
void MasterAttributes::WriteXilinxCtbHDF5Attributes(H5::Group *group) {
MasterAttributes::WriteHDF5Exptime(group);
MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5AdcMask(group);
MasterAttributes::WriteHDF5AnalogFlag(group);
MasterAttributes::WriteHDF5AnalogSamples(group);
MasterAttributes::WriteHDF5DigitalFlag(group);
MasterAttributes::WriteHDF5DigitalSamples(group);
MasterAttributes::WriteHDF5DbitOffset(group);
MasterAttributes::WriteHDF5DbitReorder(group);
MasterAttributes::WriteHDF5DbitList(group);
MasterAttributes::WriteHDF5TransceiverMask(group);
MasterAttributes::WriteHDF5TransceiverFlag(group);
MasterAttributes::WriteHDF5TransceiverSamples(group);
void MasterAttributes::WriteXilinxCtbHDF5Attributes(H5::H5File *fd,
H5::Group *group) {
MasterAttributes::WriteHDF5Exptime(fd, group);
MasterAttributes::WriteHDF5Period(fd, group);
MasterAttributes::WriteHDF5AdcMask(fd, group);
MasterAttributes::WriteHDF5AnalogFlag(fd, group);
MasterAttributes::WriteHDF5AnalogSamples(fd, group);
MasterAttributes::WriteHDF5DigitalFlag(fd, group);
MasterAttributes::WriteHDF5DigitalSamples(fd, group);
MasterAttributes::WriteHDF5DbitOffset(fd, group);
MasterAttributes::WriteHDF5DbitReorder(fd, group);
MasterAttributes::WriteHDF5DbitList(fd, group);
MasterAttributes::WriteHDF5TransceiverMask(fd, group);
MasterAttributes::WriteHDF5TransceiverFlag(fd, group);
MasterAttributes::WriteHDF5TransceiverSamples(fd, group);
}
#endif
} // namespace sls

View File

@ -57,7 +57,7 @@ class MasterAttributes {
uint32_t transceiverMask{0};
uint32_t transceiver{0};
uint32_t transceiverSamples{0};
std::vector<slsDetectorDefs::ROI> rois{};
slsDetectorDefs::ROI receiverRoi{};
uint32_t counterMask{0};
std::array<ns, 3> exptimeArray{};
std::array<ns, 3> gateDelayArray{};
@ -80,78 +80,77 @@ class MasterAttributes {
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C
void WriteCommonHDF5Attributes(H5::H5File *fd, H5::Group *group);
void WriteFinalHDF5Attributes(H5::Group *group);
void WriteHDF5ROIs(H5::Group *group);
void WriteHDF5Exptime(H5::Group *group);
void WriteHDF5Period(H5::Group *group);
void WriteHDF5DynamicRange(H5::Group *group);
void WriteHDF5TenGiga(H5::Group *group);
void WriteHDF5NumUDPInterfaces(H5::Group *group);
void WriteHDF5ReadNRows(H5::Group *group);
void WriteHDF5ThresholdEnergy(H5::Group *group);
void WriteHDF5ThresholdEnergies(H5::Group *group);
void WriteHDF5SubExpTime(H5::Group *group);
void WriteHDF5SubPeriod(H5::Group *group);
void WriteHDF5SubQuad(H5::Group *group);
void WriteHDF5RateCorrections(H5::Group *group);
void WriteHDF5CounterMask(H5::Group *group);
void WriteHDF5ExptimeArray(H5::Group *group);
void WriteHDF5GateDelayArray(H5::Group *group);
void WriteHDF5Gates(H5::Group *group);
void WriteHDF5BurstMode(H5::Group *group);
void WriteHDF5AdcMask(H5::Group *group);
void WriteHDF5AnalogFlag(H5::Group *group);
void WriteHDF5AnalogSamples(H5::Group *group);
void WriteHDF5DigitalFlag(H5::Group *group);
void WriteHDF5DigitalSamples(H5::Group *group);
void WriteHDF5DbitOffset(H5::Group *group);
void WriteHDF5DbitList(H5::Group *group);
void WriteHDF5DbitReorder(H5::Group *group);
void WriteHDF5TransceiverMask(H5::Group *group);
void WriteHDF5TransceiverFlag(H5::Group *group);
void WriteHDF5TransceiverSamples(H5::Group *group);
void WriteFinalHDF5Attributes(H5::H5File *fd, H5::Group *group);
void WriteHDF5Exptime(H5::H5File *fd, H5::Group *group);
void WriteHDF5Period(H5::H5File *fd, H5::Group *group);
void WriteHDF5DynamicRange(H5::H5File *fd, H5::Group *group);
void WriteHDF5TenGiga(H5::H5File *fd, H5::Group *group);
void WriteHDF5NumUDPInterfaces(H5::H5File *fd, H5::Group *group);
void WriteHDF5ReadNRows(H5::H5File *fd, H5::Group *group);
void WriteHDF5ThresholdEnergy(H5::H5File *fd, H5::Group *group);
void WriteHDF5ThresholdEnergies(H5::H5File *fd, H5::Group *group);
void WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group);
void WriteHDF5SubPeriod(H5::H5File *fd, H5::Group *group);
void WriteHDF5SubQuad(H5::H5File *fd, H5::Group *group);
void WriteHDF5RateCorrections(H5::H5File *fd, H5::Group *group);
void WriteHDF5CounterMask(H5::H5File *fd, H5::Group *group);
void WriteHDF5ExptimeArray(H5::H5File *fd, H5::Group *group);
void WriteHDF5GateDelayArray(H5::H5File *fd, H5::Group *group);
void WriteHDF5Gates(H5::H5File *fd, H5::Group *group);
void WriteHDF5BurstMode(H5::H5File *fd, H5::Group *group);
void WriteHDF5AdcMask(H5::H5File *fd, H5::Group *group);
void WriteHDF5AnalogFlag(H5::H5File *fd, H5::Group *group);
void WriteHDF5AnalogSamples(H5::H5File *fd, H5::Group *group);
void WriteHDF5DigitalFlag(H5::H5File *fd, H5::Group *group);
void WriteHDF5DigitalSamples(H5::H5File *fd, H5::Group *group);
void WriteHDF5DbitOffset(H5::H5File *fd, H5::Group *group);
void WriteHDF5DbitList(H5::H5File *fd, H5::Group *group);
void WriteHDF5DbitReorder(H5::H5File *fd, H5::Group *group);
void WriteHDF5TransceiverMask(H5::H5File *fd, H5::Group *group);
void WriteHDF5TransceiverFlag(H5::H5File *fd, H5::Group *group);
void WriteHDF5TransceiverSamples(H5::H5File *fd, H5::Group *group);
#endif
void GetJungfrauBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C
void WriteJungfrauHDF5Attributes(H5::Group *group);
void WriteJungfrauHDF5Attributes(H5::H5File *fd, H5::Group *group);
#endif
void GetEigerBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C
void WriteEigerHDF5Attributes(H5::Group *group);
void WriteEigerHDF5Attributes(H5::H5File *fd, H5::Group *group);
#endif
void GetMythen3BinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C
void WriteMythen3HDF5Attributes(H5::Group *group);
void WriteMythen3HDF5Attributes(H5::H5File *fd, H5::Group *group);
#endif
void GetGotthard2BinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C
void WriteGotthard2HDF5Attributes(H5::Group *group);
void WriteGotthard2HDF5Attributes(H5::H5File *fd, H5::Group *group);
#endif
void GetMoenchBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C
void WriteMoenchHDF5Attributes(H5::Group *group);
void WriteMoenchHDF5Attributes(H5::H5File *fd, H5::Group *group);
#endif
void
GetCtbBinaryAttributes(rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C
void WriteCtbHDF5Attributes(H5::Group *group);
void WriteCtbHDF5Attributes(H5::H5File *fd, H5::Group *group);
#endif
void GetXilinxCtbBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C
void WriteXilinxCtbHDF5Attributes(H5::Group *group);
void WriteXilinxCtbHDF5Attributes(H5::H5File *fd, H5::Group *group);
#endif
};

View File

@ -47,8 +47,8 @@ class GeneralDataTest : public GeneralData {
// dummy DataProcessor class for testing
class DataProcessorTest : public DataProcessor {
public:
DataProcessorTest() : DataProcessor(0){};
~DataProcessorTest(){};
DataProcessorTest() : DataProcessor(0) {};
~DataProcessorTest() {};
void ArrangeDbitData(size_t &size, char *data) {
DataProcessor::ArrangeDbitData(size, data);
}

View File

@ -88,7 +88,6 @@ message(STATUS "RAPID: ${SLS_INTERNAL_RAPIDJSON_DIR}")
target_link_libraries(slsSupportObject
PUBLIC
slsProjectOptions
${STD_FS_LIB} # from helpers.cmake
PRIVATE
slsProjectWarnings

View File

@ -113,12 +113,10 @@ template <typename T, size_t Capacity> class StaticVector {
// auto begin() noexcept -> decltype(data_.begin()) { return data_.begin();
// }
const_iterator begin() const noexcept { return data_.begin(); }
iterator end() noexcept { return data_.begin() + current_size; }
const_iterator end() const noexcept { return data_.begin() + current_size; }
iterator end() noexcept { return &data_[current_size]; }
const_iterator end() const noexcept { return &data_[current_size]; }
const_iterator cbegin() const noexcept { return data_.cbegin(); }
const_iterator cend() const noexcept {
return data_.cbegin() + current_size;
}
const_iterator cend() const noexcept { return &data_[current_size]; }
void size_check(size_type s) const {
if (s > Capacity) {

View File

@ -47,8 +47,6 @@ std::string ToString(const defs::polarity s);
std::string ToString(const defs::timingInfoDecoder s);
std::string ToString(const defs::collectionMode s);
std::string ToString(bool value);
std::string ToString(const slsDetectorDefs::xy &coord);
std::ostream &operator<<(std::ostream &os, const slsDetectorDefs::xy &coord);
std::string ToString(const slsDetectorDefs::ROI &roi);
@ -349,5 +347,4 @@ std::vector<T> StringTo(const std::vector<std::string> &strings) {
return result;
}
} // namespace sls

View File

@ -11,7 +11,7 @@ class Version {
private:
std::string version_;
std::string date_;
inline static const std::string defaultVersion_[] = {"developer", "0.0.0"};
const std::string defaultBranch_ = "developer";
public:
explicit Version(const std::string &s);

View File

@ -237,8 +237,7 @@ class slsDetectorDefs {
return (xmin == -1 && xmax == -1 && ymin == -1 && ymax == -1);
}
constexpr bool noRoi() const {
return ((xmin == 0 && xmax == 0) &&
((ymin == 0 && ymax == 0) || (ymin == -1 && ymax == -1)));
return (xmin == 0 && xmax == 0 && ymin == 0 && ymax == 0);
}
void setNoRoi() {
xmin = 0;

View File

@ -1,12 +1,12 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
/** API versions */
#define APILIB "0.0.0 0x250523"
#define APIRECEIVER "0.0.0 0x250523"
#define APICTB "0.0.0 0x250523"
#define APIGOTTHARD2 "0.0.0 0x250523"
#define APIMOENCH "0.0.0 0x250523"
#define APIEIGER "0.0.0 0x250523"
#define APIXILINXCTB "0.0.0 0x250523"
#define APIJUNGFRAU "0.0.0 0x250523"
#define APIMYTHEN3 "0.0.0 0x250523"
#define APILIB "developer 0x241122"
#define APIRECEIVER "developer 0x241122"
#define APICTB "developer 0x250310"
#define APIGOTTHARD2 "developer 0x250310"
#define APIMOENCH "developer 0x250310"
#define APIEIGER "developer 0x250310"
#define APIXILINXCTB "developer 0x250311"
#define APIJUNGFRAU "developer 0x250318"
#define APIMYTHEN3 "developer 0x250409"

View File

@ -5,8 +5,6 @@
namespace sls {
std::string ToString(bool value) { return value ? "1" : "0"; }
std::string ToString(const slsDetectorDefs::xy &coord) {
std::ostringstream oss;
oss << '[' << coord.x << ", " << coord.y << ']';

View File

@ -21,8 +21,7 @@ Version::Version(const std::string &s) {
}
bool Version::hasSemanticVersioning() const {
return (version_ != defaultVersion_[0]) && (version_ != defaultVersion_[1]);
return version_ != defaultBranch_;
}
std::string Version::getVersion() const { return version_; }

View File

@ -14,7 +14,6 @@ target_sources(tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/test-TypeTraits.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-UdpRxSocket.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-logger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-Version.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-ZmqSocket.cpp
)

View File

@ -8,10 +8,10 @@
#include <sstream>
#include <vector>
using sls::StaticVector;
namespace sls {
TEST_CASE("StaticVector is a container") {
REQUIRE(sls::is_container<StaticVector<int, 7>>::value == true);
REQUIRE(is_container<StaticVector<int, 7>>::value == true);
}
TEST_CASE("Comparing StaticVector containers") {
@ -90,17 +90,10 @@ TEST_CASE("Copy construct from array") {
REQUIRE(fcc == arr);
}
TEST_CASE("Construct from a smaller StaticVector") {
StaticVector<int, 3> sv{1, 2, 3};
StaticVector<int, 5> sv2{sv};
REQUIRE(sv == sv2);
}
TEST_CASE("Free function and method gives the same iterators") {
StaticVector<int, 3> fcc{1, 2, 3};
REQUIRE(std::begin(fcc) == fcc.begin());
}
SCENARIO("StaticVectors can be sized and resized", "[support]") {
GIVEN("A default constructed container") {
@ -253,23 +246,23 @@ SCENARIO("Sorting, removing and other manipulation of a container",
REQUIRE(a[3] == 90);
}
}
WHEN("Sorting is done using free function for begin and end") {
std::sort(std::begin(a), std::end(a));
THEN("it also works") {
REQUIRE(a[0] == 12);
REQUIRE(a[1] == 12);
REQUIRE(a[2] == 14);
REQUIRE(a[3] == 90);
}
}
WHEN("Erasing elements of a certain value") {
a.erase(std::remove(std::begin(a), std::end(a), 12));
THEN("all elements of that value are removed") {
REQUIRE(a.size() == 2);
REQUIRE(a[0] == 14);
REQUIRE(a[1] == 90);
}
}
// WHEN("Sorting is done using free function for begin and end") {
// std::sort(begin(a), end(a));
// THEN("it also works") {
// REQUIRE(a[0] == 12);
// REQUIRE(a[1] == 12);
// REQUIRE(a[2] == 14);
// REQUIRE(a[3] == 90);
// }
// }
// WHEN("Erasing elements of a certain value") {
// a.erase(std::remove(begin(a), end(a), 12));
// THEN("all elements of that value are removed") {
// REQUIRE(a.size() == 2);
// REQUIRE(a[0] == 14);
// REQUIRE(a[1] == 90);
// }
// }
}
}
@ -341,3 +334,5 @@ TEST_CASE("StaticVector stream") {
oss << vec;
REQUIRE(oss.str() == "[33, 85667, 2]");
}
} // namespace sls

View File

@ -16,16 +16,6 @@ namespace sls {
using namespace sls::time;
TEST_CASE("Convert bool to string", "[support]") {
REQUIRE(ToString(true) == "1");
REQUIRE(ToString(false) == "0");
}
TEST_CASE("Convert string to bool", "[support]") {
REQUIRE(StringTo<bool>("1") == true);
REQUIRE(StringTo<bool>("0") == false);
}
TEST_CASE("Integer conversions", "[support]") {
REQUIRE(ToString(0) == "0");
REQUIRE(ToString(1) == "1");

View File

@ -1,19 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include "catch.hpp"
#include "sls/Version.h"
namespace sls {
TEST_CASE("check if version is semantic", "[.version]") {
auto [version_string, has_semantic_version] =
GENERATE(std::make_tuple("developer 0x250512", false),
std::make_tuple("0.0.0 0x250512", false));
Version version(version_string);
CHECK(version.hasSemanticVersioning() == has_semantic_version);
}
} // namespace sls

View File

@ -60,5 +60,3 @@ include(Catch)
catch_discover_tests(tests)
configure_file(scripts/test_simulators.py ${CMAKE_BINARY_DIR}/bin/test_simulators.py COPYONLY)
configure_file(scripts/test_frame_synchronizer.py ${CMAKE_BINARY_DIR}/bin/test_frame_synchronizer.py COPYONLY)
configure_file(scripts/utils_for_test.py ${CMAKE_BINARY_DIR}/bin/utils_for_test.py COPYONLY)

View File

@ -1,141 +0,0 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package
'''
This file is used to start up simulators, frame synchronizer, pull sockets, acquire, test and kill them finally.
'''
import sys, time
import traceback, json
from slsdet import Detector
from slsdet.defines import DEFAULT_TCP_RX_PORTNO
from utils_for_test import (
Log,
LogLevel,
RuntimeException,
checkIfProcessRunning,
killProcess,
cleanup,
cleanSharedmemory,
startProcessInBackground,
startProcessInBackgroundWithLogFile,
checkLogForErrors,
startDetectorVirtualServer,
loadConfig,
ParseArguments
)
LOG_PREFIX_FNAME = '/tmp/slsFrameSynchronizer_test'
MAIN_LOG_FNAME = LOG_PREFIX_FNAME + '_log.txt'
PULL_SOCKET_PREFIX_FNAME = LOG_PREFIX_FNAME + '_pull_socket_'
def startFrameSynchronizerPullSocket(name, fp):
fname = PULL_SOCKET_PREFIX_FNAME + name + '.txt'
cmd = ['python', '-u', 'frameSynchronizerPullSocket.py']
startProcessInBackgroundWithLogFile(cmd, fp, fname)
time.sleep(1)
checkLogForErrors(fp, fname)
def startFrameSynchronizer(num_mods, fp):
cmd = ['slsFrameSynchronizer', str(DEFAULT_TCP_RX_PORTNO), str(num_mods)]
# in 10.0.0
#cmd = ['slsFrameSynchronizer', '-p', str(DEFAULT_TCP_RX_PORTNO), '-n', str(num_mods)]
startProcessInBackground(cmd, fp)
time.sleep(1)
def acquire(fp, det):
Log(LogLevel.INFO, 'Acquiring')
Log(LogLevel.INFO, 'Acquiring', fp)
det.acquire()
def testFramesCaught(name, det, num_frames):
fnum = det.rx_framescaught[0]
if fnum != num_frames:
raise RuntimeException(f"{name} caught only {fnum}. Expected {num_frames}")
Log(LogLevel.INFOGREEN, f'Frames caught test passed for {name}')
Log(LogLevel.INFOGREEN, f'Frames caught test passed for {name}', fp)
def testZmqHeadetTypeCount(name, det, num_mods, num_frames, fp):
Log(LogLevel.INFO, f"Testing Zmq Header type count for {name}")
Log(LogLevel.INFO, f"Testing Zmq Header type count for {name}", fp)
htype_counts = {
"header": 0,
"series_end": 0,
"module": 0
}
try:
# get a count of each htype from file
pull_socket_fname = PULL_SOCKET_PREFIX_FNAME + name + '.txt'
with open(pull_socket_fname, 'r') as log_fp:
for line in log_fp:
line = line.strip()
if not line or not line.startswith('{'):
continue
try:
data = json.loads(line)
htype = data.get("htype")
if htype in htype_counts:
htype_counts[htype] += 1
except json.JSONDecodeError:
continue
# test if file contents matches expected counts
num_ports_per_module = 1 if name == "gotthard2" else det.numinterfaces
total_num_frame_parts = num_ports_per_module * num_mods * num_frames
for htype, expected_count in [("header", num_mods), ("series_end", num_mods), ("module", total_num_frame_parts)]:
if htype_counts[htype] != expected_count:
msg = f"Expected {expected_count} '{htype}' entries, found {htype_counts[htype]}"
raise RuntimeException(msg)
except Exception as e:
raise RuntimeException(f'Failed to get zmq header count type. Error:{str(e)}') from e
Log(LogLevel.INFOGREEN, f"Zmq Header type count test passed for {name}")
Log(LogLevel.INFOGREEN, f"Zmq Header type count test passed for {name}", fp)
def startTestsForAll(args, fp):
for server in args.servers:
try:
Log(LogLevel.INFOBLUE, f'Synchronizer Tests for {server}')
Log(LogLevel.INFOBLUE, f'Synchronizer Tests for {server}', fp)
cleanup(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)
acquire(fp, d)
testFramesCaught(server, d, args.num_frames)
testZmqHeadetTypeCount(server, d, args.num_mods, args.num_frames, fp)
Log(LogLevel.INFO, '\n')
except Exception as e:
raise RuntimeException(f'Synchronizer Tests failed') from e
Log(LogLevel.INFOGREEN, 'Passed all synchronizer tests for all detectors \n' + str(args.servers))
if __name__ == '__main__':
args = ParseArguments(description='Automated tests to test frame synchronizer', default_num_mods=2)
Log(LogLevel.INFOBLUE, '\nLog File: ' + MAIN_LOG_FNAME + '\n')
with open(MAIN_LOG_FNAME, 'w') as fp:
try:
startTestsForAll(args, fp)
cleanup(fp)
except Exception as e:
with open(MAIN_LOG_FNAME, 'a') as fp_error:
traceback.print_exc(file=fp_error)
cleanup(fp)
Log(LogLevel.ERROR, f'Tests Failed.')

View File

@ -4,86 +4,251 @@
This file is used to start up simulators, receivers and run all the tests on them and finally kill the simulators and receivers.
'''
import argparse
import sys, subprocess, time, traceback
import os, sys, subprocess, time, colorama
from slsdet import Detector
from slsdet.defines import DEFAULT_TCP_RX_PORTNO
from colorama import Fore
from slsdet import Detector, detectorType, detectorSettings
from slsdet.defines import DEFAULT_TCP_CNTRL_PORTNO, DEFAULT_TCP_RX_PORTNO, DEFAULT_UDP_DST_PORTNO
HALFMOD2_TCP_CNTRL_PORTNO=1955
HALFMOD2_TCP_RX_PORTNO=1957
from utils_for_test import (
Log,
LogLevel,
RuntimeException,
checkIfProcessRunning,
killProcess,
cleanup,
cleanSharedmemory,
startProcessInBackground,
runProcessWithLogFile,
startDetectorVirtualServer,
loadConfig,
ParseArguments
)
colorama.init(autoreset=True)
class RuntimeException (Exception):
def __init__ (self, message):
super().__init__(Fore.RED + message)
def Log(color, message):
print('\n' + color + message, flush=True)
LOG_PREFIX_FNAME = '/tmp/slsDetectorPackage_virtual_test'
MAIN_LOG_FNAME = LOG_PREFIX_FNAME + '_log.txt'
GENERAL_TESTS_LOG_FNAME = LOG_PREFIX_FNAME + '_results_general.txt'
CMD_TEST_LOG_PREFIX_FNAME = LOG_PREFIX_FNAME + '_results_cmd_'
def checkIfProcessRunning(processName):
cmd = f"pgrep -f {processName}"
res = subprocess.getoutput(cmd)
return bool(res.strip())
def startReceiver(num_mods, fp):
if num_mods == 1:
cmd = ['slsReceiver']
def killProcess(name):
if checkIfProcessRunning(name):
Log(Fore.GREEN, 'killing ' + name)
p = subprocess.run(['killall', name])
if p.returncode != 0:
raise RuntimeException('killall failed for ' + name)
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)
print('process not running : ' + name)
def startGeneralTests(fp):
fname = GENERAL_TESTS_LOG_FNAME
cmd = ['tests', '--abort', '-s']
def killAllStaleProcesses(fp):
killProcess('eigerDetectorServer_virtual')
killProcess('jungfrauDetectorServer_virtual')
killProcess('mythen3DetectorServer_virtual')
killProcess('gotthard2DetectorServer_virtual')
killProcess('ctbDetectorServer_virtual')
killProcess('moenchDetectorServer_virtual')
killProcess('xilinx_ctbDetectorServer_virtual')
killProcess('slsReceiver')
killProcess('slsMultiReceiver')
cleanSharedmemory(fp)
def cleanup(name, fp):
'''
kill both servers, receivers and clean shared memory
'''
Log(Fore.GREEN, 'Cleaning up...')
killProcess(name + 'DetectorServer_virtual')
killProcess('slsReceiver')
killProcess('slsMultiReceiver')
cleanSharedmemory(fp)
def cleanSharedmemory(fp):
Log(Fore.GREEN, 'Cleaning up shared memory...')
try:
cleanup(fp)
runProcessWithLogFile('General Tests', cmd, fp, fname)
p = subprocess.run(['sls_detector_get', 'free'], stdout=fp, stderr=fp)
except:
Log(Fore.RED, 'Could not free shared memory')
raise
def startProcessInBackground(name):
try:
# in background and dont print output
p = subprocess.Popen(name.split(), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, restore_signals=False)
Log(Fore.GREEN, 'Starting up ' + name + ' ...')
except Exception as e:
raise RuntimeException(f'General tests failed.') from e
Log(Fore.RED, f'Could not start {name}:{e}')
raise
def startServer(name):
startProcessInBackground(name + 'DetectorServer_virtual')
# second half
if name == 'eiger':
startProcessInBackground(name + 'DetectorServer_virtual -p' + str(HALFMOD2_TCP_CNTRL_PORTNO))
tStartup = 6
Log(Fore.WHITE, 'Takes ' + str(tStartup) + ' seconds... Please be patient')
time.sleep(tStartup)
def startReceiver(name):
startProcessInBackground('slsReceiver')
# second half
if name == 'eiger':
startProcessInBackground('slsReceiver -t' + str(HALFMOD2_TCP_RX_PORTNO))
time.sleep(2)
def loadConfig(name, rx_hostname, settingsdir):
Log(Fore.GREEN, 'Loading config')
try:
d = Detector()
if name == 'eiger':
d.hostname = 'localhost:' + str(DEFAULT_TCP_CNTRL_PORTNO) + '+localhost:' + str(HALFMOD2_TCP_CNTRL_PORTNO)
#d.udp_dstport = {2: 50003}
# will set up for every module
d.udp_dstport = DEFAULT_UDP_DST_PORTNO
d.udp_dstport2 = DEFAULT_UDP_DST_PORTNO + 1
d.rx_hostname = rx_hostname + ':' + str(DEFAULT_TCP_RX_PORTNO) + '+' + rx_hostname + ':' + str(HALFMOD2_TCP_RX_PORTNO)
d.udp_dstip = 'auto'
d.trimen = [4500, 5400, 6400]
d.settingspath = settingsdir + '/eiger/'
d.setThresholdEnergy(4500, detectorSettings.STANDARD)
else:
d.hostname = 'localhost'
d.rx_hostname = rx_hostname
d.udp_dstip = 'auto'
d.udp_srcip = 'auto'
if d.type == detectorType.JUNGFRAU or d.type == detectorType.MOENCH or d.type == detectorType.XILINX_CHIPTESTBOARD:
d.powerchip = 1
if d.type == detectorType.XILINX_CHIPTESTBOARD:
d.configureTransceiver()
except:
Log(Fore.RED, 'Could not load config for ' + name)
raise
def startCmdTests(name, fp, fname):
Log(Fore.GREEN, 'Cmd Tests for ' + name)
cmd = 'tests --abort [.cmdcall] -s -o ' + fname
try:
subprocess.run(cmd.split(), stdout=fp, stderr=fp, check=True, text=True)
except subprocess.CalledProcessError as e:
pass
with open (fname, 'r') as f:
for line in f:
if "FAILED" in line:
msg = 'Cmd tests failed for ' + name + '!!!'
sys.stdout = original_stdout
Log(Fore.RED, msg)
Log(Fore.RED, line)
sys.stdout = fp
raise Exception(msg)
Log(Fore.GREEN, 'Cmd Tests successful for ' + name)
def startGeneralTests(fp, fname):
Log(Fore.GREEN, 'General Tests')
cmd = 'tests --abort -s -o ' + fname
try:
subprocess.run(cmd.split(), stdout=fp, stderr=fp, check=True, text=True)
except subprocess.CalledProcessError as e:
pass
with open (fname, 'r') as f:
for line in f:
if "FAILED" in line:
msg = 'General tests failed !!!'
sys.stdout = original_stdout
Log(Fore.RED, msg + '\n' + line)
sys.stdout = fp
raise Exception(msg)
Log(Fore.GREEN, 'General Tests successful')
def startCmdTestsForAll(args, fp):
for server in args.servers:
try:
num_mods = 2 if server == 'eiger' else 1
fname = CMD_TEST_LOG_PREFIX_FNAME + server + '.txt'
cmd = ['tests', '--abort', '[.cmdcall]', '-s']
Log(LogLevel.INFOBLUE, f'Starting Cmd Tests for {server}')
cleanup(fp)
startDetectorVirtualServer(name=server, num_mods=num_mods, fp=fp)
startReceiver(num_mods, fp)
loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=num_mods)
runProcessWithLogFile('Cmd Tests for ' + server, cmd, fp, fname)
except Exception as e:
raise RuntimeException(f'Cmd Tests failed for {server}.') from e
# parse cmd line for rx_hostname and settingspath using the argparse library
parser = argparse.ArgumentParser(description = 'automated tests with the virtual detector servers')
parser.add_argument('rx_hostname', nargs='?', default='localhost', help = 'hostname/ip of the current machine')
parser.add_argument('settingspath', nargs='?', default='../../settingsdir', help = 'Relative or absolut path to the settingspath')
parser.add_argument('-s', '--servers', help='Detector servers to run', nargs='*')
args = parser.parse_args()
Log(LogLevel.INFOGREEN, 'Passed all tests for all detectors \n' + str(args.servers))
if args.servers is None:
servers = [
'eiger',
'jungfrau',
'mythen3',
'gotthard2',
'ctb',
'moench',
'xilinx_ctb'
]
else:
servers = args.servers
if __name__ == '__main__':
args = ParseArguments('Automated tests with the virtual detector servers')
if args.num_mods > 1:
raise RuntimeException(f'Cannot support multiple modules at the moment (except Eiger).')
Log(Fore.WHITE, 'Arguments:\nrx_hostname: ' + args.rx_hostname + '\nsettingspath: \'' + args.settingspath + '\'')
Log(LogLevel.INFOBLUE, '\nLog File: ' + MAIN_LOG_FNAME + '\n')
with open(MAIN_LOG_FNAME, 'w') as fp:
try:
startGeneralTests(fp)
startCmdTestsForAll(args, fp)
cleanup(fp)
except Exception as e:
with open(MAIN_LOG_FNAME, 'a') as fp_error:
traceback.print_exc(file=fp_error)
cleanup(fp)
Log(LogLevel.ERROR, f'Tests Failed.')
# redirect to file
prefix_fname = '/tmp/slsDetectorPackage_virtual_test'
original_stdout = sys.stdout
original_stderr = sys.stderr
fname = prefix_fname + '_log.txt'
Log(Fore.BLUE, '\nLog File: ' + fname)
with open(fname, 'w') as fp:
# general tests
file_results = prefix_fname + '_results_general.txt'
Log(Fore.BLUE, 'General tests (results: ' + file_results + ')')
sys.stdout = fp
sys.stderr = fp
Log(Fore.BLUE, 'General tests (results: ' + file_results + ')')
try:
startGeneralTests(fp, file_results)
killAllStaleProcesses(fp)
testError = False
for server in servers:
try:
# print to terminal for progress
sys.stdout = original_stdout
sys.stderr = original_stderr
file_results = prefix_fname + '_results_cmd_' + server + '.txt'
Log(Fore.BLUE, 'Cmd tests for ' + server + ' (results: ' + file_results + ')')
sys.stdout = fp
sys.stderr = fp
Log(Fore.BLUE, 'Cmd tests for ' + server + ' (results: ' + file_results + ')')
# cmd tests for det
cleanup(server, fp)
startServer(server)
startReceiver(server)
loadConfig(server, args.rx_hostname, args.settingspath)
startCmdTests(server, fp, file_results)
cleanup(server, fp)
except Exception as e:
# redirect to terminal
sys.stdout = original_stdout
sys.stderr = original_stderr
Log(Fore.RED, f'Exception caught while testing {server}. Cleaning up...')
testError = True
break
# redirect to terminal
sys.stdout = original_stdout
sys.stderr = original_stderr
if not testError:
Log(Fore.GREEN, 'Passed all tests for virtual detectors \n' + str(servers))
except Exception as e:
# redirect to terminal
sys.stdout = original_stdout
sys.stderr = original_stderr
Log(Fore.RED, f'Exception caught with general testing. Cleaning up...')
cleanSharedmemory(sys.stdout)

View File

@ -1,259 +0,0 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package
'''
This file is used for common utils used for integration tests between simulators and receivers.
'''
import sys, subprocess, time, argparse
from enum import Enum
from colorama import Fore, Style, init
from slsdet import Detector, detectorSettings
from slsdet.defines import DEFAULT_TCP_RX_PORTNO, DEFAULT_UDP_DST_PORTNO
SERVER_START_PORTNO=1900
init(autoreset=True)
class LogLevel(Enum):
INFO = 0
INFORED = 1
INFOGREEN = 2
INFOBLUE = 3
WARNING = 4
ERROR = 5
DEBUG = 6
LOG_LABELS = {
LogLevel.WARNING: "WARNING: ",
LogLevel.ERROR: "ERROR: ",
LogLevel.DEBUG: "DEBUG: "
}
LOG_COLORS = {
LogLevel.INFO: Fore.WHITE,
LogLevel.INFORED: Fore.RED,
LogLevel.INFOGREEN: Fore.GREEN,
LogLevel.INFOBLUE: Fore.BLUE,
LogLevel.WARNING: Fore.YELLOW,
LogLevel.ERROR: Fore.RED,
LogLevel.DEBUG: Fore.CYAN
}
def Log(level: LogLevel, message: str, stream=sys.stdout):
color = LOG_COLORS.get(level, Fore.WHITE)
label = LOG_LABELS.get(level, "")
print(f"{color}{label}{message}{Style.RESET_ALL}", file=stream, flush=True)
class RuntimeException (Exception):
def __init__ (self, message):
Log(LogLevel.ERROR, message)
super().__init__(message)
def checkIfProcessRunning(processName):
cmd = f"pgrep -f {processName}"
res = subprocess.getoutput(cmd)
return res.strip().splitlines()
def killProcess(name, fp):
pids = checkIfProcessRunning(name)
if pids:
Log(LogLevel.INFO, f"Killing '{name}' processes with PIDs: {', '.join(pids)}", fp)
for pid in pids:
try:
p = subprocess.run(['kill', pid])
if p.returncode != 0 and bool(checkIfProcessRunning(name)):
raise RuntimeException(f"Could not kill {name} with pid {pid}")
except Exception as e:
raise RuntimeException(f"Failed to kill process {name} pid:{pid}. Error: {str(e)}") from e
#else:
# Log(LogLevel.INFO, 'process not running : ' + name)
def cleanSharedmemory(fp):
Log(LogLevel.INFO, 'Cleaning up shared memory', fp)
try:
p = subprocess.run(['sls_detector_get', 'free'], stdout=fp, stderr=fp)
except:
raise RuntimeException('Could not free shared memory')
def cleanup(fp):
Log(LogLevel.INFO, 'Cleaning up')
Log(LogLevel.INFO, 'Cleaning up', fp)
killProcess('DetectorServer_virtual', fp)
killProcess('slsReceiver', fp)
killProcess('slsMultiReceiver', fp)
killProcess('slsFrameSynchronizer', fp)
killProcess('frameSynchronizerPullSocket', fp)
cleanSharedmemory(fp)
def startProcessInBackground(cmd, fp):
Log(LogLevel.INFO, 'Starting up ' + ' '.join(cmd))
Log(LogLevel.INFO, 'Starting up ' + ' '.join(cmd), fp)
try:
p = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, restore_signals=False)
except Exception as e:
raise RuntimeException(f'Failed to start {cmd}:{str(e)}') from e
def startProcessInBackgroundWithLogFile(cmd, fp, log_file_name: str):
Log(LogLevel.INFOBLUE, 'Starting up ' + ' '.join(cmd) + '. Log: ' + log_file_name)
Log(LogLevel.INFOBLUE, 'Starting up ' + ' '.join(cmd) + '. Log: ' + log_file_name, fp)
try:
with open(log_file_name, 'w') as log_fp:
subprocess.Popen(cmd, stdout=log_fp, stderr=log_fp, text=True)
except Exception as e:
raise RuntimeException(f'Failed to start {cmd}:{str(e)}') from e
def checkLogForErrors(fp, log_file_path: str):
try:
with open(log_file_path, 'r') as log_file:
for line in log_file:
if 'Error' in line:
Log(LogLevel.ERROR, f"Error found in log: {line.strip()}")
Log(LogLevel.ERROR, f"Error found in log: {line.strip()}", fp)
raise RuntimeException("Error found in log file")
except FileNotFoundError:
print(f"Log file not found: {log_file_path}")
raise
except Exception as e:
print(f"Exception while reading log: {e}")
raise
def runProcessWithLogFile(name, cmd, fp, log_file_name):
Log(LogLevel.INFOBLUE, 'Running ' + name + '. Log: ' + log_file_name)
Log(LogLevel.INFOBLUE, 'Running ' + name + '. Log: ' + log_file_name, fp)
Log(LogLevel.INFOBLUE, 'Cmd: ' + ' '.join(cmd), fp)
try:
with open(log_file_name, 'w') as log_fp:
subprocess.run(cmd, stdout=log_fp, stderr=log_fp, check=True, text=True)
except subprocess.CalledProcessError as e:
pass
except Exception as e:
Log(LogLevel.ERROR, f'Failed to run {name}:{str(e)}', fp)
raise RuntimeException(f'Failed to run {name}:{str(e)}')
with open (log_file_name, 'r') as f:
for line in f:
if "FAILED" in line:
raise RuntimeException(f'{line}')
Log(LogLevel.INFOGREEN, name + ' successful!\n')
Log(LogLevel.INFOGREEN, name + ' successful!\n', fp)
def startDetectorVirtualServer(name :str, num_mods, fp):
for i in range(num_mods):
port_no = SERVER_START_PORTNO + (i * 2)
cmd = [name + 'DetectorServer_virtual', '-p', str(port_no)]
startProcessInBackgroundWithLogFile(cmd, fp, "/tmp/virtual_det_" + name + str(i) + ".txt")
match name:
case 'jungfrau':
time.sleep(7)
case 'gotthard2':
time.sleep(5)
case _:
time.sleep(3)
def connectToVirtualServers(name, num_mods):
try:
d = Detector()
except Exception as e:
raise RuntimeException(f'Could not create Detector object for {name}. Error: {str(e)}') from e
counts_sec = 5
while (counts_sec != 0):
try:
d.virtual = [num_mods, SERVER_START_PORTNO]
break
except Exception as e:
# stop server still not up, wait a bit longer
if "Cannot connect to" in str(e):
Log(LogLevel.WARNING, f'Still waiting for {name} virtual server to be up...{counts_sec}s left')
time.sleep(1)
counts_sec -= 1
else:
raise
return d
def loadConfig(name, rx_hostname, settingsdir, fp, num_mods = 1, num_frames = 1):
Log(LogLevel.INFO, 'Loading config')
Log(LogLevel.INFO, 'Loading config', fp)
try:
d = connectToVirtualServers(name, num_mods)
d.udp_dstport = DEFAULT_UDP_DST_PORTNO
if name == 'eiger':
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" 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)
d.frames = num_frames
except Exception as e:
raise RuntimeException(f'Could not load config for {name}. Error: {str(e)}') from e
return d
def ParseArguments(description, default_num_mods=1):
parser = argparse.ArgumentParser(description)
parser.add_argument('rx_hostname', nargs='?', default='localhost',
help='Hostname/IP of the current machine')
parser.add_argument('settingspath', nargs='?', default='../../settingsdir',
help='Relative or absolute path to the settings directory')
parser.add_argument('-n', '--num-mods', nargs='?', default=default_num_mods, type=int,
help='Number of modules to test with')
parser.add_argument('-f', '--num-frames', nargs='?', default=1, type=int,
help='Number of frames to test with')
parser.add_argument('-s', '--servers', nargs='*',
help='Detector servers to run')
args = parser.parse_args()
# Set default server list if not provided
if args.servers is None:
args.servers = [
'eiger',
'jungfrau',
'mythen3',
'gotthard2',
'ctb',
'moench',
'xilinx_ctb'
]
Log(LogLevel.INFO, 'Arguments:\n' +
'rx_hostname: ' + args.rx_hostname +
'\nsettingspath: \'' + args.settingspath +
'\nservers: \'' + ' '.join(args.servers) +
'\nnum_mods: \'' + str(args.num_mods) +
'\nnum_frames: \'' + str(args.num_frames) + '\'')
return args

View File

@ -1,81 +0,0 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2025 Contributors to the SLS Detector Package
"""
Script to update API VERSION file based on the version in VERSION file.
"""
import argparse
import sys
import os
import re
import time
from datetime import datetime
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
API_FILE = SCRIPT_DIR + "/slsSupportLib/include/sls/versionAPI.h"
VERSION_FILE = SCRIPT_DIR + "/VERSION"
parser = argparse.ArgumentParser(description = 'updates API version')
parser.add_argument('api_module_name', choices=["APILIB", "APIRECEIVER", "APICTB", "APIGOTTHARD2", "APIMOENCH", "APIEIGER", "APIXILINXCTB", "APIJUNGFRAU", "APIMYTHEN3"], help = 'module name to change api version options are: ["APILIB", "APIRECEIVER", "APICTB", "APIGOTTHARD2", "APIMOENCH", "APIEIGER", "APIXILINXCTB", "APIJUNGFRAU", "APIMYTHEN3"]')
parser.add_argument('api_dir', help = 'Relative or absolute path to the module code')
def update_api_file(new_api : str, api_module_name : str, api_file_name : str):
regex_pattern = re.compile(rf'#define\s+{api_module_name}\s+')
with open(api_file_name, "r") as api_file:
lines = api_file.readlines()
with open(api_file_name, "w") as api_file:
for line in lines:
if regex_pattern.match(line):
api_file.write(f'#define {api_module_name} "{new_api}"\n')
else:
api_file.write(line)
def get_latest_modification_date(directory : str):
latest_time = 0
latest_date = None
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith(".o"):
continue
full_path = os.path.join(root, file)
try:
mtime = os.path.getmtime(full_path)
if mtime > latest_time:
latest_time = mtime
except FileNotFoundError:
continue
latest_date = datetime.fromtimestamp(latest_time).strftime("%y%m%d")
return latest_date
def update_api_version(api_module_name : str, api_dir : str):
api_date = get_latest_modification_date(api_dir)
api_date = "0x"+str(api_date)
with open(VERSION_FILE, "r") as version_file:
api_version = version_file.read().strip()
api_version = api_version + " " + api_date #not sure if we should give an argument option version_branch
update_api_file(api_version, api_module_name, API_FILE)
print(f"updated {api_module_name} api version to: {api_version}")
if __name__ == "__main__":
args = parser.parse_args()
api_dir = SCRIPT_DIR + "/" + args.api_dir
update_api_version(args.api_module_name, api_dir)

65
updateAPIVersion.sh Executable file
View File

@ -0,0 +1,65 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package
usage="\nUsage: updateAPIVersion.sh [API_NAME] [API_DIR] [API_BRANCH(opt)]."
if [ $# -lt 2 ]; then
echo -e "Requires atleast 2 arguments. $usage"
return [-1]
fi
API_NAME=$1
PACKAGE_DIR=$PWD
API_DIR=$PACKAGE_DIR/$2
API_FILE=$PACKAGE_DIR/slsSupportLib/include/sls/versionAPI.h
CURR_DIR=$PWD
if [ ! -d "$API_DIR" ]; then
echo "[API_DIR] does not exist. $usage"
return [-1]
fi
#go to directory
cd $API_DIR
#deleting line from file
NUM=$(sed -n '/'$API_NAME' /=' $API_FILE)
#echo $NUM
if [ "$NUM" -gt 0 ]; then
sed -i ${NUM}d $API_FILE
fi
#find new API date
API_DATE="find . -printf \"%T@ %CY-%Cm-%Cd\n\"| sort -nr | cut -d' ' -f2- | egrep -v '(\.)o' | head -n 1"
API_DATE=`eval $API_DATE`
API_DATE=$(sed "s/-//g" <<< $API_DATE | awk '{print $1;}' )
#extracting only date
API_DATE=${API_DATE:2:6}
#prefix of 0x
API_DATE=${API_DATE/#/0x}
echo "date="$API_DATE
# API_VAL concatenates branch and date
API_VAL=""
# API branch is defined (3rd argument)
if [ $# -eq 3 ]; then
API_BRANCH=$3
echo "branch="$API_BRANCH
API_VAL+="\"$API_BRANCH $API_DATE\""
else
# API branch not defined (default is developer)
echo "branch=developer"
API_VAL+="\"developer $API_DATE\""
fi
#copy it to versionAPI.h
echo "#define "$API_NAME $API_VAL >> $API_FILE
#go back to original directory
cd $CURR_DIR

View File

@ -1,34 +0,0 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2025 Contributors to the SLS Detector Package
"""
Script to update API VERSION for slsReceiverSoftware or slsDetectorSoftware
"""
import argparse
import os
from updateAPIVersion import update_api_version
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
parser = argparse.ArgumentParser(description = 'updates API version')
parser.add_argument('module_name', nargs="?", choices=["slsDetectorSoftware", "slsReceiverSoftware", "all"], default="all", help = 'module name to change api version options are: ["slsDetectorSoftware", "slsReceiverSoftware, "all"]')
if __name__ == "__main__":
args = parser.parse_args()
if args.module_name == "all":
client_names = ["APILIB", "APIRECEIVER"]
client_directories = [SCRIPT_DIR+"/slsDetectorSoftware", SCRIPT_DIR+"/slsReceiverSoftware"]
elif args.module_name == "slsDetectorSoftware":
client_names = ["APILIB"]
client_directories = [SCRIPT_DIR+"/slsDetectorSoftware"]
else:
client_names = ["APIRECEIVER"]
client_directories = [SCRIPT_DIR+"/slsReceiverSoftware"]
for client_name, client_directory in zip(client_names, client_directories):
update_api_version(client_name, client_directory)

59
updateClientAPIVersion.sh Executable file
View File

@ -0,0 +1,59 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package
branch=""
client_list=("slsDetectorSoftware" "slsReceiverSoftware")
usage="\nUsage: updateClientAPI.sh [all|slsDetectorSoftware|slsReceiverSoftware] [branch]. \n\tNo arguments means all with 'developer' branch. \n\tNo 'branch' input means 'developer branch'"
# arguments
if [ $# -eq 0 ]; then
declare -a client=${client_list[@]}
echo "API Versioning all"
elif [ $# -eq 1 ] || [ $# -eq 2 ]; then
# 'all' client
if [[ $1 == "all" ]]; then
declare -a client=${client_list[@]}
echo "API Versioning all"
else
# only one server
if [[ $client_list != *$1* ]]; then
echo -e "Invalid argument 1: $1. $usage"
return -1
fi
declare -a client=("${1}")
#echo "Versioning only $1"
fi
if [ $# -eq 2 ]; then
if [[ $client_list == *$2* ]]; then
echo -e "Invalid argument 2: $2. $usage"
return -1
fi
branch+=$2
#echo "with branch $branch"
fi
else
echo -e "Too many arguments.$usage"
return -1
fi
#echo "list is: ${client[@]}"
# versioning each client
for i in ${client[@]}
do
dir=$i
case $dir in
slsDetectorSoftware)
declare -a name=APILIB
;;
slsReceiverSoftware)
declare -a name=APIRECEIVER
;;
*)
echo -n "unknown client argument $i"
return -1
;;
esac
echo -e "Versioning $dir [$name]"
./updateAPIVersion.sh $name $dir $branch
done