Compare commits

..

3 Commits

Author SHA1 Message Date
Khalil Ferjaoui
e412e72e5b Add test script to ensure no leaks in PC queue
All checks were successful
Build on RHEL8 / build (push) Successful in 3m15s
Build on RHEL9 / build (push) Successful in 3m34s
2025-09-15 10:15:42 +02:00
Erik Fröjdh
9008393955 Merge branch 'main' into fix/spsc-move-assign-leak
All checks were successful
Build on RHEL8 / build (push) Successful in 3m13s
Build on RHEL9 / build (push) Successful in 3m21s
2025-09-12 08:47:05 +02:00
Khalil Ferjaoui
a8b87e6b53 Fix: make ProducerConsumerQueue move-safe 2025-09-04 17:55:08 +02:00
12 changed files with 192 additions and 423 deletions

View File

@@ -388,7 +388,7 @@ set(SourceFiles
${CMAKE_CURRENT_SOURCE_DIR}/src/RawSubFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/task.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/ifstream_helpers.cpp
)
)
add_library(aare_core STATIC ${SourceFiles})
target_include_directories(aare_core PUBLIC
@@ -412,8 +412,6 @@ target_link_libraries(
)
set_property(TARGET aare_core PROPERTY POSITION_INDEPENDENT_CODE ON)
if(AARE_TESTS)
target_compile_definitions(aare_core PRIVATE AARE_TESTS)
endif()
@@ -433,6 +431,10 @@ set_target_properties(aare_core PROPERTIES
PUBLIC_HEADER "${PUBLICHEADERS}"
)
if (AARE_PYTHON_BINDINGS)
set_property(TARGET aare_core PROPERTY POSITION_INDEPENDENT_CODE ON)
endif()
if(AARE_TESTS)
set(TestSources
${CMAKE_CURRENT_SOURCE_DIR}/src/algorithm.test.cpp
@@ -463,7 +465,6 @@ if(AARE_TESTS)
target_sources(tests PRIVATE ${TestSources} )
endif()
if(AARE_MASTER_PROJECT)
install(TARGETS aare_core aare_compiler_flags
EXPORT "${TARGETS_EXPORT_NAME}"
@@ -473,6 +474,7 @@ if(AARE_MASTER_PROJECT)
)
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_INSTALL_RPATH $ORIGIN)
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)

View File

