diff --git a/python/src/detector.cpp b/python/src/detector.cpp index 5393cbf6e..4a5ffc02c 100644 --- a/python/src/detector.cpp +++ b/python/src/detector.cpp @@ -924,17 +924,6 @@ void init_det(py::module &m) { (void (Detector::*)(bool, sls::Positions)) & Detector::setRxArping, py::arg(), py::arg() = Positions{}); - CppDetectorApi.def("getIndividualRxROIs", - (Result(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(Detector::*)(sls::Positions) const) & diff --git a/slsDetectorSoftware/generator/commands.yaml b/slsDetectorSoftware/generator/commands.yaml index f33cf7be2..3b96e48f5 100644 --- a/slsDetectorSoftware/generator/commands.yaml +++ b/slsDetectorSoftware/generator/commands.yaml @@ -1739,12 +1739,13 @@ readout: PUT: function: startDetectorReadout -rx_clearroi: - inherit_actions: EXECUTE_SET_COMMAND_NOID - help: "\n\tResets Region of interest in receiver. Default is all channels/pixels enabled." - actions: - PUT: - function: clearRxROI +# TODO +#rx_clearroi: +# inherit_actions: EXECUTE_SET_COMMAND_NOID +# help: "\n\tResets Region of interest in receiver. Default is all channels/pixels enabled." +# actions: +# PUT: +# function: clearRxROI ################# EXECUTE_SET_COMMAND ######################## start: @@ -2592,17 +2593,18 @@ rx_zmqip: PUT: argc: -1 -rx_roi: - is_description: true - actions: - GET: - argc: 0 - PUT: - args: - - argc: 2 - arg_types: [ int, int ] - - argc: 4 - arg_types: [ int, int, int, int ] +#TODO +#rx_roi: +# is_description: true +# actions: +# GET: +# argc: 0 +# PUT: +# args: +# - argc: 2 +# arg_types: [ int, int ] +# - argc: 4 +# arg_types: [ int, int, int, int ] ratecorr: is_description: true diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index eb679a578..fd85e427a 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -985,16 +985,16 @@ class Detector { * every minute. Useful in 10G mode. */ void setRxArping(bool value, Positions pos = {}); - /** at module level */ - Result getIndividualRxROIs(Positions pos) const; - - defs::ROI getRxROI() const; + std::vector getRxROI() const; /** only at multi module level without gap pixels */ - void setRxROI(const defs::ROI value); + void setRxROI(const std::vector& args); void clearRxROI(); + int getNumberOfUdpPortsInRxROI() const; + + ///@} /** @name File */ diff --git a/slsDetectorSoftware/src/Caller.cpp b/slsDetectorSoftware/src/Caller.cpp index 78a6f79d7..9fb08ff69 100644 --- a/slsDetectorSoftware/src/Caller.cpp +++ b/slsDetectorSoftware/src/Caller.cpp @@ -10594,7 +10594,7 @@ std::string Caller::rx_arping(int action) { return os.str(); } - +/* std::string Caller::rx_clearroi(int action) { std::ostringstream os; @@ -10637,7 +10637,7 @@ std::string Caller::rx_clearroi(int action) { return os.str(); } - +*/ std::string Caller::rx_dbitoffset(int action) { std::ostringstream os; diff --git a/slsDetectorSoftware/src/Caller.h b/slsDetectorSoftware/src/Caller.h index 3e1be13ac..d1df0c0f2 100644 --- a/slsDetectorSoftware/src/Caller.h +++ b/slsDetectorSoftware/src/Caller.h @@ -233,7 +233,7 @@ class Caller { std::string runclk(int action); std::string runtime(int action); std::string rx_arping(int action); - std::string rx_clearroi(int action); + //std::string rx_clearroi(int action); std::string rx_dbitlist(int action); std::string rx_dbitoffset(int action); std::string rx_dbitreorder(int action); @@ -251,7 +251,7 @@ class Caller { std::string rx_padding(int action); std::string rx_printconfig(int action); std::string rx_realudpsocksize(int action); - std::string rx_roi(int action); + //std::string rx_roi(int action); std::string rx_silent(int action); std::string rx_start(int action); std::string rx_status(int action); @@ -580,7 +580,7 @@ class Caller { {"runclk", &Caller::runclk}, {"runtime", &Caller::runtime}, {"rx_arping", &Caller::rx_arping}, - {"rx_clearroi", &Caller::rx_clearroi}, + //{"rx_clearroi", &Caller::rx_clearroi}, {"rx_dbitlist", &Caller::rx_dbitlist}, {"rx_dbitoffset", &Caller::rx_dbitoffset}, {"rx_dbitreorder", &Caller::rx_dbitreorder}, @@ -598,7 +598,7 @@ class Caller { {"rx_padding", &Caller::rx_padding}, {"rx_printconfig", &Caller::rx_printconfig}, {"rx_realudpsocksize", &Caller::rx_realudpsocksize}, - {"rx_roi", &Caller::rx_roi}, + //{"rx_roi", &Caller::rx_roi}, {"rx_silent", &Caller::rx_silent}, {"rx_start", &Caller::rx_start}, {"rx_status", &Caller::rx_status}, diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index bdea93207..394a9d5e7 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -719,6 +719,7 @@ std::string Caller::rx_zmqip(int action) { } return os.str(); } +/* TODO std::string Caller::rx_roi(int action) { std::ostringstream os; if (action == defs::HELP_ACTION) { @@ -761,7 +762,7 @@ std::string Caller::rx_roi(int action) { throw RuntimeError("Unknown action"); } return os.str(); -} +}*/ std::string Caller::ratecorr(int action) { std::ostringstream os; if (action == defs::HELP_ACTION) { diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index f84e5fbb3..375faaeaa 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -1367,16 +1367,22 @@ void Detector::setRxArping(bool value, Positions pos) { pimpl->Parallel(&Module::setRxArping, pos, value); } -Result Detector::getIndividualRxROIs(Positions pos) const { - return pimpl->Parallel(&Module::getRxROI, pos); +std::vector Detector::getRxROI() const { + return pimpl->getRxROI(); } -defs::ROI Detector::getRxROI() const { return pimpl->getRxROI(); } - -void Detector::setRxROI(const defs::ROI value) { pimpl->setRxROI(value); } +// RxROIs can be set for all types except CTB. At multi level without gap pixels +void Detector::setRxROI(const std::vector& args) { + pimpl->setRxROI(args); +} void Detector::clearRxROI() { pimpl->clearRxROI(); } +int Detector::getNumberOfUdpPortsInRxROI() const { + return pimpl->getNumberOfUdpPortsInRxROI(); + +} + // File Result Detector::getFileFormat(Positions pos) const { diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 3e3efb8b5..07117715a 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -31,6 +31,7 @@ namespace sls { + DetectorImpl::DetectorImpl(int detector_index, bool verify, bool update) : detectorIndex(detector_index), shm(detector_index, -1), ctb_shm(detector_index, -1, CtbConfig::shm_tag()) { @@ -130,10 +131,6 @@ 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) { @@ -539,7 +536,7 @@ void DetectorImpl::readFrameFromReceiver() { bool quadEnable = false; // to flip image bool eiger = false; - std::array rxRoi = shm()->rx_roi.getIntArray(); + std::array rxRoi {};//TODO: get roi from json header std::vector runningList(zmqSocket.size()); std::vector connectList(zmqSocket.size()); @@ -1696,7 +1693,8 @@ void DetectorImpl::verifyUniqueHost( } } -defs::ROI DetectorImpl::getRxROI() const { +std::vector DetectorImpl::getRxROI() const { + if (shm()->detType == CHIPTESTBOARD || shm()->detType == defs::XILINX_CHIPTESTBOARD) { throw RuntimeError("RxRoi not implemented for this Detector"); @@ -1704,6 +1702,9 @@ defs::ROI DetectorImpl::getRxROI() const { if (modules.size() == 0) { throw RuntimeError("No Modules added"); } + + return std::vector{}; + /* // complete detector in roi auto t = Parallel(&Module::getRxROI, {}); if (t.equal() && t.front().completeRoi()) { @@ -1770,9 +1771,56 @@ defs::ROI DetectorImpl::getRxROI() const { retval.ymax = 0; } return retval; + */ } -void DetectorImpl::setRxROI(const defs::ROI arg) { +bool DetectorImpl::roisOverlap(const defs::ROI& a, const defs::ROI& b) { + return !(a.xmax < b.xmin || a.xmin > b.xmax || + a.ymax < b.ymin || a.ymin > b.ymax); + +} + +void DetectorImpl::validateROIs(const std::vector& 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)); + } + if (roi.completeRoi()) { + throw RuntimeError("Did you mean the clear roi command (API: " + "clearRxROI, cmd: rx_clearroi) Roi: " + ToString(roi) + "?"); + } + 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)); + } + + bool is2D = (modules[0]->getNumberOfChannels().y > 1 ? true : false); + if (is2D) { + if (roi.ymin < 0 || roi.ymax >= shm()->numberOfChannels.y) { + throw RuntimeError("ROI y-dimension outside detector bounds. Roi: " + ToString(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])) { + clearRxROI(); + throw RuntimeError("Overlapping ROIs detected — all cleared."); + } + } + } +} + +void DetectorImpl::setRxROI(const std::vector& args) { if (shm()->detType == CHIPTESTBOARD || shm()->detType == defs::XILINX_CHIPTESTBOARD) { throw RuntimeError("RxRoi not implemented for this Detector"); @@ -1780,32 +1828,14 @@ void DetectorImpl::setRxROI(const defs::ROI arg) { 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(); - 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."); - } - - 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 (size_t iModule = 0; iModule != modules.size(); ++iModule) { // default init = complete roi @@ -1884,14 +1914,15 @@ void DetectorImpl::setRxROI(const defs::ROI arg) { } else { modules[0]->setRxROIMetadata(arg); } + */ } 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; + ;//Parallel(&Module::setRxROI, {}, defs::ROI{}); TODO: clear roi +} + +int DetectorImpl::getNumberOfUdpPortsInRxROI() const { + return 0;// TODO } void DetectorImpl::getBadChannels(const std::string &fname, diff --git a/slsDetectorSoftware/src/DetectorImpl.h b/slsDetectorSoftware/src/DetectorImpl.h index da56e5a22..c899566f2 100644 --- a/slsDetectorSoftware/src/DetectorImpl.h +++ b/slsDetectorSoftware/src/DetectorImpl.h @@ -24,7 +24,7 @@ class detectorData; class Module; #define DETECTOR_SHMAPIVERSION 0x190809 -#define DETECTOR_SHMVERSION 0x220505 +#define DETECTOR_SHMVERSION 0x250616 #define SHORT_STRING_LENGTH 50 /** @@ -65,8 +65,6 @@ 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 { @@ -303,9 +301,10 @@ class DetectorImpl : public virtual slsDetectorDefs { std::vector> verifyUniqueRxHost(const std::vector &names) const; - defs::ROI getRxROI() const; - void setRxROI(const defs::ROI arg); + std::vector getRxROI() const; + void setRxROI(const std::vector& args); void clearRxROI(); + int getNumberOfUdpPortsInRxROI() const; void getBadChannels(const std::string &fname, Positions pos) const; void setBadChannels(const std::string &fname, Positions pos); @@ -428,6 +427,9 @@ class DetectorImpl : public virtual slsDetectorDefs { void verifyUniqueHost( bool isDet, std::vector> &hosts) const; + bool roisOverlap(const defs::ROI& a, const defs::ROI& b); + void validateROIs(const std::vector& rois); + const int detectorIndex{0}; SharedMemory shm{0, -1}; SharedMemory ctb_shm{0, -1, CtbConfig::shm_tag()}; diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index d1356c30f..47f4ffe79 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -1520,7 +1520,7 @@ bool Module::getRxArping() const { void Module::setRxArping(bool enable) { sendToReceiver(F_SET_RECEIVER_ARPING, static_cast(enable), nullptr); } - +/* defs::ROI Module::getRxROI() const { return sendToReceiver(F_RECEIVER_GET_RECEIVER_ROI); } @@ -1533,7 +1533,7 @@ void Module::setRxROI(const slsDetectorDefs::ROI arg) { void Module::setRxROIMetadata(const slsDetectorDefs::ROI arg) { sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI_METADATA, arg, nullptr); } - +*/ // File slsDetectorDefs::fileFormat Module::getFileFormat() const { return sendToReceiver(F_GET_RECEIVER_FILE_FORMAT); diff --git a/slsDetectorSoftware/src/Module.h b/slsDetectorSoftware/src/Module.h index 86c9e3d5f..a687be6c3 100644 --- a/slsDetectorSoftware/src/Module.h +++ b/slsDetectorSoftware/src/Module.h @@ -301,9 +301,9 @@ class Module : public virtual slsDetectorDefs { std::array getReceiverThreadIds() const; bool getRxArping() const; void setRxArping(bool enable); - defs::ROI getRxROI() const; - void setRxROI(const slsDetectorDefs::ROI arg); - void setRxROIMetadata(const slsDetectorDefs::ROI arg); + //defs::ROI getRxROI() const; + //void setRxROI(const slsDetectorDefs::ROI arg); + //void setRxROIMetadata(const slsDetectorDefs::ROI arg); /************************************************** * * diff --git a/slsDetectorSoftware/tests/CMakeLists.txt b/slsDetectorSoftware/tests/CMakeLists.txt index d87f17ed0..f70e393f2 100755 --- a/slsDetectorSoftware/tests/CMakeLists.txt +++ b/slsDetectorSoftware/tests/CMakeLists.txt @@ -5,6 +5,7 @@ target_sources(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test-SharedMemory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-slsDetector.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test-Roi.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller-rx.cpp diff --git a/slsDetectorSoftware/tests/test-Roi.cpp b/slsDetectorSoftware/tests/test-Roi.cpp new file mode 100644 index 000000000..9ce6c3b30 --- /dev/null +++ b/slsDetectorSoftware/tests/test-Roi.cpp @@ -0,0 +1,84 @@ +#include "catch.hpp" +#include + +#include + +#include "DetectorImpl.h" +#include "sls/Detector.h" +#include "Module.h" + +#include + +namespace sls { + +TEST_CASE("ROI validation") { + DetectorImpl det(0, false, false); + det.addTestModule(slsDetectorDefs::JUNGFRAU); + std::cout << "size:"<< det.size() << std::endl; + DetectorImpl detector(0, false, false); + + SECTION("Valid non-overlapping ROIs") { + std::vector rois = { + {0, 10, 0, 10}, + {20, 30, 0, 10}, + {0, 10, 20, 30}, + {40, 50, 0, 10} + }; + REQUIRE_NOTHROW(DetectorImplTestHelper::testValidateRois(detector, rois)); + } + + SECTION("Overlapping ROIs should throw") { + std::vector rois = { + {0, 10, 0, 10}, + {5, 15, 0, 10} + }; + REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), + sls::RuntimeError); + } + + SECTION("Invalid ROI (xmin > xmax)") { + std::vector rois = { + {12, 8, 0, 10} + }; + REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), + sls::RuntimeError); + } + + SECTION("Invalid ROI (ymin > ymax)") { + std::vector rois = { + {0, 10, 20, 5} + }; + REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), + sls::RuntimeError); + } + + SECTION("Invalid ROI (outside detector bounds)") { + // Assuming detector has 100x100 dimensions + detector.setNumberOfChannels({100, 100}); + std::vector rois = { + {95, 105, 0, 10} // xmax out of bounds + }; + REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), + sls::RuntimeError); + } + + SECTION("Valid ROI for 1D detector") { + detector.setNumberOfChannels({100, 1}); + std::vector rois = { + {10, 20, -1, -1} + }; + REQUIRE_NOTHROW(DetectorImplTestHelper::testValidateRois(detector, rois)); + } + + SECTION("Invalid Y for 1D detector") { + detector.setNumberOfChannels({100, 1}); + std::vector rois = { + {10, 20, 0, 10} // Y should be -1 for 1D + }; + REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), + sls::RuntimeError); + } +} + + +} // namespace sls