mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-06-23 10:07:59 +02:00
Compare commits
174 Commits
dev/roi_pe
...
9.1.1
Author | SHA1 | Date | |
---|---|---|---|
0d1642c56e | |||
9bb25445f5 | |||
376514606f | |||
8707196f58 | |||
9f9b1d496c | |||
b2dd964907 | |||
348d820265 | |||
d414c7459b | |||
8eb2134d9f | |||
b8b067d74b | |||
3619a032ac | |||
2ee7e36fb3 | |||
d739453f2b | |||
3bfa3bfba3 | |||
894c227723 | |||
f3e5804d02 | |||
2c4cd80748 | |||
674865120b | |||
c0ae090be0 | |||
a85ad6cd84 | |||
5f6dea2d6d | |||
f5bf509525 | |||
03eded30f9 | |||
684f511bf8 | |||
2c93d40e81 | |||
9889a31f81 | |||
b00a37bc16 | |||
15030ab732 | |||
0ecc6030c6 | |||
6c604e2340 | |||
0f4d10912b | |||
af386a736e | |||
a43f2c946f | |||
8d21fd364b | |||
9aceb07d80 | |||
7b3accf372 | |||
cfde194834 | |||
8ac9cd6b15 | |||
3e38de5092 | |||
70e7879dd9 | |||
37b2efb1ed | |||
7ac18fbad9 | |||
6839315a7c | |||
527915a2ca | |||
64aad1e196 | |||
d3f847100e | |||
e1224936ca | |||
f29ef9e345 | |||
00e3b196f6 | |||
0109973e68 | |||
ad995b381a | |||
53b84b17a6 | |||
16d404c21b | |||
34ce96ffa0 | |||
d5fa26ef9a | |||
77f20b4e97 | |||
a295208c12 | |||
36a6087e1d | |||
fb406a7c6c | |||
6e4380db43 | |||
903652bb72 | |||
1609706093 | |||
14d2d171bb | |||
dd8452b365 | |||
15a9fb86da | |||
222d2b3fad | |||
a57531312f | |||
85a03a1d72 | |||
fc197ed002 | |||
a5d242876b | |||
76ce5de89e | |||
dbb0dbcbcd | |||
87d40d418e | |||
c82712b587 | |||
9dd1509714 | |||
c8290598db | |||
ff6a2655a2 | |||
7b2e6ae4ab | |||
706f3a103c | |||
5de98b3db0 | |||
7494e41862 | |||
7607fdc9a7 | |||
1bfffb842d | |||
7c48ae9a49 | |||
bf82aeee8d | |||
84e83bf551 | |||
60ce31bb17 | |||
2947b65e02 | |||
1b41e39ad1 | |||
64fea22c2b | |||
9beaed7813 | |||
0aeb7e4417 | |||
4880f87791 | |||
97f0c1fe46 | |||
a86fd00e59 | |||
24894667b7 | |||
4b414bfddb | |||
15d357d9ab | |||
f95de054f9 | |||
0aef8113dd | |||
9785a41048 | |||
417e1a88a5 | |||
9c0dd0385d | |||
5ab64efe3e | |||
8f77e4d4fe | |||
41c5b75b10 | |||
bfe53c6693 | |||
f7997dd09a | |||
c64e87a2b6 | |||
5eeb8e29c1 | |||
09697fa325 | |||
90b4daef39 | |||
2082f1eee7 | |||
d3a636b563 | |||
50b9b6ca39 | |||
e86b57cdfc | |||
14e11e8b5b | |||
beafe86554 | |||
af3dc1e7f4 | |||
573177203b | |||
a3ca9ebce5 | |||
8174fc9691 | |||
d6eac6da71 | |||
56c7ae4852 | |||
9b9b09ceaf | |||
cfebaee2a5 | |||
4613c54f57 | |||
51f9d6f011 | |||
58ac7ac280 | |||
82edfa75d3 | |||
35ed926047 | |||
4023ed0775 | |||
b6ef3bc39e | |||
2035666792 | |||
1ff4d806e7 | |||
3861379653 | |||
91140bbb71 | |||
a5632fcbea | |||
d44329117d | |||
4a454aa698 | |||
0e43072db8 | |||
6c67025ea8 | |||
e5ee27dbfa | |||
601249cc71 | |||
ff60b8c379 | |||
37ce3d6f59 | |||
bf26533fd8 | |||
7106273521 | |||
1484d038de | |||
fb0090c79e | |||
adc68cd519 | |||
1566eef247 | |||
e7cd90db78 | |||
45414149fe | |||
48759f440e | |||
b367b7e431 | |||
f0b2a6f6f9 | |||
f761046bfc | |||
1a859b83db | |||
70bfc875a6 | |||
c0755308a4 | |||
ab5509e10c | |||
004cb26646 | |||
a4f47a5945 | |||
312f3f473d | |||
5871086cd6 | |||
6a0fe823b3 | |||
5912aae53e | |||
8833ccf5cc | |||
77c558a7be | |||
378fc301b8 | |||
87d6e16090 | |||
2ef021041c | |||
574127b5ac |
@ -1 +0,0 @@
|
||||
# This file is generated by cmake for dependency checking of the CMakeCache.txt file
|
@ -249,8 +249,8 @@ endif()
|
||||
if(SLS_USE_SANITIZER)
|
||||
target_compile_options(slsProjectOptions INTERFACE -fsanitize=address,undefined -fno-omit-frame-pointer)
|
||||
target_link_libraries(slsProjectOptions INTERFACE -fsanitize=address,undefined)
|
||||
# target_compile_options(slsProjectOptions INTERFACE -fsanitize=thread)
|
||||
# target_link_libraries(slsProjectOptions INTERFACE -fsanitize=thread)
|
||||
#target_compile_options(slsProjectOptions INTERFACE -fsanitize=thread -fno-omit-frame-pointer)
|
||||
#target_link_libraries(slsProjectOptions INTERFACE -fsanitize=thread)
|
||||
endif()
|
||||
|
||||
|
||||
|
57
RELEASE.txt
57
RELEASE.txt
@ -1,21 +1,13 @@
|
||||
SLS Detector Package Major Release x.x.x released on xx.xx.202x
|
||||
===============================================================
|
||||
SLS Detector Package Bug Fix Release 9.1.1 released on 22.05.2025
|
||||
==================================================================
|
||||
|
||||
This document describes the differences between vx.x.x and vx.0.2
|
||||
This document describes the differences between v9.1.1 and v9.1.0
|
||||
|
||||
|
||||
|
||||
CONTENTS
|
||||
--------
|
||||
1 New, Changed or Resolved Features
|
||||
1.1 Compilation
|
||||
1.2 Callback
|
||||
1.3 Python
|
||||
1.4 Client
|
||||
1.5 Detector Server
|
||||
1.6 Simulator
|
||||
1.7 Receiver
|
||||
1.8 Gui
|
||||
1 Resolved Features
|
||||
2 On-board Detector Server Compatibility
|
||||
3 Firmware Requirements
|
||||
4 Kernel Requirements
|
||||
@ -24,11 +16,33 @@ This document describes the differences between vx.x.x and vx.0.2
|
||||
|
||||
|
||||
|
||||
1 New, Changed or Resolved Features
|
||||
=====================================
|
||||
1 Resolved Features
|
||||
======================
|
||||
|
||||
|
||||
|
||||
Detector Server
|
||||
---------------
|
||||
|
||||
|
||||
* [Mythen3] Fix trimbits and badchannels
|
||||
They were shifted by 1. Fixed.
|
||||
|
||||
|
||||
Receiver
|
||||
--------
|
||||
|
||||
|
||||
* slsFrameSynchronizer - does not stream out frames
|
||||
It streamed out start and stop zmq packets but did
|
||||
not stream out frames with no error message. Fixed.
|
||||
Updated documentation.
|
||||
|
||||
|
||||
* slsMultiReceiver - 3rd Command line argument (vebose option)
|
||||
When this option to print headers is enabled, the sample call back
|
||||
headers update the image size to a random number 26112. This
|
||||
is fixed and left commented out for easy reference for users.
|
||||
|
||||
|
||||
|
||||
2 On-board Detector Server Compatibility
|
||||
@ -36,8 +50,8 @@ This document describes the differences between vx.x.x and vx.0.2
|
||||
|
||||
|
||||
Eiger 9.0.0
|
||||
Jungfrau 9.0.0
|
||||
Mythen3 9.0.0
|
||||
Jungfrau 9.1.0
|
||||
Mythen3 9.1.1
|
||||
Gotthard2 9.0.0
|
||||
Gotthard 9.0.0
|
||||
Moench 9.0.0
|
||||
@ -66,14 +80,14 @@ This document describes the differences between vx.x.x and vx.0.2
|
||||
|
||||
Eiger 02.10.2023 (v32) (updated in 7.0.3)
|
||||
|
||||
Jungfrau 20.09.2023 (v1.5, HW v1.0) (updated in 8.0.0)
|
||||
21.09.2023 (v2.5, HW v2.0) (updated in 8.0.0)
|
||||
Jungfrau 09.02.2025 (v1.6, HW v1.0) (updated in 9.1.0)
|
||||
08.02.2025 (v2.6, HW v2.0) (updated in 9.1.0)
|
||||
|
||||
Mythen3 11.10.2024 (v1.5) (updated in 9.0.0)
|
||||
Mythen3 13.11.2024 (v2.0) (updated in 9.0.0)
|
||||
|
||||
Gotthard2 03.10.2024 (v1.0) (updated in 9.0.0)
|
||||
|
||||
Moench 26.10.2023 (v2.0) (updated in 9.0.0)
|
||||
Moench 26.10.2023 (v2.0) (updated in 8.0.2)
|
||||
|
||||
Gotthard 08.02.2018 (50um and 25um Master)
|
||||
09.02.2018 (25 um Slave)
|
||||
@ -212,3 +226,4 @@ This document describes the differences between vx.x.x and vx.0.2
|
||||
|
||||
dhanya.thattil@psi.ch
|
||||
erik.frojdh@psi.ch
|
||||
alice.mazzoleni@psi.ch
|
||||
|
@ -6,3 +6,9 @@ python:
|
||||
- 3.12
|
||||
- 3.13
|
||||
|
||||
|
||||
c_stdlib:
|
||||
- sysroot # [linux]
|
||||
|
||||
c_stdlib_version: # [linux]
|
||||
- 2.17 # [linux]
|
||||
|
@ -15,36 +15,20 @@ build:
|
||||
requirements:
|
||||
build:
|
||||
- {{ compiler('c') }}
|
||||
- {{stdlib('c')}}
|
||||
- {{compiler('cxx')}}
|
||||
- cmake
|
||||
- cmake<=3.28
|
||||
- ninja
|
||||
- qt 5.*
|
||||
- xorg-libx11
|
||||
- xorg-libice
|
||||
- xorg-libxext
|
||||
- xorg-libsm
|
||||
- xorg-libxau
|
||||
- xorg-libxrender
|
||||
- xorg-libxfixes
|
||||
- {{ cdt('mesa-libgl-devel') }} # [linux]
|
||||
- {{ cdt('mesa-libegl-devel') }} # [linux]
|
||||
- {{ cdt('mesa-dri-drivers') }} # [linux]
|
||||
- {{ cdt('libselinux') }} # [linux]
|
||||
- {{ cdt('libxdamage') }} # [linux]
|
||||
- {{ cdt('libxxf86vm') }} # [linux]
|
||||
- expat
|
||||
|
||||
host:
|
||||
- libstdcxx-ng
|
||||
- libgcc-ng
|
||||
- xorg-libx11
|
||||
- xorg-libice
|
||||
- xorg-libxext
|
||||
- xorg-libsm
|
||||
- xorg-libxau
|
||||
- xorg-libxrender
|
||||
- xorg-libxfixes
|
||||
- libgl-devel
|
||||
- libtiff
|
||||
- zlib
|
||||
- expat
|
||||
|
||||
|
||||
run:
|
||||
- libstdcxx-ng
|
||||
- libgcc-ng
|
||||
@ -104,6 +88,7 @@ outputs:
|
||||
- {{ compiler('c') }}
|
||||
- {{compiler('cxx')}}
|
||||
- {{ pin_subpackage('slsdetlib', exact=True) }}
|
||||
|
||||
|
||||
run:
|
||||
- {{ pin_subpackage('slsdetlib', exact=True) }}
|
||||
@ -123,3 +108,4 @@ outputs:
|
||||
run:
|
||||
- {{ pin_subpackage('slsdetlib', exact=True) }}
|
||||
- expat
|
||||
|
||||
|
@ -63,4 +63,4 @@ html_static_path = ['static']
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.add_stylesheet('css/extra.css') # may also be an URL
|
||||
app.add_css_file('css/extra.css') # may also be an URL
|
||||
|
@ -4,11 +4,54 @@ Command line interface
|
||||
Usage
|
||||
-------------
|
||||
|
||||
Commands can be used either with sls_detector_get or sls_detector_put
|
||||
The syntax is *'[detector index]-[module index]:[command]'*, where the indices are by default '0', when not specified.
|
||||
|
||||
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.
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Applies to all modules of detector 0
|
||||
sls_detector_put exptime 5s
|
||||
|
||||
# Applies to only the 4th module
|
||||
sls_detector_put 3:exptime 5s
|
||||
|
||||
|
||||
Detector index
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
This index is useful when configuring multiple detectors from a single host. Each detector uses a unique shared memory identified by a detector index, derived again from the hostname command. It is followed by a '-'.
|
||||
|
||||
.. code-block::
|
||||
|
||||
# For detector with index 2 in shared memory
|
||||
sls_detector_put 2-hostname bchip133+bchip123+bchip456
|
||||
|
||||
# Without '-', the detector index defaults to 0
|
||||
sls_detector_put hostname bchip133+bchip123+bchip456
|
||||
|
||||
# Accessing all modules with detector index 2
|
||||
sls_detector_put 2-exptime
|
||||
|
||||
# Starting acquisition only for detector with index 2
|
||||
sls_detector_put 2-start
|
||||
|
||||
# Applies only to the 2nd detector, 4th module
|
||||
sls_detector_put 1-3:exptime 5s
|
||||
|
||||
|
||||
Command Execution
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Commands can be executed using:
|
||||
|
||||
* **sls_detector_put**: setting values
|
||||
* **sls_detector_get**: getting values
|
||||
* **sls_detector**: automatically infers based on the number of arguments.
|
||||
* **sls_detector_help**: gets help on the specific command
|
||||
* **sls_detector_acquire**: initiates acquisition with the detector. This command blocks until the entire acquisition process is completed.
|
||||
|
||||
.. code-block::
|
||||
|
||||
sls_detector_get exptime
|
||||
|
||||
Help
|
||||
--------
|
||||
@ -28,12 +71,15 @@ Help
|
||||
# list of deprecated commands
|
||||
list deprecated
|
||||
|
||||
# autocompletion
|
||||
# bash_autocomplete.sh or zsh_autocomplete.sh must be sourced from the
|
||||
# main package folder to enable auto completion of commands and arguments
|
||||
# for the command line on that shell.
|
||||
source bash_autocomplete.sh
|
||||
|
||||
Autocompletion
|
||||
---------------
|
||||
|
||||
bash_autocomplete.sh or zsh_autocomplete.sh must be sourced from the main package folder to enable auto completion of commands and arguments for the command line on that shell.
|
||||
|
||||
.. code-block::
|
||||
|
||||
source bash_autocomplete.sh
|
||||
|
||||
|
||||
Commands
|
||||
|
@ -13,7 +13,6 @@ containing results from all modules. (:ref:`Result class<Result Class>`)
|
||||
|
||||
Here are some :ref:`examples <Cplusplus Api Examples>` on how to use the API.
|
||||
|
||||
.. _Cplusplus Api Examples:
|
||||
.. doxygenclass:: sls::Detector
|
||||
:members:
|
||||
:undoc-members:
|
@ -39,7 +39,7 @@ Welcome to slsDetectorPackage's documentation!
|
||||
|
||||
.. toctree::
|
||||
:caption: Command line
|
||||
:maxdepth: 2
|
||||
:maxdepth: 1
|
||||
|
||||
commandline
|
||||
quick_start_guide
|
||||
@ -79,8 +79,9 @@ Welcome to slsDetectorPackage's documentation!
|
||||
:caption: Receiver
|
||||
:maxdepth: 2
|
||||
|
||||
receivers
|
||||
slsreceiver
|
||||
receivers
|
||||
|
||||
|
||||
.. toctree::
|
||||
:caption: Receiver Files
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
.. _master file attributes:
|
||||
|
||||
Master File Attributes
|
||||
=======================
|
||||
|
||||
|
@ -128,6 +128,10 @@ For Multiple Modules
|
||||
# set file path
|
||||
fpath /tmp
|
||||
|
||||
.. note ::
|
||||
The **hostname** and **detsize** command in a multi module system can affect the row and column values in the udp/zmq header. The modules are stacked row by row until they reach the y-axis limit set by detsize (if specified). Then, stacking continues in the next column and so on.
|
||||
|
||||
|
||||
Gui
|
||||
----
|
||||
|
||||
|
@ -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
|
||||
|
@ -39,13 +39,13 @@ Arguments
|
||||
|
||||
|
||||
.. _Automatic start servers:
|
||||
|
||||
Automatic start
|
||||
------------------
|
||||
|
||||
One can start the on-board detector server automatically upon powering on the board.
|
||||
|
||||
#. Create a soft link to the binary on board
|
||||
:
|
||||
#. Create a soft link to the binary on board:
|
||||
.. code-block:: bash
|
||||
|
||||
ln -sf someDetectorServervx.x.x someDetectorServer
|
||||
@ -87,8 +87,7 @@ One can start the on-board detector server automatically upon powering on the bo
|
||||
/root/xxxDetectorServer >> /dev/null &
|
||||
|
||||
|
||||
#. Sync, reboot and verify
|
||||
:
|
||||
#. Sync, reboot and verify:
|
||||
.. code-block:: bash
|
||||
|
||||
sync
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. _Detector Server Upgrade:
|
||||
|
||||
Upgrade
|
||||
========
|
||||
|
||||
|
@ -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
|
||||
|
||||
slsReceiver # default port 1954
|
||||
|
||||
# default port 1954
|
||||
slsReceiver
|
||||
|
||||
# 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 # option 1
|
||||
|
||||
rx_tcpport 1957 # option 2
|
||||
rx_hostname xxx
|
||||
|
||||
# custom receiver port
|
||||
rx_hostname xxx:1957
|
||||
|
||||
# custom receiver port
|
||||
rx_tcpport 1954
|
||||
rx_hostname xxx
|
||||
# ---multi module---
|
||||
|
||||
# multi modules with custom ports
|
||||
rx_hostname xxx:1955+xxx:1956+
|
||||
|
||||
|
||||
# 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
.. _detector udp header:
|
||||
.. _detector udp header config:
|
||||
|
||||
|
||||
Config file
|
||||
|
@ -73,9 +73,9 @@ Description
|
||||
|
||||
* **modId**: module ID picked up from det_id_[detector type].txt on the detector cpu.
|
||||
|
||||
* **row**: row position of the module in the detector system. It is calculated by the order of the module in hostname command, as well as the detsize command.
|
||||
* **row**: row position of the module in the detector system. It is calculated by the order of the module in hostname command, as well as the detsize command. The modules are stacked row by row until they reach the y-axis limit set by detsize (if specified). Then, stacking continues in the next column and so on.
|
||||
|
||||
* **column**: column position of the module in the detector system. It is calculated by the order of the module in hostname command, as well as the detsize command.
|
||||
* **column**: column position of the module in the detector system. It is calculated by the order of the module in hostname command, as well as the detsize command. The modules are stacked row by row until they reach the y-axis limit set by detsize (if specified). Then, stacking continues in the next column and so on.
|
||||
|
||||
* **detType**: detector type from enum of detectorType in the package.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. _Virtual Detector Servers:
|
||||
|
||||
Simulators
|
||||
===========
|
||||
|
||||
|
@ -64,6 +64,10 @@ 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
|
||||
)
|
||||
@ -76,4 +80,5 @@ if(SLS_INSTALL_PYTHONEXT)
|
||||
|
||||
install(FILES ${PYTHON_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/python/slsdet)
|
||||
install(FILES ../VERSION DESTINATION ${CMAKE_INSTALL_PREFIX}/python/slsdet)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
19
python/scripts/frameSynchronizerPullSocket.py
Normal file
19
python/scripts/frameSynchronizerPullSocket.py
Normal file
@ -0,0 +1,19 @@
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
# Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
# Script to get combined zmq packets from frame synchronizer using pull zmq sockets
|
||||
import json
|
||||
import zmq
|
||||
|
||||
c = zmq.Context()
|
||||
s = c.socket(zmq.PULL)
|
||||
s.connect("tcp://127.0.0.1:5555")
|
||||
|
||||
while True:
|
||||
m = s.recv_multipart()
|
||||
for p in m:
|
||||
if p.startswith(b"{"):
|
||||
print(p.decode().strip())
|
||||
else:
|
||||
print("binary")
|
||||
print("--------")
|
||||
|
@ -123,6 +123,9 @@ def visit(node):
|
||||
if node.kind == cindex.CursorKind.CLASS_DECL:
|
||||
if node.displayname == "Detector":
|
||||
for child in node.get_children():
|
||||
# Skip assignment operators
|
||||
if child.kind == cindex.CursorKind.CXX_METHOD and child.spelling == "operator=":
|
||||
continue
|
||||
if (
|
||||
child.kind == cindex.CursorKind.CXX_METHOD
|
||||
and child.access_specifier == cindex.AccessSpecifier.PUBLIC
|
||||
|
@ -151,6 +151,10 @@ class Detector(CppDetectorApi):
|
||||
def hostname(self):
|
||||
"""Frees shared memory and sets hostname (or IP address) of all modules concatenated by +
|
||||
Virtual servers can already use the port in hostname separated by ':' and ports incremented by 2 to accomodate the stop server as well.
|
||||
|
||||
Note
|
||||
-----
|
||||
The row and column values in the udp/zmq header are affected by the order in this command and the detsize command. The modules are stacked row by row until they reach the y-axis limit set by detsize (if specified). Then, stacking continues in the next column and so on. This only affects row and column in udp/zmq header.
|
||||
|
||||
Example
|
||||
-------
|
||||
@ -2566,7 +2570,7 @@ class Detector(CppDetectorApi):
|
||||
|
||||
Note
|
||||
-----
|
||||
By default, the on-chip gain switching is active during the entire exposure. This mode disables the on-chip gain switching comparator automatically after 93.75% of exposure time (only for longer than 100us). The % is only for chipv1.0, the duration can be set for chipv1.1.\n
|
||||
By default, the on-chip gain switching is active during the entire exposure. This mode disables the on-chip gain switching comparator automatically and the duration is set using compdisabletime.\n
|
||||
Default is 0 or this mode disabled (comparator enabled throughout). 1 enables mode. 0 disables mode.
|
||||
"""
|
||||
return self.getAutoComparatorDisable()
|
||||
@ -2580,10 +2584,6 @@ class Detector(CppDetectorApi):
|
||||
def compdisabletime(self):
|
||||
"""[Jungfrau] Time before end of exposure when comparator is disabled.
|
||||
|
||||
Note
|
||||
-----
|
||||
It is only possible for chipv1.1.
|
||||
|
||||
:getter: always returns in seconds. To get in DurationWrapper, use getComparatorDisableTime
|
||||
|
||||
Example
|
||||
@ -2913,7 +2913,7 @@ class Detector(CppDetectorApi):
|
||||
@property
|
||||
@element
|
||||
def timing_info_decoder(self):
|
||||
"""[Jungfrau] [Jungfrau] Advanced Command and only for SWISSFEL and SHINE. Sets the bunch id or timing info decoder. Default is SWISSFEL.
|
||||
"""[Jungfrau] [Jungfrau] Advanced Command and only for SWISSFEL and SHINE. Sets the bunch id or timing info decoder. Default is SWISSFEL. Only allowed for pcbv2.0.
|
||||
Enum: timingInfoDecoder
|
||||
"""
|
||||
return self.getTimingInfoDecoder()
|
||||
|
@ -1 +0,0 @@
|
||||
../slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServer_developer
|
1
serverBin/ctbDetectorServerv9.1.0
Symbolic link
1
serverBin/ctbDetectorServerv9.1.0
Symbolic link
@ -0,0 +1 @@
|
||||
../slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServerv9.1.0
|
@ -1 +0,0 @@
|
||||
../slsDetectorServers/eigerDetectorServer/bin/eigerDetectorServer_developer
|
1
serverBin/eigerDetectorServerv9.0.0
Symbolic link
1
serverBin/eigerDetectorServerv9.0.0
Symbolic link
@ -0,0 +1 @@
|
||||
../slsDetectorServers/eigerDetectorServer/bin/eigerDetectorServerv9.0.0
|
@ -1 +0,0 @@
|
||||
../slsDetectorServers/gotthard2DetectorServer/bin/gotthard2DetectorServer_developer
|
1
serverBin/gotthard2DetectorServerv9.0.0
Symbolic link
1
serverBin/gotthard2DetectorServerv9.0.0
Symbolic link
@ -0,0 +1 @@
|
||||
../slsDetectorServers/gotthard2DetectorServer/bin/gotthard2DetectorServerv9.0.0
|
@ -1 +0,0 @@
|
||||
../slsDetectorServers/gotthardDetectorServer/bin/gotthardDetectorServer_developer
|
1
serverBin/gotthardDetectorServerv9.0.0
Symbolic link
1
serverBin/gotthardDetectorServerv9.0.0
Symbolic link
@ -0,0 +1 @@
|
||||
../slsDetectorServers/gotthardDetectorServer/bin/gotthardDetectorServerv9.0.0
|
@ -1 +0,0 @@
|
||||
../slsDetectorServers/jungfrauDetectorServer/bin/jungfrauDetectorServer_developer
|
1
serverBin/jungfrauDetectorServerv9.1.0
Symbolic link
1
serverBin/jungfrauDetectorServerv9.1.0
Symbolic link
@ -0,0 +1 @@
|
||||
../slsDetectorServers/jungfrauDetectorServer/bin/jungfrauDetectorServerv9.1.0
|
@ -1 +0,0 @@
|
||||
../slsDetectorServers/moenchDetectorServer/bin/moenchDetectorServer_developer
|
1
serverBin/moenchDetectorServerv9.0.0
Symbolic link
1
serverBin/moenchDetectorServerv9.0.0
Symbolic link
@ -0,0 +1 @@
|
||||
../slsDetectorServers/moenchDetectorServer/bin/moenchDetectorServerv9.0.0
|
@ -1 +0,0 @@
|
||||
../slsDetectorServers/mythen3DetectorServer/bin/mythen3DetectorServer_developer
|
1
serverBin/mythen3DetectorServerv9.1.1
Symbolic link
1
serverBin/mythen3DetectorServerv9.1.1
Symbolic link
@ -0,0 +1 @@
|
||||
../slsDetectorServers/mythen3DetectorServer/bin/mythen3DetectorServerv9.1.1
|
1
serverBin/xilinx_ctbDetectorServerv9.1.0
Symbolic link
1
serverBin/xilinx_ctbDetectorServerv9.1.0
Symbolic link
@ -0,0 +1 @@
|
||||
../slsDetectorServers/xilinx_ctbDetectorServer/bin/xilinx_ctbDetectorServerv9.1.0
|
@ -503,6 +503,7 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
}
|
||||
#endif
|
||||
if (ee == PHOTON && val[iy * nx + ix] == max) {
|
||||
good = 1;
|
||||
ee = PHOTON_MAX;
|
||||
// cout << "**" <<id<< " " << iframe << " " << nDark << " "
|
||||
// << ix << " " << iy << " " << rms << " " << max << " " <<
|
||||
@ -536,7 +537,6 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
cout << max << " " << val[iy * nx + ix] << endl;
|
||||
}
|
||||
//else (clusters + nph)->print();
|
||||
good = 1;
|
||||
if (eMin > 0 && tot < eMin)
|
||||
good = 0;
|
||||
if (eMax > 0 && tot > eMax)
|
||||
|
Binary file not shown.
BIN
slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServerv9.1.0
Executable file
BIN
slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServerv9.1.0
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
slsDetectorServers/gotthard2DetectorServer/bin/gotthard2DetectorServerv9.0.0
Executable file
BIN
slsDetectorServers/gotthard2DetectorServer/bin/gotthard2DetectorServerv9.0.0
Executable file
Binary file not shown.
Binary file not shown.
BIN
slsDetectorServers/gotthardDetectorServer/bin/gotthardDetectorServerv9.0.0
Executable file
BIN
slsDetectorServers/gotthardDetectorServer/bin/gotthardDetectorServerv9.0.0
Executable file
Binary file not shown.
Binary file not shown.
BIN
slsDetectorServers/jungfrauDetectorServer/bin/jungfrauDetectorServerv9.1.0
Executable file
BIN
slsDetectorServers/jungfrauDetectorServer/bin/jungfrauDetectorServerv9.1.0
Executable file
Binary file not shown.
@ -1974,9 +1974,6 @@ int autoCompDisable(int on) {
|
||||
}
|
||||
|
||||
int setComparatorDisableTime(int64_t val) {
|
||||
if (getChipVersion() != 11) {
|
||||
return FAIL;
|
||||
}
|
||||
if (val < 0) {
|
||||
LOG(logERROR,
|
||||
("Invalid comp disable time: %lld ns\n", (long long int)val));
|
||||
@ -2817,7 +2814,8 @@ void *start_timer(void *arg) {
|
||||
getNextFrameNumber(&frameNr);
|
||||
int iRxEntry = firstDest;
|
||||
for (int iframes = 0; iframes != numFrames; ++iframes) {
|
||||
usleep(transmissionDelayUs);
|
||||
if (transmissionDelayUs)
|
||||
usleep(transmissionDelayUs);
|
||||
|
||||
// check if manual stop
|
||||
if (sharedMemory_getStop() == 1) {
|
||||
|
@ -5,8 +5,8 @@
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
||||
#define MIN_REQRD_VRSN_T_RD_API 0x171220
|
||||
#define REQRD_FRMWRE_VRSN_BOARD2 0x230920 // 1.0 pcb (version = 010)
|
||||
#define REQRD_FRMWRE_VRSN 0x230921 // 2.0 pcb (version = 011)
|
||||
#define REQRD_FRMWRE_VRSN_BOARD2 0x250209 // 1.0 pcb (version = 010)
|
||||
#define REQRD_FRMWRE_VRSN 0x250208 // 2.0 pcb (version = 011)
|
||||
|
||||
#define NUM_HARDWARE_VERSIONS (2)
|
||||
#define HARDWARE_VERSION_NUMBERS \
|
||||
|
Binary file not shown.
BIN
slsDetectorServers/moenchDetectorServer/bin/moenchDetectorServerv9.0.0
Executable file
BIN
slsDetectorServers/moenchDetectorServer/bin/moenchDetectorServerv9.0.0
Executable file
Binary file not shown.
@ -1927,7 +1927,8 @@ void *start_timer(void *arg) {
|
||||
getNextFrameNumber(&frameNr);
|
||||
int iRxEntry = firstDest;
|
||||
for (int iframes = 0; iframes != numFrames; ++iframes) {
|
||||
usleep(transmissionDelayUs);
|
||||
if (transmissionDelayUs)
|
||||
usleep(transmissionDelayUs);
|
||||
|
||||
// check if manual stop
|
||||
if (sharedMemory_getStop() == 1) {
|
||||
|
Binary file not shown.
@ -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,
|
||||
|
@ -50,7 +50,7 @@
|
||||
#define DEFAULT_NUM_CYCLES (1)
|
||||
#define DEFAULT_GATE_WIDTH (100 * 1000 * 1000) // ns
|
||||
#define DEFAULT_GATE_DELAY (0)
|
||||
#define DEFAULT_PERIOD (2 * 1000 * 1000) // ns
|
||||
#define DEFAULT_PERIOD (0) // ns
|
||||
#define DEFAULT_DELAY_AFTER_TRIGGER (0)
|
||||
#define DEFAULT_HIGH_VOLTAGE (0)
|
||||
#define DEFAULT_TIMING_MODE (AUTO_TIMING)
|
||||
|
@ -9090,16 +9090,9 @@ int get_comp_disable_time(int file_des) {
|
||||
functionNotImplemented();
|
||||
#else
|
||||
// get only
|
||||
if (getChipVersion() != 11) {
|
||||
ret = FAIL;
|
||||
strcpy(mess,
|
||||
"Cannot get comparator disable time. Only valid for chipv1.1\n");
|
||||
LOG(logERROR, (mess));
|
||||
} else {
|
||||
retval = getComparatorDisableTime();
|
||||
LOG(logDEBUG1,
|
||||
("retval comp disable time %lld ns\n", (long long int)retval));
|
||||
}
|
||||
retval = getComparatorDisableTime();
|
||||
LOG(logDEBUG1,
|
||||
("retval comp disable time %lld ns\n", (long long int)retval));
|
||||
#endif
|
||||
return Server_SendResult(file_des, INT64, &retval, sizeof(retval));
|
||||
}
|
||||
@ -9117,23 +9110,16 @@ int set_comp_disable_time(int file_des) {
|
||||
#else
|
||||
// only set
|
||||
if (Server_VerifyLock() == OK) {
|
||||
if (getChipVersion() != 11) {
|
||||
ret = FAIL;
|
||||
strcpy(mess, "Cannot get comparator disable time. Only valid for "
|
||||
"chipv1.1\n");
|
||||
ret = setComparatorDisableTime(arg);
|
||||
int64_t retval = getComparatorDisableTime();
|
||||
LOG(logDEBUG1,
|
||||
("retval get comp disable time %lld ns\n", (long long int)retval));
|
||||
if (ret == FAIL) {
|
||||
sprintf(mess,
|
||||
"Could not set comp disable time. Set %lld ns, read "
|
||||
"%lld ns.\n",
|
||||
(long long int)arg, (long long int)retval);
|
||||
LOG(logERROR, (mess));
|
||||
} else {
|
||||
ret = setComparatorDisableTime(arg);
|
||||
int64_t retval = getComparatorDisableTime();
|
||||
LOG(logDEBUG1, ("retval get comp disable time %lld ns\n",
|
||||
(long long int)retval));
|
||||
if (ret == FAIL) {
|
||||
sprintf(mess,
|
||||
"Could not set comp disable time. Set %lld ns, read "
|
||||
"%lld ns.\n",
|
||||
(long long int)arg, (long long int)retval);
|
||||
LOG(logERROR, (mess));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -11104,11 +11090,18 @@ int get_timing_info_decoder(int file_des) {
|
||||
functionNotImplemented();
|
||||
#else
|
||||
// get only
|
||||
ret = getTimingInfoDecoder(&retval);
|
||||
LOG(logDEBUG1, ("retval timing info decoder: %d\n", retval));
|
||||
if (ret == FAIL) {
|
||||
strcpy(mess, "Could not get timing info decoder\n");
|
||||
if (isHardwareVersion_1_0()) {
|
||||
ret = FAIL;
|
||||
sprintf(mess, "Could not get timing info decoder. Not supported "
|
||||
"for hardware version 1.0\n");
|
||||
LOG(logERROR, (mess));
|
||||
} else {
|
||||
ret = getTimingInfoDecoder(&retval);
|
||||
LOG(logDEBUG1, ("retval timing info decoder: %d\n", retval));
|
||||
if (ret == FAIL) {
|
||||
strcpy(mess, "Could not get timing info decoder\n");
|
||||
LOG(logERROR, (mess));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return Server_SendResult(file_des, INT32, &retval, sizeof(retval));
|
||||
@ -11136,6 +11129,12 @@ int set_timing_info_decoder(int file_des) {
|
||||
modeNotImplemented("Timing info decoder index", (int)arg);
|
||||
break;
|
||||
}
|
||||
if (ret == OK && isHardwareVersion_1_0()) {
|
||||
ret = FAIL;
|
||||
sprintf(mess, "Could not set timing info decoder. Not supported "
|
||||
"for hardware version 1.0\n");
|
||||
LOG(logERROR, (mess));
|
||||
}
|
||||
if (ret == OK) {
|
||||
ret = setTimingInfoDecoder(arg);
|
||||
if (ret == FAIL) {
|
||||
|
Binary file not shown.
BIN
slsDetectorServers/xilinx_ctbDetectorServer/bin/xilinx_ctbDetectorServerv9.1.0
Executable file
BIN
slsDetectorServers/xilinx_ctbDetectorServer/bin/xilinx_ctbDetectorServerv9.1.0
Executable file
Binary file not shown.
@ -468,7 +468,7 @@ subdeadtime:
|
||||
function: setSubDeadTime
|
||||
|
||||
compdisabletime:
|
||||
help: "[duration] [(optional unit) ns|us|ms|s]\n\t[Jungfrau] Time before end of exposure when comparator is disabled. It is only possible for chipv1.1."
|
||||
help: "[duration] [(optional unit) ns|us|ms|s]\n\t[Jungfrau] Time before end of exposure when comparator is disabled."
|
||||
inherit_actions: TIME_COMMAND
|
||||
actions:
|
||||
GET:
|
||||
@ -1123,7 +1123,7 @@ temp_control:
|
||||
input_types: [ bool ]
|
||||
|
||||
autocompdisable:
|
||||
help: "[0, 1]\n\t[Jungfrau] Auto comparator disable mode. By default, the on-chip gain switching is active during the entire exposure.This mode disables the on - chip gain switching comparator automatically after 93.75% (only for chipv1.0) of exposure time (only for longer than 100us). It is possible to set the duration for chipv1.1 using compdisabletime command.\n\tDefault is 0 or this mode disabled(comparator enabled throughout). 1 enables mode. 0 disables mode. "
|
||||
help: "[0, 1]\n\t[Jungfrau] Auto comparator disable mode. By default, the on-chip gain switching is active during the entire exposure.This mode disables the on - chip gain switching comparator automatically and the duration is set using compdisabletime command.\n\tDefault is 0 or this mode disabled(comparator enabled throughout). 1 enables mode. 0 disables mode. "
|
||||
inherit_actions: INTEGER_COMMAND_VEC_ID
|
||||
actions:
|
||||
GET:
|
||||
@ -1210,7 +1210,7 @@ polarity:
|
||||
input_types: [ defs::polarity ]
|
||||
|
||||
timing_info_decoder:
|
||||
help: "[swissfel|shine]\n\t[Jungfrau] Advanced Command and only for Swissfel and Shine. Sets the bunch id or timing info decoder. Default is swissfel."
|
||||
help: "[swissfel|shine]\n\t[Jungfrau] Advanced Command and only for Swissfel and Shine. Sets the bunch id or timing info decoder. Default is swissfel. Only allowed for pcbv2.0."
|
||||
inherit_actions: INTEGER_COMMAND_VEC_ID
|
||||
actions:
|
||||
GET:
|
||||
@ -3429,7 +3429,7 @@ udp_dstlist:
|
||||
output: [ ToString(args) ]
|
||||
|
||||
txdelay:
|
||||
help: "[n_delay]\n\t[Eiger][Jungfrau][Moench][Mythen3] Set transmission delay for all modules in the detector using the step size provided.Sets up \n\t[Eiger] txdelay_left to (2 * mod_index * n_delay), \n\t[Eiger] txdelay_right to ((2 * mod_index + 1) * n_delay) and \n\t[Eiger] txdelay_frame to (2 *num_modules * n_delay)\n\t[Jungfrau][Moench][Mythen3] txdelay_frame to (num_modules * n_delay) for every module."
|
||||
help: "[n_delay]\n\t[Eiger][Jungfrau][Moench][Mythen3] Set transmission delay for all modules in the detector using the step size provided.Sets up \n\t[Eiger] txdelay_left to (2 * mod_index * n_delay), \n\t[Eiger] txdelay_right to ((2 * mod_index + 1) * n_delay) and \n\t[Eiger] txdelay_frame to (2 * num_modules * n_delay)\n\t[Jungfrau][Moench][Mythen3] txdelay_frame to (num_modules * n_delay) for every module."
|
||||
actions:
|
||||
GET:
|
||||
argc: 0
|
||||
|
@ -762,10 +762,9 @@ autocompdisable:
|
||||
function_alias: autocompdisable
|
||||
help: "[0, 1]\n\t[Jungfrau] Auto comparator disable mode. By default, the on-chip\
|
||||
\ gain switching is active during the entire exposure.This mode disables the on\
|
||||
\ - chip gain switching comparator automatically after 93.75% (only for chipv1.0)\
|
||||
\ of exposure time (only for longer than 100us). It is possible to set the duration\
|
||||
\ for chipv1.1 using compdisabletime command.\n\tDefault is 0 or this mode disabled(comparator\
|
||||
\ enabled throughout). 1 enables mode. 0 disables mode. "
|
||||
\ - chip gain switching comparator automatically and the duration is set using\
|
||||
\ compdisabletime command.\n\tDefault is 0 or this mode disabled(comparator enabled\
|
||||
\ throughout). 1 enables mode. 0 disables mode. "
|
||||
infer_action: true
|
||||
template: true
|
||||
badchannels:
|
||||
@ -1607,7 +1606,7 @@ compdisabletime:
|
||||
command_name: compdisabletime
|
||||
function_alias: compdisabletime
|
||||
help: "[duration] [(optional unit) ns|us|ms|s]\n\t[Jungfrau] Time before end of\
|
||||
\ exposure when comparator is disabled. It is only possible for chipv1.1."
|
||||
\ exposure when comparator is disabled."
|
||||
infer_action: true
|
||||
template: true
|
||||
confadc:
|
||||
@ -11488,7 +11487,8 @@ timing_info_decoder:
|
||||
command_name: timing_info_decoder
|
||||
function_alias: timing_info_decoder
|
||||
help: "[swissfel|shine]\n\t[Jungfrau] Advanced Command and only for Swissfel and\
|
||||
\ Shine. Sets the bunch id or timing info decoder. Default is swissfel."
|
||||
\ Shine. Sets the bunch id or timing info decoder. Default is swissfel. Only allowed\
|
||||
\ for pcbv2.0."
|
||||
infer_action: true
|
||||
template: true
|
||||
timinglist:
|
||||
@ -11915,7 +11915,7 @@ txdelay:
|
||||
help: "[n_delay]\n\t[Eiger][Jungfrau][Moench][Mythen3] Set transmission delay for\
|
||||
\ all modules in the detector using the step size provided.Sets up \n\t[Eiger]\
|
||||
\ txdelay_left to (2 * mod_index * n_delay), \n\t[Eiger] txdelay_right to ((2\
|
||||
\ * mod_index + 1) * n_delay) and \n\t[Eiger] txdelay_frame to (2 *num_modules\
|
||||
\ * mod_index + 1) * n_delay) and \n\t[Eiger] txdelay_frame to (2 * num_modules\
|
||||
\ * n_delay)\n\t[Jungfrau][Moench][Mythen3] txdelay_frame to (num_modules * n_delay)\
|
||||
\ for every module."
|
||||
infer_action: true
|
||||
|
@ -65,7 +65,12 @@ class Detector {
|
||||
|
||||
Result<std::string> getHostname(Positions pos = {}) const;
|
||||
|
||||
/**Frees shared memory, adds detectors to the list. */
|
||||
/**Frees shared memory, adds detectors to the list. The row and column
|
||||
* values in the udp/zmq header are affected by the order in this command
|
||||
* and the setDetectorSize function. The modules are stacked row by row
|
||||
* until they reach the y-axis limit set by detsize (if specified). Then,
|
||||
* stacking continues in the next column and so on. This only affects row
|
||||
* and column in udp/zmq header.*/
|
||||
void setHostname(const std::vector<std::string> &hostname);
|
||||
|
||||
/** connects to n servers at local host starting at specific control port.
|
||||
@ -1304,11 +1309,9 @@ class Detector {
|
||||
* //TODO naming
|
||||
* By default, the on-chip gain switching is active during the
|
||||
* entire exposure. This mode disables the on-chip gain switching comparator
|
||||
* automatically after 93.75% of exposure time (only for longer than 100us).
|
||||
* The % is for chipv1.0. One can set the duration for chipv1.1 using
|
||||
* setComparatorDisableTime\n Default is false or this mode
|
||||
* disabled(comparator enabled throughout). true enables mode. 0 disables
|
||||
* mode.
|
||||
* automatically and the duration is set using setComparatorDisableTime\n
|
||||
* Default is false or this mode disabled(comparator enabled throughout).
|
||||
* true enables mode. 0 disables mode.
|
||||
*/
|
||||
void setAutoComparatorDisable(bool value, Positions pos = {});
|
||||
|
||||
@ -1316,7 +1319,7 @@ class Detector {
|
||||
Result<ns> getComparatorDisableTime(Positions pos = {}) const;
|
||||
|
||||
/** [Jungfrau] Time before end of exposure when comparator is
|
||||
* disabled. It is only possible for chipv1.1.*/
|
||||
* disabled.*/
|
||||
void setComparatorDisableTime(ns t, Positions pos = {});
|
||||
|
||||
/** [Jungfrau] Advanced TODO naming */
|
||||
@ -1382,7 +1385,7 @@ class Detector {
|
||||
Result<defs::timingInfoDecoder>
|
||||
getTimingInfoDecoder(Positions pos = {}) const;
|
||||
|
||||
/** [Jungfrau] Advanced Command! */
|
||||
/** [Jungfrau] Advanced Command! Only for pcb v2.0 */
|
||||
void setTimingInfoDecoder(defs::timingInfoDecoder value,
|
||||
Positions pos = {});
|
||||
|
||||
|
@ -1018,7 +1018,7 @@ std::string Caller::autocompdisable(int action) {
|
||||
// print help
|
||||
if (action == slsDetectorDefs::HELP_ACTION) {
|
||||
os << R"V0G0N([0, 1]
|
||||
[Jungfrau] Auto comparator disable mode. By default, the on-chip gain switching is active during the entire exposure.This mode disables the on - chip gain switching comparator automatically after 93.75% (only for chipv1.0) of exposure time (only for longer than 100us). It is possible to set the duration for chipv1.1 using compdisabletime command.
|
||||
[Jungfrau] Auto comparator disable mode. By default, the on-chip gain switching is active during the entire exposure.This mode disables the on - chip gain switching comparator automatically and the duration is set using compdisabletime command.
|
||||
Default is 0 or this mode disabled(comparator enabled throughout). 1 enables mode. 0 disables mode. )V0G0N"
|
||||
<< std::endl;
|
||||
return os.str();
|
||||
@ -2108,7 +2108,7 @@ std::string Caller::compdisabletime(int action) {
|
||||
// print help
|
||||
if (action == slsDetectorDefs::HELP_ACTION) {
|
||||
os << R"V0G0N([duration] [(optional unit) ns|us|ms|s]
|
||||
[Jungfrau] Time before end of exposure when comparator is disabled. It is only possible for chipv1.1. )V0G0N"
|
||||
[Jungfrau] Time before end of exposure when comparator is disabled. )V0G0N"
|
||||
<< std::endl;
|
||||
return os.str();
|
||||
}
|
||||
@ -14744,7 +14744,7 @@ std::string Caller::timing_info_decoder(int action) {
|
||||
// print help
|
||||
if (action == slsDetectorDefs::HELP_ACTION) {
|
||||
os << R"V0G0N([swissfel|shine]
|
||||
[Jungfrau] Advanced Command and only for Swissfel and Shine. Sets the bunch id or timing info decoder. Default is swissfel. )V0G0N"
|
||||
[Jungfrau] Advanced Command and only for Swissfel and Shine. Sets the bunch id or timing info decoder. Default is swissfel. Only allowed for pcbv2.0. )V0G0N"
|
||||
<< std::endl;
|
||||
return os.str();
|
||||
}
|
||||
@ -15365,7 +15365,7 @@ std::string Caller::txdelay(int action) {
|
||||
[Eiger][Jungfrau][Moench][Mythen3] Set transmission delay for all modules in the detector using the step size provided.Sets up
|
||||
[Eiger] txdelay_left to (2 * mod_index * n_delay),
|
||||
[Eiger] txdelay_right to ((2 * mod_index + 1) * n_delay) and
|
||||
[Eiger] txdelay_frame to (2 *num_modules * n_delay)
|
||||
[Eiger] txdelay_frame to (2 * num_modules * n_delay)
|
||||
[Jungfrau][Moench][Mythen3] txdelay_frame to (num_modules * n_delay) for every module. )V0G0N"
|
||||
<< std::endl;
|
||||
return os.str();
|
||||
|
@ -210,7 +210,12 @@ std::string Caller::hostname(int action) {
|
||||
os << "\n\tFrees shared memory and sets hostname (or IP address) of "
|
||||
"all modules concatenated by +.\n\t Virtual servers can already "
|
||||
"use the port in hostname separated by ':' and ports incremented "
|
||||
"by 2 to accomodate the stop server as well."
|
||||
"by 2 to accomodate the stop server as well. The row and column "
|
||||
"values in the udp/zmq header are affected by the order in this "
|
||||
"command and the detsize command. The modules are stacked row by "
|
||||
"row until they reach the y-axis limit set by detsize (if "
|
||||
"specified). Then, stacking continues in the next column and so "
|
||||
"on. This only affects row and column in udp/zmq header."
|
||||
<< '\n';
|
||||
} else if (action == defs::GET_ACTION) {
|
||||
if (!args.empty()) {
|
||||
|
@ -99,6 +99,12 @@ void Detector::loadParameters(const std::vector<std::string> ¶meters) {
|
||||
CmdParser parser;
|
||||
for (const auto ¤t_line : parameters) {
|
||||
parser.Parse(current_line);
|
||||
if (parser.multi_id() != 0) {
|
||||
throw RuntimeError(
|
||||
"Multi-detector indices [" + std::to_string(parser.multi_id()) +
|
||||
"] are not allowed in the file. Instead, use the index for "
|
||||
"'config' or 'parameters' command?");
|
||||
}
|
||||
caller.call(parser.command(), parser.arguments(), parser.detector_id(),
|
||||
defs::PUT_ACTION, std::cout, parser.receiver_id());
|
||||
}
|
||||
|
@ -1177,9 +1177,19 @@ int DetectorImpl::acquire() {
|
||||
if (dataReady == nullptr) {
|
||||
setJoinThreadFlag(true);
|
||||
} else if (receiver) {
|
||||
while (numZmqRunning != 0) {
|
||||
Parallel(&Module::restreamStopFromReceiver, {});
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
// wait for postprocessor to process dummies
|
||||
if (dataReady != nullptr) {
|
||||
// process dummy from stop receier
|
||||
if (numZmqRunning != 0)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
while (numZmqRunning != 0) {
|
||||
Parallel(&Module::restreamStopFromReceiver, {});
|
||||
// time to process restream dummy
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
// increase time for fewer dummies and to catch up
|
||||
if (numZmqRunning != 0)
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
dataProcessingThread.join();
|
||||
|
@ -905,8 +905,13 @@ void Module::startReceiver() {
|
||||
}
|
||||
|
||||
void Module::stopReceiver() {
|
||||
auto rxStatusPrior = getReceiverStatus();
|
||||
sendToReceiver(F_STOP_RECEIVER, static_cast<int>(shm()->stoppedFlag),
|
||||
nullptr);
|
||||
|
||||
if (rxStatusPrior == IDLE && getReceiverStreaming()) {
|
||||
restreamStopFromReceiver();
|
||||
}
|
||||
}
|
||||
|
||||
void Module::startAcquisition() {
|
||||
@ -920,26 +925,8 @@ void Module::startReadout() {
|
||||
}
|
||||
|
||||
void Module::stopAcquisition() {
|
||||
|
||||
// get det status before stopping acq
|
||||
runStatus detStatus = ERROR;
|
||||
try {
|
||||
detStatus = getRunStatus();
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
sendToDetectorStop(F_STOP_ACQUISITION);
|
||||
shm()->stoppedFlag = true;
|
||||
|
||||
// restream dummy header, if rxr streaming and det idle before stop
|
||||
try {
|
||||
if (shm()->useReceiverFlag && getReceiverStreaming()) {
|
||||
if (detStatus == IDLE && getReceiverStatus() == IDLE) {
|
||||
restreamStopFromReceiver();
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
void Module::restreamStopFromReceiver() {
|
||||
|
@ -262,8 +262,7 @@ TEST_CASE("compdisabletime", "[.cmdcall]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
auto det_type = det.getDetectorType().squash();
|
||||
if (det_type == defs::JUNGFRAU &&
|
||||
det.getChipVersion().squash() * 10 == 11) {
|
||||
if (det_type == defs::JUNGFRAU) {
|
||||
auto prev_val = det.getComparatorDisableTime();
|
||||
{
|
||||
std::ostringstream oss;
|
||||
@ -670,7 +669,8 @@ TEST_CASE("pedestalmode", "[.cmdcall]") {
|
||||
TEST_CASE("timing_info_decoder", "[.cmdcall]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
if (det.getDetectorType().squash() == defs::JUNGFRAU) {
|
||||
if (det.getDetectorType().squash() == defs::JUNGFRAU &&
|
||||
det.getHardwareVersion().squash() == "2.0") {
|
||||
auto prev_val = det.getTimingInfoDecoder();
|
||||
/*{
|
||||
std::ostringstream oss;
|
||||
|
@ -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});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3323,7 +3323,7 @@ TEST_CASE("reg", "[.cmdcall]") {
|
||||
addr = 0x80;
|
||||
}
|
||||
if (det_type == defs::GOTTHARD2) {
|
||||
addr = 0x20;
|
||||
addr = 0x298;
|
||||
}
|
||||
std::string saddr = ToStringHex(addr);
|
||||
auto prev_val = det.readRegister(addr);
|
||||
@ -3379,7 +3379,7 @@ TEST_CASE("setbit", "[.cmdcall]") {
|
||||
addr = 0x80;
|
||||
}
|
||||
if (det_type == defs::GOTTHARD2) {
|
||||
addr = 0x20;
|
||||
addr = 0x298;
|
||||
}
|
||||
std::string saddr = ToStringHex(addr);
|
||||
auto prev_val = det.readRegister(addr);
|
||||
@ -3409,7 +3409,7 @@ TEST_CASE("clearbit", "[.cmdcall]") {
|
||||
addr = 0x80;
|
||||
}
|
||||
if (det_type == defs::GOTTHARD2) {
|
||||
addr = 0x20;
|
||||
addr = 0x298;
|
||||
}
|
||||
std::string saddr = ToStringHex(addr);
|
||||
auto prev_val = det.readRegister(addr);
|
||||
@ -3439,7 +3439,7 @@ TEST_CASE("getbit", "[.cmdcall]") {
|
||||
addr = 0x80;
|
||||
}
|
||||
if (det_type == defs::GOTTHARD2) {
|
||||
addr = 0x20;
|
||||
addr = 0x298;
|
||||
}
|
||||
std::string saddr = ToStringHex(addr);
|
||||
auto prev_val = det.readRegister(addr);
|
||||
|
@ -138,13 +138,34 @@ if (SLS_USE_RECEIVER_BINARIES)
|
||||
slsProjectWarnings
|
||||
)
|
||||
|
||||
install(TARGETS slsReceiver slsMultiReceiver
|
||||
add_executable(slsFrameSynchronizer
|
||||
src/FrameSynchronizerApp.cpp
|
||||
)
|
||||
|
||||
set_target_properties(slsFrameSynchronizer PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
|
||||
)
|
||||
if((CMAKE_BUILD_TYPE STREQUAL "Release") AND SLS_LTO_AVAILABLE)
|
||||
set_property(TARGET slsFrameSynchronizer PROPERTY INTERPROCEDURAL_OPTIMIZATION True)
|
||||
endif()
|
||||
|
||||
target_link_libraries(slsFrameSynchronizer
|
||||
PUBLIC
|
||||
slsReceiverStatic
|
||||
pthread
|
||||
rt
|
||||
PRIVATE
|
||||
slsProjectWarnings
|
||||
"$<BUILD_INTERFACE:libzmq-static>"
|
||||
)
|
||||
|
||||
install(TARGETS slsReceiver slsMultiReceiver slsFrameSynchronizer
|
||||
EXPORT "${TARGETS_EXPORT_NAME}"
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sls
|
||||
)
|
||||
)
|
||||
|
||||
endif(SLS_USE_RECEIVER_BINARIES)
|
||||
|
||||
|
@ -33,6 +33,8 @@ using Interface = ServerInterface;
|
||||
#define gettid() syscall(SYS_gettid)
|
||||
#endif
|
||||
|
||||
std::mutex ClientInterface::callbackMutex;
|
||||
|
||||
ClientInterface::~ClientInterface() {
|
||||
killTcpThread = true;
|
||||
LOG(logINFO) << "Shutting down TCP Socket on port " << portNumber;
|
||||
@ -55,12 +57,14 @@ std::string ClientInterface::getReceiverVersion() { return APIRECEIVER; }
|
||||
/***callback functions***/
|
||||
void ClientInterface::registerCallBackStartAcquisition(
|
||||
int (*func)(const startCallbackHeader, void *), void *arg) {
|
||||
std::lock_guard<std::mutex> lock(callbackMutex);
|
||||
startAcquisitionCallBack = func;
|
||||
pStartAcquisition = arg;
|
||||
}
|
||||
|
||||
void ClientInterface::registerCallBackAcquisitionFinished(
|
||||
void (*func)(const endCallbackHeader, void *), void *arg) {
|
||||
std::lock_guard<std::mutex> lock(callbackMutex);
|
||||
acquisitionFinishedCallBack = func;
|
||||
pAcquisitionFinished = arg;
|
||||
}
|
||||
@ -69,6 +73,7 @@ void ClientInterface::registerCallBackRawDataReady(
|
||||
void (*func)(sls_receiver_header &, dataCallbackHeader, char *, size_t &,
|
||||
void *),
|
||||
void *arg) {
|
||||
std::lock_guard<std::mutex> lock(callbackMutex);
|
||||
rawDataReadyCallBack = func;
|
||||
pRawDataReady = arg;
|
||||
}
|
||||
@ -461,15 +466,18 @@ void ClientInterface::setDetectorType(detectorType arg) {
|
||||
std::string(e.what()) + ']');
|
||||
}
|
||||
// callbacks after (in setdetectortype, the object is reinitialized)
|
||||
if (startAcquisitionCallBack != nullptr)
|
||||
impl()->registerCallBackStartAcquisition(startAcquisitionCallBack,
|
||||
pStartAcquisition);
|
||||
if (acquisitionFinishedCallBack != nullptr)
|
||||
impl()->registerCallBackAcquisitionFinished(acquisitionFinishedCallBack,
|
||||
pAcquisitionFinished);
|
||||
if (rawDataReadyCallBack != nullptr)
|
||||
impl()->registerCallBackRawDataReady(rawDataReadyCallBack,
|
||||
pRawDataReady);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(callbackMutex);
|
||||
if (startAcquisitionCallBack != nullptr)
|
||||
impl()->registerCallBackStartAcquisition(startAcquisitionCallBack,
|
||||
pStartAcquisition);
|
||||
if (acquisitionFinishedCallBack != nullptr)
|
||||
impl()->registerCallBackAcquisitionFinished(
|
||||
acquisitionFinishedCallBack, pAcquisitionFinished);
|
||||
if (rawDataReadyCallBack != nullptr)
|
||||
impl()->registerCallBackRawDataReady(rawDataReadyCallBack,
|
||||
pRawDataReady);
|
||||
}
|
||||
|
||||
impl()->setThreadIds(parentThreadId, tcpThreadId);
|
||||
}
|
||||
|
@ -194,6 +194,8 @@ class ClientInterface : private virtual slsDetectorDefs {
|
||||
pid_t tcpThreadId{0};
|
||||
std::vector<std::string> udpips =
|
||||
std::vector<std::string>(MAX_NUMBER_OF_LISTENING_THREADS);
|
||||
// necessary if Receiver objects using threads with callbacks
|
||||
static std::mutex callbackMutex;
|
||||
};
|
||||
|
||||
} // namespace sls
|
||||
|
651
slsReceiverSoftware/src/FrameSynchronizerApp.cpp
Normal file
651
slsReceiverSoftware/src/FrameSynchronizerApp.cpp
Normal file
@ -0,0 +1,651 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
/* Creates the slsFrameSynchronizer for running multiple receivers in different
|
||||
* threads form a single binary that will spit out zmq streams without
|
||||
* reconstructing image. Sample python script for pull socket for this combiner
|
||||
* in python/scripts folder. TODO: Not handling empty frames from one socket
|
||||
*/
|
||||
#include "sls/Receiver.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/container_utils.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "sls/versionAPI.h"
|
||||
|
||||
#include <csignal> //SIGINT
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <ostream>
|
||||
#include <semaphore.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h> //wait
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <zmq.h>
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
std::vector<sem_t *> semaphores;
|
||||
sls::TLogLevel printHeadersLevel = sls::logDEBUG;
|
||||
|
||||
/** Define Colors to print data call back in different colors for different
|
||||
* recievers */
|
||||
#define PRINT_IN_COLOR(c, f, ...) \
|
||||
printf("\033[%dm" f RESET, 30 + c + 1, ##__VA_ARGS__)
|
||||
|
||||
/** Structure handling different threads */
|
||||
using ZmqMsgList = std::vector<zmq_msg_t *>;
|
||||
using FrameMap = std::map<uint64_t, ZmqMsgList>;
|
||||
using PortFrameMap = std::map<uint16_t, FrameMap>;
|
||||
struct FrameStatus {
|
||||
bool starting = true;
|
||||
bool terminate = false;
|
||||
int num_receivers;
|
||||
sem_t available;
|
||||
std::mutex mtx;
|
||||
ZmqMsgList headers;
|
||||
PortFrameMap frames;
|
||||
ZmqMsgList ends;
|
||||
|
||||
FrameStatus(bool start, bool term, int num_recv)
|
||||
: starting(start), terminate(term), num_receivers(num_recv) {
|
||||
sem_init(&available, 0, 0);
|
||||
}
|
||||
};
|
||||
FrameStatus *global_frame_status = nullptr;
|
||||
|
||||
/**
|
||||
* Control+C Interrupt Handler
|
||||
* to let all the processes know to exit properly
|
||||
*/
|
||||
void sigInterruptHandler(int p) {
|
||||
for (size_t i = 0; i != semaphores.size(); ++i) {
|
||||
sem_post(semaphores[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
if (global_frame_status) {
|
||||
std::lock_guard<std::mutex> lock(global_frame_status->mtx);
|
||||
for (auto &outer_pair : global_frame_status->frames) {
|
||||
for (auto &inner_pair : outer_pair.second) {
|
||||
for (zmq_msg_t *msg : inner_pair.second) {
|
||||
if (msg) {
|
||||
zmq_msg_close(msg);
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
inner_pair.second.clear();
|
||||
}
|
||||
outer_pair.second.clear();
|
||||
}
|
||||
global_frame_status->frames.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* prints usage of this example program
|
||||
*/
|
||||
std::string getHelpMessage() {
|
||||
std::ostringstream os;
|
||||
os << "\nUsage:\n"
|
||||
<< "./slsFrameSynchronizer --version or -v\n"
|
||||
<< "\t - Gets the slsFrameSynchronizer version\n\n"
|
||||
<< "./slsFrameSynchronizer [start tcp port] [num recevers] [print "
|
||||
"callback headers (optional)]\n"
|
||||
<< "\t - tcp port has to be non-zero and 16 bit\n"
|
||||
<< "\t - print callback headers option is 0 (disabled) by default\n";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
void zmq_free(void *data, void *hint) { delete[] static_cast<char *>(data); }
|
||||
|
||||
void print_frames(const PortFrameMap &frame_port_map) {
|
||||
LOG(sls::logDEBUG) << "Printing frames";
|
||||
for (const auto &it : frame_port_map) {
|
||||
const uint16_t udpPort = it.first;
|
||||
const auto &frame_map = it.second;
|
||||
LOG(sls::logDEBUG) << "UDP port: " << udpPort;
|
||||
for (const auto &frame : frame_map) {
|
||||
const uint64_t fnum = frame.first;
|
||||
const auto &msg_list = frame.second;
|
||||
LOG(sls::logDEBUG)
|
||||
<< " acq index: " << fnum << '[' << msg_list.size() << ']';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Valid frame numbers mean they exist across all ports or
|
||||
* has at least a larger fnum in the port with the missing fnum **/
|
||||
std::set<uint64_t> get_valid_fnums(const PortFrameMap &port_frame_map) {
|
||||
// empty list
|
||||
std::set<uint64_t> valid_fnums;
|
||||
if (port_frame_map.empty()) {
|
||||
return valid_fnums;
|
||||
}
|
||||
|
||||
// collect all unique frame numbers from all ports
|
||||
std::set<uint64_t> unique_fnums;
|
||||
for (const auto &it : port_frame_map) {
|
||||
const FrameMap &frame_map = it.second;
|
||||
for (const auto &frame : frame_map) {
|
||||
unique_fnums.insert(frame.first);
|
||||
}
|
||||
}
|
||||
|
||||
// collect valid frame numbers
|
||||
for (auto &fnum : unique_fnums) {
|
||||
bool is_valid = true;
|
||||
for (const auto &it : port_frame_map) {
|
||||
const uint16_t port = it.first;
|
||||
const FrameMap &frame_map = it.second;
|
||||
auto frame = frame_map.find(fnum);
|
||||
// invalid: fnum missing in one port
|
||||
if (frame == frame_map.end()) {
|
||||
LOG(sls::logDEBUG)
|
||||
<< "Fnum " << fnum << " is missing in port " << port;
|
||||
auto upper_frame = frame_map.upper_bound(fnum);
|
||||
if (upper_frame == frame_map.end()) {
|
||||
LOG(sls::logDEBUG) << "And no larger fnum found. Fnum "
|
||||
<< fnum << " is invalid.\n";
|
||||
is_valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_valid) {
|
||||
valid_fnums.insert(fnum);
|
||||
}
|
||||
}
|
||||
|
||||
return valid_fnums;
|
||||
}
|
||||
|
||||
int zmq_send_multipart(void *socket, const ZmqMsgList &messages) {
|
||||
size_t num_messages = messages.size();
|
||||
for (size_t i = 0; i != num_messages; ++i) {
|
||||
zmq_msg_t *msg = messages[i];
|
||||
// determine flags: ZMQ_SNDMORE for all messages except the last
|
||||
int flags = (i == num_messages - 1) ? 0 : ZMQ_SNDMORE;
|
||||
if (zmq_msg_send(msg, socket, flags) == -1) {
|
||||
LOG(sls::logERROR)
|
||||
<< "Error sending message: " << zmq_strerror(zmq_errno());
|
||||
return slsDetectorDefs::FAIL;
|
||||
}
|
||||
}
|
||||
return slsDetectorDefs::OK;
|
||||
}
|
||||
|
||||
void Correlate(FrameStatus *stat) {
|
||||
void *context = zmq_ctx_new();
|
||||
|
||||
void *socket = zmq_socket(context, ZMQ_PUSH);
|
||||
int rc = zmq_bind(socket, "tcp://*:5555");
|
||||
if (rc != 0) {
|
||||
LOG(sls::logERROR) << "failed to bind";
|
||||
}
|
||||
|
||||
while (true) {
|
||||
sem_wait(&(stat->available));
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(stat->mtx);
|
||||
|
||||
if (stat->terminate) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (stat->starting) {
|
||||
// sending all start packets
|
||||
if (static_cast<int>(stat->headers.size()) ==
|
||||
stat->num_receivers) {
|
||||
stat->starting = false;
|
||||
// clean up
|
||||
zmq_send_multipart(socket, stat->headers);
|
||||
for (zmq_msg_t *msg : stat->headers) {
|
||||
if (msg) {
|
||||
zmq_msg_close(msg);
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
stat->headers.clear();
|
||||
}
|
||||
} else {
|
||||
// print_frames(stat->frames);
|
||||
auto valid_fnums = get_valid_fnums(stat->frames);
|
||||
// sending all valid fnum data packets
|
||||
for (const auto &fnum : valid_fnums) {
|
||||
ZmqMsgList msg_list;
|
||||
for (const auto &it : stat->frames) {
|
||||
const uint16_t port = it.first;
|
||||
const FrameMap &frame_map = it.second;
|
||||
auto frame = frame_map.find(fnum);
|
||||
if (frame != frame_map.end()) {
|
||||
msg_list.insert(msg_list.end(),
|
||||
stat->frames[port][fnum].begin(),
|
||||
stat->frames[port][fnum].end());
|
||||
}
|
||||
}
|
||||
LOG(printHeadersLevel)
|
||||
<< "Sending data packets for fnum " << fnum;
|
||||
zmq_send_multipart(socket, msg_list);
|
||||
// clean up
|
||||
for (const auto &it : stat->frames) {
|
||||
const uint16_t port = it.first;
|
||||
const FrameMap &frame_map = it.second;
|
||||
auto frame = frame_map.find(fnum);
|
||||
if (frame != frame_map.end()) {
|
||||
for (zmq_msg_t *msg : frame->second) {
|
||||
if (msg) {
|
||||
zmq_msg_close(msg);
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
stat->frames[port].erase(fnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// sending all end packets
|
||||
if (static_cast<int>(stat->ends.size()) == stat->num_receivers) {
|
||||
zmq_send_multipart(socket, stat->ends);
|
||||
// clean up
|
||||
for (zmq_msg_t *msg : stat->ends) {
|
||||
if (msg) {
|
||||
zmq_msg_close(msg);
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
zmq_close(socket);
|
||||
zmq_ctx_destroy(context);
|
||||
}
|
||||
|
||||
int StartAcquisitionCallback(
|
||||
const slsDetectorDefs::startCallbackHeader callbackHeader,
|
||||
void *objectPointer) {
|
||||
LOG(printHeadersLevel)
|
||||
<< "Start Acquisition:"
|
||||
<< "\n\t["
|
||||
<< "\n\tUDP Port : " << sls::ToString(callbackHeader.udpPort)
|
||||
<< "\n\tDynamic Range : " << callbackHeader.dynamicRange
|
||||
<< "\n\tDetector Shape : "
|
||||
<< sls::ToString(callbackHeader.detectorShape)
|
||||
<< "\n\tImage Size : " << callbackHeader.imageSize
|
||||
<< "\n\tFile Path : " << callbackHeader.filePath
|
||||
<< "\n\tFile Name : " << callbackHeader.fileName
|
||||
<< "\n\tFile Index : " << callbackHeader.fileIndex
|
||||
<< "\n\tQuad Enable : " << callbackHeader.quad
|
||||
<< "\n\tAdditional Json Header : "
|
||||
<< sls::ToString(callbackHeader.addJsonHeader).c_str() << "\n\t]";
|
||||
std::ostringstream oss;
|
||||
oss << "{\"htype\":\"header\""
|
||||
<< ", \"udpPorts\":" << sls::ToString(callbackHeader.udpPort)
|
||||
<< ", \"bitmode\":" << callbackHeader.dynamicRange
|
||||
<< ", \"filePath\":\"" << callbackHeader.filePath
|
||||
<< "\", \"fileName\":\"" << callbackHeader.fileName
|
||||
<< "\", \"fileIndex\":" << callbackHeader.fileIndex
|
||||
<< ", \"detshape\":" << sls::ToString(callbackHeader.detectorShape)
|
||||
<< ", \"size\":" << callbackHeader.imageSize
|
||||
<< ", \"quad\":" << (callbackHeader.quad ? 1 : 0);
|
||||
|
||||
if (!callbackHeader.addJsonHeader.empty()) {
|
||||
oss << ", \"addJsonHeader\": {";
|
||||
for (auto it = callbackHeader.addJsonHeader.begin();
|
||||
it != callbackHeader.addJsonHeader.end(); ++it) {
|
||||
if (it != callbackHeader.addJsonHeader.begin()) {
|
||||
oss << ", ";
|
||||
}
|
||||
oss << "\"" << it->first.c_str() << "\":\"" << it->second.c_str()
|
||||
<< "\"";
|
||||
}
|
||||
oss << " } ";
|
||||
}
|
||||
oss << "}\n";
|
||||
|
||||
std::string message = oss.str();
|
||||
LOG(sls::logDEBUG) << "Start Acquisition message:" << std::endl << message;
|
||||
|
||||
int length = message.length();
|
||||
char *hdata = new char[length];
|
||||
memcpy(hdata, message.c_str(), length);
|
||||
zmq_msg_t *hmsg = new zmq_msg_t;
|
||||
zmq_msg_init_data(hmsg, hdata, length, zmq_free, NULL);
|
||||
|
||||
// push zmq msg into stat to be processed
|
||||
FrameStatus *stat = static_cast<FrameStatus *>(objectPointer);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(stat->mtx);
|
||||
stat->headers.push_back(hmsg);
|
||||
stat->starting = true;
|
||||
// clean up old frames
|
||||
for (int port : callbackHeader.udpPort) {
|
||||
for (auto &frame_map : stat->frames[port]) {
|
||||
for (zmq_msg_t *msg : frame_map.second) {
|
||||
if (msg) {
|
||||
zmq_msg_close(msg);
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
frame_map.second.clear();
|
||||
}
|
||||
stat->frames[port].clear();
|
||||
}
|
||||
}
|
||||
sem_post(&stat->available);
|
||||
return slsDetectorDefs::OK; // TODO: change return to void
|
||||
}
|
||||
|
||||
void AcquisitionFinishedCallback(
|
||||
const slsDetectorDefs::endCallbackHeader callbackHeader,
|
||||
void *objectPointer) {
|
||||
LOG(printHeadersLevel) << "Acquisition Finished:"
|
||||
<< "\n\t["
|
||||
<< "\n\tUDP Port : "
|
||||
<< sls::ToString(callbackHeader.udpPort)
|
||||
<< "\n\tComplete Frames : "
|
||||
<< sls::ToString(callbackHeader.completeFrames)
|
||||
<< "\n\tLast Frame Index : "
|
||||
<< sls::ToString(callbackHeader.lastFrameIndex)
|
||||
<< "\n\t]";
|
||||
std::ostringstream oss;
|
||||
oss << "{\"htype\":\"series_end\""
|
||||
<< ", \"udpPorts\":" << sls::ToString(callbackHeader.udpPort)
|
||||
<< ", \"comleteFrames\":"
|
||||
<< sls::ToString(callbackHeader.completeFrames)
|
||||
<< ", \"lastFrameIndex\":"
|
||||
<< sls::ToString(callbackHeader.lastFrameIndex) << "}\n";
|
||||
std::string message = oss.str();
|
||||
int length = message.length();
|
||||
LOG(sls::logDEBUG) << "Acquisition Finished message:" << std::endl
|
||||
<< message;
|
||||
|
||||
char *hdata = new char[length];
|
||||
memcpy(hdata, message.c_str(), length);
|
||||
zmq_msg_t *hmsg = new zmq_msg_t;
|
||||
zmq_msg_init_data(hmsg, hdata, length, zmq_free, NULL);
|
||||
|
||||
// push zmq msg into stat to be processed
|
||||
FrameStatus *stat = static_cast<FrameStatus *>(objectPointer);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(stat->mtx);
|
||||
stat->ends.push_back(hmsg);
|
||||
}
|
||||
sem_post(&stat->available);
|
||||
}
|
||||
|
||||
void GetDataCallback(slsDetectorDefs::sls_receiver_header &header,
|
||||
slsDetectorDefs::dataCallbackHeader callbackHeader,
|
||||
char *dataPointer, size_t &imageSize,
|
||||
void *objectPointer) {
|
||||
|
||||
slsDetectorDefs::sls_detector_header detectorHeader = header.detHeader;
|
||||
|
||||
if (printHeadersLevel < sls::logDEBUG) {
|
||||
// print in different color for each udp port
|
||||
PRINT_IN_COLOR((callbackHeader.udpPort % 10),
|
||||
"Data: "
|
||||
"\n\tCallback Header: "
|
||||
"\n\t["
|
||||
"\n\tUDP Port: %u"
|
||||
"\n\tShape: [%u, %u]"
|
||||
"\n\tAcq Index : %lu"
|
||||
"\n\tFrame Index :%lu"
|
||||
"\n\tProgress : %.2f%%"
|
||||
"\n\tComplete Image :%s"
|
||||
"\n\tFlip Rows :%s"
|
||||
"\n\tAdditional Json Header : %s"
|
||||
"\n\t]"
|
||||
"\n\ttReceiver Header: "
|
||||
"\n\t["
|
||||
"\n\tFrame Number : %lu"
|
||||
"\n\tExposure Length :%u"
|
||||
"\n\tPackets Caught :%u"
|
||||
"\n\tDetector Specific 1: %lu"
|
||||
"\n\tTimestamp : %lu"
|
||||
"\n\tModule Id :%u"
|
||||
"\n\tRow : %u"
|
||||
"\n\tColumn :%u"
|
||||
"\n\tDetector Specific 2 : %u"
|
||||
"\n\tDetector Specific 3 : %u"
|
||||
"\n\tDetector Specific 4 : %u"
|
||||
"\n\tDetector Type : %s"
|
||||
"\n\tVersion: %u"
|
||||
"\n\t]"
|
||||
"\n\tFirst Byte Data: 0x%x"
|
||||
"\n\tImage Size: %zu\n\n",
|
||||
callbackHeader.udpPort, callbackHeader.shape.x,
|
||||
callbackHeader.shape.y, callbackHeader.acqIndex,
|
||||
callbackHeader.frameIndex, callbackHeader.progress,
|
||||
sls::ToString(callbackHeader.completeImage).c_str(),
|
||||
sls::ToString(callbackHeader.flipRows).c_str(),
|
||||
sls::ToString(callbackHeader.addJsonHeader).c_str(),
|
||||
detectorHeader.frameNumber, detectorHeader.expLength,
|
||||
detectorHeader.packetNumber, detectorHeader.detSpec1,
|
||||
detectorHeader.timestamp, detectorHeader.modId,
|
||||
detectorHeader.row, detectorHeader.column,
|
||||
detectorHeader.detSpec2, detectorHeader.detSpec3,
|
||||
detectorHeader.detSpec4,
|
||||
sls::ToString(detectorHeader.detType).c_str(),
|
||||
detectorHeader.version,
|
||||
// header->packetsMask.to_string().c_str(),
|
||||
((uint8_t)(*((uint8_t *)(dataPointer)))), imageSize);
|
||||
}
|
||||
std::ostringstream oss;
|
||||
oss << "{\"htype\":\"module\""
|
||||
<< ", \"port\":" << callbackHeader.udpPort
|
||||
<< ", \"shape\":" << sls::ToString(callbackHeader.shape)
|
||||
<< ", \"acqIndex\":" << callbackHeader.acqIndex
|
||||
<< ", \"frameIndex\":" << callbackHeader.frameIndex
|
||||
<< ", \"flipRows\":" << (callbackHeader.flipRows ? 1 : 0)
|
||||
<< ", \"progress\":" << callbackHeader.progress
|
||||
<< ", \"completeImage\":" << (callbackHeader.completeImage ? 1 : 0)
|
||||
<< ", \"imageSize\":" << imageSize
|
||||
<< ", \"frameNumber\":" << detectorHeader.frameNumber
|
||||
<< ", \"expLength\":" << detectorHeader.expLength
|
||||
<< ", \"packetNumber\":" << detectorHeader.packetNumber
|
||||
<< ", \"detSpec1\":" << detectorHeader.detSpec1
|
||||
<< ", \"timestamp\":" << detectorHeader.timestamp
|
||||
<< ", \"modId\":" << detectorHeader.modId
|
||||
<< ", \"row\":" << detectorHeader.row
|
||||
<< ", \"column\":" << detectorHeader.column
|
||||
<< ", \"detSpec2\":" << detectorHeader.detSpec2
|
||||
<< ", \"detSpec3\":" << detectorHeader.detSpec3
|
||||
<< ", \"detSpec4\":" << detectorHeader.detSpec4
|
||||
<< ", \"detType\":" << static_cast<int>(detectorHeader.detType)
|
||||
<< ", \"version\":" << static_cast<int>(detectorHeader.version);
|
||||
|
||||
if (!callbackHeader.addJsonHeader.empty()) {
|
||||
oss << ", \"addJsonHeader\": {";
|
||||
for (auto it = callbackHeader.addJsonHeader.begin();
|
||||
it != callbackHeader.addJsonHeader.end(); ++it) {
|
||||
if (it != callbackHeader.addJsonHeader.begin()) {
|
||||
oss << ", ";
|
||||
}
|
||||
oss << "\"" << it->first.c_str() << "\":\"" << it->second.c_str()
|
||||
<< "\"";
|
||||
}
|
||||
oss << " } ";
|
||||
}
|
||||
oss << "}\n";
|
||||
std::string message = oss.str();
|
||||
LOG(sls::logDEBUG) << "Data message:" << std::endl << message;
|
||||
|
||||
// creating header part of data packet
|
||||
int length = message.length();
|
||||
char *hdata = new char[length];
|
||||
memcpy(hdata, message.c_str(), length);
|
||||
zmq_msg_t *hmsg = new zmq_msg_t;
|
||||
zmq_msg_init_data(hmsg, hdata, length, zmq_free, NULL);
|
||||
|
||||
// created data part of data packet
|
||||
char *data = new char[imageSize];
|
||||
zmq_msg_t *msg = new zmq_msg_t;
|
||||
zmq_msg_init_data(msg, data, imageSize, zmq_free, NULL);
|
||||
|
||||
// push both parts into stat to be processed
|
||||
FrameStatus *stat = static_cast<FrameStatus *>(objectPointer);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(stat->mtx);
|
||||
stat->frames[callbackHeader.udpPort][header.detHeader.frameNumber]
|
||||
.push_back(hmsg);
|
||||
stat->frames[callbackHeader.udpPort][header.detHeader.frameNumber]
|
||||
.push_back(msg);
|
||||
}
|
||||
sem_post(&stat->available);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example of main program using the Receiver class
|
||||
*
|
||||
* - Defines in file for:
|
||||
* - Default Number of receivers is 1
|
||||
* - Default Start TCP port is 1954
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// version
|
||||
if (argc == 2) {
|
||||
std::string sargv1 = std::string(argv[1]);
|
||||
if (sargv1 == "--version" || sargv1 == "-v") {
|
||||
std::cout << "slsFrameSynchronizer Version: " << APIRECEIVER
|
||||
<< std::endl;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
/** - set default values */
|
||||
int numReceivers = 1;
|
||||
uint16_t startTCPPort = DEFAULT_TCP_RX_PORTNO;
|
||||
bool printHeaders = false;
|
||||
|
||||
/** - get number of receivers and start tcp port from command line
|
||||
* arguments */
|
||||
if (argc > 1) {
|
||||
try {
|
||||
if (argc == 3 || argc == 4) {
|
||||
startTCPPort = sls::StringTo<uint16_t>(argv[1]);
|
||||
if (startTCPPort == 0) {
|
||||
throw std::runtime_error("Invalid start tcp port");
|
||||
}
|
||||
numReceivers = std::stoi(argv[2]);
|
||||
if (numReceivers > 1024) {
|
||||
cprintf(RED,
|
||||
"Did you mix up the order of the arguments?\n%s\n",
|
||||
getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (numReceivers == 0) {
|
||||
cprintf(RED, "Invalid number of receivers.\n%s\n",
|
||||
getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (argc == 4) {
|
||||
printHeaders = sls::StringTo<bool>(argv[3]);
|
||||
if (printHeaders) {
|
||||
printHeadersLevel = sls::logINFOBLUE;
|
||||
}
|
||||
}
|
||||
} else
|
||||
throw std::runtime_error("Invalid number of arguments");
|
||||
} catch (const std::exception &e) {
|
||||
cprintf(RED, "Error: %s\n%s\n", e.what(), getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
cprintf(RESET, "Number of Receivers: %d\n", numReceivers);
|
||||
cprintf(RESET, "Start TCP Port: %hu\n", startTCPPort);
|
||||
cprintf(RESET, "Print Callback Headers: %s\n\n",
|
||||
(printHeaders ? "Enabled" : "Disabled"));
|
||||
|
||||
/** - Catch signal SIGINT to close files and call destructors properly */
|
||||
struct sigaction sa;
|
||||
sa.sa_flags = 0; // no flags
|
||||
sa.sa_handler = sigInterruptHandler; // handler function
|
||||
sigemptyset(&sa.sa_mask); // dont block additional signals during invocation
|
||||
// of handler
|
||||
if (sigaction(SIGINT, &sa, nullptr) == -1) {
|
||||
cprintf(RED, "Could not set handler function for SIGINT\n");
|
||||
}
|
||||
|
||||
/** - Ignore SIG_PIPE, prevents global signal handler, handle locally,
|
||||
instead of a server crashing due to client crash when writing, it just
|
||||
gives error */
|
||||
struct sigaction asa;
|
||||
asa.sa_flags = 0; // no flags
|
||||
asa.sa_handler = SIG_IGN; // handler function
|
||||
sigemptyset(&asa.sa_mask); // dont block additional signals during
|
||||
// invocation of handler
|
||||
if (sigaction(SIGPIPE, &asa, nullptr) == -1) {
|
||||
cprintf(RED, "Could not set handler function for SIGPIPE\n");
|
||||
}
|
||||
|
||||
FrameStatus stat{true, false, numReceivers};
|
||||
// store pointer for signal handler
|
||||
global_frame_status = &stat;
|
||||
|
||||
// thread synchronizing all packets
|
||||
void *user_data = static_cast<void *>(&stat);
|
||||
std::thread combinerThread(Correlate, &stat);
|
||||
|
||||
for (int i = 0; i != numReceivers; ++i) {
|
||||
sem_t *semaphore = new sem_t;
|
||||
sem_init(semaphore, 1, 0);
|
||||
semaphores.push_back(semaphore);
|
||||
|
||||
uint16_t port = startTCPPort + i;
|
||||
threads.emplace_back([i, semaphore, port, user_data]() {
|
||||
sls::Receiver receiver(port);
|
||||
receiver.registerCallBackStartAcquisition(StartAcquisitionCallback,
|
||||
user_data);
|
||||
receiver.registerCallBackAcquisitionFinished(
|
||||
AcquisitionFinishedCallback, user_data);
|
||||
receiver.registerCallBackRawDataReady(GetDataCallback, user_data);
|
||||
/** - as long as no Ctrl+C */
|
||||
sem_wait(semaphore);
|
||||
sem_destroy(semaphore);
|
||||
delete semaphore;
|
||||
|
||||
// clean up frames
|
||||
if (i == 0)
|
||||
cleanup();
|
||||
});
|
||||
}
|
||||
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(stat.mtx);
|
||||
stat.terminate = true;
|
||||
sem_post(&stat.available);
|
||||
}
|
||||
combinerThread.join();
|
||||
sem_destroy(&stat.available);
|
||||
|
||||
LOG(sls::logINFOBLUE) << "Goodbye!";
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -149,12 +149,12 @@ void Listener::CreateUDPSocket(int &actualSize) {
|
||||
packetSize = generalData->vetoPacketSize;
|
||||
}
|
||||
|
||||
std::string ip =
|
||||
(eth.length() ? InterfaceNameToIp(eth).str().c_str() : "");
|
||||
|
||||
std::string ip;
|
||||
if (eth.length() > 0)
|
||||
ip = InterfaceNameToIp(eth).str();
|
||||
udpSocket = nullptr;
|
||||
udpSocket = make_unique<UdpRxSocket>(
|
||||
udpPortNumber, packetSize, (ip.length() ? ip.c_str() : nullptr),
|
||||
udpPortNumber, packetSize, (ip.empty() ? nullptr : ip.c_str()),
|
||||
generalData->udpSocketBufferSize);
|
||||
LOG(logINFO) << index << ": UDP port opened at port " << udpPortNumber
|
||||
<< " (" << (ip.length() ? ip : "any") << ')';
|
||||
@ -213,10 +213,13 @@ void Listener::CreateDummySocketForUDPSocketBufferSize(int s, int &actualSize) {
|
||||
try {
|
||||
// to allowe ports to be bound from udpsocket
|
||||
udpSocket.reset();
|
||||
UdpRxSocket g(
|
||||
udpPortNumber, packetSize,
|
||||
(eth.length() ? InterfaceNameToIp(eth).str().c_str() : nullptr),
|
||||
generalData->udpSocketBufferSize);
|
||||
|
||||
std::string ip;
|
||||
if (eth.length() > 0)
|
||||
ip = InterfaceNameToIp(eth).str();
|
||||
UdpRxSocket g(udpPortNumber, packetSize,
|
||||
(ip.empty() ? nullptr : ip.c_str()),
|
||||
generalData->udpSocketBufferSize);
|
||||
|
||||
// doubled due to kernel bookkeeping (could also be less due to
|
||||
// permissions)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "sls/container_utils.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "sls/versionAPI.h"
|
||||
|
||||
#include <csignal> //SIGINT
|
||||
#include <cstring>
|
||||
@ -39,7 +40,9 @@ void sigInterruptHandler(int p) { sem_post(&semaphore); }
|
||||
*/
|
||||
std::string getHelpMessage() {
|
||||
std::ostringstream os;
|
||||
os << "\nUsage:\n"
|
||||
os << "\nUsage:\n\n"
|
||||
<< "./slsMultiReceiver --version or -v\n"
|
||||
<< "\t - Gets the slsMultiReceiver version\n\n"
|
||||
<< "./slsMultiReceiver [start tcp port] [num recevers] [call back "
|
||||
"option (optional)]\n"
|
||||
<< "\t - tcp port has to be non-zero and 16 bit\n"
|
||||
@ -147,8 +150,21 @@ void GetData(slsDetectorDefs::sls_receiver_header &header,
|
||||
// header->packetsMask.to_string().c_str(),
|
||||
((uint8_t)(*((uint8_t *)(dataPointer)))), imageSize);
|
||||
|
||||
// if data is modified, eg ROI and size is reduced
|
||||
imageSize = 26000;
|
||||
// // example of how to use roi or modify data that is later written to file
|
||||
// slsDetectorDefs::ROI roi{0, 10, 0, 20};
|
||||
// int width = roi.xmax - roi.xmin;
|
||||
// int height = roi.ymax - roi.ymin;
|
||||
// uint8_t *destPtr = (uint8_t *)dataPointer;
|
||||
// for (int irow = roi.ymin; irow < roi.ymax; ++irow) {
|
||||
// memcpy(destPtr,
|
||||
// ((uint8_t *)(dataPointer + irow * callbackHeader.shape.x +
|
||||
// roi.xmin)),
|
||||
// width);
|
||||
// destPtr += width;
|
||||
// }
|
||||
// memcpy((uint8_t*)dataPointer, (uint8_t*)dataPointer
|
||||
// // setting roi for eg. changes size
|
||||
// imageSize = width * height;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,6 +176,16 @@ void GetData(slsDetectorDefs::sls_receiver_header &header,
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// version
|
||||
if (argc == 2) {
|
||||
std::string sargv1 = std::string(argv[1]);
|
||||
if (sargv1 == "--version" || sargv1 == "-v") {
|
||||
std::cout << "slsMultiReceiver Version: " << APIRECEIVER
|
||||
<< std::endl;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
/** - set default values */
|
||||
int numReceivers = 1;
|
||||
uint16_t startTCPPort = DEFAULT_TCP_RX_PORTNO;
|
||||
@ -242,40 +268,43 @@ int main(int argc, char *argv[]) {
|
||||
else if (pid == 0) {
|
||||
cprintf(BLUE, "Child process %d [ Tid: %ld ]\n", i, (long)gettid());
|
||||
|
||||
std::unique_ptr<sls::Receiver> receiver = nullptr;
|
||||
try {
|
||||
receiver = sls::make_unique<sls::Receiver>(startTCPPort + i);
|
||||
uint16_t port = startTCPPort + i;
|
||||
sls::Receiver receiver(port);
|
||||
|
||||
/** - register callbacks. remember to set file write enable
|
||||
* to 0 (using the client) if we should not write files and you
|
||||
* will write data using the callbacks */
|
||||
if (withCallback) {
|
||||
|
||||
/** - Call back for start acquisition */
|
||||
cprintf(BLUE, "Registering StartAcq()\n");
|
||||
receiver.registerCallBackStartAcquisition(StartAcq,
|
||||
nullptr);
|
||||
|
||||
/** - Call back for acquisition finished */
|
||||
cprintf(BLUE, "Registering AcquisitionFinished()\n");
|
||||
receiver.registerCallBackAcquisitionFinished(
|
||||
AcquisitionFinished, nullptr);
|
||||
|
||||
/* - Call back for raw data */
|
||||
cprintf(BLUE, "Registering GetData() \n");
|
||||
receiver.registerCallBackRawDataReady(GetData, nullptr);
|
||||
}
|
||||
|
||||
/** - as long as no Ctrl+C */
|
||||
sem_wait(&semaphore);
|
||||
sem_destroy(&semaphore);
|
||||
|
||||
} catch (...) {
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Exiting Child Process [ Tid: " << gettid() << " ]";
|
||||
throw;
|
||||
}
|
||||
/** - register callbacks. remember to set file write enable to 0
|
||||
* (using the client) if we should not write files and you will
|
||||
* write data using the callbacks */
|
||||
if (withCallback) {
|
||||
|
||||
/** - Call back for start acquisition */
|
||||
cprintf(BLUE, "Registering StartAcq()\n");
|
||||
receiver->registerCallBackStartAcquisition(StartAcq, nullptr);
|
||||
|
||||
/** - Call back for acquisition finished */
|
||||
cprintf(BLUE, "Registering AcquisitionFinished()\n");
|
||||
receiver->registerCallBackAcquisitionFinished(
|
||||
AcquisitionFinished, nullptr);
|
||||
|
||||
/* - Call back for raw data */
|
||||
cprintf(BLUE, "Registering GetData() \n");
|
||||
receiver->registerCallBackRawDataReady(GetData, nullptr);
|
||||
}
|
||||
|
||||
/** - as long as no Ctrl+C */
|
||||
sem_wait(&semaphore);
|
||||
sem_destroy(&semaphore);
|
||||
cprintf(BLUE, "Exiting Child Process [ Tid: %ld ]\n",
|
||||
(long)gettid());
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ Receiver::Receiver(int argc, char *argv[]) : tcpipInterface(nullptr) {
|
||||
"\t started with privileges. \n\n";
|
||||
|
||||
while (c != -1) {
|
||||
c = getopt_long(argc, argv, "hvf:t:u:", long_options, &option_index);
|
||||
c = getopt_long(argc, argv, "hvt:u:", long_options, &option_index);
|
||||
|
||||
// Detect the end of the options.
|
||||
if (c == -1)
|
||||
@ -87,7 +87,7 @@ Receiver::Receiver(int argc, char *argv[]) : tcpipInterface(nullptr) {
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
std::cout << "SLS Receiver Version: " << APIRECEIVER << std::endl;
|
||||
std::cout << "slsReceiver Version: " << APIRECEIVER << std::endl;
|
||||
LOG(logINFOBLUE) << "Exiting [ Tid: " << gettid() << " ]";
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -16,6 +16,8 @@ enum TLogLevel {
|
||||
logINFOBLUE,
|
||||
logINFOGREEN,
|
||||
logINFORED,
|
||||
logINFOCYAN,
|
||||
logINFOMAGENTA,
|
||||
logINFO,
|
||||
logDEBUG,
|
||||
logDEBUG1,
|
||||
@ -60,16 +62,25 @@ class Logger {
|
||||
// Danger this buffer need as many elements as TLogLevel
|
||||
static const char *Color(TLogLevel level) noexcept {
|
||||
static const char *const colors[] = {
|
||||
RED BOLD, YELLOW BOLD, BLUE, GREEN, RED, RESET,
|
||||
RESET, RESET, RESET, RESET, RESET, RESET};
|
||||
RED BOLD, YELLOW BOLD, BLUE, GREEN, RED, CYAN, MAGENTA,
|
||||
RESET, RESET, RESET, RESET, RESET, RESET, RESET};
|
||||
// out of bounds
|
||||
if (level < 0 || level >= sizeof(colors) / sizeof(colors[0])) {
|
||||
return RESET;
|
||||
}
|
||||
return colors[level];
|
||||
}
|
||||
|
||||
// Danger this buffer need as many elements as TLogLevel
|
||||
static std::string ToString(TLogLevel level) {
|
||||
static const char *const buffer[] = {
|
||||
"ERROR", "WARNING", "INFO", "INFO", "INFO", "INFO",
|
||||
"DEBUG", "DEBUG1", "DEBUG2", "DEBUG3", "DEBUG4", "DEBUG5"};
|
||||
"ERROR", "WARNING", "INFO", "INFO", "INFO",
|
||||
"INFO", "INFO", "INFO", "DEBUG", "DEBUG1",
|
||||
"DEBUG2", "DEBUG3", "DEBUG4", "DEBUG5"};
|
||||
// out of bounds
|
||||
if (level < 0 || level >= sizeof(buffer) / sizeof(buffer[0])) {
|
||||
return "UNKNOWN";
|
||||
}
|
||||
return buffer[level];
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
/** API versions */
|
||||
#define APICTB "developer 0x241107"
|
||||
#define APIGOTTHARD "developer 0x241107"
|
||||
#define APIGOTTHARD2 "developer 0x241107"
|
||||
#define APIMOENCH "developer 0x241107"
|
||||
#define APIXILINXCTB "developer 0x241107"
|
||||
#define APIEIGER "developer 0x241107"
|
||||
#define APIJUNGFRAU "developer 0x241120"
|
||||
#define APIMYTHEN3 "developer 0x241121"
|
||||
#define APILIB "developer 0x241122"
|
||||
#define APIRECEIVER "developer 0x241122"
|
||||
#define APIGOTTHARD "9.0.0 0x241121"
|
||||
#define APIGOTTHARD2 "9.0.0 0x241121"
|
||||
#define APIMOENCH "9.0.0 0x241121"
|
||||
#define APIEIGER "9.0.0 0x241121"
|
||||
#define APICTB "9.1.0 0x250204"
|
||||
#define APIXILINXCTB "9.1.0 0x250204"
|
||||
#define APIJUNGFRAU "9.1.0 0x250318"
|
||||
#define APILIB "9.1.0 0x250325"
|
||||
#define APIMYTHEN3 "9.1.1 0x250409"
|
||||
#define APIRECEIVER "9.1.1 0x250513"
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
140
tests/scripts/test_frame_synchronizer.py
Normal file
140
tests/scripts/test_frame_synchronizer.py
Normal file
@ -0,0 +1,140 @@
|
||||
# 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,
|
||||
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)
|
||||
|
||||
|
||||
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):
|
||||
Log(LogLevel.INFO, 'Acquiring')
|
||||
Log(LogLevel.INFO, 'Acquiring', fp)
|
||||
d = Detector()
|
||||
d.acquire()
|
||||
|
||||
|
||||
def testFramesCaught(name, num_frames):
|
||||
d = Detector()
|
||||
fnum = d.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, 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
|
||||
d = Detector()
|
||||
num_ports_per_module = 1 if name == "gotthard2" else d.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)
|
||||
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)
|
||||
testFramesCaught(server, args.num_frames)
|
||||
testZmqHeadetTypeCount(server, 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.')
|
||||
|
||||
|
@ -4,250 +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('gotthardDetectorServer_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'
|
||||
if d.type == detectorType.GOTTHARD:
|
||||
d.udp_srcip = d.udp_dstip
|
||||
else:
|
||||
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',
|
||||
'gotthard',
|
||||
'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 + ')')
|
||||
|
||||
# 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
|
||||
num_mods = 2 if server == 'eiger' else 1
|
||||
fname = CMD_TEST_LOG_PREFIX_FNAME + server + '.txt'
|
||||
cmd = ['tests', '--abort', '[.cmdcall]', '-s']
|
||||
|
||||
Log(LogLevel.INFOBLUE, f'Starting Cmd Tests for {server}')
|
||||
cleanup(fp)
|
||||
startDetectorVirtualServer(name=server, num_mods=num_mods, fp=fp)
|
||||
startReceiver(num_mods, fp)
|
||||
loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=num_mods)
|
||||
runProcessWithLogFile('Cmd Tests for ' + server, cmd, fp, fname)
|
||||
except Exception as e:
|
||||
raise RuntimeException(f'Cmd Tests failed for {server}.') from e
|
||||
|
||||
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.')
|
||||
|
247
tests/scripts/utils_for_test.py
Normal file
247
tests/scripts/utils_for_test.py
Normal file
@ -0,0 +1,247 @@
|
||||
# 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):
|
||||
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 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)]
|
||||
if name == 'gotthard':
|
||||
cmd += ['-m', '1']
|
||||
startProcessInBackground(cmd, fp)
|
||||
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":
|
||||
if name == "gotthard":
|
||||
d.udp_srcip = d.udp_dstip
|
||||
else:
|
||||
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
|
||||
|
||||
|
||||
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',
|
||||
'gotthard',
|
||||
'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
|
Reference in New Issue
Block a user