mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-06-23 10:07:59 +02:00
Api (#48)
* WIP * WIP * WIP * cleaned up multi * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * split up python module * WIP * WIP * WIP * WIP * WIP * ok * fixed bugs from rebase * WIP * fixed broken test * WIP * fixed python * WIP * sphinx help * including new commands * docs * WIP * WIP * more tests * added missing public header * WIP
This commit is contained in:
@ -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";
|
||||
if (action == slsDetectorDefs::HELP_ACTION)
|
||||
return "list\n\tlists all available commands, list deprecated - "
|
||||
"list deprecated commands\n";
|
||||
|
||||
if (args.size() == 0) {
|
||||
auto commands = slsDetectorCommand(nullptr).getAllCommands();
|
||||
@ -127,6 +193,22 @@ template <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
|
||||
|
19
slsSupportLib/include/TimeHelper.h
Normal file
19
slsSupportLib/include/TimeHelper.h
Normal 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
|
140
slsSupportLib/include/ToString.h
Normal file
140
slsSupportLib/include/ToString.h
Normal 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
|
48
slsSupportLib/include/TypeTraits.h
Normal file
48
slsSupportLib/include/TypeTraits.h
Normal 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
|
@ -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())
|
||||
return false;
|
||||
const auto &first = container[0];
|
||||
return std::all_of(container.cbegin(), container.cend(),
|
||||
[first](const T &element) { return element == first; });
|
||||
/** Compare elements in a Container to see if they are all equal */
|
||||
template <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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
@ -111,15 +120,31 @@ minusOneIfDifferent(const std::vector<std::vector<T>> &container) {
|
||||
|
||||
template <typename T, size_t size>
|
||||
std::array<T, size>
|
||||
minusOneIfDifferent(const std::vector<std::array<T,size>> &container) {
|
||||
minusOneIfDifferent(const std::vector<std::array<T, size>> &container) {
|
||||
if (allEqual(container))
|
||||
return container.front();
|
||||
|
||||
std::array<T,size> arr;
|
||||
|
||||
std::array<T, size> arr;
|
||||
arr.fill(static_cast<T>(-1));
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first value if all values are equal
|
||||
* otherwise return default_value. If no default
|
||||
* value is supplied it will be default constructed
|
||||
*/
|
||||
template <typename Container>
|
||||
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
|
||||
|
@ -1,14 +1,6 @@
|
||||
#pragma once
|
||||
/************************************************
|
||||
* @file sls_detector_exceptions.h
|
||||
* @short exceptions defined
|
||||
***********************************************/
|
||||
/**
|
||||
*@short exceptions defined
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
|
@ -1,30 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace sls {
|
||||
|
||||
/* Implementation of a safe string copy function for setting fields in
|
||||
for example the multi sls detector. It tries to copy the size of the
|
||||
destination from the source, stopping on '\0'.
|
||||
/* Implementation of a safe string copy function for setting fields in
|
||||
for example the multi sls detector. It tries to copy the size of the
|
||||
destination from the source, stopping on '\0'.
|
||||
|
||||
Warning this will truncate the source string and should be used with care.
|
||||
Warning this will truncate the source string and should be used with care.
|
||||
Still this is better than strcpy and a buffer overflow...
|
||||
*/
|
||||
template <size_t array_size>
|
||||
void strcpy_safe(char (&destination)[array_size], const char *source) {
|
||||
assert(array_size > strlen(source));
|
||||
strncpy(destination, source, array_size-1);
|
||||
strncpy(destination, source, array_size - 1);
|
||||
destination[array_size - 1] = '\0';
|
||||
}
|
||||
|
||||
template <size_t array_size>
|
||||
void strcpy_safe(char (&destination)[array_size], const std::string& source) {
|
||||
void strcpy_safe(char (&destination)[array_size], const std::string &source) {
|
||||
assert(array_size > source.size());
|
||||
strncpy(destination, source.c_str(), array_size-1);
|
||||
strncpy(destination, source.c_str(), array_size - 1);
|
||||
destination[array_size - 1] = '\0';
|
||||
}
|
||||
|
||||
@ -32,8 +32,7 @@ void strcpy_safe(char (&destination)[array_size], const std::string& source) {
|
||||
Removes all occurrences of the specified char from a c string
|
||||
Templated on array size to ensure no access after buffer limits.
|
||||
*/
|
||||
template <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)
|
||||
@ -44,7 +43,7 @@ void removeChar(char (&str)[array_size], char ch) {
|
||||
str[count] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
Split a string using the specified delimeter and return a vector of strings.
|
||||
TODO! Look into switching to absl or a string_view based implementation. Current
|
||||
implementation should not be used in a performance critical place.
|
||||
@ -62,9 +61,10 @@ Concatenate strings using + if the strings are different
|
||||
std::string concatenateIfDifferent(const std::vector<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>
|
||||
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
|
||||
|
Reference in New Issue
Block a user