merge fix from developer

This commit is contained in:
2025-07-03 11:59:35 +02:00
104 changed files with 3337 additions and 834 deletions

View File

@ -0,0 +1,29 @@
name: Build on RHEL8
on:
push:
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: "ubuntu-latest"
container:
image: gitea.psi.ch/detectors/rhel8-detectors-dev
steps:
- name: Clone repository
run: |
echo Cloning ${{ github.ref_name }}
git clone https://${{secrets.GITHUB_TOKEN}}@gitea.psi.ch/${{ github.repository }}.git --branch=${{ github.ref_name }} .
- name: Build library
run: |
mkdir build && cd build
cmake .. -DSLS_USE_PYTHON=ON -DSLS_USE_TESTS=ON
make -j 2
- name: C++ unit tests
working-directory: ${{gitea.workspace}}/build
run: ctest

View File

@ -0,0 +1,27 @@
name: Build on RHEL9
on:
push:
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: "ubuntu-latest"
container:
image: gitea.psi.ch/detectors/rhel9-detectors-dev
steps:
- uses: actions/checkout@v4
- name: Build library
run: |
mkdir build && cd build
cmake .. -DSLS_USE_PYTHON=ON -DSLS_USE_TESTS=ON
make -j 2
- name: C++ unit tests
working-directory: ${{gitea.workspace}}/build
run: ctest

64
.github/workflows/build_wheel.yml vendored Normal file
View File