@@ -1,10 +1,5 @@
# Release notes
### 2025.10.1
Bugfixes:
- File supports reading new master json file format (multiple ROI's not supported yet)
### 2025.8.22
@@ -48,6 +43,3 @@ Bugfixes:

View File

@@ -93,12 +93,6 @@ class NDView : public ArrayExpr<NDView<T, Ndim>, Ndim> {
: buffer_(buffer), strides_(c_strides<Ndim>(shape)), shape_(shape),
size_(std::accumulate(std::begin(shape), std::end(shape), 1,
std::multiplies<>())) {}
// stride-aware constructor
NDView(T* buffer, std::array<ssize_t, Ndim> shape, std::array<ssize_t, Ndim> strides)
: buffer_(buffer), shape_(shape), strides_(strides),
size_(std::accumulate(std::begin(shape), std::end(shape), 1,
std::multiplies<>())) {}
template <typename... Ix>
std::enable_if_t<sizeof...(Ix) == Ndim, T &> operator()(Ix... index) {

View File

@@ -45,19 +45,63 @@ template <class T> struct ProducerConsumerQueue {
ProducerConsumerQueue(const ProducerConsumerQueue &) = delete;
ProducerConsumerQueue &operator=(const ProducerConsumerQueue &) = delete;
ProducerConsumerQueue(ProducerConsumerQueue &&other) {
// ProducerConsumerQueue(ProducerConsumerQueue &&other) {
// size_ = other.size_;
// records_ = other.records_;
// other.records_ = nullptr;
// readIndex_ = other.readIndex_.load(std::memory_order_acquire);
// writeIndex_ = other.writeIndex_.load(std::memory_order_acquire);
// }
ProducerConsumerQueue(ProducerConsumerQueue&& other) noexcept {
size_ = other.size_;
records_ = other.records_;
readIndex_.store(other.readIndex_.load(std::memory_order_acquire),
std::memory_order_relaxed);
writeIndex_.store(other.writeIndex_.load(std::memory_order_acquire),
std::memory_order_relaxed);
other.records_ = nullptr;
readIndex_ = other.readIndex_.load(std::memory_order_acquire);
writeIndex_ = other.writeIndex_.load(std::memory_order_acquire);
other.size_ = 0;
other.readIndex_.store(0, std::memory_order_relaxed);
other.writeIndex_.store(0, std::memory_order_relaxed);
}
ProducerConsumerQueue &operator=(ProducerConsumerQueue &&other) {
// ProducerConsumerQueue &operator=(ProducerConsumerQueue &&other) {
// size_ = other.size_;
// records_ = other.records_;
// other.records_ = nullptr;
// readIndex_ = other.readIndex_.load(std::memory_order_acquire);
// writeIndex_ = other.writeIndex_.load(std::memory_order_acquire);
// return *this;
// }
ProducerConsumerQueue& operator=(ProducerConsumerQueue&& other) {
if (this == &other) return *this;
//Destroy existing elements and free old storage
if (records_ && !std::is_trivially_destructible<T>::value) {
size_t r = readIndex_.load(std::memory_order_relaxed);
size_t w = writeIndex_.load(std::memory_order_relaxed);
while (r != w) {
records_[r].~T();
if (++r == size_) r = 0;
}
}
std::free(records_);
//Steal other's state
size_ = other.size_;
records_ = other.records_;
readIndex_.store( other.readIndex_.load(std::memory_order_acquire), std::memory_order_relaxed );
writeIndex_.store( other.writeIndex_.load(std::memory_order_acquire), std::memory_order_relaxed );
//leave 'other' empty and harmless
other.records_ = nullptr;
readIndex_ = other.readIndex_.load(std::memory_order_acquire);
writeIndex_ = other.writeIndex_.load(std::memory_order_acquire);
other.size_ = 0;
other.readIndex_.store(0, std::memory_order_relaxed);
other.writeIndex_.store(0, std::memory_order_relaxed);
return *this;
}

View File

@@ -42,16 +42,14 @@ class RawFileNameComponents {
class ScanParameters {
bool m_enabled = false;
DACIndex m_dac{};
std::string m_dac;
int m_start = 0;
int m_stop = 0;
int m_step = 0;
int64_t m_settleTime = 0; // [ns]
// TODO! add settleTime, requires string to time conversion
public:
ScanParameters(const std::string &par);
ScanParameters(const bool enabled, const DACIndex dac, const int start,
const int stop, const int step, const int64_t settleTime);
ScanParameters() = default;
ScanParameters(const ScanParameters &) = default;
ScanParameters &operator=(const ScanParameters &) = default;
@@ -59,9 +57,8 @@ class ScanParameters {
int start() const;
int stop() const;
int step() const;
DACIndex dac() const;
const std::string &dac() const;
bool enabled() const;
int64_t settleTime() const;
void increment_stop();
};

View File

@@ -215,122 +215,6 @@ enum class DetectorType {
Unknown
};
/**
* @brief Enum class to define the Digital to Analog converter
* The values are the same as in slsDetectorPackage
*/
enum DACIndex {
DAC_0,
DAC_1,
DAC_2,
DAC_3,
DAC_4,
DAC_5,
DAC_6,
DAC_7,
DAC_8,
DAC_9,
DAC_10,
DAC_11,
DAC_12,
DAC_13,
DAC_14,
DAC_15,
DAC_16,
DAC_17,
VSVP,
VTRIM,
VRPREAMP,
VRSHAPER,
VSVN,
VTGSTV,
VCMP_LL,
VCMP_LR,
VCAL,
VCMP_RL,
RXB_RB,
RXB_LB,
VCMP_RR,
VCP,
VCN,
VISHAPER,
VTHRESHOLD,
IO_DELAY,
VREF_DS,
VOUT_CM,
VIN_CM,
VREF_COMP,
VB_COMP,
VDD_PROT,
VIN_COM,
VREF_PRECH,
VB_PIXBUF,
VB_DS,
VREF_H_ADC,
VB_COMP_FE,
VB_COMP_ADC,
VCOM_CDS,
VREF_RSTORE,
VB_OPA_1ST,
VREF_COMP_FE,
VCOM_ADC1,
VREF_L_ADC,
VREF_CDS,
VB_CS,
VB_OPA_FD,
VCOM_ADC2,
VCASSH,
VTH2,
VRSHAPER_N,
VIPRE_OUT,
VTH3,
VTH1,
VICIN,
VCAS,
VCAL_N,
VIPRE,
VCAL_P,
VDCSH,
VBP_COLBUF,
VB_SDA,
VCASC_SFP,
VIPRE_CDS,
IBIAS_SFP,
ADC_VPP,
HIGH_VOLTAGE,
TEMPERATURE_ADC,
TEMPERATURE_FPGA,
TEMPERATURE_FPGAEXT,
TEMPERATURE_10GE,
TEMPERATURE_DCDC,
TEMPERATURE_SODL,
TEMPERATURE_SODR,
TEMPERATURE_FPGA2,
TEMPERATURE_FPGA3,
TRIMBIT_SCAN,
V_POWER_A = 100,
V_POWER_B = 101,
V_POWER_C = 102,
V_POWER_D = 103,
V_POWER_IO = 104,
V_POWER_CHIP = 105,
I_POWER_A = 106,
I_POWER_B = 107,
I_POWER_C = 108,
I_POWER_D = 109,
I_POWER_IO = 110,
V_LIMIT = 111,
SLOW_ADC0 = 1000,
SLOW_ADC1,
SLOW_ADC2,
SLOW_ADC3,
SLOW_ADC4,
SLOW_ADC5,
SLOW_ADC6,
SLOW_ADC7,
SLOW_ADC_TEMP
};
enum class TimingMode { Auto, Trigger };
enum class FrameDiscardPolicy { NoDiscard, Discard, DiscardPartial };
@@ -347,15 +231,6 @@ 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);
constexpr uint16_t ADC_MASK = 0x3FFF; // used to mask out the gain bits in Jungfrau
} // namespace aare

20
src/Makefile Normal file
View File

@@ -0,0 +1,20 @@
# Makefile
CXX := g++
CXXFLAGS := -std=c++17 -O0 -g
INCLUDE := -I../include
SRC := ProducerConsumerQueue.test.cpp
BIN := test_pcq
.PHONY: all clean run
all: $(BIN)
$(BIN): $(SRC)
$(CXX) $(CXXFLAGS) $(INCLUDE) $< -o $@
run: $(BIN)
./$(BIN)
clean:
$(RM) $(BIN)

View File

@@ -0,0 +1,83 @@
#include <iostream>
#include <atomic>
#include <string>
#include <vector>
#include "aare/ProducerConsumerQueue.hpp"
struct Tracker {
static std::atomic<int> ctors;
static std::atomic<int> dtors;
static std::atomic<int> moves;
static std::atomic<int> live;
std::string tag;
std::vector<int> buf;
Tracker() = delete;
explicit Tracker(int id)
: tag("T" + std::to_string(id)), buf(1 << 18, id)
{
++ctors; ++live;
}
Tracker(Tracker&& other) noexcept
: tag(std::move(other.tag)), buf(std::move(other.buf))
{
++moves;
++ctors;
++live;
}
Tracker& operator=(Tracker&&) = delete;
Tracker(const Tracker&) = delete;
Tracker& operator=(const Tracker&) = delete;
~Tracker()
{
++dtors; --live;
}
};
std::atomic<int> Tracker::ctors{0};
std::atomic<int> Tracker::dtors{0};
std::atomic<int> Tracker::moves{0};
std::atomic<int> Tracker::live{0};
int main() {
using Queue = aare::ProducerConsumerQueue<Tracker>;
// Scope make sure destructors have ran before we check the counters.
{
Queue q1(8);
Queue q2(8);
for (int i = 0; i < 3; ++i) q2.write(Tracker(100 + i));
for (int i = 0; i < 5; ++i) q1.write(Tracker(200 + i));
q2 = std::move(q1);
Tracker tmp(9999);
if (auto* p = q2.frontPtr())
{
(void)p;
}
}
std::cout << "ctors=" << Tracker::ctors.load()
<< " dtors=" << Tracker::dtors.load()
<< " moves=" << Tracker::moves.load()
<< " live=" << Tracker::live.load()
<< "\n";
bool ok = (Tracker::ctors.load() == Tracker::dtors.load()) && (Tracker::live.load() == 0);
if (!ok)
{
std::cerr << "Leak or skipped destructors detected (move-assignment bug)\n";
return 1;
}
std::cout << "No leaks; move-assignment cleans up correctly\n";
return 0;
}

View File

@@ -99,8 +99,7 @@ TEST_CASE("Read data from a jungfrau 500k single port raw file",
}
TEST_CASE("Read frame numbers from a raw file", "[.with-data]") {
auto fpath =
test_data_path() / "raw/eiger" / "eiger_500k_16bit_master_0.json";
auto fpath = test_data_path() / "raw/eiger" / "eiger_500k_16bit_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
// we know this file has 3 frames with frame numbers 14, 15, 16
@@ -289,7 +288,8 @@ TEST_CASE("check find_geometry", "[.with-data]") {
}
}
TEST_CASE("Open multi module file with ROI", "[.with-data]") {
TEST_CASE("Open multi module file with ROI",
"[.with-data]") {
auto fpath = test_data_path() / "raw/SingleChipROI/Data_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
@@ -319,4 +319,4 @@ TEST_CASE("Read file with unordered frames", "[.with-data]") {
REQUIRE(std::filesystem::exists(fpath));
File f(fpath);
REQUIRE_THROWS((f.read_frame()));
}
}

View File

@@ -64,12 +64,6 @@ const std::string &RawFileNameComponents::base_name() const {
const std::string &RawFileNameComponents::ext() const { return m_ext; }
int RawFileNameComponents::file_index() const { return m_file_index; }
ScanParameters::ScanParameters(const bool enabled, const DACIndex dac,
const int start, const int stop, const int step,
const int64_t settleTime)
: m_enabled(enabled), m_dac(dac), m_start(start), m_stop(stop),
m_step(step), m_settleTime(settleTime){};
// "[enabled\ndac dac 4\nstart 500\nstop 2200\nstep 5\nsettleTime 100us\n]"
ScanParameters::ScanParameters(const std::string &par) {
std::istringstream iss(par.substr(1, par.size() - 2));
@@ -78,7 +72,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 = 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) {
@@ -93,9 +87,8 @@ int ScanParameters::start() const { return m_start; }
int ScanParameters::stop() const { return m_stop; }
void ScanParameters::increment_stop() { m_stop += 1; }
int ScanParameters::step() const { return m_step; }
DACIndex ScanParameters::dac() const { return m_dac; }
const std::string &ScanParameters::dac() const { return m_dac; }
bool ScanParameters::enabled() const { return m_enabled; }
int64_t ScanParameters::settleTime() const { return m_settleTime; }
RawMasterFile::RawMasterFile(const std::filesystem::path &fpath)
: m_fnc(fpath) {
@@ -177,7 +170,6 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
std::ifstream ifs(fpath);
json j;
ifs >> j;
double v = j["Version"];
m_version = fmt::format("{:.1f}", v);
@@ -189,9 +181,7 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
j["Geometry"]["x"]}; // TODO: isnt it only available for version > 7.1?
// - try block default should be 1x1
m_image_size_in_bytes =
v < 8.0 ? j["Image Size in bytes"] : j["Image Size"];
m_image_size_in_bytes = j["Image Size in bytes"];
m_frames_in_file = j["Frames in File"];
m_pixels_y = j["Pixels"]["y"];
m_pixels_x = j["Pixels"]["x"];
@@ -216,6 +206,7 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
} catch (const json::out_of_range &e) {
// keep the optional empty
}
// ----------------------------------------------------------------
// Special treatment of analog flag because of Moench03
try {
@@ -236,6 +227,7 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
m_analog_flag = 0;
}
//-----------------------------------------------------------------
try {
m_quad = j.at("Quad");
} catch (const json::out_of_range &e) {
@@ -247,6 +239,7 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
// }catch (const json::out_of_range &e) {
// m_adc_mask = 0;
// }
try {
int digital_flag = j.at("Digital Flag");
if (digital_flag) {
@@ -255,6 +248,7 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
} catch (const json::out_of_range &e) {
// keep the optional empty
}
try {
m_transceiver_flag = j.at("Transceiver Flag");
if (m_transceiver_flag) {
@@ -263,20 +257,10 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
} catch (const json::out_of_range &e) {
// keep the optional empty
}
try {
if (v < 8.0) {
std::string scan_parameters = j.at("Scan Parameters");
m_scan_parameters = ScanParameters(scan_parameters);
} else {
auto json_obj = j.at("Scan Parameters");
m_scan_parameters = ScanParameters(
json_obj.at("enable").get<int>(),
static_cast<DACIndex>(json_obj.at("dacInd").get<int>()),
json_obj.at("start offset").get<int>(),
json_obj.at("stop offset").get<int>(),
json_obj.at("step size").get<int>(),
json_obj.at("dac settle time ns").get<int>());
}
std::string scan_parameters = j.at("Scan Parameters");
m_scan_parameters = ScanParameters(scan_parameters);
if (v < 7.21) {
m_scan_parameters
.increment_stop(); // adjust for endpoint being included
@@ -284,7 +268,6 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
} catch (const json::out_of_range &e) {
// not a scan
}
try {
m_udp_interfaces_per_module = {j.at("Number of UDP Interfaces"), 1};
} catch (const json::out_of_range &e) {
@@ -294,22 +277,14 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
m_udp_interfaces_per_module = {1, 2};
}
}
try {
ROI tmp_roi;
if (v < 8.0) {
auto obj = j.at("Receiver Roi");
tmp_roi.xmin = obj.at("xmin");
tmp_roi.xmax = obj.at("xmax");
tmp_roi.ymin = obj.at("ymin");
tmp_roi.ymax = obj.at("ymax");
} else {
// TODO: for now only handle single ROI
auto obj = j.at("Receiver Rois");
tmp_roi.xmin = obj[0].at("xmin");
tmp_roi.xmax = obj[0].at("xmax");
tmp_roi.ymin = obj[0].at("ymin");
tmp_roi.ymax = obj[0].at("ymax");
}
auto obj = j.at("Receiver Roi");
tmp_roi.xmin = obj.at("xmin");
tmp_roi.xmax = obj.at("xmax");
tmp_roi.ymin = obj.at("ymin");
tmp_roi.ymax = obj.at("ymax");
// if any of the values are set update the roi
if (tmp_roi.xmin != 4294967295 || tmp_roi.xmax != 4294967295 ||
@@ -323,10 +298,14 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
}
} catch (const json::out_of_range &e) {
LOG(TLogLevel::logERROR) << e.what() << std::endl;
std::cout << e.what() << std::endl;
// leave the optional empty
}
// if we have an roi we need to update the geometry for the subfiles
if (m_roi) {
}
// Update detector type for Moench
// TODO! How does this work with old .raw master files?
#ifdef AARE_VERBOSE

View File

@@ -51,7 +51,7 @@ TEST_CASE("Parse scan parameters") {
ScanParameters s("[enabled\ndac dac 4\nstart 500\nstop 2200\nstep "
"5\nsettleTime 100us\n]");
REQUIRE(s.enabled());
REQUIRE(s.dac() == DACIndex::DAC_4);
REQUIRE(s.dac() == "dac 4");
REQUIRE(s.start() == 500);
REQUIRE(s.stop() == 2200);
REQUIRE(s.step() == 5);
@@ -60,7 +60,7 @@ TEST_CASE("Parse scan parameters") {
TEST_CASE("A disabled scan") {
ScanParameters s("[disabled]");
REQUIRE_FALSE(s.enabled());
REQUIRE(s.dac() == DACIndex::DAC_0);
REQUIRE(s.dac() == "");
REQUIRE(s.start() == 0);
REQUIRE(s.stop() == 0);
REQUIRE(s.step() == 0);
@@ -68,7 +68,7 @@ TEST_CASE("A disabled scan") {
TEST_CASE("Parse a master file in .json format", "[.integration]") {
auto fpath =
test_data_path() / "raw" / "jungfrau" / "jungfrau_single_master_0.json";
test_data_path() / "jungfrau" / "jungfrau_single_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
RawMasterFile f(fpath);
@@ -224,41 +224,6 @@ TEST_CASE("Parse a master file in .raw format", "[.integration]") {
// Packets Caught Mask : 64 bytes
}
TEST_CASE("Parse a master file in new .json format",
"[.integration][.width-data]") {
auto file_path =
test_data_path() / "raw" / "newmythen03" / "run_87_master_0.json";
REQUIRE(std::filesystem::exists(file_path));
RawMasterFile f(file_path);
// Version : 8.0
REQUIRE(f.version() == "8.0");
REQUIRE(f.detector_type() == DetectorType::Mythen3);
// Timing Mode : auto
REQUIRE(f.timing_mode() == TimingMode::Auto);
// Geometry : [2, 1]
REQUIRE(f.geometry().col == 2);
REQUIRE(f.geometry().row == 1);
// Image Size : 5120 bytes
REQUIRE(f.image_size_in_bytes() == 5120);
REQUIRE(f.scan_parameters().enabled() == false);
REQUIRE(f.scan_parameters().dac() == DACIndex::DAC_0);
REQUIRE(f.scan_parameters().start() == 0);
REQUIRE(f.scan_parameters().stop() == 0);
REQUIRE(f.scan_parameters().step() == 0);
REQUIRE(f.scan_parameters().settleTime() == 0);
auto roi = f.roi().value();
REQUIRE(roi.xmin == 0);
REQUIRE(roi.xmax == 2559);
REQUIRE(roi.ymin == -1);
REQUIRE(roi.ymax == -1);
}
TEST_CASE("Read eiger master file", "[.integration]") {
auto fpath = test_data_path() / "eiger" / "eiger_500k_32bit_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
@@ -327,4 +292,4 @@ TEST_CASE("Read eiger master file", "[.integration]") {
// "Packets Caught Mask": "64 bytes"
// }
// }
}
}

View File

@@ -115,186 +115,4 @@ template <> FrameDiscardPolicy StringTo(const std::string &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 +
"\"");
}
} // namespace aare