From 4ceee97c03a008ae47989d98162fe698c9e319b2 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil <33750417+thattil@users.noreply.github.com> Date: Wed, 7 Aug 2019 11:21:07 +0200 Subject: [PATCH] Api (#48) * WIP * WIP * WIP * cleaned up multi * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * split up python module * WIP * WIP * WIP * WIP * WIP * ok * fixed bugs from rebase * WIP * fixed broken test * WIP * fixed python * WIP * sphinx help * including new commands * docs * WIP * WIP * more tests * added missing public header * WIP --- .gitignore | 1 - CMakeLists.txt | 21 +- cmake/FindSphinx.cmake | 11 + docs/CMakeLists.txt | 67 +++ {doxygen => docs}/Doxyfile.in | 10 +- docs/conf.py.in | 62 +++ docs/src/ToString.rst | 6 + docs/src/commandline.rst | 16 + docs/src/container_utils.rst | 14 + docs/src/dependencies.rst | 53 ++ docs/src/detector.rst | 16 + docs/src/gendoc.cpp | 56 +++ docs/src/index.rst | 50 ++ docs/src/installation.rst | 5 + docs/src/pydetector.rst | 9 + docs/src/pyenums.rst | 12 + .../examples.rst => docs/src/pyexamples.rst | 4 +- docs/src/receiver.rst | 6 + docs/src/result.rst | 4 + docs/src/type_traits.rst | 7 + integrationTests/CMakeLists.txt | 23 +- integrationTests/a.cpp | 88 ---- python/CMakeLists.txt | 8 +- python/setup.py | 4 +- python/sls_detector/__init__.py | 3 + python/sls_detector/experimental.py | 181 ++++++- .../{Detector.h => DetectorPythonInterface.h} | 26 +- python/src/enums.cpp | 19 + python/src/experimental.cpp | 70 +++ python/src/main.cpp | 469 +++++++++--------- python/src/typecaster.h | 11 + sample/CMakeLists.txt | 21 + sample/api.cpp | 67 +++ sample/useResult.cpp | 55 ++ slsDetectorSoftware/CMakeLists.txt | 3 + slsDetectorSoftware/include/Detector.h | 127 +++++ slsDetectorSoftware/include/Result.h | 99 ++++ .../include/multiSlsDetector.h | 411 +++++++++------ .../include/multiSlsDetectorClient.h | 8 +- slsDetectorSoftware/include/slsDetector.h | 2 +- slsDetectorSoftware/src/Detector.cpp | 129 +++++ slsDetectorSoftware/src/multiSlsDetector.cpp | 6 + slsDetectorSoftware/src/slsDetector.cpp | 2 +- slsDetectorSoftware/tests/CMakeLists.txt | 1 + slsDetectorSoftware/tests/test-Result.cpp | 75 +++ .../tests/test-multiSlsDetectorClient.cpp | 41 +- slsSupportLib/CMakeLists.txt | 4 + slsSupportLib/include/CmdProxy.h | 100 +++- slsSupportLib/include/TimeHelper.h | 19 + slsSupportLib/include/ToString.h | 140 ++++++ slsSupportLib/include/TypeTraits.h | 48 ++ slsSupportLib/include/container_utils.h | 43 +- .../include/sls_detector_exceptions.h | 8 - slsSupportLib/include/string_utils.h | 31 +- slsSupportLib/src/ToString.cpp | 18 + slsSupportLib/src/string_utils.cpp | 12 + slsSupportLib/tests/CMakeLists.txt | 1 + slsSupportLib/tests/test-ToString.cpp | 85 ++++ 58 files changed, 2317 insertions(+), 571 deletions(-) create mode 100644 cmake/FindSphinx.cmake create mode 100644 docs/CMakeLists.txt rename {doxygen => docs}/Doxyfile.in (99%) create mode 100644 docs/conf.py.in create mode 100644 docs/src/ToString.rst create mode 100644 docs/src/commandline.rst create mode 100644 docs/src/container_utils.rst create mode 100644 docs/src/dependencies.rst create mode 100644 docs/src/detector.rst create mode 100644 docs/src/gendoc.cpp create mode 100644 docs/src/index.rst create mode 100644 docs/src/installation.rst create mode 100644 docs/src/pydetector.rst create mode 100644 docs/src/pyenums.rst rename python/sphinx/examples.rst => docs/src/pyexamples.rst (98%) create mode 100644 docs/src/receiver.rst create mode 100644 docs/src/result.rst create mode 100644 docs/src/type_traits.rst delete mode 100644 integrationTests/a.cpp rename python/src/{Detector.h => DetectorPythonInterface.h} (97%) create mode 100644 python/src/enums.cpp create mode 100644 python/src/experimental.cpp create mode 100644 python/src/typecaster.h create mode 100644 sample/CMakeLists.txt create mode 100644 sample/api.cpp create mode 100644 sample/useResult.cpp create mode 100644 slsDetectorSoftware/include/Detector.h create mode 100644 slsDetectorSoftware/include/Result.h create mode 100644 slsDetectorSoftware/src/Detector.cpp create mode 100644 slsDetectorSoftware/tests/test-Result.cpp create mode 100644 slsSupportLib/include/TimeHelper.h create mode 100644 slsSupportLib/include/ToString.h create mode 100644 slsSupportLib/include/TypeTraits.h create mode 100644 slsSupportLib/src/ToString.cpp create mode 100644 slsSupportLib/tests/test-ToString.cpp diff --git a/.gitignore b/.gitignore index efbd9ce60..d31ff259f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ bin/ *.o .* build -docs/ RELEASE.txt Testing/ diff --git a/CMakeLists.txt b/CMakeLists.txt index ac8d0068e..ab0c1dac6 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,7 +129,7 @@ set(CMAKE_INSTALL_RPATH "$ORIGIN") set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) -find_package(Doxygen) + find_package(ZeroMQ 4 REQUIRED) if (SLS_USE_TESTS) @@ -182,24 +182,11 @@ configure_file( .clang-tidy ) -if (DOXYGEN_FOUND) - # set input and output files - set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/doxygen/Doxyfile.in) - set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) +add_subdirectory(sample) + +add_subdirectory(docs) - # request to configure the file - configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY) - message("Doxygen build started") - # note the option ALL which allows to build the docs together with the application - add_custom_target( docs - COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating API documentation with Doxygen" - VERBATIM ) -else (DOXYGEN_FOUND) - message("Doxygen need to be installed to generate the doxygen documentation") -endif (DOXYGEN_FOUND) if(SLS_MASTER_PROJECT) diff --git a/cmake/FindSphinx.cmake b/cmake/FindSphinx.cmake new file mode 100644 index 000000000..7e5dfd065 --- /dev/null +++ b/cmake/FindSphinx.cmake @@ -0,0 +1,11 @@ +#Look for an executable called sphinx-build +find_program(SPHINX_EXECUTABLE + NAMES sphinx-build + DOC "Path to sphinx-build executable") + +include(FindPackageHandleStandardArgs) + +#Handle standard arguments to find_package like REQUIRED and QUIET +find_package_handle_standard_args(Sphinx + "Failed to find sphinx-build executable" + SPHINX_EXECUTABLE) \ No newline at end of file diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt new file mode 100644 index 000000000..7d9d32e42 --- /dev/null +++ b/docs/CMakeLists.txt @@ -0,0 +1,67 @@ +find_package(Doxygen) +find_package(Sphinx) + + +if (DOXYGEN_FOUND AND SPHINX_FOUND) + + # #Utility to generate command line documentation + add_executable(gendoc src/gendoc.cpp) + target_link_libraries(gendoc PRIVATE + slsDetectorShared + ) + set_target_properties(gendoc PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin + ) + + + + + #Doxygen + set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) + set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY) + + #Sphinx + set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src) + set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}) + + set(SPHINX_SOURCE_FILES + src/commandline.rst + src/container_utils.rst + src/dependencies.rst + src/detector.rst + src/index.rst + src/installation.rst + src/pydetector.rst + src/pyenums.rst + src/pyexamples.rst + src/receiver.rst + src/result.rst + src/type_traits.rst + src/ToString.rst + + ) + + foreach(filename ${SPHINX_SOURCE_FILES}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${filename} + "${SPHINX_BUILD}/${filename}") + endforeach(filename ${SPHINX_SOURCE_FILES}) + + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in" + "${SPHINX_BUILD}/conf.py" + @ONLY) + + add_custom_target(docs + gendoc + COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} + COMMAND ${SPHINX_EXECUTABLE} -a -b html + -Dbreathe_projects.slsDetectorPackage=${CMAKE_CURRENT_BINARY_DIR}/xml + -c "${SPHINX_BUILD}" + ${SPHINX_BUILD}/src + ${SPHINX_BUILD}/html + COMMENT "Generating documentation with Sphinx") + +else (DOXYGEN_FOUND AND SPHINX_FOUND) + message("Doxygen and Sphinx are needed to build documentation") +endif (DOXYGEN_FOUND AND SPHINX_FOUND) diff --git a/doxygen/Doxyfile.in b/docs/Doxyfile.in similarity index 99% rename from doxygen/Doxyfile.in rename to docs/Doxyfile.in index 6af795392..6ebcfe04a 100644 --- a/doxygen/Doxyfile.in +++ b/docs/Doxyfile.in @@ -58,7 +58,7 @@ PROJECT_LOGO = # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/docs/ +OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@ # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and @@ -791,7 +791,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = @CMAKE_CURRENT_SOURCE_DIR@ +INPUT = @PROJECT_SOURCE_DIR@ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -890,7 +890,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = */tests/* */python */manual */rapidjson */catch */integrationTests *README* */slsDetectorGui/* +EXCLUDE_PATTERNS = */docs/* */tests/* */python/* */manual */slsDetectorServers/* */libs/* */integrationTests *README* */slsDetectorGui/* */ctbGui/* */slsDetectorCalibration/* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -1104,7 +1104,7 @@ IGNORE_PREFIX = # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. -GENERATE_HTML = YES +GENERATE_HTML = NO # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1936,7 +1936,7 @@ MAN_LINKS = NO # captures the structure of the code including all documentation. # The default value is: NO. -GENERATE_XML = NO +GENERATE_XML = YES # The XML_OUTPUT tag is used to specify where the XML pages will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of diff --git a/docs/conf.py.in b/docs/conf.py.in new file mode 100644 index 000000000..a420abec3 --- /dev/null +++ b/docs/conf.py.in @@ -0,0 +1,62 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +# sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath('../bin/')) +#sys.path.insert(0, '/home/l_frojdh/sls/build/bin') +#sys.path.insert(0, @CMAKE_CURRENT_BINARY_DIR@) +print(sys.path) + +# -- Project information ----------------------------------------------------- + +project = 'slsDetectorPackage' +copyright = '2019, PSD Detector Group' +author = 'PSD Detector Group' +version = '@PROJECT_VERSION@' + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['breathe', + 'sphinx_rtd_theme', + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon', + ] + +breathe_default_project = "slsDetectorPackage" +napoleon_use_ivar = True + + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "sphinx_rtd_theme" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +#html_static_path = ['_static'] diff --git a/docs/src/ToString.rst b/docs/src/ToString.rst new file mode 100644 index 000000000..cfb02e799 --- /dev/null +++ b/docs/src/ToString.rst @@ -0,0 +1,6 @@ +ToString +============== + +String conversion + +.. doxygenfile:: ToString.h \ No newline at end of file diff --git a/docs/src/commandline.rst b/docs/src/commandline.rst new file mode 100644 index 000000000..1a7380745 --- /dev/null +++ b/docs/src/commandline.rst @@ -0,0 +1,16 @@ +Command line interface +============================================== + +Usage +------------- + +Commands can be uses either with sls_detector_get or sls_detector_put + +.. code-block:: + + sls_detector_get vrf + +Commands +----------- + +.. include:: ../commands.rst diff --git a/docs/src/container_utils.rst b/docs/src/container_utils.rst new file mode 100644 index 000000000..1f87108ff --- /dev/null +++ b/docs/src/container_utils.rst @@ -0,0 +1,14 @@ +ContainerUtils +================== + +Helper functions to handle standard container compliant +containers. Supports array, vector, sls::Result etc. + +While not a part of the public API we aim not to change this +interface too much. However, we don't give the same strong +guarantees as for Detector etc. + +Any reoccurring container operation should probably be added to +this file. + +.. doxygenfile:: container_utils.h \ No newline at end of file diff --git a/docs/src/dependencies.rst b/docs/src/dependencies.rst new file mode 100644 index 000000000..2d9b76204 --- /dev/null +++ b/docs/src/dependencies.rst @@ -0,0 +1,53 @@ +Dependencies +========================= + +While we value few dependencies some libraries are required in +order to not have to reinvent the wheel. Due to the state of package +management in C++ we decided to bundle some of them with our source +code. These are found in the libs/ directory. + +----------------------- +Core +----------------------- +To use the basic building blocks, meaning sls_detector_get/put and +the shared libraries these are needed: + + * Linux, preferably recent kernel (currently no cross platform support) + * CMake > 3.9 + * C++11 compatible compiler. (We test with gcc and clang) + * ZeroMQ version 4 + +----------------------- +GUI +----------------------- + +The GUI is currently using Qt4 but watch out for an upgrade to 5. + + * Qt 4.8 + * Qwt 6 + +----------------------- +Python bindings +----------------------- + + * Python > 3.6 + * pybind11 (packaged in libs/) + + +----------------------- +Documentation +----------------------- + +The documentation that you are reading now is built with + + * Doxygen (to extract C++ classes etc.) + * Breathe (Sphinx plugin to handle doxygen xml) + * Sphinx + +----------------------- +Packaged in libs/ +----------------------- + + * catch2 (unit testing) + * rapidjson (streaming from receiver) + * pybind11 (python bindings) \ No newline at end of file diff --git a/docs/src/detector.rst b/docs/src/detector.rst new file mode 100644 index 000000000..a78447f99 --- /dev/null +++ b/docs/src/detector.rst @@ -0,0 +1,16 @@ +Detector +============================================== + +The sls::Detector is the new public API to control +detectors from C++. This API is also used internally +for the Python bindings and the command line interface. +If a receiver has been configured this is also controlled +through this class. + +Most, if not all, functions are called in parallel +and the return value is a thin std::vector wrapper +containing results from all modules. (Result) + +.. doxygenclass:: sls::Detector + :members: + :undoc-members: \ No newline at end of file diff --git a/docs/src/gendoc.cpp b/docs/src/gendoc.cpp new file mode 100644 index 000000000..31dc13246 --- /dev/null +++ b/docs/src/gendoc.cpp @@ -0,0 +1,56 @@ +/** + * Utility program to generate input files for the command line + * documentation. Uses the string returned from sls_detector_help cmd + * + */ +#include +#include +#include +#include +#include + + +#include "CmdProxy.h" +#include "Detector.h" +#include "sls_detector_defs.h" + +std::string replace_all(const std::string &src, const std::string &from, + const std::string &to) { + + std::string results; + std::string::const_iterator end = src.end(); + std::string::const_iterator current = src.begin(); + std::string::const_iterator next = + std::search(current, end, from.begin(), from.end()); + while (next != end) { + results.append(current, next); + results.append(to); + current = next + from.size(); + next = std::search(current, end, from.begin(), from.end()); + } + results.append(current, next); + return results; +} + +int main() { + + std::cout << "Generating command line documentation!\n"; + + sls::CmdProxy proxy(nullptr); + auto commands = proxy.GetProxyCommands(); + + std::ofstream fs("commands.rst"); + fs << ".. glossary::\n"; + + for (const auto &cmd : commands) { + std::ostringstream os; + proxy.Call(cmd, {}, -1, slsDetectorDefs::HELP_ACTION, os); + + auto tmp = os.str().erase(0, cmd.size()); + auto usage = tmp.substr(0, tmp.find_first_of('\n')); + tmp.erase(0, usage.size()); + auto help = replace_all(tmp, "\n\t", "\n\t\t"); + fs << '\t' << cmd << usage << help << "\n"; + } + +} \ No newline at end of file diff --git a/docs/src/index.rst b/docs/src/index.rst new file mode 100644 index 000000000..3b5141d26 --- /dev/null +++ b/docs/src/index.rst @@ -0,0 +1,50 @@ +.. slsDetectorPackage documentation master file, created by + sphinx-quickstart on Mon Jul 29 17:38:15 2019. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to slsDetectorPackage's documentation! +============================================== + +.. toctree:: + :maxdepth: 1 + :caption: Installation: + + installation + dependencies + +.. toctree:: + :caption: C++ API + :maxdepth: 2 + + detector + result + receiver + +.. toctree:: + :caption: Python API + :maxdepth: 2 + + pydetector + pyenums + pyexamples + +.. toctree:: + :caption: Command line + :maxdepth: 2 + + commandline + +.. toctree:: + :caption: Developer + + container_utils + type_traits + ToString + +.. Indices and tables +.. ================== + +.. * :ref:`genindex` +.. * :ref:`modindex` +.. * :ref:`search` diff --git a/docs/src/installation.rst b/docs/src/installation.rst new file mode 100644 index 000000000..4a363e182 --- /dev/null +++ b/docs/src/installation.rst @@ -0,0 +1,5 @@ + +Installation +============================================== + +get the source etc. \ No newline at end of file diff --git a/docs/src/pydetector.rst b/docs/src/pydetector.rst new file mode 100644 index 000000000..c9cf612e3 --- /dev/null +++ b/docs/src/pydetector.rst @@ -0,0 +1,9 @@ +Detector +===================================================== + +.. py:currentmodule:: sls_detector + +.. autoclass:: ExperimentalDetector + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/src/pyenums.rst b/docs/src/pyenums.rst new file mode 100644 index 000000000..9fa518968 --- /dev/null +++ b/docs/src/pyenums.rst @@ -0,0 +1,12 @@ +Enums +=========== + +These enums are defined in slsDetectorDefs in the C++ package and +exposed to Python through pybind11. + +.. py:currentmodule:: sls_detector + +.. autoclass:: runStatus + :members: + :undoc-members: + :show-inheritance: diff --git a/python/sphinx/examples.rst b/docs/src/pyexamples.rst similarity index 98% rename from python/sphinx/examples.rst rename to docs/src/pyexamples.rst index f3bc7d478..7b3eb7b1d 100755 --- a/python/sphinx/examples.rst +++ b/docs/src/pyexamples.rst @@ -18,7 +18,7 @@ file writing etc. threshold = range(0, 2000, 200) for th in threshold: d.vthreshold = th - d.acq() + d.acquire() If we want to control the shutter of for example, the big X-ray box we can add @@ -30,7 +30,7 @@ and closes is afterwards. with xrf_shutter_open(box, 'Fe'): for th in threshold: d.vthreshold = th - d.acq() + d.acquire() ----------------------- diff --git a/docs/src/receiver.rst b/docs/src/receiver.rst new file mode 100644 index 000000000..a909e7cba --- /dev/null +++ b/docs/src/receiver.rst @@ -0,0 +1,6 @@ +Receiver +============================================== + +.. doxygenclass:: slsReceiver + :members: +.. :undoc-members: \ No newline at end of file diff --git a/docs/src/result.rst b/docs/src/result.rst new file mode 100644 index 000000000..1abd1b4a3 --- /dev/null +++ b/docs/src/result.rst @@ -0,0 +1,4 @@ +Result +============================================== + +.. doxygenfile:: Result.h diff --git a/docs/src/type_traits.rst b/docs/src/type_traits.rst new file mode 100644 index 000000000..da8c3c5de --- /dev/null +++ b/docs/src/type_traits.rst @@ -0,0 +1,7 @@ +TypeTraits +============== + +Template meta functions in the same spirit as type_traits +from the standard library. + +.. doxygenfile:: TypeTraits.h \ No newline at end of file diff --git a/integrationTests/CMakeLists.txt b/integrationTests/CMakeLists.txt index 5bfc62e07..5aba78ee0 100755 --- a/integrationTests/CMakeLists.txt +++ b/integrationTests/CMakeLists.txt @@ -7,11 +7,11 @@ # ${PROJECT_SOURCE_DIR}/catch # ) -target_sources(tests PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/test-integrationMulti.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test-integrationDectector.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test-eigerIntegration.cpp -) +# target_sources(tests PRIVATE +# ${CMAKE_CURRENT_SOURCE_DIR}/test-integrationMulti.cpp +# ${CMAKE_CURRENT_SOURCE_DIR}/test-integrationDectector.cpp +# ${CMAKE_CURRENT_SOURCE_DIR}/test-eigerIntegration.cpp +# ) # if(SLS_USE_TESTS) # set(TEST_SOURCES @@ -32,18 +32,7 @@ target_sources(tests PRIVATE # RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin # ) -# add_executable(a src/a.cpp) -# target_link_libraries(a -# slsProjectOptions -# slsProjectWarnings -# slsDetectorShared -# slsSupportLib -# pthread -# rt -# ) -# set_target_properties(a PROPERTIES -# RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin -# ) + # endif() diff --git a/integrationTests/a.cpp b/integrationTests/a.cpp deleted file mode 100644 index 216fc41a8..000000000 --- a/integrationTests/a.cpp +++ /dev/null @@ -1,88 +0,0 @@ - -#include "catch.hpp" - -#include "ClientSocket.h" -#include "Timer.h" -#include "logger.h" -#include "network_utils.h" -#include "slsDetector.h" -#include "sls_detector_defs.h" -#include "sls_detector_exceptions.h" -#include "sls_detector_funcs.h" -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "network_utils.h" - -using namespace sls; -using ROI = slsDetectorDefs::ROI; - -// Easy printing of an ROI -std::ostream &operator<<(std::ostream &out, const ROI &r) { - return out << "xmin: " << std::setw(5) << r.xmin - << " xmax: " << std::setw(5) << r.xmax - << " ymin: " << std::setw(5) << r.ymin - << " ymax: " << std::setw(5) << r.ymax; -} - -int main() { - - std::cout << "nullptr: " << sizeof(nullptr) << "\n"; - // int ret[]{0,0,0}; - // for (auto i: ret) - // std::cout << i << "\n"; - // uint32_t imageSize = 101; - // uint32_t packetSize = 100; - // std::cout << "a: " << std::ceil((double)imageSize / (double)packetSize) <<'\n'; - // std::cout << "b: " << imageSize / packetSize <<'\n'; - // std::cout << "c: " << static_cast(imageSize / packetSize) << '\n'; - // std::cout << "c: " << (imageSize + packetSize-1) / packetSize << '\n'; - - // slsDetectorDefs::ROI roilimits[5]; - // roilimits[0].xmin = 5; - // roilimits[0].xmax = 12; - // roilimits[0].ymin = 5; - // roilimits[0].ymax = 15; - - // roilimits[1].xmin = 0; - // roilimits[1].xmax = 3; - // roilimits[1].ymin = 20; - // roilimits[1].ymax = 25; - - // roilimits[2].xmin = 500; - // roilimits[2].xmax = 600; - // roilimits[2].ymin = 100; - // roilimits[2].ymax = 200; - - // roilimits[3].xmin = 300; - // roilimits[3].xmax = 500; - // roilimits[3].ymin = 800; - // roilimits[3].ymax = 900; - - // roilimits[4].xmin = 1000; - // roilimits[4].xmax = 2000; - // roilimits[4].ymin = 300; - // roilimits[4].ymax = 500; - - // std::cout << "Before sorting:\n"; - // for (auto r : roilimits) { - // std::cout << r << '\n'; - // } - - // std::sort(std::begin(roilimits), std::end(roilimits), - // [](ROI a, ROI b) { return a.xmin < b.xmin; }); - - // std::cout << "After sorting: \n"; - // for (auto r : roilimits) { - // std::cout << r << '\n'; - // } -} diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 12042c6b6..93b70120b 100755 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,11 +1,13 @@ -pybind11_add_module(_sls_detector src/main.cpp) +pybind11_add_module(_sls_detector + src/main.cpp + src/enums.cpp + src/experimental.cpp +) target_link_libraries(_sls_detector PUBLIC - slsProjectOptions - slsProjectWarnings slsDetectorShared slsReceiverShared slsSupportLib diff --git a/python/setup.py b/python/setup.py index 0ccbf9f04..264cb946d 100755 --- a/python/setup.py +++ b/python/setup.py @@ -36,7 +36,9 @@ class get_pybind_include(object): ext_modules = [ Extension( '_sls_detector', - ['src/main.cpp'], + ['src/main.cpp', + 'src/enums.cpp', + 'src/experimental.cpp'], include_dirs=[ # Path to pybind11 headers get_pybind_include(), diff --git a/python/sls_detector/__init__.py b/python/sls_detector/__init__.py index ff98359a3..dc5202f13 100755 --- a/python/sls_detector/__init__.py +++ b/python/sls_detector/__init__.py @@ -4,3 +4,6 @@ from .experimental import ExperimentalDetector from .jungfrau import Jungfrau from .jungfrau_ctb import JungfrauCTB from _sls_detector import DetectorApi + +import _sls_detector +runStatus = _sls_detector.slsDetectorDefs.runStatus diff --git a/python/sls_detector/experimental.py b/python/sls_detector/experimental.py index a7f54416e..1f9c749e1 100755 --- a/python/sls_detector/experimental.py +++ b/python/sls_detector/experimental.py @@ -1,9 +1,180 @@ - from _sls_detector import multiDetectorApi +from _sls_detector import slsDetectorDefs +runStatus = slsDetectorDefs.runStatus +from .utils import element_if_equal, all_equal +import datetime as dt + +from functools import wraps + + +def freeze(cls): + cls.__frozen = False + + def frozensetattr(self, key, value): + if self.__frozen and not hasattr(self, key): + raise AttributeError( + "Class {} is frozen. Cannot set {} = {}".format( + cls.__name__, key, value + ) + ) + else: + object.__setattr__(self, key, value) + + def init_decorator(func): + @wraps(func) + def wrapper(self, *args, **kwargs): + func(self, *args, **kwargs) + self.__frozen = True + + return wrapper + + cls.__setattr__ = frozensetattr + cls.__init__ = init_decorator(cls.__init__) + return cls + + +@freeze class ExperimentalDetector(multiDetectorApi): - def __init__(self): - super().__init__(0) - self.online = True + """ + This class is the base for detector specific + interfaces. Most functions exists in two versions + like the getExptime() function that uses the + C++ API directly and the simplified exptime property. + """ + def __init__(self, multi_id = 0): + """ + multi_id refers to the shared memory id of the + slsDetectorPackage. Default value is 0. + """ + super().__init__(multi_id) + + # Acq + @property + def rx_status(self): + """ + Read the status of the receiver + """ + return element_if_equal(self.getReceiverStatus()) + + @rx_status.setter + def rx_status(self, status_str): + if status_str == "start": + self.startReceiver() + elif status_str == "stop": + self.stopReceiver() + else: + raise NotImplementedError("Unknown argument to rx_status") + + @property + def busy(self): + """ + Checks if the detector is acquiring. Can also be set but should only be used if the acquire fails and + leaves the detector with busy == True + + .. note :: + + Only works when the measurement is launched using acquire, not with status start! + + Returns + -------- + bool + :py:obj:`True` if the detector is acquiring otherwise :py:obj:`False` + + Examples + ---------- + + :: + + d.busy + >> True + + #If the detector is stuck reset by: + d.busy = False + + + """ + return self.getAcquiringFlag() + + @busy.setter + def busy(self, value): + self.setAcquiringFlag(value) + + # Configuration + @property + def startingfnum(self): + return element_if_equal(self.getStartingFrameNumber()) + + @startingfnum.setter + def startingfnum(self, value): + self.setStartingFrameNumber(value) + + @property + def config(self): + return NotImplementedError("config is set only") + + @config.setter + def config(self, fname): + self.setConfig(fname) + + # File + @property + def fname(self): + return element_if_equal(self.getFileName()) + + @fname.setter + def fname(self, file_name): + self.setFileName(file_name) + + @property + def fpath(self): + return element_if_equal(self.getFilePath()) + + @fpath.setter + def fpath(self, path): + self.setFilePath(path) + + @property + def fwrite(self): + return element_if_equal(self.getFileWrite()) + + @fwrite.setter + def fwrite(self, value): + self.setFileWrite(value) + + @property + def foverwrite(self): + return element_if_equal(self.getFileOverWrite()) + + @foverwrite.setter + def foverwrite(self, value): + self.setFileOverWrite(value) + + # Time + @property + def exptime(self): + res = self.getExptime() + return element_if_equal([it.total_seconds() for it in res]) + + @exptime.setter + def exptime(self, t): + self.setExptime(dt.timedelta(seconds=t)) + + @property + def subexptime(self): + res = self.getSubExptime() + return element_if_equal([it.total_seconds() for it in res]) + + @subexptime.setter + def subexptime(self, t): + self.setSubExptime(dt.timedelta(seconds=t)) + + @property + def period(self): + res = self.getPeriod() + return element_if_equal([it.total_seconds() for it in res]) + + @period.setter + def period(self, t): + self.setPeriod(dt.timedelta(seconds=t)) - \ No newline at end of file diff --git a/python/src/Detector.h b/python/src/DetectorPythonInterface.h similarity index 97% rename from python/src/Detector.h rename to python/src/DetectorPythonInterface.h index 1c9451236..b044e519d 100755 --- a/python/src/Detector.h +++ b/python/src/DetectorPythonInterface.h @@ -11,9 +11,9 @@ #include "slsDetector.h" #include "sls_detector_defs.h" -class Detector { +class DetectorPythonInterface { public: - Detector(int i) : det(i), multi_detector_id(i) { + DetectorPythonInterface(int i) : det(i), multi_detector_id(i) { // Disable output from std::cout // std::cout.setstate(std::ios_base::failbit); } @@ -352,7 +352,7 @@ class Detector { void checkDetectorVersionCompatibility() { det.checkDetectorVersionCompatibility(); } - bool checkReceiverVersionCompatibility() { + void checkReceiverVersionCompatibility() { det.checkReceiverVersionCompatibility(); } @@ -695,7 +695,7 @@ class Detector { int multi_detector_id = 0; }; -void Detector::setFileFormat(const std::string &format) { +void DetectorPythonInterface::setFileFormat(const std::string &format) { if (format == "binary") { det.setFileFormat(slsDetectorDefs::fileFormat::BINARY); } else if (format == "hdf5") { @@ -703,7 +703,7 @@ void Detector::setFileFormat(const std::string &format) { } } -std::string Detector::getFileFormat() { +std::string DetectorPythonInterface::getFileFormat() { auto format = det.setFileFormat(slsDetectorDefs::fileFormat::GET_FILE_FORMAT, -1); switch (format) { @@ -717,7 +717,7 @@ std::string Detector::getFileFormat() { } slsDetectorDefs::networkParameter -Detector::networkNameToEnum(std::string par_name) { +DetectorPythonInterface::networkNameToEnum(std::string par_name) { if (par_name == "detectormac") { return slsDetectorDefs::networkParameter::DETECTOR_MAC; @@ -761,9 +761,9 @@ Detector::networkNameToEnum(std::string par_name) { throw std::runtime_error("Could not decode network parameter"); }; -// slsDetectorDefs::fileFormat Detector::file/// +// slsDetectorDefs::fileFormat DetectorPythonInterface::file/// -slsDetectorDefs::dacIndex Detector::dacNameToEnum(std::string dac_name) { +slsDetectorDefs::dacIndex DetectorPythonInterface::dacNameToEnum(std::string dac_name) { // to avoid uninitialised slsDetectorDefs::dacIndex dac = slsDetectorDefs::dacIndex::E_SvP; @@ -918,7 +918,7 @@ slsDetectorDefs::dacIndex Detector::dacNameToEnum(std::string dac_name) { // overflow of single subframes */ // }; -std::vector Detector::getReadoutFlags() { +std::vector DetectorPythonInterface::getReadoutFlags() { std::vector flags; auto r = det.setReadOutFlags(); if (r & slsDetectorDefs::readOutFlags::STORE_IN_RAM) @@ -953,7 +953,7 @@ std::vector Detector::getReadoutFlags() { } // note singular -void Detector::setReadoutFlag(const std::string flag_name) { +void DetectorPythonInterface::setReadoutFlag(const std::string flag_name) { if (flag_name == "none") det.setReadOutFlags(slsDetectorDefs::readOutFlags::NORMAL_READOUT); else if (flag_name == "storeinram") @@ -988,7 +988,7 @@ void Detector::setReadoutFlag(const std::string flag_name) { throw std::runtime_error("Flag name not recognized"); } -std::vector Detector::getRateCorrection() { +std::vector DetectorPythonInterface::getRateCorrection() { std::vector rate_corr; for (int i = 0; i < det.getNumberOfDetectors(); ++i) { rate_corr.push_back(det.getRateCorrection(i)); @@ -996,7 +996,7 @@ std::vector Detector::getRateCorrection() { return rate_corr; } -void Detector::pulseAllPixels(int n) { +void DetectorPythonInterface::pulseAllPixels(int n) { // int pulsePixelNMove(int n=0,int x=0,int y=0); // int pulsePixel(int n=0,int x=0,int y=0); @@ -1008,7 +1008,7 @@ void Detector::pulseAllPixels(int n) { } return; } -void Detector::pulseDiagonal(int n) { +void DetectorPythonInterface::pulseDiagonal(int n) { // int pulsePixelNMove(int n=0,int x=0,int y=0); // int pulsePixel(int n=0,int x=0,int y=0); diff --git a/python/src/enums.cpp b/python/src/enums.cpp new file mode 100644 index 000000000..054690c59 --- /dev/null +++ b/python/src/enums.cpp @@ -0,0 +1,19 @@ +#include +#include +#include +#include + +#include "sls_detector_defs.h" +namespace py = pybind11; +void init_enums(py::module &m) { + py::class_ Defs(m, "slsDetectorDefs"); + py::enum_(Defs, "runStatus") + .value("IDLE", slsDetectorDefs::runStatus::IDLE) + .value("ERROR", slsDetectorDefs::runStatus::ERROR) + .value("WAITING", slsDetectorDefs::runStatus::WAITING) + .value("RUN_FINISHED", slsDetectorDefs::runStatus::RUN_FINISHED) + .value("TRANSMITTING", slsDetectorDefs::runStatus::TRANSMITTING) + .value("RUNNING", slsDetectorDefs::runStatus::RUNNING) + .value("STOPPED", slsDetectorDefs::runStatus::STOPPED) + .export_values(); +} diff --git a/python/src/experimental.cpp b/python/src/experimental.cpp new file mode 100644 index 000000000..b8d31a9b2 --- /dev/null +++ b/python/src/experimental.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +#include "Detector.h" +#include "sls_detector_defs.h" +#include "typecaster.h" +namespace py = pybind11; +void init_experimental(py::module &m) { + // Experimental API to use the multi directly and inherit from to reduce + // code duplication need to investigate how to handle documentation + using sls::Detector; + using sls::Positions; + py::class_ multiDetectorApi(m, "multiDetectorApi"); + multiDetectorApi + .def(py::init()) + + // Acq related + .def("acquire", &Detector::acquire) + .def("startReceiver", &Detector::startReceiver, py::arg() = Positions{}) + .def("stopReceiver", &Detector::stopReceiver, py::arg() = Positions{}) + .def("getAcquiringFlag", &Detector::getAcquiringFlag) + .def("setAcquiringFlag", &Detector::setAcquiringFlag) + .def("getReceiverStatus", &Detector::getReceiverStatus, + py::arg() = Positions{}) + + // Configuration + .def("free", &Detector::freeSharedMemory) + .def("setConfig", &Detector::setConfig) + .def("getHostname", &Detector::getHostname, py::arg() = Positions{}) + + // Bits and registers + .def("setBit", &Detector::setBit, py::arg(), py::arg(), + py::arg() = Positions{}) + .def("clearBit", &Detector::clearBit, py::arg(), py::arg(), + py::arg() = Positions{}) + .def("getRegister", &Detector::getRegister, py::arg(), + py::arg() = Positions{}) + + .def("getStartingFrameNumber", &Detector::getStartingFrameNumber, + py::arg() = Positions{}) + .def("setStartingFrameNumber", &Detector::setStartingFrameNumber, + py::arg(), py::arg() = Positions{}) + + // File + .def("getFileName", &Detector::getFileName) + .def("setFileName", &Detector::setFileName, py::arg()) + .def("getFilePath", &Detector::getFilePath) + .def("setFilePath", &Detector::setFilePath, py::arg()) + .def("setFileWrite", &Detector::setFileWrite, py::arg(), + py::arg() = Positions{}) + .def("getFileWrite", &Detector::getFileWrite, py::arg() = Positions{}) + .def("setFileOverWrite", &Detector::setFileOverWrite, py::arg(), + py::arg() = Positions{}) + .def("getFileOverWrite", &Detector::getFileOverWrite, + py::arg() = Positions{}) + + // Time + .def("setExptime", &Detector::setExptime, py::arg(), + py::arg() = Positions{}) + .def("getExptime", &Detector::getExptime, py::arg() = Positions{}) + .def("setPeriod", &Detector::setPeriod, py::arg(), + py::arg() = Positions{}) + .def("getPeriod", &Detector::getPeriod, py::arg() = Positions{}) + .def("setSubExptime", &Detector::setSubExptime, py::arg(), + py::arg() = Positions{}) + .def("getSubExptime", &Detector::getSubExptime, + py::arg() = Positions{}); +} diff --git a/python/src/main.cpp b/python/src/main.cpp index 6e5fcb72e..9eab3cdd8 100755 --- a/python/src/main.cpp +++ b/python/src/main.cpp @@ -1,12 +1,31 @@ +#include #include #include #include #include "Detector.h" +#include "DetectorPythonInterface.h" +#include "Result.h" #include "mythenFileIO.h" +#include +#include + +#include "typecaster.h" + +// // Add type_typecaster to pybind for our wrapper type +// namespace pybind11 { +// namespace detail { +// template +// struct type_caster> +// : list_caster, Type> {}; +// } // namespace detail +// } // namespace pybind11 + +using ds = std::chrono::duration; namespace py = pybind11; - +void init_enums(py::module &); +void init_experimental(py::module &); PYBIND11_MODULE(_sls_detector, m) { m.doc() = R"pbdoc( C/C++ API @@ -18,7 +37,10 @@ PYBIND11_MODULE(_sls_detector, m) { )pbdoc"; - py::class_ DetectorApi(m, "DetectorApi", R"pbdoc( + init_enums(m); + init_experimental(m); + + py::class_ DetectorApi(m, "DetectorApi", R"pbdoc( Interface to the multiSlsDetector class through Detector.h These functions are used by the python classes Eiger and Jungfrau and normally it is better to use them than to directly access functions here. @@ -43,298 +65,283 @@ PYBIND11_MODULE(_sls_detector, m) { )pbdoc"); DetectorApi.def(py::init()) - .def("freeSharedMemory", &Detector::freeSharedMemory) - .def("getMultiDetectorId", &Detector::getMultiDetectorId) - .def("acq", &Detector::acquire) - .def("getAcquiringFlag", &Detector::getAcquiringFlag) - .def("setAcquiringFlag", &Detector::setAcquiringFlag) + .def("freeSharedMemory", &DetectorPythonInterface::freeSharedMemory) + .def("getMultiDetectorId", &DetectorPythonInterface::getMultiDetectorId) + .def("acq", &DetectorPythonInterface::acquire) + .def("getAcquiringFlag", &DetectorPythonInterface::getAcquiringFlag) + .def("setAcquiringFlag", &DetectorPythonInterface::setAcquiringFlag) - .def("setAllTrimbits", &Detector::setAllTrimbits) - .def("getAllTrimbits", &Detector::getAllTrimbits) - .def("setCounterBit", &Detector::setCounterBit) - .def("getCounterBit", &Detector::getCounterBit) + .def("setAllTrimbits", &DetectorPythonInterface::setAllTrimbits) + .def("getAllTrimbits", &DetectorPythonInterface::getAllTrimbits) + .def("setCounterBit", &DetectorPythonInterface::setCounterBit) + .def("getCounterBit", &DetectorPythonInterface::getCounterBit) - .def("getAdc", &Detector::getAdc) - .def("getDac", &Detector::getDac) - .def("getDac_mV", &Detector::getDac_mV) - .def("setDac", &Detector::setDac) - .def("setDac_mV", &Detector::setDac_mV) - .def("getDacFromIndex", &Detector::getDacFromIndex) - .def("setDacFromIndex", &Detector::setDacFromIndex) + .def("getAdc", &DetectorPythonInterface::getAdc) + .def("getDac", &DetectorPythonInterface::getDac) + .def("getDac_mV", &DetectorPythonInterface::getDac_mV) + .def("setDac", &DetectorPythonInterface::setDac) + .def("setDac_mV", &DetectorPythonInterface::setDac_mV) + .def("getDacFromIndex", &DetectorPythonInterface::getDacFromIndex) + .def("setDacFromIndex", &DetectorPythonInterface::setDacFromIndex) - .def("getDbitPipeline", &Detector::getDbitPipeline) - .def("setDbitPipeline", &Detector::setDbitPipeline) - .def("getDbitPhase", &Detector::getDbitPhase) - .def("setDbitPhase", &Detector::setDbitPhase) - .def("getDbitClock", &Detector::getDbitClock) - .def("setDbitClock", &Detector::setDbitClock) + .def("getDbitPipeline", &DetectorPythonInterface::getDbitPipeline) + .def("setDbitPipeline", &DetectorPythonInterface::setDbitPipeline) + .def("getDbitPhase", &DetectorPythonInterface::getDbitPhase) + .def("setDbitPhase", &DetectorPythonInterface::setDbitPhase) + .def("getDbitClock", &DetectorPythonInterface::getDbitClock) + .def("setDbitClock", &DetectorPythonInterface::setDbitClock) - .def("setThresholdEnergy", &Detector::setThresholdEnergy) - .def("getThresholdEnergy", &Detector::getThresholdEnergy) + .def("setThresholdEnergy", &DetectorPythonInterface::setThresholdEnergy) + .def("getThresholdEnergy", &DetectorPythonInterface::getThresholdEnergy) - .def("getSettings", &Detector::getSettings) - .def("setSettings", &Detector::setSettings) - .def("getSettingsDir", &Detector::getSettingsDir) - .def("setSettingsDir", &Detector::setSettingsDir) + .def("getSettings", &DetectorPythonInterface::getSettings) + .def("setSettings", &DetectorPythonInterface::setSettings) + .def("getSettingsDir", &DetectorPythonInterface::getSettingsDir) + .def("setSettingsDir", &DetectorPythonInterface::setSettingsDir) - .def("loadTrimbitFile", &Detector::loadTrimbitFile) - .def("setTrimEnergies", &Detector::setTrimEnergies) - .def("getTrimEnergies", &Detector::getTrimEnergies) + .def("loadTrimbitFile", &DetectorPythonInterface::loadTrimbitFile) + .def("setTrimEnergies", &DetectorPythonInterface::setTrimEnergies) + .def("getTrimEnergies", &DetectorPythonInterface::getTrimEnergies) - .def("pulseChip", &Detector::pulseChip) - .def("pulseAllPixels", &Detector::pulseAllPixels) - .def("pulseDiagonal", &Detector::pulseDiagonal) - .def("getRunStatus", &Detector::getRunStatus) - .def("readConfigurationFile", &Detector::readConfigurationFile) - .def("readParametersFile", &Detector::readParametersFile) - .def("checkOnline", &Detector::checkOnline) - .def("setReadoutClockSpeed", &Detector::setReadoutClockSpeed) - .def("getReadoutClockSpeed", &Detector::getReadoutClockSpeed) - .def("getSyncClkSpeed", &Detector::getSyncClkSpeed) - .def("getHostname", &Detector::getHostname) - .def("setHostname", &Detector::setHostname) + .def("pulseChip", &DetectorPythonInterface::pulseChip) + .def("pulseAllPixels", &DetectorPythonInterface::pulseAllPixels) + .def("pulseDiagonal", &DetectorPythonInterface::pulseDiagonal) + .def("getRunStatus", &DetectorPythonInterface::getRunStatus) + .def("readConfigurationFile", + &DetectorPythonInterface::readConfigurationFile) + .def("readParametersFile", &DetectorPythonInterface::readParametersFile) + .def("checkOnline", &DetectorPythonInterface::checkOnline) + .def("setReadoutClockSpeed", + &DetectorPythonInterface::setReadoutClockSpeed) + .def("getReadoutClockSpeed", + &DetectorPythonInterface::getReadoutClockSpeed) + .def("getSyncClkSpeed", &DetectorPythonInterface::getSyncClkSpeed) + .def("getHostname", &DetectorPythonInterface::getHostname) + .def("setHostname", &DetectorPythonInterface::setHostname) - .def("getReceiverPort", &Detector::getReceiverPort) - .def("setReceiverPort", &Detector::setReceiverPort) + .def("getReceiverPort", &DetectorPythonInterface::getReceiverPort) + .def("setReceiverPort", &DetectorPythonInterface::setReceiverPort) - .def("isChipPowered", &Detector::isChipPowered) - .def("powerChip", &Detector::powerChip) + .def("isChipPowered", &DetectorPythonInterface::isChipPowered) + .def("powerChip", &DetectorPythonInterface::powerChip) - .def("readRegister", &Detector::readRegister) - .def("writeRegister", &Detector::writeRegister) - .def("writeAdcRegister", &Detector::writeAdcRegister) - .def("setBitInRegister", &Detector::setBitInRegister) - .def("clearBitInRegister", &Detector::clearBitInRegister) + .def("readRegister", &DetectorPythonInterface::readRegister) + .def("writeRegister", &DetectorPythonInterface::writeRegister) + .def("writeAdcRegister", &DetectorPythonInterface::writeAdcRegister) + .def("setBitInRegister", &DetectorPythonInterface::setBitInRegister) + .def("clearBitInRegister", &DetectorPythonInterface::clearBitInRegister) - .def("setDynamicRange", &Detector::setDynamicRange) - .def("getDynamicRange", &Detector::getDynamicRange) - .def("getFirmwareVersion", &Detector::getFirmwareVersion) - .def("getServerVersion", &Detector::getServerVersion) - .def("getClientVersion", &Detector::getClientVersion) - .def("getReceiverVersion", &Detector::getReceiverVersion) - .def("getDetectorNumber", &Detector::getDetectorNumber) - .def("getRateCorrection", &Detector::getRateCorrection) - .def("setRateCorrection", &Detector::setRateCorrection) + .def("setDynamicRange", &DetectorPythonInterface::setDynamicRange) + .def("getDynamicRange", &DetectorPythonInterface::getDynamicRange) + .def("getFirmwareVersion", &DetectorPythonInterface::getFirmwareVersion) + .def("getServerVersion", &DetectorPythonInterface::getServerVersion) + .def("getClientVersion", &DetectorPythonInterface::getClientVersion) + .def("getReceiverVersion", &DetectorPythonInterface::getReceiverVersion) + .def("getDetectorNumber", &DetectorPythonInterface::getDetectorNumber) + .def("getRateCorrection", &DetectorPythonInterface::getRateCorrection) + .def("setRateCorrection", &DetectorPythonInterface::setRateCorrection) - .def("startAcquisition", &Detector::startAcquisition) - .def("stopAcquisition", &Detector::stopAcquisition) - .def("startReceiver", &Detector::startReceiver) - .def("stopReceiver", &Detector::stopReceiver) + .def("startAcquisition", &DetectorPythonInterface::startAcquisition) + .def("stopAcquisition", &DetectorPythonInterface::stopAcquisition) + .def("startReceiver", &DetectorPythonInterface::startReceiver) + .def("stopReceiver", &DetectorPythonInterface::stopReceiver) .def("getFilePath", - (std::string(Detector::*)()) & Detector::getFilePath, + (std::string(DetectorPythonInterface::*)()) & + DetectorPythonInterface::getFilePath, "Using multiSlsDetector") .def("getFilePath", - (std::string(Detector::*)(int)) & Detector::getFilePath, + (std::string(DetectorPythonInterface::*)(int)) & + DetectorPythonInterface::getFilePath, "File path for individual detector") - .def("setFilePath", - (void (Detector::*)(std::string)) & Detector::setFilePath) - .def("setFilePath", - (void (Detector::*)(std::string, int)) & Detector::setFilePath) + .def("setFilePath", (void (DetectorPythonInterface::*)(std::string)) & + DetectorPythonInterface::setFilePath) - .def("setFileName", &Detector::setFileName) - .def("getFileName", &Detector::getFileName) - .def("setFileIndex", &Detector::setFileIndex) - .def("getFileIndex", &Detector::getFileIndex) + .def("setFileName", &DetectorPythonInterface::setFileName) + .def("getFileName", &DetectorPythonInterface::getFileName) + .def("setFileIndex", &DetectorPythonInterface::setFileIndex) + .def("getFileIndex", &DetectorPythonInterface::getFileIndex) - .def("setExposureTime", &Detector::setExposureTime) - .def("getExposureTime", &Detector::getExposureTime) - .def("setSubExposureTime", &Detector::setSubExposureTime) - .def("getSubExposureTime", &Detector::getSubExposureTime) - .def("setPeriod", &Detector::setPeriod) - .def("getPeriod", &Detector::getPeriod) - .def("setSubExposureDeadTime", &Detector::setSubExposureDeadTime) - .def("getSubExposureDeadTime", &Detector::getSubExposureDeadTime) + .def("setExposureTime", &DetectorPythonInterface::setExposureTime) + .def("getExposureTime", &DetectorPythonInterface::getExposureTime) + .def("setSubExposureTime", &DetectorPythonInterface::setSubExposureTime) + .def("getSubExposureTime", &DetectorPythonInterface::getSubExposureTime) + .def("setPeriod", &DetectorPythonInterface::setPeriod) + .def("getPeriod", &DetectorPythonInterface::getPeriod) + .def("setSubExposureDeadTime", &DetectorPythonInterface::setSubExposureDeadTime) + .def("getSubExposureDeadTime", &DetectorPythonInterface::getSubExposureDeadTime) - .def("getCycles", &Detector::getCycles) - .def("setCycles", &Detector::setCycles) - .def("getNumberOfGates", &Detector::getNumberOfGates) - .def("setNumberOfGates", &Detector::setNumberOfGates) - .def("getDelay", &Detector::getDelay) - .def("setDelay", &Detector::setDelay) + .def("getCycles", &DetectorPythonInterface::getCycles) + .def("setCycles", &DetectorPythonInterface::setCycles) + .def("getNumberOfGates", &DetectorPythonInterface::getNumberOfGates) + .def("setNumberOfGates", &DetectorPythonInterface::setNumberOfGates) + .def("getDelay", &DetectorPythonInterface::getDelay) + .def("setDelay", &DetectorPythonInterface::setDelay) - .def("setStoragecellStart", &Detector::setStoragecellStart) - .def("getStoragecellStart", &Detector::getStoragecellStart) - .def("setNumberOfStorageCells", &Detector::setNumberOfStorageCells) - .def("getNumberOfStorageCells", &Detector::getNumberOfStorageCells) + .def("setStoragecellStart", &DetectorPythonInterface::setStoragecellStart) + .def("getStoragecellStart", &DetectorPythonInterface::getStoragecellStart) + .def("setNumberOfStorageCells", &DetectorPythonInterface::setNumberOfStorageCells) + .def("getNumberOfStorageCells", &DetectorPythonInterface::getNumberOfStorageCells) - .def("getTimingMode", &Detector::getTimingMode) - .def("setTimingMode", &Detector::setTimingMode) + .def("getTimingMode", &DetectorPythonInterface::getTimingMode) + .def("setTimingMode", &DetectorPythonInterface::setTimingMode) - .def("getDetectorType", &Detector::getDetectorType) + .def("getDetectorType", &DetectorPythonInterface::getDetectorType) - .def("setThresholdTemperature", &Detector::setThresholdTemperature) - .def("getThresholdTemperature", &Detector::getThresholdTemperature) - .def("setTemperatureControl", &Detector::setTemperatureControl) - .def("getTemperatureControl", &Detector::getTemperatureControl) - .def("getTemperatureEvent", &Detector::getTemperatureEvent) - .def("resetTemperatureEvent", &Detector::resetTemperatureEvent) + .def("setThresholdTemperature", &DetectorPythonInterface::setThresholdTemperature) + .def("getThresholdTemperature", &DetectorPythonInterface::getThresholdTemperature) + .def("setTemperatureControl", &DetectorPythonInterface::setTemperatureControl) + .def("getTemperatureControl", &DetectorPythonInterface::getTemperatureControl) + .def("getTemperatureEvent", &DetectorPythonInterface::getTemperatureEvent) + .def("resetTemperatureEvent", &DetectorPythonInterface::resetTemperatureEvent) - .def("getRxDataStreamStatus", &Detector::getRxDataStreamStatus) - .def("setRxDataStreamStatus", &Detector::setRxDataStreamStatus) + .def("getRxDataStreamStatus", &DetectorPythonInterface::getRxDataStreamStatus) + .def("setRxDataStreamStatus", &DetectorPythonInterface::setRxDataStreamStatus) // Network stuff - .def("getReceiverHostname", &Detector::getReceiverHostname, + .def("getReceiverHostname", + &DetectorPythonInterface::getReceiverHostname, py::arg("det_id") = -1) - .def("setReceiverHostname", &Detector::setReceiverHostname, - py::arg("hostname"), py::arg("det_id") = -1) - .def("getReceiverStreamingPort", &Detector::getReceiverStreamingPort) - .def("setReceiverStreamingPort", &Detector::setReceiverStreamingPort) - .def("getReceiverUDPPort", &Detector::getReceiverUDPPort) - .def("getReceiverUDPPort2", &Detector::getReceiverUDPPort2) - .def("setReceiverUDPPort", &Detector::setReceiverUDPPort) - .def("setReceiverUDPPort2", &Detector::setReceiverUDPPort2) - .def("setReceiverUDPIP", &Detector::setReceiverUDPIP) - .def("getReceiverUDPIP", &Detector::getReceiverUDPIP) - .def("getReceiverUDPMAC", &Detector::getReceiverUDPMAC) - .def("setReceiverUDPMAC", &Detector::setReceiverUDPMAC) + .def("setReceiverHostname", + &DetectorPythonInterface::setReceiverHostname, py::arg("hostname"), + py::arg("det_id") = -1) + .def("getReceiverStreamingPort", + &DetectorPythonInterface::getReceiverStreamingPort) + .def("setReceiverStreamingPort", + &DetectorPythonInterface::setReceiverStreamingPort) + .def("getReceiverUDPPort", &DetectorPythonInterface::getReceiverUDPPort) + .def("getReceiverUDPPort2", + &DetectorPythonInterface::getReceiverUDPPort2) + .def("setReceiverUDPPort", &DetectorPythonInterface::setReceiverUDPPort) + .def("setReceiverUDPPort2", + &DetectorPythonInterface::setReceiverUDPPort2) + .def("setReceiverUDPIP", &DetectorPythonInterface::setReceiverUDPIP) + .def("getReceiverUDPIP", &DetectorPythonInterface::getReceiverUDPIP) + .def("getReceiverUDPMAC", &DetectorPythonInterface::getReceiverUDPMAC) + .def("setReceiverUDPMAC", &DetectorPythonInterface::setReceiverUDPMAC) - .def("getReceiverPort", &Detector::getReceiverPort) - .def("setReceiverPort", &Detector::setReceiverPort) + .def("getReceiverPort", &DetectorPythonInterface::getReceiverPort) + .def("setReceiverPort", &DetectorPythonInterface::setReceiverPort) .def("configureNetworkParameters", - &Detector::configureNetworkParameters) - .def("getDelayFrame", &Detector::getDelayFrame) - .def("setDelayFrame", &Detector::setDelayFrame) - .def("getDelayLeft", &Detector::getDelayLeft) - .def("setDelayLeft", &Detector::setDelayLeft) - .def("getDelayRight", &Detector::getDelayRight) - .def("setDelayRight", &Detector::setDelayRight) - .def("getLastClientIP", &Detector::getLastClientIP) - .def("getReceiverLastClientIP", &Detector::getReceiverLastClientIP) + &DetectorPythonInterface::configureNetworkParameters) + .def("getDelayFrame", &DetectorPythonInterface::getDelayFrame) + .def("setDelayFrame", &DetectorPythonInterface::setDelayFrame) + .def("getDelayLeft", &DetectorPythonInterface::getDelayLeft) + .def("setDelayLeft", &DetectorPythonInterface::setDelayLeft) + .def("getDelayRight", &DetectorPythonInterface::getDelayRight) + .def("setDelayRight", &DetectorPythonInterface::setDelayRight) + .def("getLastClientIP", &DetectorPythonInterface::getLastClientIP) + .def("getReceiverLastClientIP", + &DetectorPythonInterface::getReceiverLastClientIP) - .def("setFramesPerFile", &Detector::setFramesPerFile) - .def("getFramesPerFile", &Detector::getFramesPerFile) - .def("setReceiverFifoDepth", &Detector::setReceiverFifoDepth) - .def("getReceiverFifoDepth", &Detector::getReceiverFifoDepth) + .def("setFramesPerFile", &DetectorPythonInterface::setFramesPerFile) + .def("getFramesPerFile", &DetectorPythonInterface::getFramesPerFile) + .def("setReceiverFifoDepth", + &DetectorPythonInterface::setReceiverFifoDepth) + .def("getReceiverFifoDepth", + &DetectorPythonInterface::getReceiverFifoDepth) .def("getReceiverFrameDiscardPolicy", - &Detector::getReceiverFrameDiscardPolicy) + &DetectorPythonInterface::getReceiverFrameDiscardPolicy) .def("setReceiverFramesDiscardPolicy", - &Detector::setReceiverFramesDiscardPolicy) - .def("setPartialFramesPadding", &Detector::setPartialFramesPadding) - .def("getPartialFramesPadding", &Detector::getPartialFramesPadding) + &DetectorPythonInterface::setReceiverFramesDiscardPolicy) + .def("setPartialFramesPadding", + &DetectorPythonInterface::setPartialFramesPadding) + .def("getPartialFramesPadding", + &DetectorPythonInterface::getPartialFramesPadding) - .def("getUserDetails", &Detector::getUserDetails) + .def("getUserDetails", &DetectorPythonInterface::getUserDetails) .def("checkDetectorVersionCompatibility", - &Detector::checkDetectorVersionCompatibility) + &DetectorPythonInterface::checkDetectorVersionCompatibility) .def("checkReceiverVersionCompatibility", - &Detector::checkReceiverVersionCompatibility) - .def("getMeasuredPeriod", &Detector::getMeasuredPeriod) - .def("getMeasuredSubPeriod", &Detector::getMeasuredSubPeriod) + &DetectorPythonInterface::checkReceiverVersionCompatibility) + .def("getMeasuredPeriod", &DetectorPythonInterface::getMeasuredPeriod) + .def("getMeasuredSubPeriod", + &DetectorPythonInterface::getMeasuredSubPeriod) - .def("setFileWrite", &Detector::setFileWrite) - .def("getFileWrite", &Detector::getFileWrite) - .def("setFileOverWrite", &Detector::setFileOverWrite) - .def("getFileOverWrite", &Detector::getFileOverWrite) - .def("getDacVthreshold", &Detector::getDacVthreshold) - .def("setDacVthreshold", &Detector::setDacVthreshold) - .def("setNumberOfFrames", &Detector::setNumberOfFrames) - .def("getNumberOfFrames", &Detector::getNumberOfFrames) + .def("setFileWrite", &DetectorPythonInterface::setFileWrite) + .def("getFileWrite", &DetectorPythonInterface::getFileWrite) + .def("setFileOverWrite", &DetectorPythonInterface::setFileOverWrite) + .def("getFileOverWrite", &DetectorPythonInterface::getFileOverWrite) + .def("getDacVthreshold", &DetectorPythonInterface::getDacVthreshold) + .def("setDacVthreshold", &DetectorPythonInterface::setDacVthreshold) + .def("setNumberOfFrames", &DetectorPythonInterface::setNumberOfFrames) + .def("getNumberOfFrames", &DetectorPythonInterface::getNumberOfFrames) // Overloaded calls .def("getFramesCaughtByReceiver", - (int (Detector::*)()) & Detector::getFramesCaughtByReceiver) + (int (DetectorPythonInterface::*)()) & + DetectorPythonInterface::getFramesCaughtByReceiver) .def("getFramesCaughtByReceiver", - (int (Detector::*)(int)) & Detector::getFramesCaughtByReceiver) + (int (DetectorPythonInterface::*)(int)) & + DetectorPythonInterface::getFramesCaughtByReceiver) - .def("resetFramesCaught", &Detector::resetFramesCaught) + .def("resetFramesCaught", &DetectorPythonInterface::resetFramesCaught) .def("getReceiverCurrentFrameIndex", - &Detector::getReceiverCurrentFrameIndex) - .def("getGapPixels", &Detector::getGapPixels) - .def("setGapPixels", &Detector::setGapPixels) - .def("getFlippedDataX", &Detector::getFlippedDataX) - .def("getFlippedDataY", &Detector::getFlippedDataY) - .def("setFlippedDataX", &Detector::setFlippedDataX) - .def("setFlippedDataY", &Detector::setFlippedDataY) + &DetectorPythonInterface::getReceiverCurrentFrameIndex) + .def("getGapPixels", &DetectorPythonInterface::getGapPixels) + .def("setGapPixels", &DetectorPythonInterface::setGapPixels) + .def("getFlippedDataX", &DetectorPythonInterface::getFlippedDataX) + .def("getFlippedDataY", &DetectorPythonInterface::getFlippedDataY) + .def("setFlippedDataX", &DetectorPythonInterface::setFlippedDataX) + .def("setFlippedDataY", &DetectorPythonInterface::setFlippedDataY) - .def("getServerLock", &Detector::getServerLock) - .def("setServerLock", &Detector::setServerLock) - .def("getReceiverLock", &Detector::getReceiverLock) - .def("setReceiverLock", &Detector::setReceiverLock) + .def("getServerLock", &DetectorPythonInterface::getServerLock) + .def("setServerLock", &DetectorPythonInterface::setServerLock) + .def("getReceiverLock", &DetectorPythonInterface::getReceiverLock) + .def("setReceiverLock", &DetectorPythonInterface::setReceiverLock) - .def("getReadoutFlags", &Detector::getReadoutFlags) - .def("setReadoutFlag", &Detector::setReadoutFlag) + .def("getReadoutFlags", &DetectorPythonInterface::getReadoutFlags) + .def("setReadoutFlag", &DetectorPythonInterface::setReadoutFlag) - .def("setFileFormat", &Detector::setFileFormat) - .def("getFileFormat", &Detector::getFileFormat) + .def("setFileFormat", &DetectorPythonInterface::setFileFormat) + .def("getFileFormat", &DetectorPythonInterface::getFileFormat) - .def("getActive", &Detector::getActive) - .def("setActive", &Detector::setActive) + .def("getActive", &DetectorPythonInterface::getActive) + .def("setActive", &DetectorPythonInterface::setActive) - .def("getTenGigabitEthernet", &Detector::getTenGigabitEthernet) - .def("setTenGigabitEthernet", &Detector::setTenGigabitEthernet) + .def("getTenGigabitEthernet", + &DetectorPythonInterface::getTenGigabitEthernet) + .def("setTenGigabitEthernet", + &DetectorPythonInterface::setTenGigabitEthernet) - .def("getPatternLoops", &Detector::getPatternLoops, py::arg("level"), + .def("getPatternLoops", &DetectorPythonInterface::getPatternLoops, + py::arg("level"), py::arg("det_id") = -1) + .def("setPatternLoops", &DetectorPythonInterface::setPatternLoops, + py::arg("level"), py::arg("start"), py::arg("stop"), py::arg("n"), py::arg("det_id") = -1) - .def("setPatternLoops", &Detector::setPatternLoops, py::arg("level"), - py::arg("start"), py::arg("stop"), py::arg("n"), + .def("setPatternWord", &DetectorPythonInterface::setPatternWord, + py::arg("addr"), py::arg("word"), py::arg("det_id") = -1) + .def("getPatternWord", &DetectorPythonInterface::getPatternWord, + py::arg("addr"), py::arg("det_id") = -1) + + .def("setPatternIOControl", + &DetectorPythonInterface::setPatternIOControl, py::arg("word"), py::arg("det_id") = -1) - .def("setPatternWord", &Detector::setPatternWord, py::arg("addr"), - py::arg("word"), py::arg("det_id") = -1) - .def("getPatternWord", &Detector::getPatternWord, py::arg("addr"), + .def("setPatternClockControl", + &DetectorPythonInterface::setPatternClockControl, py::arg("word"), py::arg("det_id") = -1) - .def("setPatternIOControl", &Detector::setPatternIOControl, - py::arg("word"), py::arg("det_id") = -1) - .def("setPatternClockControl", &Detector::setPatternClockControl, - py::arg("word"), py::arg("det_id") = -1) - - .def("setPatternWaitAddr", &Detector::setPatternWaitAddr, + .def("setPatternWaitAddr", &DetectorPythonInterface::setPatternWaitAddr, py::arg("level"), py::arg("addr"), py::arg("det_id") = -1) - .def("getPatternWaitAddr", &Detector::getPatternWaitAddr, + .def("getPatternWaitAddr", &DetectorPythonInterface::getPatternWaitAddr, py::arg("level"), py::arg("det_id") = -1) - .def("setPatternWaitTime", &Detector::setPatternWaitTime, + .def("setPatternWaitTime", &DetectorPythonInterface::setPatternWaitTime, py::arg("level"), py::arg("duration"), py::arg("det_id") = -1) - .def("getPatternWaitTime", &Detector::getPatternWaitTime, + .def("getPatternWaitTime", &DetectorPythonInterface::getPatternWaitTime, py::arg("level"), py::arg("det_id") = -1) - .def("getImageSize", &Detector::getImageSize) - .def("setImageSize", &Detector::setImageSize) - .def("getNumberOfDetectors", &Detector::getNumberOfDetectors) - .def("getDetectorGeometry", &Detector::getDetectorGeometry); + .def("getImageSize", &DetectorPythonInterface::getImageSize) + .def("setImageSize", &DetectorPythonInterface::setImageSize) + .def("getNumberOfDetectors", + &DetectorPythonInterface::getNumberOfDetectors) + .def("getDetectorGeometry", + &DetectorPythonInterface::getDetectorGeometry); - // Experimental API to use the multi directly and inherit from to reduce - // code duplication need to investigate how to handle documentation - py::class_ multiDetectorApi(m, "multiDetectorApi"); - multiDetectorApi.def(py::init()) - .def("acquire", &multiSlsDetector::acquire) - - .def_property("exptime", - py::cpp_function(&multiSlsDetector::setExposureTime, - py::arg(), py::arg() = -1, py::arg() = 0, - py::arg("det_id") = -1), - py::cpp_function(&multiSlsDetector::setExposureTime, - py::arg(), py::arg() = -1, py::arg() = 0, - py::arg("det_id") = -1)) - .def("getExposureTime", &multiSlsDetector::setExposureTime, py::arg()=-1, - py::arg() = 0, py::arg("det_id") = -1) - .def_property_readonly( - "hostname", py::cpp_function(&multiSlsDetector::getHostname, - py::arg(), py::arg("det_id") = -1)) - .def_property("busy", - py::cpp_function(&multiSlsDetector::getAcquiringFlag), - py::cpp_function(&multiSlsDetector::setAcquiringFlag)) - .def_property_readonly( - "rx_tcpport", py::cpp_function(&multiSlsDetector::getReceiverPort)) - .def_property_readonly( - "detectornumber", - py::cpp_function(&multiSlsDetector::getDetectorNumber)) - .def_property("rx_udpip", - py::cpp_function(&multiSlsDetector::getReceiverUDPIP, - py::arg(), py::arg("det_id") = -1), - py::cpp_function(&multiSlsDetector::setReceiverUDPIP, - py::arg(), py::arg("ip"), - py::arg("det_id") = -1)) - .def("_getReceiverUDPIP", &multiSlsDetector::getReceiverUDPIP) - .def("_setReceiverUDPIP", &multiSlsDetector::setReceiverUDPIP) - .def("getPatternLoops", &multiSlsDetector::getPatternLoops, - py::arg("level"), py::arg("det_id") = -1) - .def("setPatternLoops", &multiSlsDetector::setPatternLoops) - .def("setPatternWord", &multiSlsDetector::setPatternWord, - py::arg("addr"), py::arg("word"), py::arg("det_id") = -1); + py::module io = m.def_submodule("io", "Submodule for io"); io.def("read_my302_file", &read_my302_file, "some"); diff --git a/python/src/typecaster.h b/python/src/typecaster.h new file mode 100644 index 000000000..c5a9bfc6d --- /dev/null +++ b/python/src/typecaster.h @@ -0,0 +1,11 @@ +#pragma once +#include +#include "Result.h" +// Add type_typecaster to pybind for our wrapper type +namespace pybind11 { +namespace detail { +template +struct type_caster> + : list_caster, Type> {}; +} // namespace detail +} // namespace pybind11 \ No newline at end of file diff --git a/sample/CMakeLists.txt b/sample/CMakeLists.txt new file mode 100644 index 000000000..ff1835f63 --- /dev/null +++ b/sample/CMakeLists.txt @@ -0,0 +1,21 @@ +add_executable(a api.cpp) +target_link_libraries(a + slsDetectorShared + slsSupportLib + pthread + rt +) + +set_target_properties(a PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin +) + + +add_executable(result useResult.cpp) +target_link_libraries(result + slsDetectorShared +) + +set_target_properties(result PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin +) \ No newline at end of file diff --git a/sample/api.cpp b/sample/api.cpp new file mode 100644 index 000000000..b16c6f8ff --- /dev/null +++ b/sample/api.cpp @@ -0,0 +1,67 @@ +#include "Detector.h" + +#include +#include + +std::ostream &operator<<(std::ostream &os, const std::chrono::nanoseconds &t) { + os << t.count() << "ns"; + return os; +} + +template +struct is_container : std::false_type {}; + +template struct is_container_helper {}; + +template +struct is_container< + T, typename std::conditional< + false, + is_container_helper().size()), + decltype(std::declval().begin()), + decltype(std::declval().end()), + decltype(std::declval().cbegin()), + decltype(std::declval().cend()), + decltype(std::declval().empty())>, + void>::type> : public std::true_type {}; + +template +auto operator<<(std::ostream &os, const Container &con) -> + typename std::enable_if::value, + std::ostream &>::type { + if (con.empty()) + return os << "[]"; + auto it = con.cbegin(); + os << '[' << *it++; + while (it != con.cend()) + os << ", " << *it++; + return os << ']'; +} + +using sls::Detector; +using std::chrono::nanoseconds; +using std::chrono::seconds; + +int main() { + Detector d; + d.setConfig("/home/l_frojdh/virtual.config"); + + // d.setExptime(nanoseconds(500)); // set exptime of all modules + // auto t0 = d.getExptime(); + // std::cout << "exptime: " << t0 << '\n'; + + // d.setExptime(seconds(1), {1}); // set exptime of module one + // auto t1 = d.getExptime({1,3,5}); // get exptime of module 1, 3 and 5 + // std::cout << "exptime: " < +#include "Result.h" +#include "ToString.h" + +auto main() -> int { + + using sls::Result; // declared in namespace sls + using sls::ToString; + + std::cout << "Examples on usage of Result\n"; + + // Result exposes the underlying constructors of std::vector + Result res{1, 2, 3, 4, 5}; + std::cout << "res: " << res << '\n'; + + Result res2(5, 3.7); + std::cout << "res2: " << res2 << '\n'; + + // and can be converted to and from a vector. However, the + // conversion to a vector is not efficient since a copy is made + // and should only be done when a vector is needed for further use + // in most sense and in standard algorithms Result behaves as a + // vector. + std::vector vec(5, 5); + std::cout << "vec: " << ToString(vec) << "\n"; + + Result res3 = vec; + std::cout << "res3: " << res3 << '\n'; + + std::vector vec2 = res3; + std::cout << "vec2: " << ToString(vec2) << "\n"; + + + // WARNING this feature is still not decied, its convenient + // but might turn out to be a source of bugs... + // it is also possible to convert from Result to T + int r = res3; + std::cout << "r: " << r << '\n'; + std::cout << "static_cast: " << static_cast(res3) << '\n'; + std::cout << "static_cast: " << static_cast(res3) << '\n'; + + int r2 = res; + std::cout << "res: " << res << " converted to int: " << r2 << "\n"; + + //Using squash we can also convert to a single value + std::cout << "res.squash(): " << res.squash() << '\n'; + std::cout << "res3.squash(): " << res3.squash() << '\n'; + + + //.squash also takes a default value + std::cout << "res.squash(-1): " << res.squash(-1) << '\n'; + std::cout << "res3.squash(-1): " << res3.squash(-1) << '\n'; + + // +} \ No newline at end of file diff --git a/slsDetectorSoftware/CMakeLists.txt b/slsDetectorSoftware/CMakeLists.txt index 11cf02f1f..b09cc757f 100755 --- a/slsDetectorSoftware/CMakeLists.txt +++ b/slsDetectorSoftware/CMakeLists.txt @@ -3,6 +3,7 @@ set(SOURCES src/slsDetectorUsers.cpp src/slsDetectorCommand.cpp src/slsDetector.cpp + src/Detector.cpp ) set(HEADERS @@ -39,6 +40,8 @@ set(PUBLICHEADERS include/slsDetectorUsers.h include/detectorData.h include/multiSlsDetector.h + include/Detector.h + include/Result.h ) set_target_properties(slsDetectorShared PROPERTIES LIBRARY_OUTPUT_NAME SlsDetector diff --git a/slsDetectorSoftware/include/Detector.h b/slsDetectorSoftware/include/Detector.h new file mode 100644 index 000000000..3dd3b40ad --- /dev/null +++ b/slsDetectorSoftware/include/Detector.h @@ -0,0 +1,127 @@ +#pragma once +#include "Result.h" +#include "sls_detector_defs.h" +#include +#include +#include + +class multiSlsDetector; +namespace sls { +using ns = std::chrono::nanoseconds; +using Positions = const std::vector &; +using defs = slsDetectorDefs; + +/** + * \class Detector + */ +class Detector { + std::unique_ptr pimpl; + + public: + /** + * @param multi_id multi detector shared memory id + */ + Detector(int multi_id = 0); + ~Detector(); + + // Acquisition + + /** + * Blocking call, starts the receiver and detector. Acquired + * the number of frames set. + */ + void acquire(); + void startReceiver(Positions pos = {}); + void stopReceiver(Positions pos = {}); + + /** + * Get the acquiring flag. When true the detector blocks + * any attempt to start a new acquisition. + */ + bool getAcquiringFlag() const; + + /** + * Set the acquiring flag. This might have to done manually + * after an acquisition was aborted. + */ + void setAcquiringFlag(bool value); + + /** Read back the run status of the receiver */ + Result getReceiverStatus(Positions pos = {}); + + // Configuration + + /** + * Frees the shared memory of this detector and all modules + * belonging to it. + */ + void freeSharedMemory(); + void setConfig(const std::string &fname); + Result getHostname(Positions pos = {}) const; + // void setHostname(Positions pos = {}); + + Result getStartingFrameNumber(Positions pos = {}) const; + void setStartingFrameNumber(uint64_t value, Positions pos); + + // Bits and registers + + /** + * Clears (sets to 0) bit number bitnr in register at addr. + * @param addr address of the register + * @param bitnr bit number to clear + * @param pos detector position + */ + void clearBit(uint32_t addr, int bitnr, Positions pos = {}); + + /** + * Sets bit number bitnr in register at addr to 1 + * @param addr address of the register + * @param bitnr bit number to clear + * @param pos detector position + */ + void setBit(uint32_t addr, int bitnr, Positions pos = {}); + + /** + * Reads 32 bit register from detector + * @param addr address of the register + * @returns value read from register + */ + Result getRegister(uint32_t addr, Positions pos = {}); + + /************************************************** + * * + * FILE, anything concerning file writing or * + * reading goes here * + * * + * ************************************************/ + + /** + * Returns receiver file name prefix. The actual file name + * contains module id and file index as well. + * @param pos detector positions + * @returns file name prefix + */ + Result getFileName() const; + + /** + * Sets the receiver file name prefix + * @param fname file name prefix + */ + void setFileName(const std::string &fname); + Result getFilePath() const; + void setFilePath(const std::string &fname); + Result getFileWrite(Positions pos = {}) const; + void setFileWrite(bool value, Positions pos = {}); + Result getFileOverWrite(Positions pos = {}) const; + void setFileOverWrite(bool value, Positions pos = {}); + + // Time + Result getExptime(Positions pos = {}) const; + void setExptime(ns t, Positions pos = {}); + Result getSubExptime(Positions pos = {}) const; + void setSubExptime(ns t, Positions pos = {}); + Result getPeriod(Positions pos = {}) const; + void setPeriod(ns t, Positions pos = {}); +}; + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorSoftware/include/Result.h b/slsDetectorSoftware/include/Result.h new file mode 100644 index 000000000..e4869c2f2 --- /dev/null +++ b/slsDetectorSoftware/include/Result.h @@ -0,0 +1,99 @@ +#pragma once + +/** + * \file Result.h + * Result is a thin wrapper around std::vector and used for returning values + * from the detector. Since every module could have a different value, we need + * to return a vector instead of just a single value. + * + * Easy conversions to single values are provided using the squash method. + */ + +#include +#include +#include + +#include "ToString.h" +#include "container_utils.h" + +namespace sls { + +/** + * @tparam T type to store in the result + * @tparam Allocator for the underlying vector, default + */ +template > class Result { + /** wrapped vector */ + std::vector vec; + + public: + Result() = default; + Result(std::initializer_list list) : vec(list){}; + + /** + * Forward arguments to the constructor of std::vector + * @tparam Args template paramter pack to forward + */ + template + Result(Args &&... args) : vec(std::forward(args)...) {} + + using value_type = typename std::vector::value_type; + using iterator = typename std::vector::iterator; + using const_iterator = typename std::vector::const_iterator; + using size_type = typename std::vector::size_type; + using reference = typename std::vector::reference; + using const_reference = typename std::vector::const_reference; + + auto begin() noexcept -> decltype(vec.begin()) { return vec.begin(); } + auto begin() const noexcept -> decltype(vec.begin()) { return vec.begin(); } + auto cbegin() const noexcept -> decltype(vec.cbegin()) { + return vec.cbegin(); + } + auto end() noexcept -> decltype(vec.end()) { return vec.end(); } + auto end() const noexcept -> decltype(vec.end()) { return vec.end(); } + auto cend() const noexcept -> decltype(vec.cend()) { return vec.cend(); } + auto size() const noexcept -> decltype(vec.size()) { return vec.size(); } + auto empty() const noexcept -> decltype(vec.empty()) { return vec.empty(); } + auto front() -> decltype(vec.front()) { return vec.front(); } + auto front() const -> decltype(vec.front()) { return vec.front(); } + + template + auto push_back(V value) -> decltype(vec.push_back(value)) { + vec.push_back(std::forward(value)); + } + + auto operator[](size_type pos) -> decltype(vec[pos]) { return vec[pos]; } + const_reference operator[](size_type pos) const { return vec[pos]; } + + /** + * If all elements are equal it returns the front value + * otherwise a default constructed T + */ + T squash() const { return Squash(vec); } + + /** + * If all elements are equal return the front value, otherwise + * return the supplied default value + */ + T squash(T default_value) const { return Squash(vec, default_value); } + + /** Test whether all elements of the result are equal */ + bool equal() const noexcept { return allEqual(vec); } + + /** Convert Result to std::vector */ + operator std::vector() { return vec; } + + /** Convert Result to T using squash() */ + operator T() { return squash(); } +}; + +/** + * operator << overload to print Result, uses ToString for the conversion + * @tparam T type stored in the Result + */ +template +std::ostream &operator<<(std::ostream &os, const Result &res) { + return os << ToString(res); +} + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorSoftware/include/multiSlsDetector.h b/slsDetectorSoftware/include/multiSlsDetector.h index bf16deaca..ef9908af7 100755 --- a/slsDetectorSoftware/include/multiSlsDetector.h +++ b/slsDetectorSoftware/include/multiSlsDetector.h @@ -4,7 +4,6 @@ #include "logger.h" #include "sls_detector_defs.h" - class slsDetector; class ZmqSocket; class detectorData; @@ -20,14 +19,17 @@ class detectorData; #define SHORT_STRING_LENGTH 50 #define DATE_LENGTH 30 + +#include +#include /** - * @short structure allocated in shared memory to store detector settings - * for IPC and cache - */ + * @short structure allocated in shared memory to store detector settings + * for IPC and cache + */ struct sharedMultiSlsDetector { /* FIXED PATTERN FOR STATIC FUNCTIONS. DO NOT CHANGE, ONLY APPEND - * ------*/ + * ------*/ /** shared memory version */ int shmversion; @@ -45,7 +47,7 @@ struct sharedMultiSlsDetector { int numberOfDetectors; /** END OF FIXED PATTERN - * -----------------------------------------------*/ + * -----------------------------------------------*/ /** Number of detectors operated at once */ int numberOfDetector[2]; @@ -72,11 +74,11 @@ struct sharedMultiSlsDetector { int maxNumberOfChannel[2]; /** max number of channels including gap pixels for all detectors in - * one dimension*/ + * one dimension*/ int maxNumberOfChannelInclGapPixels[2]; /** max number of channels allowed for the complete set of detectors in - * one dimension */ + * one dimension */ int maxNumberOfChannelsPerDetector[2]; /** timer values */ @@ -98,8 +100,7 @@ class multiSlsDetector : public virtual slsDetectorDefs { * one * @param update true to update last user pid, date etc */ - explicit multiSlsDetector(int multi_id = 0, - bool verify = true, + explicit multiSlsDetector(int multi_id = 0, bool verify = true, bool update = true); /** @@ -107,6 +108,101 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ virtual ~multiSlsDetector(); + template struct NonDeduced { using type = CT; }; + template + std::vector Parallel(RT (slsDetector::*somefunc)(CT...), + std::vector positions, + typename NonDeduced::type... Args) { + + if (positions.empty() || (positions.size() == 1 && positions[0] == -1 )) { + positions.resize(detectors.size()); + std::iota(begin(positions), end(positions), 0); + } + std::vector> futures; + futures.reserve(positions.size()); + for (size_t i : positions) { + if (i >= detectors.size()) + throw sls::RuntimeError("Detector out of range"); + futures.push_back(std::async(std::launch::async, somefunc, + detectors[i].get(), Args...)); + } + std::vector result; + result.reserve(positions.size()); + for (auto &i : futures) { + result.push_back(i.get()); + } + return result; + } + + template + std::vector Parallel(RT (slsDetector::*somefunc)(CT...) const, + std::vector positions, + typename NonDeduced::type... Args) const{ + + if (positions.empty() || (positions.size() == 1 && positions[0] == -1 )) { + positions.resize(detectors.size()); + std::iota(begin(positions), end(positions), 0); + } + std::vector> futures; + futures.reserve(positions.size()); + for (size_t i : positions) { + if (i >= detectors.size()) + throw sls::RuntimeError("Detector out of range"); + futures.push_back(std::async(std::launch::async, somefunc, + detectors[i].get(), Args...)); + } + std::vector result; + result.reserve(positions.size()); + for (auto &i : futures) { + result.push_back(i.get()); + } + return result; + } + + template + void Parallel(void (slsDetector::*somefunc)(CT...), + std::vector positions, + typename NonDeduced::type... Args) { + + if (positions.empty() || (positions.size() == 1 && positions[0] == -1 )) { + positions.resize(detectors.size()); + std::iota(begin(positions), end(positions), 0); + } + std::vector> futures; + futures.reserve(positions.size()); + for (size_t i : positions) { + if (i >= detectors.size()) + throw sls::RuntimeError("Detector out of range"); + futures.push_back(std::async(std::launch::async, somefunc, + detectors[i].get(), Args...)); + } + for (auto &i : futures) { + i.get(); + } + } + + template + void Parallel(void (slsDetector::*somefunc)(CT...) const, + std::vector positions, + typename NonDeduced::type... Args) const{ + + if (positions.empty() || (positions.size() == 1 && positions[0] == -1 )) { + positions.resize(detectors.size()); + std::iota(begin(positions), end(positions), 0); + } + std::vector> futures; + futures.reserve(positions.size()); + for (size_t i : positions) { + if (i >= detectors.size()) + throw sls::RuntimeError("Detector out of range"); + futures.push_back(std::async(std::launch::async, somefunc, + detectors[i].get(), Args...)); + } + for (auto &i : futures) { + i.get(); + } + } + /** * Creates/open shared memory, initializes detector structure and members * Called by constructor/ set hostname / read config file @@ -114,14 +210,12 @@ class multiSlsDetector : public virtual slsDetectorDefs { * one * @param update true to update last user pid, date etc */ - void setupMultiDetector(bool verify = true, - bool update = true); + void setupMultiDetector(bool verify = true, bool update = true); /** * Loop through the detectors serially and return the result as a vector */ - template - struct NonDeduced { using type = CT; }; + template std::vector serialCall(RT (slsDetector::*somefunc)(CT...), typename NonDeduced::type... Args); @@ -149,13 +243,13 @@ class multiSlsDetector : public virtual slsDetectorDefs { std::vector parallelCall(RT (slsDetector::*somefunc)(CT...) const, typename NonDeduced::type... Args) const; + template + void parallelCall(void (slsDetector::*somefunc)(CT...), + typename NonDeduced::type... Args); template - void parallelCall(void (slsDetector::*somefunc)(CT...), typename NonDeduced::type... Args); - - template - void parallelCall(void (slsDetector::*somefunc)(CT...) const, typename NonDeduced::type... Args) const; - + void parallelCall(void (slsDetector::*somefunc)(CT...) const, + typename NonDeduced::type... Args) const; /** * Decodes which detector and the corresponding channel numbers for it @@ -210,22 +304,24 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ int64_t getId(idMode mode, int detPos = -1); - /** - * Get Client Software version - * @returns client software version - */ + int getMultiId()const{return multiId;} + + /** + * Get Client Software version + * @returns client software version + */ int64_t getClientSoftwareVersion() const; - /** - * Get Receiver software version - * @return receiver software version - */ + /** + * Get Receiver software version + * @return receiver software version + */ int64_t getReceiverSoftwareVersion(int detPos = -1); - /** - * Get Detector Number - * @returns vector of detector number - */ + /** + * Get Detector Number + * @returns vector of detector number + */ std::vector getDetectorNumber(); /** * Free shared memory from the command line @@ -621,7 +717,7 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ void setStartingFrameNumber(const uint64_t value, int detPos = -1); - /** + /** * Get starting frame number for the next acquisition * @param detPos -1 for all detectors in list or specific detector position * @returns starting frame number @@ -761,7 +857,8 @@ class multiSlsDetector : public virtual slsDetectorDefs { * @param detPos -1 for all detectors in list or specific detector position * @returns value of speed set */ - int setSpeed(speedVariable index, int value = -1, int mode = 0, int detPos = -1); + int setSpeed(speedVariable index, int value = -1, int mode = 0, + int detPos = -1); /** * Set/get dynamic range and updates the number of dataBytes @@ -780,9 +877,9 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ int getDataBytes(int detPos = -1); - /** + /** * Returns the number of detectors in the multi structure*/ - size_t size() const{ return detectors.size();} + size_t size() const { return detectors.size(); } /** * Set/get dacs value @@ -898,12 +995,14 @@ class multiSlsDetector : public virtual slsDetectorDefs { std::string getDetectorMAC(int detPos = -1); /** - * Validates the format of the detector MAC address (bottom half) and sets it (Jungfrau only) + * Validates the format of the detector MAC address (bottom half) and sets + * it (Jungfrau only) * @param detectorMAC detector MAC address (bottom half) * @param detPos -1 for all detectors in list or specific detector position * @returns the detector MAC address (bottom half) */ - std::string setDetectorMAC2(const std::string &detectorMAC, int detPos = -1); + std::string setDetectorMAC2(const std::string &detectorMAC, + int detPos = -1); /** * Returns the detector MAC address (bottom half) Jungfrau only @@ -928,7 +1027,8 @@ class multiSlsDetector : public virtual slsDetectorDefs { std::string getDetectorIP(int detPos = -1) const; /** - * Validates the format of the detector IP address (bottom half) and sets it (Jungfrau only) + * Validates the format of the detector IP address (bottom half) and sets it + * (Jungfrau only) * @param detectorIP detector IP address (bottom half) * @param detPos -1 for all detectors in list or specific detector position * @returns the detector IP address (bottom half) @@ -944,13 +1044,15 @@ class multiSlsDetector : public virtual slsDetectorDefs { /** * Validates and sets the receiver. - * Also updates the receiver with all the shared memory parameters significant for the receiver - * Also configures the detector to the receiver as UDP destination + * Also updates the receiver with all the shared memory parameters + * significant for the receiver Also configures the detector to the receiver + * as UDP destination * @param receiver receiver hostname or IP address * @param detPos -1 for all detectors in list or specific detector position * @returns the receiver IP address from shared memory */ - std::string setReceiverHostname(const std::string &receiver, int detPos = -1); + std::string setReceiverHostname(const std::string &receiver, + int detPos = -1); /** * Returns the receiver IP address @@ -975,7 +1077,8 @@ class multiSlsDetector : public virtual slsDetectorDefs { std::string getReceiverUDPIP(int detPos = -1) const; /** - * Validates the format of the receiver UDP IP address (bottom half) and sets it(Jungfrau only) + * Validates the format of the receiver UDP IP address (bottom half) and + * sets it(Jungfrau only) * @param udpip receiver UDP IP address (bottom half) * @param detPos -1 for all detectors in list or specific detector position * @returns the receiver UDP IP address (bottom half) @@ -1005,7 +1108,8 @@ class multiSlsDetector : public virtual slsDetectorDefs { std::string getReceiverUDPMAC(int detPos = -1) const; /** - * Validates the format of the receiver UDP MAC address (bottom half) and sets it (Jungfrau only) + * Validates the format of the receiver UDP MAC address (bottom half) and + * sets it (Jungfrau only) * @param udpmac receiver UDP MAC address (bottom half) * @param detPos -1 for all detectors in list or specific detector position * @returns the receiver UDP MAC address (bottom half) @@ -1043,14 +1147,16 @@ class multiSlsDetector : public virtual slsDetectorDefs { int setReceiverUDPPort2(int udpport, int detPos = -1); /** - * Returns the receiver UDP port 2 of same interface (Eiger and Jungfrau only) + * Returns the receiver UDP port 2 of same interface (Eiger and Jungfrau + * only) * @param detPos -1 for all detectors in list or specific detector position * @returns the receiver UDP port 2 of same interface */ int getReceiverUDPPort2(int detPos = -1) const; /** - * Sets the number of UDP interfaces to stream data from detector (Jungfrau only) + * Sets the number of UDP interfaces to stream data from detector (Jungfrau + * only) * @param n number of interfaces. Options 1 or 2. * @param detPos -1 for all detectors in list or specific detector position * @returns the number of interfaces @@ -1058,14 +1164,16 @@ class multiSlsDetector : public virtual slsDetectorDefs { int setNumberofUDPInterfaces(int n, int detPos = -1); /** - * Returns the number of UDP interfaces to stream data from detector (Jungfrau only) + * Returns the number of UDP interfaces to stream data from detector + * (Jungfrau only) * @param detPos -1 for all detectors in list or specific detector position * @returns the number of interfaces */ int getNumberofUDPInterfaces(int detPos = -1) const; /** - * Selects the UDP interfaces to stream data from detector. Effective only when number of interfaces is 1. (Jungfrau only) + * Selects the UDP interfaces to stream data from detector. Effective only + * when number of interfaces is 1. (Jungfrau only) * @param n selected interface. Options 1 or 2. * @param detPos -1 for all detectors in list or specific detector position * @returns the interface selected @@ -1073,7 +1181,8 @@ class multiSlsDetector : public virtual slsDetectorDefs { int selectUDPInterface(int n, int detPos = -1); /** - * Returns the UDP interfaces to stream data from detector. Effective only when number of interfaces is 1. (Jungfrau only) + * Returns the UDP interfaces to stream data from detector. Effective only + * when number of interfaces is 1. (Jungfrau only) * @param detPos -1 for all detectors in list or specific detector position * @returns the interface selected */ @@ -1090,11 +1199,12 @@ class multiSlsDetector : public virtual slsDetectorDefs { void setClientDataStreamingInPort(int i = -1, int detPos = -1); /** - * Returns the client zmq port - * If detPos is -1(multi module), port returns client streaming port of first module + * Returns the client zmq port + * If detPos is -1(multi module), port returns client streaming port of + * first module * @param detPos -1 for all detectors in list or specific detector position - * @returns the client zmq port - */ + * @returns the client zmq port + */ int getClientStreamingPort(int detPos = -1); /** @@ -1108,11 +1218,12 @@ class multiSlsDetector : public virtual slsDetectorDefs { void setReceiverDataStreamingOutPort(int i = -1, int detPos = -1); /** - * Returns the receiver zmq port - * If detPos is -1(multi module), port returns receiver streaming port of first module + * Returns the receiver zmq port + * If detPos is -1(multi module), port returns receiver streaming port of + * first module * @param detPos -1 for all detectors in list or specific detector position - * @returns the receiver zmq port - */ + * @returns the receiver zmq port + */ int getReceiverStreamingPort(int detPos = -1); /** @@ -1126,11 +1237,12 @@ class multiSlsDetector : public virtual slsDetectorDefs { int detPos = -1); /** - * Returns the client zmq ip - * If detPos is -1(multi module), ip returns concatenation of all client streaming ip + * Returns the client zmq ip + * If detPos is -1(multi module), ip returns concatenation of all client + * streaming ip * @param detPos -1 for all detectors in list or specific detector position - * @returns the client zmq ip - */ + * @returns the client zmq ip + */ std::string getClientStreamingIP(int detPos = -1); /** @@ -1144,11 +1256,12 @@ class multiSlsDetector : public virtual slsDetectorDefs { int detPos = -1); /** - * Returns the receiver zmq ip - * If detPos is -1(multi module), ip returns concatenation of all receiver streaming ip - * @param detPos -1 for all detectors in list or specific detector position - * @returns the receiver zmq ip - */ + * Returns the receiver zmq ip + * If detPos is -1(multi module), ip returns concatenation of all receiver + * streaming ip + * @param detPos -1 for all detectors in list or specific detector position + * @returns the receiver zmq ip + */ std::string getReceiverStreamingIP(int detPos = -1); /** @@ -1159,7 +1272,8 @@ class multiSlsDetector : public virtual slsDetectorDefs { * @param detPos -1 for all detectors in list or specific detector position * @returns transmission delay */ - int setDetectorNetworkParameter(networkParameter index, int delay, int detPos = -1); + int setDetectorNetworkParameter(networkParameter index, int delay, + int detPos = -1); /** * Sets the additional json header @@ -1167,7 +1281,8 @@ class multiSlsDetector : public virtual slsDetectorDefs { * @param detPos -1 for all detectors in list or specific detector position * @returns additional json header, default is empty */ - std::string setAdditionalJsonHeader(const std::string &jsonheader, int detPos = -1); + std::string setAdditionalJsonHeader(const std::string &jsonheader, + int detPos = -1); /** * Returns the additional json header @@ -1177,14 +1292,17 @@ class multiSlsDetector : public virtual slsDetectorDefs { std::string getAdditionalJsonHeader(int detPos = -1); /** - * Sets the value for the additional json header parameter if found, else append it + * Sets the value for the additional json header parameter if found, else + * append it * @param key additional json header parameter * @param value additional json header parameter value (cannot be empty) * @param detPos -1 for all detectors in list or specific detector position * @returns the additional json header parameter value, * empty if no parameter found in additional json header */ - std::string setAdditionalJsonParameter(const std::string &key, const std::string &value, int detPos = -1); + std::string setAdditionalJsonParameter(const std::string &key, + const std::string &value, + int detPos = -1); /** * Returns the additional json header parameter value @@ -1193,21 +1311,26 @@ class multiSlsDetector : public virtual slsDetectorDefs { * @returns the additional json header parameter value, * empty if no parameter found in additional json header */ - std::string getAdditionalJsonParameter(const std::string &key, int detPos = -1); + std::string getAdditionalJsonParameter(const std::string &key, + int detPos = -1); /** - * Sets the detector minimum/maximum energy threshold in processor (for Moench only) + * Sets the detector minimum/maximum energy threshold in processor (for + * Moench only) * @param index 0 for emin, antyhing else for emax * @param v value to set (-1 gets) - * @returns detector minimum/maximum energy threshold (-1 for not found or error in computing json parameter value) + * @returns detector minimum/maximum energy threshold (-1 for not found or + * error in computing json parameter value) */ - int setDetectorMinMaxEnergyThreshold(const int index, int value, int detPos = -1); + int setDetectorMinMaxEnergyThreshold(const int index, int value, + int detPos = -1); /** * Sets the frame mode in processor (Moench only) * @param value frameModeType (-1 gets) * @param detPos -1 for all detectors in list or specific detector position - * @returns frame mode (-1 for not found or error in computing json parameter value) + * @returns frame mode (-1 for not found or error in computing json + * parameter value) */ int setFrameMode(frameModeType value, int detPos = -1); @@ -1215,7 +1338,8 @@ class multiSlsDetector : public virtual slsDetectorDefs { * Sets the detector mode in processor (Moench only) * @param value detectorModetype (-1 gets) * @param detPos -1 for all detectors in list or specific detector position - * @returns detector mode (-1 for not found or error in computing json parameter value) + * @returns detector mode (-1 for not found or error in computing json + * parameter value) */ int setDetectorMode(detectorModeType value, int detPos = -1); @@ -1225,7 +1349,8 @@ class multiSlsDetector : public virtual slsDetectorDefs { * @param detPos -1 for all detectors in list or specific detector position * @returns receiver udp socket buffer size */ - int64_t setReceiverUDPSocketBufferSize(int64_t udpsockbufsize = -1, int detPos = -1); + int64_t setReceiverUDPSocketBufferSize(int64_t udpsockbufsize = -1, + int detPos = -1); /** * Returns the receiver UDP socket buffer size @@ -1324,77 +1449,77 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ void setADCEnableMask(uint32_t mask, int detPos = -1); - /** + /** * Get ADC Enable Mask (CTB, Moench) * @param detPos -1 for all detectors in list or specific detector position * @returns ADC Enable mask */ uint32_t getADCEnableMask(int detPos = -1); - /** + /** * Set ADC invert register (CTB, Moench) * @param value ADC invert value * @param detPos -1 for all detectors in list or specific detector position */ void setADCInvert(uint32_t value, int detPos = -1); - /** + /** * Get ADC invert register (CTB, Moench) * @param detPos -1 for all detectors in list or specific detector position * @returns ADC invert value */ uint32_t getADCInvert(int detPos = -1); - /** + /** * Set external sampling source (CTB only) * @param value external sampling source (Option: 0-63) * @param detPos -1 for all detectors in list or specific detector position */ void setExternalSamplingSource(int value, int detPos = -1); - /** + /** * Get external sampling source (CTB only) * @param detPos -1 for all detectors in list or specific detector position * @returns external sampling source */ int getExternalSamplingSource(int detPos = -1); - /** + /** * Set external sampling enable (CTB only) * @param value external sampling source (Option: 0-63) * @param detPos -1 for all detectors in list or specific detector position */ void setExternalSampling(bool value, int detPos = -1); - /** + /** * Get external sampling source (CTB only) * @param detPos -1 for all detectors in list or specific detector position * @returns external sampling enable */ int getExternalSampling(int detPos = -1); - /** + /** * Set external sampling enable (CTB only) * @param list external sampling source (Option: 0-63) * @param detPos -1 for all detectors in list or specific detector position */ void setReceiverDbitList(std::vector list, int detPos = -1); - /** + /** * Get external sampling source (CTB only) * @param detPos -1 for all detectors in list or specific detector position * @returns external sampling enable */ std::vector getReceiverDbitList(int detPos = -1); - /** + /** * Set digital data offset in bytes (CTB only) * @param value digital data offset in bytes * @param detPos -1 for all detectors in list or specific detector position */ void setReceiverDbitOffset(int value, int detPos = -1); - /** + /** * Get digital data offset in bytes (CTB only) * @param detPos -1 for all detectors in list or specific detector position * @returns digital data offset in bytes @@ -1565,7 +1690,8 @@ class multiSlsDetector : public virtual slsDetectorDefs { void rebootController(int detPos = -1); /** - * Updates the firmware, detector server and then reboots detector controller blackfin. (Not Eiger) + * Updates the firmware, detector server and then reboots detector + * controller blackfin. (Not Eiger) * @param sname name of detector server binary * @param hostname name of pc to tftp from * @param fname programming file name @@ -1589,7 +1715,6 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ int setAutoComparatorDisableMode(int ival = -1, int detPos = -1); - /** * Set Rate correction ( Eiger) * @param t dead time in ns - if 0 disable correction, @@ -1600,17 +1725,17 @@ class multiSlsDetector : public virtual slsDetectorDefs { void setRateCorrection(int64_t t = 0, int detPos = -1); /** - * Get rate correction ( Eiger) - * @param detPos -1 for all detectors in list or specific detector position - * @returns 0 if rate correction disabled, > 0 otherwise (ns) - */ + * Get rate correction ( Eiger) + * @param detPos -1 for all detectors in list or specific detector position + * @returns 0 if rate correction disabled, > 0 otherwise (ns) + */ int64_t getRateCorrection(int detPos = -1); /** - * Prints receiver configuration - * @param level print level - * @param detPos -1 for all detectors in list or specific detector position - */ + * Prints receiver configuration + * @param level print level + * @param detPos -1 for all detectors in list or specific detector position + */ void printReceiverConfiguration(TLogLevel level = logINFO, int detPos = -1); /** @@ -1824,8 +1949,8 @@ class multiSlsDetector : public virtual slsDetectorDefs { * @returns file write enable */ int getFileWrite(int detPos = -1) const; - - /** + + /** * Sets/Gets receiver master file write enable * @param value 1 or 0 to set/reset master file write enable * @param detPos -1 for all detectors in list or specific detector position @@ -1923,26 +2048,27 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ int setPattern(const std::string &fname, int detPos = -1); - /** - * Sets pattern IO control (CTB/ Moench) - * @param word 64bit word to be written, -1 gets - * @param detPos -1 for all detectors in list or specific detector position - * @returns actual value - */ - uint64_t setPatternIOControl(uint64_t word = -1, int detPos = -1); + /** + * Sets pattern IO control (CTB/ Moench) + * @param word 64bit word to be written, -1 gets + * @param detPos -1 for all detectors in list or specific detector position + * @returns actual value + */ + uint64_t setPatternIOControl(uint64_t word = -1, int detPos = -1); - /** - * Sets pattern clock control (CTB/ Moench) - * @param word 64bit word to be written, -1 gets - * @param detPos -1 for all detectors in list or specific detector position - * @returns actual value - */ - uint64_t setPatternClockControl(uint64_t word = -1, int detPos = -1); + /** + * Sets pattern clock control (CTB/ Moench) + * @param word 64bit word to be written, -1 gets + * @param detPos -1 for all detectors in list or specific detector position + * @returns actual value + */ + uint64_t setPatternClockControl(uint64_t word = -1, int detPos = -1); /** * Writes a pattern word (CTB/ Moench) * @param addr address of the word - * @param word 64bit word to be written, -1 reads the addr (same as executing the pattern) + * @param word 64bit word to be written, -1 reads the addr (same as + * executing the pattern) * @param detPos -1 for all detectors in list or specific detector position * @returns actual value */ @@ -1956,15 +2082,16 @@ class multiSlsDetector : public virtual slsDetectorDefs { * @param n number of loops for level 0-2, -1 gets * @param detPos -1 for all detectors in list or specific detector position */ - void setPatternLoops(int level, int start = -1, int stop = -1, int n = -1, int detPos = -1); + void setPatternLoops(int level, int start = -1, int stop = -1, int n = -1, + int detPos = -1); - /** - * Gets the pattern loop limits (CTB/ Moench) - * @param level -1 complete pattern, 0,1,2, loop level - * @param detPos -1 for all detectors in list or specific detector position - * @returns array of start address, stop address and number of loops - */ - std::array getPatternLoops(int level, int detPos = -1); + /** + * Gets the pattern loop limits (CTB/ Moench) + * @param level -1 complete pattern, 0,1,2, loop level + * @param detPos -1 for all detectors in list or specific detector position + * @returns array of start address, stop address and number of loops + */ + std::array getPatternLoops(int level, int detPos = -1); /** * Sets the wait address (CTB/ Moench) @@ -1999,14 +2126,16 @@ class multiSlsDetector : public virtual slsDetectorDefs { uint64_t getPatternMask(int detPos = -1); /** - * Selects the bits that the mask will be applied to for every pattern (CTB/ Moench) + * Selects the bits that the mask will be applied to for every pattern (CTB/ + * Moench) * @param mask mask to select bits * @param detPos -1 for all detectors in list or specific detector position */ void setPatternBitMask(uint64_t mask, int detPos = -1); /** - * Gets the bits that the mask will be applied to for every pattern (CTB/ Moench) + * Gets the bits that the mask will be applied to for every pattern (CTB/ + * Moench) * @param detPos -1 for all detectors in list or specific detector position * @returns mask of bits selected */ @@ -2132,16 +2261,14 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ void addSlsDetector(const std::string &hostname); - - - /** - * add gap pixels to the image (only for Eiger in 4 bit mode) - * @param image pointer to image without gap pixels - * @param gpImage poiner to image with gap pixels, if NULL, allocated - * inside function - * @returns number of data bytes of image with gap pixels - */ - int processImageWithGapPixels(char *image, char *&gpImage); + /** + * add gap pixels to the image (only for Eiger in 4 bit mode) + * @param image pointer to image without gap pixels + * @param gpImage poiner to image with gap pixels, if NULL, allocated + * inside function + * @returns number of data bytes of image with gap pixels + */ + int processImageWithGapPixels(char *image, char *&gpImage); /** * Set total progress (total number of frames/images in an acquisition) @@ -2197,14 +2324,13 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ std::vector readPofFile(const std::string &fname); - /** - * Convert a double holding time in seconds to an int64_t with nano seconds - * Used for conversion when sending time to detector - * @param t time in seconds - * @returns time in nano seconds - */ - int64_t secondsToNanoSeconds(double t); - + /** + * Convert a double holding time in seconds to an int64_t with nano seconds + * Used for conversion when sending time to detector + * @param t time in seconds + * @returns time in nano seconds + */ + int64_t secondsToNanoSeconds(double t); /** Multi detector Id */ const int multiId{0}; @@ -2260,4 +2386,3 @@ class multiSlsDetector : public virtual slsDetectorDefs { void (*dataReady)(detectorData *, uint64_t, uint32_t, void *){nullptr}; void *pCallbackArg{nullptr}; }; - diff --git a/slsDetectorSoftware/include/multiSlsDetectorClient.h b/slsDetectorSoftware/include/multiSlsDetectorClient.h index ba924f199..e370d4905 100755 --- a/slsDetectorSoftware/include/multiSlsDetectorClient.h +++ b/slsDetectorSoftware/include/multiSlsDetectorClient.h @@ -4,6 +4,7 @@ #include "CmdLineParser.h" #include "CmdProxy.h" +#include "Detector.h" #include "container_utils.h" #include "multiSlsDetector.h" #include "slsDetectorCommand.h" @@ -109,7 +110,12 @@ class multiSlsDetectorClient { // returns an empty string If the command is not in CmdProxy but // deprecated the new command is returned if (action_ != slsDetectorDefs::READOUT_ACTION) { - sls::CmdProxy proxy(detPtr); + int multi_id = 0; + if (detPtr != nullptr) + multi_id = detPtr->getMultiId(); + sls::Detector d(multi_id); + sls::CmdProxy proxy(&d); + // sls::CmdProxy proxy(detPtr); auto cmd = proxy.Call(parser.command(), parser.arguments(), parser.detector_id(), action_); if (cmd.empty()) { diff --git a/slsDetectorSoftware/include/slsDetector.h b/slsDetectorSoftware/include/slsDetector.h index e3f03780e..582b3283f 100755 --- a/slsDetectorSoftware/include/slsDetector.h +++ b/slsDetectorSoftware/include/slsDetector.h @@ -629,7 +629,7 @@ class slsDetector : public virtual slsDetectorDefs { * Set starting frame number for the next acquisition * @param val starting frame number */ - void setStartingFrameNumber(const uint64_t value); + void setStartingFrameNumber(uint64_t value); /** * Get starting frame number for the next acquisition diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp new file mode 100644 index 000000000..fe7f12b81 --- /dev/null +++ b/slsDetectorSoftware/src/Detector.cpp @@ -0,0 +1,129 @@ +#include "Detector.h" +#include "container_utils.h" +#include "multiSlsDetector.h" +#include "slsDetector.h" +#include "sls_detector_defs.h" +namespace sls { + +using defs = slsDetectorDefs; + +Detector::Detector(int multi_id) + : pimpl(sls::make_unique(multi_id)) {} +Detector::~Detector() = default; + + +// Acquisition +void Detector::acquire() { pimpl->acquire(); } + +void Detector::startReceiver(Positions pos) { + pimpl->Parallel(&slsDetector::startReceiver, pos); +} +void Detector::stopReceiver(Positions pos) { + pimpl->Parallel(&slsDetector::stopReceiver, pos); +} + +Result Detector::getReceiverStatus(Positions pos) { + return pimpl->Parallel(&slsDetector::getReceiverStatus, pos); +} + +bool Detector::getAcquiringFlag() const{ + return pimpl->getAcquiringFlag(); +} + +void Detector::setAcquiringFlag(bool value){ + pimpl->setAcquiringFlag(value); +} + +// Configuration +Result Detector::getHostname(Positions pos) const { + return pimpl->Parallel(&slsDetector::getHostname, pos); +} + +void Detector::freeSharedMemory() { pimpl->freeSharedMemory(); } + + +void Detector::setConfig(const std::string &fname) { + pimpl->readConfigurationFile(fname); +} + +void Detector::clearBit(uint32_t addr, int bitnr, Positions pos) { + pimpl->Parallel(&slsDetector::clearBit, pos, addr, bitnr); +} +void Detector::setBit(uint32_t addr, int bitnr, Positions pos) { + pimpl->Parallel(&slsDetector::setBit, pos, addr, bitnr); +} +Result Detector::getRegister(uint32_t addr, Positions pos) { + return pimpl->Parallel(&slsDetector::readRegister, pos, addr); +} + +Result Detector::getExptime(Positions pos) const { + auto r = pimpl->Parallel(&slsDetector::setTimer, pos, + defs::ACQUISITION_TIME, -1); + return Result(begin(r), end(r)); +} + +Result Detector::getStartingFrameNumber(Positions pos) const { + return pimpl->Parallel(&slsDetector::getStartingFrameNumber, pos); +} +void Detector::setStartingFrameNumber(uint64_t value, Positions pos) { + pimpl->Parallel(&slsDetector::setStartingFrameNumber, pos, value); +} + +void Detector::setExptime(ns t, Positions pos) { + pimpl->Parallel(&slsDetector::setTimer, pos, defs::ACQUISITION_TIME, + t.count()); +} + +Result Detector::getSubExptime(Positions pos) const { + auto r = pimpl->Parallel(&slsDetector::setTimer, pos, + defs::SUBFRAME_ACQUISITION_TIME, -1); + return Result(begin(r), end(r)); +} + +void Detector::setSubExptime(ns t, Positions pos) { + pimpl->Parallel(&slsDetector::setTimer, pos, + defs::SUBFRAME_ACQUISITION_TIME, t.count()); +} + +Result Detector::getPeriod(Positions pos) const { + auto r = + pimpl->Parallel(&slsDetector::setTimer, pos, defs::FRAME_PERIOD, -1); + return Result(begin(r), end(r)); +} + +void Detector::setPeriod(ns t, Positions pos) { + pimpl->Parallel(&slsDetector::setTimer, pos, defs::FRAME_PERIOD, t.count()); +} + +// File +void Detector::setFileName(const std::string &fname) { + pimpl->Parallel(&slsDetector::setFileName, Positions{}, fname); +} +Result Detector::getFileName() const { + return pimpl->Parallel(&slsDetector::setFileName, Positions{}, ""); +} + +void Detector::setFilePath(const std::string &fpath) { + pimpl->Parallel(&slsDetector::setFilePath, Positions{}, fpath); +} +Result Detector::getFilePath() const { + return pimpl->Parallel(&slsDetector::getFilePath, Positions{}); +} + +void Detector::setFileWrite(bool value, Positions pos) { + pimpl->Parallel(&slsDetector::setFileWrite, Positions{}, value); +} + +Result Detector::getFileWrite(Positions pos) const { + return pimpl->Parallel(&slsDetector::getFileWrite, Positions{}); +} + +void Detector::setFileOverWrite(bool value, Positions pos) { + pimpl->Parallel(&slsDetector::setFileOverWrite, Positions{}, value); +} + +Result Detector::getFileOverWrite(Positions pos) const { + return pimpl->Parallel(&slsDetector::getFileOverWrite, Positions{}); +} + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorSoftware/src/multiSlsDetector.cpp b/slsDetectorSoftware/src/multiSlsDetector.cpp index c5044ce0c..0c7b14feb 100755 --- a/slsDetectorSoftware/src/multiSlsDetector.cpp +++ b/slsDetectorSoftware/src/multiSlsDetector.cpp @@ -4457,3 +4457,9 @@ std::vector multiSlsDetector::readPofFile(const std::string &fname) { FILE_LOG(logINFO) << "Read file into memory"; return buffer; } + + + + + + diff --git a/slsDetectorSoftware/src/slsDetector.cpp b/slsDetectorSoftware/src/slsDetector.cpp index 90987b4f5..6a6386a6e 100755 --- a/slsDetectorSoftware/src/slsDetector.cpp +++ b/slsDetectorSoftware/src/slsDetector.cpp @@ -1382,7 +1382,7 @@ void slsDetector::configureMAC() { } } -void slsDetector::setStartingFrameNumber(const uint64_t value) { +void slsDetector::setStartingFrameNumber(uint64_t value) { FILE_LOG(logDEBUG1) << "Setting starting frame number to " << value; sendToDetector(F_SET_STARTING_FRAME_NUMBER, value, nullptr); } diff --git a/slsDetectorSoftware/tests/CMakeLists.txt b/slsDetectorSoftware/tests/CMakeLists.txt index dcde08ad2..70d6ff999 100755 --- a/slsDetectorSoftware/tests/CMakeLists.txt +++ b/slsDetectorSoftware/tests/CMakeLists.txt @@ -3,4 +3,5 @@ target_sources(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test-slsDetector.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-multiSlsDetector.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-multiSlsDetectorClient.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test-Result.cpp ) \ No newline at end of file diff --git a/slsDetectorSoftware/tests/test-Result.cpp b/slsDetectorSoftware/tests/test-Result.cpp new file mode 100644 index 000000000..73e3878df --- /dev/null +++ b/slsDetectorSoftware/tests/test-Result.cpp @@ -0,0 +1,75 @@ +#include "Result.h" +#include "catch.hpp" + +#include + +using sls::Result; + +TEST_CASE("Default construction", "[detector][n2]") { + Result res; + REQUIRE(res.size() == 0); + REQUIRE(res.empty() == true); +} + +TEST_CASE("Initializer list construction", "[n2]") { + Result res{1, 2, 5}; + REQUIRE(res.empty() == false); + REQUIRE(res.size() == 3); + REQUIRE(res[0] == 1); + REQUIRE(res[1] == 2); + REQUIRE(res[2] == 5); +} + +TEST_CASE("Construct with value and number", "[n2]") { + Result res(5, 7); + REQUIRE(res.size() == 5); + REQUIRE(res[0] == 7); + REQUIRE(res[1] == 7); + REQUIRE(res[2] == 7); + REQUIRE(res[3] == 7); + REQUIRE(res[4] == 7); +} + +TEST_CASE("Squash empty", "[n2]") { + Result res; + REQUIRE(res.squash() == 0.); +} + +TEST_CASE("Squash gives either value or default constructed value", "[n2]") { + Result res{3, 3, 3}; + REQUIRE(res.squash() == 3); + + res.push_back(5); + REQUIRE(res.squash() == 0); + REQUIRE(res.squash(-1) == -1); +} + +TEST_CASE("Updating an element", "[n2]") { + + Result res{1, 2, 3}; + REQUIRE(res[0] == 1); + REQUIRE(res[1] == 2); + REQUIRE(res[2] == 3); + + res[0] = 5; + REQUIRE(res[0] == 5); + REQUIRE(res[1] == 2); + REQUIRE(res[2] == 3); +} + +TEST_CASE("equal", "[n2]"){ + Result res; + + // There are no elements to compare + REQUIRE(res.equal() == false); + + //all (the one) elements are equal + res.push_back(1.2); + REQUIRE(res.equal() == true); + + res.push_back(1.2); + REQUIRE(res.equal() == true); + + res.push_back(1.3); + REQUIRE(res.equal() == false); +} diff --git a/slsDetectorSoftware/tests/test-multiSlsDetectorClient.cpp b/slsDetectorSoftware/tests/test-multiSlsDetectorClient.cpp index 2d1374a42..812d35c13 100644 --- a/slsDetectorSoftware/tests/test-multiSlsDetectorClient.cpp +++ b/slsDetectorSoftware/tests/test-multiSlsDetectorClient.cpp @@ -1,4 +1,5 @@ #include "catch.hpp" +#include "multiSlsDetector.h" #include "multiSlsDetectorClient.h" #include "sls_detector_defs.h" #include @@ -108,7 +109,7 @@ TEST_CASE("enablefoverwrite", "[.cmd]") { } } -//EIGER ONLY +// EIGER ONLY // TEST_CASE("activatecmd", "[.cmd]") { // { @@ -395,4 +396,40 @@ TEST_CASE("rx_checkversion", "[.cmd]") { std::ostringstream oss; multiSlsDetectorClient("rx_checkversion", GET, nullptr, oss); REQUIRE(oss.str() == "rx_checkversion compatible\n"); -} \ No newline at end of file +} + +TEST_CASE("exptime", "[.cmd]") { + { + std::ostringstream oss; + multiSlsDetectorClient("exptime 0.05", PUT, nullptr, oss); + REQUIRE(oss.str() == "exptime 0.050000000\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("exptime", GET, nullptr, oss); + REQUIRE(oss.str() == "exptime 0.050000000\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("exptime 1", PUT, nullptr, oss); + REQUIRE(oss.str() == "exptime 1.000000000\n"); + } +} + +// TEST_CASE("exptime2", "[.cmd]") { +// { +// std::ostringstream oss; +// multiSlsDetectorClient("exptime2 0.05", PUT, nullptr, oss); +// REQUIRE(oss.str() == "exptime2 0.05s\n"); +// } +// { +// std::ostringstream oss; +// multiSlsDetectorClient("exptime2", GET, nullptr, oss); +// REQUIRE(oss.str() == "exptime2 0.05s\n"); +// } +// { +// std::ostringstream oss; +// multiSlsDetectorClient("exptime2 1", PUT, nullptr, oss); +// REQUIRE(oss.str() == "exptime2 1s\n"); +// } +// } \ No newline at end of file diff --git a/slsSupportLib/CMakeLists.txt b/slsSupportLib/CMakeLists.txt index cf6b0a409..21ebdfa71 100755 --- a/slsSupportLib/CMakeLists.txt +++ b/slsSupportLib/CMakeLists.txt @@ -7,6 +7,7 @@ set(SOURCES src/ServerSocket.cpp src/ServerInterface2.cpp src/network_utils.cpp + src/ToString.cpp ) set(HEADERS @@ -29,6 +30,9 @@ set(PUBLICHEADERS include/ServerInterface2.h include/network_utils.h include/FixedCapacityContainer.h + include/ToString.h + include/TimeHelper.h + include/TypeTraits.h ) add_library(slsSupportLib SHARED diff --git a/slsSupportLib/include/CmdProxy.h b/slsSupportLib/include/CmdProxy.h index 278c2723f..1b05a79c3 100644 --- a/slsSupportLib/include/CmdProxy.h +++ b/slsSupportLib/include/CmdProxy.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -7,12 +8,48 @@ #include #include +#include "Result.h" +#include "TimeHelper.h" +#include "ToString.h" +#include "container_utils.h" #include "logger.h" #include "slsDetectorCommand.h" -#include "sls_detector_exceptions.h" #include "sls_detector_defs.h" +#include "sls_detector_exceptions.h" #include "string_utils.h" +#define TIME_COMMAND(GETFCN, SETFCN, HLPSTR) \ + std::ostringstream os; \ + os << cmd << ' '; \ + if (action == slsDetectorDefs::HELP_ACTION) \ + os << HLPSTR << '\n'; \ + else if (action == slsDetectorDefs::GET_ACTION) { \ + auto t = det->GETFCN({det_id}); \ + if (args.size() == 0) { \ + os << OutString(t) << '\n'; \ + } else if (args.size() == 1) { \ + os << OutString(t, args[0]) << '\n'; \ + } else { \ + WrongNumberOfParameters(2); \ + } \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + if (args.size() == 1) { \ + std::string time_str(args[0]); \ + std::string unit = RemoveUnit(time_str); \ + auto t = StringTo(time_str, unit); \ + det->SETFCN(t, {det_id}); \ + } else if (args.size() == 2) { \ + auto t = StringTo(args[0], args[1]); \ + det->SETFCN(t, {det_id}); \ + } else { \ + WrongNumberOfParameters(2); \ + } \ + os << ToString(args) << '\n'; \ + } else { \ + throw sls::RuntimeError("Unknown action"); \ + } \ + return os.str(); + namespace sls { template class CmdProxy { @@ -20,9 +57,8 @@ template class CmdProxy { explicit CmdProxy(T *detectorPtr) : det(detectorPtr) {} std::string Call(const std::string &command, - const std::vector &arguments, - int detector_id, - int action=-1) { + const std::vector &arguments, int detector_id, + int action = -1, std::ostream &os = std::cout) { cmd = command; args = arguments; det_id = detector_id; @@ -31,7 +67,7 @@ template class CmdProxy { auto it = functions.find(cmd); if (it != functions.end()) { - std::cout << ((*this).*(it->second))(action); + os << ((*this).*(it->second))(action); return {}; } else { return cmd; @@ -53,17 +89,47 @@ template class CmdProxy { size_t GetFunctionMapSize() const noexcept { return functions.size(); }; + std::vector GetAllCommands() { + auto commands = slsDetectorCommand(nullptr).getAllCommands(); + for (const auto &it : functions) + commands.emplace_back(it.first); + std::sort(begin(commands), end(commands)); + return commands; + } + std::vector GetProxyCommands() { + std::vector commands; + for (const auto &it : functions) + commands.emplace_back(it.first); + std::sort(begin(commands), end(commands)); + return commands; + } + private: T *det; std::string cmd; std::vector args; int det_id{-1}; + template std::string OutString(const V &value) { + if (value.equal()) + return ToString(value.front()); + return ToString(value); + } + template + std::string OutString(const V &value, const std::string &unit) { + if (value.equal()) + return ToString(value.front(), unit); + return ToString(value, unit); + } + using FunctionMap = std::map; using StringMap = std::map; // Initialize maps for translating name and function - FunctionMap functions{{"list", &CmdProxy::ListCommands}}; + FunctionMap functions{{"list", &CmdProxy::ListCommands}, + {"exptime2", &CmdProxy::Exptime}, + {"period2", &CmdProxy::Period}, + {"subexptime2", &CmdProxy::SubExptime}}; StringMap depreciated_functions{{"r_readfreq", "rx_readfreq"}, {"r_padding", "rx_padding"}, @@ -92,10 +158,10 @@ template class CmdProxy { } // Mapped functions - std::string ListCommands(int action) { - if (action==slsDetectorDefs::HELP_ACTION) - return "list - lists all available commands, list deprecated - list deprecated commands\n"; + if (action == slsDetectorDefs::HELP_ACTION) + return "list\n\tlists all available commands, list deprecated - " + "list deprecated commands\n"; if (args.size() == 0) { auto commands = slsDetectorCommand(nullptr).getAllCommands(); @@ -127,6 +193,22 @@ template class CmdProxy { return ""; } } + + std::string Period(int action) { + TIME_COMMAND( + getPeriod, setPeriod, + "[duration] [(optional unit) ns|us|ms|s]\n\tSet the period"); + } + std::string Exptime(int action) { + TIME_COMMAND( + getExptime, setExptime, + "[duration] [(optional unit) ns|us|ms|s]\n\tSet the exposure time"); + } + std::string SubExptime(int action) { + TIME_COMMAND(getSubExptime, setSubExptime, + "[duration] [(optional unit) ns|us|ms|s]\n\tSet the " + "exposure time of EIGER subframes"); + } }; } // namespace sls diff --git a/slsSupportLib/include/TimeHelper.h b/slsSupportLib/include/TimeHelper.h new file mode 100644 index 000000000..bf043b11c --- /dev/null +++ b/slsSupportLib/include/TimeHelper.h @@ -0,0 +1,19 @@ +#pragma once +#include + +#include "TypeTraits.h" +namespace sls { +namespace time { +using ns = std::chrono::nanoseconds; +using us = std::chrono::microseconds; +using ms = std::chrono::milliseconds; +using s = std::chrono::seconds; + +//Absolute value of std::chrono::duration +template +constexpr std::chrono::duration abs(std::chrono::duration d) { + return d >= d.zero() ? d : -d; +} + +} // namespace time +} // namespace sls \ No newline at end of file diff --git a/slsSupportLib/include/ToString.h b/slsSupportLib/include/ToString.h new file mode 100644 index 000000000..8acd31a29 --- /dev/null +++ b/slsSupportLib/include/ToString.h @@ -0,0 +1,140 @@ +#pragma once + +/** + * \file ToString.h + * + * Conversion from various types to std::string + * + */ + +#include "TimeHelper.h" +#include "TypeTraits.h" +#include "sls_detector_exceptions.h" +#include "string_utils.h" +#include +#include +#include +#include +#include + +namespace sls { + +std::string ToString(const std::vector &vec, + const char delimiter = ' '); + +/** Convert std::chrono::duration with specified output unit */ +template +typename std::enable_if::value, std::string>::type +ToString(T t, const std::string &unit) { + using std::chrono::duration; + using std::chrono::duration_cast; + std::ostringstream os; + if (unit == "ns") + os << duration_cast>(t).count() << unit; + else if (unit == "us") + os << duration_cast>(t).count() << unit; + else if (unit == "ms") + os << duration_cast>(t).count() << unit; + else if (unit == "s") + os << duration_cast>(t).count() << unit; + else + throw std::runtime_error("Unknown unit: " + unit); + return os.str(); +} + +/** Convert std::chrono::duration automatically selecting the unit */ +template +typename std::enable_if::value, std::string>::type +ToString(From t) { + auto tns = std::chrono::duration_cast(t); + if (time::abs(tns) < std::chrono::microseconds(1)) { + return ToString(tns, "ns"); + } else if (time::abs(tns) < std::chrono::milliseconds(1)) { + return ToString(tns, "us"); + } else if (time::abs(tns) < std::chrono::milliseconds(99)) { + return ToString(tns, "ms"); + } else { + return ToString(tns, "s"); + } +} + +/** Conversion of floating point values, removes trailing zeros*/ +template +typename std::enable_if::value, std::string>::type +ToString(const T &value) { + auto s = std::to_string(value); + s.erase(s.find_last_not_of('0') + 1u, std::string::npos); + s.erase(s.find_last_not_of('.') + 1u, std::string::npos); + return s; +} + +/** Conversion of integer types, do not remove trailing zeros */ +template +typename std::enable_if::value, std::string>::type +ToString(const T &value) { + return std::to_string(value); +} + +/** For a container loop over all elements and call ToString */ +template +typename std::enable_if::value, std::string>::type +ToString(const T &container) { + std::ostringstream os; + os << '['; + if (!container.empty()) { + auto it = container.cbegin(); + os << ToString(*it++); + while (it != container.cend()) + os << ", " << ToString(*it++); + } + os << ']'; + return os.str(); +} + +/** Container and specified unit, call ToString(value, unit) */ +template +typename std::enable_if::value, std::string>::type +ToString(const T &container, const std::string &unit) { + std::ostringstream os; + os << '['; + if (!container.empty()) { + auto it = container.cbegin(); + os << ToString(*it++, unit); + while (it != container.cend()) + os << ", " << ToString(*it++, unit); + } + os << ']'; + return os.str(); +} + +template +T StringTo(const std::string &t, const std::string &unit) { + double tval{0}; + try { + tval = std::stod(t); + } catch (const std::invalid_argument &e) { + throw sls::RuntimeError("Could not convert string to time"); + } + + using std::chrono::duration; + using std::chrono::duration_cast; + if (unit == "ns") { + return duration_cast(duration(tval)); + } else if (unit == "us") { + return duration_cast(duration(tval)); + } else if (unit == "ms") { + return duration_cast(duration(tval)); + } else if (unit == "s" || unit.empty()) { + return duration_cast(std::chrono::duration(tval)); + } else { + throw sls::RuntimeError( + "Invalid unit in conversion from string to std::chrono::duration"); + } +} + +template T StringTo(std::string t) { + auto unit = RemoveUnit(t); + return StringTo(t, unit); +} + +} // namespace sls diff --git a/slsSupportLib/include/TypeTraits.h b/slsSupportLib/include/TypeTraits.h new file mode 100644 index 000000000..2a5409e78 --- /dev/null +++ b/slsSupportLib/include/TypeTraits.h @@ -0,0 +1,48 @@ +#pragma once +#include + +namespace sls { + +/** + * Type trait to check if atemplate parameter is a std::chrono::duration + */ + +template +struct is_duration : std::false_type {}; + +template struct is_duration_helper {}; + +template +struct is_duration().min()), + decltype(std::declval().max()), + decltype(std::declval().zero())>, + void>::type> : public std::true_type {}; + +/** + * Type trait to evaluate if template parameter is + * complying with a standard container + */ +template +struct is_container : std::false_type {}; + +template struct is_container_helper {}; + +template +struct is_container< + T, typename std::conditional< + false, + is_container_helper().size()), + decltype(std::declval().begin()), + decltype(std::declval().end()), + decltype(std::declval().cbegin()), + decltype(std::declval().cend()), + decltype(std::declval().empty())>, + void>::type> : public std::true_type {}; + +} // namespace sls \ No newline at end of file diff --git a/slsSupportLib/include/container_utils.h b/slsSupportLib/include/container_utils.h index 0f325dd36..b364adb2c 100755 --- a/slsSupportLib/include/container_utils.h +++ b/slsSupportLib/include/container_utils.h @@ -9,6 +9,8 @@ #include #include +#include "TypeTraits.h" + namespace sls { // C++11 make_unique implementation for exception safety @@ -26,14 +28,21 @@ make_unique(std::size_t n) { return std::unique_ptr(new RT[n]); } -template bool allEqual(const std::vector &container) { - if (container.empty()) - return false; - const auto &first = container[0]; - return std::all_of(container.cbegin(), container.cend(), - [first](const T &element) { return element == first; }); +/** Compare elements in a Container to see if they are all equal */ +template bool allEqual(const Container &c) { + if (!c.empty() && + std::all_of(begin(c), end(c), + [c](const typename Container::value_type &element) { + return element == c.front(); + })) + return true; + return false; } +/** + * Compare elements but with specified tolerance, useful + * for floating point values. + */ template typename std::enable_if::value, bool>::type allEqualWithTol(const std::vector &container, const T tol) { @@ -111,15 +120,31 @@ minusOneIfDifferent(const std::vector> &container) { template std::array -minusOneIfDifferent(const std::vector> &container) { +minusOneIfDifferent(const std::vector> &container) { if (allEqual(container)) return container.front(); - - std::array arr; + + std::array arr; arr.fill(static_cast(-1)); return arr; } +/** + * Return the first value if all values are equal + * otherwise return default_value. If no default + * value is supplied it will be default constructed + */ +template +typename Container::value_type +Squash(const Container &c, typename Container::value_type default_value = {}) { + if (!c.empty() && + std::all_of(begin(c), end(c), + [c](const typename Container::value_type &element) { + return element == c.front(); + })) + return c.front(); + return default_value; +} } // namespace sls diff --git a/slsSupportLib/include/sls_detector_exceptions.h b/slsSupportLib/include/sls_detector_exceptions.h index 52c2adc01..c018ac716 100755 --- a/slsSupportLib/include/sls_detector_exceptions.h +++ b/slsSupportLib/include/sls_detector_exceptions.h @@ -1,14 +1,6 @@ #pragma once -/************************************************ - * @file sls_detector_exceptions.h - * @short exceptions defined - ***********************************************/ -/** - *@short exceptions defined - */ #include "logger.h" - #include #include diff --git a/slsSupportLib/include/string_utils.h b/slsSupportLib/include/string_utils.h index 293af39d4..2cfb90768 100755 --- a/slsSupportLib/include/string_utils.h +++ b/slsSupportLib/include/string_utils.h @@ -1,30 +1,30 @@ #pragma once -#include -#include #include #include +#include +#include namespace sls { -/* Implementation of a safe string copy function for setting fields in -for example the multi sls detector. It tries to copy the size of the -destination from the source, stopping on '\0'. +/* Implementation of a safe string copy function for setting fields in +for example the multi sls detector. It tries to copy the size of the +destination from the source, stopping on '\0'. -Warning this will truncate the source string and should be used with care. +Warning this will truncate the source string and should be used with care. Still this is better than strcpy and a buffer overflow... */ template void strcpy_safe(char (&destination)[array_size], const char *source) { assert(array_size > strlen(source)); - strncpy(destination, source, array_size-1); + strncpy(destination, source, array_size - 1); destination[array_size - 1] = '\0'; } template -void strcpy_safe(char (&destination)[array_size], const std::string& source) { +void strcpy_safe(char (&destination)[array_size], const std::string &source) { assert(array_size > source.size()); - strncpy(destination, source.c_str(), array_size-1); + strncpy(destination, source.c_str(), array_size - 1); destination[array_size - 1] = '\0'; } @@ -32,8 +32,7 @@ void strcpy_safe(char (&destination)[array_size], const std::string& source) { Removes all occurrences of the specified char from a c string Templated on array size to ensure no access after buffer limits. */ -template -void removeChar(char (&str)[array_size], char ch) { +template void removeChar(char (&str)[array_size], char ch) { int count = 0; for (int i = 0; str[i]; i++) { if (str[i] != ch) @@ -44,7 +43,7 @@ void removeChar(char (&str)[array_size], char ch) { str[count] = '\0'; } -/* +/* Split a string using the specified delimeter and return a vector of strings. TODO! Look into switching to absl or a string_view based implementation. Current implementation should not be used in a performance critical place. @@ -62,9 +61,10 @@ Concatenate strings using + if the strings are different std::string concatenateIfDifferent(const std::vector &container); /* -Concatenate vector of things with str method using + if the strings are different +Concatenate vector of things with str method using + if the strings are +different */ -template +template std::string concatenateIfDifferent(const std::vector &container); /* @@ -72,4 +72,7 @@ Convert an ip address string to a string in hex format. (removing dots) */ std::string stringIpToHex(const std::string &ip); +// remove the end of the string starting with the first aplhabetic character +// return the end +std::string RemoveUnit(std::string &str); }; // namespace sls diff --git a/slsSupportLib/src/ToString.cpp b/slsSupportLib/src/ToString.cpp new file mode 100644 index 000000000..541ce2829 --- /dev/null +++ b/slsSupportLib/src/ToString.cpp @@ -0,0 +1,18 @@ +#include "ToString.h" + +namespace sls { + +std::string ToString(const std::vector &vec, + const char delimiter) { + std::ostringstream os; + if (vec.empty()) + return os.str(); + auto it = vec.cbegin(); + os << *it++; + if (vec.size() > 1) { + while (it != vec.cend()) + os << delimiter << *it++; + } + return os.str(); +} +} // namespace sls \ No newline at end of file diff --git a/slsSupportLib/src/string_utils.cpp b/slsSupportLib/src/string_utils.cpp index 2ddfe6785..290020ca6 100755 --- a/slsSupportLib/src/string_utils.cpp +++ b/slsSupportLib/src/string_utils.cpp @@ -47,6 +47,18 @@ std::string concatenateIfDifferent(const std::vector &container) { } } +std::string RemoveUnit(std::string &str) { + auto it = str.begin(); + while (it != str.end()) { + if (std::isalpha(*it)) + break; + ++it; + } + auto pos = it - str.begin(); + auto unit = str.substr(pos); + str.erase(it, end(str)); + return unit; +} template std::string concatenateIfDifferent(const std::vector &); template std::string concatenateIfDifferent(const std::vector &); diff --git a/slsSupportLib/tests/CMakeLists.txt b/slsSupportLib/tests/CMakeLists.txt index c40c80581..4490ec18b 100755 --- a/slsSupportLib/tests/CMakeLists.txt +++ b/slsSupportLib/tests/CMakeLists.txt @@ -7,4 +7,5 @@ target_sources(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test-sls_detector_defs.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-Sockets.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-FixedCapacityContainer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test-ToString.cpp ) \ No newline at end of file diff --git a/slsSupportLib/tests/test-ToString.cpp b/slsSupportLib/tests/test-ToString.cpp new file mode 100644 index 000000000..f080003b0 --- /dev/null +++ b/slsSupportLib/tests/test-ToString.cpp @@ -0,0 +1,85 @@ +#include "TimeHelper.h" +#include "ToString.h" +#include "catch.hpp" +#include +using namespace sls; + + +TEST_CASE("Integer conversions", "[support][now]"){ + REQUIRE(ToString(0) == "0"); + REQUIRE(ToString(1) == "1"); + REQUIRE(ToString(-1) == "-1"); + REQUIRE(ToString(100) == "100"); + REQUIRE(ToString(589633100) == "589633100"); + +} + +TEST_CASE("floating point conversions", "[support][now]"){ + REQUIRE(ToString(0.) == "0"); + REQUIRE(ToString(1.) == "1"); + REQUIRE(ToString(-1.) == "-1"); + REQUIRE(ToString(100.) == "100"); + REQUIRE(ToString(589633100.) == "589633100"); + REQUIRE(ToString(2.35) == "2.35"); + REQUIRE(ToString(2.3500) == "2.35"); + REQUIRE(ToString(2.35010) == "2.3501"); + REQUIRE(ToString(5000) == "5000"); + REQUIRE(ToString(5E15) == "5000000000000000"); + +} + +TEST_CASE("conversion from duration to string", "[support][now]") { + REQUIRE(ToString(time::ns(150)) == "150ns"); + REQUIRE(ToString(time::ms(783)) == "0.783s"); + REQUIRE(ToString(time::ms(783), "ms") == "783ms"); + REQUIRE(ToString(time::us(0)) == "0ns"); // Defaults to the lowest unit + REQUIRE(ToString(time::us(0), "s") == "0s"); + REQUIRE(ToString(time::s(-1)) == "-1s"); + REQUIRE(ToString(time::us(-100)) == "-100us"); +} + +TEST_CASE("string to std::chrono::duration", "[support][now]") { + REQUIRE(StringTo("150", "ns") == time::ns(150)); + REQUIRE(StringTo("150ns") == time::ns(150)); + REQUIRE(StringTo("150s") == time::s(150)); + REQUIRE(StringTo("3 s") == time::s(3)); + + REQUIRE_THROWS(StringTo("5xs")); + REQUIRE_THROWS(StringTo("asvn")); +} + +TEST_CASE("Convert vector of time", "[support][now]"){ + std::vector vec{time::ns(150), time::us(10), time::ns(600)}; + REQUIRE(ToString(vec) == "[150ns, 10us, 600ns]"); + REQUIRE(ToString(vec, "ns") == "[150ns, 10000ns, 600ns]"); +} + +TEST_CASE("Vector of int", "[support][now]"){ + std::vector vec; + REQUIRE(ToString(vec) == "[]"); + + vec.push_back(1); + REQUIRE(ToString(vec) == "[1]"); + + vec.push_back(172); + REQUIRE(ToString(vec) == "[1, 172]"); + + vec.push_back(5000); + REQUIRE(ToString(vec) == "[1, 172, 5000]"); + +} + +TEST_CASE("Vector of double", "[support][now]"){ + std::vector vec; + REQUIRE(ToString(vec) == "[]"); + + vec.push_back(1.3); + REQUIRE(ToString(vec) == "[1.3]"); + + vec.push_back(5669.325); + REQUIRE(ToString(vec) == "[1.3, 5669.325]"); + + vec.push_back(-5669.325005); + REQUIRE(ToString(vec) == "[1.3, 5669.325, -5669.325005]"); + +} \ No newline at end of file