Files
slsDetectorPackage/slsSupportLib/include/sls/ToString.h
T
Martin Mueller 0837de2a5a CTB frequency rounding, CTB frequency measurement, CTB frequency units (#1423)
* round CTB clocks to next closest possible value, added freq measurement

* added time for firmware to measrue actual value after frequency change

* add check for backwards compatibility

* change CTB and XCTB clock values to MHz, TODO: units and validation errors

* changed runclk command to use units and float, TODO: dbit, adcclk, why is everything called StringTo ?

* do the same for dbit and adcclk

* added tolerance to exptime, fixed test

* update default values in server defs

* added virtual check in Altera_PLL, update testcases

* change python and pyctbgui to accept and return floating point MHz

* update help and comments

* Dev/ctb clocks fix (#1434)

* introduced new type Hz, typetraits, String conversions, command generation (not yet generated)

* incorrect unit typo

* cmd generation and compiles

* default to MHz, removed space between units for consistency with timers, min and max checks for clks

* in python, but need to change the default to Hz again for clean code and intuition

* allow ints, doubles, implicit conversions

* dont allow raw ints, doubles and implicit conversions

* fixed tests

* added operators for Hz in python

* fix test for min clk for xilinx ctb

* fix test

* fix python tests

* fixed xilinx period and default clks

* test fix

* removed the 3 clock cycle check for ctb and implemented properly the max adc clk frq for altera ctb

* removing 3 clock cycle code from xilinx as well

* formatting

* loadpattern before 3 clk cycles code

* actualtime and measurement time to be implemented in 100ns already in fw

* fix tests

* pyzmq dependency forthe tests

* fixed pyctbgui for freq

* insert tolerance check again

* also added tolerance check for patwaittime

* formatting

* minor: rounding test

* removed Rep redundant in ToString for freq

* intro frequency unit enums, removed unnecessary template behavior for ToString with freq unit, switching from parsing string unit argument to the enum argument for ToString, adding parsing string to unit at CLI boundary

* minor, and binaries

* minor, default clk vals are 0 but set up at detector setup

* get frequency only for that unit

* tolerance process

* missed in previous commit

* some more changes to exptime and validations

* ctb is probably done

* periodleft and delayleft

* fixed xilinx freq conv as well

* fixed m3 bug, binaries

* xilinx: setup also done in stop server so that the clk is not 0

* missed a test marker

* binaries in

* review fixes, simpler validation of timers in ctb and xilinx ctb

* typo fix

* format

* fix tests

---------

Co-authored-by: Martin Mueller <martin.mueller@psi.ch>
Co-authored-by: Dhanya Thattil <dhanya.thattil@psi.ch>
2026-05-06 15:52:13 +02:00

411 lines
14 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> 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();
}
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;
}
} // namespace sls