diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index ae407f22b..aaca367ec 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -119,6 +119,10 @@ class Detector { Result getModuleSize(Positions pos = {}) const; + defs::xy getPortPerModuleGeometry() const; + + Result getPortSize(Positions pos = {}) const; + /** Gets the actual full detector size. It is the same even if ROI changes */ defs::xy getDetectorSize() const; diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index 033224ad8..bb0cfdf2f 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -722,16 +722,15 @@ std::string Caller::rx_zmqip(int action) { 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 << "[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" - << "For example: [0, 100, 0, 100];[200, 300, 0, 100] will set two " - "rois.\n\t" - << "Only allowed at multi module level and without gap " - "pixels." - << '\n'; + os << helpMessage; } else if (action == defs::GET_ACTION) { if (!args.empty()) { WrongNumberOfParameters(0); @@ -759,26 +758,29 @@ std::string Caller::rx_roi(int action) { return a.find('[') != std::string::npos && a.find(']') != std::string::npos; }); - - // previous format: 2 or 4 separate args - if ((args.size() == 2 || args.size() == 4) && !isVectorInput) { - defs::ROI t; - t.xmin = StringTo(args[0]); - t.xmax = StringTo(args[1]); - if (args.size() == 4) { - t.ymin = StringTo(args[2]); - t.ymax = StringTo(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()); + try { + // previous format: 2 or 4 separate args + if ((args.size() == 2 || args.size() == 4) && !isVectorInput) { + defs::ROI t; + t.xmin = StringTo(args[0]); + t.xmax = StringTo(args[1]); + if (args.size() == 4) { + t.ymin = StringTo(args[2]); + t.ymax = StringTo(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); } // only multi level @@ -791,9 +793,9 @@ std::string Caller::rx_roi(int action) { for (const auto &r : rois) { os << r << ';'; } - if (!rois.empty()) { - os.seekp(-1, std::ios_base::end); // remove trailing ; - } + //if (!rois.empty()) { + // os.seekp(-1, std::ios_base::end); // remove trailing ; + //} os << '\n'; } else { throw RuntimeError("Unknown action"); diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index 785868e2d..960b84654 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -201,6 +201,22 @@ Result Detector::getModuleSize(Positions pos) const { return pimpl->Parallel(&Module::getNumberOfChannels, pos); } +defs::xy Detector::getPortPerModuleGeometry() const { + return pimpl->getPortGeometry(); +} + +Result Detector::getPortSize(Positions pos) const { + Result 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(); } diff --git a/slsDetectorSoftware/src/DetectorImpl.h b/slsDetectorSoftware/src/DetectorImpl.h index b4329de49..4d82088b7 100644 --- a/slsDetectorSoftware/src/DetectorImpl.h +++ b/slsDetectorSoftware/src/DetectorImpl.h @@ -301,6 +301,7 @@ class DetectorImpl : public virtual slsDetectorDefs { std::vector> verifyUniqueRxHost(const std::vector &names) const; + defs::xy getPortGeometry() const; std::vector getRxROI() const; void setRxROI(const std::vector &args); void clearRxROI(); @@ -428,7 +429,6 @@ class DetectorImpl : public virtual slsDetectorDefs { void validateROIs(const std::vector &rois); defs::xy calculatePosition(size_t moduleIndex, const defs::xy &geometry) const; - defs::xy getPortGeometry() const; defs::xy calculatePosition(int moduleIndex, defs::xy geometry) const; defs::ROI getModuleROI(int moduleIndex) const; void convertGlobalRoiToPortLevel( diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 45e2b8cc8..aff9ef607 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -466,7 +466,6 @@ TEST_CASE("rx_arping", "[.cmdcall][.rx]") { } } } - TEST_CASE("rx_roi", "[.cmdcall]") { Detector det; Caller caller(&det); @@ -479,8 +478,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { defs::xy detsize = det.getDetectorSize(); // 1d - if (det_type == defs::GOTTHARD || det_type == defs::GOTTHARD2 || - det_type == defs::MYTHEN3) { + if (det_type == defs::GOTTHARD2 || det_type == defs::MYTHEN3) { { std::ostringstream oss; caller.call("rx_roi", {"5", "10"}, -1, PUT, oss); @@ -491,20 +489,6 @@ TEST_CASE("rx_roi", "[.cmdcall]") { caller.call("rx_roi", {"10", "15"}, -1, PUT, oss); REQUIRE(oss.str() == "rx_roi [10, 15]\n"); } - // vector of rois - // separated by space is allowed - REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[5, 10, -1, -1]", "[25, 28, -1, -1]"}, -1, PUT)); - // separated by semicolon is allowed - REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[0, 10, -1, -1];[20, 30, -1, -1];[40, 50, -1, -1]"}, - -1, PUT)); - // 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)); REQUIRE_THROWS(caller.call("rx_roi", {"0", "0"}, -1, PUT)); REQUIRE_THROWS(caller.call("rx_roi", {"-1", "-1"}, -1, PUT)); // xmin > xmax @@ -516,19 +500,37 @@ TEST_CASE("rx_roi", "[.cmdcall]") { PUT)); // module level not allowed REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 10, -1, -1]; [25, 28, -1, -1]"}, 0, PUT)); + "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)); - // valid - { + + 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; - caller.call("rx_roi", {"[5, 10, -1, -1]; [15, 20, -1, -1]"}, -1, - PUT, oss); - REQUIRE(oss.str() == "rx_roi [5, 10];[15, 20]\n"); + // 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"); + } } - // 2d + // 2d eiger, jungfrau, moench else { { std::ostringstream oss; @@ -552,21 +554,6 @@ TEST_CASE("rx_roi", "[.cmdcall]") { std::to_string(detsize.y - 5) + std::string("]\n")); } - // vector of rois - // separated by space is allowed - REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[5, 10, 20, 30]", "[25, 28, 14, 15]"}, -1, PUT)); - // separated by semicolon is allowed - REQUIRE_NOTHROW(caller.call("rx_roi", - {"[0, 10, 0, 10];[20, 30, 0, 10];[0, " - "10, 20, 30];[40, 50, 0, 10]"}, - -1, PUT)); - // 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)); REQUIRE_THROWS( caller.call("rx_roi", {"0", "0", "0", "0"}, -1, PUT)); REQUIRE_THROWS( @@ -585,19 +572,58 @@ TEST_CASE("rx_roi", "[.cmdcall]") { PUT)); // module level not allowed REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 10, 20, 30]; [25, 28, 14, 15]"}, 0, PUT)); + "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)); - // valid - { + + 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; - caller.call("rx_roi", {"[5, 10, 20, 30]; [25, 28, 14, 15]"}, -1, - PUT, 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];[25, 28, 14, 15]\n"); + "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"); + } } } @@ -607,6 +633,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { } } + TEST_CASE("rx_clearroi", "[.cmdcall]") { Detector det; Caller caller(&det);