mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2026-01-22 21:50:45 +01:00
Added parsing of exptime and period from master files (#256)
- New aare:to_string/string_to similar to what we have in slsDetectorPackage - Added members period and exptime to RawMasterFile - Parsing exposure time and period for json and raw master file formats - Parsing of RawMasterFile from string stream to enable test without files Comments: - to_string is at the moment not a public header. Can make it later if needed. This gives us full freedom with the API - FileConfig should probably be deprecated need to look into it. Meanwhile removed python bindings and string conv
This commit is contained in:
@@ -387,6 +387,7 @@ set(SourceFiles
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/RawFile.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/RawMasterFile.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/RawSubFile.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/to_string.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/task.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/ifstream_helpers.cpp
|
||||
)
|
||||
@@ -460,6 +461,7 @@ if(AARE_TESTS)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/RawFile.test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/RawSubFile.test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/task.test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/to_string.test.cpp
|
||||
|
||||
)
|
||||
target_sources(tests PRIVATE ${TestSources} )
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
- Expanding 24 to 32 bit data
|
||||
- Decoding digital data from Mythen 302
|
||||
- added ``transform_eta_values``. Function transforms :math:`\eta` to uniform spatial coordinates. Should only be used for easier debugging.
|
||||
- New to_string, string_to for aare
|
||||
- Added exptime and period members to RawMasterFile including decoding
|
||||
|
||||
|
||||
### 2025.11.21
|
||||
|
||||
@@ -34,15 +34,15 @@ struct FileConfig {
|
||||
DetectorType detector_type{DetectorType::Unknown};
|
||||
int max_frames_per_file{};
|
||||
size_t total_frames{};
|
||||
std::string to_string() const {
|
||||
return "{ dtype: " + dtype.to_string() +
|
||||
", rows: " + std::to_string(rows) +
|
||||
", cols: " + std::to_string(cols) +
|
||||
", geometry: " + geometry.to_string() +
|
||||
", detector_type: " + ToString(detector_type) +
|
||||
", max_frames_per_file: " + std::to_string(max_frames_per_file) +
|
||||
", total_frames: " + std::to_string(total_frames) + " }";
|
||||
}
|
||||
// std::string to_string() const {
|
||||
// return "{ dtype: " + dtype.to_string() +
|
||||
// ", rows: " + std::to_string(rows) +
|
||||
// ", cols: " + std::to_string(cols) +
|
||||
// ", geometry: " + geometry.to_string() +
|
||||
// ", detector_type: " + ToString(detector_type) +
|
||||
// ", max_frames_per_file: " + std::to_string(max_frames_per_file) +
|
||||
// ", total_frames: " + std::to_string(total_frames) + " }";
|
||||
// }
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <fmt/format.h>
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
#include <chrono>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
@@ -84,6 +85,9 @@ class RawMasterFile {
|
||||
size_t m_bitdepth{};
|
||||
uint8_t m_quad = 0;
|
||||
|
||||
std::optional<std::chrono::nanoseconds> m_exptime;
|
||||
std::chrono::nanoseconds m_period{0};
|
||||
|
||||
xy m_geometry{};
|
||||
xy m_udp_interfaces_per_module{1, 1};
|
||||
|
||||
@@ -109,6 +113,7 @@ class RawMasterFile {
|
||||
|
||||
public:
|
||||
RawMasterFile(const std::filesystem::path &fpath);
|
||||
RawMasterFile(std::istream &is, const std::string &fname); // for testing
|
||||
|
||||
std::filesystem::path data_fname(size_t mod_id, size_t file_id) const;
|
||||
|
||||
@@ -140,9 +145,12 @@ class RawMasterFile {
|
||||
|
||||
ScanParameters scan_parameters() const;
|
||||
|
||||
std::optional<std::chrono::nanoseconds> exptime() const { return m_exptime; }
|
||||
std::chrono::nanoseconds period() const { return m_period; }
|
||||
|
||||
private:
|
||||
void parse_json(const std::filesystem::path &fpath);
|
||||
void parse_raw(const std::filesystem::path &fpath);
|
||||
void parse_json(std::istream &is);
|
||||
void parse_raw(std::istream &is);
|
||||
void retrieve_geometry();
|
||||
};
|
||||
|
||||
|
||||
@@ -348,29 +348,11 @@ enum class corner : int {
|
||||
enum class TimingMode { Auto, Trigger };
|
||||
enum class FrameDiscardPolicy { NoDiscard, Discard, DiscardPartial };
|
||||
|
||||
template <class T> T StringTo(const std::string &arg) { return T(arg); }
|
||||
|
||||
template <class T> std::string ToString(T arg) { return T(arg); }
|
||||
|
||||
template <> DetectorType StringTo(const std::string & /*name*/);
|
||||
template <> std::string ToString(DetectorType arg);
|
||||
|
||||
template <> TimingMode StringTo(const std::string & /*mode*/);
|
||||
|
||||
template <> FrameDiscardPolicy StringTo(const std::string & /*mode*/);
|
||||
|
||||
using DataTypeVariants = std::variant<uint16_t, uint32_t>;
|
||||
|
||||
constexpr uint16_t ADC_MASK =
|
||||
0x3FFF; // used to mask out the gain bits in Jungfrau
|
||||
|
||||
/**
|
||||
* @brief Convert a string to a DACIndex
|
||||
* @param arg string representation of the dacIndex
|
||||
* @return DACIndex
|
||||
* @throw invalid argument error if the string does not match any DACIndex
|
||||
*/
|
||||
template <> DACIndex StringTo(const std::string &arg);
|
||||
|
||||
class BitOffset{
|
||||
uint8_t m_offset{};
|
||||
|
||||
@@ -106,7 +106,7 @@ class Logger {
|
||||
}
|
||||
|
||||
std::ostringstream &Get() {
|
||||
os << Color(m_level) << "- " << Timestamp() << " " << ToString(m_level)
|
||||
os << Color(m_level) << "- " << Timestamp() << " " << Logger::ToString(m_level)
|
||||
<< ": ";
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ void define_file_io_bindings(py::module &m) {
|
||||
.def_property_readonly("bytes_per_pixel", &File::bytes_per_pixel)
|
||||
.def_property_readonly(
|
||||
"detector_type",
|
||||
[](File &self) { return ToString(self.detector_type()); })
|
||||
[](File &self) { return self.detector_type(); })
|
||||
.def("read_frame",
|
||||
[](File &self) {
|
||||
const uint8_t item_size = self.bytes_per_pixel();
|
||||
@@ -161,21 +161,6 @@ void define_file_io_bindings(py::module &m) {
|
||||
}
|
||||
});
|
||||
|
||||
py::class_<FileConfig>(m, "FileConfig")
|
||||
.def(py::init<>())
|
||||
.def_readwrite("rows", &FileConfig::rows)
|
||||
.def_readwrite("cols", &FileConfig::cols)
|
||||
.def_readwrite("version", &FileConfig::version)
|
||||
.def_readwrite("geometry", &FileConfig::geometry)
|
||||
.def_readwrite("detector_type", &FileConfig::detector_type)
|
||||
.def_readwrite("max_frames_per_file", &FileConfig::max_frames_per_file)
|
||||
.def_readwrite("total_frames", &FileConfig::total_frames)
|
||||
.def_readwrite("dtype", &FileConfig::dtype)
|
||||
.def("__eq__", &FileConfig::operator==)
|
||||
.def("__ne__", &FileConfig::operator!=)
|
||||
.def("__repr__", [](const FileConfig &a) {
|
||||
return "<FileConfig: " + a.to_string() + ">";
|
||||
});
|
||||
|
||||
py::class_<ScanParameters>(m, "ScanParameters")
|
||||
.def(py::init<const std::string &>())
|
||||
|
||||
@@ -85,5 +85,21 @@ void define_raw_master_file_bindings(py::module &m) {
|
||||
.def_property_readonly("quad", &RawMasterFile::quad)
|
||||
.def_property_readonly("scan_parameters",
|
||||
&RawMasterFile::scan_parameters)
|
||||
.def_property_readonly("roi", &RawMasterFile::roi);
|
||||
.def_property_readonly("roi", &RawMasterFile::roi)
|
||||
.def_property_readonly(
|
||||
"exptime",
|
||||
[](RawMasterFile &self) -> std::optional<double> {
|
||||
if (self.exptime()) {
|
||||
double seconds =
|
||||
std::chrono::duration<double>(*self.exptime()).count();
|
||||
return seconds;
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
})
|
||||
.def_property_readonly("period", [](RawMasterFile &self) {
|
||||
double seconds =
|
||||
std::chrono::duration<double>(self.period()).count();
|
||||
return seconds;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "aare/logger.hpp"
|
||||
#include <sstream>
|
||||
|
||||
#include "to_string.hpp"
|
||||
|
||||
namespace aare {
|
||||
|
||||
RawFileNameComponents::RawFileNameComponents(
|
||||
@@ -79,7 +81,7 @@ ScanParameters::ScanParameters(const std::string &par) {
|
||||
if (line == "enabled") {
|
||||
m_enabled = true;
|
||||
} else if (line.find("dac") != std::string::npos) {
|
||||
m_dac = StringTo<DACIndex>(line.substr(4));
|
||||
m_dac = string_to<DACIndex>(line.substr(4));
|
||||
} else if (line.find("start") != std::string::npos) {
|
||||
m_start = std::stoi(line.substr(6));
|
||||
} else if (line.find("stop") != std::string::npos) {
|
||||
@@ -104,10 +106,24 @@ RawMasterFile::RawMasterFile(const std::filesystem::path &fpath)
|
||||
throw std::runtime_error(fmt::format("{} File does not exist: {}",
|
||||
LOCATION, fpath.string()));
|
||||
}
|
||||
|
||||
std::ifstream ifs(fpath);
|
||||
if (m_fnc.ext() == ".json") {
|
||||
parse_json(fpath);
|
||||
parse_json(ifs);
|
||||
} else if (m_fnc.ext() == ".raw") {
|
||||
parse_raw(fpath);
|
||||
parse_raw(ifs);
|
||||
} else {
|
||||
throw std::runtime_error(LOCATION + "Unsupported file type");
|
||||
}
|
||||
}
|
||||
|
||||
RawMasterFile::RawMasterFile(std::istream &is, const std::string &fname)
|
||||
: m_fnc(fname) {
|
||||
|
||||
if (m_fnc.ext() == ".json") {
|
||||
parse_json(is);
|
||||
} else if (m_fnc.ext() == ".raw") {
|
||||
parse_raw(is);
|
||||
} else {
|
||||
throw std::runtime_error(LOCATION + "Unsupported file type");
|
||||
}
|
||||
@@ -179,16 +195,15 @@ ScanParameters RawMasterFile::scan_parameters() const {
|
||||
|
||||
std::optional<ROI> RawMasterFile::roi() const { return m_roi; }
|
||||
|
||||
void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
|
||||
std::ifstream ifs(fpath);
|
||||
void RawMasterFile::parse_json(std::istream &is) {
|
||||
json j;
|
||||
ifs >> j;
|
||||
is >> j;
|
||||
|
||||
double v = j["Version"];
|
||||
m_version = fmt::format("{:.1f}", v);
|
||||
|
||||
m_type = StringTo<DetectorType>(j["Detector Type"].get<std::string>());
|
||||
m_timing_mode = StringTo<TimingMode>(j["Timing Mode"].get<std::string>());
|
||||
m_type = string_to<DetectorType>(j["Detector Type"].get<std::string>());
|
||||
m_timing_mode = string_to<TimingMode>(j["Timing Mode"].get<std::string>());
|
||||
|
||||
m_geometry = {
|
||||
j["Geometry"]["y"],
|
||||
@@ -204,24 +219,46 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
|
||||
|
||||
m_max_frames_per_file = j["Max Frames Per File"];
|
||||
|
||||
// Before v8.0 we had Exptime instead of Exposure Time
|
||||
// Mythen3 uses 3 exposure times and is not handled at the moment
|
||||
if (j.contains("Exptime") && j["Exptime"].is_string()) {
|
||||
m_exptime = string_to<std::chrono::nanoseconds>(
|
||||
j["Exptime"].get<std::string>());
|
||||
}
|
||||
if (j.contains("Exposure Time") && j["Exposure Time"].is_string()) {
|
||||
m_exptime = string_to<std::chrono::nanoseconds>(
|
||||
j["Exposure Time"].get<std::string>());
|
||||
}
|
||||
|
||||
// Before v8.0 we had Period instead of Acquisition Period
|
||||
if (j.contains("Period") && j["Period"].is_string()) {
|
||||
m_period =
|
||||
string_to<std::chrono::nanoseconds>(j["Period"].get<std::string>());
|
||||
}
|
||||
if (j.contains("Acquisition Period") &&
|
||||
j["Acquisition Period"].is_string()) {
|
||||
m_period = string_to<std::chrono::nanoseconds>(
|
||||
j["Acquisition Period"].get<std::string>());
|
||||
}
|
||||
|
||||
// TODO! Not valid for CTB but not changing api right now!
|
||||
// Not all detectors write the bitdepth but in case
|
||||
// its not there it is 16
|
||||
try {
|
||||
m_bitdepth = j.at("Dynamic Range");
|
||||
} catch (const json::out_of_range &e) {
|
||||
if(j.contains("Bit Depth") && j["Bit Depth"].is_number()){
|
||||
m_bitdepth = j["Bit Depth"];
|
||||
} else {
|
||||
m_bitdepth = 16;
|
||||
}
|
||||
m_total_frames_expected = j["Total Frames"];
|
||||
|
||||
m_frame_padding = j["Frame Padding"];
|
||||
m_frame_discard_policy = StringTo<FrameDiscardPolicy>(
|
||||
m_frame_discard_policy = string_to<FrameDiscardPolicy>(
|
||||
j["Frame Discard Policy"].get<std::string>());
|
||||
|
||||
try {
|
||||
m_number_of_rows = j.at("Number of rows");
|
||||
} catch (const json::out_of_range &e) {
|
||||
// keep the optional empty
|
||||
if(j.contains("Number of rows") && j["Number of rows"].is_number()){
|
||||
m_number_of_rows = j["Number of rows"];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Special treatment of analog flag because of Moench03
|
||||
try {
|
||||
@@ -334,19 +371,18 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
|
||||
} catch (const json::out_of_range &e) {
|
||||
// leave the optional empty
|
||||
}
|
||||
try {
|
||||
// TODO: what is the best format to handle
|
||||
m_counter_mask = j.at("Counter Mask");
|
||||
} catch (const json::out_of_range &e) {
|
||||
// leave the optional empty
|
||||
|
||||
if (j.contains("Counter Mask")) {
|
||||
if (j["Counter Mask"].is_number())
|
||||
m_counter_mask = j["Counter Mask"];
|
||||
else if (j["Counter Mask"].is_string())
|
||||
m_counter_mask =
|
||||
std::stoi(j["Counter Mask"].get<std::string>(), nullptr, 16);
|
||||
}
|
||||
|
||||
|
||||
// Update detector type for Moench
|
||||
// TODO! How does this work with old .raw master files?
|
||||
#ifdef AARE_VERBOSE
|
||||
fmt::print("Detecting Moench03: m_pixels_y: {}, m_analog_samples: {}\n",
|
||||
m_pixels_y, m_analog_samples.value_or(0));
|
||||
#endif
|
||||
if (m_type == DetectorType::Moench && !m_analog_samples &&
|
||||
m_pixels_y == 400) {
|
||||
m_type = DetectorType::Moench03;
|
||||
@@ -355,10 +391,8 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
|
||||
m_type = DetectorType::Moench03_old;
|
||||
}
|
||||
}
|
||||
void RawMasterFile::parse_raw(const std::filesystem::path &fpath) {
|
||||
|
||||
std::ifstream ifs(fpath);
|
||||
for (std::string line; std::getline(ifs, line);) {
|
||||
void RawMasterFile::parse_raw(std::istream &is) {
|
||||
for (std::string line; std::getline(is, line);) {
|
||||
if (line == "#Frame Header")
|
||||
break;
|
||||
auto pos = line.find(':');
|
||||
@@ -383,12 +417,12 @@ void RawMasterFile::parse_raw(const std::filesystem::path &fpath) {
|
||||
} else if (key == "TimeStamp") {
|
||||
|
||||
} else if (key == "Detector Type") {
|
||||
m_type = StringTo<DetectorType>(value);
|
||||
m_type = string_to<DetectorType>(value);
|
||||
if (m_type == DetectorType::Moench) {
|
||||
m_type = DetectorType::Moench03_old;
|
||||
}
|
||||
} else if (key == "Timing Mode") {
|
||||
m_timing_mode = StringTo<TimingMode>(value);
|
||||
m_timing_mode = string_to<TimingMode>(value);
|
||||
} else if (key == "Image Size") {
|
||||
m_image_size_in_bytes = std::stoi(value);
|
||||
} else if (key == "Frame Padding") {
|
||||
@@ -429,6 +463,10 @@ void RawMasterFile::parse_raw(const std::filesystem::path &fpath) {
|
||||
m_pixels_x = std::stoi(value.substr(0, pos));
|
||||
} else if (key == "Total Frames") {
|
||||
m_total_frames_expected = std::stoi(value);
|
||||
} else if (key == "Exptime") {
|
||||
m_exptime = string_to<std::chrono::nanoseconds>(value);
|
||||
} else if (key == "Period") {
|
||||
m_period = string_to<std::chrono::nanoseconds>(value);
|
||||
} else if (key == "Dynamic Range") {
|
||||
m_bitdepth = std::stoi(value);
|
||||
} else if (key == "Quad") {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "test_config.hpp"
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace aare;
|
||||
|
||||
@@ -164,7 +165,7 @@ TEST_CASE("Parse a master file in .raw format", "[.integration]") {
|
||||
|
||||
auto fpath =
|
||||
test_data_path() /
|
||||
"moench/"
|
||||
"raw/moench04/"
|
||||
"moench04_noise_200V_sto_both_100us_no_light_thresh_900_master_0.raw";
|
||||
REQUIRE(std::filesystem::exists(fpath));
|
||||
RawMasterFile f(fpath);
|
||||
@@ -194,7 +195,9 @@ TEST_CASE("Parse a master file in .raw format", "[.integration]") {
|
||||
// Total Frames : 100
|
||||
REQUIRE(f.total_frames_expected() == 100);
|
||||
// Exptime : 100us
|
||||
REQUIRE(f.exptime() == std::chrono::microseconds(100));
|
||||
// Period : 4ms
|
||||
REQUIRE(f.period() == std::chrono::milliseconds(4));
|
||||
// Ten Giga : 1
|
||||
// ADC Mask : 0xffffffff
|
||||
// Analog Flag : 1
|
||||
@@ -255,13 +258,13 @@ TEST_CASE("Parse a master file in new .json format",
|
||||
|
||||
auto roi = f.roi().value();
|
||||
REQUIRE(roi.xmin == 0);
|
||||
REQUIRE(roi.xmax == 2559);
|
||||
REQUIRE(roi.ymin == -1);
|
||||
REQUIRE(roi.ymax == -1);
|
||||
REQUIRE(roi.xmax == 2560);
|
||||
REQUIRE(roi.ymin == 0);
|
||||
REQUIRE(roi.ymax == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("Read eiger master file", "[.integration]") {
|
||||
auto fpath = test_data_path() / "eiger" / "eiger_500k_32bit_master_0.json";
|
||||
auto fpath = test_data_path() / "raw/eiger/eiger_500k_32bit_master_0.json";
|
||||
REQUIRE(std::filesystem::exists(fpath));
|
||||
RawMasterFile f(fpath);
|
||||
|
||||
@@ -303,7 +306,9 @@ TEST_CASE("Read eiger master file", "[.integration]") {
|
||||
// "Dynamic Range": 32,
|
||||
// "Ten Giga": 0,
|
||||
// "Exptime": "5s",
|
||||
REQUIRE(f.exptime() == std::chrono::seconds(5));
|
||||
// "Period": "1s",
|
||||
REQUIRE(f.period() == std::chrono::seconds(1));
|
||||
// "Threshold Energy": -1,
|
||||
// "Sub Exptime": "2.62144ms",
|
||||
// "Sub Period": "2.62144ms",
|
||||
@@ -329,3 +334,392 @@ TEST_CASE("Read eiger master file", "[.integration]") {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
TEST_CASE("Parse EIGER 7.2 master from string stream") {
|
||||
std::string master_content = R"({
|
||||
"Version": 7.2,
|
||||
"Timestamp": "Tue Mar 26 17:24:34 2024",
|
||||
"Detector Type": "Eiger",
|
||||
"Timing Mode": "auto",
|
||||
"Geometry": {
|
||||
"x": 2,
|
||||
"y": 2
|
||||
},
|
||||
"Image Size in bytes": 524288,
|
||||
"Pixels": {
|
||||
"x": 512,
|
||||
"y": 256
|
||||
},
|
||||
"Max Frames Per File": 10000,
|
||||
"Frame Discard Policy": "nodiscard",
|
||||
"Frame Padding": 1,
|
||||
"Scan Parameters": "[disabled]",
|
||||
"Total Frames": 3,
|
||||
"Receiver Roi": {
|
||||
"xmin": 4294967295,
|
||||
"xmax": 4294967295,
|
||||
"ymin": 4294967295,
|
||||
"ymax": 4294967295
|
||||
},
|
||||
"Dynamic Range": 32,
|
||||
"Ten Giga": 0,
|
||||
"Exptime": "5s",
|
||||
"Period": "1s",
|
||||
"Threshold Energy": -1,
|
||||
"Sub Exptime": "2.62144ms",
|
||||
"Sub Period": "2.62144ms",
|
||||
"Quad": 0,
|
||||
"Number of rows": 256,
|
||||
"Rate Corrections": "[0, 0]",
|
||||
"Frames in File": 3,
|
||||
"Frame Header Format": {
|
||||
"Frame Number": "8 bytes",
|
||||
"SubFrame Number/ExpLength": "4 bytes",
|
||||
"Packet Number": "4 bytes",
|
||||
"Bunch ID": "8 bytes",
|
||||
"Timestamp": "8 bytes",
|
||||
"Module Id": "2 bytes",
|
||||
"Row": "2 bytes",
|
||||
"Column": "2 bytes",
|
||||
"Reserved": "2 bytes",
|
||||
"Debug": "4 bytes",
|
||||
"Round Robin Number": "2 bytes",
|
||||
"Detector Type": "1 byte",
|
||||
"Header Version": "1 byte",
|
||||
"Packets Caught Mask": "64 bytes"
|
||||
}
|
||||
})";
|
||||
|
||||
std::istringstream iss(master_content);
|
||||
RawMasterFile f(iss, "test_master_0.json");
|
||||
|
||||
REQUIRE(f.version() == "7.2");
|
||||
REQUIRE(f.detector_type() == DetectorType::Eiger);
|
||||
REQUIRE(f.timing_mode() == TimingMode::Auto);
|
||||
REQUIRE(f.geometry().col == 2);
|
||||
REQUIRE(f.geometry().row == 2);
|
||||
REQUIRE(f.image_size_in_bytes() == 524288);
|
||||
REQUIRE(f.pixels_x() == 512);
|
||||
REQUIRE(f.pixels_y() == 256);
|
||||
REQUIRE(f.max_frames_per_file() == 10000);
|
||||
REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard);
|
||||
REQUIRE(f.frame_padding() == 1);
|
||||
REQUIRE(f.total_frames_expected() == 3);
|
||||
REQUIRE(f.exptime() == std::chrono::seconds(5));
|
||||
REQUIRE(f.period() == std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
TEST_CASE("Parse JUNGFRAU 7.2 master from string stream") {
|
||||
std::string master_content = R"({
|
||||
"Version": 7.2,
|
||||
"Timestamp": "Tue Feb 20 08:29:19 2024",
|
||||
"Detector Type": "Jungfrau",
|
||||
"Timing Mode": "auto",
|
||||
"Geometry": {
|
||||
"x": 1,
|
||||
"y": 2
|
||||
},
|
||||
"Image Size in bytes": 524288,
|
||||
"Pixels": {
|
||||
"x": 1024,
|
||||
"y": 256
|
||||
},
|
||||
"Max Frames Per File": 3,
|
||||
"Frame Discard Policy": "nodiscard",
|
||||
"Frame Padding": 1,
|
||||
"Scan Parameters": "[disabled]",
|
||||
"Total Frames": 10,
|
||||
"Receiver Roi": {
|
||||
"xmin": 4294967295,
|
||||
"xmax": 4294967295,
|
||||
"ymin": 4294967295,
|
||||
"ymax": 4294967295
|
||||
},
|
||||
"Exptime": "10us",
|
||||
"Period": "1ms",
|
||||
"Number of UDP Interfaces": 2,
|
||||
"Number of rows": 512,
|
||||
"Frames in File": 10,
|
||||
"Frame Header Format": {
|
||||
"Frame Number": "8 bytes",
|
||||
"SubFrame Number/ExpLength": "4 bytes",
|
||||
"Packet Number": "4 bytes",
|
||||
"Bunch ID": "8 bytes",
|
||||
"Timestamp": "8 bytes",
|
||||
"Module Id": "2 bytes",
|
||||
"Row": "2 bytes",
|
||||
"Column": "2 bytes",
|
||||
"Reserved": "2 bytes",
|
||||
"Debug": "4 bytes",
|
||||
"Round Robin Number": "2 bytes",
|
||||
"Detector Type": "1 byte",
|
||||
"Header Version": "1 byte",
|
||||
"Packets Caught Mask": "64 bytes"
|
||||
}
|
||||
})";
|
||||
|
||||
std::istringstream iss(master_content);
|
||||
RawMasterFile f(iss, "test_master_0.json");
|
||||
|
||||
REQUIRE(f.version() == "7.2");
|
||||
REQUIRE(f.detector_type() == DetectorType::Jungfrau);
|
||||
REQUIRE(f.timing_mode() == TimingMode::Auto);
|
||||
REQUIRE(f.geometry().col == 1);
|
||||
REQUIRE(f.geometry().row == 2);
|
||||
REQUIRE(f.n_modules() == 2);
|
||||
REQUIRE(f.image_size_in_bytes() == 524288);
|
||||
REQUIRE(f.pixels_x() == 1024);
|
||||
REQUIRE(f.pixels_y() == 256);
|
||||
REQUIRE(f.max_frames_per_file() == 3);
|
||||
REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard);
|
||||
REQUIRE(f.frame_padding() == 1);
|
||||
REQUIRE(f.total_frames_expected() == 10);
|
||||
REQUIRE(f.exptime() == std::chrono::microseconds(10));
|
||||
REQUIRE(f.period() == std::chrono::milliseconds(1));
|
||||
REQUIRE(f.number_of_rows() == 512);
|
||||
|
||||
REQUIRE(f.frames_in_file() == 10);
|
||||
REQUIRE(f.udp_interfaces_per_module() == xy{2, 1});
|
||||
}
|
||||
|
||||
TEST_CASE("Parse a CTB file from stream"){
|
||||
std::string master_content = R"({
|
||||
"Version": 8.0,
|
||||
"Timestamp": "Mon Dec 15 10:57:27 2025",
|
||||
"Detector Type": "ChipTestBoard",
|
||||
"Timing Mode": "auto",
|
||||
"Geometry": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
},
|
||||
"Image Size": 18432,
|
||||
"Pixels": {
|
||||
"x": 2,
|
||||
"y": 1
|
||||
},
|
||||
"Max Frames Per File": 20000,
|
||||
"Frame Discard Policy": "nodiscard",
|
||||
"Frame Padding": 1,
|
||||
"Scan Parameters": {
|
||||
"enable": 0,
|
||||
"dacInd": 0,
|
||||
"start offset": 0,
|
||||
"stop offset": 0,
|
||||
"step size": 0,
|
||||
"dac settle time ns": 0
|
||||
},
|
||||
"Total Frames": 1,
|
||||
"Exposure Time": "0.25s",
|
||||
"Acquisition Period": "10ms",
|
||||
"Ten Giga": 1,
|
||||
"ADC Mask": 4294967295,
|
||||
"Analog Flag": 0,
|
||||
"Analog Samples": 1,
|
||||
"Digital Flag": 0,
|
||||
"Digital Samples": 1,
|
||||
"Dbit Offset": 0,
|
||||
"Dbit Reorder": 1,
|
||||
"Dbit Bitset": 0,
|
||||
"Transceiver Mask": 3,
|
||||
"Transceiver Flag": 1,
|
||||
"Transceiver Samples": 1152,
|
||||
"Frames in File": 40,
|
||||
"Additional JSON Header": {}
|
||||
})";
|
||||
|
||||
std::istringstream iss(master_content);
|
||||
RawMasterFile f(iss, "test_master_0.json");
|
||||
|
||||
REQUIRE(f.version() == "8.0");
|
||||
REQUIRE(f.detector_type() == DetectorType::ChipTestBoard);
|
||||
REQUIRE(f.timing_mode() == TimingMode::Auto);
|
||||
REQUIRE(f.geometry().col == 1);
|
||||
REQUIRE(f.geometry().row == 1);
|
||||
REQUIRE(f.image_size_in_bytes() == 18432);
|
||||
REQUIRE(f.pixels_x() == 2);
|
||||
REQUIRE(f.pixels_y() == 1);
|
||||
REQUIRE(f.max_frames_per_file() == 20000);
|
||||
// CTB does not have bitdepth in master file, but for the moment we write 16
|
||||
// TODO! refactor using std::optional
|
||||
// REQUIRE(f.bitdepth() == std::nullopt);
|
||||
REQUIRE(f.n_modules() == 1);
|
||||
REQUIRE(f.quad() == 0);
|
||||
REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard);
|
||||
REQUIRE(f.frame_padding() == 1);
|
||||
REQUIRE(f.total_frames_expected() == 1); //This is Total Frames in the master file
|
||||
REQUIRE(f.exptime() == std::chrono::milliseconds(250));
|
||||
REQUIRE(f.period() == std::chrono::milliseconds(10));
|
||||
REQUIRE(f.analog_samples() == std::nullopt); //Analog Flag is 0
|
||||
REQUIRE(f.digital_samples() == std::nullopt); //Digital Flag is 0
|
||||
REQUIRE(f.transceiver_samples() == 1152);
|
||||
REQUIRE(f.frames_in_file() == 40);
|
||||
}
|
||||
|
||||
TEST_CASE("Parse v8.0 MYTHEN3 from stream"){
|
||||
std::string master_content = R"({
|
||||
"Version": 8.0,
|
||||
"Timestamp": "Wed Oct 1 14:37:26 2025",
|
||||
"Detector Type": "Mythen3",
|
||||
"Timing Mode": "auto",
|
||||
"Geometry": {
|
||||
"x": 2,
|
||||
"y": 1
|
||||
},
|
||||
"Image Size": 5120,
|
||||
"Pixels": {
|
||||
"x": 1280,
|
||||
"y": 1
|
||||
},
|
||||
"Max Frames Per File": 10000,
|
||||
"Frame Discard Policy": "nodiscard",
|
||||
"Frame Padding": 1,
|
||||
"Scan Parameters": {
|
||||
"enable": 0,
|
||||
"dacInd": 0,
|
||||
"start offset": 0,
|
||||
"stop offset": 0,
|
||||
"step size": 0,
|
||||
"dac settle time ns": 0
|
||||
},
|
||||
"Total Frames": 1,
|
||||
"Receiver Rois": [
|
||||
{
|
||||
"xmin": 0,
|
||||
"xmax": 2559,
|
||||
"ymin": -1,
|
||||
"ymax": -1
|
||||
}
|
||||
],
|
||||
"Dynamic Range": 32,
|
||||
"Ten Giga": 1,
|
||||
"Acquisition Period": "0ns",
|
||||
"Counter Mask": 4,
|
||||
"Exposure Times": [
|
||||
"5s",
|
||||
"5s",
|
||||
"5s"
|
||||
],
|
||||
"Gate Delays": [
|
||||
"0ns",
|
||||
"0ns",
|
||||
"0ns"
|
||||
],
|
||||
"Gates": 1,
|
||||
"Threshold Energies": [
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"Readout Speed": "half_speed",
|
||||
"Frames in File": 1,
|
||||
"Additional JSON Header": {}
|
||||
})";
|
||||
|
||||
std::istringstream iss(master_content);
|
||||
RawMasterFile f(iss, "test_master_0.json");
|
||||
|
||||
REQUIRE(f.version() == "8.0");
|
||||
REQUIRE(f.detector_type() == DetectorType::Mythen3);
|
||||
REQUIRE(f.timing_mode() == TimingMode::Auto);
|
||||
REQUIRE(f.geometry().col == 2);
|
||||
REQUIRE(f.geometry().row == 1);
|
||||
REQUIRE(f.image_size_in_bytes() == 5120);
|
||||
REQUIRE(f.pixels_x() == 1280);
|
||||
REQUIRE(f.pixels_y() == 1);
|
||||
REQUIRE(f.max_frames_per_file() == 10000);
|
||||
REQUIRE(f.n_modules() == 2);
|
||||
REQUIRE(f.quad() == 0);
|
||||
REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard);
|
||||
REQUIRE(f.frame_padding() == 1);
|
||||
REQUIRE(f.total_frames_expected() == 1); //This is Total Frames in the master file
|
||||
REQUIRE(f.counter_mask() == 4);
|
||||
|
||||
// Mythen3 has three exposure times, but for the moment we don't handle them
|
||||
REQUIRE(f.exptime() == std::nullopt);
|
||||
|
||||
// Period is ok though
|
||||
REQUIRE(f.period() == std::chrono::nanoseconds(0));
|
||||
}
|
||||
|
||||
TEST_CASE("Parse a v7.1 Mythen3 from stream"){
|
||||
std::string master_content = R"({
|
||||
"Version": 7.1,
|
||||
"Timestamp": "Wed Sep 21 13:48:10 2022",
|
||||
"Detector Type": "Mythen3",
|
||||
"Timing Mode": "auto",
|
||||
"Geometry": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
},
|
||||
"Image Size in bytes": 15360,
|
||||
"Pixels": {
|
||||
"x": 3840,
|
||||
"y": 1
|
||||
},
|
||||
"Max Frames Per File": 10000,
|
||||
"Frame Discard Policy": "nodiscard",
|
||||
"Frame Padding": 1,
|
||||
"Scan Parameters": "[disabled]",
|
||||
"Total Frames": 1,
|
||||
"Receiver Roi": {
|
||||
"xmin": 4294967295,
|
||||
"xmax": 4294967295,
|
||||
"ymin": 4294967295,
|
||||
"ymax": 4294967295
|
||||
},
|
||||
"Dynamic Range": 32,
|
||||
"Ten Giga": 1,
|
||||
"Period": "2ms",
|
||||
"Counter Mask": "0x7",
|
||||
"Exptime1": "0.1s",
|
||||
"Exptime2": "0.1s",
|
||||
"Exptime3": "0.1s",
|
||||
"GateDelay1": "0ns",
|
||||
"GateDelay2": "0ns",
|
||||
"GateDelay3": "0ns",
|
||||
"Gates": 1,
|
||||
"Threshold Energies": "[-1, -1, -1]",
|
||||
"Frames in File": 1,
|
||||
"Frame Header Format": {
|
||||
"Frame Number": "8 bytes",
|
||||
"SubFrame Number/ExpLength": "4 bytes",
|
||||
"Packet Number": "4 bytes",
|
||||
"Bunch ID": "8 bytes",
|
||||
"Timestamp": "8 bytes",
|
||||
"Module Id": "2 bytes",
|
||||
"Row": "2 bytes",
|
||||
"Column": "2 bytes",
|
||||
"Reserved": "2 bytes",
|
||||
"Debug": "4 bytes",
|
||||
"Round Robin Number": "2 bytes",
|
||||
"Detector Type": "1 byte",
|
||||
"Header Version": "1 byte",
|
||||
"Packets Caught Mask": "64 bytes"
|
||||
}
|
||||
})";
|
||||
|
||||
std::istringstream iss(master_content);
|
||||
RawMasterFile f(iss, "test_master_0.json");
|
||||
|
||||
REQUIRE(f.version() == "7.1");
|
||||
REQUIRE(f.detector_type() == DetectorType::Mythen3);
|
||||
REQUIRE(f.timing_mode() == TimingMode::Auto);
|
||||
REQUIRE(f.geometry().col == 1);
|
||||
REQUIRE(f.geometry().row == 1);
|
||||
REQUIRE(f.image_size_in_bytes() == 15360);
|
||||
REQUIRE(f.pixels_x() == 3840);
|
||||
REQUIRE(f.pixels_y() == 1);
|
||||
REQUIRE(f.max_frames_per_file() == 10000);
|
||||
REQUIRE(f.n_modules() == 1);
|
||||
REQUIRE(f.quad() == 0);
|
||||
REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard);
|
||||
REQUIRE(f.frame_padding() == 1);
|
||||
REQUIRE(f.total_frames_expected() == 1); //This is Total Frames in the master file
|
||||
REQUIRE(f.counter_mask() == 0x7);
|
||||
|
||||
// Mythen3 has three exposure times, but for the moment we don't handle them
|
||||
REQUIRE(f.exptime() == std::nullopt);
|
||||
|
||||
// Period is ok though
|
||||
REQUIRE(f.period() == std::chrono::milliseconds(2));
|
||||
}
|
||||
320
src/defs.cpp
320
src/defs.cpp
@@ -11,292 +11,46 @@ void assert_failed(const std::string &msg) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a DetectorType to a string
|
||||
* @param type DetectorType
|
||||
* @return string representation of the DetectorType
|
||||
*/
|
||||
template <> std::string ToString(DetectorType arg) {
|
||||
switch (arg) {
|
||||
case DetectorType::Generic:
|
||||
return "Generic";
|
||||
case DetectorType::Eiger:
|
||||
return "Eiger";
|
||||
case DetectorType::Gotthard:
|
||||
return "Gotthard";
|
||||
case DetectorType::Jungfrau:
|
||||
return "Jungfrau";
|
||||
case DetectorType::ChipTestBoard:
|
||||
return "ChipTestBoard";
|
||||
case DetectorType::Moench:
|
||||
return "Moench";
|
||||
case DetectorType::Mythen3:
|
||||
return "Mythen3";
|
||||
case DetectorType::Gotthard2:
|
||||
return "Gotthard2";
|
||||
case DetectorType::Xilinx_ChipTestBoard:
|
||||
return "Xilinx_ChipTestBoard";
|
||||
// /**
|
||||
// * @brief Convert a DetectorType to a string
|
||||
// * @param type DetectorType
|
||||
// * @return string representation of the DetectorType
|
||||
// */
|
||||
// template <> std::string ToString(DetectorType arg) {
|
||||
// switch (arg) {
|
||||
// case DetectorType::Generic:
|
||||
// return "Generic";
|
||||
// case DetectorType::Eiger:
|
||||
// return "Eiger";
|
||||
// case DetectorType::Gotthard:
|
||||
// return "Gotthard";
|
||||
// case DetectorType::Jungfrau:
|
||||
// return "Jungfrau";
|
||||
// case DetectorType::ChipTestBoard:
|
||||
// return "ChipTestBoard";
|
||||
// case DetectorType::Moench:
|
||||
// return "Moench";
|
||||
// case DetectorType::Mythen3:
|
||||
// return "Mythen3";
|
||||
// case DetectorType::Gotthard2:
|
||||
// return "Gotthard2";
|
||||
// case DetectorType::Xilinx_ChipTestBoard:
|
||||
// return "Xilinx_ChipTestBoard";
|
||||
|
||||
// Custom ones
|
||||
case DetectorType::Moench03:
|
||||
return "Moench03";
|
||||
case DetectorType::Moench03_old:
|
||||
return "Moench03_old";
|
||||
case DetectorType::Unknown:
|
||||
return "Unknown";
|
||||
// // Custom ones
|
||||
// case DetectorType::Moench03:
|
||||
// return "Moench03";
|
||||
// case DetectorType::Moench03_old:
|
||||
// return "Moench03_old";
|
||||
// case DetectorType::Unknown:
|
||||
// return "Unknown";
|
||||
|
||||
// no default case to trigger compiler warning if not all
|
||||
// enum values are handled
|
||||
}
|
||||
throw std::runtime_error("Could not decode detector to string");
|
||||
}
|
||||
// // no default case to trigger compiler warning if not all
|
||||
// // enum values are handled
|
||||
// }
|
||||
// throw std::runtime_error("Could not decode detector to string");
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief Convert a string to a DetectorType
|
||||
* @param name string representation of the DetectorType
|
||||
* @return DetectorType
|
||||
* @throw runtime_error if the string does not match any DetectorType
|
||||
*/
|
||||
template <> DetectorType StringTo(const std::string &arg) {
|
||||
if (arg == "Generic")
|
||||
return DetectorType::Generic;
|
||||
if (arg == "Eiger")
|
||||
return DetectorType::Eiger;
|
||||
if (arg == "Gotthard")
|
||||
return DetectorType::Gotthard;
|
||||
if (arg == "Jungfrau")
|
||||
return DetectorType::Jungfrau;
|
||||
if (arg == "ChipTestBoard")
|
||||
return DetectorType::ChipTestBoard;
|
||||
if (arg == "Moench")
|
||||
return DetectorType::Moench;
|
||||
if (arg == "Mythen3")
|
||||
return DetectorType::Mythen3;
|
||||
if (arg == "Gotthard2")
|
||||
return DetectorType::Gotthard2;
|
||||
if (arg == "Xilinx_ChipTestBoard")
|
||||
return DetectorType::Xilinx_ChipTestBoard;
|
||||
|
||||
// Custom ones
|
||||
if (arg == "Moench03")
|
||||
return DetectorType::Moench03;
|
||||
if (arg == "Moench03_old")
|
||||
return DetectorType::Moench03_old;
|
||||
if (arg == "Unknown")
|
||||
return DetectorType::Unknown;
|
||||
|
||||
throw std::runtime_error("Could not decode detector from: \"" + arg + "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a string to a TimingMode
|
||||
* @param mode string representation of the TimingMode
|
||||
* @return TimingMode
|
||||
* @throw runtime_error if the string does not match any TimingMode
|
||||
*/
|
||||
template <> TimingMode StringTo(const std::string &arg) {
|
||||
if (arg == "auto")
|
||||
return TimingMode::Auto;
|
||||
if (arg == "trigger")
|
||||
return TimingMode::Trigger;
|
||||
throw std::runtime_error("Could not decode timing mode from: \"" + arg +
|
||||
"\"");
|
||||
}
|
||||
|
||||
template <> FrameDiscardPolicy StringTo(const std::string &arg) {
|
||||
if (arg == "nodiscard")
|
||||
return FrameDiscardPolicy::NoDiscard;
|
||||
if (arg == "discard")
|
||||
return FrameDiscardPolicy::Discard;
|
||||
if (arg == "discardpartial")
|
||||
return FrameDiscardPolicy::DiscardPartial;
|
||||
throw std::runtime_error("Could not decode frame discard policy from: \"" +
|
||||
arg + "\"");
|
||||
}
|
||||
|
||||
// template <> TimingMode StringTo<TimingMode>(std::string mode);
|
||||
|
||||
template <> DACIndex StringTo(const std::string &arg) {
|
||||
if (arg == "dac 0")
|
||||
return DACIndex::DAC_0;
|
||||
else if (arg == "dac 1")
|
||||
return DACIndex::DAC_1;
|
||||
else if (arg == "dac 2")
|
||||
return DACIndex::DAC_2;
|
||||
else if (arg == "dac 3")
|
||||
return DACIndex::DAC_3;
|
||||
else if (arg == "dac 4")
|
||||
return DACIndex::DAC_4;
|
||||
else if (arg == "dac 5")
|
||||
return DACIndex::DAC_5;
|
||||
else if (arg == "dac 6")
|
||||
return DACIndex::DAC_6;
|
||||
else if (arg == "dac 7")
|
||||
return DACIndex::DAC_7;
|
||||
else if (arg == "dac 8")
|
||||
return DACIndex::DAC_8;
|
||||
else if (arg == "dac 9")
|
||||
return DACIndex::DAC_9;
|
||||
else if (arg == "dac 10")
|
||||
return DACIndex::DAC_10;
|
||||
else if (arg == "dac 11")
|
||||
return DACIndex::DAC_11;
|
||||
else if (arg == "dac 12")
|
||||
return DACIndex::DAC_12;
|
||||
else if (arg == "dac 13")
|
||||
return DACIndex::DAC_13;
|
||||
else if (arg == "dac 14")
|
||||
return DACIndex::DAC_14;
|
||||
else if (arg == "dac 15")
|
||||
return DACIndex::DAC_15;
|
||||
else if (arg == "dac 16")
|
||||
return DACIndex::DAC_16;
|
||||
else if (arg == "dac 17")
|
||||
return DACIndex::DAC_17;
|
||||
else if (arg == "vsvp")
|
||||
return DACIndex::VSVP;
|
||||
else if (arg == "vtrim")
|
||||
return DACIndex::VTRIM;
|
||||
else if (arg == "vrpreamp")
|
||||
return DACIndex::VRPREAMP;
|
||||
else if (arg == "vrshaper")
|
||||
return DACIndex::VRSHAPER;
|
||||
else if (arg == "vsvn")
|
||||
return DACIndex::VSVN;
|
||||
else if (arg == "vtgstv")
|
||||
return DACIndex::VTGSTV;
|
||||
else if (arg == "vcmp_ll")
|
||||
return DACIndex::VCMP_LL;
|
||||
else if (arg == "vcmp_lr")
|
||||
return DACIndex::VCMP_LR;
|
||||
else if (arg == "vcal")
|
||||
return DACIndex::VCAL;
|
||||
else if (arg == "vcmp_rl")
|
||||
return DACIndex::VCMP_RL;
|
||||
else if (arg == "rxb_rb")
|
||||
return DACIndex::RXB_RB;
|
||||
else if (arg == "rxb_lb")
|
||||
return DACIndex::RXB_LB;
|
||||
else if (arg == "vcmp_rr")
|
||||
return DACIndex::VCMP_RR;
|
||||
else if (arg == "vcp")
|
||||
return DACIndex::VCP;
|
||||
else if (arg == "vcn")
|
||||
return DACIndex::VCN;
|
||||
else if (arg == "vishaper")
|
||||
return DACIndex::VISHAPER;
|
||||
else if (arg == "vthreshold")
|
||||
return DACIndex::VTHRESHOLD;
|
||||
else if (arg == "vref_ds")
|
||||
return DACIndex::VREF_DS;
|
||||
else if (arg == "vout_cm")
|
||||
return DACIndex::VOUT_CM;
|
||||
else if (arg == "vin_cm")
|
||||
return DACIndex::VIN_CM;
|
||||
else if (arg == "vref_comp")
|
||||
return DACIndex::VREF_COMP;
|
||||
else if (arg == "vb_comp")
|
||||
return DACIndex::VB_COMP;
|
||||
else if (arg == "vdd_prot")
|
||||
return DACIndex::VDD_PROT;
|
||||
else if (arg == "vin_com")
|
||||
return DACIndex::VIN_COM;
|
||||
else if (arg == "vref_prech")
|
||||
return DACIndex::VREF_PRECH;
|
||||
else if (arg == "vb_pixbuf")
|
||||
return DACIndex::VB_PIXBUF;
|
||||
else if (arg == "vb_ds")
|
||||
return DACIndex::VB_DS;
|
||||
else if (arg == "vref_h_adc")
|
||||
return DACIndex::VREF_H_ADC;
|
||||
else if (arg == "vb_comp_fe")
|
||||
return DACIndex::VB_COMP_FE;
|
||||
else if (arg == "vb_comp_adc")
|
||||
return DACIndex::VB_COMP_ADC;
|
||||
else if (arg == "vcom_cds")
|
||||
return DACIndex::VCOM_CDS;
|
||||
else if (arg == "vref_rstore")
|
||||
return DACIndex::VREF_RSTORE;
|
||||
else if (arg == "vb_opa_1st")
|
||||
return DACIndex::VB_OPA_1ST;
|
||||
else if (arg == "vref_comp_fe")
|
||||
return DACIndex::VREF_COMP_FE;
|
||||
else if (arg == "vcom_adc1")
|
||||
return DACIndex::VCOM_ADC1;
|
||||
else if (arg == "vref_l_adc")
|
||||
return DACIndex::VREF_L_ADC;
|
||||
else if (arg == "vref_cds")
|
||||
return DACIndex::VREF_CDS;
|
||||
else if (arg == "vb_cs")
|
||||
return DACIndex::VB_CS;
|
||||
else if (arg == "vb_opa_fd")
|
||||
return DACIndex::VB_OPA_FD;
|
||||
else if (arg == "vcom_adc2")
|
||||
return DACIndex::VCOM_ADC2;
|
||||
else if (arg == "vcassh")
|
||||
return DACIndex::VCASSH;
|
||||
else if (arg == "vth2")
|
||||
return DACIndex::VTH2;
|
||||
else if (arg == "vrshaper_n")
|
||||
return DACIndex::VRSHAPER_N;
|
||||
else if (arg == "vipre_out")
|
||||
return DACIndex::VIPRE_OUT;
|
||||
else if (arg == "vth3")
|
||||
return DACIndex::VTH3;
|
||||
else if (arg == "vth1")
|
||||
return DACIndex::VTH1;
|
||||
else if (arg == "vicin")
|
||||
return DACIndex::VICIN;
|
||||
else if (arg == "vcas")
|
||||
return DACIndex::VCAS;
|
||||
else if (arg == "vcal_n")
|
||||
return DACIndex::VCAL_N;
|
||||
else if (arg == "vipre")
|
||||
return DACIndex::VIPRE;
|
||||
else if (arg == "vcal_p")
|
||||
return DACIndex::VCAL_P;
|
||||
else if (arg == "vdcsh")
|
||||
return DACIndex::VDCSH;
|
||||
else if (arg == "vbp_colbuf")
|
||||
return DACIndex::VBP_COLBUF;
|
||||
else if (arg == "vb_sda")
|
||||
return DACIndex::VB_SDA;
|
||||
else if (arg == "vcasc_sfp")
|
||||
return DACIndex::VCASC_SFP;
|
||||
else if (arg == "vipre_cds")
|
||||
return DACIndex::VIPRE_CDS;
|
||||
else if (arg == "ibias_sfp")
|
||||
return DACIndex::IBIAS_SFP;
|
||||
else if (arg == "trimbits")
|
||||
return DACIndex::TRIMBIT_SCAN;
|
||||
else if (arg == "highvoltage")
|
||||
return DACIndex::HIGH_VOLTAGE;
|
||||
else if (arg == "iodelay")
|
||||
return DACIndex::IO_DELAY;
|
||||
else if (arg == "temp_adc")
|
||||
return DACIndex::TEMPERATURE_ADC;
|
||||
else if (arg == "temp_fpga")
|
||||
return DACIndex::TEMPERATURE_FPGA;
|
||||
else if (arg == "temp_fpgaext")
|
||||
return DACIndex::TEMPERATURE_FPGAEXT;
|
||||
else if (arg == "temp_10ge")
|
||||
return DACIndex::TEMPERATURE_10GE;
|
||||
else if (arg == "temp_dcdc")
|
||||
return DACIndex::TEMPERATURE_DCDC;
|
||||
else if (arg == "temp_sodl")
|
||||
return DACIndex::TEMPERATURE_SODL;
|
||||
else if (arg == "temp_sodr")
|
||||
return DACIndex::TEMPERATURE_SODR;
|
||||
else if (arg == "temp_fpgafl")
|
||||
return DACIndex::TEMPERATURE_FPGA2;
|
||||
else if (arg == "temp_fpgafr")
|
||||
return DACIndex::TEMPERATURE_FPGA3;
|
||||
else if (arg == "temp_slowadc")
|
||||
return DACIndex::SLOW_ADC_TEMP;
|
||||
else
|
||||
throw std::invalid_argument("Could not decode DACIndex from: \"" + arg +
|
||||
"\"");
|
||||
}
|
||||
|
||||
BitOffset::BitOffset(uint32_t offset){
|
||||
if (offset>7)
|
||||
|
||||
@@ -4,52 +4,7 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <string>
|
||||
|
||||
using aare::StringTo;
|
||||
using aare::ToString;
|
||||
|
||||
TEST_CASE("Enum to string conversion") {
|
||||
// TODO! By the way I don't think the enum string conversions should be in
|
||||
// the defs.hpp file but let's use this to show a test
|
||||
REQUIRE(ToString(aare::DetectorType::Generic) == "Generic");
|
||||
REQUIRE(ToString(aare::DetectorType::Eiger) == "Eiger");
|
||||
REQUIRE(ToString(aare::DetectorType::Gotthard) == "Gotthard");
|
||||
REQUIRE(ToString(aare::DetectorType::Jungfrau) == "Jungfrau");
|
||||
REQUIRE(ToString(aare::DetectorType::ChipTestBoard) == "ChipTestBoard");
|
||||
REQUIRE(ToString(aare::DetectorType::Moench) == "Moench");
|
||||
REQUIRE(ToString(aare::DetectorType::Mythen3) == "Mythen3");
|
||||
REQUIRE(ToString(aare::DetectorType::Gotthard2) == "Gotthard2");
|
||||
REQUIRE(ToString(aare::DetectorType::Xilinx_ChipTestBoard) ==
|
||||
"Xilinx_ChipTestBoard");
|
||||
REQUIRE(ToString(aare::DetectorType::Moench03) == "Moench03");
|
||||
REQUIRE(ToString(aare::DetectorType::Moench03_old) == "Moench03_old");
|
||||
REQUIRE(ToString(aare::DetectorType::Unknown) == "Unknown");
|
||||
}
|
||||
|
||||
TEST_CASE("String to enum") {
|
||||
REQUIRE(StringTo<aare::DetectorType>("Generic") ==
|
||||
aare::DetectorType::Generic);
|
||||
REQUIRE(StringTo<aare::DetectorType>("Eiger") == aare::DetectorType::Eiger);
|
||||
REQUIRE(StringTo<aare::DetectorType>("Gotthard") ==
|
||||
aare::DetectorType::Gotthard);
|
||||
REQUIRE(StringTo<aare::DetectorType>("Jungfrau") ==
|
||||
aare::DetectorType::Jungfrau);
|
||||
REQUIRE(StringTo<aare::DetectorType>("ChipTestBoard") ==
|
||||
aare::DetectorType::ChipTestBoard);
|
||||
REQUIRE(StringTo<aare::DetectorType>("Moench") ==
|
||||
aare::DetectorType::Moench);
|
||||
REQUIRE(StringTo<aare::DetectorType>("Mythen3") ==
|
||||
aare::DetectorType::Mythen3);
|
||||
REQUIRE(StringTo<aare::DetectorType>("Gotthard2") ==
|
||||
aare::DetectorType::Gotthard2);
|
||||
REQUIRE(StringTo<aare::DetectorType>("Xilinx_ChipTestBoard") ==
|
||||
aare::DetectorType::Xilinx_ChipTestBoard);
|
||||
REQUIRE(StringTo<aare::DetectorType>("Moench03") ==
|
||||
aare::DetectorType::Moench03);
|
||||
REQUIRE(StringTo<aare::DetectorType>("Moench03_old") ==
|
||||
aare::DetectorType::Moench03_old);
|
||||
REQUIRE(StringTo<aare::DetectorType>("Unknown") ==
|
||||
aare::DetectorType::Unknown);
|
||||
}
|
||||
|
||||
TEST_CASE("Enum values") {
|
||||
// Since some of the enums are written to file we need to make sure
|
||||
@@ -103,23 +58,3 @@ TEST_CASE("Basic ops on BitOffset"){
|
||||
REQUIRE(offset2==offset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TEST_CASE("cluster set and get data") {
|
||||
|
||||
// aare::DynamicCluster c2(33, 44, aare::Dtype(typeid(double)));
|
||||
// REQUIRE(c2.cluster_sizeX == 33);
|
||||
// REQUIRE(c2.cluster_sizeY == 44);
|
||||
// REQUIRE(c2.dt == aare::Dtype::DOUBLE);
|
||||
// double v = 3.14;
|
||||
// c2.set<double>(0, v);
|
||||
// double v2 = c2.get<double>(0);
|
||||
// REQUIRE(aare::compare_floats<double>(v, v2));
|
||||
|
||||
// c2.set<double>(33 * 44 - 1, 123.11);
|
||||
// double v3 = c2.get<double>(33 * 44 - 1);
|
||||
// REQUIRE(aare::compare_floats<double>(123.11, v3));
|
||||
|
||||
// REQUIRE_THROWS_AS(c2.set(0, 1), std::invalid_argument); // set int to
|
||||
// double
|
||||
// }
|
||||
276
src/to_string.cpp
Normal file
276
src/to_string.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
#include "to_string.hpp"
|
||||
|
||||
namespace aare {
|
||||
|
||||
template <> DetectorType string_to(const std::string &arg) {
|
||||
if (arg == "Generic")
|
||||
return DetectorType::Generic;
|
||||
if (arg == "Eiger")
|
||||
return DetectorType::Eiger;
|
||||
if (arg == "Gotthard")
|
||||
return DetectorType::Gotthard;
|
||||
if (arg == "Jungfrau")
|
||||
return DetectorType::Jungfrau;
|
||||
if (arg == "ChipTestBoard")
|
||||
return DetectorType::ChipTestBoard;
|
||||
if (arg == "Moench")
|
||||
return DetectorType::Moench;
|
||||
if (arg == "Mythen3")
|
||||
return DetectorType::Mythen3;
|
||||
if (arg == "Gotthard2")
|
||||
return DetectorType::Gotthard2;
|
||||
if (arg == "Xilinx_ChipTestBoard")
|
||||
return DetectorType::Xilinx_ChipTestBoard;
|
||||
|
||||
// Custom ones
|
||||
if (arg == "Moench03")
|
||||
return DetectorType::Moench03;
|
||||
if (arg == "Moench03_old")
|
||||
return DetectorType::Moench03_old;
|
||||
if (arg == "Unknown")
|
||||
return DetectorType::Unknown;
|
||||
|
||||
throw std::runtime_error("Could not decode detector from: \"" + arg + "\"");
|
||||
}
|
||||
|
||||
template <> TimingMode string_to(const std::string &arg) {
|
||||
if (arg == "auto")
|
||||
return TimingMode::Auto;
|
||||
if (arg == "trigger")
|
||||
return TimingMode::Trigger;
|
||||
throw std::runtime_error("Could not decode timing mode from: \"" + arg +
|
||||
"\"");
|
||||
}
|
||||
|
||||
template <> FrameDiscardPolicy string_to(const std::string &arg) {
|
||||
if (arg == "nodiscard")
|
||||
return FrameDiscardPolicy::NoDiscard;
|
||||
if (arg == "discard")
|
||||
return FrameDiscardPolicy::Discard;
|
||||
if (arg == "discardpartial")
|
||||
return FrameDiscardPolicy::DiscardPartial;
|
||||
throw std::runtime_error("Could not decode frame discard policy from: \"" +
|
||||
arg + "\"");
|
||||
}
|
||||
|
||||
|
||||
template <> DACIndex string_to(const std::string &arg) {
|
||||
if (arg == "dac 0")
|
||||
return DACIndex::DAC_0;
|
||||
else if (arg == "dac 1")
|
||||
return DACIndex::DAC_1;
|
||||
else if (arg == "dac 2")
|
||||
return DACIndex::DAC_2;
|
||||
else if (arg == "dac 3")
|
||||
return DACIndex::DAC_3;
|
||||
else if (arg == "dac 4")
|
||||
return DACIndex::DAC_4;
|
||||
else if (arg == "dac 5")
|
||||
return DACIndex::DAC_5;
|
||||
else if (arg == "dac 6")
|
||||
return DACIndex::DAC_6;
|
||||
else if (arg == "dac 7")
|
||||
return DACIndex::DAC_7;
|
||||
else if (arg == "dac 8")
|
||||
return DACIndex::DAC_8;
|
||||
else if (arg == "dac 9")
|
||||
return DACIndex::DAC_9;
|
||||
else if (arg == "dac 10")
|
||||
return DACIndex::DAC_10;
|
||||
else if (arg == "dac 11")
|
||||
return DACIndex::DAC_11;
|
||||
else if (arg == "dac 12")
|
||||
return DACIndex::DAC_12;
|
||||
else if (arg == "dac 13")
|
||||
return DACIndex::DAC_13;
|
||||
else if (arg == "dac 14")
|
||||
return DACIndex::DAC_14;
|
||||
else if (arg == "dac 15")
|
||||
return DACIndex::DAC_15;
|
||||
else if (arg == "dac 16")
|
||||
return DACIndex::DAC_16;
|
||||
else if (arg == "dac 17")
|
||||
return DACIndex::DAC_17;
|
||||
else if (arg == "vsvp")
|
||||
return DACIndex::VSVP;
|
||||
else if (arg == "vtrim")
|
||||
return DACIndex::VTRIM;
|
||||
else if (arg == "vrpreamp")
|
||||
return DACIndex::VRPREAMP;
|
||||
else if (arg == "vrshaper")
|
||||
return DACIndex::VRSHAPER;
|
||||
else if (arg == "vsvn")
|
||||
return DACIndex::VSVN;
|
||||
else if (arg == "vtgstv")
|
||||
return DACIndex::VTGSTV;
|
||||
else if (arg == "vcmp_ll")
|
||||
return DACIndex::VCMP_LL;
|
||||
else if (arg == "vcmp_lr")
|
||||
return DACIndex::VCMP_LR;
|
||||
else if (arg == "vcal")
|
||||
return DACIndex::VCAL;
|
||||
else if (arg == "vcmp_rl")
|
||||
return DACIndex::VCMP_RL;
|
||||
else if (arg == "rxb_rb")
|
||||
return DACIndex::RXB_RB;
|
||||
else if (arg == "rxb_lb")
|
||||
return DACIndex::RXB_LB;
|
||||
else if (arg == "vcmp_rr")
|
||||
return DACIndex::VCMP_RR;
|
||||
else if (arg == "vcp")
|
||||
return DACIndex::VCP;
|
||||
else if (arg == "vcn")
|
||||
return DACIndex::VCN;
|
||||
else if (arg == "vishaper")
|
||||
return DACIndex::VISHAPER;
|
||||
else if (arg == "vthreshold")
|
||||
return DACIndex::VTHRESHOLD;
|
||||
else if (arg == "vref_ds")
|
||||
return DACIndex::VREF_DS;
|
||||
else if (arg == "vout_cm")
|
||||
return DACIndex::VOUT_CM;
|
||||
else if (arg == "vin_cm")
|
||||
return DACIndex::VIN_CM;
|
||||
else if (arg == "vref_comp")
|
||||
return DACIndex::VREF_COMP;
|
||||
else if (arg == "vb_comp")
|
||||
return DACIndex::VB_COMP;
|
||||
else if (arg == "vdd_prot")
|
||||
return DACIndex::VDD_PROT;
|
||||
else if (arg == "vin_com")
|
||||
return DACIndex::VIN_COM;
|
||||
else if (arg == "vref_prech")
|
||||
return DACIndex::VREF_PRECH;
|
||||
else if (arg == "vb_pixbuf")
|
||||
return DACIndex::VB_PIXBUF;
|
||||
else if (arg == "vb_ds")
|
||||
return DACIndex::VB_DS;
|
||||
else if (arg == "vref_h_adc")
|
||||
return DACIndex::VREF_H_ADC;
|
||||
else if (arg == "vb_comp_fe")
|
||||
return DACIndex::VB_COMP_FE;
|
||||
else if (arg == "vb_comp_adc")
|
||||
return DACIndex::VB_COMP_ADC;
|
||||
else if (arg == "vcom_cds")
|
||||
return DACIndex::VCOM_CDS;
|
||||
else if (arg == "vref_rstore")
|
||||
return DACIndex::VREF_RSTORE;
|
||||
else if (arg == "vb_opa_1st")
|
||||
return DACIndex::VB_OPA_1ST;
|
||||
else if (arg == "vref_comp_fe")
|
||||
return DACIndex::VREF_COMP_FE;
|
||||
else if (arg == "vcom_adc1")
|
||||
return DACIndex::VCOM_ADC1;
|
||||
else if (arg == "vref_l_adc")
|
||||
return DACIndex::VREF_L_ADC;
|
||||
else if (arg == "vref_cds")
|
||||
return DACIndex::VREF_CDS;
|
||||
else if (arg == "vb_cs")
|
||||
return DACIndex::VB_CS;
|
||||
else if (arg == "vb_opa_fd")
|
||||
return DACIndex::VB_OPA_FD;
|
||||
else if (arg == "vcom_adc2")
|
||||
return DACIndex::VCOM_ADC2;
|
||||
else if (arg == "vcassh")
|
||||
return DACIndex::VCASSH;
|
||||
else if (arg == "vth2")
|
||||
return DACIndex::VTH2;
|
||||
else if (arg == "vrshaper_n")
|
||||
return DACIndex::VRSHAPER_N;
|
||||
else if (arg == "vipre_out")
|
||||
return DACIndex::VIPRE_OUT;
|
||||
else if (arg == "vth3")
|
||||
return DACIndex::VTH3;
|
||||
else if (arg == "vth1")
|
||||
return DACIndex::VTH1;
|
||||
else if (arg == "vicin")
|
||||
return DACIndex::VICIN;
|
||||
else if (arg == "vcas")
|
||||
return DACIndex::VCAS;
|
||||
else if (arg == "vcal_n")
|
||||
return DACIndex::VCAL_N;
|
||||
else if (arg == "vipre")
|
||||
return DACIndex::VIPRE;
|
||||
else if (arg == "vcal_p")
|
||||
return DACIndex::VCAL_P;
|
||||
else if (arg == "vdcsh")
|
||||
return DACIndex::VDCSH;
|
||||
else if (arg == "vbp_colbuf")
|
||||
return DACIndex::VBP_COLBUF;
|
||||
else if (arg == "vb_sda")
|
||||
return DACIndex::VB_SDA;
|
||||
else if (arg == "vcasc_sfp")
|
||||
return DACIndex::VCASC_SFP;
|
||||
else if (arg == "vipre_cds")
|
||||
return DACIndex::VIPRE_CDS;
|
||||
else if (arg == "ibias_sfp")
|
||||
return DACIndex::IBIAS_SFP;
|
||||
else if (arg == "trimbits")
|
||||
return DACIndex::TRIMBIT_SCAN;
|
||||
else if (arg == "highvoltage")
|
||||
return DACIndex::HIGH_VOLTAGE;
|
||||
else if (arg == "iodelay")
|
||||
return DACIndex::IO_DELAY;
|
||||
else if (arg == "temp_adc")
|
||||
return DACIndex::TEMPERATURE_ADC;
|
||||
else if (arg == "temp_fpga")
|
||||
return DACIndex::TEMPERATURE_FPGA;
|
||||
else if (arg == "temp_fpgaext")
|
||||
return DACIndex::TEMPERATURE_FPGAEXT;
|
||||
else if (arg == "temp_10ge")
|
||||
return DACIndex::TEMPERATURE_10GE;
|
||||
else if (arg == "temp_dcdc")
|
||||
return DACIndex::TEMPERATURE_DCDC;
|
||||
else if (arg == "temp_sodl")
|
||||
return DACIndex::TEMPERATURE_SODL;
|
||||
else if (arg == "temp_sodr")
|
||||
return DACIndex::TEMPERATURE_SODR;
|
||||
else if (arg == "temp_fpgafl")
|
||||
return DACIndex::TEMPERATURE_FPGA2;
|
||||
else if (arg == "temp_fpgafr")
|
||||
return DACIndex::TEMPERATURE_FPGA3;
|
||||
else if (arg == "temp_slowadc")
|
||||
return DACIndex::SLOW_ADC_TEMP;
|
||||
else
|
||||
throw std::invalid_argument("Could not decode DACIndex from: \"" + arg +
|
||||
"\"");
|
||||
}
|
||||
|
||||
|
||||
std::string remove_unit(std::string &str) {
|
||||
auto it = str.begin();
|
||||
while (it != str.end()) {
|
||||
if (std::isalpha(*it)) {
|
||||
// Check if this is scientific notation (e or E followed by optional sign and digits)
|
||||
if (((*it == 'e' || *it == 'E') && (it + 1) != str.end())) {
|
||||
auto next = it + 1;
|
||||
// Skip optional sign
|
||||
if (*next == '+' || *next == '-') {
|
||||
++next;
|
||||
}
|
||||
// Check if followed by at least one digit
|
||||
if (next != str.end() && std::isdigit(*next)) {
|
||||
// This is scientific notation, continue scanning
|
||||
it = next;
|
||||
while (it != str.end() && std::isdigit(*it)) {
|
||||
++it;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Not scientific notation, this is the start of the unit
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
auto pos = it - str.begin();
|
||||
auto unit = str.substr(pos);
|
||||
str.erase(it, end(str));
|
||||
// Strip trailing whitespace
|
||||
while (!str.empty() && std::isspace(str.back())) {
|
||||
str.pop_back();
|
||||
}
|
||||
return unit;
|
||||
}
|
||||
|
||||
} // namespace aare
|
||||
90
src/to_string.hpp
Normal file
90
src/to_string.hpp
Normal file
@@ -0,0 +1,90 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/*
|
||||
*The file to_string.hpp contains conversion to and from string for various aare
|
||||
* types. It is intentionally not a part of the public API.
|
||||
* Only include the conversion that are actually needed!!!
|
||||
*/
|
||||
|
||||
#include "aare/defs.hpp" //enums
|
||||
|
||||
#include <chrono> //time conversions
|
||||
|
||||
namespace aare {
|
||||
|
||||
|
||||
std::string remove_unit(std::string &str);
|
||||
|
||||
template <typename T>
|
||||
T string_to(const std::string &t, const std::string &unit) {
|
||||
double tval{0};
|
||||
try {
|
||||
tval = std::stod(t);
|
||||
} catch (const std::invalid_argument &e) {
|
||||
throw std::runtime_error("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 std::runtime_error(
|
||||
"Invalid unit in conversion from string to std::chrono::duration");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if T has a constructor that takes a string, lets use it.
|
||||
// template <class T> T string_to(const std::string &arg) { return T{arg}; }
|
||||
template <typename T> T string_to(const std::string &arg) {
|
||||
std::string tmp{arg};
|
||||
auto unit = remove_unit(tmp);
|
||||
return string_to<T>(tmp, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a string to DetectorType
|
||||
* @param name string representation of the DetectorType
|
||||
* @return DetectorType
|
||||
* @throw runtime_error if the string does not match any DetectorType
|
||||
*/
|
||||
template <> DetectorType string_to(const std::string &arg);
|
||||
|
||||
/**
|
||||
* @brief Convert a string to TimingMode
|
||||
* @param mode string representation of the TimingMode
|
||||
* @return TimingMode
|
||||
* @throw runtime_error if the string does not match any TimingMode
|
||||
*/
|
||||
template <> TimingMode string_to(const std::string &arg);
|
||||
|
||||
/**
|
||||
* @brief Convert a string to FrameDiscardPolicy
|
||||
* @param mode string representation of the FrameDiscardPolicy
|
||||
* @return FrameDiscardPolicy
|
||||
* @throw runtime_error if the string does not match any FrameDiscardPolicy
|
||||
*/
|
||||
template <> FrameDiscardPolicy string_to(const std::string &arg);
|
||||
|
||||
/**
|
||||
* @brief Convert a string to a DACIndex
|
||||
* @param arg string representation of the dacIndex
|
||||
* @return DACIndex
|
||||
* @throw invalid argument error if the string does not match any DACIndex
|
||||
*/
|
||||
template <> DACIndex string_to(const std::string &arg);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace aare
|
||||
266
src/to_string.test.cpp
Normal file
266
src/to_string.test.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
#include "aare/defs.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "to_string.hpp"
|
||||
using aare::string_to;
|
||||
|
||||
TEST_CASE("DetectorType string to enum") {
|
||||
REQUIRE(string_to<aare::DetectorType>("Generic") ==
|
||||
aare::DetectorType::Generic);
|
||||
REQUIRE(string_to<aare::DetectorType>("Eiger") == aare::DetectorType::Eiger);
|
||||
REQUIRE(string_to<aare::DetectorType>("Gotthard") ==
|
||||
aare::DetectorType::Gotthard);
|
||||
REQUIRE(string_to<aare::DetectorType>("Jungfrau") ==
|
||||
aare::DetectorType::Jungfrau);
|
||||
REQUIRE(string_to<aare::DetectorType>("ChipTestBoard") ==
|
||||
aare::DetectorType::ChipTestBoard);
|
||||
REQUIRE(string_to<aare::DetectorType>("Moench") ==
|
||||
aare::DetectorType::Moench);
|
||||
REQUIRE(string_to<aare::DetectorType>("Mythen3") ==
|
||||
aare::DetectorType::Mythen3);
|
||||
REQUIRE(string_to<aare::DetectorType>("Gotthard2") ==
|
||||
aare::DetectorType::Gotthard2);
|
||||
REQUIRE(string_to<aare::DetectorType>("Xilinx_ChipTestBoard") ==
|
||||
aare::DetectorType::Xilinx_ChipTestBoard);
|
||||
REQUIRE(string_to<aare::DetectorType>("Moench03") ==
|
||||
aare::DetectorType::Moench03);
|
||||
REQUIRE(string_to<aare::DetectorType>("Moench03_old") ==
|
||||
aare::DetectorType::Moench03_old);
|
||||
REQUIRE(string_to<aare::DetectorType>("Unknown") ==
|
||||
aare::DetectorType::Unknown);
|
||||
REQUIRE_THROWS(string_to<aare::DetectorType>("invalid_detector"));
|
||||
}
|
||||
|
||||
TEST_CASE("TimingMode string to enum") {
|
||||
REQUIRE(string_to<aare::TimingMode>("auto") == aare::TimingMode::Auto);
|
||||
REQUIRE(string_to<aare::TimingMode>("trigger") == aare::TimingMode::Trigger);
|
||||
REQUIRE_THROWS(string_to<aare::TimingMode>("invalid_mode"));
|
||||
}
|
||||
|
||||
TEST_CASE("FrameDiscardPolicy string to enum") {
|
||||
REQUIRE(string_to<aare::FrameDiscardPolicy>("nodiscard") ==
|
||||
aare::FrameDiscardPolicy::NoDiscard);
|
||||
REQUIRE(string_to<aare::FrameDiscardPolicy>("discard") ==
|
||||
aare::FrameDiscardPolicy::Discard);
|
||||
REQUIRE(string_to<aare::FrameDiscardPolicy>("discardpartial") ==
|
||||
aare::FrameDiscardPolicy::DiscardPartial);
|
||||
REQUIRE_THROWS(string_to<aare::FrameDiscardPolicy>("invalid_policy"));
|
||||
}
|
||||
|
||||
TEST_CASE("DACIndex string to enum") {
|
||||
// Numeric DACs
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 0") == aare::DACIndex::DAC_0);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 1") == aare::DACIndex::DAC_1);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 2") == aare::DACIndex::DAC_2);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 3") == aare::DACIndex::DAC_3);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 4") == aare::DACIndex::DAC_4);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 5") == aare::DACIndex::DAC_5);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 6") == aare::DACIndex::DAC_6);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 7") == aare::DACIndex::DAC_7);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 8") == aare::DACIndex::DAC_8);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 9") == aare::DACIndex::DAC_9);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 10") == aare::DACIndex::DAC_10);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 11") == aare::DACIndex::DAC_11);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 12") == aare::DACIndex::DAC_12);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 13") == aare::DACIndex::DAC_13);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 14") == aare::DACIndex::DAC_14);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 15") == aare::DACIndex::DAC_15);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 16") == aare::DACIndex::DAC_16);
|
||||
REQUIRE(string_to<aare::DACIndex>("dac 17") == aare::DACIndex::DAC_17);
|
||||
|
||||
// Named DACs
|
||||
REQUIRE(string_to<aare::DACIndex>("vsvp") == aare::DACIndex::VSVP);
|
||||
REQUIRE(string_to<aare::DACIndex>("vtrim") == aare::DACIndex::VTRIM);
|
||||
REQUIRE(string_to<aare::DACIndex>("vrpreamp") == aare::DACIndex::VRPREAMP);
|
||||
REQUIRE(string_to<aare::DACIndex>("vrshaper") == aare::DACIndex::VRSHAPER);
|
||||
REQUIRE(string_to<aare::DACIndex>("vsvn") == aare::DACIndex::VSVN);
|
||||
REQUIRE(string_to<aare::DACIndex>("vtgstv") == aare::DACIndex::VTGSTV);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcmp_ll") == aare::DACIndex::VCMP_LL);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcmp_lr") == aare::DACIndex::VCMP_LR);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcal") == aare::DACIndex::VCAL);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcmp_rl") == aare::DACIndex::VCMP_RL);
|
||||
REQUIRE(string_to<aare::DACIndex>("rxb_rb") == aare::DACIndex::RXB_RB);
|
||||
REQUIRE(string_to<aare::DACIndex>("rxb_lb") == aare::DACIndex::RXB_LB);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcmp_rr") == aare::DACIndex::VCMP_RR);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcp") == aare::DACIndex::VCP);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcn") == aare::DACIndex::VCN);
|
||||
REQUIRE(string_to<aare::DACIndex>("vishaper") == aare::DACIndex::VISHAPER);
|
||||
REQUIRE(string_to<aare::DACIndex>("vthreshold") == aare::DACIndex::VTHRESHOLD);
|
||||
REQUIRE(string_to<aare::DACIndex>("vref_ds") == aare::DACIndex::VREF_DS);
|
||||
REQUIRE(string_to<aare::DACIndex>("vout_cm") == aare::DACIndex::VOUT_CM);
|
||||
REQUIRE(string_to<aare::DACIndex>("vin_cm") == aare::DACIndex::VIN_CM);
|
||||
REQUIRE(string_to<aare::DACIndex>("vref_comp") == aare::DACIndex::VREF_COMP);
|
||||
REQUIRE(string_to<aare::DACIndex>("vb_comp") == aare::DACIndex::VB_COMP);
|
||||
REQUIRE(string_to<aare::DACIndex>("vdd_prot") == aare::DACIndex::VDD_PROT);
|
||||
REQUIRE(string_to<aare::DACIndex>("vin_com") == aare::DACIndex::VIN_COM);
|
||||
REQUIRE(string_to<aare::DACIndex>("vref_prech") == aare::DACIndex::VREF_PRECH);
|
||||
REQUIRE(string_to<aare::DACIndex>("vb_pixbuf") == aare::DACIndex::VB_PIXBUF);
|
||||
REQUIRE(string_to<aare::DACIndex>("vb_ds") == aare::DACIndex::VB_DS);
|
||||
REQUIRE(string_to<aare::DACIndex>("vref_h_adc") == aare::DACIndex::VREF_H_ADC);
|
||||
REQUIRE(string_to<aare::DACIndex>("vb_comp_fe") == aare::DACIndex::VB_COMP_FE);
|
||||
REQUIRE(string_to<aare::DACIndex>("vb_comp_adc") == aare::DACIndex::VB_COMP_ADC);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcom_cds") == aare::DACIndex::VCOM_CDS);
|
||||
REQUIRE(string_to<aare::DACIndex>("vref_rstore") == aare::DACIndex::VREF_RSTORE);
|
||||
REQUIRE(string_to<aare::DACIndex>("vb_opa_1st") == aare::DACIndex::VB_OPA_1ST);
|
||||
REQUIRE(string_to<aare::DACIndex>("vref_comp_fe") == aare::DACIndex::VREF_COMP_FE);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcom_adc1") == aare::DACIndex::VCOM_ADC1);
|
||||
REQUIRE(string_to<aare::DACIndex>("vref_l_adc") == aare::DACIndex::VREF_L_ADC);
|
||||
REQUIRE(string_to<aare::DACIndex>("vref_cds") == aare::DACIndex::VREF_CDS);
|
||||
REQUIRE(string_to<aare::DACIndex>("vb_cs") == aare::DACIndex::VB_CS);
|
||||
REQUIRE(string_to<aare::DACIndex>("vb_opa_fd") == aare::DACIndex::VB_OPA_FD);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcom_adc2") == aare::DACIndex::VCOM_ADC2);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcassh") == aare::DACIndex::VCASSH);
|
||||
REQUIRE(string_to<aare::DACIndex>("vth2") == aare::DACIndex::VTH2);
|
||||
REQUIRE(string_to<aare::DACIndex>("vrshaper_n") == aare::DACIndex::VRSHAPER_N);
|
||||
REQUIRE(string_to<aare::DACIndex>("vipre_out") == aare::DACIndex::VIPRE_OUT);
|
||||
REQUIRE(string_to<aare::DACIndex>("vth3") == aare::DACIndex::VTH3);
|
||||
REQUIRE(string_to<aare::DACIndex>("vth1") == aare::DACIndex::VTH1);
|
||||
REQUIRE(string_to<aare::DACIndex>("vicin") == aare::DACIndex::VICIN);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcas") == aare::DACIndex::VCAS);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcal_n") == aare::DACIndex::VCAL_N);
|
||||
REQUIRE(string_to<aare::DACIndex>("vipre") == aare::DACIndex::VIPRE);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcal_p") == aare::DACIndex::VCAL_P);
|
||||
REQUIRE(string_to<aare::DACIndex>("vdcsh") == aare::DACIndex::VDCSH);
|
||||
REQUIRE(string_to<aare::DACIndex>("vbp_colbuf") == aare::DACIndex::VBP_COLBUF);
|
||||
REQUIRE(string_to<aare::DACIndex>("vb_sda") == aare::DACIndex::VB_SDA);
|
||||
REQUIRE(string_to<aare::DACIndex>("vcasc_sfp") == aare::DACIndex::VCASC_SFP);
|
||||
REQUIRE(string_to<aare::DACIndex>("vipre_cds") == aare::DACIndex::VIPRE_CDS);
|
||||
REQUIRE(string_to<aare::DACIndex>("ibias_sfp") == aare::DACIndex::IBIAS_SFP);
|
||||
REQUIRE(string_to<aare::DACIndex>("trimbits") == aare::DACIndex::TRIMBIT_SCAN);
|
||||
REQUIRE(string_to<aare::DACIndex>("highvoltage") == aare::DACIndex::HIGH_VOLTAGE);
|
||||
REQUIRE(string_to<aare::DACIndex>("iodelay") == aare::DACIndex::IO_DELAY);
|
||||
REQUIRE(string_to<aare::DACIndex>("temp_adc") == aare::DACIndex::TEMPERATURE_ADC);
|
||||
REQUIRE(string_to<aare::DACIndex>("temp_fpga") == aare::DACIndex::TEMPERATURE_FPGA);
|
||||
REQUIRE(string_to<aare::DACIndex>("temp_fpgaext") == aare::DACIndex::TEMPERATURE_FPGAEXT);
|
||||
REQUIRE(string_to<aare::DACIndex>("temp_10ge") == aare::DACIndex::TEMPERATURE_10GE);
|
||||
REQUIRE(string_to<aare::DACIndex>("temp_dcdc") == aare::DACIndex::TEMPERATURE_DCDC);
|
||||
REQUIRE(string_to<aare::DACIndex>("temp_sodl") == aare::DACIndex::TEMPERATURE_SODL);
|
||||
REQUIRE(string_to<aare::DACIndex>("temp_sodr") == aare::DACIndex::TEMPERATURE_SODR);
|
||||
REQUIRE(string_to<aare::DACIndex>("temp_fpgafl") == aare::DACIndex::TEMPERATURE_FPGA2);
|
||||
REQUIRE(string_to<aare::DACIndex>("temp_fpgafr") == aare::DACIndex::TEMPERATURE_FPGA3);
|
||||
REQUIRE(string_to<aare::DACIndex>("temp_slowadc") == aare::DACIndex::SLOW_ADC_TEMP);
|
||||
|
||||
REQUIRE_THROWS(string_to<aare::DACIndex>("invalid_dac"));
|
||||
}
|
||||
|
||||
TEST_CASE("Remove unit from string") {
|
||||
using aare::remove_unit;
|
||||
|
||||
// Test basic numeric value with unit
|
||||
{
|
||||
std::string input = "123.45 V";
|
||||
std::string unit = remove_unit(input);
|
||||
REQUIRE(unit == "V");
|
||||
REQUIRE(input == "123.45");
|
||||
}
|
||||
|
||||
// Test integer value with unit
|
||||
{
|
||||
std::string input = "42 Hz";
|
||||
std::string unit = remove_unit(input);
|
||||
REQUIRE(unit == "Hz");
|
||||
REQUIRE(input == "42");
|
||||
}
|
||||
|
||||
// Test negative value with unit
|
||||
{
|
||||
std::string input = "-50.5 mV";
|
||||
std::string unit = remove_unit(input);
|
||||
REQUIRE(unit == "mV");
|
||||
REQUIRE(input == "-50.5");
|
||||
}
|
||||
|
||||
// Test value with no unit (only numbers)
|
||||
{
|
||||
std::string input = "123.45";
|
||||
std::string unit = remove_unit(input);
|
||||
REQUIRE(unit == "");
|
||||
REQUIRE(input == "123.45");
|
||||
}
|
||||
|
||||
// Test value with only unit (letters at start)
|
||||
{
|
||||
std::string input = "kHz";
|
||||
std::string unit = remove_unit(input);
|
||||
REQUIRE(unit == "kHz");
|
||||
REQUIRE(input == "");
|
||||
}
|
||||
|
||||
// Test with multiple word units
|
||||
{
|
||||
std::string input = "100 degrees Celsius";
|
||||
std::string unit = remove_unit(input);
|
||||
REQUIRE(unit == "degrees Celsius");
|
||||
REQUIRE(input == "100");
|
||||
}
|
||||
|
||||
// Test with scientific notation
|
||||
{
|
||||
std::string input = "1.23e-5 A";
|
||||
std::string unit = remove_unit(input);
|
||||
REQUIRE(unit == "A");
|
||||
REQUIRE(input == "1.23e-5");
|
||||
}
|
||||
|
||||
// Another test with scientific notation
|
||||
{
|
||||
std::string input = "-4.56E6 m/s";
|
||||
std::string unit = remove_unit(input);
|
||||
REQUIRE(unit == "m/s");
|
||||
REQUIRE(input == "-4.56E6");
|
||||
}
|
||||
|
||||
// Test with scientific notation uppercase
|
||||
{
|
||||
std::string input = "5.67E+3 Hz";
|
||||
std::string unit = remove_unit(input);
|
||||
REQUIRE(unit == "Hz");
|
||||
REQUIRE(input == "5.67E+3");
|
||||
}
|
||||
|
||||
// Test with leading zeros
|
||||
{
|
||||
std::string input = "00123 ohm";
|
||||
std::string unit = remove_unit(input);
|
||||
REQUIRE(unit == "ohm");
|
||||
REQUIRE(input == "00123");
|
||||
}
|
||||
|
||||
// Test with leading zeros no space
|
||||
{
|
||||
std::string input = "00123ohm";
|
||||
std::string unit = remove_unit(input);
|
||||
REQUIRE(unit == "ohm");
|
||||
REQUIRE(input == "00123");
|
||||
}
|
||||
|
||||
// Test empty string
|
||||
{
|
||||
std::string input = "";
|
||||
std::string unit = remove_unit(input);
|
||||
REQUIRE(unit == "");
|
||||
REQUIRE(input == "");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Conversions from time string to chrono durations") {
|
||||
using namespace std::chrono;
|
||||
using aare::string_to;
|
||||
|
||||
REQUIRE(string_to<nanoseconds>("100 ns") == nanoseconds(100));
|
||||
REQUIRE(string_to<nanoseconds>("1s") == nanoseconds(1000000000));
|
||||
REQUIRE(string_to<microseconds>("200 us") == microseconds(200));
|
||||
REQUIRE(string_to<milliseconds>("300 ms") == milliseconds(300));
|
||||
REQUIRE(string_to<seconds>("5 s") == seconds(5));
|
||||
|
||||
REQUIRE(string_to<nanoseconds>("1.5 us") == nanoseconds(1500));
|
||||
REQUIRE(string_to<microseconds>("2.5 ms") == microseconds(2500));
|
||||
REQUIRE(string_to<milliseconds>("3.5 s") == milliseconds(3500));
|
||||
|
||||
REQUIRE(string_to<seconds>("2") == seconds(2)); // No unit defaults to seconds
|
||||
|
||||
REQUIRE_THROWS(string_to<seconds>("10 min")); // Unsupported unit
|
||||
}
|
||||
Reference in New Issue
Block a user