mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-06-19 00:07:13 +02:00
Compare commits
2 Commits
dev/roi_pe
...
dev/client
Author | SHA1 | Date | |
---|---|---|---|
5093472aa1 | |||
e14d307a42 |
64
.github/workflows/build_wheel.yml
vendored
64
.github/workflows/build_wheel.yml
vendored
@ -1,64 +0,0 @@
|
||||
name: Build wheel
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
|
||||
jobs:
|
||||
build_wheels:
|
||||
name: Build wheels on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest,]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build wheels
|
||||
run: pipx run cibuildwheel==2.23.0
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
|
||||
path: ./wheelhouse/*.whl
|
||||
|
||||
build_sdist:
|
||||
name: Build source distribution
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build sdist
|
||||
run: pipx run build --sdist
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cibw-sdist
|
||||
path: dist/*.tar.gz
|
||||
|
||||
upload_pypi:
|
||||
needs: [build_wheels, build_sdist]
|
||||
runs-on: ubuntu-latest
|
||||
environment: pypi
|
||||
permissions:
|
||||
id-token: write
|
||||
if: github.event_name == 'release' && github.event.action == 'published'
|
||||
# or, alternatively, upload to PyPI on every tag starting with 'v' (remove on: release above to use this)
|
||||
# if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
# unpacks all CIBW artifacts into dist/
|
||||
pattern: cibw-*
|
||||
path: dist
|
||||
merge-multiple: true
|
||||
|
||||
- uses: pypa/gh-action-pypi-publish@release/v1
|
@ -42,7 +42,6 @@ set(SPHINX_SOURCE_FILES
|
||||
src/pyexamples.rst
|
||||
src/pyPatternGenerator.rst
|
||||
src/servers.rst
|
||||
src/multidet.rst
|
||||
src/receiver_api.rst
|
||||
src/result.rst
|
||||
src/type_traits.rst
|
||||
|
@ -6,8 +6,6 @@ Usage
|
||||
|
||||
The syntax is *'[detector index]-[module index]:[command]'*, where the indices are by default '0', when not specified.
|
||||
|
||||
.. _cl-module-index-label:
|
||||
|
||||
Module index
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Modules are indexed based on their order in the hostname command. They are used to configure a specific module within a detector and are followed by a ':' in syntax.
|
||||
|
@ -28,12 +28,6 @@ Welcome to slsDetectorPackage's documentation!
|
||||
receiver_api
|
||||
examples
|
||||
|
||||
.. toctree::
|
||||
:caption: how to
|
||||
:maxdepth: 2
|
||||
|
||||
multidet
|
||||
|
||||
.. toctree::
|
||||
:caption: Python API
|
||||
:maxdepth: 2
|
||||
|
@ -1,228 +0,0 @@
|
||||
Using multiple detectors
|
||||
==========================
|
||||
|
||||
The slsDetectorPackage supports using several detectors on the same computer.
|
||||
This can either be two users, that need to use the same computer without interfering
|
||||
with each other, or the same user that wants to use multiple detectors at the same time.
|
||||
The detectors in turn can consist of multiple modules. For example, a 9M Jungfrau detector
|
||||
consists of 18 modules which typically are addressed at once as a single detector.
|
||||
|
||||
.. note ::
|
||||
|
||||
To address a single module of a multi-module detector you can use the module index.
|
||||
|
||||
- Command line: :ref:`cl-module-index-label`
|
||||
- Python: :ref:`py-module-index-label`
|
||||
|
||||
|
||||
Coming back to multiple detectors we have two tools to our disposal:
|
||||
|
||||
#. Detector index
|
||||
#. The SLSDETNAME environment variable
|
||||
|
||||
They can be used together or separately depending on the use case.
|
||||
|
||||
Detector index
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When configuring a detector you can specify a detector index. The default is 0.
|
||||
|
||||
**Command line**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Given that we have two detectors (my-det and my-det2) that we want to use,
|
||||
# we can configure them with different indices.
|
||||
|
||||
# Configure the first detector with index 0
|
||||
$ sls_detector_put hostname my-det
|
||||
|
||||
# Set number of frames for detector 0 to 10
|
||||
$ sls_detector_put frames 10
|
||||
|
||||
|
||||
#
|
||||
#Configure the second detector with index 1 (notice the 1- before hostname)
|
||||
$ sls_detector_put 1-hostname my-det2
|
||||
|
||||
|
||||
# Further configuration
|
||||
...
|
||||
|
||||
# Set number of frames for detector 1 to 19
|
||||
$ sls_detector_put 1-frames 19
|
||||
|
||||
# Note that if we call sls_detector_get without specifying the index,
|
||||
# it will return the configuration of detector 0
|
||||
$ sls_detector_get frames
|
||||
10
|
||||
|
||||
The detector index is added to the name of the shared memory segment, so in this case
|
||||
the shared memory segments would be:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
#First detector
|
||||
/dev/shm/slsDetectorPackage_detector_0
|
||||
/dev/shm/slsDetectorPackage_detector_0_module_0
|
||||
|
||||
#Second detector
|
||||
/dev/shm/slsDetectorPackage_detector_1
|
||||
/dev/shm/slsDetectorPackage_detector_1_module_0
|
||||
|
||||
|
||||
**Python**
|
||||
|
||||
The main difference between the command line and the Python API is that you set the index
|
||||
when you create the detector object and you don't have to repeat it for every call.
|
||||
|
||||
The C++ API works int the same way.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from slsdet import Detector
|
||||
|
||||
|
||||
# The same can be achieved in Python by creating a detector object with an index.
|
||||
# Again we have two detectors (my-det and my-det2) that we want to use:
|
||||
|
||||
# Configure detector with index 0
|
||||
d = Detector()
|
||||
|
||||
# If the detector has already been configured and has a shared memory
|
||||
# segment, you can omit setting the hostname again
|
||||
d.hostname = 'my-det'
|
||||
|
||||
#Further configuration
|
||||
...
|
||||
|
||||
# Configure a second detector with index 1
|
||||
d2 = Detector(1)
|
||||
d2.hostname = 'my-det2'
|
||||
|
||||
d.frames = 10
|
||||
d2.frames = 19
|
||||
|
||||
|
||||
$SLSDETNAME
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To avoid interfering with other users on shared PCs it is best to always set the SLSDETNAME environmental variable.
|
||||
Imagining a fictive user: Anna, we can set SLSDETNAME from the shell before configuring the detector:
|
||||
|
||||
**Command line**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Set the SLSDETNAME variable
|
||||
$ export SLSDETNAME=Anna
|
||||
|
||||
# You can check that it is set
|
||||
$ echo $SLSDETNAME
|
||||
Anna
|
||||
|
||||
# Now configures a detector with index 0 and prefixed with the name Anna
|
||||
# /dev/shm/slsDetectorPackage_detector_0_Anna
|
||||
$ sls_detector_put hostname my-det
|
||||
|
||||
|
||||
.. tip ::
|
||||
|
||||
Set SLSDETNAME in your .bashrc in order to not forget it when opening a new terminal.
|
||||
|
||||
|
||||
**Python**
|
||||
|
||||
With python the best way is to set the SLSDETNAME from the command line before starting the python interpreter.
|
||||
|
||||
Bash:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ export SLSDETNAME=Anna
|
||||
|
||||
Python:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from slsdet import Detector
|
||||
|
||||
# Now configures a detector with index 0 and prefixed with the name Anna
|
||||
# /dev/shm/slsDetectorPackage_detector_0_Anna
|
||||
d = Detector()
|
||||
d.hostname = 'my-det'
|
||||
|
||||
You can also set SLSDETNAME from within the Python interpreter, but you have to be aware that it will only
|
||||
affect the current process and not the whole shell session.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import os
|
||||
os.environ['SLSDETNAME'] = 'Anna'
|
||||
|
||||
# You can check that it is set
|
||||
print(os.environ['SLSDETNAME']) # Output: Anna
|
||||
|
||||
#Now SLSDETNAME is set to Anna but as soon as you exit the python interpreter
|
||||
# it will not be set anymore
|
||||
|
||||
.. note ::
|
||||
|
||||
Python has two ways of reading environment variables: `**os.environ**` as shown above which throws a
|
||||
KeyError if the variable is not set and `os.getenv('SLSDETNAME')` which returns None if the variable is not set.
|
||||
|
||||
For more details see the official python documentation on: https://docs.python.org/3/library/os.html#os.environ
|
||||
|
||||
|
||||
Checking for other detectors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If using shared accounts on a shared computer (which you anyway should not do), it is good practice to check
|
||||
if there are other detectors configured by other users before configuring your own detector.
|
||||
|
||||
You can do this by listing the files in the shared memory directory `/dev/shm/` that start with `sls`. In this
|
||||
example we can see that two single module detectors are configured one with index 0 and one with index 1.
|
||||
SLSDETNAME is set to `Anna` so it makes sense to assume that she is the user that configured these detectors.
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# List the files in /dev/shm that starts with sls
|
||||
$ ls /dev/shm/sls*
|
||||
/dev/shm/slsDetectorPackage_detector_0_Anna
|
||||
/dev/shm/slsDetectorPackage_detector_0_module_0_Anna
|
||||
/dev/shm/slsDetectorPackage_detector_1_Anna
|
||||
/dev/shm/slsDetectorPackage_detector_1_module_0_Anna
|
||||
|
||||
We also provide a command: user, which gets information about the shared memory segment that
|
||||
the client points to without doing any changes.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
#in this case 3 simulated Mythen3 modules
|
||||
$ sls_detector_get user
|
||||
user
|
||||
Hostname: localhost+localhost+localhost+
|
||||
Type: Mythen3
|
||||
PID: 1226078
|
||||
User: l_msdetect
|
||||
Date: Mon Jun 2 05:46:20 PM CEST 2025
|
||||
|
||||
|
||||
Other considerations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The shared memory is not the only way to interfere with other users. You also need to make sure that you are not
|
||||
using the same:
|
||||
|
||||
* rx_tcpport
|
||||
* Unique combination of udp_dstip and udp_dstport
|
||||
* rx_zmqport
|
||||
* zmqport
|
||||
|
||||
.. attention ::
|
||||
|
||||
The computer that you are using need to have enough resources to run multiple detectors at the same time.
|
||||
This includes CPU and network bandwidth. Please coordinate with the other users!
|
||||
|
@ -123,47 +123,6 @@ in a large detector.
|
||||
# Set exposure time for module 1, 5 and 7
|
||||
d.setExptime(0.1, [1,5,7])
|
||||
|
||||
|
||||
|
||||
.. _py-module-index-label:
|
||||
|
||||
----------------------------------
|
||||
Accessing individual modules
|
||||
----------------------------------
|
||||
|
||||
Using the C++ like API you can access individual modules in a large detector
|
||||
by passing in the module index as an argument to the function.
|
||||
|
||||
::
|
||||
|
||||
# Read the UDP destination port for all modules
|
||||
>>> d.getDestinationUDPPort()
|
||||
[50001, 50002, 50003]
|
||||
|
||||
|
||||
# Read it for module 0 and 1
|
||||
>>> d.getDestinationUDPPort([0, 1])
|
||||
[50001, 50002]
|
||||
|
||||
>>> d.setDestinationUDPPort(50010, 1)
|
||||
>>> d.getDestinationUDPPort()
|
||||
[50001, 50010, 50003]
|
||||
|
||||
From the more pythonic API there is no way to read from only one module but you can read
|
||||
and then use list slicing to get the values for the modules you are interested in.
|
||||
|
||||
::
|
||||
|
||||
>>> d.udp_dstport
|
||||
[50001, 50010, 50003]
|
||||
>>> d.udp_dstport[0]
|
||||
50001
|
||||
|
||||
#For some but not all properties you can also pass in a dictionary with module index as key
|
||||
>>> ip = IpAddr('127.0.0.1')
|
||||
>>> d.udp_dstip = {1:ip}
|
||||
|
||||
|
||||
--------------------
|
||||
Finding functions
|
||||
--------------------
|
||||
|
@ -14,4 +14,4 @@ slsDetectorPackage/8.0.2_rh8 stable cmake/3.15.5 Qt/5.12.10
|
||||
slsDetectorPackage/9.0.0_rh8 stable cmake/3.15.5 Qt/5.12.10
|
||||
slsDetectorPackage/9.1.0_rh8 stable cmake/3.15.5 Qt/5.12.10
|
||||
slsDetectorPackage/9.1.1_rh8 stable cmake/3.15.5 Qt/5.12.10
|
||||
slsDetectorPackage/9.2.0_rh8 stable cmake/3.15.5 Qt/5.12.10
|
||||
|
||||
|
@ -924,6 +924,17 @@ void init_det(py::module &m) {
|
||||
(void (Detector::*)(bool, sls::Positions)) &
|
||||
Detector::setRxArping,
|
||||
py::arg(), py::arg() = Positions{});
|
||||
CppDetectorApi.def("getIndividualRxROIs",
|
||||
(Result<defs::ROI>(Detector::*)(sls::Positions) const) &
|
||||
Detector::getIndividualRxROIs,
|
||||
py::arg());
|
||||
CppDetectorApi.def("getRxROI",
|
||||
(defs::ROI(Detector::*)() const) & Detector::getRxROI);
|
||||
CppDetectorApi.def(
|
||||
"setRxROI", (void (Detector::*)(const defs::ROI)) & Detector::setRxROI,
|
||||
py::arg());
|
||||
CppDetectorApi.def("clearRxROI",
|
||||
(void (Detector::*)()) & Detector::clearRxROI);
|
||||
CppDetectorApi.def(
|
||||
"getFileFormat",
|
||||
(Result<defs::fileFormat>(Detector::*)(sls::Positions) const) &
|
||||
|
@ -29,7 +29,6 @@ target_link_libraries(slsDetectorObject
|
||||
slsProjectOptions
|
||||
slsSupportStatic
|
||||
pthread
|
||||
rt
|
||||
PRIVATE
|
||||
slsProjectWarnings
|
||||
)
|
||||
@ -98,8 +97,7 @@ if(SLS_USE_TEXTCLIENT)
|
||||
add_executable(${val1} src/CmdApp.cpp)
|
||||
|
||||
target_link_libraries(${val1}
|
||||
slsDetectorStatic
|
||||
pthread
|
||||
slsDetectorStatic
|
||||
)
|
||||
SET_SOURCE_FILES_PROPERTIES( src/Caller.cpp PROPERTIES COMPILE_FLAGS "-Wno-unused-variable -Wno-unused-but-set-variable")
|
||||
|
||||
|
@ -21,7 +21,6 @@ class Caller {
|
||||
UdpDestination getUdpEntry();
|
||||
int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand);
|
||||
void WrongNumberOfParameters(size_t expected);
|
||||
std::vector<defs::ROI> parseRoiVector(const std::string &input);
|
||||
|
||||
template <typename V> std::string OutStringHex(const V &value) {
|
||||
if (value.equal())
|
||||
|
@ -2598,7 +2598,11 @@ rx_roi:
|
||||
GET:
|
||||
argc: 0
|
||||
PUT:
|
||||
argc: -1
|
||||
args:
|
||||
- argc: 2
|
||||
arg_types: [ int, int ]
|
||||
- argc: 4
|
||||
arg_types: [ int, int, int, int ]
|
||||
|
||||
ratecorr:
|
||||
is_description: true
|
||||
|
@ -119,10 +119,6 @@ class Detector {
|
||||
|
||||
Result<defs::xy> getModuleSize(Positions pos = {}) const;
|
||||
|
||||
defs::xy getPortPerModuleGeometry() const;
|
||||
|
||||
Result<defs::xy> getPortSize(Positions pos = {}) const;
|
||||
|
||||
/** Gets the actual full detector size. It is the same even if ROI changes
|
||||
*/
|
||||
defs::xy getDetectorSize() const;
|
||||
@ -989,14 +985,13 @@ class Detector {
|
||||
* every minute. Useful in 10G mode. */
|
||||
void setRxArping(bool value, Positions pos = {});
|
||||
|
||||
/** Returns multi level ROIs */
|
||||
std::vector<defs::ROI> getRxROI() const;
|
||||
/** at module level */
|
||||
Result<defs::ROI> getIndividualRxROIs(Positions pos) const;
|
||||
|
||||
/** Returns port level ROIs. Max 2 ports and hence max 2 elements per readout */
|
||||
Result<std::array<defs::ROI, 2>> getRxROI(int module_id) const;
|
||||
defs::ROI getRxROI() const;
|
||||
|
||||
/** only at multi module level without gap pixels. At most, 1 ROI per UDP port */
|
||||
void setRxROI(const std::vector<defs::ROI> &args);
|
||||
/** only at multi module level without gap pixels */
|
||||
void setRxROI(const defs::ROI value);
|
||||
|
||||
void clearRxROI();
|
||||
|
||||
|
@ -21,7 +21,6 @@ class Caller {
|
||||
UdpDestination getUdpEntry();
|
||||
int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand);
|
||||
void WrongNumberOfParameters(size_t expected);
|
||||
std::vector<defs::ROI> parseRoiVector(const std::string &input);
|
||||
|
||||
template <typename V> std::string OutStringHex(const V &value) {
|
||||
if (value.equal())
|
||||
|
@ -719,112 +719,49 @@ std::string Caller::rx_zmqip(int action) {
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
std::string Caller::rx_roi(int action) {
|
||||
std::ostringstream os;
|
||||
std::string helpMessage = std::string("[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in receiver.\n\t")
|
||||
+ "For a list of rois, use '[' and ']; ' to distinguish between "
|
||||
"rois and use comma inside the square brackets.\n\t If one fails to use space after semicolon, please use quotes"
|
||||
+ "For example: [0,100,0,100]; [200,300,0,100] will set two "
|
||||
"rois.or '[0,100,0,100];[200,300,0,100]' when the vector is a single string\n\t"
|
||||
+ "Only allowed at multi module level and without gap "
|
||||
"pixels.\n";
|
||||
if (action == defs::HELP_ACTION) {
|
||||
os << helpMessage;
|
||||
os << "[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in "
|
||||
"receiver.\n\tOnly allowed at multi module level and without gap "
|
||||
"pixels."
|
||||
<< '\n';
|
||||
} else if (action == defs::GET_ACTION) {
|
||||
if (!args.empty()) {
|
||||
WrongNumberOfParameters(0);
|
||||
}
|
||||
if (det_id != -1) {
|
||||
throw RuntimeError("Cannot execute receiver ROI at module level");
|
||||
} else {
|
||||
if (det_id == -1) {
|
||||
auto t = det->getRxROI();
|
||||
os << ToString(t) << '\n';
|
||||
os << t << '\n';
|
||||
} else {
|
||||
auto t = det->getIndividualRxROIs(std::vector<int>{det_id});
|
||||
os << t << '\n';
|
||||
}
|
||||
} else if (action == defs::PUT_ACTION) {
|
||||
std::vector<defs::ROI> rois;
|
||||
|
||||
// Support multiple args with bracketed ROIs, or single arg with
|
||||
// semicolon-separated vector
|
||||
bool isVectorInput =
|
||||
std::all_of(args.begin(), args.end(), [](const std::string &a) {
|
||||
return a.find('[') != std::string::npos &&
|
||||
a.find(']') != std::string::npos;
|
||||
});
|
||||
try {
|
||||
// previous format: 2 or 4 separate args
|
||||
if ((args.size() == 2 || args.size() == 4) && !isVectorInput) {
|
||||
defs::ROI t;
|
||||
t.xmin = StringTo<int>(args[0]);
|
||||
t.xmax = StringTo<int>(args[1]);
|
||||
if (args.size() == 4) {
|
||||
t.ymin = StringTo<int>(args[2]);
|
||||
t.ymax = StringTo<int>(args[3]);
|
||||
}
|
||||
rois.emplace_back(t);
|
||||
} else {
|
||||
if (!isVectorInput)
|
||||
WrongNumberOfParameters(2);
|
||||
else {
|
||||
for (const auto &arg : args) {
|
||||
auto subRois = parseRoiVector(arg);
|
||||
rois.insert(rois.end(), subRois.begin(), subRois.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
throw RuntimeError("Could not parse ROI: " + helpMessage);
|
||||
defs::ROI t;
|
||||
// 2 or 4 arguments
|
||||
if (args.size() != 2 && args.size() != 4) {
|
||||
WrongNumberOfParameters(2);
|
||||
}
|
||||
if (args.size() == 2 || args.size() == 4) {
|
||||
t.xmin = StringTo<int>(args[0]);
|
||||
t.xmax = StringTo<int>(args[1]);
|
||||
}
|
||||
if (args.size() == 4) {
|
||||
t.ymin = StringTo<int>(args[2]);
|
||||
t.ymax = StringTo<int>(args[3]);
|
||||
}
|
||||
|
||||
// only multi level
|
||||
if (det_id != -1) {
|
||||
throw RuntimeError("Cannot execute receiver ROI at module level");
|
||||
}
|
||||
|
||||
det->setRxROI(rois);
|
||||
os << ToString(rois) << '\n';
|
||||
det->setRxROI(t);
|
||||
os << t << '\n';
|
||||
} else {
|
||||
throw RuntimeError("Unknown action");
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
std::vector<defs::ROI> Caller::parseRoiVector(const std::string &input) {
|
||||
std::vector<defs::ROI> rois;
|
||||
std::stringstream ss(input);
|
||||
std::string token;
|
||||
|
||||
while (std::getline(ss, token, ';')) {
|
||||
token.erase(std::remove_if(token.begin(), token.end(), ::isspace),
|
||||
token.end());
|
||||
if (token.empty())
|
||||
continue;
|
||||
if (token.front() != '[' || token.back() != ']') {
|
||||
throw RuntimeError("Each ROI must be enclosed in square brackets: "
|
||||
"[xmin,xmax,ymin,ymax]");
|
||||
}
|
||||
token = token.substr(1, token.size() - 2); // remove brackets
|
||||
std::vector<std::string> parts;
|
||||
std::stringstream inner(token);
|
||||
std::string num;
|
||||
while (std::getline(inner, num, ',')) {
|
||||
parts.push_back(num);
|
||||
}
|
||||
|
||||
if (parts.size() != 4) {
|
||||
throw RuntimeError("ROI must have 4 comma-separated integers");
|
||||
}
|
||||
|
||||
defs::ROI roi;
|
||||
roi.xmin = StringTo<int>(parts[0]);
|
||||
roi.xmax = StringTo<int>(parts[1]);
|
||||
roi.ymin = StringTo<int>(parts[2]);
|
||||
roi.ymax = StringTo<int>(parts[3]);
|
||||
rois.emplace_back(roi);
|
||||
}
|
||||
return rois;
|
||||
}
|
||||
|
||||
std::string Caller::ratecorr(int action) {
|
||||
std::ostringstream os;
|
||||
if (action == defs::HELP_ACTION) {
|
||||
|
@ -201,22 +201,6 @@ Result<defs::xy> Detector::getModuleSize(Positions pos) const {
|
||||
return pimpl->Parallel(&Module::getNumberOfChannels, pos);
|
||||
}
|
||||
|
||||
defs::xy Detector::getPortPerModuleGeometry() const {
|
||||
return pimpl->getPortGeometry();
|
||||
}
|
||||
|
||||
Result<defs::xy> Detector::getPortSize(Positions pos) const {
|
||||
Result<defs::xy> res = pimpl->Parallel(&Module::getNumberOfChannels, pos);
|
||||
defs::xy portGeometry = getPortPerModuleGeometry();
|
||||
for (auto &it : res) {
|
||||
if (portGeometry.x == 2)
|
||||
it.x /= 2;
|
||||
if (portGeometry.y == 2)
|
||||
it.y /= 2;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
defs::xy Detector::getDetectorSize() const {
|
||||
return pimpl->getNumberOfChannels();
|
||||
}
|
||||
@ -1383,22 +1367,16 @@ void Detector::setRxArping(bool value, Positions pos) {
|
||||
pimpl->Parallel(&Module::setRxArping, pos, value);
|
||||
}
|
||||
|
||||
std::vector<defs::ROI> Detector::getRxROI() const {
|
||||
return pimpl->getRxROI();
|
||||
Result<defs::ROI> Detector::getIndividualRxROIs(Positions pos) const {
|
||||
return pimpl->Parallel(&Module::getRxROI, pos);
|
||||
}
|
||||
|
||||
Result<std::array<defs::ROI, 2>> Detector::getRxROI(int module_id) const {
|
||||
return pimpl->Parallel(&Module::getRxROI, {module_id});
|
||||
}
|
||||
defs::ROI Detector::getRxROI() const { return pimpl->getRxROI(); }
|
||||
|
||||
// RxROIs can be set for all types except CTB. At multi level without gap pixels
|
||||
void Detector::setRxROI(const std::vector<defs::ROI> &args) {
|
||||
pimpl->setRxROI(args);
|
||||
}
|
||||
void Detector::setRxROI(const defs::ROI value) { pimpl->setRxROI(value); }
|
||||
|
||||
void Detector::clearRxROI() { pimpl->clearRxROI(); }
|
||||
|
||||
|
||||
// File
|
||||
|
||||
Result<defs::fileFormat> Detector::getFileFormat(Positions pos) const {
|
||||
|
@ -130,6 +130,10 @@ void DetectorImpl::initializeDetectorStructure() {
|
||||
shm()->gapPixels = false;
|
||||
// zmqlib default
|
||||
shm()->zmqHwm = -1;
|
||||
shm()->rx_roi.xmin = -1;
|
||||
shm()->rx_roi.xmax = -1;
|
||||
shm()->rx_roi.ymin = -1;
|
||||
shm()->rx_roi.ymax = -1;
|
||||
}
|
||||
|
||||
void DetectorImpl::initializeMembers(bool verify) {
|
||||
@ -535,7 +539,7 @@ void DetectorImpl::readFrameFromReceiver() {
|
||||
bool quadEnable = false;
|
||||
// to flip image
|
||||
bool eiger = false;
|
||||
std::array<int, 4> rxRoi{}; // TODO: get roi from json header
|
||||
std::array<int, 4> rxRoi = shm()->rx_roi.getIntArray();
|
||||
|
||||
std::vector<bool> runningList(zmqSocket.size());
|
||||
std::vector<bool> connectList(zmqSocket.size());
|
||||
@ -1544,6 +1548,31 @@ void DetectorImpl::setDefaultDac(defs::dacIndex index, int defaultValue,
|
||||
Parallel(&Module::setDefaultDac, pos, index, defaultValue, sett);
|
||||
}
|
||||
|
||||
defs::xy DetectorImpl::getPortGeometry() const {
|
||||
defs::xy portGeometry(1, 1);
|
||||
switch (shm()->detType) {
|
||||
case EIGER:
|
||||
portGeometry.x = modules[0]->getNumberofUDPInterfacesFromShm();
|
||||
break;
|
||||
case JUNGFRAU:
|
||||
case MOENCH:
|
||||
portGeometry.y = modules[0]->getNumberofUDPInterfacesFromShm();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return portGeometry;
|
||||
}
|
||||
|
||||
defs::xy DetectorImpl::calculatePosition(int moduleIndex,
|
||||
defs::xy geometry) const {
|
||||
defs::xy pos{};
|
||||
int maxYMods = shm()->numberOfModules.y;
|
||||
pos.y = (moduleIndex % maxYMods) * geometry.y;
|
||||
pos.x = (moduleIndex / maxYMods) * geometry.x;
|
||||
return pos;
|
||||
}
|
||||
|
||||
void DetectorImpl::verifyUniqueDetHost(const uint16_t port,
|
||||
std::vector<int> positions) const {
|
||||
// port for given positions
|
||||
@ -1667,8 +1696,7 @@ void DetectorImpl::verifyUniqueHost(
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<defs::ROI> DetectorImpl::getRxROI() const {
|
||||
|
||||
defs::ROI DetectorImpl::getRxROI() const {
|
||||
if (shm()->detType == CHIPTESTBOARD ||
|
||||
shm()->detType == defs::XILINX_CHIPTESTBOARD) {
|
||||
throw RuntimeError("RxRoi not implemented for this Detector");
|
||||
@ -1676,169 +1704,75 @@ std::vector<defs::ROI> DetectorImpl::getRxROI() const {
|
||||
if (modules.size() == 0) {
|
||||
throw RuntimeError("No Modules added");
|
||||
}
|
||||
// complete detector in roi
|
||||
auto t = Parallel(&Module::getRxROI, {});
|
||||
if (t.equal() && t.front().completeRoi()) {
|
||||
LOG(logDEBUG) << "no roi";
|
||||
return defs::ROI(0, shm()->numberOfChannels.x - 1, 0,
|
||||
shm()->numberOfChannels.y - 1);
|
||||
}
|
||||
|
||||
// return std::vector<defs::ROI>{};
|
||||
return rxRoiTemp;
|
||||
// TODO
|
||||
}
|
||||
defs::xy numChansPerMod = modules[0]->getNumberOfChannels();
|
||||
bool is2D = (numChansPerMod.y > 1 ? true : false);
|
||||
defs::xy geometry = getPortGeometry();
|
||||
|
||||
bool DetectorImpl::roisOverlap(const defs::ROI &a, const defs::ROI &b) const {
|
||||
bool xOverlap = !(a.xmax < b.xmin || a.xmin > b.xmax);
|
||||
bool yOverlap = !(a.ymax < b.ymin || a.ymin > b.ymax);
|
||||
return xOverlap && yOverlap;
|
||||
}
|
||||
defs::ROI retval{};
|
||||
for (size_t iModule = 0; iModule != modules.size(); ++iModule) {
|
||||
|
||||
void DetectorImpl::validateROIs(const std::vector<defs::ROI> &rois) {
|
||||
for (size_t i = 0; i < rois.size(); ++i) {
|
||||
const auto &roi = rois[i];
|
||||
|
||||
if (roi.noRoi()) {
|
||||
throw RuntimeError("Invalid Roi of size 0. Roi: " + ToString(roi));
|
||||
}
|
||||
bool is2D = (modules[0]->getNumberOfChannels().y > 1 ? true : false);
|
||||
if (roi.completeRoi()) {
|
||||
std::ostringstream oss;
|
||||
oss << "Did you mean the clear roi command (API: clearRxROI, cmd: "
|
||||
"rx_clearroi) Roi: [ -1, -1 ";
|
||||
oss << (is2D ? ", -1, -1 ]?" : "]?");
|
||||
throw RuntimeError(oss.str());
|
||||
}
|
||||
if (roi.xmin > roi.xmax || roi.ymin > roi.ymax) {
|
||||
throw RuntimeError(
|
||||
"Invalid Roi. xmin/ymin exceeds xmax/ymax. Roi: " +
|
||||
ToString(roi));
|
||||
}
|
||||
|
||||
if (roi.xmin < 0 || roi.xmax >= shm()->numberOfChannels.x) {
|
||||
throw RuntimeError(
|
||||
"ROI x-dimension outside detector bounds. Roi: " +
|
||||
ToString(roi));
|
||||
}
|
||||
|
||||
if (is2D) {
|
||||
if (roi.ymin < 0 || roi.ymax >= shm()->numberOfChannels.y) {
|
||||
throw RuntimeError(
|
||||
"ROI y-dimension outside detector bounds. Roi: " +
|
||||
ToString(roi));
|
||||
}
|
||||
defs::ROI moduleRoi = modules[iModule]->getRxROI();
|
||||
if (moduleRoi.noRoi()) {
|
||||
LOG(logDEBUG) << iModule << ": no roi";
|
||||
} else {
|
||||
if ((roi.ymin != -1 && roi.ymin != 0) ||
|
||||
(roi.ymax != -1 && roi.ymax != 0)) {
|
||||
throw RuntimeError(
|
||||
"Invalid Y range for 1D detector: should be -1. Roi: " +
|
||||
ToString(roi));
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t j = i + 1; j < rois.size(); ++j) {
|
||||
if (roisOverlap(rois[i], rois[j])) {
|
||||
throw RuntimeError("Invalid Overlapping Rois.");
|
||||
// expand complete roi
|
||||
if (moduleRoi.completeRoi()) {
|
||||
moduleRoi.xmin = 0;
|
||||
moduleRoi.xmax = numChansPerMod.x;
|
||||
if (is2D) {
|
||||
moduleRoi.ymin = 0;
|
||||
moduleRoi.ymax = numChansPerMod.y;
|
||||
}
|
||||
}
|
||||
LOG(logDEBUG) << iModule << ": " << moduleRoi;
|
||||
|
||||
// get roi at detector level
|
||||
defs::xy pos = calculatePosition(iModule, geometry);
|
||||
defs::ROI moduleFullRoi{};
|
||||
moduleFullRoi.xmin = numChansPerMod.x * pos.x + moduleRoi.xmin;
|
||||
moduleFullRoi.xmax = numChansPerMod.x * pos.x + moduleRoi.xmax;
|
||||
if (is2D) {
|
||||
moduleFullRoi.ymin = numChansPerMod.y * pos.y + moduleRoi.ymin;
|
||||
moduleFullRoi.ymax = numChansPerMod.y * pos.y + moduleRoi.ymax;
|
||||
}
|
||||
LOG(logDEBUG) << iModule << ": (full roi)" << moduleFullRoi;
|
||||
|
||||
// get min and max
|
||||
if (retval.xmin == -1 || moduleFullRoi.xmin < retval.xmin) {
|
||||
LOG(logDEBUG) << iModule << ": xmin updated";
|
||||
retval.xmin = moduleFullRoi.xmin;
|
||||
}
|
||||
if (retval.xmax == -1 || moduleFullRoi.xmax > retval.xmax) {
|
||||
LOG(logDEBUG) << iModule << ": xmax updated";
|
||||
retval.xmax = moduleFullRoi.xmax;
|
||||
}
|
||||
if (retval.ymin == -1 || moduleFullRoi.ymin < retval.ymin) {
|
||||
LOG(logDEBUG) << iModule << ": ymin updated";
|
||||
retval.ymin = moduleFullRoi.ymin;
|
||||
}
|
||||
if (retval.ymax == -1 || moduleFullRoi.ymax > retval.ymax) {
|
||||
LOG(logDEBUG) << iModule << ": ymax updated";
|
||||
retval.ymax = moduleFullRoi.ymax;
|
||||
}
|
||||
}
|
||||
LOG(logDEBUG) << iModule << ": (retval): " << retval;
|
||||
}
|
||||
if (retval.ymin == -1) {
|
||||
retval.ymin = 0;
|
||||
retval.ymax = 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
defs::xy DetectorImpl::calculatePosition(size_t moduleIndex,
|
||||
const defs::xy &geometry) const {
|
||||
if ((geometry.x != 0 && geometry.x != 1) ||
|
||||
(geometry.y != 0 && geometry.y != 1)) {
|
||||
throw RuntimeError("Invalid geometry configuration. Geometry: " +
|
||||
ToString(geometry));
|
||||
}
|
||||
|
||||
if (moduleIndex >= static_cast<size_t>(geometry.x * geometry.y)) {
|
||||
throw RuntimeError("Module index " + std::to_string(moduleIndex) +
|
||||
" out of bounds.");
|
||||
}
|
||||
|
||||
int x = moduleIndex % geometry.x;
|
||||
int y = moduleIndex / geometry.x;
|
||||
return defs::xy{x, y};
|
||||
}
|
||||
|
||||
defs::xy DetectorImpl::getPortGeometry() const {
|
||||
defs::xy portGeometry(1, 1);
|
||||
switch (shm()->detType) {
|
||||
case EIGER:
|
||||
portGeometry.x = modules[0]->getNumberofUDPInterfacesFromShm();
|
||||
break;
|
||||
case JUNGFRAU:
|
||||
case MOENCH:
|
||||
portGeometry.y = modules[0]->getNumberofUDPInterfacesFromShm();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return portGeometry;
|
||||
}
|
||||
|
||||
defs::xy DetectorImpl::calculatePosition(int moduleIndex,
|
||||
defs::xy geometry) const {
|
||||
int maxYMods = shm()->numberOfModules.y;
|
||||
int y = (moduleIndex % maxYMods) * geometry.y;
|
||||
int x = (moduleIndex / maxYMods) * geometry.x;
|
||||
return defs::xy{x, y};
|
||||
}
|
||||
|
||||
defs::ROI DetectorImpl::getModuleROI(int moduleIndex) const {
|
||||
const defs::xy modSize = modules[0]->getNumberOfChannels();
|
||||
// calculate module position (not taking into account port geometry)
|
||||
const defs::xy modPos = calculatePosition(moduleIndex, defs::xy{1, 1});
|
||||
return defs::ROI{modSize.x * modPos.x, modSize.x * (modPos.x + 1) - 1,
|
||||
modSize.y * modPos.y,
|
||||
modSize.y * (modPos.y + 1) - 1}; // convert y for 1d?
|
||||
}
|
||||
|
||||
void DetectorImpl::convertGlobalRoiToPortLevel(
|
||||
const defs::ROI &userRoi, const defs::ROI &moduleRoi,
|
||||
std::array<defs::ROI, 2> &portRois) const {
|
||||
const defs::xy modSize = modules[0]->getNumberOfChannels();
|
||||
const defs::xy geometry = getPortGeometry();
|
||||
const int numPorts = geometry.x * geometry.y;
|
||||
if (numPorts > 2) {
|
||||
throw RuntimeError("Only up to 2 ports per module supported.");
|
||||
}
|
||||
|
||||
for (int port = 0; port < numPorts; ++port) {
|
||||
defs::ROI portRoi = moduleRoi;
|
||||
// Calculate port ROI boundaries (split vertically or horizontally)
|
||||
if (geometry.x == 2) {
|
||||
int midX = (moduleRoi.xmin + moduleRoi.xmax) / 2;
|
||||
if (port == 0)
|
||||
portRoi.xmax = midX;
|
||||
else
|
||||
portRoi.xmin = midX + 1;
|
||||
} else if (geometry.y == 2) {
|
||||
int midY = (moduleRoi.ymin + moduleRoi.ymax) / 2;
|
||||
if (port == 0)
|
||||
portRoi.ymax = midY;
|
||||
else
|
||||
portRoi.ymin = midY + 1;
|
||||
}
|
||||
|
||||
// Check if user ROI overlaps with this port ROI
|
||||
if (roisOverlap(userRoi, portRoi)) {
|
||||
defs::ROI clipped{};
|
||||
clipped.xmin = std::max(userRoi.xmin, portRoi.xmin);
|
||||
clipped.xmax = std::min(userRoi.xmax, portRoi.xmax);
|
||||
if (modSize.y > 1) {
|
||||
clipped.ymin = std::max(userRoi.ymin, portRoi.ymin);
|
||||
clipped.ymax = std::min(userRoi.ymax, portRoi.ymax);
|
||||
}
|
||||
|
||||
// Check if port ROI already exists for this port
|
||||
if (!portRois[port].completeRoi()) {
|
||||
throw RuntimeError(
|
||||
"Multiple ROIs specified for the same port " +
|
||||
std::to_string(port) +
|
||||
" with ROI: " + ToString(userRoi));
|
||||
}
|
||||
portRois[port] = clipped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DetectorImpl::setRxROI(const std::vector<defs::ROI> &args) {
|
||||
void DetectorImpl::setRxROI(const defs::ROI arg) {
|
||||
if (shm()->detType == CHIPTESTBOARD ||
|
||||
shm()->detType == defs::XILINX_CHIPTESTBOARD) {
|
||||
throw RuntimeError("RxRoi not implemented for this Detector");
|
||||
@ -1846,42 +1780,118 @@ void DetectorImpl::setRxROI(const std::vector<defs::ROI> &args) {
|
||||
if (modules.size() == 0) {
|
||||
throw RuntimeError("No Modules added");
|
||||
}
|
||||
if (arg.noRoi()) {
|
||||
throw RuntimeError("Invalid Roi of size 0.");
|
||||
}
|
||||
if (arg.completeRoi()) {
|
||||
throw RuntimeError("Did you mean the clear roi command (API: "
|
||||
"clearRxROI, cmd: rx_clearroi)?");
|
||||
}
|
||||
if (arg.xmin > arg.xmax || arg.ymin > arg.ymax) {
|
||||
throw RuntimeError(
|
||||
"Invalid Receiver Roi. xmin/ymin exceeds xmax/ymax.");
|
||||
}
|
||||
|
||||
validateROIs(args);
|
||||
defs::xy numChansPerMod = modules[0]->getNumberOfChannels();
|
||||
bool is2D = (numChansPerMod.y > 1 ? true : false);
|
||||
defs::xy geometry = getPortGeometry();
|
||||
|
||||
for (size_t iModule = 0; iModule < modules.size(); ++iModule) {
|
||||
auto moduleGlobalRoi = getModuleROI(iModule);
|
||||
if (!is2D && ((arg.ymin != -1 && arg.ymin != 0) ||
|
||||
(arg.ymax != -1 && arg.ymax != 0))) {
|
||||
throw RuntimeError(
|
||||
"Invalid Receiver roi. Cannot set 2d roi for a 1d detector.");
|
||||
}
|
||||
|
||||
// at most 2 rois per module (for each port)
|
||||
std::array<defs::ROI, 2> portRois{};
|
||||
if (arg.xmin < 0 || arg.xmax >= shm()->numberOfChannels.x ||
|
||||
(is2D && (arg.ymin < 0 || arg.ymax >= shm()->numberOfChannels.y))) {
|
||||
throw RuntimeError("Invalid Receiver Roi. Outside detector range.");
|
||||
}
|
||||
|
||||
for (const auto &arg : args) {
|
||||
if (roisOverlap(arg, moduleGlobalRoi)) {
|
||||
convertGlobalRoiToPortLevel(arg, moduleGlobalRoi, portRois);
|
||||
for (size_t iModule = 0; iModule != modules.size(); ++iModule) {
|
||||
// default init = complete roi
|
||||
defs::ROI moduleRoi{};
|
||||
|
||||
// incomplete roi
|
||||
if (!arg.completeRoi()) {
|
||||
// multi module Gotthard2
|
||||
if (shm()->detType == GOTTHARD2 && size() > 1) {
|
||||
moduleRoi.xmin = arg.xmin / 2;
|
||||
moduleRoi.xmax = arg.xmax / 2;
|
||||
if (iModule == 0) {
|
||||
// all should be even
|
||||
if (arg.xmin % 2 != 0) {
|
||||
++moduleRoi.xmin;
|
||||
}
|
||||
} else if (iModule == 1) {
|
||||
// all should be odd
|
||||
if (arg.xmax % 2 == 0) {
|
||||
--moduleRoi.xmax;
|
||||
}
|
||||
} else {
|
||||
throw RuntimeError("Cannot have more than 2 modules for a "
|
||||
"Gotthard2 detector");
|
||||
}
|
||||
} else {
|
||||
// get module limits
|
||||
defs::xy pos = calculatePosition(iModule, geometry);
|
||||
defs::ROI moduleFullRoi{};
|
||||
moduleFullRoi.xmin = numChansPerMod.x * pos.x;
|
||||
moduleFullRoi.xmax = numChansPerMod.x * (pos.x + 1) - 1;
|
||||
if (is2D) {
|
||||
moduleFullRoi.ymin = numChansPerMod.y * pos.y;
|
||||
moduleFullRoi.ymax = numChansPerMod.y * (pos.y + 1) - 1;
|
||||
}
|
||||
|
||||
// no roi
|
||||
if (arg.xmin > moduleFullRoi.xmax ||
|
||||
arg.xmax < moduleFullRoi.xmin ||
|
||||
(is2D && (arg.ymin > moduleFullRoi.ymax ||
|
||||
arg.ymax < moduleFullRoi.ymin))) {
|
||||
moduleRoi.setNoRoi();
|
||||
}
|
||||
// incomplete module roi
|
||||
else if (arg.xmin > moduleFullRoi.xmin ||
|
||||
arg.xmax < moduleFullRoi.xmax ||
|
||||
(is2D && (arg.ymin > moduleFullRoi.ymin ||
|
||||
arg.ymax < moduleFullRoi.ymax))) {
|
||||
moduleRoi.xmin = (arg.xmin <= moduleFullRoi.xmin)
|
||||
? 0
|
||||
: (arg.xmin % numChansPerMod.x);
|
||||
moduleRoi.xmax = (arg.xmax >= moduleFullRoi.xmax)
|
||||
? numChansPerMod.x - 1
|
||||
: (arg.xmax % numChansPerMod.x);
|
||||
if (is2D) {
|
||||
moduleRoi.ymin = (arg.ymin <= moduleFullRoi.ymin)
|
||||
? 0
|
||||
: (arg.ymin % numChansPerMod.y);
|
||||
moduleRoi.ymax = (arg.ymax >= moduleFullRoi.ymax)
|
||||
? numChansPerMod.y - 1
|
||||
: (arg.ymax % numChansPerMod.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// print the rois for debugging
|
||||
LOG(logINFOBLUE) << "Module " << iModule << " RxROIs:";
|
||||
for (size_t iPort = 0; iPort != 2; iPort++) {
|
||||
LOG(logINFOBLUE)
|
||||
<< " Port " << iPort << ": " << ToString(portRois[iPort]);
|
||||
}
|
||||
modules[iModule]->setRxROI(portRois);
|
||||
modules[iModule]->setRxROI(moduleRoi);
|
||||
}
|
||||
rxRoiTemp = args;
|
||||
// updating shm rx_roi for gui purposes
|
||||
shm()->rx_roi = arg;
|
||||
|
||||
// metadata
|
||||
modules[0]->setRxROIMetadata(args);
|
||||
}
|
||||
|
||||
void DetectorImpl::clearRxROI() {
|
||||
rxRoiTemp.clear();
|
||||
for (size_t iModule = 0; iModule < modules.size(); ++iModule) {
|
||||
modules[iModule]->setRxROI(std::array<defs::ROI, 2>{});
|
||||
if (arg.completeRoi()) {
|
||||
modules[0]->setRxROIMetadata(defs::ROI(0, shm()->numberOfChannels.x - 1,
|
||||
0,
|
||||
shm()->numberOfChannels.y - 1));
|
||||
} else {
|
||||
modules[0]->setRxROIMetadata(arg);
|
||||
}
|
||||
}
|
||||
|
||||
int DetectorImpl::getNumberOfUdpPortsInRxROI() const {
|
||||
return 0; // TODO
|
||||
void DetectorImpl::clearRxROI() {
|
||||
Parallel(&Module::setRxROI, {}, defs::ROI{});
|
||||
shm()->rx_roi.xmin = -1;
|
||||
shm()->rx_roi.ymin = -1;
|
||||
shm()->rx_roi.xmax = -1;
|
||||
shm()->rx_roi.ymax = -1;
|
||||
}
|
||||
|
||||
void DetectorImpl::getBadChannels(const std::string &fname,
|
||||
|
@ -24,7 +24,7 @@ class detectorData;
|
||||
class Module;
|
||||
|
||||
#define DETECTOR_SHMAPIVERSION 0x190809
|
||||
#define DETECTOR_SHMVERSION 0x250616
|
||||
#define DETECTOR_SHMVERSION 0x220505
|
||||
#define SHORT_STRING_LENGTH 50
|
||||
|
||||
/**
|
||||
@ -65,6 +65,8 @@ struct sharedDetector {
|
||||
bool gapPixels;
|
||||
/** high water mark of listening tcp port (only data) */
|
||||
int zmqHwm;
|
||||
/** in shm for gui purposes */
|
||||
defs::ROI rx_roi{};
|
||||
};
|
||||
|
||||
class DetectorImpl : public virtual slsDetectorDefs {
|
||||
@ -301,11 +303,9 @@ class DetectorImpl : public virtual slsDetectorDefs {
|
||||
std::vector<std::pair<std::string, uint16_t>>
|
||||
verifyUniqueRxHost(const std::vector<std::string> &names) const;
|
||||
|
||||
defs::xy getPortGeometry() const;
|
||||
std::vector<defs::ROI> getRxROI() const;
|
||||
void setRxROI(const std::vector<defs::ROI> &args);
|
||||
defs::ROI getRxROI() const;
|
||||
void setRxROI(const defs::ROI arg);
|
||||
void clearRxROI();
|
||||
int getNumberOfUdpPortsInRxROI() const;
|
||||
|
||||
void getBadChannels(const std::string &fname, Positions pos) const;
|
||||
void setBadChannels(const std::string &fname, Positions pos);
|
||||
@ -422,19 +422,12 @@ class DetectorImpl : public virtual slsDetectorDefs {
|
||||
*/
|
||||
int kbhit();
|
||||
|
||||
defs::xy getPortGeometry() const;
|
||||
defs::xy calculatePosition(int moduleIndex, defs::xy geometry) const;
|
||||
|
||||
void verifyUniqueHost(
|
||||
bool isDet, std::vector<std::pair<std::string, uint16_t>> &hosts) const;
|
||||
|
||||
bool roisOverlap(const defs::ROI &a, const defs::ROI &b) const;
|
||||
void validateROIs(const std::vector<defs::ROI> &rois);
|
||||
defs::xy calculatePosition(size_t moduleIndex,
|
||||
const defs::xy &geometry) const;
|
||||
defs::xy calculatePosition(int moduleIndex, defs::xy geometry) const;
|
||||
defs::ROI getModuleROI(int moduleIndex) const;
|
||||
void convertGlobalRoiToPortLevel(
|
||||
const defs::ROI &userRoi, const defs::ROI &moduleRoi,
|
||||
std::array<defs::ROI, 2> &portRois) const;
|
||||
|
||||
const int detectorIndex{0};
|
||||
SharedMemory<sharedDetector> shm{0, -1};
|
||||
SharedMemory<CtbConfig> ctb_shm{0, -1, CtbConfig::shm_tag()};
|
||||
@ -462,8 +455,6 @@ class DetectorImpl : public virtual slsDetectorDefs {
|
||||
|
||||
void (*dataReady)(detectorData *, uint64_t, uint32_t, void *){nullptr};
|
||||
void *pCallbackArg{nullptr};
|
||||
|
||||
std::vector<defs::ROI> rxRoiTemp;
|
||||
};
|
||||
|
||||
} // namespace sls
|
@ -1203,7 +1203,7 @@ void Module::setDestinationUDPIP(const IpAddr ip) {
|
||||
}
|
||||
sendToDetector(F_SET_DEST_UDP_IP, ip, nullptr);
|
||||
if (shm()->useReceiverFlag) {
|
||||
MacAddr retval(0LU);
|
||||
MacAddr retval{uint64_t(0)};
|
||||
sendToReceiver(F_SET_RECEIVER_UDP_IP, ip, retval);
|
||||
LOG(logINFO) << "Setting destination udp mac of Module " << moduleIndex
|
||||
<< " to " << retval;
|
||||
@ -1226,7 +1226,7 @@ void Module::setDestinationUDPIP2(const IpAddr ip) {
|
||||
}
|
||||
sendToDetector(F_SET_DEST_UDP_IP2, ip, nullptr);
|
||||
if (shm()->useReceiverFlag) {
|
||||
MacAddr retval(0LU);
|
||||
MacAddr retval{uint64_t(0)};
|
||||
sendToReceiver(F_SET_RECEIVER_UDP_IP2, ip, retval);
|
||||
LOG(logINFO) << "Setting destination udp mac2 of Module " << moduleIndex
|
||||
<< " to " << retval;
|
||||
@ -1521,25 +1521,16 @@ void Module::setRxArping(bool enable) {
|
||||
sendToReceiver(F_SET_RECEIVER_ARPING, static_cast<int>(enable), nullptr);
|
||||
}
|
||||
|
||||
std::array<defs::ROI, 2> Module::getRxROI() const {
|
||||
return sendToReceiver<std::array<slsDetectorDefs::ROI, 2>>(F_RECEIVER_GET_RECEIVER_ROI);
|
||||
defs::ROI Module::getRxROI() const {
|
||||
return sendToReceiver<slsDetectorDefs::ROI>(F_RECEIVER_GET_RECEIVER_ROI);
|
||||
}
|
||||
|
||||
void Module::setRxROI(std::array<defs::ROI, 2> portRois) {
|
||||
/*LOG(logDEBUG) << "Sending to receiver " << moduleIndex << " [rx roi: " << ToString(portRois)
|
||||
<< ']';
|
||||
auto receiver = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort);
|
||||
receiver.Send(F_RECEIVER_SET_RECEIVER_ROI);
|
||||
receiver.setFnum(F_RECEIVER_SET_RECEIVER_ROI);
|
||||
receiver.Send(portRois);
|
||||
if (receiver.Receive<int>() == FAIL) {
|
||||
throw ReceiverError("Receiver " + std::to_string(moduleIndex) +
|
||||
" returned error: " + receiver.readErrorMessage());
|
||||
}*/
|
||||
sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI, portRois, nullptr);
|
||||
void Module::setRxROI(const slsDetectorDefs::ROI arg) {
|
||||
LOG(logDEBUG) << moduleIndex << ": " << arg;
|
||||
sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI, arg, nullptr);
|
||||
}
|
||||
|
||||
void Module::setRxROIMetadata(const std::vector<slsDetectorDefs::ROI> &arg) {
|
||||
void Module::setRxROIMetadata(const slsDetectorDefs::ROI arg) {
|
||||
sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI_METADATA, arg, nullptr);
|
||||
}
|
||||
|
||||
|
@ -301,9 +301,9 @@ class Module : public virtual slsDetectorDefs {
|
||||
std::array<pid_t, NUM_RX_THREAD_IDS> getReceiverThreadIds() const;
|
||||
bool getRxArping() const;
|
||||
void setRxArping(bool enable);
|
||||
std::array<defs::ROI, 2> getRxROI() const;
|
||||
void setRxROI(const std::array<slsDetectorDefs::ROI, 2> portRois);
|
||||
void setRxROIMetadata(const std::vector<slsDetectorDefs::ROI> &args);
|
||||
defs::ROI getRxROI() const;
|
||||
void setRxROI(const slsDetectorDefs::ROI arg);
|
||||
void setRxROIMetadata(const slsDetectorDefs::ROI arg);
|
||||
|
||||
/**************************************************
|
||||
* *
|
||||
|
@ -25,8 +25,12 @@
|
||||
#include <unistd.h>
|
||||
|
||||
namespace sls {
|
||||
|
||||
#define SHM_DETECTOR_PREFIX "/slsDetectorPackage_detector_"
|
||||
#ifdef __APPLE__
|
||||
// On macOS SHM_NAME_MAX is 31 so we need the shortest possible prefix
|
||||
#define SHM_DETECTOR_PREFIX "/sls_"
|
||||
#else
|
||||
#define SHM_DETECTOR_PREFIX "/slsDetectorPackage_detector_"
|
||||
#endif
|
||||
#define SHM_MODULE_PREFIX "_module_"
|
||||
#define SHM_ENV_NAME "SLSDETNAME"
|
||||
|
||||
@ -203,6 +207,11 @@ template <typename T> class SharedMemory {
|
||||
throw SharedMemoryError(msg);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
// On macOS, fstat returns the allocated size and not the requested size.
|
||||
// This means we can't check for size since we always get for example 16384 bytes.
|
||||
return;
|
||||
#endif
|
||||
auto actual_size = static_cast<size_t>(sb.st_size);
|
||||
auto expected_size = sizeof(T);
|
||||
if (actual_size != expected_size) {
|
||||
|
@ -466,6 +466,7 @@ TEST_CASE("rx_arping", "[.cmdcall][.rx]") {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("rx_roi", "[.cmdcall]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
@ -478,69 +479,33 @@ TEST_CASE("rx_roi", "[.cmdcall]") {
|
||||
defs::xy detsize = det.getDetectorSize();
|
||||
|
||||
// 1d
|
||||
if (det_type == defs::GOTTHARD2 || det_type == defs::MYTHEN3) {
|
||||
if (det_type == defs::GOTTHARD || det_type == defs::GOTTHARD2 ||
|
||||
det_type == defs::MYTHEN3) {
|
||||
{
|
||||
std::ostringstream oss;
|
||||
caller.call("rx_roi", {"5", "10"}, -1, PUT, oss);
|
||||
REQUIRE(oss.str() == "rx_roi [[5, 10]]\n");
|
||||
REQUIRE(oss.str() == "rx_roi [5, 10]\n");
|
||||
}
|
||||
{
|
||||
std::ostringstream oss;
|
||||
caller.call("rx_roi", {"10", "15"}, -1, PUT, oss);
|
||||
REQUIRE(oss.str() == "rx_roi [[10, 15]]\n");
|
||||
REQUIRE(oss.str() == "rx_roi [10, 15]\n");
|
||||
}
|
||||
REQUIRE_THROWS(caller.call("rx_roi", {"0", "0"}, -1, PUT));
|
||||
REQUIRE_THROWS(caller.call("rx_roi", {"-1", "-1"}, -1, PUT));
|
||||
// xmin > xmax
|
||||
REQUIRE_THROWS(caller.call("rx_roi", {"[12, 8, -1, -1]"}, -1, PUT));
|
||||
// outside detector bounds
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi",
|
||||
{"[95," + std::to_string(detsize.x + 5) + ", -1, -1]"}, -1,
|
||||
PUT));
|
||||
// module level not allowed
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[5, 10, -1, -1]"}, 0, PUT));
|
||||
|
||||
// vector of rois
|
||||
// square brackets missing
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[5, 20, -1, -1; 25, 30, -1, -1]"}, -1, PUT));
|
||||
// invalid roi, 4 parts expected
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[5, 20, -1]; [25, 30, -1, -1]"}, -1, PUT));
|
||||
// overlapping rois
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[0, 10,-1, -1];[5, 15, -1, -1]"}, -1, PUT));
|
||||
|
||||
if (det.size() == 2) {
|
||||
auto moduleSize = det.getModuleSize()[0];
|
||||
std::string stringMin = std::to_string(moduleSize.x);
|
||||
std::string stringMax = std::to_string(moduleSize.x + 1);
|
||||
|
||||
// separated by space is allowed
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[5, 10, -1, -1]", "[" + stringMin + ", " + stringMax + ", -1, -1]"}, -1, PUT));
|
||||
std::ostringstream oss;
|
||||
// separated by semicolon is allowed
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[5, 10, -1, -1];[" + stringMin + ", " + stringMax + ", -1, -1]"}, -1, PUT, oss));
|
||||
REQUIRE(oss.str() ==
|
||||
"rx_roi [[5, 10], [" + stringMin + ", " + stringMax + "]]\n");
|
||||
|
||||
}
|
||||
REQUIRE_THROWS(
|
||||
caller.call("rx_roi", {"10", "15", "25", "30"}, -1, PUT));
|
||||
}
|
||||
// 2d eiger, jungfrau, moench
|
||||
// 2d
|
||||
else {
|
||||
{
|
||||
std::ostringstream oss;
|
||||
caller.call("rx_roi", {"10", "15", "1", "5"}, -1, PUT, oss);
|
||||
REQUIRE(oss.str() == "rx_roi [[10, 15, 1, 5]]\n");
|
||||
REQUIRE(oss.str() == "rx_roi [10, 15, 1, 5]\n");
|
||||
}
|
||||
{
|
||||
std::ostringstream oss;
|
||||
caller.call("rx_roi", {"10", "22", "18", "19"}, -1, PUT, oss);
|
||||
REQUIRE(oss.str() == "rx_roi [[10, 22, 18, 19]]\n");
|
||||
REQUIRE(oss.str() == "rx_roi [10, 22, 18, 19]\n");
|
||||
}
|
||||
{
|
||||
std::ostringstream oss;
|
||||
@ -548,83 +513,14 @@ TEST_CASE("rx_roi", "[.cmdcall]") {
|
||||
{"1", std::to_string(detsize.x - 5), "1",
|
||||
std::to_string(detsize.y - 5)},
|
||||
-1, PUT, oss);
|
||||
REQUIRE(oss.str() == std::string("rx_roi [[1, ") +
|
||||
REQUIRE(oss.str() == std::string("rx_roi [1, ") +
|
||||
std::to_string(detsize.x - 5) +
|
||||
std::string(", 1, ") +
|
||||
std::to_string(detsize.y - 5) +
|
||||
std::string("]]\n"));
|
||||
std::string("]\n"));
|
||||
}
|
||||
REQUIRE_THROWS(
|
||||
caller.call("rx_roi", {"0", "0", "0", "0"}, -1, PUT));
|
||||
REQUIRE_THROWS(
|
||||
caller.call("rx_roi", {"-1", "-1", "-1", "-1"}, -1, PUT));
|
||||
// xmin > xmax
|
||||
REQUIRE_THROWS(caller.call("rx_roi", {"[12, 8, 0, 10]"}, -1, PUT));
|
||||
// ymin > ymax
|
||||
REQUIRE_THROWS(caller.call("rx_roi", {"[0, 10, 20, 5]"}, -1, PUT));
|
||||
// outside detector bounds
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[95," + std::to_string(detsize.x + 5) + ", 0, 10]"},
|
||||
-1, PUT));
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi",
|
||||
{"[95, 100, 0, " + std::to_string(detsize.y + 5) + "]"}, -1,
|
||||
PUT));
|
||||
// module level not allowed
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[5, 10, 20, 30]"}, 0, PUT));
|
||||
|
||||
// vector of rois
|
||||
// square brackets missing
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[5, 20, 20, 30; 25, 30, 14, 15]"}, -1, PUT));
|
||||
// invalid roi, 4 parts expected
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[5, 20, 20]; [25, 30, 14, 15]"}, -1, PUT));
|
||||
// overlapping rois
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[0, 10, 0, 10];[5, 15, 0, 10]"}, -1, PUT));
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[0, 10, 0, 10];[0, 10, 9, 11]"}, -1, PUT));
|
||||
|
||||
auto portSize = det.getPortSize()[0];
|
||||
if (det_type == defs::EIGER) {
|
||||
std::string stringMin = std::to_string(portSize.x);
|
||||
std::string stringMax = std::to_string(portSize.x + 1);
|
||||
|
||||
// separated by space is allowed
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[5, 10, 20, 30]", "[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT));
|
||||
std::ostringstream oss;
|
||||
// separated by semicolon is allowed
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[5, 10, 20, 30];[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT, oss));
|
||||
REQUIRE(oss.str() ==
|
||||
"rx_roi [[5, 10, 20, 30], [" + stringMin + ", " + stringMax + ", 20, 30]]\n");
|
||||
}
|
||||
if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH) {
|
||||
// 2 interfaces or 2 modules
|
||||
if ((det.getNumberofUDPInterfaces().tsquash(
|
||||
"inconsistent number of interfaces") == 2) || (det.size() == 2)) {
|
||||
std::string stringMin = std::to_string(portSize.y);
|
||||
std::string stringMax = std::to_string(portSize.y + 1);
|
||||
if (det.size() == 2) {
|
||||
auto moduleSize = det.getModuleSize()[0];
|
||||
stringMin = std::to_string(moduleSize.y);
|
||||
stringMax = std::to_string(moduleSize.y + 1);
|
||||
}
|
||||
|
||||
// separated by space is allowed
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[5, 10, 20, 30]", "[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT));
|
||||
std::ostringstream oss;
|
||||
// separated by semicolon is allowed
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[5, 10, 20, 30];[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT, oss));
|
||||
REQUIRE(oss.str() ==
|
||||
"rx_roi [[5, 10, 20, 30], [25, 28, " + stringMin + ", " + stringMax + "]]\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i != det.size(); ++i) {
|
||||
@ -633,7 +529,6 @@ TEST_CASE("rx_roi", "[.cmdcall]") {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("rx_clearroi", "[.cmdcall]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
|
@ -113,12 +113,10 @@ template <typename T, size_t Capacity> class StaticVector {
|
||||
// auto begin() noexcept -> decltype(data_.begin()) { return data_.begin();
|
||||
// }
|
||||
const_iterator begin() const noexcept { return data_.begin(); }
|
||||
iterator end() noexcept { return data_.begin() + current_size; }
|
||||
const_iterator end() const noexcept { return data_.begin() + current_size; }
|
||||
iterator end() noexcept { return data_.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_.cbegin() + current_size;
|
||||
}
|
||||
const_iterator cend() const noexcept { return data_.cbegin()+current_size; }
|
||||
|
||||
void size_check(size_type s) const {
|
||||
if (s > Capacity) {
|
||||
|
@ -349,5 +349,4 @@ std::vector<T> StringTo(const std::vector<std::string> &strings) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace sls
|
||||
|
@ -237,8 +237,7 @@ class slsDetectorDefs {
|
||||
return (xmin == -1 && xmax == -1 && ymin == -1 && ymax == -1);
|
||||
}
|
||||
constexpr bool noRoi() const {
|
||||
return ((xmin == 0 && xmax == 0) &&
|
||||
((ymin == 0 && ymax == 0) || (ymin == -1 && ymax == -1)));
|
||||
return (xmin == 0 && xmax == 0 && ymin == 0 && ymax == 0);
|
||||
}
|
||||
void setNoRoi() {
|
||||
xmin = 0;
|
||||
|
@ -10,3 +10,4 @@
|
||||
#define APIXILINXCTB "0.0.0 0x250523"
|
||||
#define APIJUNGFRAU "0.0.0 0x250523"
|
||||
#define APIMYTHEN3 "0.0.0 0x250523"
|
||||
|
||||
|
@ -5,7 +5,12 @@
|
||||
|
||||
namespace sls {
|
||||
|
||||
std::string ToString(bool value) { return value ? "1" : "0"; }
|
||||
|
||||
std::string ToString(bool value) {
|
||||
return value ? "1" : "0";
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string ToString(const slsDetectorDefs::xy &coord) {
|
||||
std::ostringstream oss;
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <netdb.h>
|
||||
#include <sstream>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/prctl.h>
|
||||
// #include <sys/prctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
@ -178,30 +178,30 @@ IpAddr InterfaceNameToIp(const std::string &ifn) {
|
||||
|
||||
MacAddr InterfaceNameToMac(const std::string &inf) {
|
||||
// TODO! Copied from genericSocket needs to be refactored!
|
||||
struct ifreq ifr;
|
||||
char mac[32];
|
||||
const int mac_len = sizeof(mac);
|
||||
memset(mac, 0, mac_len);
|
||||
// struct ifreq ifr;
|
||||
// char mac[32];
|
||||
// const int mac_len = sizeof(mac);
|
||||
// memset(mac, 0, mac_len);
|
||||
|
||||
int sock = socket(PF_INET, SOCK_STREAM, 0);
|
||||
strncpy(ifr.ifr_name, inf.c_str(), sizeof(ifr.ifr_name) - 1);
|
||||
ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
|
||||
// int sock = socket(PF_INET, SOCK_STREAM, 0);
|
||||
// strncpy(ifr.ifr_name, inf.c_str(), sizeof(ifr.ifr_name) - 1);
|
||||
// ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
|
||||
|
||||
if (-1 == ioctl(sock, SIOCGIFHWADDR, &ifr)) {
|
||||
perror("ioctl(SIOCGIFHWADDR) ");
|
||||
return MacAddr{};
|
||||
}
|
||||
for (int j = 0, k = 0; j < 6; j++) {
|
||||
k += snprintf(
|
||||
mac + k, mac_len - k - 1, j ? ":%02X" : "%02X",
|
||||
(int)(unsigned int)(unsigned char)ifr.ifr_hwaddr.sa_data[j]);
|
||||
}
|
||||
mac[mac_len - 1] = '\0';
|
||||
// if (-1 == ioctl(sock, SIOCGIFHWADDR, &ifr)) {
|
||||
// perror("ioctl(SIOCGIFHWADDR) ");
|
||||
// return MacAddr{};
|
||||
// }
|
||||
// for (int j = 0, k = 0; j < 6; j++) {
|
||||
// k += snprintf(
|
||||
// mac + k, mac_len - k - 1, j ? ":%02X" : "%02X",
|
||||
// (int)(unsigned int)(unsigned char)ifr.ifr_hwaddr.sa_data[j]);
|
||||
// }
|
||||
// mac[mac_len - 1] = '\0';
|
||||
|
||||
if (sock != 1) {
|
||||
close(sock);
|
||||
}
|
||||
return MacAddr(mac);
|
||||
// if (sock != 1) {
|
||||
// close(sock);
|
||||
// }
|
||||
return MacAddr();
|
||||
}
|
||||
|
||||
void validatePortNumber(uint16_t port) {
|
||||
|
@ -8,12 +8,15 @@
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
|
||||
using sls::StaticVector;
|
||||
|
||||
TEST_CASE("StaticVector is a container") {
|
||||
REQUIRE(sls::is_container<StaticVector<int, 7>>::value == true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_CASE("Comparing StaticVector containers") {
|
||||
StaticVector<int, 5> a{0, 1, 2};
|
||||
StaticVector<int, 5> b{0, 1, 2};
|
||||
@ -341,3 +344,4 @@ TEST_CASE("StaticVector stream") {
|
||||
oss << vec;
|
||||
REQUIRE(oss.str() == "[33, 85667, 2]");
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ TEST_CASE("Convert string to bool", "[support]") {
|
||||
REQUIRE(StringTo<bool>("0") == false);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Integer conversions", "[support]") {
|
||||
REQUIRE(ToString(0) == "0");
|
||||
REQUIRE(ToString(1) == "1");
|
||||
|
@ -25,7 +25,6 @@ target_link_libraries(tests
|
||||
slsProjectOptions
|
||||
slsSupportStatic
|
||||
pthread
|
||||
rt
|
||||
PRIVATE
|
||||
slsProjectWarnings
|
||||
)
|
||||
|
@ -20,7 +20,6 @@ from utils_for_test import (
|
||||
cleanSharedmemory,
|
||||
startProcessInBackground,
|
||||
startProcessInBackgroundWithLogFile,
|
||||
checkLogForErrors,
|
||||
startDetectorVirtualServer,
|
||||
loadConfig,
|
||||
ParseArguments
|
||||
@ -35,9 +34,6 @@ def startFrameSynchronizerPullSocket(name, fp):
|
||||
fname = PULL_SOCKET_PREFIX_FNAME + name + '.txt'
|
||||
cmd = ['python', '-u', 'frameSynchronizerPullSocket.py']
|
||||
startProcessInBackgroundWithLogFile(cmd, fp, fname)
|
||||
time.sleep(1)
|
||||
checkLogForErrors(fp, fname)
|
||||
|
||||
|
||||
|
||||
def startFrameSynchronizer(num_mods, fp):
|
||||
@ -48,14 +44,16 @@ def startFrameSynchronizer(num_mods, fp):
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def acquire(fp, det):
|
||||
def acquire(fp):
|
||||
Log(LogLevel.INFO, 'Acquiring')
|
||||
Log(LogLevel.INFO, 'Acquiring', fp)
|
||||
det.acquire()
|
||||
d = Detector()
|
||||
d.acquire()
|
||||
|
||||
|
||||
def testFramesCaught(name, det, num_frames):
|
||||
fnum = det.rx_framescaught[0]
|
||||
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}")
|
||||
|
||||
@ -63,7 +61,7 @@ def testFramesCaught(name, det, num_frames):
|
||||
Log(LogLevel.INFOGREEN, f'Frames caught test passed for {name}', fp)
|
||||
|
||||
|
||||
def testZmqHeadetTypeCount(name, det, num_mods, num_frames, 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)
|
||||
@ -90,7 +88,8 @@ def testZmqHeadetTypeCount(name, det, num_mods, num_frames, fp):
|
||||
continue
|
||||
|
||||
# test if file contents matches expected counts
|
||||
num_ports_per_module = 1 if name == "gotthard2" else det.numinterfaces
|
||||
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:
|
||||
@ -112,10 +111,10 @@ def startTestsForAll(args, fp):
|
||||
startDetectorVirtualServer(server, args.num_mods, fp)
|
||||
startFrameSynchronizerPullSocket(server, fp)
|
||||
startFrameSynchronizer(args.num_mods, fp)
|
||||
d = loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=args.num_mods, num_frames=args.num_frames)
|
||||
acquire(fp, d)
|
||||
testFramesCaught(server, d, args.num_frames)
|
||||
testZmqHeadetTypeCount(server, d, args.num_mods, args.num_frames, 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
|
||||
|
@ -104,7 +104,7 @@ def startProcessInBackground(cmd, fp):
|
||||
raise RuntimeException(f'Failed to start {cmd}:{str(e)}') from e
|
||||
|
||||
|
||||
def startProcessInBackgroundWithLogFile(cmd, fp, log_file_name: str):
|
||||
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:
|
||||
@ -114,22 +114,6 @@ def startProcessInBackgroundWithLogFile(cmd, fp, log_file_name: str):
|
||||
raise RuntimeException(f'Failed to start {cmd}:{str(e)}') from e
|
||||
|
||||
|
||||
def checkLogForErrors(fp, log_file_path: str):
|
||||
try:
|
||||
with open(log_file_path, 'r') as log_file:
|
||||
for line in log_file:
|
||||
if 'Error' in line:
|
||||
Log(LogLevel.ERROR, f"Error found in log: {line.strip()}")
|
||||
Log(LogLevel.ERROR, f"Error found in log: {line.strip()}", fp)
|
||||
raise RuntimeException("Error found in log file")
|
||||
except FileNotFoundError:
|
||||
print(f"Log file not found: {log_file_path}")
|
||||
raise
|
||||
except Exception as e:
|
||||
print(f"Exception while reading log: {e}")
|
||||
raise
|
||||
|
||||
|
||||
def runProcessWithLogFile(name, cmd, fp, log_file_name):
|
||||
Log(LogLevel.INFOBLUE, 'Running ' + name + '. Log: ' + log_file_name)
|
||||
Log(LogLevel.INFOBLUE, 'Running ' + name + '. Log: ' + log_file_name, fp)
|
||||
@ -156,7 +140,7 @@ def startDetectorVirtualServer(name :str, num_mods, fp):
|
||||
for i in range(num_mods):
|
||||
port_no = SERVER_START_PORTNO + (i * 2)
|
||||
cmd = [name + 'DetectorServer_virtual', '-p', str(port_no)]
|
||||
startProcessInBackgroundWithLogFile(cmd, fp, "/tmp/virtual_det_" + name + str(i) + ".txt")
|
||||
startProcessInBackground(cmd, fp)
|
||||
match name:
|
||||
case 'jungfrau':
|
||||
time.sleep(7)
|
||||
@ -217,8 +201,6 @@ def loadConfig(name, rx_hostname, settingsdir, fp, num_mods = 1, num_frames = 1)
|
||||
d.frames = num_frames
|
||||
except Exception as e:
|
||||
raise RuntimeException(f'Could not load config for {name}. Error: {str(e)}') from e
|
||||
|
||||
return d
|
||||
|
||||
|
||||
def ParseArguments(description, default_num_mods=1):
|
||||
|
Reference in New Issue
Block a user