* 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
This commit is contained in:
Dhanya Thattil 2019-08-07 11:21:07 +02:00 committed by GitHub
parent 98ddf154b2
commit 4ceee97c03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 2317 additions and 571 deletions

1
.gitignore vendored
View File

@ -9,7 +9,6 @@ bin/
*.o
.*
build
docs/
RELEASE.txt
Testing/

View File

@ -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)

11
cmake/FindSphinx.cmake Normal file
View File

@ -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)

67
docs/CMakeLists.txt Normal file
View File

@ -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)

View File

@ -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

62
docs/conf.py.in Normal file
View File

@ -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']

6
docs/src/ToString.rst Normal file
View File

@ -0,0 +1,6 @@
ToString
==============
String conversion
.. doxygenfile:: ToString.h

16
docs/src/commandline.rst Normal file
View File

@ -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

View File

@ -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

53
docs/src/dependencies.rst Normal file
View File

@ -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)

16
docs/src/detector.rst Normal file
View File

@ -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<T>)
.. doxygenclass:: sls::Detector
:members:
:undoc-members:

56
docs/src/gendoc.cpp Normal file
View File

@ -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 <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#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<sls::Detector> 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";
}
}

50
docs/src/index.rst Normal file
View File

@ -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`

View File

@ -0,0 +1,5 @@
Installation
==============================================
get the source etc.

9
docs/src/pydetector.rst Normal file
View File

@ -0,0 +1,9 @@
Detector
=====================================================
.. py:currentmodule:: sls_detector
.. autoclass:: ExperimentalDetector
:members:
:undoc-members:
:show-inheritance:

12
docs/src/pyenums.rst Normal file
View File

@ -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:

View File

@ -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()
-----------------------

6
docs/src/receiver.rst Normal file
View File

@ -0,0 +1,6 @@
Receiver
==============================================
.. doxygenclass:: slsReceiver
:members:
.. :undoc-members:

4
docs/src/result.rst Normal file
View File

@ -0,0 +1,4 @@
Result
==============================================
.. doxygenfile:: Result.h

7
docs/src/type_traits.rst Normal file
View File

@ -0,0 +1,7 @@
TypeTraits
==============
Template meta functions in the same spirit as type_traits
from the standard library.
.. doxygenfile:: TypeTraits.h

View File

@ -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()

View File

@ -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 <iomanip>
#include <iostream>
#include <vector>
#include <arpa/inet.h>
#include <netdb.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <algorithm>
#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<double>(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';
// }
}

View File

@ -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

View File

@ -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(),

View File

@ -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

View File

@ -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))

View File

@ -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<std::string> Detector::getReadoutFlags() {
std::vector<std::string> DetectorPythonInterface::getReadoutFlags() {
std::vector<std::string> flags;
auto r = det.setReadOutFlags();
if (r & slsDetectorDefs::readOutFlags::STORE_IN_RAM)
@ -953,7 +953,7 @@ std::vector<std::string> 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<double> Detector::getRateCorrection() {
std::vector<double> DetectorPythonInterface::getRateCorrection() {
std::vector<double> rate_corr;
for (int i = 0; i < det.getNumberOfDetectors(); ++i) {
rate_corr.push_back(det.getRateCorrection(i));
@ -996,7 +996,7 @@ std::vector<double> 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);

19
python/src/enums.cpp Normal file
View File

@ -0,0 +1,19 @@
#include <pybind11/chrono.h>
#include <pybind11/operators.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "sls_detector_defs.h"
namespace py = pybind11;
void init_enums(py::module &m) {
py::class_<slsDetectorDefs> Defs(m, "slsDetectorDefs");
py::enum_<slsDetectorDefs::runStatus>(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();
}

View File

@ -0,0 +1,70 @@
#include <pybind11/chrono.h>
#include <pybind11/operators.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#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_<Detector> multiDetectorApi(m, "multiDetectorApi");
multiDetectorApi
.def(py::init<int>())
// 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{});
}

View File

@ -1,12 +1,31 @@
#include <pybind11/chrono.h>
#include <pybind11/operators.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "Detector.h"
#include "DetectorPythonInterface.h"
#include "Result.h"
#include "mythenFileIO.h"
#include <chrono>
#include <vector>
#include "typecaster.h"
// // Add type_typecaster to pybind for our wrapper type
// namespace pybind11 {
// namespace detail {
// template <typename Type, typename Alloc>
// struct type_caster<sls::Result<Type, Alloc>>
// : list_caster<sls::Result<Type, Alloc>, Type> {};
// } // namespace detail
// } // namespace pybind11
using ds = std::chrono::duration<double>;
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_<Detector> DetectorApi(m, "DetectorApi", R"pbdoc(
init_enums(m);
init_experimental(m);
py::class_<DetectorPythonInterface> 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<int>())
.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_<multiSlsDetector> multiDetectorApi(m, "multiDetectorApi");
multiDetectorApi.def(py::init<int>())
.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");

11
python/src/typecaster.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include <pybind11/pybind11.h>
#include "Result.h"
// Add type_typecaster to pybind for our wrapper type
namespace pybind11 {
namespace detail {
template <typename Type, typename Alloc>
struct type_caster<sls::Result<Type, Alloc>>
: list_caster<sls::Result<Type, Alloc>, Type> {};
} // namespace detail
} // namespace pybind11

21
sample/CMakeLists.txt Normal file
View File

@ -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
)

67
sample/api.cpp Normal file
View File

@ -0,0 +1,67 @@
#include "Detector.h"
#include <chrono>
#include <iostream>
std::ostream &operator<<(std::ostream &os, const std::chrono::nanoseconds &t) {
os << t.count() << "ns";
return os;
}
template <typename T, typename _ = void>
struct is_container : std::false_type {};
template <typename... Ts> struct is_container_helper {};
template <typename T>
struct is_container<
T, typename std::conditional<
false,
is_container_helper<typename T::value_type, typename T::size_type,
typename T::iterator, typename T::const_iterator,
decltype(std::declval<T>().size()),
decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end()),
decltype(std::declval<T>().cbegin()),
decltype(std::declval<T>().cend()),
decltype(std::declval<T>().empty())>,
void>::type> : public std::true_type {};
template <typename Container>
auto operator<<(std::ostream &os, const Container &con) ->
typename std::enable_if<is_container<Container>::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: " <<t1 << '\n';
std::cout << "Period: " << d.getPeriod() << '\n';
std::cout << "Period: " << d.getPeriod().squash() << '\n';
// std::cout << "fname: " << d.getFname() << "\n";
// std::cout << "fwrite: " << std::boolalpha << d.getFwrite() << '\n';
// d.freeSharedMemory();
}

55
sample/useResult.cpp Normal file
View File

@ -0,0 +1,55 @@
#include <iostream>
#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<T>\n";
// Result exposes the underlying constructors of std::vector
Result<int> res{1, 2, 3, 4, 5};
std::cout << "res: " << res << '\n';
Result<double> 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<T> behaves as a
// vector.
std::vector<int> vec(5, 5);
std::cout << "vec: " << ToString(vec) << "\n";
Result<int> res3 = vec;
std::cout << "res3: " << res3 << '\n';
std::vector<int> 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<T> to T
int r = res3;
std::cout << "r: " << r << '\n';
std::cout << "static_cast<int>: " << static_cast<int>(res3) << '\n';
std::cout << "static_cast<double>: " << static_cast<double>(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';
//
}

View File

@ -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

View File

@ -0,0 +1,127 @@
#pragma once
#include "Result.h"
#include "sls_detector_defs.h"
#include <chrono>
#include <memory>
#include <vector>
class multiSlsDetector;
namespace sls {
using ns = std::chrono::nanoseconds;
using Positions = const std::vector<int> &;
using defs = slsDetectorDefs;
/**
* \class Detector
*/
class Detector {
std::unique_ptr<multiSlsDetector> 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<defs::runStatus> 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<std::string> getHostname(Positions pos = {}) const;
// void setHostname(Positions pos = {});
Result<uint64_t> 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<uint32_t> 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<std::string> getFileName() const;
/**
* Sets the receiver file name prefix
* @param fname file name prefix
*/
void setFileName(const std::string &fname);
Result<std::string> getFilePath() const;
void setFilePath(const std::string &fname);
Result<bool> getFileWrite(Positions pos = {}) const;
void setFileWrite(bool value, Positions pos = {});
Result<bool> getFileOverWrite(Positions pos = {}) const;
void setFileOverWrite(bool value, Positions pos = {});
// Time
Result<ns> getExptime(Positions pos = {}) const;
void setExptime(ns t, Positions pos = {});
Result<ns> getSubExptime(Positions pos = {}) const;
void setSubExptime(ns t, Positions pos = {});
Result<ns> getPeriod(Positions pos = {}) const;
void setPeriod(ns t, Positions pos = {});
};
} // namespace sls

View File

@ -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 <algorithm>
#include <iostream>
#include <vector>
#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 T, class Allocator = std::allocator<T>> class Result {
/** wrapped vector */
std::vector<T, Allocator> vec;
public:
Result() = default;
Result(std::initializer_list<T> list) : vec(list){};
/**
* Forward arguments to the constructor of std::vector
* @tparam Args template paramter pack to forward
*/
template <typename... Args>
Result(Args &&... args) : vec(std::forward<Args>(args)...) {}
using value_type = typename std::vector<T>::value_type;
using iterator = typename std::vector<T>::iterator;
using const_iterator = typename std::vector<T>::const_iterator;
using size_type = typename std::vector<T>::size_type;
using reference = typename std::vector<T>::reference;
using const_reference = typename std::vector<T>::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 <typename V>
auto push_back(V value) -> decltype(vec.push_back(value)) {
vec.push_back(std::forward<V>(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<T> to std::vector<T> */
operator std::vector<T>() { return vec; }
/** Convert Result<T> 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 <typename T>
std::ostream &operator<<(std::ostream &os, const Result<T> &res) {
return os << ToString(res);
}
} // namespace sls

View File

@ -4,7 +4,6 @@
#include "logger.h"
#include "sls_detector_defs.h"
class slsDetector;
class ZmqSocket;
class detectorData;
@ -20,6 +19,9 @@ class detectorData;
#define SHORT_STRING_LENGTH 50
#define DATE_LENGTH 30
#include <future>
#include <numeric>
/**
* @short structure allocated in shared memory to store detector settings
* for IPC and cache
@ -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 <class CT> struct NonDeduced { using type = CT; };
template <typename RT, typename... CT>
std::vector<RT> Parallel(RT (slsDetector::*somefunc)(CT...),
std::vector<int> positions,
typename NonDeduced<CT>::type... Args) {
if (positions.empty() || (positions.size() == 1 && positions[0] == -1 )) {
positions.resize(detectors.size());
std::iota(begin(positions), end(positions), 0);
}
std::vector<std::future<RT>> 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<RT> result;
result.reserve(positions.size());
for (auto &i : futures) {
result.push_back(i.get());
}
return result;
}
template <typename RT, typename... CT>
std::vector<RT> Parallel(RT (slsDetector::*somefunc)(CT...) const,
std::vector<int> positions,
typename NonDeduced<CT>::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<std::future<RT>> 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<RT> result;
result.reserve(positions.size());
for (auto &i : futures) {
result.push_back(i.get());
}
return result;
}
template <typename... CT>
void Parallel(void (slsDetector::*somefunc)(CT...),
std::vector<int> positions,
typename NonDeduced<CT>::type... Args) {
if (positions.empty() || (positions.size() == 1 && positions[0] == -1 )) {
positions.resize(detectors.size());
std::iota(begin(positions), end(positions), 0);
}
std::vector<std::future<void>> 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 <typename... CT>
void Parallel(void (slsDetector::*somefunc)(CT...) const,
std::vector<int> positions,
typename NonDeduced<CT>::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<std::future<void>> 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 <class CT>
struct NonDeduced { using type = CT; };
template <typename RT, typename... CT>
std::vector<RT> serialCall(RT (slsDetector::*somefunc)(CT...),
typename NonDeduced<CT>::type... Args);
@ -149,13 +243,13 @@ class multiSlsDetector : public virtual slsDetectorDefs {
std::vector<RT> parallelCall(RT (slsDetector::*somefunc)(CT...) const,
typename NonDeduced<CT>::type... Args) const;
template <typename... CT>
void parallelCall(void (slsDetector::*somefunc)(CT...),
typename NonDeduced<CT>::type... Args);
template <typename... CT>
void parallelCall(void (slsDetector::*somefunc)(CT...), typename NonDeduced<CT>::type... Args);
template <typename... CT>
void parallelCall(void (slsDetector::*somefunc)(CT...) const, typename NonDeduced<CT>::type... Args) const;
void parallelCall(void (slsDetector::*somefunc)(CT...) const,
typename NonDeduced<CT>::type... Args) const;
/**
* Decodes which detector and the corresponding channel numbers for it
@ -210,6 +304,8 @@ class multiSlsDetector : public virtual slsDetectorDefs {
*/
int64_t getId(idMode mode, int detPos = -1);
int getMultiId()const{return multiId;}
/**
* Get Client Software version
* @returns client software version
@ -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
@ -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
*/
@ -1091,7 +1200,8 @@ class multiSlsDetector : public virtual slsDetectorDefs {
/**
* Returns the client zmq port
* If detPos is -1(multi module), port returns client streaming port of first module
* 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
*/
@ -1109,7 +1219,8 @@ class multiSlsDetector : public virtual slsDetectorDefs {
/**
* Returns the receiver zmq port
* If detPos is -1(multi module), port returns receiver streaming port of first module
* 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
*/
@ -1127,7 +1238,8 @@ class multiSlsDetector : public virtual slsDetectorDefs {
/**
* Returns the client zmq ip
* If detPos is -1(multi module), ip returns concatenation of all client streaming 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
*/
@ -1145,7 +1257,8 @@ class multiSlsDetector : public virtual slsDetectorDefs {
/**
* Returns the receiver zmq ip
* If detPos is -1(multi module), ip returns concatenation of all receiver streaming 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
*/
@ -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
@ -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,
@ -1942,7 +2067,8 @@ class multiSlsDetector : public virtual slsDetectorDefs {
/**
* 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,7 +2082,8 @@ 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)
@ -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,8 +2261,6 @@ 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
@ -2205,7 +2332,6 @@ class multiSlsDetector : public virtual slsDetectorDefs {
*/
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};
};

View File

@ -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<multiSlsDetector> proxy(detPtr);
int multi_id = 0;
if (detPtr != nullptr)
multi_id = detPtr->getMultiId();
sls::Detector d(multi_id);
sls::CmdProxy<sls::Detector> proxy(&d);
// sls::CmdProxy<multiSlsDetector> proxy(detPtr);
auto cmd = proxy.Call(parser.command(), parser.arguments(),
parser.detector_id(), action_);
if (cmd.empty()) {

View File

@ -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

View File

@ -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<multiSlsDetector>(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<defs::runStatus> 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<std::string> 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<uint32_t> Detector::getRegister(uint32_t addr, Positions pos) {
return pimpl->Parallel(&slsDetector::readRegister, pos, addr);
}
Result<ns> Detector::getExptime(Positions pos) const {
auto r = pimpl->Parallel(&slsDetector::setTimer, pos,
defs::ACQUISITION_TIME, -1);
return Result<ns>(begin(r), end(r));
}
Result<uint64_t> 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<ns> Detector::getSubExptime(Positions pos) const {
auto r = pimpl->Parallel(&slsDetector::setTimer, pos,
defs::SUBFRAME_ACQUISITION_TIME, -1);
return Result<ns>(begin(r), end(r));
}
void Detector::setSubExptime(ns t, Positions pos) {
pimpl->Parallel(&slsDetector::setTimer, pos,
defs::SUBFRAME_ACQUISITION_TIME, t.count());
}
Result<ns> Detector::getPeriod(Positions pos) const {
auto r =
pimpl->Parallel(&slsDetector::setTimer, pos, defs::FRAME_PERIOD, -1);
return Result<ns>(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<std::string> Detector::getFileName() const {
return pimpl->Parallel(&slsDetector::setFileName, Positions{}, "");
}
void Detector::setFilePath(const std::string &fpath) {
pimpl->Parallel(&slsDetector::setFilePath, Positions{}, fpath);
}
Result<std::string> Detector::getFilePath() const {
return pimpl->Parallel(&slsDetector::getFilePath, Positions{});
}
void Detector::setFileWrite(bool value, Positions pos) {
pimpl->Parallel(&slsDetector::setFileWrite, Positions{}, value);
}
Result<bool> 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<bool> Detector::getFileOverWrite(Positions pos) const {
return pimpl->Parallel(&slsDetector::getFileOverWrite, Positions{});
}
} // namespace sls

View File

@ -4457,3 +4457,9 @@ std::vector<char> multiSlsDetector::readPofFile(const std::string &fname) {
FILE_LOG(logINFO) << "Read file into memory";
return buffer;
}

View File

@ -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);
}

View File

@ -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
)

View File

@ -0,0 +1,75 @@
#include "Result.h"
#include "catch.hpp"
#include <type_traits>
using sls::Result;
TEST_CASE("Default construction", "[detector][n2]") {
Result<int> res;
REQUIRE(res.size() == 0);
REQUIRE(res.empty() == true);
}
TEST_CASE("Initializer list construction", "[n2]") {
Result<int> 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<int> 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<double> res;
REQUIRE(res.squash() == 0.);
}
TEST_CASE("Squash gives either value or default constructed value", "[n2]") {
Result<int> 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<int> 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<float> 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);
}

View File

@ -1,4 +1,5 @@
#include "catch.hpp"
#include "multiSlsDetector.h"
#include "multiSlsDetectorClient.h"
#include "sls_detector_defs.h"
#include <sstream>
@ -396,3 +397,39 @@ TEST_CASE("rx_checkversion", "[.cmd]") {
multiSlsDetectorClient("rx_checkversion", GET, nullptr, oss);
REQUIRE(oss.str() == "rx_checkversion compatible\n");
}
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");
// }
// }

View File

@ -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

View File

@ -1,5 +1,6 @@
#pragma once
#include <chrono>
#include <iomanip>
#include <iostream>
#include <map>
@ -7,12 +8,48 @@
#include <string>
#include <vector>
#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::ns>(time_str, unit); \
det->SETFCN(t, {det_id}); \
} else if (args.size() == 2) { \
auto t = StringTo<time::ns>(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 <typename T> class CmdProxy {
@ -20,9 +57,8 @@ template <typename T> class CmdProxy {
explicit CmdProxy(T *detectorPtr) : det(detectorPtr) {}
std::string Call(const std::string &command,
const std::vector<std::string> &arguments,
int detector_id,
int action=-1) {
const std::vector<std::string> &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 <typename T> 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 <typename T> class CmdProxy {
size_t GetFunctionMapSize() const noexcept { return functions.size(); };
std::vector<std::string> 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<std::string> GetProxyCommands() {
std::vector<std::string> 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<std::string> args;
int det_id{-1};
template <typename V> std::string OutString(const V &value) {
if (value.equal())
return ToString(value.front());
return ToString(value);
}
template <typename V>
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<std::string, std::string (CmdProxy::*)(int)>;
using StringMap = std::map<std::string, std::string>;
// 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 <typename T> 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";
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 <typename T> 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

View File

@ -0,0 +1,19 @@
#pragma once
#include <chrono>
#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 <class Rep, class Period>
constexpr std::chrono::duration<Rep, Period> abs(std::chrono::duration<Rep, Period> d) {
return d >= d.zero() ? d : -d;
}
} // namespace time
} // namespace sls

View File

@ -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 <chrono>
#include <iomanip>
#include <sstream>
#include <type_traits>
#include <vector>
namespace sls {
std::string ToString(const std::vector<std::string> &vec,
const char delimiter = ' ');
/** Convert std::chrono::duration with specified output unit */
template <typename T, typename Rep = double>
typename std::enable_if<is_duration<T>::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<duration<Rep, std::nano>>(t).count() << unit;
else if (unit == "us")
os << duration_cast<duration<Rep, std::micro>>(t).count() << unit;
else if (unit == "ms")
os << duration_cast<duration<Rep, std::milli>>(t).count() << unit;
else if (unit == "s")
os << duration_cast<duration<Rep>>(t).count() << unit;
else
throw std::runtime_error("Unknown unit: " + unit);
return os.str();
}
/** Convert std::chrono::duration automatically selecting the unit */
template <typename From>
typename std::enable_if<is_duration<From>::value, std::string>::type
ToString(From t) {
auto tns = std::chrono::duration_cast<std::chrono::nanoseconds>(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 T>
typename std::enable_if<std::is_floating_point<T>::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 T>
typename std::enable_if<std::is_integral<T>::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 T>
typename std::enable_if<is_container<T>::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 T>
typename std::enable_if<is_container<T>::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 <typename T>
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<T>(duration<double, std::nano>(tval));
} else if (unit == "us") {
return duration_cast<T>(duration<double, std::micro>(tval));
} else if (unit == "ms") {
return duration_cast<T>(duration<double, std::milli>(tval));
} else if (unit == "s" || unit.empty()) {
return duration_cast<T>(std::chrono::duration<double>(tval));
} else {
throw sls::RuntimeError(
"Invalid unit in conversion from string to std::chrono::duration");
}
}
template <typename T> T StringTo(std::string t) {
auto unit = RemoveUnit(t);
return StringTo<T>(t, unit);
}
} // namespace sls

View File

@ -0,0 +1,48 @@
#pragma once
#include <type_traits>
namespace sls {
/**
* Type trait to check if atemplate parameter is a std::chrono::duration
*/
template <typename T, typename _ = void>
struct is_duration : std::false_type {};
template <typename... Ts> struct is_duration_helper {};
template <typename T>
struct is_duration<T,
typename std::conditional<
false,
is_duration_helper<typename T::rep, typename T::period,
decltype(std::declval<T>().min()),
decltype(std::declval<T>().max()),
decltype(std::declval<T>().zero())>,
void>::type> : public std::true_type {};
/**
* Type trait to evaluate if template parameter is
* complying with a standard container
*/
template <typename T, typename _ = void>
struct is_container : std::false_type {};
template <typename... Ts> struct is_container_helper {};
template <typename T>
struct is_container<
T, typename std::conditional<
false,
is_container_helper<typename T::value_type, typename T::size_type,
typename T::iterator, typename T::const_iterator,
decltype(std::declval<T>().size()),
decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end()),
decltype(std::declval<T>().cbegin()),
decltype(std::declval<T>().cend()),
decltype(std::declval<T>().empty())>,
void>::type> : public std::true_type {};
} // namespace sls

View File

@ -9,6 +9,8 @@
#include <type_traits>
#include <vector>
#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<T>(new RT[n]);
}
template <typename T> bool allEqual(const std::vector<T> &container) {
if (container.empty())
/** Compare elements in a Container to see if they are all equal */
template <typename Container> 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;
const auto &first = container[0];
return std::all_of(container.cbegin(), container.cend(),
[first](const T &element) { return element == first; });
}
/**
* Compare elements but with specified tolerance, useful
* for floating point values.
*/
template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type
allEqualWithTol(const std::vector<T> &container, const T tol) {
@ -120,6 +129,22 @@ minusOneIfDifferent(const std::vector<std::array<T,size>> &container) {
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>
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

View File

@ -1,14 +1,6 @@
#pragma once
/************************************************
* @file sls_detector_exceptions.h
* @short exceptions defined
***********************************************/
/**
*@short exceptions defined
*/
#include "logger.h"
#include <iostream>
#include <stdexcept>

View File

@ -1,9 +1,9 @@
#pragma once
#include <string>
#include <vector>
#include <cassert>
#include <cstring>
#include <string>
#include <vector>
namespace sls {
@ -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 <size_t array_size>
void removeChar(char (&str)[array_size], char ch) {
template <size_t array_size> void removeChar(char (&str)[array_size], char ch) {
int count = 0;
for (int i = 0; str[i]; i++) {
if (str[i] != ch)
@ -62,7 +61,8 @@ Concatenate strings using + if the strings are different
std::string concatenateIfDifferent(const std::vector<std::string> &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 <typename T>
std::string concatenateIfDifferent(const std::vector<T> &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

View File

@ -0,0 +1,18 @@
#include "ToString.h"
namespace sls {
std::string ToString(const std::vector<std::string> &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

View File

@ -47,6 +47,18 @@ std::string concatenateIfDifferent(const std::vector<T> &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<IpAddr> &);
template std::string concatenateIfDifferent(const std::vector<MacAddr> &);

View File

@ -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
)

View File

@ -0,0 +1,85 @@
#include "TimeHelper.h"
#include "ToString.h"
#include "catch.hpp"
#include <vector>
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<time::ns>("150", "ns") == time::ns(150));
REQUIRE(StringTo<time::ns>("150ns") == time::ns(150));
REQUIRE(StringTo<time::ns>("150s") == time::s(150));
REQUIRE(StringTo<time::s>("3 s") == time::s(3));
REQUIRE_THROWS(StringTo<time::ns>("5xs"));
REQUIRE_THROWS(StringTo<time::ns>("asvn"));
}
TEST_CASE("Convert vector of time", "[support][now]"){
std::vector<time::ns> 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<int> 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<double> 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]");
}