Dev/rx disable datastream port (#1448)
Build and Deploy on local RHEL9 / build (push) Successful in 2m13s
Build on RHEL9 docker image / build (push) Successful in 3m53s
Build and Deploy on local RHEL8 / build (push) Successful in 4m58s
Build on RHEL8 docker image / build (push) Successful in 5m47s
Run Simulator Tests on local RHEL9 / build (push) Successful in 18m55s
Run Simulator Tests on local RHEL8 / build (push) Successful in 22m26s

- changed 
   - command from `datastream` to `udp_datastream` to be more specific
   - Detector API:
      - setNumberofUDPInterfaces(pos) =>setNumberofUDPInterfaces() # no position anymore
      - getDataStream(portPosition, pos) =>getUDPDataStream(portPosition, pos)
      - setDataStream(portPosition, pos) => setUDPDataStream(portPosition) # no position anymore
      
   - modified the dataprocessing thread: 
      - if gui or call back, start zmq processing (connecting sockets) before starting receiver (disabled ports sends dummy that the client zmq sockets are not ready for)
      - if only progress, starting progress processing thread after startReceiver
      -


- added
   - Detector API:
      - getRxDisabledUDPPortIndices()
      - getPortPositionList()  
   - allow disabling/enabling udp interface in receiver for Jungfrua/Moench when both udp interfaces is enabled  (This is to go fast, where only one half of the module matters)
   - write ports type and disabled ports to master file (tests for it as well)
   - tests for python commands as well
   - datastream command to deprecated commands
   - refactored tests to make the new parameters fit

* first draft of disabling data port at the receiver side. Todo: master file and stream for gui to use

* updated help in command

* formatting

* md5 unchanged

* fix test, check port position for detector type

* wip, udp port enable metadata in client, to:receiver, zmq streaming

* wip, master attributes

* wip, imple=> save only disabled ports with port index, 1 interface, is empty

* works in file. still needs refactoring

* updated writer versions

* udp ports type pass, disabled with api yet

* fixed disabled ports meta data as well

* fixed in developer via other PR

* renamed.more intuitive

* fix in gui that wont wait for disabled ports

* added tests for master file

* extra tests

* move the master fiel tests into its own tests with the disable marker for github tests

* refactoring

* python test

* more intuitive and doc

* release notes

* example for python

* back to before

* minor documentation fix and sending nports unnecessarily for getRxUDPPortDisableMetadata

* doc

* review fixes, 1. using std::array instead of vector, 2. moving udp_datastream command testing with different values into master attributes testing file because we test the master file

* minor

* review: update help

* progress printed before assigned

* try catch inside hdf5

* auto generated code for CLI and formatting

* missing packets should not be checked at github workflow level

* formatting

* improved python doc for udp_datastream help

* indent doc python done
This commit is contained in:
2026-07-13 14:58:25 +02:00
committed by GitHub
co-authored by GitHub
parent 9cbf588217
commit c3ad3d2e73
48 changed files with 1269 additions and 142431 deletions
+61 -17
View File
@@ -622,7 +622,7 @@ class Detector(CppDetectorApi):
>>> d.exptime = 5e-07
>>>
>>> # using timedelta (up to microseconds precision)
>>> from datatime import timedelta
>>> from datetime import timedelta
>>> d.exptime = timedelta(seconds = 1, microseconds = 3)
>>>
>>> # using DurationWrapper to set in seconds
@@ -674,7 +674,7 @@ class Detector(CppDetectorApi):
>>> d.period = 5e-07
>>>
>>> # using timedelta (up to microseconds precision)
>>> from datatime import timedelta
>>> from datetime import timedelta
>>> d.period = timedelta(seconds = 1, microseconds = 3)
>>>
>>> # using DurationWrapper to set in seconds
@@ -740,7 +740,7 @@ class Detector(CppDetectorApi):
>>> d.delay = 5e-07
>>>
>>> # using timedelta (up to microseconds precision)
>>> from datatime import timedelta
>>> from datetime import timedelta
>>> d.delay = timedelta(seconds = 1, microseconds = 3)
>>>
>>> # using DurationWrapper to set in seconds
@@ -2429,19 +2429,63 @@ class Detector(CppDetectorApi):
"""
@property
def datastream(self):
def udp_datastream(self):
"""
datastream [left|right] [0, 1]
[Eiger] Enables or disables data streaming from left or/and right side of detector for 10GbE mode. 1 (enabled) by default.
Get or set UDP data streaming for detector/receiver ports.
[Eiger]: LEFT, RIGHT - 10GbE UDP ports of the detector.
[Jungfrau][Moench]: TOP, BOTTOM - UDP ports of the receiver
(only when numinterfaces is set to 2).
:getter: Returns a dictionary containing the UDP data stream enable state
for all available ports. When multiple detector modules are present,
identical values are returned as a single boolean. If different
values are found, a list of booleans is returned.
:setter: Takes a tuple of ``(portPosition, bool)`` to set the UDP data
stream state for a single port.
Enum: portPosition
Example
-------
Get UDP streaming state for all ports:
>>> d.udp_datastream
{<portPosition.TOP: 2>: False, <portPosition.BOTTOM: 3>: True}
Multiple detectors with identical states:
>>> d.udp_datastream
{<portPosition.TOP: 2>: False, <portPosition.BOTTOM: 3>: True}
Multiple detectors with different states:
>>> d.udp_datastream
{<portPosition.TOP: 2>: [False, True], <portPosition.BOTTOM: 3>: [True, True]}
Enable UDP streaming for a specific port:
>>> from slsdet import portPosition
>>> d.udp_datastream = (portPosition.TOP, True)
Disable UDP streaming for a specific port:
>>> d.udp_datastream = (portPosition.BOTTOM, False)
"""
result = {}
for port in [defs.LEFT, defs.RIGHT]:
result[port] = element_if_equal(self.getDataStream(port))
if self.type in [detectorType.JUNGFRAU, detectorType.MOENCH]:
ports = [defs.TOP, defs.BOTTOM]
else:
ports = [defs.LEFT, defs.RIGHT]
for port in ports:
result[port] = element_if_equal(self.getUDPDataStream(port))
return result
@datastream.setter
def datastream(self, value):
ut.set_using_dict(self.setDataStream, *value)
@udp_datastream.setter
def udp_datastream(self, value):
self.setUDPDataStream(*value)
@property
@element
@@ -2473,7 +2517,7 @@ class Detector(CppDetectorApi):
>>> d.subexptime = 5e-07
>>>
>>> # using timedelta (up to microseconds precision)
>>> from datatime import timedelta
>>> from datetime import timedelta
>>> d.subexptime = timedelta(seconds = 1.23, microseconds = 203)
>>>
>>> # using DurationWrapper to set in seconds
@@ -2539,7 +2583,7 @@ class Detector(CppDetectorApi):
>>> d.subdeadtime = 5e-07
>>>
>>> # using timedelta (up to microseconds precision)
>>> from datatime import timedelta
>>> from datetime import timedelta
>>> d.subdeadtime = timedelta(seconds = 1.23, microseconds = 203)
>>>
>>> # using DurationWrapper to set in seconds
@@ -2736,7 +2780,7 @@ class Detector(CppDetectorApi):
>>> d.compdisabletime = 5e-07
>>>
>>> # using timedelta (up to microseconds precision)
>>> from datatime import timedelta
>>> from datetime import timedelta
>>> d.compdisabletime = timedelta(seconds = 1, microseconds = 3)
>>>
>>> # using DurationWrapper to set in seconds
@@ -2829,7 +2873,7 @@ class Detector(CppDetectorApi):
>>> d.storagecell_delay = 5e-07
>>>
>>> # using timedelta (up to microseconds precision)
>>> from datatime import timedelta
>>> from datetime import timedelta
>>> d.storagecell_delay = timedelta(seconds = 1, microseconds = 3)
>>>
>>> # using DurationWrapper to set in seconds
@@ -3175,7 +3219,7 @@ class Detector(CppDetectorApi):
>>> d.burstperiod = 5e-07
>>>
>>> # using timedelta (up to microseconds precision)
>>> from datatime import timedelta
>>> from datetime import timedelta
>>> d.burstperiod = timedelta(seconds = 1, microseconds = 3)
>>>
>>> # using DurationWrapper to set in seconds
@@ -3335,7 +3379,7 @@ class Detector(CppDetectorApi):
>>> d.gatedelay = 5e-07
>>>
>>> # using timedelta (up to microseconds precision)
>>> from datatime import timedelta
>>> from datetime import timedelta
>>> d.gatedelay = timedelta(seconds = 1, microseconds = 3)
>>>
>>> # using DurationWrapper to set in seconds
+18 -12
View File
@@ -653,9 +653,9 @@ void init_det(py::module &m) {
Detector::getNumberofUDPInterfaces,
py::arg() = Positions{});
CppDetectorApi.def("setNumberofUDPInterfaces",
(void (Detector::*)(int, sls::Positions)) &
(void (Detector::*)(int)) &
Detector::setNumberofUDPInterfaces,
py::arg(), py::arg() = Positions{});
py::arg());
CppDetectorApi.def("getSelectedUDPInterface",
(Result<int>(Detector::*)(sls::Positions) const) &
Detector::getSelectedUDPInterface,
@@ -841,6 +841,22 @@ void init_det(py::module &m) {
CppDetectorApi.def(
"setTransmissionDelay",
(void (Detector::*)(int)) & Detector::setTransmissionDelay, py::arg());
CppDetectorApi.def("getUDPDataStream",
(Result<bool>(Detector::*)(const defs::portPosition,
sls::Positions) const) &
Detector::getUDPDataStream,
py::arg(), py::arg() = Positions{});
CppDetectorApi.def("setUDPDataStream",
(void (Detector::*)(const defs::portPosition, const bool,
sls::Positions)) &
Detector::setUDPDataStream,
py::arg(), py::arg(), py::arg() = Positions{});
CppDetectorApi.def("getRxDisabledUDPPortIndices",
(std::vector<int>(Detector::*)() const) &
Detector::getRxDisabledUDPPortIndices);
CppDetectorApi.def("getPortPositionList",
(std::vector<defs::portPosition>(Detector::*)() const) &
Detector::getPortPositionList);
CppDetectorApi.def("getUseReceiverFlag",
(Result<bool>(Detector::*)(sls::Positions) const) &
Detector::getUseReceiverFlag,
@@ -1174,16 +1190,6 @@ void init_det(py::module &m) {
CppDetectorApi.def("setQuad",
(void (Detector::*)(const bool)) & Detector::setQuad,
py::arg());
CppDetectorApi.def("getDataStream",
(Result<bool>(Detector::*)(const defs::portPosition,
sls::Positions) const) &
Detector::getDataStream,
py::arg(), py::arg() = Positions{});
CppDetectorApi.def("setDataStream",
(void (Detector::*)(const defs::portPosition, const bool,
sls::Positions)) &
Detector::setDataStream,
py::arg(), py::arg(), py::arg() = Positions{});
CppDetectorApi.def("getTop",
(Result<bool>(Detector::*)(sls::Positions) const) &
Detector::getTop,
+87 -3
View File
@@ -11,9 +11,8 @@ from utils_for_test import (
LogLevel,
)
from slsdet import Detector
from slsdet._slsdet import slsDetectorDefs
from slsdet.utils import all_equal, element_if_equal
detectorType = slsDetectorDefs.detectorType
@@ -919,4 +918,89 @@ def test_type(session_simulator):
def test_numinterfaces(session_simulator):
d = Detector()
assert d.numinterfaces == 1
assert d.numinterfaces == 1
@pytest.mark.detectorintegration
def test_udp_datastream(session_simulator, request):
""" Test using udp_datastream for eiger, jungfrau and moench."""
det_type, num_interfaces, num_mods, d = session_simulator
assert d is not None
from slsdet import portPosition
if det_type in ['eiger']:
ports = [portPosition.LEFT, portPosition.RIGHT]
prev = [d.getUDPDataStream(i) for i in ports]
# ensure all equal for each value in prev
assert all_equal(prev)
prev_val = [element_if_equal(v) for v in prev]
#list
with pytest.raises(Exception) as exc_info:
d.udp_datastream = (ports[0], [True, False])
# invalid port position
with pytest.raises(Exception) as exc_info:
d.udp_datastream = (portPosition.TOP, True)
with pytest.raises(Exception) as exc_info:
d.udp_datastream = (portPosition.BOTTOM, True)
# without port position
with pytest.raises(Exception) as exc_info:
d.udp_datastream = True
d.udp_datastream = (ports[0], False)
assert d.udp_datastream[ports[0]] is False
d.udp_datastream = (ports[1], False)
assert d.udp_datastream[ports[1]] is False
d.udp_datastream = (ports[0], True)
assert d.udp_datastream[ports[0]] is True
d.udp_datastream = (ports[1], True)
assert d.udp_datastream[ports[1]] is True
d.setUDPDataStream(ports[0], element_if_equal(prev[0]))
d.setUDPDataStream(ports[1], element_if_equal(prev[1]))
elif det_type in ['jungfrau', 'moench'] and num_interfaces == 2:
ports = [portPosition.TOP, portPosition.BOTTOM]
prev = [d.getUDPDataStream(i) for i in ports]
# ensure all equal for each value in prev
assert all_equal(prev)
prev_val = [element_if_equal(v) for v in prev]
#list
with pytest.raises(Exception) as exc_info:
d.udp_datastream = (ports[0], [True, False])
# invalid port position
with pytest.raises(Exception) as exc_info:
d.udp_datastream = (portPosition.LEFT, True)
with pytest.raises(Exception) as exc_info:
d.udp_datastream = (portPosition.RIGHT, True)
# without port position
with pytest.raises(Exception) as exc_info:
d.udp_datastream = True
d.udp_datastream = (ports[0], False)
assert d.udp_datastream[ports[0]] is False
d.udp_datastream = (ports[1], False)
assert d.udp_datastream[ports[1]] is False
d.udp_datastream = (ports[0], True)
assert d.udp_datastream[ports[0]] is True
d.udp_datastream = (ports[1], True)
assert d.udp_datastream[ports[1]] is True
d.setUDPDataStream(ports[0], element_if_equal(prev[0]))
d.setUDPDataStream(ports[1], element_if_equal(prev[1]))
else:
with pytest.raises(Exception) as exc_info:
d.udp_datastream
Log(LogLevel.INFOGREEN, f"{request.node.name} passed")