mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2026-11-10 02:53:53 +01:00
Build on RHEL9 docker image / build (push) Successful in 4m15s
Build on RHEL8 docker image / build (push) Successful in 5m13s
Build and Deploy on local RHEL9 / build (push) Successful in 2m1s
Build and Deploy on local RHEL8 / build (push) Successful in 5m10s
Run Simulator Tests on local RHEL9 / build (push) Successful in 20m43s
Run Simulator Tests on local RHEL8 / build (push) Successful in 24m8s
* [Mythen3] Check bad-channel flags before shifting the channel register The bad-channel test in setChannelRegisterChip ran after the register was divided by two, so the mask 0x38 hit the LSB of the counter 0 trim instead of the flags. Every channel with an odd trim value was logged as a bad channel, 1280 lines per module, which made setAllTrimbits about 190 ms slower for odd values. Test the flags where they were set. Also remove an unused message buffer in validate_writePatternWord and log the client pattern file name at debug level instead of printing it on every pattern load. * check is back * m3 binary in --------- Co-authored-by: Dhanya Thattil <dhanya.thattil@psi.ch>
461 lines
16 KiB
C++
461 lines
16 KiB
C++
// SPDX-License-Identifier: LGPL-3.0-or-other
|
|
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
|
#pragma once
|
|
/**
|
|
* \file ToString.h
|
|
*
|
|
* Conversion from various types to std::string
|
|
*
|
|
*/
|
|
|
|
#include "sls/TimeHelper.h"
|
|
#include "sls/TypeTraits.h"
|
|
#include "sls/bit_utils.h"
|
|
#include "sls/sls_detector_defs.h"
|
|
#include "sls/sls_detector_exceptions.h"
|
|
#include "sls/string_utils.h"
|
|
#include <array>
|
|
#include <chrono>
|
|
#include <iomanip>
|
|
#include <map>
|
|
#include <sstream>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
namespace sls {
|
|
|
|
using defs = slsDetectorDefs;
|
|
std::string ToString(const defs::runStatus s);
|
|
std::string ToString(const defs::detectorType s);
|
|
std::string ToString(const defs::detectorSettings s);
|
|
std::string ToString(const defs::speedLevel s);
|
|
std::string ToString(const defs::timingMode s);
|
|
std::string ToString(const defs::frameDiscardPolicy s);
|
|
std::string ToString(const defs::fileFormat s);
|
|
std::string ToString(const defs::externalSignalFlag s);
|
|
std::string ToString(const defs::readoutMode s);
|
|
std::string ToString(const defs::dacIndex s);
|
|
std::string ToString(const std::vector<defs::dacIndex> &vec);
|
|
std::string ToString(const defs::powerIndex s);
|
|
std::string ToString(const std::vector<defs::powerIndex> &vec);
|
|
std::string ToString(const defs::burstMode s);
|
|
std::string ToString(const defs::timingSourceType s);
|
|
std::string ToString(const defs::M3_GainCaps s);
|
|
std::string ToString(const defs::portPosition s);
|
|
std::string ToString(const defs::streamingInterface s);
|
|
std::string ToString(const defs::vetoAlgorithm s);
|
|
std::string ToString(const defs::gainMode s);
|
|
std::string ToString(const defs::polarity s);
|
|
std::string ToString(const defs::timingInfoDecoder s);
|
|
std::string ToString(const defs::collectionMode s);
|
|
|
|
std::string ToString(bool value);
|
|
std::string ToString(bool value, defs::boolFormat format);
|
|
|
|
std::string ToString(const slsDetectorDefs::xy &coord);
|
|
std::ostream &operator<<(std::ostream &os, const slsDetectorDefs::xy &coord);
|
|
std::string ToString(const slsDetectorDefs::ROI &roi);
|
|
std::ostream &operator<<(std::ostream &os, const slsDetectorDefs::ROI &roi);
|
|
std::string ToString(const slsDetectorDefs::rxParameters &r);
|
|
std::ostream &operator<<(std::ostream &os,
|
|
const slsDetectorDefs::rxParameters &r);
|
|
std::string ToString(const slsDetectorDefs::scanParameters &r);
|
|
std::ostream &operator<<(std::ostream &os,
|
|
const slsDetectorDefs::scanParameters &r);
|
|
std::string ToString(const slsDetectorDefs::currentSrcParameters &r);
|
|
std::ostream &operator<<(std::ostream &os,
|
|
const slsDetectorDefs::currentSrcParameters &r);
|
|
std::string ToString(const slsDetectorDefs::pedestalParameters &r);
|
|
std::ostream &operator<<(std::ostream &os,
|
|
const slsDetectorDefs::pedestalParameters &r);
|
|
|
|
const std::string &ToString(const std::string &s);
|
|
|
|
/** 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");
|
|
}
|
|
}
|
|
|
|
/** Convert frequency with specified output unit */
|
|
std::string ToString(defs::Hz f, defs::FrequencyUnit unit);
|
|
|
|
/** Convert frequency automatically selecting the unit */
|
|
std::string ToString(defs::Hz f);
|
|
|
|
/** 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);
|
|
}
|
|
|
|
/** Conversion of integer types, do not remove trailing zeros */
|
|
template <typename T>
|
|
typename std::enable_if<std::is_integral<T>::value, std::string>::type
|
|
ToStringHex(const T &value) {
|
|
std::ostringstream os;
|
|
os << "0x" << std::hex << value << std::dec;
|
|
return os.str();
|
|
}
|
|
|
|
/** Conversion of integer types, do not remove trailing zeros */
|
|
template <typename T>
|
|
typename std::enable_if<std::is_integral<T>::value, std::string>::type
|
|
ToStringHex(const T &value, int width) {
|
|
std::ostringstream os;
|
|
os << "0x" << std::hex << std::setfill('0') << std::setw(width) << value
|
|
<< std::dec;
|
|
return os.str();
|
|
}
|
|
|
|
/**
|
|
* hex
|
|
* For a container loop over all elements and call ToString on the element
|
|
* Container<std::string> is excluded
|
|
*/
|
|
template <typename T>
|
|
typename std::enable_if<
|
|
is_container<T>::value &&
|
|
!std::is_same<typename T::value_type, std::string>::value,
|
|
std::string>::type
|
|
ToStringHex(const T &container) {
|
|
std::ostringstream os;
|
|
os << '[';
|
|
if (!container.empty()) {
|
|
auto it = container.cbegin();
|
|
os << ToStringHex(*it++);
|
|
while (it != container.cend())
|
|
os << ", " << ToStringHex(*it++);
|
|
}
|
|
os << ']';
|
|
return os.str();
|
|
}
|
|
|
|
template <typename T>
|
|
typename std::enable_if<
|
|
is_container<T>::value &&
|
|
!std::is_same<typename T::value_type, std::string>::value,
|
|
std::string>::type
|
|
ToStringHex(const T &container, int width) {
|
|
std::ostringstream os;
|
|
os << '[';
|
|
if (!container.empty()) {
|
|
auto it = container.cbegin();
|
|
os << ToStringHex(*it++, width);
|
|
while (it != container.cend())
|
|
os << ", " << ToStringHex(*it++, width);
|
|
}
|
|
os << ']';
|
|
return os.str();
|
|
}
|
|
|
|
template <typename KeyType, typename ValueType>
|
|
std::string ToString(const std::map<KeyType, ValueType> &m) {
|
|
std::ostringstream os;
|
|
os << '{';
|
|
if (!m.empty()) {
|
|
auto it = m.cbegin();
|
|
os << ToString(it->first) << ": " << ToString(it->second);
|
|
it++;
|
|
while (it != m.cend()) {
|
|
os << ", " << ToString(it->first) << ": " << ToString(it->second);
|
|
it++;
|
|
}
|
|
}
|
|
os << '}';
|
|
return os.str();
|
|
}
|
|
|
|
/**
|
|
* Print a c style array
|
|
*/
|
|
template <typename T, size_t size> std::string ToString(const T (&arr)[size]) {
|
|
std::ostringstream os;
|
|
os << '[';
|
|
if (size) {
|
|
size_t i = 0;
|
|
os << ToString(arr[i++]);
|
|
for (; i < size; ++i)
|
|
os << ", " << ToString(arr[i]);
|
|
}
|
|
os << ']';
|
|
return os.str();
|
|
}
|
|
|
|
/**
|
|
* For a container loop over all elements and call ToString on the element
|
|
* Container<std::string> is excluded
|
|
*/
|
|
template <typename T>
|
|
typename std::enable_if<
|
|
is_container<T>::value &&
|
|
!std::is_same<typename T::value_type, std::string>::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();
|
|
}
|
|
|
|
/**
|
|
* Special case when container holds a string, don't call ToString again but
|
|
* print directly to stream
|
|
*/
|
|
|
|
template <typename T>
|
|
typename std::enable_if<
|
|
is_container<T>::value &&
|
|
std::is_same<typename T::value_type, std::string>::value,
|
|
std::string>::type
|
|
ToString(const T &vec) {
|
|
std::ostringstream os;
|
|
os << '[';
|
|
if (!vec.empty()) {
|
|
auto it = vec.begin();
|
|
os << *it++;
|
|
while (it != vec.end())
|
|
os << ", " << *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();
|
|
}
|
|
|
|
/** Container and specified unit, call ToString(value, FrequencyUnit) */
|
|
template <typename T>
|
|
typename std::enable_if<is_container<T>::value, std::string>::type
|
|
ToString(const T &container, defs::FrequencyUnit 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, std::enable_if_t<sls::is_duration<T>::value, int> = 0>
|
|
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 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 RuntimeError(
|
|
"Invalid unit in conversion from string to std::chrono::duration");
|
|
}
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<sls::is_frequency<T>::value, int> = 0>
|
|
T StringTo(const std::string &f, const std::string &unit) {
|
|
double fval{0};
|
|
try {
|
|
fval = std::stod(f);
|
|
} catch (const std::invalid_argument &e) {
|
|
throw RuntimeError("Could not convert string to frequency");
|
|
}
|
|
auto unitLower = [&] {
|
|
std::string result = unit;
|
|
std::transform(result.begin(), result.end(), result.begin(),
|
|
[](unsigned char c) { return std::tolower(c); });
|
|
return result;
|
|
}();
|
|
|
|
if (unitLower == "mhz") {
|
|
return T(static_cast<int>(fval * 1e6));
|
|
} else if (unitLower == "khz") {
|
|
return T(static_cast<int>(fval * 1e3));
|
|
} else if (unitLower.empty() || unitLower == "hz") {
|
|
return T(static_cast<int>(fval));
|
|
} else {
|
|
throw RuntimeError(
|
|
"Invalid unit in conversion from string to frequency");
|
|
}
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<!is_container<T>::value, int> = 0>
|
|
T StringTo(const std::string &t) {
|
|
std::string tmp{t};
|
|
auto unit = RemoveUnit(tmp);
|
|
return StringTo<T>(tmp, unit);
|
|
}
|
|
|
|
template <> defs::detectorType StringTo(const std::string &s);
|
|
template <> defs::detectorSettings StringTo(const std::string &s);
|
|
template <> defs::speedLevel StringTo(const std::string &s);
|
|
template <> defs::timingMode StringTo(const std::string &s);
|
|
template <> defs::frameDiscardPolicy StringTo(const std::string &s);
|
|
template <> defs::fileFormat StringTo(const std::string &s);
|
|
template <> defs::externalSignalFlag StringTo(const std::string &s);
|
|
template <> defs::readoutMode StringTo(const std::string &s);
|
|
template <> defs::dacIndex StringTo(const std::string &s);
|
|
template <> defs::powerIndex StringTo(const std::string &s);
|
|
template <> defs::burstMode StringTo(const std::string &s);
|
|
template <> defs::timingSourceType StringTo(const std::string &s);
|
|
template <> defs::M3_GainCaps StringTo(const std::string &s);
|
|
template <> defs::portPosition StringTo(const std::string &s);
|
|
template <> defs::streamingInterface StringTo(const std::string &s);
|
|
template <> defs::vetoAlgorithm StringTo(const std::string &s);
|
|
template <> defs::gainMode StringTo(const std::string &s);
|
|
template <> defs::polarity StringTo(const std::string &s);
|
|
template <> defs::timingInfoDecoder StringTo(const std::string &s);
|
|
template <> defs::collectionMode StringTo(const std::string &s);
|
|
template <> RegisterAddress StringTo(const std::string &s);
|
|
template <> RegisterValue StringTo(const std::string &s);
|
|
|
|
template <> uint8_t StringTo(const std::string &s);
|
|
template <> uint16_t StringTo(const std::string &s);
|
|
template <> uint32_t StringTo(const std::string &s);
|
|
template <> uint64_t StringTo(const std::string &s);
|
|
template <> int StringTo(const std::string &s);
|
|
template <> bool StringTo(const std::string &s);
|
|
bool StringTo(const std::string &s, defs::boolFormat format);
|
|
template <> int64_t StringTo(const std::string &s);
|
|
|
|
/** For types with a .str() method use this for conversion */
|
|
template <typename T>
|
|
typename std::enable_if<has_str<T>::value, std::string>::type
|
|
ToString(const T &obj) {
|
|
return obj.str();
|
|
}
|
|
|
|
/** Convert vector of strings to vector of type T */
|
|
template <typename T>
|
|
std::vector<T> StringTo(const std::vector<std::string> &strings) {
|
|
std::vector<T> result;
|
|
result.reserve(strings.size());
|
|
for (const auto &s : strings)
|
|
result.push_back(StringTo<T>(s));
|
|
return result;
|
|
}
|
|
|
|
/** Parse comma-separated string into vector type T (e.g.,
|
|
* StringTo<std::vector<int>>()) */
|
|
template <typename T, std::enable_if_t<is_container<T>::value &&
|
|
!std::is_same_v<T, std::string>,
|
|
int> = 0>
|
|
T StringTo(const std::string &s) {
|
|
using ElementType = typename T::value_type;
|
|
// Enclosing brackets are optional but must match. Nested pairs are
|
|
// accepted since the caller may already have wrapped the list once.
|
|
std::string list = s;
|
|
auto strip = [](std::string &str) {
|
|
auto first = str.find_first_not_of(' ');
|
|
if (first == std::string::npos) {
|
|
str.clear();
|
|
return;
|
|
}
|
|
str = str.substr(first, str.find_last_not_of(' ') - first + 1);
|
|
};
|
|
strip(list);
|
|
while (list.size() >= 2 && list.front() == '[' && list.back() == ']') {
|
|
list = list.substr(1, list.size() - 2);
|
|
strip(list);
|
|
}
|
|
if (list.find_first_of("[]") != std::string::npos) {
|
|
throw RuntimeError("Mismatched brackets in list '" + s + "'");
|
|
}
|
|
|
|
T res;
|
|
std::istringstream ss(list);
|
|
std::string item;
|
|
while (std::getline(ss, item, ',')) {
|
|
item.erase(std::remove_if(item.begin(), item.end(),
|
|
[](char c) { return c == '"' || c == ' '; }),
|
|
item.end());
|
|
|
|
try {
|
|
if (item.empty())
|
|
continue;
|
|
auto val = StringTo<ElementType>(item);
|
|
res.push_back(val);
|
|
} catch (const std::exception &e) {
|
|
throw RuntimeError("Could not convert '" + item +
|
|
"' to the container element type. " +
|
|
std::string(e.what()));
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
} // namespace sls
|