@ -0,0 +1,64 @@
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,6 +21,7 @@ if (${CMAKE_VERSION} VERSION_GREATER "3.24")
endif()
include(cmake/project_version.cmake)
include(cmake/SlsAddFlag.cmake)
include(cmake/helpers.cmake)
@ -44,6 +45,10 @@ endif()
# Patch is applied in the FetchContent_Declare
set(SLS_LIBZMQ_VERSION "4.3.4")
find_program(PATCH_EXECUTABLE patch)
if(NOT PATCH_EXECUTABLE)
message(FATAL_ERROR "The 'patch' tool is required for patching lib zeromq. Please install it.")
endif()
if(SLS_FETCH_ZMQ_FROM_GITHUB)
# Opt in to pull down a zmq version from github instead of
@ -189,11 +194,9 @@ find_package(ClangFormat)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
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()
default_build_type("Release")
set_std_fs_lib()
message(STATUS "Extra linking to fs lib:${STD_FS_LIB}")
#Enable LTO if available
include(CheckIPOSupported)
@ -216,7 +219,7 @@ endif()
# to control options for the libraries
if(NOT TARGET slsProjectOptions)
add_library(slsProjectOptions INTERFACE)
target_compile_features(slsProjectOptions INTERFACE cxx_std_11)
target_compile_features(slsProjectOptions INTERFACE cxx_std_17)
endif()
if (NOT TARGET slsProjectWarnings)
@ -329,7 +332,8 @@ if (SLS_USE_INTEGRATION_TESTS)
endif (SLS_USE_INTEGRATION_TESTS)
if (SLS_USE_PYTHON)
find_package (Python 3.8 COMPONENTS Interpreter Development)
find_package (Python 3.8 COMPONENTS Interpreter Development.Module REQUIRED)
set(PYBIND11_FINDPYTHON ON) # Needed for RH8
if(SLS_FETCH_PYBIND11_FROM_GITHUB)
FetchContent_Declare(
pybind11

View File

@ -25,7 +25,9 @@ mark_as_advanced(
ClangFormat_BIN)
if(ClangFormat_FOUND)
exec_program(${ClangFormat_BIN} ${CMAKE_CURRENT_SOURCE_DIR} ARGS --version OUTPUT_VARIABLE CLANG_VERSION_TEXT)
execute_process(COMMAND ${ClangFormat_BIN} --version
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
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

46
cmake/helpers.cmake Normal file
View File

@ -0,0 +1,46 @@
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

@ -1,11 +1,11 @@
package:
name: sls_detector_software
version: 2025.3.19
source:
path: ../..
{% set version = load_file_regex(load_file = 'VERSION', regex_pattern = '(\d+(?:\.\d+)*(?:[\+\w\.]+))').group(1) %}
package:
name: sls_detector_software
version: {{ version }}
build:
number: 0
binary_relocation: True
@ -28,6 +28,7 @@ requirements:
- libgl-devel # [linux]
- libtiff
- zlib
- expat
run:
- libstdcxx-ng
@ -49,8 +50,6 @@ outputs:
- libgcc-ng
- name: slsdetgui
script: copy_gui.sh
requirements:
@ -60,6 +59,7 @@ outputs:
- {{compiler('cxx')}}
- {{ pin_subpackage('slsdetlib', exact=True) }}
run:
- {{ pin_subpackage('slsdetlib', exact=True) }}
- qt 5.*

View File

@ -1,10 +1,11 @@
package:
name: slsdet
version: 2025.3.19 #TODO! how to not duplicate this?
source:
path: ../..
{% set version = load_file_regex(load_file = 'VERSION', regex_pattern = '(\d+(?:\.\d+)*(?:[\+\w\.]+))').group(1) %}
package:
name: slsdet
version: {{ version }}
build:
number: 0
script:
@ -17,7 +18,6 @@ requirements:
- {{ stdlib("c") }}
- {{ compiler('cxx') }}
host:
- cmake
- ninja

View File

@ -42,6 +42,7 @@ 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

@ -359,6 +359,7 @@ Chip Test Board
"Digital Flag": 0,
"Digital Samples": 1000,
"Dbit Offset": 0,
"Dbit Reorder": 1,
"Dbit Bitset": 0,
"Transceiver Mask": "0x3",
"Transceiver Flag": 0,

View File

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

View File

@ -6,18 +6,33 @@
Installation
===============
One can either install pre-built binaries using conda or build from source.
.. contents::
:local:
:depth: 2
:backlinks: top
.. 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.
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.
Install binaries using conda
----------------------------------
.. _conda pre-built binaries:
1. Install pre-built binaries using conda (Recommended)
--------------------------------------------------------
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)
@ -63,12 +78,29 @@ 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:
1. Download Source Code from github
3. Build from source
-------------------------
3.1. Download Source Code from github
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: bash
@ -83,12 +115,12 @@ Build from source
2. Build from Source
3.2. Build from Source
^^^^^^^^^^^^^^^^^^^^^^^^^^
One can either build using cmake or use the in-built cmk.sh script.
Build using CMake
3.2.1. Build using CMake
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: bash
@ -135,7 +167,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>`
Build using in-built cmk.sh script
3.2.2. Build using in-built cmk.sh script
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -185,8 +217,8 @@ Build using in-built cmk.sh script
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>`
Build on old distributions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3.3. Build on old distributions using conda
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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
@ -210,7 +242,7 @@ using this compiler
Build slsDetectorGui (Qt5)
3.4. Build slsDetectorGui (Qt5)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1. Using pre-built binary on conda
@ -271,7 +303,7 @@ Build slsDetectorGui (Qt5)
Build this documentation
3.5. Build this documentation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The documentation for the slsDetectorPackage is build using a combination
@ -294,8 +326,8 @@ is to use conda
make rst # rst only, saves time in case the API did not change
Pybind and Zeromq
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4. Pybind and Zeromq
-------------------------
.. _pybind for different slsDetectorPackage versions:

View File

@ -345,6 +345,9 @@ Chip Test Board
+-----------------------+-------------------------------------------------+
| Dbit Offset | Digital offset of valid data in bytes |
+-----------------------+-------------------------------------------------+
| Dbit Reorder | Reorder such that it groups each signal (0-63) |
| | from all the different samples together |
+-----------------------+-------------------------------------------------+
| Dbit Bitset | Digital 64 bit mask of bits enabled in receiver |
+-----------------------+-------------------------------------------------+
| Transceiver Mask | Mask of channels enabled in Transceiver |

228
docs/src/multidet.rst Normal file
View File

@ -0,0 +1,228 @@
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,6 +123,47 @@ 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 @@
Receivers
Custom Receiver
=================
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.
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>`.
To know more about detector receiver configuration, please check out :ref:`detector udp header and udp commands in the config file <detector udp header>`
| Please note the following when using a custom receiver:
Custom Receiver
----------------
* **udp_dstmac** must be configured in the config file. This parameter is not required when using an in-built receiver.
| 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.
* Cannot use "auto" for **udp_dstip**.
| Cannot use "auto" for **udp_dstip**.
* No **rx_** commands in the config file. These commands are for configuring the slsReceiver.
| Also ensure that there are no **rx_** commands in the config file. These commands are for configuring the slsReceiver.
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.
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,4 +1,5 @@
.. _Detector Server Upgrade:
Upgrade
========

View File

@ -1,16 +1,55 @@
slsReceiver/ slsMultiReceiver
In-built Receiver
================================
| 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
# default port 1954
slsReceiver
slsReceiver # default port 1954
# custom port 2012
slsReceiver -t2012
slsReceiver -t2012 # custom port 2012
For Multiple Modules
@ -18,57 +57,66 @@ For Multiple Modules
# each receiver (for each module) requires a unique tcp port (if all on same machine)
# using slsReceiver in multiple consoles
# option 1 (one for each module)
slsReceiver
slsReceiver -t1955
# slsMultiReceiver [starting port] [number of receivers]
# option 2
slsMultiReceiver 2012 2
# slsMultiReceiver [starting port] [number of receivers] [print each frame header for debugging]
slsMultiReceiver 2012 2 1
# option 3
slsFrameSynchronizer 2012 2
Client Commands
-----------------
| One can remove **udp_dstmac** from the config file, as the slsReceiver fetches this from the **udp_ip**.
* Client commands to the receiver begin with **rx_** or **f_** (file commands).
| One can use "auto" for **udp_dstip** if one wants to use default ip of **rx_hostname**.
* **rx_hostname** has to be the first command to the receiver so the client knows which receiver process to communicate with.
| The first command to the receiver (**rx_** commands) should be **rx_hostname**. The following are the different ways to establish contact.
* 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.
.. code-block:: bash
# default receiver tcp port (1954)
# ---single module---
# default receiver port at 1954
rx_hostname xxx
# custom receiver port
rx_hostname xxx:1957
rx_hostname xxx:1957 # option 1
# custom receiver port
rx_tcpport 1954
rx_tcpport 1957 # option 2
rx_hostname xxx
# multi modules with custom ports
rx_hostname xxx:1955+xxx:1956+
# ---multi module---
# multi modules using increasing tcp ports when using multi detector command
# using increasing tcp ports
rx_tcpport 1955
rx_hostname xxx
# or specify multi modules with custom ports on same rxr pc
0:rx_tcpport 1954
# custom ports
rx_hostname xxx:1955+xxx:1958+ # option 1
0:rx_tcpport 1954 # option 2
1:rx_tcpport 1955
2:rx_tcpport 1956
rx_hostname xxx
# multi modules with custom ports on different rxr pc
# custom ports on different receiver machines
0:rx_tcpport 1954
0:rx_hostname xxx
1:rx_tcpport 1955
1:rx_hostname yyy
1:rx_hostname yyyrxr
| Example commands:
@ -91,6 +139,32 @@ Client Commands
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:
.. _detector udp header config:
Config file

View File

@ -1,4 +1,5 @@
.. _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

@ -22,6 +22,7 @@ class SignalsTab(QtWidgets.QWidget):
self.plotTab = None
self.legend: LegendItem | None = None
self.rx_dbitoffset = None
self.rx_dbitreorder = None
self.rx_dbitlist = None
def refresh(self):
@ -29,6 +30,7 @@ class SignalsTab(QtWidgets.QWidget):
self.updateDigitalBitEnable()
self.updateIOOut()
self.getDBitOffset()
self.getDBitReorder()
def connect_ui(self):
for i in range(Defines.signals.count):
@ -49,6 +51,7 @@ class SignalsTab(QtWidgets.QWidget):
partial(self.setIOOutRange, Defines.signals.half, Defines.signals.count))
self.view.lineEditPatIOCtrl.editingFinished.connect(self.setIOOutReg)
self.view.spinBoxDBitOffset.editingFinished.connect(self.setDbitOffset)
self.view.checkBoxDBitReorder.stateChanged.connect(self.setDbitReorder)
def setup_ui(self):
self.plotTab = self.mainWindow.plotTab
@ -87,60 +90,79 @@ class SignalsTab(QtWidgets.QWidget):
self.legend.addItem(plot, name)
@recordOrApplyPedestal
def _processWaveformData(self, data, aSamples, dSamples, rx_dbitlist, isPlottedArray, rx_dbitoffset, romode,
def _processWaveformData(self, data, aSamples, dSamples, rx_dbitreorder, rx_dbitlist, isPlottedArray, romode,
nADCEnabled):
"""
transform raw waveform data into a processed numpy array
@param data: raw waveform data
"""
dbitoffset = rx_dbitoffset
if romode == 2:
dbitoffset += nADCEnabled * 2 * aSamples
digital_array = np.array(np.frombuffer(data, offset=dbitoffset, dtype=np.uint8))
nbitsPerDBit = dSamples
if nbitsPerDBit % 8 != 0:
nbitsPerDBit += (8 - (dSamples % 8))
offset = 0
arr = []
for i in rx_dbitlist:
# where numbits * numsamples is not a multiple of 8
if offset % 8 != 0:
offset += (8 - (offset % 8))
if not isPlottedArray[i]:
offset += nbitsPerDBit
return None
waveform = np.zeros(dSamples)
for iSample in range(dSamples):
# all samples for digital bit together from slsReceiver
index = int(offset / 8)
iBit = offset % 8
bit = (digital_array[index] >> iBit) & 1
waveform[iSample] = bit
offset += 1
arr.append(waveform)
return np.array(arr)
#transform raw waveform data into a processed numpy array
#@param data: raw waveform data
start_digital_data = 0
if romode == 2:
start_digital_data += nADCEnabled * 2 * aSamples
digital_array = np.array(np.frombuffer(data, offset=start_digital_data, dtype=np.uint8))
if rx_dbitreorder:
samples_per_bit = np.empty((len(rx_dbitlist), dSamples), dtype=np.uint8) #stored per row all the corresponding signals of all samples
nbitsPerDBit = dSamples
if nbitsPerDBit % 8 != 0:
nbitsPerDBit += (8 - (dSamples % 8))
bit_index = 0
for idx, i in enumerate(rx_dbitlist):
# where numbits * numsamples is not a multiple of 8
if bit_index % 8 != 0:
bit_index += (8 - (bit_index % 8))
if not isPlottedArray[i]:
bit_index += nbitsPerDBit
samples_per_bit[idx, :] = np.nan
continue
for iSample in range(dSamples):
# all samples for digital bit together from slsReceiver
index = int(bit_index / 8)
iBit = bit_index % 8
bit = (digital_array[index] >> iBit) & 1
samples_per_bit[idx,iSample] = bit
bit_index += 1
return samples_per_bit
else:
nbitsPerSample = len(rx_dbitlist) if len(rx_dbitlist) % 8 == 0 else len(rx_dbitlist) + (8 - (len(rx_dbitlist) % 8))
bits_per_sample = np.empty((dSamples, len(rx_dbitlist)), dtype=np.uint8) #store per row all selected bits of a sample
for iSample in range(dSamples):
bit_index = nbitsPerSample * iSample
for idx, i in enumerate(rx_dbitlist):
if not isPlottedArray[i]:
bit_index += 1
bits_per_sample[iSample, idx] = np.nan
index = int(bit_index/8)
iBit = idx % 8
bit = (digital_array[index] >> iBit) & 1
bits_per_sample[iSample, idx] = bit
bit_index += 1
return bits_per_sample.T.copy()
def processWaveformData(self, data, aSamples, dSamples):
"""
view function
plots processed waveform data
data: raw waveform data
dsamples: digital samples
asamples: analog samples
"""
#view function
#plots processed waveform data
#data: raw waveform data
#dsamples: digital samples
#asamples: analog samples
self.refresh()
waveforms = {}
isPlottedArray = {i: getattr(self.view, f"checkBoxBIT{i}Plot").isChecked() for i in self.rx_dbitlist}
digital_array = self._processWaveformData(data, aSamples, dSamples, self.rx_dbitlist, isPlottedArray,
self.rx_dbitoffset, self.mainWindow.romode.value,
digital_array = self._processWaveformData(data, aSamples, dSamples, self.rx_dbitreorder, self.rx_dbitlist, isPlottedArray,
self.mainWindow.romode.value,
self.mainWindow.nADCEnabled)
irow = 0
for idx, i in enumerate(self.rx_dbitlist):
# bits enabled but not plotting
waveform = digital_array[idx]
if waveform is None:
waveform = digital_array[idx, :]
if np.isnan(waveform[0]):
continue
self.mainWindow.digitalPlots[i].setData(waveform)
plotName = getattr(self.view, f"labelBIT{i}").text()
@ -151,8 +173,10 @@ class SignalsTab(QtWidgets.QWidget):
irow += 1
else:
self.mainWindow.digitalPlots[i].setY(0)
return waveforms
def initializeAllDigitalPlots(self):
self.mainWindow.plotDigitalWaveform = pg.plot()
self.mainWindow.plotDigitalWaveform.addLegend(colCount=Defines.colCount)
@ -360,14 +384,25 @@ class SignalsTab(QtWidgets.QWidget):
self.view.spinBoxDBitOffset.setValue(self.rx_dbitoffset)
self.view.spinBoxDBitOffset.editingFinished.connect(self.setDbitOffset)
def getDBitReorder(self):
self.view.checkBoxDBitReorder.stateChanged.disconnect()
self.rx_dbitreorder = self.det.rx_dbitreorder
self.view.checkBoxDBitReorder.setChecked(self.rx_dbitreorder)
self.view.checkBoxDBitReorder.stateChanged.connect(self.setDbitReorder)
def setDbitOffset(self):
self.det.rx_dbitoffset = self.view.spinBoxDBitOffset.value()
def setDbitReorder(self):
self.det.rx_dbitreorder = self.view.checkBoxDBitReorder.isChecked()
def saveParameters(self) -> list:
commands = []
dblist = [str(i) for i in range(Defines.signals.count) if getattr(self.view, f"checkBoxBIT{i}DB").isChecked()]
if len(dblist) > 0:
commands.append(f"rx_dbitlist {', '.join(dblist)}")
commands.append(f"rx_dbitoffset {self.view.spinBoxDBitOffset.value()}")
commands.append(f"rx_dbitreorder {self.view.checkBoxDBitReorder.isChecked()}")
commands.append(f"patioctrl {self.view.lineEditPatIOCtrl.text()}")
return commands

View File

@ -6074,6 +6074,33 @@
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_17">
<item row="0" column="4">
<widget class="QSpinBox" name="spinBoxDBitOffset">
<property name="minimumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_66">
<property name="font">
@ -6086,6 +6113,36 @@
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QCheckBox" name="checkBoxDBitReorder">
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>DBit Reorder</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_48">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>IO Control Register:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEditPatIOCtrl">
<property name="sizePolicy">
@ -6133,50 +6190,18 @@
</property>
</spacer>
</item>
<item row="0" column="4">
<widget class="QSpinBox" name="spinBoxDBitOffset">
<property name="minimumSize">
<item row="0" column="5">
<spacer name="horizontalSpacer_22">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>150</width>
<height>32</height>
<width>40</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_48">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>IO Control Register:</string>
</property>
</widget>
</spacer>
</item>
</layout>
</widget>

View File

@ -1,27 +1,37 @@
[tool.scikit-build.metadata.version]
provider = "scikit_build_core.metadata.regex"
input = "VERSION"
regex = '^(?P<version>\d+(?:\.\d+)*(?:[\.\+\w]+)?)$'
result = "{version}"
[build-system]
requires = ["scikit-build-core>=0.10", "pybind11", "numpy"]
requires = [ "scikit-build-core>=0.10", "pybind11", "numpy",]
build-backend = "scikit_build_core.build"
[project]
name = "slsdet"
version = "2025.3.19"
dynamic = ["version"]
dependencies = [
"numpy",
]
[tool.cibuildwheel]
before-all = "uname -a"
build = "cp{311,312,313}-manylinux_x86_64"
[tool.scikit-build]
build.verbose = true
cmake.build-type = "Release"
install.components = ["python"]
[tool.scikit-build.build]
verbose = true
[tool.scikit-build.cmake]
build-type = "Release"
[tool.scikit-build.install]
components = [ "python",]
[tool.scikit-build.cmake.define]
#Only build the control software and python ext
SLS_USE_RECEIVER = "OFF"
SLS_USE_RECEIVER_BINARIES = "OFF"
SLS_USE_TEXTCLIENT = "OFF"
SLS_BUILD_SHARED_LIBRARIES = "OFF"
SLS_USE_PYTHON = "ON"
SLS_INSTALL_PYTHONEXT = "ON"

View File

@ -65,6 +65,9 @@ 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

@ -3463,6 +3463,16 @@ class Detector(CppDetectorApi):
def rx_dbitoffset(self, value):
ut.set_using_dict(self.setRxDbitOffset, value)
@property
@element
def rx_dbitreorder(self):
"""[Ctb] Reorder digital data to group together all samples per signal. Default is 1. Setting to 0 means 'do not reorder' and to keep what the board spits out, which is that all signals in a sample are grouped together."""
return self.getRxDbitReorder()
@rx_dbitreorder.setter
def rx_dbitreorder(self, value):
ut.set_using_dict(self.setRxDbitReorder, value)
@property
@element
def maxadcphaseshift(self):

View File

@ -1664,6 +1664,14 @@ void init_det(py::module &m) {
(void (Detector::*)(int, sls::Positions)) &
Detector::setRxDbitOffset,
py::arg(), py::arg() = Positions{});
CppDetectorApi.def("getRxDbitReorder",
(Result<bool>(Detector::*)(sls::Positions) const) &
Detector::getRxDbitReorder,
py::arg() = Positions{});
CppDetectorApi.def("setRxDbitReorder",
(void (Detector::*)(bool, sls::Positions)) &
Detector::setRxDbitReorder,
py::arg(), py::arg() = Positions{});
CppDetectorApi.def("setDigitalIODelay",
(void (Detector::*)(uint64_t, int, sls::Positions)) &
Detector::setDigitalIODelay,

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

@ -1,8 +1,6 @@
# 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
@ -10,7 +8,12 @@ det_list=("ctbDetectorServer
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'"
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
# arguments
if [ $# -eq 0 ]; then
@ -34,15 +37,12 @@ elif [ $# -eq 1 ] || [ $# -eq 2 ]; then
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
update_api=$2
if not $update_api ; then
target=clean
fi
branch+=$2
#echo "with branch $branch"
fi
else
echo -e "Too many arguments.$usage"
@ -53,6 +53,9 @@ 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[@]}
@ -62,14 +65,13 @@ do
echo -e "Compiling $dir [$file]"
cd $dir
make clean
if make version API_BRANCH=$branch; then
if make $target; 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

@ -1,86 +0,0 @@
# 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 Normal file → Executable file
View File

@ -3,21 +3,31 @@
deterror="OK"
dir="eigerDetectorServer"
file="${dir}_developer"
branch=""
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
# arguments
if [ $# -eq 1 ]; then
branch+=$1
#echo "with branch $branch"
update_api=$1
if not $update_api ; then
target=clean
fi
elif [ ! $# -eq 0 ]; then
echo -e "Only one optional argument allowed for branch."
echo -e "Only one optional argument allowed for update_api."
return -1
fi
if $update_api; then
echo "updating api to $(cat ../VERSION)"
fi
echo -e "Compiling $dir [$file]"
cd $dir
make clean
if make version API_BRANCH=$branch; then
if make $target; then
deterror="OK"
else
deterror="FAIL"
@ -25,7 +35,6 @@ 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,11 +25,10 @@ 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; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -15,6 +15,8 @@
#include "loadPattern.h"
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // usleep
#ifdef VIRTUAL
@ -92,6 +94,10 @@ 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;
@ -437,6 +443,32 @@ 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() {
@ -2258,11 +2290,23 @@ void *start_timer(void *arg) {
int packetsPerFrame = ceil((double)imageSize / (double)dataSize);
// Generate Data
char imageData[imageSize];
char *imageData = (char *)malloc(imageSize);
memset(imageData, 0, imageSize);
if (imageData == NULL) {
LOG(logERROR, ("Can not allocate image Data RAM."
"Probable cause: Memory Leak.\n"));
return NULL;
}
/*
for (int i = 0; i < imageSize; i += sizeof(uint16_t)) {
*((uint16_t *)(imageData + i)) = i;
}
*/
for (int i = 0; i < imageSize; i += 2 * sizeof(uint64_t)) {
*((uint64_t *)(imageData + i)) = 0xffffffffffffffff;
}
// Send data
uint64_t frameNr = 0;
@ -2319,6 +2363,8 @@ void *start_timer(void *arg) {
setNextFrameNumber(frameNr + numFrames);
}
free(imageData);
closeUDPSocket(0);
sharedMemory_setStatus(IDLE);

View File

@ -25,11 +25,10 @@ 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; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -24,11 +24,10 @@ 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; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -24,11 +24,10 @@ 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; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -24,11 +24,10 @@ 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; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -25,11 +25,10 @@ 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; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -304,7 +304,7 @@ patternParameters *setChannelRegisterChip(int ichip, char *mask,
chanReg |= (0x1 << (3 + icounter));
}
}
chanReg /= 2;
// deserialize
if (chanReg & CHAN_REG_BAD_CHANNEL_MSK) {
LOG(logINFOBLUE,

View File

@ -5,6 +5,23 @@
#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,6 +113,10 @@ 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,11 +36,10 @@ 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; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -1537,8 +1537,12 @@ void *start_timer(void *arg) {
packetSize, packetsPerFrame));
// Generate Data
char imageData[imageSize];
char *imageData = (char *)malloc(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;
}
@ -1561,6 +1565,7 @@ void *start_timer(void *arg) {
usleep(expUs);
int srcOffset = 0;
int dataSent = 0;
// loop packet
for (int i = 0; i != packetsPerFrame; ++i) {
@ -1577,10 +1582,12 @@ 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,
(imageSize < maxDataSize ? imageSize : maxDataSize));
srcOffset += maxDataSize;
imageData + srcOffset, dataSize);
srcOffset += dataSize;
dataSent += dataSize;
sendUDPPacket(0, 0, packetData, packetSize);
}

View File

@ -100,7 +100,6 @@ 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

@ -80,7 +80,7 @@ _sd() {
local IS_PATH=0
local SLS_COMMANDS=" acquire activate adcclk adcenable adcenable10g adcindex adcinvert adclist adcname adcphase adcpipeline adcreg adcvpp apulse asamples autocompdisable badchannels blockingtrigger burstmode burstperiod bursts burstsl bustest cdsgain chipversion clearbit clearbusy clientversion clkdiv clkfreq clkphase collectionmode column compdisabletime confadc config configtransceiver counters currentsource dac dacindex daclist dacname dacvalues datastream dbitclk dbitphase dbitpipeline defaultdac defaultpattern delay delayl detectorserverversion detsize diodelay dpulse dr drlist dsamples execcommand exptime exptime1 exptime2 exptime3 extrastoragecells extsampling extsamplingsrc extsig fformat filtercells filterresistor findex firmwaretest firmwareversion fliprows flowcontrol10g fmaster fname foverwrite fpath framecounter frames framesl frametime free fwrite gaincaps gainmode gappixels gatedelay gatedelay1 gatedelay2 gatedelay3 gates getbit hardwareversion highvoltage hostname im_a im_b im_c im_d im_io imagetest initialchecks inj_ch interpolation interruptsubframe kernelversion lastclient led lock master maxadcphaseshift maxclkphaseshift maxdbitphaseshift measuredperiod measuredsubperiod moduleid nextframenumber nmod numinterfaces overflow packageversion parallel parameters partialreset patfname patioctrl patlimits patloop patloop0 patloop1 patloop2 patmask patnloop patnloop0 patnloop1 patnloop2 patsetbit pattern patternstart patwait patwait0 patwait1 patwait2 patwaittime patwaittime0 patwaittime1 patwaittime2 patword pedestalmode period periodl polarity port powerchip powerindex powerlist powername powervalues programfpga pulse pulsechip pulsenmove pumpprobe quad ratecorr readnrows readout readoutspeed readoutspeedlist rebootcontroller reg resetdacs resetfpga romode row runclk runtime rx_arping rx_clearroi rx_dbitlist rx_dbitoffset rx_discardpolicy rx_fifodepth rx_frameindex rx_framescaught rx_framesperfile rx_hostname rx_jsonaddheader rx_jsonpara rx_lastclient rx_lock rx_missingpackets rx_padding rx_printconfig rx_realudpsocksize rx_roi rx_silent rx_start rx_status rx_stop rx_tcpport rx_threads rx_udpsocksize rx_version rx_zmqfreq rx_zmqhwm rx_zmqip rx_zmqport rx_zmqstartfnum rx_zmqstream samples savepattern scan scanerrmsg selinterface serialnumber setbit settings settingslist settingspath signalindex signallist signalname sleep slowadc slowadcindex slowadclist slowadcname slowadcvalues start status stop stopport storagecell_delay storagecell_start subdeadtime subexptime sync syncclk temp_10ge temp_adc temp_control temp_dcdc temp_event temp_fpga temp_fpgaext temp_fpgafl temp_fpgafr temp_slowadc temp_sodl temp_sodr temp_threshold templist tempvalues tengiga threshold thresholdnotb timing timing_info_decoder timinglist timingsource top transceiverenable trigger triggers triggersl trimbits trimen trimval tsamples txdelay txdelay_frame txdelay_left txdelay_right type udp_cleardst udp_dstip udp_dstip2 udp_dstlist udp_dstmac udp_dstmac2 udp_dstport udp_dstport2 udp_firstdst udp_numdst udp_reconfigure udp_srcip udp_srcip2 udp_srcmac udp_srcmac2 udp_validate update updatedetectorserver updatekernel updatemode user v_a v_b v_c v_chip v_d v_io v_limit vchip_comp_adc vchip_comp_fe vchip_cs vchip_opa_1st vchip_opa_fd vchip_ref_comp_fe versions veto vetoalg vetofile vetophoton vetoref vetostream virtual vm_a vm_b vm_c vm_d vm_io zmqhwm zmqip zmqport "
local SLS_COMMANDS=" acquire activate adcclk adcenable adcenable10g adcindex adcinvert adclist adcname adcphase adcpipeline adcreg adcvpp apulse asamples autocompdisable badchannels blockingtrigger burstmode burstperiod bursts burstsl bustest cdsgain chipversion clearbit clearbusy clientversion clkdiv clkfreq clkphase collectionmode column compdisabletime confadc config configtransceiver counters currentsource dac dacindex daclist dacname dacvalues datastream dbitclk dbitphase dbitpipeline defaultdac defaultpattern delay delayl detectorserverversion detsize diodelay dpulse dr drlist dsamples execcommand exptime exptime1 exptime2 exptime3 extrastoragecells extsampling extsamplingsrc extsig fformat filtercells filterresistor findex firmwaretest firmwareversion fliprows flowcontrol10g fmaster fname foverwrite fpath framecounter frames framesl frametime free fwrite gaincaps gainmode gappixels gatedelay gatedelay1 gatedelay2 gatedelay3 gates getbit hardwareversion highvoltage hostname im_a im_b im_c im_d im_io imagetest initialchecks inj_ch interpolation interruptsubframe kernelversion lastclient led lock master maxadcphaseshift maxclkphaseshift maxdbitphaseshift measuredperiod measuredsubperiod moduleid nextframenumber nmod numinterfaces overflow packageversion parallel parameters partialreset patfname patioctrl patlimits patloop patloop0 patloop1 patloop2 patmask patnloop patnloop0 patnloop1 patnloop2 patsetbit pattern patternstart patwait patwait0 patwait1 patwait2 patwaittime patwaittime0 patwaittime1 patwaittime2 patword pedestalmode period periodl polarity port powerchip powerindex powerlist powername powervalues programfpga pulse pulsechip pulsenmove pumpprobe quad ratecorr readnrows readout readoutspeed readoutspeedlist rebootcontroller reg resetdacs resetfpga romode row runclk runtime rx_arping rx_clearroi rx_dbitlist rx_dbitoffset rx_dbitreorder rx_discardpolicy rx_fifodepth rx_frameindex rx_framescaught rx_framesperfile rx_hostname rx_jsonaddheader rx_jsonpara rx_lastclient rx_lock rx_missingpackets rx_padding rx_printconfig rx_realudpsocksize rx_roi rx_silent rx_start rx_status rx_stop rx_tcpport rx_threads rx_udpsocksize rx_version rx_zmqfreq rx_zmqhwm rx_zmqip rx_zmqport rx_zmqstartfnum rx_zmqstream samples savepattern scan scanerrmsg selinterface serialnumber setbit settings settingslist settingspath signalindex signallist signalname sleep slowadc slowadcindex slowadclist slowadcname slowadcvalues start status stop stopport storagecell_delay storagecell_start subdeadtime subexptime sync syncclk temp_10ge temp_adc temp_control temp_dcdc temp_event temp_fpga temp_fpgaext temp_fpgafl temp_fpgafr temp_slowadc temp_sodl temp_sodr temp_threshold templist tempvalues tengiga threshold thresholdnotb timing timing_info_decoder timinglist timingsource top transceiverenable trigger triggers triggersl trimbits trimen trimval tsamples txdelay txdelay_frame txdelay_left txdelay_right type udp_cleardst udp_dstip udp_dstip2 udp_dstlist udp_dstmac udp_dstmac2 udp_dstport udp_dstport2 udp_firstdst udp_numdst udp_reconfigure udp_srcip udp_srcip2 udp_srcmac udp_srcmac2 udp_validate update updatedetectorserver updatekernel updatemode user v_a v_b v_c v_chip v_d v_io v_limit vchip_comp_adc vchip_comp_fe vchip_cs vchip_opa_1st vchip_opa_fd vchip_ref_comp_fe versions veto vetoalg vetofile vetophoton vetoref vetostream virtual vm_a vm_b vm_c vm_d vm_io zmqhwm zmqip zmqport "
__acquire() {
FCN_RETURN=""
return 0
@ -2088,6 +2088,15 @@ fi
fi
return 0
}
__rx_dbitreorder() {
FCN_RETURN=""
if [[ ${IS_GET} -eq 0 ]]; then
if [[ "${cword}" == "2" ]]; then
FCN_RETURN="0 1"
fi
fi
return 0
}
__rx_discardpolicy() {
FCN_RETURN=""
if [[ ${IS_GET} -eq 0 ]]; then

View File

@ -4,7 +4,7 @@
_sd() {
local SLS_COMMANDS=" acquire activate adcclk adcenable adcenable10g adcindex adcinvert adclist adcname adcphase adcpipeline adcreg adcvpp apulse asamples autocompdisable badchannels blockingtrigger burstmode burstperiod bursts burstsl bustest cdsgain chipversion clearbit clearbusy clientversion clkdiv clkfreq clkphase collectionmode column compdisabletime confadc config configtransceiver counters currentsource dac dacindex daclist dacname dacvalues datastream dbitclk dbitphase dbitpipeline defaultdac defaultpattern delay delayl detectorserverversion detsize diodelay dpulse dr drlist dsamples execcommand exptime exptime1 exptime2 exptime3 extrastoragecells extsampling extsamplingsrc extsig fformat filtercells filterresistor findex firmwaretest firmwareversion fliprows flowcontrol10g fmaster fname foverwrite fpath framecounter frames framesl frametime free fwrite gaincaps gainmode gappixels gatedelay gatedelay1 gatedelay2 gatedelay3 gates getbit hardwareversion highvoltage hostname im_a im_b im_c im_d im_io imagetest initialchecks inj_ch interpolation interruptsubframe kernelversion lastclient led lock master maxadcphaseshift maxclkphaseshift maxdbitphaseshift measuredperiod measuredsubperiod moduleid nextframenumber nmod numinterfaces overflow packageversion parallel parameters partialreset patfname patioctrl patlimits patloop patloop0 patloop1 patloop2 patmask patnloop patnloop0 patnloop1 patnloop2 patsetbit pattern patternstart patwait patwait0 patwait1 patwait2 patwaittime patwaittime0 patwaittime1 patwaittime2 patword pedestalmode period periodl polarity port powerchip powerindex powerlist powername powervalues programfpga pulse pulsechip pulsenmove pumpprobe quad ratecorr readnrows readout readoutspeed readoutspeedlist rebootcontroller reg resetdacs resetfpga romode row runclk runtime rx_arping rx_clearroi rx_dbitlist rx_dbitoffset rx_discardpolicy rx_fifodepth rx_frameindex rx_framescaught rx_framesperfile rx_hostname rx_jsonaddheader rx_jsonpara rx_lastclient rx_lock rx_missingpackets rx_padding rx_printconfig rx_realudpsocksize rx_roi rx_silent rx_start rx_status rx_stop rx_tcpport rx_threads rx_udpsocksize rx_version rx_zmqfreq rx_zmqhwm rx_zmqip rx_zmqport rx_zmqstartfnum rx_zmqstream samples savepattern scan scanerrmsg selinterface serialnumber setbit settings settingslist settingspath signalindex signallist signalname sleep slowadc slowadcindex slowadclist slowadcname slowadcvalues start status stop stopport storagecell_delay storagecell_start subdeadtime subexptime sync syncclk temp_10ge temp_adc temp_control temp_dcdc temp_event temp_fpga temp_fpgaext temp_fpgafl temp_fpgafr temp_slowadc temp_sodl temp_sodr temp_threshold templist tempvalues tengiga threshold thresholdnotb timing timing_info_decoder timinglist timingsource top transceiverenable trigger triggers triggersl trimbits trimen trimval tsamples txdelay txdelay_frame txdelay_left txdelay_right type udp_cleardst udp_dstip udp_dstip2 udp_dstlist udp_dstmac udp_dstmac2 udp_dstport udp_dstport2 udp_firstdst udp_numdst udp_reconfigure udp_srcip udp_srcip2 udp_srcmac udp_srcmac2 udp_validate update updatedetectorserver updatekernel updatemode user v_a v_b v_c v_chip v_d v_io v_limit vchip_comp_adc vchip_comp_fe vchip_cs vchip_opa_1st vchip_opa_fd vchip_ref_comp_fe versions veto vetoalg vetofile vetophoton vetoref vetostream virtual vm_a vm_b vm_c vm_d vm_io zmqhwm zmqip zmqport "
local SLS_COMMANDS=" acquire activate adcclk adcenable adcenable10g adcindex adcinvert adclist adcname adcphase adcpipeline adcreg adcvpp apulse asamples autocompdisable badchannels blockingtrigger burstmode burstperiod bursts burstsl bustest cdsgain chipversion clearbit clearbusy clientversion clkdiv clkfreq clkphase collectionmode column compdisabletime confadc config configtransceiver counters currentsource dac dacindex daclist dacname dacvalues datastream dbitclk dbitphase dbitpipeline defaultdac defaultpattern delay delayl detectorserverversion detsize diodelay dpulse dr drlist dsamples execcommand exptime exptime1 exptime2 exptime3 extrastoragecells extsampling extsamplingsrc extsig fformat filtercells filterresistor findex firmwaretest firmwareversion fliprows flowcontrol10g fmaster fname foverwrite fpath framecounter frames framesl frametime free fwrite gaincaps gainmode gappixels gatedelay gatedelay1 gatedelay2 gatedelay3 gates getbit hardwareversion highvoltage hostname im_a im_b im_c im_d im_io imagetest initialchecks inj_ch interpolation interruptsubframe kernelversion lastclient led lock master maxadcphaseshift maxclkphaseshift maxdbitphaseshift measuredperiod measuredsubperiod moduleid nextframenumber nmod numinterfaces overflow packageversion parallel parameters partialreset patfname patioctrl patlimits patloop patloop0 patloop1 patloop2 patmask patnloop patnloop0 patnloop1 patnloop2 patsetbit pattern patternstart patwait patwait0 patwait1 patwait2 patwaittime patwaittime0 patwaittime1 patwaittime2 patword pedestalmode period periodl polarity port powerchip powerindex powerlist powername powervalues programfpga pulse pulsechip pulsenmove pumpprobe quad ratecorr readnrows readout readoutspeed readoutspeedlist rebootcontroller reg resetdacs resetfpga romode row runclk runtime rx_arping rx_clearroi rx_dbitlist rx_dbitoffset rx_dbitreorder rx_discardpolicy rx_fifodepth rx_frameindex rx_framescaught rx_framesperfile rx_hostname rx_jsonaddheader rx_jsonpara rx_lastclient rx_lock rx_missingpackets rx_padding rx_printconfig rx_realudpsocksize rx_roi rx_silent rx_start rx_status rx_stop rx_tcpport rx_threads rx_udpsocksize rx_version rx_zmqfreq rx_zmqhwm rx_zmqip rx_zmqport rx_zmqstartfnum rx_zmqstream samples savepattern scan scanerrmsg selinterface serialnumber setbit settings settingslist settingspath signalindex signallist signalname sleep slowadc slowadcindex slowadclist slowadcname slowadcvalues start status stop stopport storagecell_delay storagecell_start subdeadtime subexptime sync syncclk temp_10ge temp_adc temp_control temp_dcdc temp_event temp_fpga temp_fpgaext temp_fpgafl temp_fpgafr temp_slowadc temp_sodl temp_sodr temp_threshold templist tempvalues tengiga threshold thresholdnotb timing timing_info_decoder timinglist timingsource top transceiverenable trigger triggers triggersl trimbits trimen trimval tsamples txdelay txdelay_frame txdelay_left txdelay_right type udp_cleardst udp_dstip udp_dstip2 udp_dstlist udp_dstmac udp_dstmac2 udp_dstport udp_dstport2 udp_firstdst udp_numdst udp_reconfigure udp_srcip udp_srcip2 udp_srcmac udp_srcmac2 udp_validate update updatedetectorserver updatekernel updatemode user v_a v_b v_c v_chip v_d v_io v_limit vchip_comp_adc vchip_comp_fe vchip_cs vchip_opa_1st vchip_opa_fd vchip_ref_comp_fe versions veto vetoalg vetofile vetophoton vetoref vetostream virtual vm_a vm_b vm_c vm_d vm_io zmqhwm zmqip zmqport "
__acquire() {
FCN_RETURN=""
return 0
@ -2012,6 +2012,15 @@ fi
fi
return 0
}
__rx_dbitreorder() {
FCN_RETURN=""
if [[ ${IS_GET} -eq 0 ]]; then
if [[ "${cword}" == "2" ]]; then
FCN_RETURN="0 1"
fi
fi
return 0
}
__rx_discardpolicy() {
FCN_RETURN=""
if [[ ${IS_GET} -eq 0 ]]; then

View File

@ -1412,6 +1412,18 @@ lock:
function: setDetectorLock
input_types: [ bool ]
rx_dbitreorder:
help: "[0, 1]\n\t[Ctb] Reorder digital data such that it groups each signal (0-63) from all the different samples together . Default is 1. Setting to 0 means 'do not reorder' and to keep what the board spits out, which is that all signals in a sample are grouped together."
inherit_actions: INTEGER_COMMAND_VEC_ID
actions:
GET:
function: getRxDbitReorder
PUT:
function: setRxDbitReorder
input_types: [ bool ]
################# INTEGER_COMMAND_VEC_ID_GET #################
master:

View File

@ -8305,6 +8305,48 @@ rx_dbitoffset:
help: "[n_bytes]\n\t[Ctb] Offset in bytes in digital data to skip in receiver."
infer_action: true
template: true
rx_dbitreorder:
actions:
GET:
args:
- arg_types: []
argc: 0
cast_input: []
check_det_id: false
convert_det_id: true
function: getRxDbitReorder
input: []
input_types: []
output:
- OutString(t)
require_det_id: true
store_result_in_t: true
PUT:
args:
- arg_types:
- bool
argc: 1
cast_input:
- true
check_det_id: false
convert_det_id: true
function: setRxDbitReorder
input:
- args[0]
input_types:
- bool
output:
- args.front()
require_det_id: true
store_result_in_t: false
command_name: rx_dbitreorder
function_alias: rx_dbitreorder
help: "[0, 1]\n\t[Ctb] Reorder digital data such that it groups each signal (0-63)\
\ from all the different samples together . Default is 1. Setting to 0 means 'do\
\ not reorder' and to keep what the board spits out, which is that all signals\
\ in a sample are grouped together."
infer_action: true
template: true
rx_discardpolicy:
actions:
GET:

View File

@ -1729,6 +1729,16 @@ class Detector {
/** [CTB] Set number of bytes of digital data to skip in the Receiver */
void setRxDbitOffset(int value, Positions pos = {});
/** [CTB] */
Result<bool> getRxDbitReorder(Positions pos = {}) const;
/** [CTB] Reorder digital data such that it groups each signal (0-63)
* from all the different samples together.
* Default is true. Setting to false means 'do not reorder' and to keep what
* the board spits out, which is that all signals in a sample are grouped
* together */
void setRxDbitReorder(bool reorder, Positions pos = {});
/**
* [CTB] Set Digital IO Delay
* cannot get

View File

@ -10700,6 +10700,68 @@ std::string Caller::rx_dbitoffset(int action) {
return os.str();
}
std::string Caller::rx_dbitreorder(int action) {
std::ostringstream os;
// print help
if (action == slsDetectorDefs::HELP_ACTION) {
os << R"V0G0N([0, 1]
[Ctb] Reorder digital data such that it groups each signal (0-63) from all the different samples together . Default is 1. Setting to 0 means 'do not reorder' and to keep what the board spits out, which is that all signals in a sample are grouped together. )V0G0N"
<< std::endl;
return os.str();
}
// check if action and arguments are valid
if (action == slsDetectorDefs::GET_ACTION) {
if (1 && args.size() != 0) {
throw RuntimeError("Wrong number of arguments for action GET");
}
if (args.size() == 0) {
}
}
else if (action == slsDetectorDefs::PUT_ACTION) {
if (1 && args.size() != 1) {
throw RuntimeError("Wrong number of arguments for action PUT");
}
if (args.size() == 1) {
try {
StringTo<bool>(args[0]);
} catch (...) {
throw RuntimeError("Could not convert argument 0 to bool");
}
}
}
else {
throw RuntimeError("INTERNAL ERROR: Invalid action: supported actions "
"are ['GET', 'PUT']");
}
// generate code for each action
if (action == slsDetectorDefs::GET_ACTION) {
if (args.size() == 0) {
auto t = det->getRxDbitReorder(std::vector<int>{det_id});
os << OutString(t) << '\n';
}
}
if (action == slsDetectorDefs::PUT_ACTION) {
if (args.size() == 1) {
auto arg0 = StringTo<bool>(args[0]);
det->setRxDbitReorder(arg0, std::vector<int>{det_id});
os << args.front() << '\n';
}
}
return os.str();
}
std::string Caller::rx_discardpolicy(int action) {
std::ostringstream os;

View File

@ -236,6 +236,7 @@ class Caller {
std::string rx_clearroi(int action);
std::string rx_dbitlist(int action);
std::string rx_dbitoffset(int action);
std::string rx_dbitreorder(int action);
std::string rx_discardpolicy(int action);
std::string rx_fifodepth(int action);
std::string rx_frameindex(int action);
@ -582,6 +583,7 @@ class Caller {
{"rx_clearroi", &Caller::rx_clearroi},
{"rx_dbitlist", &Caller::rx_dbitlist},
{"rx_dbitoffset", &Caller::rx_dbitoffset},
{"rx_dbitreorder", &Caller::rx_dbitreorder},
{"rx_discardpolicy", &Caller::rx_discardpolicy},
{"rx_fifodepth", &Caller::rx_fifodepth},
{"rx_frameindex", &Caller::rx_frameindex},

View File

@ -2277,6 +2277,14 @@ void Detector::setRxDbitOffset(int value, Positions pos) {
pimpl->Parallel(&Module::setReceiverDbitOffset, pos, value);
}
Result<bool> Detector::getRxDbitReorder(Positions pos) const {
return pimpl->Parallel(&Module::getReceiverDbitReorder, pos);
}
void Detector::setRxDbitReorder(bool reorder, Positions pos) {
pimpl->Parallel(&Module::setReceiverDbitReorder, pos, reorder);
}
void Detector::setDigitalIODelay(uint64_t pinMask, int delay, Positions pos) {
pimpl->Parallel(&Module::setDigitalIODelay, pos, pinMask, delay);
}

View File

@ -2509,6 +2509,15 @@ void Module::setReceiverDbitOffset(int value) {
sendToReceiver(F_SET_RECEIVER_DBIT_OFFSET, value, nullptr);
}
bool Module::getReceiverDbitReorder() const {
return sendToReceiver<int>(F_GET_RECEIVER_DBIT_REORDER);
}
void Module::setReceiverDbitReorder(bool reorder) {
sendToReceiver(F_SET_RECEIVER_DBIT_REORDER, static_cast<int>(reorder),
nullptr);
}
void Module::setDigitalIODelay(uint64_t pinMask, int delay) {
uint64_t args[]{pinMask, static_cast<uint64_t>(delay)};
sendToDetector(F_DIGITAL_IO_DELAY, args, nullptr);

View File

@ -510,6 +510,8 @@ class Module : public virtual slsDetectorDefs {
void setReceiverDbitList(std::vector<int> list);
int getReceiverDbitOffset() const;
void setReceiverDbitOffset(int value);
bool getReceiverDbitReorder() const;
void setReceiverDbitReorder(bool value);
void setDigitalIODelay(uint64_t pinMask, int delay);
bool getLEDEnable() const;
void setLEDEnable(bool enable);

View File

@ -2568,6 +2568,22 @@ int InferAction::rx_dbitoffset() {
}
}
int InferAction::rx_dbitreorder() {
if (args.size() == 0) {
return slsDetectorDefs::GET_ACTION;
}
if (args.size() == 1) {
return slsDetectorDefs::PUT_ACTION;
}
else {
throw RuntimeError("Could not infer action: Wrong number of arguments");
}
}
int InferAction::rx_discardpolicy() {
if (args.size() == 0) {

View File

@ -193,6 +193,7 @@ class InferAction {
int rx_clearroi();
int rx_dbitlist();
int rx_dbitoffset();
int rx_dbitreorder();
int rx_discardpolicy();
int rx_fifodepth();
int rx_frameindex();
@ -527,6 +528,7 @@ class InferAction {
{"rx_clearroi", &InferAction::rx_clearroi},
{"rx_dbitlist", &InferAction::rx_dbitlist},
{"rx_dbitoffset", &InferAction::rx_dbitoffset},
{"rx_dbitreorder", &InferAction::rx_dbitreorder},
{"rx_discardpolicy", &InferAction::rx_discardpolicy},
{"rx_fifodepth", &InferAction::rx_fifodepth},
{"rx_frameindex", &InferAction::rx_frameindex},

View File

@ -17,6 +17,119 @@ 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,6 +17,70 @@ 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,6 +4,7 @@
#include "Caller.h"
#include "catch.hpp"
#include "sls/Detector.h"
#include "sls/logger.h"
#include "tests/globals.h"
namespace sls {
@ -88,4 +89,227 @@ 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,9 +1,46 @@
// 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);
@ -13,4 +50,26 @@ 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,6 +17,69 @@ 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,6 +15,65 @@ 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,6 +15,66 @@ 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,6 +17,74 @@ 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

@ -445,23 +445,25 @@ TEST_CASE("rx_arping", "[.cmdcall][.rx]") {
Detector det;
Caller caller(&det);
auto prev_val = det.getRxArping();
{
std::ostringstream oss;
caller.call("rx_arping", {"1"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_arping 1\n");
}
{
std::ostringstream oss;
caller.call("rx_arping", {}, -1, GET, oss);
REQUIRE(oss.str() == "rx_arping 1\n");
}
{
std::ostringstream oss;
caller.call("rx_arping", {"0"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_arping 0\n");
}
for (int i = 0; i != det.size(); ++i) {
det.setRxArping(prev_val[i], {i});
if (det.getDestinationUDPIP()[0].str() != "127.0.0.1") {
{
std::ostringstream oss;
caller.call("rx_arping", {"1"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_arping 1\n");
}
{
std::ostringstream oss;
caller.call("rx_arping", {}, -1, GET, oss);
REQUIRE(oss.str() == "rx_arping 1\n");
}
{
std::ostringstream oss;
caller.call("rx_arping", {"0"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_arping 0\n");
}
for (int i = 0; i != det.size(); ++i) {
det.setRxArping(prev_val[i], {i});
}
}
}
@ -583,6 +585,9 @@ TEST_CASE("fpath", "[.cmdcall]") {
REQUIRE(oss.str() == "fpath /tmp\n");
}
for (int i = 0; i != det.size(); ++i) {
if (prev_val[i].empty()) {
continue;
}
det.setFilePath(prev_val[i], {i});
}
}
@ -956,6 +961,37 @@ TEST_CASE("rx_dbitoffset", "[.cmdcall][.rx]") {
}
}
TEST_CASE("rx_dbitreorder", "[.cmdcall][.rx]") {
Detector det;
Caller caller(&det);
auto det_type = det.getDetectorType().squash();
if (det_type == defs::CHIPTESTBOARD ||
det_type == defs::XILINX_CHIPTESTBOARD) {
auto prev_val = det.getRxDbitReorder();
{
std::ostringstream oss;
caller.call("rx_dbitreorder", {"0"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_dbitreorder 0\n");
}
{
std::ostringstream oss;
caller.call("rx_dbitreorder", {"1"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_dbitreorder 1\n");
}
{
std::ostringstream oss;
caller.call("rx_dbitreorder", {}, -1, GET, oss);
REQUIRE(oss.str() == "rx_dbitreorder 1\n");
}
REQUIRE_THROWS(caller.call("rx_dbitreorder", {"15"}, -1, PUT));
for (int i = 0; i != det.size(); ++i) {
det.setRxDbitReorder(prev_val[i], {i});
}
} else {
REQUIRE_THROWS(caller.call("rx_dbitreorder", {}, -1, GET));
}
}
TEST_CASE("rx_jsonaddheader", "[.cmdcall][.rx]") {
Detector det;
Caller caller(&det);

View File

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

View File

@ -18,11 +18,16 @@ struct Data {
constexpr int shm_id = 10;
TEST_CASE("Create SharedMemory read and write", "[detector]") {
const char *env_p = std::getenv("SLSDETNAME");
std::string env_name = env_p ? ("_" + std::string(env_p)) : "";
SharedMemory<Data> shm(shm_id, -1);
if (shm.exists()) {
shm.removeSharedMemory();
}
shm.createSharedMemory();
CHECK(shm.getName() == std::string("/slsDetectorPackage_detector_") +
std::to_string(shm_id));
std::to_string(shm_id) + env_name);
shm()->x = 3;
shm()->y = 5.7;
@ -90,10 +95,12 @@ TEST_CASE("Open two shared memories to the same place", "[detector]") {
}
TEST_CASE("Move SharedMemory", "[detector]") {
const char *env_p = std::getenv("SLSDETNAME");
std::string env_name = env_p ? ("_" + std::string(env_p)) : "";
SharedMemory<Data> shm(shm_id, -1);
CHECK(shm.getName() == std::string("/slsDetectorPackage_detector_") +
std::to_string(shm_id));
std::to_string(shm_id) + env_name);
shm.createSharedMemory();
shm()->x = 9;
@ -104,15 +111,19 @@ TEST_CASE("Move SharedMemory", "[detector]") {
REQUIRE_THROWS(
shm()); // trying to access should throw instead of returning a nullptr
CHECK(shm2.getName() == std::string("/slsDetectorPackage_detector_") +
std::to_string(shm_id));
std::to_string(shm_id) + env_name);
shm2.removeSharedMemory();
}
TEST_CASE("Create several shared memories", "[detector]") {
const char *env_p = std::getenv("SLSDETNAME");
std::string env_name = env_p ? ("_" + std::string(env_p)) : "";
constexpr int N = 5;
std::vector<SharedMemory<int>> v;
v.reserve(N);
for (int i = 0; i != N; ++i) {
std::cout << "i:" << i << std::endl;
v.emplace_back(shm_id + i, -1);
CHECK(v[i].exists() == false);
v[i].createSharedMemory();
@ -123,7 +134,7 @@ TEST_CASE("Create several shared memories", "[detector]") {
for (int i = 0; i != N; ++i) {
CHECK(*v[i]() == i);
CHECK(v[i].getName() == std::string("/slsDetectorPackage_detector_") +
std::to_string(i + shm_id));
std::to_string(i + shm_id) + env_name);
}
for (int i = 0; i != N; ++i) {
@ -133,8 +144,12 @@ TEST_CASE("Create several shared memories", "[detector]") {
}
TEST_CASE("Create create a shared memory with a tag") {
const char *env_p = std::getenv("SLSDETNAME");
std::string env_name = env_p ? ("_" + std::string(env_p)) : "";
SharedMemory<int> shm(0, -1, "ctbdacs");
REQUIRE(shm.getName() == "/slsDetectorPackage_detector_0_ctbdacs");
REQUIRE(shm.getName() ==
"/slsDetectorPackage_detector_0" + env_name + "_ctbdacs");
}
TEST_CASE("Create create a shared memory with a tag when SLSDETNAME is set") {

View File

@ -218,6 +218,8 @@ int ClientInterface::functionTable(){
flist[F_RECEIVER_SET_TRANSCEIVER_MASK] = &ClientInterface::set_transceiver_mask;
flist[F_RECEIVER_SET_ROW] = &ClientInterface::set_row;
flist[F_RECEIVER_SET_COLUMN] = &ClientInterface::set_column;
flist[F_GET_RECEIVER_DBIT_REORDER] = &ClientInterface::get_dbit_reorder;
flist[F_SET_RECEIVER_DBIT_REORDER] = &ClientInterface::set_dbit_reorder;
for (int i = NUM_DET_FUNCTIONS + 1; i < NUM_REC_FUNCTIONS ; i++) {
@ -1789,4 +1791,25 @@ int ClientInterface::set_column(Interface &socket) {
return socket.Send(OK);
}
int ClientInterface::get_dbit_reorder(Interface &socket) {
if (detType != CHIPTESTBOARD && detType != XILINX_CHIPTESTBOARD)
functionNotImplemented();
int retval = impl()->getDbitReorder();
LOG(logDEBUG1) << "Dbit reorder retval: " << retval;
return socket.sendResult(retval);
}
int ClientInterface::set_dbit_reorder(Interface &socket) {
auto arg = socket.Receive<int>();
if (detType != CHIPTESTBOARD && detType != XILINX_CHIPTESTBOARD)
functionNotImplemented();
if (arg < 0) {
throw RuntimeError("Invalid dbit reorder: " + std::to_string(arg));
}
verifyIdle(socket);
LOG(logDEBUG1) << "Setting Dbit reorder: " << arg;
impl()->setDbitReorder(arg);
return socket.Send(OK);
}
} // namespace sls

View File

@ -164,6 +164,8 @@ class ClientInterface : private virtual slsDetectorDefs {
int set_transceiver_mask(ServerInterface &socket);
int set_row(ServerInterface &socket);
int set_column(ServerInterface &socket);
int get_dbit_reorder(ServerInterface &socket);
int set_dbit_reorder(ServerInterface &socket);
Implementation *impl() {
if (receiver != nullptr) {

View File

@ -3,7 +3,7 @@
/************************************************
* @file DataProcessor.cpp
* @short creates data processor thread that
* pulls pointers to memory addresses from fifos
* pulls pointers to memory addresses from fifos
* and processes data stored in them & writes them to file
***********************************************/
@ -23,6 +23,7 @@
#include <cerrno>
#include <cstring>
#include <iostream>
#include <numeric>
namespace sls {
@ -71,12 +72,6 @@ void DataProcessor::SetStreamingStartFnum(uint32_t value) {
void DataProcessor::SetFramePadding(bool enable) { framePadding = enable; }
void DataProcessor::SetCtbDbitList(std::vector<int> value) {
ctbDbitList = value;
}
void DataProcessor::SetCtbDbitOffset(int value) { ctbDbitOffset = value; }
void DataProcessor::SetQuadEnable(bool value) { quadEnable = value; }
void DataProcessor::SetFlipRows(bool fd) {
@ -213,8 +208,9 @@ std::string DataProcessor::CreateVirtualFile(
"Skipping virtual hdf5 file since rx_roi is enabled.");
}
bool gotthard25um =
(generalData->detType == GOTTHARD2 && (numModX * numModY) == 2);
bool gotthard25um = ((generalData->detType == GOTTHARD ||
generalData->detType == GOTTHARD2) &&
(numModX * numModY) == 2);
// 0 for infinite files
uint32_t framesPerFile =
@ -299,7 +295,7 @@ void DataProcessor::ThreadExecution() {
memImage->data);
} catch (const std::exception &e) {
fifo->FreeAddress(buffer);
return;
throw RuntimeError(e.what());
}
// stream (if time/freq to stream) or free
@ -332,6 +328,7 @@ void DataProcessor::StopProcessing(char *buf) {
void DataProcessor::ProcessAnImage(sls_receiver_header &header, size_t &size,
size_t &firstImageIndex, char *data) {
uint64_t fnum = header.detHeader.frameNumber;
LOG(logDEBUG1) << "DataProcessing " << index << ": fnum:" << fnum;
currentFrameIndex = fnum;
@ -355,9 +352,20 @@ void DataProcessor::ProcessAnImage(sls_receiver_header &header, size_t &size,
if (framePadding && nump < generalData->packetsPerFrame)
PadMissingPackets(header, data);
// rearrange ctb digital bits (if ctbDbitlist is not empty)
if (!ctbDbitList.empty()) {
RearrangeDbitData(size, 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);
}
}
// 'stream Image' check has to be done here before crop image
@ -519,11 +527,53 @@ void DataProcessor::PadMissingPackets(sls_receiver_header header, char *data) {
}
}
void DataProcessor::RemoveTrailingBits(size_t &size, char *data) {
if (!(generalData->detType == slsDetectorDefs::CHIPTESTBOARD ||
generalData->detType == slsDetectorDefs::XILINX_CHIPTESTBOARD)) {
throw std::runtime_error("behavior undefined for detector " +
std::to_string(generalData->detType));
}
const size_t nAnalogDataBytes = generalData->GetNumberOfAnalogDatabytes();
const size_t nDigitalDataBytes = generalData->GetNumberOfDigitalDatabytes();
const size_t nTransceiverDataBytes =
generalData->GetNumberOfTransceiverDatabytes();
const size_t ctbDbitOffset = generalData->ctbDbitOffset;
const size_t ctbDigitalDataBytes = nDigitalDataBytes - ctbDbitOffset;
// no digital data
if (ctbDigitalDataBytes == 0) {
LOG(logWARNING)
<< "No digital data for call back, yet ctbDbitOffset is non zero.";
return;
}
// update size and copy data
memmove(data + nAnalogDataBytes, data + nAnalogDataBytes + ctbDbitOffset,
ctbDigitalDataBytes + nTransceiverDataBytes);
size = nAnalogDataBytes + ctbDigitalDataBytes + nTransceiverDataBytes;
}
/** ctb specific */
void DataProcessor::RearrangeDbitData(size_t &size, char *data) {
int nAnalogDataBytes = generalData->GetNumberOfAnalogDatabytes();
int nDigitalDataBytes = generalData->GetNumberOfDigitalDatabytes();
int nTransceiverDataBytes = generalData->GetNumberOfTransceiverDatabytes();
void DataProcessor::ArrangeDbitData(size_t &size, char *data) {
if (!(generalData->detType == slsDetectorDefs::CHIPTESTBOARD ||
generalData->detType == slsDetectorDefs::XILINX_CHIPTESTBOARD)) {
throw std::runtime_error("behavior undefined for detector " +
std::to_string(generalData->detType));
}
const size_t nAnalogDataBytes = generalData->GetNumberOfAnalogDatabytes();
const size_t nDigitalDataBytes = generalData->GetNumberOfDigitalDatabytes();
const size_t nTransceiverDataBytes =
generalData->GetNumberOfTransceiverDatabytes();
const size_t ctbDbitOffset = generalData->ctbDbitOffset;
const bool ctbDbitReorder = generalData->ctbDbitReorder;
const auto ctbDbitList = generalData->ctbDbitList;
// TODO! (Erik) Refactor and add tests
int ctbDigitalDataBytes = nDigitalDataBytes - ctbDbitOffset;
@ -534,52 +584,106 @@ void DataProcessor::RearrangeDbitData(size_t &size, char *data) {
return;
}
char *source = (data + nAnalogDataBytes + ctbDbitOffset);
const int numDigitalSamples = (ctbDigitalDataBytes / sizeof(uint64_t));
// const int numResult8Bits = ceil((numDigitalSamples * ctbDbitList.size())
// / 8.00);
int numBitsPerDbit = numDigitalSamples;
if ((numBitsPerDbit % 8) != 0)
numBitsPerDbit += (8 - (numDigitalSamples % 8));
const int totalNumBytes = (numBitsPerDbit / 8) * ctbDbitList.size();
std::vector<uint8_t> result(totalNumBytes);
int totalNumBytes =
0; // number of bytes for selected digital data given by dtbDbitList
// store each selected bit from all samples consecutively
if (ctbDbitReorder) {
size_t numBitsPerDbit =
numDigitalSamples; // num bits per selected digital
// Bit for all samples
if ((numBitsPerDbit % 8) != 0)
numBitsPerDbit += (8 - (numDigitalSamples % 8));
totalNumBytes = (numBitsPerDbit / 8) * ctbDbitList.size();
}
// store all selected bits from one sample consecutively
else {
size_t numBitsPerSample =
ctbDbitList.size(); // num bits for all selected bits per sample
if ((numBitsPerSample % 8) != 0)
numBitsPerSample += (8 - (numBitsPerSample % 8));
totalNumBytes = (numBitsPerSample / 8) * numDigitalSamples;
}
std::vector<uint8_t> result(totalNumBytes, 0);
uint8_t *dest = &result[0];
auto *source = (uint64_t *)(data + nAnalogDataBytes + ctbDbitOffset);
// loop through digital bit enable vector
int bitoffset = 0;
for (auto bi : ctbDbitList) {
// where numbits * numDigitalSamples is not a multiple of 8
if (bitoffset != 0) {
bitoffset = 0;
++dest;
}
// loop through the frame digital data
for (auto *ptr = source; ptr < (source + numDigitalSamples);) {
// get selected bit from each 8 bit
uint8_t bit = (*ptr++ >> bi) & 1;
*dest |= bit << bitoffset;
++bitoffset;
// extract destination in 8 bit batches
if (bitoffset == 8) {
if (ctbDbitReorder) {
// loop through digital bit enable vector
int bitoffset = 0;
for (auto bi : ctbDbitList) {
// where numbits * numDigitalSamples is not a multiple of 8
if (bitoffset != 0) {
bitoffset = 0;
++dest;
}
uint8_t byte_index = bi / 8;
// loop through the frame digital data
for (auto *ptr = source + byte_index;
ptr < (source + 8 * numDigitalSamples); ptr += 8) {
// get selected bit from each 8 bit
uint8_t bit = (*ptr >> bi % 8) & 1;
*dest |= bit << bitoffset; // stored as least significant
++bitoffset;
// extract destination in 8 bit batches
if (bitoffset == 8) {
bitoffset = 0;
++dest;
}
}
}
} else {
// loop through the digital data
int bitoffset = 0;
for (auto *ptr = source; ptr < (source + 8 * numDigitalSamples);
ptr += 8) {
// where bit enable vector size is not a multiple of 8
if (bitoffset != 0) {
bitoffset = 0;
++dest;
}
// loop through digital bit enable vector
for (auto bi : ctbDbitList) {
// get selected bit from each 64 bit
uint8_t byte_index = bi / 8;
uint8_t bit = (*(ptr + byte_index) >> (bi % 8)) & 1;
*dest |= bit << bitoffset;
++bitoffset;
// extract destination in 8 bit batches
if (bitoffset == 8) {
bitoffset = 0;
++dest;
}
}
}
}
size = totalNumBytes * sizeof(uint8_t) + nAnalogDataBytes +
nTransceiverDataBytes;
// check if size changed, if so move transceiver data to avoid gap in memory
if (size != nAnalogDataBytes + nDigitalDataBytes + nTransceiverDataBytes)
memmove(data + nAnalogDataBytes + totalNumBytes * sizeof(uint8_t),
data + nAnalogDataBytes + nDigitalDataBytes,
nTransceiverDataBytes);
// copy back to memory and update size
memcpy(data + nAnalogDataBytes, result.data(),
totalNumBytes * sizeof(uint8_t));
size = totalNumBytes * sizeof(uint8_t) + nAnalogDataBytes + ctbDbitOffset +
nTransceiverDataBytes;
LOG(logDEBUG1) << "totalNumBytes: " << totalNumBytes
LOG(logDEBUG1) << "nDigitalDataBytes: " << totalNumBytes
<< " nAnalogDataBytes:" << nAnalogDataBytes
<< " ctbDbitOffset:" << ctbDbitOffset
<< " nTransceiverDataBytes:" << nTransceiverDataBytes
<< " size:" << size;
<< " toal size:" << size;
}
void DataProcessor::CropImage(size_t &size, char *data) {

View File

@ -45,8 +45,6 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
void SetStreamingTimerInMs(uint32_t value);
void SetStreamingStartFnum(uint32_t value);
void SetFramePadding(bool enable);
void SetCtbDbitList(std::vector<int> value);
void SetCtbDbitOffset(int value);
void SetQuadEnable(bool value);
void SetFlipRows(bool fd);
void SetNumberofTotalFrames(uint64_t value);
@ -91,6 +89,20 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
size_t &, void *),
void *arg);
protected:
/**
* Align corresponding digital bits together (CTB only if ctbDbitlist is not
* empty)
* set variable reorder to true if data should be rearranged such that
* it groups each signal (0-63) from all the different samples together
*/
void ArrangeDbitData(size_t &size, char *data);
/**
* remove trailing bits in digital data stream
*/
void RemoveTrailingBits(size_t &size, char *data);
private:
void RecordFirstIndex(uint64_t fnum);
@ -137,12 +149,6 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
void PadMissingPackets(sls_receiver_header header, char *data);
/**
* Align corresponding digital bits together (CTB only if ctbDbitlist is not
* empty)
*/
void RearrangeDbitData(size_t &size, char *data);
void CropImage(size_t &size, char *data);
static const std::string typeName;
@ -164,8 +170,6 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
uint32_t currentFreqCount{0};
struct timespec timerbegin {};
bool framePadding;
std::vector<int> ctbDbitList;
int ctbDbitOffset;
std::atomic<bool> startedFlag{false};
std::atomic<uint64_t> firstIndex{0};
bool quadEnable{false};

View File

@ -93,11 +93,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) {
uint16_t udpPort = it.first;
const uint16_t udpPort = it.first;
const auto &frame_map = it.second;
LOG(sls::logDEBUG) << "UDP port: " << udpPort;
for (const auto &frame : frame_map) {
uint64_t fnum = frame.first;
const uint64_t fnum = frame.first;
const auto &msg_list = frame.second;
LOG(sls::logDEBUG)
<< " acq index: " << fnum << '[' << msg_list.size() << ']';
@ -116,30 +116,26 @@ 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 (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);
for (const auto &it : port_frame_map) {
const FrameMap &frame_map = it.second;
for (const auto &frame : frame_map) {
unique_fnums.insert(frame.first);
}
}
// collect valid frame numbers
for (auto &fnum : unique_fnums) {
bool is_valid = true;
for (auto it = port_frame_map.begin(); it != port_frame_map.end();
++it) {
uint16_t port = it->first;
const FrameMap &frame_map = it->second;
for (const auto &it : port_frame_map) {
const 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;
// 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) {
auto upper_frame = frame_map.upper_bound(fnum);
if (upper_frame == frame_map.end()) {
LOG(sls::logDEBUG) << "And no larger fnum found. Fnum "
<< fnum << " is invalid.\n";
is_valid = false;
@ -209,18 +205,26 @@ void Correlate(FrameStatus *stat) {
// sending all valid fnum data packets
for (const auto &fnum : valid_fnums) {
ZmqMsgList msg_list;
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;
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()) {
msg_list.insert(msg_list.end(),
stat->frames[port][fnum].begin(),
stat->frames[port][fnum].end());
// clean up
for (zmq_msg_t *msg : stat->frames[port][fnum]) {
}
}
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) {
if (msg) {
zmq_msg_close(msg);
delete msg;
@ -229,9 +233,6 @@ 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
@ -245,6 +246,21 @@ 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

@ -52,6 +52,9 @@ class GeneralData {
uint32_t nAnalogSamples{0};
uint32_t nDigitalSamples{0};
uint32_t nTransceiverSamples{0};
std::vector<int> ctbDbitList{};
int ctbDbitOffset{0};
bool ctbDbitReorder{false};
slsDetectorDefs::readoutMode readoutType{slsDetectorDefs::ANALOG_ONLY};
uint32_t adcEnableMaskOneGiga{BIT32_MASK};
uint32_t adcEnableMaskTenGiga{BIT32_MASK};
@ -148,6 +151,18 @@ class GeneralData {
virtual void SetTransceiverEnableMask(int n) {
ThrowGenericError("SetTransceiverEnableMask");
};
virtual void SetctbDbitOffset(const int n) {
ThrowGenericError("SetctbDbitOffset");
};
virtual void SetctbDbitList(const std::vector<int> &value) {
ThrowGenericError("SetctbDbitList");
};
virtual void SetctbDbitReorder(const bool reorder) {
ThrowGenericError("SetctbDbitReorder");
};
};
class EigerData : public GeneralData {
@ -387,6 +402,7 @@ class ChipTestBoardData : public GeneralData {
framesPerFile = CTB_MAX_FRAMES_PER_FILE;
fifoDepth = 2500;
standardheader = true;
ctbDbitReorder = true;
UpdateImageSize();
};
@ -412,6 +428,12 @@ class ChipTestBoardData : public GeneralData {
UpdateImageSize();
};
void SetctbDbitOffset(const int value) { ctbDbitOffset = value; }
void SetctbDbitList(const std::vector<int> &value) { ctbDbitList = value; }
void SetctbDbitReorder(const bool value) { ctbDbitReorder = value; }
void SetOneGigaAdcEnableMask(int n) {
adcEnableMaskOneGiga = n;
UpdateImageSize();
@ -443,6 +465,7 @@ class ChipTestBoardData : public GeneralData {
nDigitalBytes = 0;
nTransceiverBytes = 0;
int nAnalogChans = 0, nDigitalChans = 0, nTransceiverChans = 0;
uint64_t digital_bytes_reserved = 0;
// analog channels (normal, analog/digital readout)
if (readoutType == slsDetectorDefs::ANALOG_ONLY ||
@ -461,7 +484,12 @@ class ChipTestBoardData : public GeneralData {
readoutType == slsDetectorDefs::ANALOG_AND_DIGITAL ||
readoutType == slsDetectorDefs::DIGITAL_AND_TRANSCEIVER) {
nDigitalChans = NCHAN_DIGITAL;
nDigitalBytes = (sizeof(uint64_t) * nDigitalSamples);
// allocate enough memory to support reordering of digital bits
uint32_t num_bytes_per_bit = (nDigitalSamples % 8 == 0)
? nDigitalSamples / 8
: nDigitalSamples / 8 + 1;
digital_bytes_reserved = 64 * num_bytes_per_bit;
nDigitalBytes = sizeof(uint64_t) * nDigitalSamples;
LOG(logDEBUG1) << "Number of Digital Channels:" << nDigitalChans
<< " Databytes: " << nDigitalBytes;
}
@ -480,7 +508,7 @@ class ChipTestBoardData : public GeneralData {
nPixelsX = nAnalogChans + nDigitalChans + nTransceiverChans;
dataSize = tengigaEnable ? 8144 : UDP_PACKET_DATA_BYTES;
packetSize = headerSizeinPacket + dataSize;
imageSize = nAnalogBytes + nDigitalBytes + nTransceiverBytes;
imageSize = nAnalogBytes + digital_bytes_reserved + nTransceiverBytes;
packetsPerFrame = ceil((double)imageSize / (double)dataSize);
LOG(logDEBUG1) << "Total Number of Channels:" << nPixelsX
@ -512,6 +540,7 @@ class XilinxChipTestBoardData : public GeneralData {
dataSize = 8144;
packetSize = headerSizeinPacket + dataSize;
tengigaEnable = true;
ctbDbitReorder = true;
UpdateImageSize();
};
@ -537,6 +566,12 @@ class XilinxChipTestBoardData : public GeneralData {
UpdateImageSize();
};
void SetctbDbitOffset(const int value) { ctbDbitOffset = value; }
void SetctbDbitList(const std::vector<int> &value) { ctbDbitList = value; }
void SetctbDbitReorder(const bool value) { ctbDbitReorder = value; }
void SetOneGigaAdcEnableMask(int n) {
adcEnableMaskOneGiga = n;
UpdateImageSize();
@ -563,6 +598,7 @@ class XilinxChipTestBoardData : public GeneralData {
nDigitalBytes = 0;
nTransceiverBytes = 0;
int nAnalogChans = 0, nDigitalChans = 0, nTransceiverChans = 0;
uint64_t digital_bytes_reserved = 0;
// analog channels (normal, analog/digital readout)
if (readoutType == slsDetectorDefs::ANALOG_ONLY ||
@ -580,7 +616,11 @@ class XilinxChipTestBoardData : public GeneralData {
readoutType == slsDetectorDefs::ANALOG_AND_DIGITAL ||
readoutType == slsDetectorDefs::DIGITAL_AND_TRANSCEIVER) {
nDigitalChans = NCHAN_DIGITAL;
nDigitalBytes = (sizeof(uint64_t) * nDigitalSamples);
uint32_t num_bytes_per_bit = (nDigitalSamples % 8 == 0)
? nDigitalSamples / 8
: nDigitalSamples / 8 + 1;
digital_bytes_reserved = 64 * num_bytes_per_bit;
nDigitalBytes = sizeof(uint64_t) * nDigitalSamples;
LOG(logDEBUG1) << "Number of Digital Channels:" << nDigitalChans
<< " Databytes: " << nDigitalBytes;
}
@ -598,7 +638,7 @@ class XilinxChipTestBoardData : public GeneralData {
}
nPixelsX = nAnalogChans + nDigitalChans + nTransceiverChans;
imageSize = nAnalogBytes + nDigitalBytes + nTransceiverBytes;
imageSize = nAnalogBytes + digital_bytes_reserved + nTransceiverBytes;
packetsPerFrame = ceil((double)imageSize / (double)dataSize);
LOG(logDEBUG1) << "Total Number of Channels:" << nPixelsX

View File

@ -200,8 +200,6 @@ void Implementation::SetupDataProcessor(int i) {
dataProcessor[i]->SetStreamingTimerInMs(streamingTimerInMs);
dataProcessor[i]->SetStreamingStartFnum(streamingStartFnum);
dataProcessor[i]->SetFramePadding(framePadding);
dataProcessor[i]->SetCtbDbitList(ctbDbitList);
dataProcessor[i]->SetCtbDbitOffset(ctbDbitOffset);
dataProcessor[i]->SetQuadEnable(quadEnable);
dataProcessor[i]->SetFlipRows(flipRows);
dataProcessor[i]->SetNumberofTotalFrames(numberOfTotalFrames);
@ -990,9 +988,11 @@ void Implementation::StartMasterWriter() {
? 1
: 0;
masterAttributes.digitalSamples = generalData->nDigitalSamples;
masterAttributes.dbitoffset = ctbDbitOffset;
masterAttributes.dbitoffset = generalData->ctbDbitOffset;
masterAttributes.dbitreorder = generalData->ctbDbitReorder;
masterAttributes.dbitlist = 0;
for (auto &i : ctbDbitList) {
for (auto &i : generalData->ctbDbitList) {
masterAttributes.dbitlist |= (static_cast<uint64_t>(1) << i);
}
masterAttributes.transceiverSamples =
@ -1748,22 +1748,29 @@ void Implementation::setTenGigaADCEnableMask(uint32_t mask) {
LOG(logINFO) << "Packets per Frame: " << (generalData->packetsPerFrame);
}
std::vector<int> Implementation::getDbitList() const { return ctbDbitList; }
void Implementation::setDbitList(const std::vector<int> &v) {
ctbDbitList = v;
for (const auto &it : dataProcessor)
it->SetCtbDbitList(ctbDbitList);
LOG(logINFO) << "Dbit list: " << ToString(ctbDbitList);
std::vector<int> Implementation::getDbitList() const {
return generalData->ctbDbitList;
}
int Implementation::getDbitOffset() const { return ctbDbitOffset; }
void Implementation::setDbitList(const std::vector<int> &v) {
generalData->SetctbDbitList(v);
LOG(logINFO) << "Dbit list: " << ToString(v);
}
int Implementation::getDbitOffset() const { return generalData->ctbDbitOffset; }
void Implementation::setDbitOffset(const int s) {
ctbDbitOffset = s;
for (const auto &it : dataProcessor)
it->SetCtbDbitOffset(ctbDbitOffset);
LOG(logINFO) << "Dbit offset: " << ctbDbitOffset;
generalData->SetctbDbitOffset(s);
LOG(logINFO) << "Dbit offset: " << s;
}
bool Implementation::getDbitReorder() const {
return generalData->ctbDbitReorder;
}
void Implementation::setDbitReorder(const bool reorder) {
generalData->SetctbDbitReorder(reorder);
LOG(logINFO) << "Dbit reorder: " << reorder;
}
uint32_t Implementation::getTransceiverEnableMask() const {

View File

@ -252,6 +252,10 @@ class Implementation : private virtual slsDetectorDefs {
int getDbitOffset() const;
/* [Ctb] */
void setDbitOffset(const int s);
bool getDbitReorder() const;
/* [Ctb] */
void setDbitReorder(const bool reorder);
uint32_t getTransceiverEnableMask() const;
/* [Ctb] */
void setTransceiverEnableMask(const uint32_t mask);
@ -366,8 +370,6 @@ class Implementation : private virtual slsDetectorDefs {
int thresholdEnergyeV{-1};
std::array<int, 3> thresholdAllEnergyeV = {{-1, -1, -1}};
std::vector<int64_t> rateCorrections;
std::vector<int> ctbDbitList;
int ctbDbitOffset{0};
// callbacks
void (*startAcquisitionCallBack)(const startCallbackHeader,

View File

@ -551,6 +551,13 @@ void MasterAttributes::WriteHDF5DbitOffset(H5::H5File *fd, H5::Group *group) {
dataset.write(&dbitoffset, H5::PredType::NATIVE_INT);
}
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::H5File *fd, H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet(
@ -744,6 +751,8 @@ void MasterAttributes::GetCtbBinaryAttributes(
w->Uint(digitalSamples);
w->Key("Dbit Offset");
w->Uint(dbitoffset);
w->Key("Dbit Reorder");
w->Uint(dbitreorder);
w->Key("Dbit Bitset");
w->Uint64(dbitlist);
w->Key("Transceiver Mask");
@ -766,6 +775,7 @@ void MasterAttributes::WriteCtbHDF5Attributes(H5::H5File *fd,
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);
@ -791,6 +801,8 @@ void MasterAttributes::GetXilinxCtbBinaryAttributes(
w->Uint(digitalSamples);
w->Key("Dbit Offset");
w->Uint(dbitoffset);
w->Key("Dbit Reorder");
w->Uint(dbitreorder);
w->Key("Dbit Bitset");
w->Uint64(dbitlist);
w->Key("Transceiver Mask");
@ -812,6 +824,7 @@ void MasterAttributes::WriteXilinxCtbHDF5Attributes(H5::H5File *fd,
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);

View File

@ -51,6 +51,7 @@ class MasterAttributes {
uint32_t analogSamples{0};
uint32_t digital{0};
uint32_t digitalSamples{0};
uint32_t dbitreorder{1};
uint32_t dbitoffset{0};
uint64_t dbitlist{0};
uint32_t transceiverMask{0};
@ -104,6 +105,7 @@ class MasterAttributes {
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);

View File

@ -19,8 +19,8 @@ namespace sls {
// files
// versions
#define HDF5_WRITER_VERSION (6.6) // 1 decimal places
#define BINARY_WRITER_VERSION (7.2) // 1 decimal places
#define HDF5_WRITER_VERSION (6.7) // 1 decimal places
#define BINARY_WRITER_VERSION (7.3) // 1 decimal places
#define MAX_FRAMES_PER_FILE 20000
#define SHORT_MAX_FRAMES_PER_FILE 100000

View File

@ -3,6 +3,9 @@
target_sources(tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/test-GeneralData.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-CircularFifo.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-ArrangeDataBasedOnBitList.cpp
)
target_include_directories(tests PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../src>")
message(STATUS "Resolved path: ${CMAKE_CURRENT_SOURCE_DIR}/../src")

View File

@ -0,0 +1,411 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2025 Contributors to the SLS Detector Package
/************************************************
* @file test-ArrangeDataBasedOnBitList.cpp
* @short test case for DataProcessor rearrange functions,
***********************************************/
#include "DataProcessor.h"
#include "GeneralData.h"
#include "catch.hpp"
#include <vector>
namespace sls {
// dummy GeneralData class for testing
class GeneralDataTest : public GeneralData {
public:
GeneralDataTest() { detType = slsDetectorDefs::CHIPTESTBOARD; }
int GetNumberOfAnalogDatabytes() { return nAnalogBytes; };
int GetNumberOfDigitalDatabytes() { return nDigitalBytes; };
int GetNumberOfTransceiverDatabytes() { return nTransceiverBytes; };
void SetNumberOfAnalogDatabytes(int value) { nAnalogBytes = value; }
void SetNumberOfDigitalDatabytes(int value) { nDigitalBytes = value; }
void SetNumberOfTransceiverDatabytes(int value) {
nTransceiverBytes = value;
}
void SetCtbDbitOffset(const int value) { ctbDbitOffset = value; }
void SetCtbDbitList(const std::vector<int> &value) { ctbDbitList = value; }
void SetCtbDbitReorder(const bool value) { ctbDbitReorder = value; }
private:
int nAnalogBytes{};
int nDigitalBytes{};
int nTransceiverBytes{};
};
// dummy DataProcessor class for testing
class DataProcessorTest : public DataProcessor {
public:
DataProcessorTest() : DataProcessor(0){};
~DataProcessorTest(){};
void ArrangeDbitData(size_t &size, char *data) {
DataProcessor::ArrangeDbitData(size, data);
}
void RemoveTrailingBits(size_t &size, char *data) {
DataProcessor::RemoveTrailingBits(size, data);
}
};
/**
* test fixture for Testing,
* num_analog_bytes = 1 byte has a value of 125
* num_transceiver_bytes = 2 both bytes have a value of 125
* num_digital_bytes is variable and is defined by number of samples
* default num sample is 5
* all bytes in digital data take a value of 255
*/
class DataProcessorTestFixture {
public:
DataProcessorTestFixture() {
// setup Test Fixture
dataprocessor = new DataProcessorTest;
generaldata = new GeneralDataTest;
generaldata->SetNumberOfAnalogDatabytes(num_analog_bytes);
generaldata->SetNumberOfTransceiverDatabytes(num_transceiver_bytes);
generaldata->SetNumberOfDigitalDatabytes(num_digital_bytes +
num_random_offset_bytes);
dataprocessor->SetGeneralData(generaldata);
}
~DataProcessorTestFixture() {
delete[] data;
delete dataprocessor;
delete generaldata;
}
size_t get_size() const {
return num_analog_bytes + num_digital_bytes + num_transceiver_bytes +
num_random_offset_bytes;
}
void set_num_samples(const size_t value) {
num_samples = value;
num_digital_bytes = num_samples * 8; // 64 (8 bytes) per sample
generaldata->SetNumberOfDigitalDatabytes(num_digital_bytes +
num_random_offset_bytes);
}
void set_random_offset_bytes(const size_t value) {
num_random_offset_bytes = value;
generaldata->SetNumberOfDigitalDatabytes(num_digital_bytes +
num_random_offset_bytes);
}
void set_data() {
delete[] data;
uint64_t max_bytes_per_bit =
num_samples % 8 == 0 ? num_samples / 8 : num_samples / 8 + 1;
uint64_t reserved_size =
get_size() - num_digital_bytes + max_bytes_per_bit * 64;
data = new char[reserved_size];
// set testing data
memset(data, dummy_value, num_analog_bytes); // set to dummy value
memset(data + num_analog_bytes, 0,
num_random_offset_bytes); // set to zero
memset(data + num_analog_bytes + num_random_offset_bytes, 0xFF,
num_digital_bytes); // all digital bits are one
memset(data + num_digital_bytes + num_analog_bytes +
num_random_offset_bytes,
dummy_value,
num_transceiver_bytes); // set to dummy value
}
DataProcessorTest *dataprocessor;
GeneralDataTest *generaldata;
const size_t num_analog_bytes = 1;
const size_t num_transceiver_bytes = 2;
const char dummy_value = static_cast<char>(125);
size_t num_digital_bytes = 40; // num_samples * 8 = 5 * 8 = 40
size_t num_random_offset_bytes = 0;
size_t num_samples = 5;
char *data = nullptr;
};
TEST_CASE_METHOD(DataProcessorTestFixture, "Remove Trailing Bits",
"[.dataprocessor][.bitoffset]") {
const size_t num_random_offset_bytes = 3;
set_random_offset_bytes(num_random_offset_bytes);
set_data();
generaldata->SetCtbDbitOffset(num_random_offset_bytes);
size_t expected_size = get_size() - num_random_offset_bytes;
char *expected_data = new char[expected_size];
memset(expected_data, dummy_value, num_analog_bytes); // set to 125
memset(expected_data + num_analog_bytes, 0xFF,
num_digital_bytes); // set to 1
memset(expected_data + num_digital_bytes + num_analog_bytes, dummy_value,
num_transceiver_bytes); // set to 125
size_t size = get_size();
dataprocessor->RemoveTrailingBits(size, data);
CHECK(size == expected_size);
CHECK(memcmp(data, expected_data, expected_size) == 0);
delete[] expected_data;
}
// parametric test tested with num_samples = 5, num_samples = 10, num_samples =
// 8
TEST_CASE_METHOD(DataProcessorTestFixture, "Reorder all",
"[.dataprocessor][.reorder]") {
// parameters: num_samples, expected_num_digital_bytes,
// expected_digital_part
auto parameters = GENERATE(
std::make_tuple(5, 64, std::vector<uint8_t>{0b00011111}),
std::make_tuple(10, 2 * 64, std::vector<uint8_t>{0xFF, 0b00000011}),
std::make_tuple(8, 64, std::vector<uint8_t>{0xFF}));
size_t num_samples, expected_num_digital_bytes;
std::vector<uint8_t> expected_digital_part;
std::tie(num_samples, expected_num_digital_bytes, expected_digital_part) =
parameters;
// set number of samples for test fixture -> create data
set_num_samples(num_samples);
set_data();
std::vector<int> bitlist(64);
std::iota(bitlist.begin(), bitlist.end(), 0);
generaldata->SetCtbDbitList(bitlist);
generaldata->SetCtbDbitReorder(true); // set reorder to true
const size_t expected_size =
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
// create expected data
char *expected_data = new char[expected_size];
memset(expected_data, dummy_value, num_analog_bytes); // set to 125
for (size_t bit = 0; bit < 64; ++bit) {
memcpy(expected_data + num_analog_bytes +
expected_digital_part.size() * bit,
expected_digital_part.data(), expected_digital_part.size());
}
memset(expected_data + expected_num_digital_bytes + num_analog_bytes,
dummy_value,
num_transceiver_bytes); // set to 125
size_t size = get_size();
dataprocessor->ArrangeDbitData(size, data); // call reorder
CHECK(size == expected_size);
CHECK(memcmp(data, expected_data, expected_size) == 0);
delete[] expected_data;
}
TEST_CASE_METHOD(DataProcessorTestFixture,
"Reorder all and remove trailing bits",
"[.dataprocessor][.reorder]") {
// set number of samples for test fixture -> create data
const size_t num_random_offset_bytes = 3;
set_random_offset_bytes(num_random_offset_bytes);
set_data();
std::vector<int> bitlist(64);
std::iota(bitlist.begin(), bitlist.end(), 0);
generaldata->SetCtbDbitList(bitlist);
generaldata->SetCtbDbitOffset(num_random_offset_bytes);
generaldata->SetCtbDbitReorder(true); // set reorder to true
const size_t expected_num_digital_bytes = 64;
std::vector<uint8_t> expected_digital_part{0b00011111};
const size_t expected_size =
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
// create expected data
char *expected_data = new char[expected_size];
memset(expected_data, dummy_value, num_analog_bytes); // set to 125
for (size_t bit = 0; bit < 64; ++bit) {
memcpy(expected_data + num_analog_bytes +
expected_digital_part.size() * bit,
expected_digital_part.data(), expected_digital_part.size());
}
memset(expected_data + expected_num_digital_bytes + num_analog_bytes,
dummy_value,
num_transceiver_bytes); // set to 125
size_t size = get_size();
dataprocessor->ArrangeDbitData(size, data); // call reorder
CHECK(size == expected_size);
CHECK(memcmp(data, expected_data, expected_size) == 0);
delete[] expected_data;
}
TEST_CASE_METHOD(DataProcessorTestFixture, "Arrange bitlist with reorder false",
"[.dataprocessor][.retrievebitlist]") {
// parameters: num_samples, bitlist, expected_num_digital_bytes,
// expected_digital_part
auto parameters = GENERATE(
std::make_tuple(5, std::vector<int>{1, 4, 5}, 5,
std::vector<uint8_t>{0b00000111}),
std::make_tuple(5, std::vector<int>{1, 5, 3, 7, 8, 50, 42, 60, 39}, 10,
std::vector<uint8_t>{0xFF, 0b00000001}),
std::make_tuple(5, std::vector<int>{1, 5, 3, 7, 8, 50, 42, 60}, 5,
std::vector<uint8_t>{0xFF}));
size_t num_samples, expected_num_digital_bytes;
std::vector<uint8_t> expected_digital_part;
std::vector<int> bitlist;
std::tie(num_samples, bitlist, expected_num_digital_bytes,
expected_digital_part) = parameters;
generaldata->SetCtbDbitList(bitlist);
generaldata->SetCtbDbitReorder(false);
set_num_samples(num_samples);
set_data();
size_t expected_size =
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
// create expected data
char *expected_data = new char[expected_size];
memset(expected_data, dummy_value, num_analog_bytes);
for (size_t sample = 0; sample < num_samples; ++sample) {
memcpy(expected_data + num_analog_bytes +
expected_digital_part.size() * sample,
expected_digital_part.data(), expected_digital_part.size());
}
memset(expected_data + expected_num_digital_bytes + num_analog_bytes,
dummy_value, num_transceiver_bytes);
size_t size = get_size();
dataprocessor->ArrangeDbitData(size, data);
CHECK(size == expected_size);
CHECK(memcmp(data, expected_data, expected_size) == 0);
delete[] expected_data;
}
TEST_CASE_METHOD(DataProcessorTestFixture, "Arrange bitlist with reorder true",
"[.dataprocessor][.retrievebitlist]") {
// parameters: num_samples, bitlist, expected_num_digital_bytes,
// expected_digital_part
auto parameters = GENERATE(
std::make_tuple(5, std::vector<int>{1, 4, 5}, 3,
std::vector<uint8_t>{0b00011111}),
std::make_tuple(10, std::vector<int>{1, 4, 5}, 6,
std::vector<uint8_t>{0xFF, 0b00000011}),
std::make_tuple(8, std::vector<int>{1, 5, 3, 7, 8, 50, 42, 60, 39}, 9,
std::vector<uint8_t>{0xFF}));
size_t num_samples, expected_num_digital_bytes;
std::vector<uint8_t> expected_digital_part;
std::vector<int> bitlist;
std::tie(num_samples, bitlist, expected_num_digital_bytes,
expected_digital_part) = parameters;
generaldata->SetCtbDbitList(bitlist);
generaldata->SetCtbDbitReorder(true);
set_num_samples(num_samples);
set_data();
size_t expected_size =
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
// create expected data
char *expected_data = new char[expected_size];
memset(expected_data, dummy_value, num_analog_bytes);
for (size_t sample = 0; sample < bitlist.size(); ++sample) {
memcpy(expected_data + num_analog_bytes +
expected_digital_part.size() * sample,
expected_digital_part.data(), expected_digital_part.size());
}
memset(expected_data + expected_num_digital_bytes + num_analog_bytes,
dummy_value, num_transceiver_bytes);
size_t size = get_size();
dataprocessor->ArrangeDbitData(size, data);
CHECK(size == expected_size);
CHECK(memcmp(data, expected_data, expected_size) == 0);
delete[] expected_data;
}
TEST_CASE_METHOD(DataProcessorTestFixture,
"Arrange bitlist and remove trailing bits",
"[.dataprocessor][.retrievebitlist]") {
size_t num_random_offset_bytes = 3;
std::vector<int> bitlist{1, 4, 5};
set_random_offset_bytes(num_random_offset_bytes);
set_data();
generaldata->SetCtbDbitList(bitlist);
generaldata->SetCtbDbitReorder(false);
generaldata->SetCtbDbitOffset(num_random_offset_bytes);
std::vector<uint8_t> expected_digital_part{0b00000111};
const size_t expected_num_digital_bytes = 5;
size_t expected_size =
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
// create expected data
char *expected_data = new char[expected_size];
memset(expected_data, dummy_value, num_analog_bytes);
for (size_t sample = 0; sample < num_samples; ++sample) {
memcpy(expected_data + num_analog_bytes +
expected_digital_part.size() * sample,
expected_digital_part.data(), expected_digital_part.size());
}
memset(expected_data + expected_num_digital_bytes + num_analog_bytes,
dummy_value, num_transceiver_bytes);
size_t size = get_size();
dataprocessor->ArrangeDbitData(size, data);
CHECK(size == expected_size);
CHECK(memcmp(data, expected_data, expected_size) == 0);
delete[] expected_data;
}
} // namespace sls

View File

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

View File

@ -113,10 +113,12 @@ 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_[current_size]; }
const_iterator end() const noexcept { return &data_[current_size]; }
iterator end() noexcept { return data_.begin() + current_size; }
const_iterator end() const noexcept { return data_.begin() + current_size; }
const_iterator cbegin() const noexcept { return data_.cbegin(); }
const_iterator cend() const noexcept { return &data_[current_size]; }
const_iterator cend() const noexcept {
return data_.cbegin() + current_size;
}
void size_check(size_type s) const {
if (s > Capacity) {

View File

@ -47,6 +47,8 @@ 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);

View File

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

View File

@ -410,6 +410,8 @@ enum detFuncs {
F_RECEIVER_SET_TRANSCEIVER_MASK,
F_RECEIVER_SET_ROW,
F_RECEIVER_SET_COLUMN,
F_GET_RECEIVER_DBIT_REORDER,
F_SET_RECEIVER_DBIT_REORDER,
NUM_REC_FUNCTIONS
};
@ -816,7 +818,8 @@ const char* getFunctionNameFromEnum(enum detFuncs func) {
case F_RECEIVER_SET_TRANSCEIVER_MASK: return "F_RECEIVER_SET_TRANSCEIVER_MASK";
case F_RECEIVER_SET_ROW: return "F_RECEIVER_SET_ROW";
case F_RECEIVER_SET_COLUMN: return "F_RECEIVER_SET_COLUMN";
case F_GET_RECEIVER_DBIT_REORDER: return "F_GET_RECEIVER_DBIT_REORDER";
case F_SET_RECEIVER_DBIT_REORDER: return "F_SET_RECEIVER_DBIT_REORDER";
case NUM_REC_FUNCTIONS: return "NUM_REC_FUNCTIONS";
default: return "Unknown Function";

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 "developer 0x241122"
#define APIRECEIVER "developer 0x241122"
#define APICTB "developer 0x250310"
#define APIGOTTHARD2 "developer 0x250310"
#define APIMYTHEN3 "developer 0x250310"
#define APIMOENCH "developer 0x250310"
#define APIEIGER "developer 0x250310"
#define APIXILINXCTB "developer 0x250311"
#define APIJUNGFRAU "developer 0x250318"
#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"

View File

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

View File

@ -14,6 +14,7 @@ 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>
namespace sls {
using sls::StaticVector;
TEST_CASE("StaticVector is a container") {
REQUIRE(is_container<StaticVector<int, 7>>::value == true);
REQUIRE(sls::is_container<StaticVector<int, 7>>::value == true);
}
TEST_CASE("Comparing StaticVector containers") {
@ -90,10 +90,17 @@ 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") {
@ -246,23 +253,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(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);
// }
// }
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);
}
}
}
}
@ -334,5 +341,3 @@ TEST_CASE("StaticVector stream") {
oss << vec;
REQUIRE(oss.str() == "[33, 85667, 2]");
}
} // namespace sls

View File

@ -16,6 +16,16 @@ 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

@ -0,0 +1,19 @@
// 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,3 +60,5 @@ 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

@ -0,0 +1,141 @@
# 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,245 +4,86 @@
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 os, sys, subprocess, time, colorama, signal
import sys, subprocess, time, traceback
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 slsdet import Detector
from slsdet.defines import DEFAULT_TCP_RX_PORTNO
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)
from utils_for_test import (
Log,
LogLevel,
RuntimeException,
checkIfProcessRunning,
killProcess,
cleanup,
cleanSharedmemory,
startProcessInBackground,
runProcessWithLogFile,
startDetectorVirtualServer,
loadConfig,
ParseArguments
)
def checkIfProcessRunning(processName):
cmd = "ps -ef | grep " + processName
print(cmd)
res=subprocess.getoutput(cmd)
print(res)
# eg. of output
#l_user 250506 243295 0 14:38 pts/5 00:00:00 /bin/sh -c ps -ef | grep slsReceiver
#l_user 250508 250506 0 14:38 pts/5 00:00:00 grep slsReceiver
print('how many')
cmd = "ps -ef | grep " + processName + " | wc -l"
print(cmd)
res=subprocess.getoutput(cmd)
print(res)
if res == '2':
return False
return 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 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)
def startReceiver(num_mods, fp):
if num_mods == 1:
cmd = ['slsReceiver']
else:
print('process not running : ' + name)
cmd = ['slsMultiReceiver', str(DEFAULT_TCP_RX_PORTNO), str(num_mods)]
# in 10.0.0
#cmd = ['slsMultiReceiver', '-p', str(DEFAULT_TCP_RX_PORTNO), '-n', str(num_mods)]
startProcessInBackground(cmd, fp)
time.sleep(1)
def killAllStaleProcesses():
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()
def cleanup(name):
'''
kill both servers, receivers and clean shared memory
'''
Log(Fore.GREEN, 'Cleaning up...')
killProcess(name + 'DetectorServer_virtual')
killProcess('slsReceiver')
killProcess('slsMultiReceiver')
cleanSharedmemory()
def cleanSharedmemory():
Log(Fore.GREEN, 'Cleaning up shared memory...')
def startGeneralTests(fp):
fname = GENERAL_TESTS_LOG_FNAME
cmd = ['tests', '--abort', '-s']
try:
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:
Log(Fore.RED, 'Could not start ' + name)
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
p = subprocess.run(cmd.split(), stdout=fp, stderr=fp, check=True, text=True)
p.check_returncode()
with open (fname, 'r') as f:
for line in f:
if "FAILED" in line:
msg = 'Cmd tests failed for ' + name + '!!!'
Log(Fore.RED, msg)
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
p = subprocess.run(cmd.split(), stdout=fp, stderr=fp, check=True, text=True)
p.check_returncode()
with open (fname, 'r') as f:
for line in f:
if "FAILED" in line:
msg = 'General tests failed !!!'
Log(Fore.RED, msg)
raise Exception(msg)
Log(Fore.GREEN, 'General Tests successful')
cleanup(fp)
runProcessWithLogFile('General Tests', cmd, fp, fname)
except Exception as e:
raise RuntimeException(f'General tests failed.') 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', help = 'hostname/ip of the current machine')
parser.add_argument('settingspath', help = 'Relative or absolut path to the settingspath')
parser.add_argument('-s', '--servers', help='Detector servers to run', nargs='*')
args = parser.parse_args()
if args.rx_hostname == 'localhost':
raise RuntimeException('Cannot use localhost for rx_hostname for the tests (fails for rx_arping for eg.)')
if args.servers is None:
servers = [
'eiger',
'jungfrau',
'mythen3',
'gotthard2',
'ctb',
'moench',
'xilinx_ctb'
]
else:
servers = args.servers
Log(Fore.WHITE, 'Arguments:\nrx_hostname: ' + args.rx_hostname + '\nsettingspath: \'' + args.settingspath + '\'')
# 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 + ')')
startGeneralTests(fp, file_results)
killAllStaleProcesses()
for server in servers:
def startCmdTestsForAll(args, fp):
for server in args.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 + ')')
num_mods = 2 if server == 'eiger' else 1
fname = CMD_TEST_LOG_PREFIX_FNAME + server + '.txt'
cmd = ['tests', '--abort', '[.cmdcall]', '-s']
# cmd tests for det
cleanup(server)
startServer(server)
startReceiver(server)
loadConfig(server, args.rx_hostname, args.settingspath)
startCmdTests(server, fp, file_results)
cleanup(server)
except:
Log(Fore.RED, 'Exception caught. Cleaning up.')
cleanup(server)
sys.stdout = original_stdout
sys.stderr = original_stderr
Log(Fore.RED, 'Cmd tests failed for ' + server + '!!!')
raise
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
Log(LogLevel.INFOGREEN, 'Passed all tests for all detectors \n' + str(args.servers))
Log(Fore.GREEN, 'Passed all tests for virtual detectors \n' + str(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).')
# redirect to terminal
sys.stdout = original_stdout
sys.stderr = original_stderr
Log(Fore.GREEN, 'Passed all tests for virtual detectors \n' + str(servers) + '\nYayyyy! :) ')
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.')

View File

@ -0,0 +1,259 @@
# 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

81
updateAPIVersion.py Normal file
View File

@ -0,0 +1,81 @@
# 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)

View File

@ -1,65 +0,0 @@
# 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

Some files were not shown because too many files have changed in this diff Show More