mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2026-08-03 22:18:13 +02:00
Merge branch 'developer' into dev/rx_disable_datastream_port
This commit is contained in:
@@ -5,6 +5,9 @@
|
||||
target_sources(tests PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-SharedMemory.cpp
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/acquire/Acquire.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/acquire/ExpectedState.cpp
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller-rx.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller-rx-running.cpp
|
||||
@@ -18,6 +21,7 @@ target_sources(tests PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller-moench.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller-global.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller-acquire.cpp
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller-master-attributes.cpp
|
||||
|
||||
|
||||
@@ -44,6 +48,8 @@ target_compile_options(tests
|
||||
|
||||
target_include_directories(tests
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/Caller"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../src>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include/sls>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../slsReceiverSoftware/src>"
|
||||
|
||||
@@ -2,289 +2,272 @@
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include "Caller.h"
|
||||
#include "catch.hpp"
|
||||
#include "sls/Detector.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "sls/versionAPI.h"
|
||||
#include "test-Caller-global.h"
|
||||
#include "tests/globals.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <sstream>
|
||||
#include "acquire/Acquire.h"
|
||||
#include "acquire/CTBState.h"
|
||||
#include "acquire/ExpectedState.h"
|
||||
#include "acquire/FileState.h"
|
||||
#include "checks/MasterFileChecks.h"
|
||||
|
||||
namespace sls {
|
||||
|
||||
using test::GET;
|
||||
using test::PUT;
|
||||
namespace acq = sls::test::acquire;
|
||||
namespace checks = sls::test::checks;
|
||||
|
||||
void acquire_and_check_file_size(
|
||||
Detector &det, std::optional<acq::CTBState> ctb_state = std::nullopt) {
|
||||
auto acq_state = acq::default_acquisition_state();
|
||||
acq_state.num_frames = 2;
|
||||
auto file_state = acq::default_file_state();
|
||||
acq::run(det, acq_state, file_state);
|
||||
auto image_size = acq::get_expected_image_size(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
checks::check_binary_file_size(image_size, acq_state.num_frames));
|
||||
}
|
||||
|
||||
void test_ctb_binary_file_size(Detector &det) {
|
||||
auto detType = det.getDetectorType().squash(defs::GENERIC);
|
||||
acq::CTBState ctb_state = acq::default_ctb_state(detType);
|
||||
// default ctb state for tests
|
||||
// readout mode = defs::ANALOG_AND_DIGITAL
|
||||
// analog samples = 5000
|
||||
// digital samples = 6000
|
||||
// trans samples = 288
|
||||
// ten_giga = isAltera ? false : true
|
||||
// adc enable 1g = 0xFFFFFF00
|
||||
// adc enable 1g = 0xFF00FFFF
|
||||
// dbit offset = 0
|
||||
// dbit list = {0, 12, 2, 43}
|
||||
// dbit reorder = false
|
||||
// trans mask = 0x3
|
||||
|
||||
acq::CTBStateGuard ctb_guard(det, std::make_optional(ctb_state));
|
||||
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.dbit_reorder = true;
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.dbit_offset = 16;
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.dbit_offset = 16;
|
||||
ctb_state.dbit_reorder = true;
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.dbit_list.clear();
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.dbit_offset = 16;
|
||||
ctb_state.dbit_list.clear();
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.dbit_reorder = true;
|
||||
ctb_state.dbit_list.clear();
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.dbit_offset = 16;
|
||||
ctb_state.dbit_reorder = true;
|
||||
ctb_state.dbit_list.clear();
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
ctb_state.dbit_offset = 16;
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
ctb_state.dbit_reorder = true;
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
ctb_state.dbit_offset = 16;
|
||||
ctb_state.dbit_reorder = true;
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
ctb_state.dbit_list.clear();
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
ctb_state.dbit_offset = 16;
|
||||
ctb_state.dbit_list.clear();
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
ctb_state.dbit_reorder = true;
|
||||
ctb_state.dbit_list.clear();
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
ctb_state.dbit_offset = 16;
|
||||
ctb_state.dbit_reorder = true;
|
||||
ctb_state.dbit_list.clear();
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::TRANSCEIVER_ONLY;
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::TRANSCEIVER_ONLY;
|
||||
ctb_state.dbit_reorder = true;
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::TRANSCEIVER_ONLY;
|
||||
ctb_state.dbit_offset = 16;
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::TRANSCEIVER_ONLY;
|
||||
ctb_state.dbit_offset = 16;
|
||||
ctb_state.dbit_reorder = true;
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::TRANSCEIVER_ONLY;
|
||||
ctb_state.dbit_list.clear();
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::TRANSCEIVER_ONLY;
|
||||
ctb_state.dbit_offset = 16;
|
||||
ctb_state.dbit_list.clear();
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::TRANSCEIVER_ONLY;
|
||||
ctb_state.dbit_reorder = true;
|
||||
ctb_state.dbit_list.clear();
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::TRANSCEIVER_ONLY;
|
||||
ctb_state.dbit_offset = 16;
|
||||
ctb_state.dbit_reorder = true;
|
||||
ctb_state.dbit_list.clear();
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
{
|
||||
ctb_state = acq::default_ctb_state(detType);
|
||||
ctb_state.readout_mode = defs::ANALOG_ONLY;
|
||||
ctb_state.dbit_offset = 16;
|
||||
ctb_state.dbit_reorder = true;
|
||||
acq::set_ctb_state(det, ctb_state);
|
||||
REQUIRE_NOTHROW(
|
||||
acquire_and_check_file_size(det, std::make_optional(ctb_state)));
|
||||
}
|
||||
}
|
||||
|
||||
// disable for jungfrau as it requires higher maximum receive buffer size
|
||||
// sysctl net.core.rmem_max=$((100*1024*1024))
|
||||
// sysctl net.core.rmem_default=$((100*1024*1024))
|
||||
TEST_CASE("jungfrau_or_moench_acquire_check_file_size",
|
||||
TEST_CASE("acquire_check_binary_file_size",
|
||||
"[.detectorintegration][.disable_check_data_file]") {
|
||||
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
auto det_type =
|
||||
det.getDetectorType().tsquash("Inconsistent detector types to test");
|
||||
|
||||
if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH) {
|
||||
|
||||
auto num_udp_interfaces = det.getNumberofUDPInterfaces().tsquash(
|
||||
"inconsistent number of udp interfaces");
|
||||
|
||||
int num_frames_to_acquire = 2;
|
||||
create_files_for_acquire(det, caller, num_frames_to_acquire);
|
||||
|
||||
// check file size (assuming local pc)
|
||||
{
|
||||
detParameters par(det_type);
|
||||
int bytes_per_pixel = det.getDynamicRange().squash() / 8;
|
||||
// if 2 udp interfaces, data split into half
|
||||
size_t expected_image_size = (par.nChanX * par.nChanY * par.nChipX *
|
||||
par.nChipY * bytes_per_pixel) /
|
||||
num_udp_interfaces;
|
||||
testFileInfo test_file_info;
|
||||
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
|
||||
expected_image_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("eiger_acquire_check_file_size",
|
||||
"[.detectorintegration][.disable_check_data_file]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
auto det_type =
|
||||
det.getDetectorType().tsquash("Inconsistent detector types to test");
|
||||
|
||||
if (det_type == defs::EIGER) {
|
||||
|
||||
int dynamic_range = det.getDynamicRange().squash();
|
||||
if (dynamic_range != 16) {
|
||||
throw RuntimeError(
|
||||
"Eiger detector must have dynamic range 16 to test");
|
||||
}
|
||||
int num_frames_to_acquire = 2;
|
||||
create_files_for_acquire(det, caller, num_frames_to_acquire);
|
||||
|
||||
// check file size (assuming local pc)
|
||||
{
|
||||
detParameters par(det_type);
|
||||
// data split into half due to 2 udp interfaces per half module
|
||||
int num_chips = (par.nChipX / 2);
|
||||
int bytes_per_pixel = (dynamic_range / 8);
|
||||
size_t expected_image_size =
|
||||
par.nChanX * par.nChanY * num_chips * bytes_per_pixel;
|
||||
testFileInfo test_file_info;
|
||||
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
|
||||
expected_image_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("mythen3_acquire_check_file_size",
|
||||
"[.detectorintegration][.disable_check_data_file]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
auto det_type =
|
||||
det.getDetectorType().tsquash("Inconsistent detector types to test");
|
||||
|
||||
if (det_type == defs::MYTHEN3) {
|
||||
|
||||
int dynamic_range = det.getDynamicRange().squash();
|
||||
int counter_mask = det.getCounterMask().squash();
|
||||
if (dynamic_range != 16 && counter_mask != 0x3) {
|
||||
throw RuntimeError("Mythen3 detector must have dynamic range 16 "
|
||||
"and counter mask 0x3 to test");
|
||||
}
|
||||
int num_counters = __builtin_popcount(counter_mask);
|
||||
int num_frames_to_acquire = 2;
|
||||
create_files_for_acquire(det, caller, num_frames_to_acquire);
|
||||
|
||||
// check file size (assuming local pc)
|
||||
{
|
||||
detParameters par(det_type);
|
||||
int bytes_per_pixel = dynamic_range / 8;
|
||||
int num_channels_per_counter = par.nChanX / 3;
|
||||
size_t expected_image_size = num_channels_per_counter *
|
||||
num_counters * par.nChipX *
|
||||
bytes_per_pixel;
|
||||
testFileInfo test_file_info;
|
||||
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
|
||||
expected_image_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("gotthard2_acquire_check_file_size",
|
||||
"[.detectorintegration][.disable_check_data_file]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
auto det_type =
|
||||
det.getDetectorType().tsquash("Inconsistent detector types to test");
|
||||
|
||||
if (det_type == defs::GOTTHARD2) {
|
||||
|
||||
int num_frames_to_acquire = 2;
|
||||
create_files_for_acquire(det, caller, num_frames_to_acquire);
|
||||
|
||||
// check file size (assuming local pc)
|
||||
{
|
||||
detParameters par(det_type);
|
||||
int bytes_per_pixel = det.getDynamicRange().squash() / 8;
|
||||
size_t expected_image_size =
|
||||
par.nChanX * par.nChipX * bytes_per_pixel;
|
||||
testFileInfo test_file_info;
|
||||
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
|
||||
expected_image_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_ctb_file_size_with_acquire(Detector &det, Caller &caller,
|
||||
int64_t num_frames,
|
||||
const testCtbAcquireInfo &test_info,
|
||||
bool isXilinxCtb) {
|
||||
|
||||
create_files_for_acquire(det, caller, num_frames, test_info);
|
||||
|
||||
// check file size (assuming local pc)
|
||||
uint64_t expected_image_size =
|
||||
calculate_ctb_image_size(test_info, isXilinxCtb).first;
|
||||
testFileInfo test_file_info;
|
||||
REQUIRE_NOTHROW(test_acquire_binary_file_size(test_file_info, num_frames,
|
||||
expected_image_size));
|
||||
}
|
||||
|
||||
// disable for xilinx_ctb as it requires higher maximum receive buffer size
|
||||
// sysctl net.core.rmem_max=$((100*1024*1024))
|
||||
// sysctl net.core.rmem_default=$((100*1024*1024))
|
||||
TEST_CASE("ctb_acquire_check_file_size",
|
||||
"[.detectorintegration][.disable_check_data_file]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
auto det_type =
|
||||
det.getDetectorType().tsquash("Inconsistent detector types to test");
|
||||
INFO("Testing acquire and checking binary file size with "
|
||||
<< ToString(det_type));
|
||||
|
||||
if (det_type == defs::CHIPTESTBOARD ||
|
||||
det_type == defs::XILINX_CHIPTESTBOARD) {
|
||||
bool isXilinxCtb = (det_type == defs::XILINX_CHIPTESTBOARD);
|
||||
int num_frames_to_acquire = 2;
|
||||
// all the test cases
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config{};
|
||||
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
|
||||
REQUIRE_NOTHROW(test_ctb_file_size_with_acquire(
|
||||
det, caller, num_frames_to_acquire, test_ctb_config,
|
||||
isXilinxCtb));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config{};
|
||||
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
REQUIRE_NOTHROW(test_ctb_file_size_with_acquire(
|
||||
det, caller, num_frames_to_acquire, test_ctb_config,
|
||||
isXilinxCtb));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config{};
|
||||
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
|
||||
test_ctb_config.dbit_reorder = true;
|
||||
REQUIRE_NOTHROW(test_ctb_file_size_with_acquire(
|
||||
det, caller, num_frames_to_acquire, test_ctb_config,
|
||||
isXilinxCtb));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config{};
|
||||
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_reorder = true;
|
||||
REQUIRE_NOTHROW(test_ctb_file_size_with_acquire(
|
||||
det, caller, num_frames_to_acquire, test_ctb_config,
|
||||
isXilinxCtb));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config{};
|
||||
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
REQUIRE_NOTHROW(test_ctb_file_size_with_acquire(
|
||||
det, caller, num_frames_to_acquire, test_ctb_config,
|
||||
isXilinxCtb));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config{};
|
||||
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
test_ctb_config.dbit_reorder = true;
|
||||
REQUIRE_NOTHROW(test_ctb_file_size_with_acquire(
|
||||
det, caller, num_frames_to_acquire, test_ctb_config,
|
||||
isXilinxCtb));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config{};
|
||||
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
REQUIRE_NOTHROW(test_ctb_file_size_with_acquire(
|
||||
det, caller, num_frames_to_acquire, test_ctb_config,
|
||||
isXilinxCtb));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config{};
|
||||
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
REQUIRE_NOTHROW(test_ctb_file_size_with_acquire(
|
||||
det, caller, num_frames_to_acquire, test_ctb_config,
|
||||
isXilinxCtb));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config{};
|
||||
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
REQUIRE_NOTHROW(test_ctb_file_size_with_acquire(
|
||||
det, caller, num_frames_to_acquire, test_ctb_config,
|
||||
isXilinxCtb));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config{};
|
||||
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
REQUIRE_NOTHROW(test_ctb_file_size_with_acquire(
|
||||
det, caller, num_frames_to_acquire, test_ctb_config,
|
||||
isXilinxCtb));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config{};
|
||||
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
test_ctb_config.dbit_reorder = true;
|
||||
REQUIRE_NOTHROW(test_ctb_file_size_with_acquire(
|
||||
det, caller, num_frames_to_acquire, test_ctb_config,
|
||||
isXilinxCtb));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config{};
|
||||
test_ctb_config.readout_mode = defs::TRANSCEIVER_ONLY;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
test_ctb_config.dbit_reorder = true;
|
||||
REQUIRE_NOTHROW(test_ctb_file_size_with_acquire(
|
||||
det, caller, num_frames_to_acquire, test_ctb_config,
|
||||
isXilinxCtb));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config{};
|
||||
test_ctb_config.readout_mode = defs::ANALOG_ONLY;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
test_ctb_config.dbit_reorder = true;
|
||||
REQUIRE_NOTHROW(test_ctb_file_size_with_acquire(
|
||||
det, caller, num_frames_to_acquire, test_ctb_config,
|
||||
isXilinxCtb));
|
||||
}
|
||||
}
|
||||
det_type == defs::XILINX_CHIPTESTBOARD)
|
||||
test_ctb_binary_file_size(det);
|
||||
else
|
||||
REQUIRE_NOTHROW(acquire_and_check_file_size(det));
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
|
||||
@@ -3,13 +3,16 @@
|
||||
#include "test-Caller-global.h"
|
||||
#include "Caller.h"
|
||||
#include "GeneralData.h"
|
||||
#include "catch.hpp"
|
||||
#include "sls/Detector.h"
|
||||
#include "sls/logger.h"
|
||||
#include "tests/globals.h"
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
namespace sls {
|
||||
|
||||
namespace acq = sls::test::acquire;
|
||||
|
||||
using test::GET;
|
||||
using test::PUT;
|
||||
void test_valid_port_caller(const std::string &command,
|
||||
@@ -96,164 +99,10 @@ void test_onchip_dac_caller(defs::dacIndex index, const std::string &dacname,
|
||||
}
|
||||
}
|
||||
|
||||
testFileInfo get_file_state(const Detector &det) {
|
||||
return testFileInfo{
|
||||
det.getFilePath().tsquash("Inconsistent file path"),
|
||||
det.getFileNamePrefix().tsquash("Inconsistent file prefix"),
|
||||
det.getAcquisitionIndex().tsquash(
|
||||
"Inconsistent file acquisition index"),
|
||||
det.getFileWrite().tsquash("Inconsistent file write state"),
|
||||
det.getFileOverWrite().tsquash("Inconsistent file overwrite state"),
|
||||
det.getFileFormat().tsquash("Inconsistent file format")};
|
||||
}
|
||||
|
||||
void set_file_state(Detector &det, const testFileInfo &file_info) {
|
||||
if (!file_info.file_path.empty())
|
||||
det.setFilePath(file_info.file_path);
|
||||
det.setFileNamePrefix(file_info.file_prefix);
|
||||
det.setAcquisitionIndex(file_info.file_acq_index);
|
||||
det.setFileWrite(file_info.file_write);
|
||||
det.setFileOverWrite(file_info.file_overwrite);
|
||||
det.setFileFormat(file_info.file_format);
|
||||
}
|
||||
|
||||
void test_acquire_binary_file_size(const testFileInfo &file_info,
|
||||
uint64_t num_frames_to_acquire,
|
||||
uint64_t expected_image_size) {
|
||||
assert(file_info.file_format == defs::BINARY);
|
||||
std::string fname = file_info.file_path + "/" + file_info.file_prefix +
|
||||
"_d0_f0_" + std::to_string(file_info.file_acq_index) +
|
||||
".raw";
|
||||
uint64_t expected_file_size =
|
||||
num_frames_to_acquire *
|
||||
(expected_image_size + sizeof(defs::sls_receiver_header));
|
||||
auto actual_file_size = std::filesystem::file_size(fname);
|
||||
REQUIRE(actual_file_size == expected_file_size);
|
||||
}
|
||||
|
||||
void test_acquire_with_receiver(Caller &caller, const Detector &det) {
|
||||
REQUIRE_NOTHROW(caller.call("rx_start", {}, -1, PUT));
|
||||
REQUIRE_NOTHROW(caller.call("start", {}, -1, PUT));
|
||||
bool idle = false;
|
||||
while (!idle) {
|
||||
std::ostringstream oss;
|
||||
REQUIRE_NOTHROW(caller.call("status", {}, -1, GET));
|
||||
auto statusList = det.getDetectorStatus();
|
||||
if (statusList.any(defs::ERROR)) {
|
||||
throw std::runtime_error("error status while acquiring");
|
||||
}
|
||||
if (statusList.contains_only(defs::IDLE, defs::STOPPED)) {
|
||||
idle = true;
|
||||
}
|
||||
}
|
||||
REQUIRE_NOTHROW(caller.call("rx_stop", {}, -1, PUT));
|
||||
}
|
||||
|
||||
void create_files_for_acquire(
|
||||
Detector &det, Caller &caller, int64_t num_frames,
|
||||
const std::optional<testCtbAcquireInfo> &test_info) {
|
||||
|
||||
// save previous state
|
||||
testFileInfo prev_file_info = get_file_state(det);
|
||||
auto prev_num_frames = det.getNumberOfFrames().tsquash(
|
||||
"Inconsistent number of frames to acquire");
|
||||
std::optional<testCtbAcquireInfo> prev_ctb_config_info{};
|
||||
if (test_info) {
|
||||
prev_ctb_config_info = get_ctb_config_state(det);
|
||||
}
|
||||
|
||||
// set state for acquire
|
||||
testFileInfo test_file_info;
|
||||
set_file_state(det, test_file_info);
|
||||
det.setNumberOfFrames(num_frames);
|
||||
if (test_info) {
|
||||
set_ctb_config_state(det, *test_info);
|
||||
}
|
||||
|
||||
// acquire and get num frames caught
|
||||
REQUIRE_NOTHROW(test_acquire_with_receiver(caller, det));
|
||||
// TODO: maybe there should not be REQUIRE statements in void function at
|
||||
// all, but traceback should be handled
|
||||
{
|
||||
auto frames_caught = det.getFramesCaught()[0][0];
|
||||
REQUIRE(frames_caught == num_frames);
|
||||
}
|
||||
|
||||
// hdf5
|
||||
#ifdef HDF5C
|
||||
test_file_info.file_format = defs::HDF5;
|
||||
test_file_info.file_acq_index = 0;
|
||||
set_file_state(det, test_file_info);
|
||||
|
||||
// acquire and get num frames caught
|
||||
test_acquire_with_receiver(caller, det);
|
||||
{
|
||||
auto frames_caught = det.getFramesCaught()[0][0];
|
||||
REQUIRE(frames_caught == num_frames);
|
||||
}
|
||||
#endif
|
||||
|
||||
// restore previous state
|
||||
// file
|
||||
set_file_state(det, prev_file_info);
|
||||
det.setNumberOfFrames(prev_num_frames);
|
||||
if (test_info) {
|
||||
set_ctb_config_state(det, *prev_ctb_config_info);
|
||||
}
|
||||
}
|
||||
|
||||
testCtbAcquireInfo get_ctb_config_state(const Detector &det) {
|
||||
testCtbAcquireInfo ctb_config_info{
|
||||
det.getReadoutMode().tsquash("inconsistent readout mode to test"),
|
||||
true,
|
||||
det.getNumberOfAnalogSamples().tsquash(
|
||||
"inconsistent number of analog samples to test"),
|
||||
det.getNumberOfDigitalSamples().tsquash(
|
||||
"inconsistent number of digital samples to test"),
|
||||
det.getNumberOfTransceiverSamples().tsquash(
|
||||
"inconsistent number of transceiver samples to test"),
|
||||
0,
|
||||
det.getTenGigaADCEnableMask().tsquash(
|
||||
"inconsistent ten giga adc enable mask to test"),
|
||||
det.getRxDbitOffset().tsquash("inconsistent rx dbit offset to test"),
|
||||
det.getRxDbitList().tsquash("inconsistent rx dbit list to test"),
|
||||
det.getRxDbitReorder().tsquash("inconsistent rx dbit reorder to test"),
|
||||
det.getTransceiverEnableMask().tsquash(
|
||||
"inconsistent transceiver mask to test")};
|
||||
|
||||
if (det.getDetectorType().tsquash("inconsistent detector type to test") ==
|
||||
slsDetectorDefs::CHIPTESTBOARD) {
|
||||
ctb_config_info.ten_giga =
|
||||
det.getTenGiga().tsquash("inconsistent ten giga enable to test");
|
||||
ctb_config_info.adc_enable_1g = det.getADCEnableMask().tsquash(
|
||||
"inconsistent adc enable mask to test");
|
||||
}
|
||||
return ctb_config_info;
|
||||
}
|
||||
|
||||
void set_ctb_config_state(Detector &det,
|
||||
const testCtbAcquireInfo &ctb_config_info) {
|
||||
det.setReadoutMode(ctb_config_info.readout_mode);
|
||||
if (det.getDetectorType().tsquash("inconsistent detector type to test") ==
|
||||
slsDetectorDefs::CHIPTESTBOARD) {
|
||||
det.setTenGiga(ctb_config_info.ten_giga);
|
||||
det.setADCEnableMask(ctb_config_info.adc_enable_1g);
|
||||
}
|
||||
det.setNumberOfAnalogSamples(ctb_config_info.num_adc_samples);
|
||||
det.setNumberOfDigitalSamples(ctb_config_info.num_dbit_samples);
|
||||
det.setNumberOfTransceiverSamples(ctb_config_info.num_trans_samples);
|
||||
det.setTenGigaADCEnableMask(ctb_config_info.adc_enable_10g);
|
||||
det.setRxDbitOffset(ctb_config_info.dbit_offset);
|
||||
det.setRxDbitList(ctb_config_info.dbit_list);
|
||||
det.setRxDbitReorder(ctb_config_info.dbit_reorder);
|
||||
det.setTransceiverEnableMask(ctb_config_info.transceiver_mask);
|
||||
}
|
||||
|
||||
std::pair<uint64_t, int>
|
||||
calculate_ctb_image_size(const testCtbAcquireInfo &test_info,
|
||||
bool isXilinxCtb) {
|
||||
calculate_ctb_image_size(const acq::CTBState &test_info, bool isXilinxCtb) {
|
||||
|
||||
// test_info.print(); // for debugging
|
||||
LOG(logDEBUG1) << test_info;
|
||||
sls::CtbImageInputs inputs{};
|
||||
inputs.mode = test_info.readout_mode;
|
||||
inputs.nAnalogSamples = test_info.num_adc_samples;
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
|
||||
#include "Caller.h"
|
||||
#include "sls/Detector.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/logger.h"
|
||||
#include "acquire/CTBState.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
||||
#include <chrono>
|
||||
@@ -14,64 +11,8 @@
|
||||
#include <thread>
|
||||
|
||||
namespace sls {
|
||||
struct testFileInfo {
|
||||
std::string file_path{"/tmp"};
|
||||
std::string file_prefix{"sls_test"};
|
||||
int64_t file_acq_index{0};
|
||||
bool file_write{true};
|
||||
bool file_overwrite{true};
|
||||
slsDetectorDefs::fileFormat file_format{slsDetectorDefs::BINARY};
|
||||
std::string getMasterFileNamePrefix() const {
|
||||
return file_path + "/" + file_prefix + "_master_" +
|
||||
std::to_string(file_acq_index);
|
||||
}
|
||||
std::string getVirtualFileName() const {
|
||||
return file_path + "/" + file_prefix + "_virtual_" +
|
||||
std::to_string(file_acq_index) + ".h5";
|
||||
}
|
||||
inline void print() const {
|
||||
LOG(logINFO) << "File Info: "
|
||||
<< "\n\tFile Path: " << file_path
|
||||
<< "\n\tFile Prefix: " << file_prefix
|
||||
<< "\n\tFile Acquisition Index: " << file_acq_index
|
||||
<< "\n\tFile Write: " << file_write
|
||||
<< "\n\tFile Overwrite: " << file_overwrite
|
||||
<< "\n\tFile Format: " << ToString(file_format)
|
||||
<< "\n\tMaster Filename: " << getMasterFileNamePrefix()
|
||||
<< "\n\tVirtual Filename: " << getVirtualFileName();
|
||||
}
|
||||
};
|
||||
|
||||
struct testCtbAcquireInfo {
|
||||
defs::readoutMode readout_mode{defs::ANALOG_AND_DIGITAL};
|
||||
bool ten_giga{false};
|
||||
int num_adc_samples{5000};
|
||||
int num_dbit_samples{6000};
|
||||
int num_trans_samples{288};
|
||||
uint32_t adc_enable_1g{0xFFFFFF00};
|
||||
uint32_t adc_enable_10g{0xFF00FFFF};
|
||||
int dbit_offset{0};
|
||||
std::vector<int> dbit_list{0, 12, 2, 43};
|
||||
bool dbit_reorder{false};
|
||||
uint32_t transceiver_mask{0x3};
|
||||
|
||||
inline void print() const {
|
||||
LOG(logINFO) << "CTB Acquire Info: "
|
||||
<< "\n\tReadout Mode: " << ToString(readout_mode)
|
||||
<< "\n\tTen Giga: " << ten_giga
|
||||
<< "\n\tADC Enable 1G: " << std::hex << adc_enable_1g
|
||||
<< std::dec << "\n\tADC Enable 10G: " << std::hex
|
||||
<< adc_enable_10g << std::dec
|
||||
<< "\n\tNumber of Analog Samples: " << num_adc_samples
|
||||
<< "\n\tNumber of Digital Samples: " << num_dbit_samples
|
||||
<< "\n\tNumber of Transceiver Samples: "
|
||||
<< num_trans_samples << "\n\tDBIT Offset: " << dbit_offset
|
||||
<< "\n\tDBIT Reorder: " << dbit_reorder
|
||||
<< "\n\tDBIT List: " << ToString(dbit_list)
|
||||
<< "\n\tTransceiver Mask: " << std::hex << transceiver_mask
|
||||
<< std::dec << std::endl;
|
||||
}
|
||||
};
|
||||
namespace acq = sls::test::acquire;
|
||||
|
||||
void test_valid_port_caller(const std::string &command,
|
||||
const std::vector<std::string> &arguments,
|
||||
@@ -82,22 +23,7 @@ void test_dac_caller(slsDetectorDefs::dacIndex index,
|
||||
void test_onchip_dac_caller(slsDetectorDefs::dacIndex index,
|
||||
const std::string &dacname, int dacvalue);
|
||||
|
||||
testFileInfo get_file_state(const Detector &det);
|
||||
void set_file_state(Detector &det, const testFileInfo &file_info);
|
||||
void test_acquire_binary_file_size(const testFileInfo &file_info,
|
||||
uint64_t num_frames_to_acquire,
|
||||
uint64_t expected_image_size);
|
||||
|
||||
void test_acquire_with_receiver(Caller &caller, const Detector &det);
|
||||
|
||||
void create_files_for_acquire(
|
||||
Detector &det, Caller &caller, int64_t num_frames = 1,
|
||||
const std::optional<testCtbAcquireInfo> &test_info = std::nullopt);
|
||||
|
||||
testCtbAcquireInfo get_ctb_config_state(const Detector &det);
|
||||
void set_ctb_config_state(Detector &det,
|
||||
const testCtbAcquireInfo &ctb_config_info);
|
||||
std::pair<uint64_t, int>
|
||||
calculate_ctb_image_size(const testCtbAcquireInfo &test_info, bool isXilinxCtb);
|
||||
calculate_ctb_image_size(const acq::CTBState &test_info, bool isXilinxCtb);
|
||||
|
||||
} // namespace sls
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,21 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include "Caller.h"
|
||||
#include "catch.hpp"
|
||||
#include "sls/Detector.h"
|
||||
#include "sls/Version.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "test-Caller-global.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <sstream>
|
||||
|
||||
#include "sls/versionAPI.h"
|
||||
#include "test-Caller-global.h"
|
||||
#include "tests/globals.h"
|
||||
|
||||
#include "acquire/Acquire.h"
|
||||
#include "acquire/FileState.h"
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
namespace sls {
|
||||
|
||||
namespace acq = sls::test::acquire;
|
||||
|
||||
using test::GET;
|
||||
using test::PUT;
|
||||
|
||||
@@ -835,19 +836,22 @@ TEST_CASE("rx_roi", "[.detectorintegration][.disable_check_data_file]") {
|
||||
// check master file creation
|
||||
// TODO: check roi in master file
|
||||
{
|
||||
REQUIRE_NOTHROW(create_files_for_acquire(det, caller));
|
||||
testFileInfo file_info;
|
||||
std::string master_file_prefix =
|
||||
file_info.getMasterFileNamePrefix();
|
||||
auto acq_state = acq::default_acquisition_state();
|
||||
auto file_state = acq::default_file_state();
|
||||
|
||||
file_state.file_format = defs::BINARY;
|
||||
acq::run(det, acq_state, file_state);
|
||||
std::string fname = acq::get_master_file_name(file_state);
|
||||
REQUIRE(std::filesystem::exists(fname));
|
||||
|
||||
std::string fname = master_file_prefix + ".json";
|
||||
REQUIRE(std::filesystem::exists(fname) == true);
|
||||
#ifdef HDF5C
|
||||
fname = master_file_prefix + ".h5";
|
||||
REQUIRE(std::filesystem::exists(fname) == true);
|
||||
file_state.file_format = defs::HDF5;
|
||||
acq::run(det, acq_state, file_state);
|
||||
fname = acq::get_master_file_name(file_state);
|
||||
REQUIRE(std::filesystem::exists(fname));
|
||||
if (det.size() > 1 || numinterfaces > 1) {
|
||||
fname = file_info.getVirtualFileName();
|
||||
REQUIRE(std::filesystem::exists(fname) == true);
|
||||
fname = acq::get_virtual_file_name(file_state);
|
||||
REQUIRE(std::filesystem::exists(fname));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
|
||||
#include "Acquire.h"
|
||||
#include "FileState.h"
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
namespace sls::test::acquire {
|
||||
|
||||
void wait_until_idle(const Detector &det) {
|
||||
bool idle = false;
|
||||
while (!idle) {
|
||||
auto statusList = det.getDetectorStatus();
|
||||
if (statusList.any(defs::ERROR)) {
|
||||
throw RuntimeError("error status during acquisition");
|
||||
}
|
||||
if (statusList.contains_only(defs::IDLE, defs::STOPPED)) {
|
||||
idle = true;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
}
|
||||
|
||||
void run_acquisition(Detector &det) {
|
||||
det.startReceiver();
|
||||
det.startDetector();
|
||||
wait_until_idle(det);
|
||||
det.stopReceiver();
|
||||
}
|
||||
|
||||
void run(Detector &det, const AcquisitionState &acq_state,
|
||||
const FileState &file_state) {
|
||||
|
||||
INFO(ToString(det.getDetectorType().squash(defs::GENERIC))
|
||||
<< " acquiring with num_frames = " << acq_state.num_frames);
|
||||
|
||||
FileStateGuard file_guard(det, file_state);
|
||||
AcquisitionStateGuard acq_guard(det, acq_state);
|
||||
run_acquisition(det);
|
||||
auto frames_caught = det.getFramesCaught()[0][0];
|
||||
REQUIRE(frames_caught == acq_state.num_frames);
|
||||
}
|
||||
|
||||
} // namespace sls::test::acquire
|
||||
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sls/Detector.h"
|
||||
#include "sls/logger.h"
|
||||
|
||||
namespace sls::test::acquire {
|
||||
|
||||
class FileState;
|
||||
|
||||
// at the moment, only number of frames
|
||||
struct AcquisitionState {
|
||||
int64_t num_frames;
|
||||
};
|
||||
|
||||
inline AcquisitionState default_acquisition_state() { return {1}; }
|
||||
|
||||
inline AcquisitionState get_acquisition_state(const Detector &det) {
|
||||
return AcquisitionState{
|
||||
det.getNumberOfFrames().tsquash("Inconsistent number of frames")};
|
||||
}
|
||||
|
||||
inline void set_acquisition_state(Detector &det, const AcquisitionState &s) {
|
||||
det.setNumberOfFrames(s.num_frames);
|
||||
}
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, const AcquisitionState &s) {
|
||||
os << "Acquisition State:"
|
||||
<< "\n Number of Frames: " << s.num_frames;
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RAII guard for restoring the acquisition state of a detector.
|
||||
* The constructor saves the current acquisition state and sets a new state,
|
||||
* while the destructor restores the original state.
|
||||
*
|
||||
*/
|
||||
class AcquisitionStateGuard {
|
||||
public:
|
||||
explicit AcquisitionStateGuard(Detector &det,
|
||||
const AcquisitionState &new_state)
|
||||
: det(det), saved_(get_acquisition_state(det)) {
|
||||
set_acquisition_state(det, new_state);
|
||||
}
|
||||
~AcquisitionStateGuard() { set_acquisition_state(det, saved_); }
|
||||
|
||||
private:
|
||||
Detector &det;
|
||||
AcquisitionState saved_;
|
||||
};
|
||||
|
||||
void wait_until_idle(const Detector &det);
|
||||
void run_acquisition(Detector &det);
|
||||
void run(Detector &det, const AcquisitionState &acq_state,
|
||||
const FileState &file_state);
|
||||
|
||||
} // namespace sls::test::acquire
|
||||
@@ -0,0 +1,138 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
|
||||
#include "sls/Detector.h"
|
||||
#include "sls/logger.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace sls::test::acquire {
|
||||
|
||||
struct CTBState {
|
||||
defs::readoutMode readout_mode;
|
||||
int num_adc_samples;
|
||||
int num_dbit_samples;
|
||||
int num_trans_samples;
|
||||
bool ten_giga;
|
||||
uint32_t adc_enable_1g;
|
||||
uint32_t adc_enable_10g;
|
||||
int dbit_offset;
|
||||
std::vector<int> dbit_list;
|
||||
bool dbit_reorder;
|
||||
uint32_t transceiver_mask;
|
||||
};
|
||||
|
||||
/** an example of CTB config */
|
||||
inline CTBState
|
||||
default_ctb_state(const defs::detectorType &detType = defs::GENERIC) {
|
||||
if (detType == defs::GENERIC) {
|
||||
throw sls::RuntimeError(
|
||||
"Cannot determine default CTB state for generic detector type.");
|
||||
}
|
||||
auto isAltera = (detType == defs::CHIPTESTBOARD);
|
||||
return {defs::ANALOG_AND_DIGITAL, 5000, 6000, 288,
|
||||
isAltera ? false : true, 0xFFFFFF00, 0xFF00FFFF, 0,
|
||||
{0, 12, 2, 43}, false, 0x3};
|
||||
}
|
||||
|
||||
inline CTBState get_ctb_state(const Detector &det) {
|
||||
auto isAltera =
|
||||
(det.getDetectorType().squash(defs::GENERIC) == defs::CHIPTESTBOARD);
|
||||
return CTBState{
|
||||
det.getReadoutMode().tsquash("Inconsistent readout mode"),
|
||||
det.getNumberOfAnalogSamples().tsquash(
|
||||
"Inconsistent number of analog samples"),
|
||||
det.getNumberOfDigitalSamples().tsquash(
|
||||
"Inconsistent number of digital samples"),
|
||||
det.getNumberOfTransceiverSamples().tsquash(
|
||||
"Inconsistent number of transceiver samples"),
|
||||
isAltera ? det.getTenGiga().tsquash("Inconsisten ten giga enable")
|
||||
: true,
|
||||
isAltera
|
||||
? det.getADCEnableMask().tsquash("Inconsistent adc enable mask")
|
||||
: 0,
|
||||
det.getTenGigaADCEnableMask().tsquash(
|
||||
"Inconsistent ten giga adc enable mask"),
|
||||
det.getRxDbitOffset().tsquash("Inconsistent rx dbit offset"),
|
||||
det.getRxDbitList().tsquash("Inconsistent rx dbit list"),
|
||||
det.getRxDbitReorder().tsquash("Inconsistent rx dbit reorder"),
|
||||
det.getTransceiverEnableMask().tsquash(
|
||||
"Inconsistent transceiver mask")};
|
||||
}
|
||||
|
||||
inline void set_ctb_state(Detector &det, const CTBState &s) {
|
||||
auto isAltera =
|
||||
(det.getDetectorType().squash(defs::GENERIC) == defs::CHIPTESTBOARD);
|
||||
det.setReadoutMode(s.readout_mode);
|
||||
if (isAltera) {
|
||||
det.setTenGiga(s.ten_giga);
|
||||
det.setADCEnableMask(s.adc_enable_1g);
|
||||
}
|
||||
det.setNumberOfAnalogSamples(s.num_adc_samples);
|
||||
det.setNumberOfDigitalSamples(s.num_dbit_samples);
|
||||
det.setNumberOfTransceiverSamples(s.num_trans_samples);
|
||||
det.setTenGigaADCEnableMask(s.adc_enable_10g);
|
||||
det.setRxDbitOffset(s.dbit_offset);
|
||||
det.setRxDbitList(s.dbit_list);
|
||||
det.setRxDbitReorder(s.dbit_reorder);
|
||||
det.setTransceiverEnableMask(s.transceiver_mask);
|
||||
}
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, const CTBState &s) {
|
||||
os << "CTB State:"
|
||||
<< "\n Readout Mode: " << ToString(s.readout_mode)
|
||||
<< "\n Num ADC Samples: " << s.num_adc_samples
|
||||
<< "\n Num DBIT Samples: " << s.num_dbit_samples
|
||||
<< "\n Num Trans Samples: " << s.num_trans_samples
|
||||
<< "\n Ten Giga: " << s.ten_giga
|
||||
<< "\n ADC Enable 1G: " << ToStringHex(s.adc_enable_1g)
|
||||
<< "\n ADC Enable 10G: " << ToStringHex(s.adc_enable_10g)
|
||||
<< "\n DBIT Offset: " << s.dbit_offset
|
||||
<< "\n DBIT List: " << ToString(s.dbit_list)
|
||||
<< "\n DBIT Reorder: " << s.dbit_reorder
|
||||
<< "\n Transceiver Mask: " << ToStringHex(s.transceiver_mask);
|
||||
return os;
|
||||
}
|
||||
|
||||
inline void print_current_ctb_state(const Detector &det) {
|
||||
auto ctb_state = get_ctb_state(det);
|
||||
LOG(logINFO) << ctb_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RAII guard for restoring the existing ctb configuration after a test.
|
||||
*
|
||||
* The constructor saves the current ctb config and sets a new config, while the
|
||||
* destructor restores the original config.
|
||||
*/
|
||||
class CTBStateGuard {
|
||||
public:
|
||||
explicit CTBStateGuard(Detector &det,
|
||||
std::optional<CTBState> new_state = std::nullopt)
|
||||
: det(det) {
|
||||
auto type = det.getDetectorType().squash(defs::GENERIC);
|
||||
if (type == defs::CHIPTESTBOARD || type == defs::XILINX_CHIPTESTBOARD) {
|
||||
active = true;
|
||||
if (!new_state.has_value()) {
|
||||
throw sls::RuntimeError(
|
||||
"New CTB state must be provided for CTBStateGuard.");
|
||||
}
|
||||
saved_ = get_ctb_state(det);
|
||||
set_ctb_state(det, new_state.value());
|
||||
}
|
||||
}
|
||||
~CTBStateGuard() {
|
||||
if (active)
|
||||
set_ctb_state(det, saved_);
|
||||
}
|
||||
|
||||
private:
|
||||
Detector &det;
|
||||
bool active{false};
|
||||
CTBState saved_;
|
||||
};
|
||||
|
||||
} // namespace sls::test::acquire
|
||||
@@ -0,0 +1,355 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
|
||||
#include "ExpectedState.h"
|
||||
#include "Caller/test-Caller-global.h"
|
||||
#include "receiver_defs.h"
|
||||
|
||||
// unnamed namespace for internal linkage
|
||||
namespace {
|
||||
using sls::defs;
|
||||
using sls::Detector;
|
||||
using ns = std::chrono::nanoseconds;
|
||||
namespace acq = sls::test::acquire;
|
||||
|
||||
defs::detectorType get_detector_type(const Detector &det) {
|
||||
return det.getDetectorType().tsquash("Inconsistent detector type");
|
||||
}
|
||||
|
||||
defs::xy get_geometry(const Detector &det) {
|
||||
auto modGeometry = det.getModuleGeometry();
|
||||
auto portperModGeometry = det.getPortPerModuleGeometry();
|
||||
return defs::xy{modGeometry.x * portperModGeometry.x,
|
||||
modGeometry.y * portperModGeometry.y};
|
||||
}
|
||||
|
||||
int get_dynamic_range(const Detector &det) {
|
||||
return det.getDynamicRange().tsquash("Inconsistent dynamic range");
|
||||
}
|
||||
|
||||
defs::xy get_port_shape(const Detector &det,
|
||||
std::optional<acq::CTBState> &ctb_state) {
|
||||
auto det_type = get_detector_type(det);
|
||||
auto portSize = det.getPortSize()[0];
|
||||
|
||||
// m3 assumes all counters enabled when getting num channels from client
|
||||
// TODO: in future, remove assumption
|
||||
if (det_type == defs::MYTHEN3) {
|
||||
int nchan = portSize.x / MAX_NUM_COUNTERS;
|
||||
auto counter_mask = det.getCounterMask().tsquash(
|
||||
"Inconsistent counter mask for Mythen3 detector");
|
||||
int num_counters = __builtin_popcount(counter_mask);
|
||||
portSize.x = nchan * num_counters;
|
||||
} else if (det_type == defs::CHIPTESTBOARD ||
|
||||
det_type == defs::XILINX_CHIPTESTBOARD) {
|
||||
if (!ctb_state.has_value()) {
|
||||
throw sls::RuntimeError(
|
||||
"CTB state must be provided to calculate expected port shape");
|
||||
}
|
||||
portSize.x =
|
||||
sls::calculate_ctb_image_size(
|
||||
ctb_state.value(), det_type == defs::XILINX_CHIPTESTBOARD)
|
||||
.second;
|
||||
portSize.y = 1;
|
||||
}
|
||||
return portSize;
|
||||
}
|
||||
|
||||
uint64_t get_total_frames(const Detector &det) {
|
||||
uint64_t repeats =
|
||||
det.getNumberOfTriggers().tsquash("Inconsistent number of triggers");
|
||||
uint64_t numFrames =
|
||||
det.getNumberOfFrames().tsquash("Inconsistent number of frames");
|
||||
int numAdditionalStorageCells = 0;
|
||||
auto det_type = get_detector_type(det);
|
||||
if (det_type == defs::GOTTHARD2) {
|
||||
auto timing_mode =
|
||||
det.getTimingMode().tsquash("Inconsistent timing mode");
|
||||
auto burst_mode = det.getBurstMode().tsquash("Inconsistent burst mode");
|
||||
auto numBursts =
|
||||
det.getNumberOfBursts().tsquash("Inconsistent number of bursts");
|
||||
if (timing_mode == defs::AUTO_TIMING) {
|
||||
// burst mode, repeats = #bursts
|
||||
if (burst_mode == defs::BURST_INTERNAL ||
|
||||
burst_mode == defs::BURST_EXTERNAL) {
|
||||
repeats = numBursts;
|
||||
}
|
||||
// continuous, repeats = 1 (no trigger as well)
|
||||
else {
|
||||
repeats = 1;
|
||||
}
|
||||
} else {
|
||||
// trigger
|
||||
// continuous, numFrames is limited
|
||||
if (burst_mode == defs::CONTINUOUS_INTERNAL ||
|
||||
burst_mode == defs::CONTINUOUS_EXTERNAL) {
|
||||
numFrames = 1;
|
||||
}
|
||||
}
|
||||
} else if (det_type == defs::JUNGFRAU) {
|
||||
numAdditionalStorageCells =
|
||||
det.getNumberOfAdditionalStorageCells().tsquash(
|
||||
"Inconsistent number of additional storage cells");
|
||||
}
|
||||
uint64_t total_frames =
|
||||
numFrames * repeats * (int64_t)(numAdditionalStorageCells + 1);
|
||||
return total_frames;
|
||||
}
|
||||
|
||||
std::vector<defs::ROI> get_rois(const Detector &det) {
|
||||
auto rois = det.getRxROI();
|
||||
auto detsize = det.getDetectorSize();
|
||||
auto det_type = get_detector_type(det);
|
||||
// compensate for m3 channel size and counter mask mess
|
||||
if (det_type == defs::MYTHEN3) {
|
||||
int nchan = detsize.x / MAX_NUM_COUNTERS;
|
||||
auto counter_mask = det.getCounterMask().tsquash(
|
||||
"Inconsistent counter mask for Mythen3 detector");
|
||||
int num_counters = __builtin_popcount(counter_mask);
|
||||
detsize.x = nchan * num_counters;
|
||||
}
|
||||
// replace -1 for complete ROI
|
||||
bool is2D = (detsize.y > 1);
|
||||
for (auto &roi : rois) {
|
||||
if (roi.completeRoi()) {
|
||||
roi.xmin = 0;
|
||||
roi.xmax = detsize.x - 1;
|
||||
if (is2D) {
|
||||
roi.ymin = 0;
|
||||
roi.ymax = detsize.y - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rois;
|
||||
}
|
||||
|
||||
ns get_exptime(const Detector &det) {
|
||||
return ns(det.getExptime().tsquash("Inconsistent exposure time"));
|
||||
}
|
||||
|
||||
ns get_period(const Detector &det) {
|
||||
return ns(det.getPeriod().tsquash("Inconsistent exposure time"));
|
||||
}
|
||||
|
||||
int get_num_udp_interfaces(const Detector &det) {
|
||||
return det.getNumberofUDPInterfaces().tsquash(
|
||||
"Inconsistent number of UDP interfaces");
|
||||
}
|
||||
|
||||
int get_read_n_rows(const Detector &det) {
|
||||
return det.getReadNRows().tsquash("Inconsistent number of read rows");
|
||||
}
|
||||
|
||||
defs::speedLevel get_readout_speed(const Detector &det) {
|
||||
return det.getReadoutSpeed().tsquash("Inconsistent readout speed");
|
||||
}
|
||||
|
||||
bool get_ten_giga(const Detector &det) {
|
||||
return det.getTenGiga().tsquash("Inconsistent 10Giga setting");
|
||||
}
|
||||
|
||||
std::pair<ns, ns> get_sub_exptime_and_sub_period(const Detector &det) {
|
||||
auto exptime = det.getSubExptime().tsquash("Inconsistent sub exptime");
|
||||
auto deadtime = det.getSubDeadTime().tsquash("Inconsistent sub deadtime");
|
||||
auto sub_period = exptime + deadtime;
|
||||
return std::make_pair(ns(exptime), ns(sub_period));
|
||||
}
|
||||
|
||||
acq::CommonExpectedState
|
||||
build_common_state(const Detector &det,
|
||||
std::optional<acq::CTBState> ctb_state) {
|
||||
acq::CommonExpectedState e;
|
||||
e.det_type = get_detector_type(det);
|
||||
e.timing_mode = det.getTimingMode().tsquash("Inconsistent timing mode");
|
||||
e.geometry = get_geometry(det);
|
||||
e.image_size = acq::get_expected_image_size(det, ctb_state);
|
||||
e.port_shape = get_port_shape(det, ctb_state);
|
||||
e.max_frames_per_file =
|
||||
det.getFramesPerFile().tsquash("Inconsistent frames per file");
|
||||
e.frame_discard_policy = det.getRxFrameDiscardPolicy().tsquash(
|
||||
"Inconsistent frame discard policy");
|
||||
e.partial_frames_padding = static_cast<int>(
|
||||
det.getPartialFramesPadding().tsquash("Inconsistent frame padding"));
|
||||
e.scan_parameters = det.getScan().tsquash("Inconsistent scan parameters");
|
||||
e.total_frames = get_total_frames(det);
|
||||
e.frames_in_file = det.getFramesCaught()[0][0];
|
||||
e.additional_json_header =
|
||||
det.getAdditionalJsonHeader().tsquash("Inconsistent JSON header");
|
||||
return e;
|
||||
}
|
||||
|
||||
acq::JungfrauExpectedState build_jungfrau_specific_state(const Detector &det) {
|
||||
acq::JungfrauExpectedState e;
|
||||
e.rois = get_rois(det);
|
||||
e.exptime = get_exptime(det);
|
||||
e.period = get_period(det);
|
||||
e.num_udp_interfaces = get_num_udp_interfaces(det);
|
||||
e.read_n_rows = get_read_n_rows(det);
|
||||
e.readout_speed = get_readout_speed(det);
|
||||
return e;
|
||||
}
|
||||
|
||||
acq::MoenchExpectedState build_moench_specific_state(const Detector &det) {
|
||||
acq::MoenchExpectedState e;
|
||||
e.rois = get_rois(det);
|
||||
e.exptime = get_exptime(det);
|
||||
e.period = get_period(det);
|
||||
e.num_udp_interfaces = get_num_udp_interfaces(det);
|
||||
e.read_n_rows = get_read_n_rows(det);
|
||||
e.readout_speed = get_readout_speed(det);
|
||||
return e;
|
||||
}
|
||||
|
||||
acq::EigerExpectedState build_eiger_specific_state(const Detector &det) {
|
||||
acq::EigerExpectedState e;
|
||||
e.rois = get_rois(det);
|
||||
e.dynamic_range = get_dynamic_range(det);
|
||||
e.ten_giga = get_ten_giga(det);
|
||||
e.exptime = get_exptime(det);
|
||||
e.period = get_period(det);
|
||||
e.threshold_energy =
|
||||
det.getThresholdEnergy().tsquash("Inconsistent threshold energy");
|
||||
auto [sub_exptime, sub_period] = get_sub_exptime_and_sub_period(det);
|
||||
e.sub_exptime = sub_exptime;
|
||||
e.sub_period = sub_period;
|
||||
e.quad = det.getQuad().tsquash("Inconsistent quad setting");
|
||||
e.read_n_rows = get_read_n_rows(det);
|
||||
{
|
||||
for (auto item : det.getRateCorrection())
|
||||
e.rate_corrections.push_back(item.count());
|
||||
}
|
||||
e.readout_speed = get_readout_speed(det);
|
||||
return e;
|
||||
}
|
||||
|
||||
acq::Mythen3ExpectedState build_mythen3_specific_state(const Detector &det) {
|
||||
acq::Mythen3ExpectedState e;
|
||||
e.rois = get_rois(det);
|
||||
e.dynamic_range = get_dynamic_range(det);
|
||||
e.ten_giga = get_ten_giga(det);
|
||||
e.period = get_period(det);
|
||||
e.counter_mask = det.getCounterMask().tsquash(
|
||||
"Inconsistent counter mask for Mythen3 detector");
|
||||
e.exp_times = det.getExptimeForAllGates().tsquash(
|
||||
"Inconsistent exposure times for all gates");
|
||||
e.gate_delays =
|
||||
det.getGateDelayForAllGates().tsquash("Inconsistent gate delays");
|
||||
e.num_gates = det.getNumberOfGates().tsquash(
|
||||
"Inconsistent number of gates for Mythen3 detector");
|
||||
e.threshold_energies =
|
||||
det.getAllThresholdEnergy().tsquash("Inconsistent threshold energies");
|
||||
e.readout_speed = get_readout_speed(det);
|
||||
return e;
|
||||
}
|
||||
|
||||
acq::Gotthard2ExpectedState
|
||||
build_gotthard2_specific_state(const Detector &det) {
|
||||
acq::Gotthard2ExpectedState e;
|
||||
e.rois = get_rois(det);
|
||||
e.exptime = get_exptime(det);
|
||||
e.period = get_period(det);
|
||||
e.burst_mode = det.getBurstMode().tsquash("Inconsistent burst mode");
|
||||
e.readout_speed = get_readout_speed(det);
|
||||
return e;
|
||||
}
|
||||
|
||||
acq::CTBExpectedState build_ctb_specific_state(const Detector &det,
|
||||
const acq::CTBState &ctb_state) {
|
||||
acq::CTBExpectedState e;
|
||||
e.exptime = get_exptime(det);
|
||||
e.period = get_period(det);
|
||||
e.ctb_acq_state = ctb_state;
|
||||
return e;
|
||||
}
|
||||
|
||||
acq::DetectorSpecificState
|
||||
build_detector_specific_state(const Detector &det,
|
||||
std::optional<acq::CTBState> ctb_state) {
|
||||
switch (det.getDetectorType().tsquash("bad type")) {
|
||||
case defs::JUNGFRAU:
|
||||
return build_jungfrau_specific_state(det);
|
||||
case defs::MOENCH:
|
||||
return build_moench_specific_state(det);
|
||||
case defs::EIGER:
|
||||
return build_eiger_specific_state(det);
|
||||
case defs::MYTHEN3:
|
||||
return build_mythen3_specific_state(det);
|
||||
case defs::GOTTHARD2:
|
||||
return build_gotthard2_specific_state(det);
|
||||
case defs::CHIPTESTBOARD:
|
||||
case defs::XILINX_CHIPTESTBOARD:
|
||||
if (!ctb_state.has_value()) {
|
||||
throw sls::RuntimeError(
|
||||
"CTB state must be provided to build expected state");
|
||||
}
|
||||
return build_ctb_specific_state(det, ctb_state.value());
|
||||
default:
|
||||
throw sls::RuntimeError("Unsupported detector type");
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
namespace sls::test::acquire {
|
||||
|
||||
ExpectedState build_expected_state(const Detector &det,
|
||||
const AcquisitionState &acq_state,
|
||||
const FileState &file_state,
|
||||
std::optional<CTBState> ctb_state) {
|
||||
ExpectedState e;
|
||||
e.common_state = build_common_state(det, ctb_state);
|
||||
e.file_state = file_state;
|
||||
e.acquisition_state = acq_state;
|
||||
e.detector_specific_state = build_detector_specific_state(det, ctb_state);
|
||||
return e;
|
||||
}
|
||||
|
||||
int get_expected_image_size(const Detector &det,
|
||||
std::optional<CTBState> ctb_state) {
|
||||
auto det_type = get_detector_type(det);
|
||||
auto dynamic_range = get_dynamic_range(det);
|
||||
int bytes_per_pixel = dynamic_range / 8;
|
||||
int image_size = 0;
|
||||
detParameters par(det_type);
|
||||
|
||||
switch (det_type) {
|
||||
case defs::EIGER: {
|
||||
int num_chips = (par.nChipX / 2);
|
||||
image_size = par.nChanX * par.nChanY * num_chips * bytes_per_pixel;
|
||||
} break;
|
||||
case defs::JUNGFRAU:
|
||||
case defs::MOENCH: {
|
||||
auto num_udp_interfaces = det.getNumberofUDPInterfaces().tsquash(
|
||||
"inconsistent number of udp interfaces");
|
||||
image_size = (par.nChanX * par.nChanY * par.nChipX * par.nChipY *
|
||||
bytes_per_pixel) /
|
||||
num_udp_interfaces;
|
||||
} break;
|
||||
case defs::MYTHEN3: {
|
||||
int counter_mask = det.getCounterMask().squash();
|
||||
int num_counters = __builtin_popcount(counter_mask);
|
||||
int num_channels_per_counter = par.nChanX / MAX_NUM_COUNTERS;
|
||||
image_size = num_channels_per_counter * num_counters * par.nChipX *
|
||||
bytes_per_pixel;
|
||||
} break;
|
||||
case defs::GOTTHARD2: {
|
||||
image_size = par.nChanX * par.nChipX * bytes_per_pixel;
|
||||
} break;
|
||||
case defs::CHIPTESTBOARD:
|
||||
case defs::XILINX_CHIPTESTBOARD:
|
||||
if (!ctb_state.has_value()) {
|
||||
throw sls::RuntimeError(
|
||||
"CTB state must be provided to calculate expected image size");
|
||||
}
|
||||
LOG(logINFORED) << ctb_state.value();
|
||||
image_size =
|
||||
sls::calculate_ctb_image_size(
|
||||
ctb_state.value(), (det_type == defs::XILINX_CHIPTESTBOARD))
|
||||
.first;
|
||||
break;
|
||||
default:
|
||||
throw sls::RuntimeError("Unsupported detector type for this test");
|
||||
}
|
||||
return image_size;
|
||||
}
|
||||
|
||||
} // namespace sls::test::acquire
|
||||
@@ -0,0 +1,119 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Acquire.h"
|
||||
#include "CTBState.h"
|
||||
#include "FileState.h"
|
||||
|
||||
#include <variant>
|
||||
|
||||
namespace sls::test::acquire {
|
||||
|
||||
struct CommonExpectedState {
|
||||
defs::detectorType det_type{};
|
||||
defs::timingMode timing_mode{};
|
||||
defs::xy geometry{};
|
||||
int image_size{};
|
||||
defs::xy port_shape{};
|
||||
int max_frames_per_file{};
|
||||
defs::frameDiscardPolicy frame_discard_policy{};
|
||||
bool partial_frames_padding{};
|
||||
defs::scanParameters scan_parameters{};
|
||||
uint64_t total_frames{};
|
||||
uint64_t frames_in_file{};
|
||||
std::map<std::string, std::string> additional_json_header{};
|
||||
};
|
||||
|
||||
struct JungfrauExpectedState {
|
||||
std::vector<defs::ROI> rois{};
|
||||
ns exptime{};
|
||||
ns period{};
|
||||
int num_udp_interfaces{};
|
||||
int read_n_rows{};
|
||||
defs::speedLevel readout_speed{};
|
||||
};
|
||||
|
||||
struct MoenchExpectedState {
|
||||
std::vector<defs::ROI> rois{};
|
||||
ns exptime{};
|
||||
ns period{};
|
||||
int num_udp_interfaces{};
|
||||
int read_n_rows{};
|
||||
defs::speedLevel readout_speed{};
|
||||
};
|
||||
|
||||
struct EigerExpectedState {
|
||||
std::vector<defs::ROI> rois{};
|
||||
int dynamic_range{};
|
||||
bool ten_giga{};
|
||||
ns exptime{};
|
||||
ns period{};
|
||||
int threshold_energy{};
|
||||
ns sub_exptime{};
|
||||
ns sub_period{};
|
||||
bool quad{};
|
||||
int read_n_rows{};
|
||||
std::vector<int64_t> rate_corrections{};
|
||||
defs::speedLevel readout_speed{};
|
||||
};
|
||||
|
||||
struct Mythen3ExpectedState {
|
||||
std::vector<defs::ROI> rois{};
|
||||
int dynamic_range{};
|
||||
bool ten_giga{};
|
||||
ns period{};
|
||||
int counter_mask{};
|
||||
std::array<ns, 3> exp_times{};
|
||||
std::array<ns, 3> gate_delays{};
|
||||
int num_gates{};
|
||||
std::array<int, 3> threshold_energies{};
|
||||
defs::speedLevel readout_speed{};
|
||||
};
|
||||
|
||||
struct Gotthard2ExpectedState {
|
||||
std::vector<defs::ROI> rois{};
|
||||
ns exptime{};
|
||||
ns period{};
|
||||
defs::burstMode burst_mode{};
|
||||
defs::speedLevel readout_speed{};
|
||||
};
|
||||
|
||||
struct CTBExpectedState {
|
||||
ns exptime{};
|
||||
ns period{};
|
||||
CTBState ctb_acq_state{};
|
||||
};
|
||||
|
||||
using DetectorSpecificState =
|
||||
std::variant<JungfrauExpectedState, MoenchExpectedState, EigerExpectedState,
|
||||
Mythen3ExpectedState, Gotthard2ExpectedState,
|
||||
CTBExpectedState>;
|
||||
|
||||
struct ExpectedState {
|
||||
FileState file_state{};
|
||||
AcquisitionState acquisition_state{};
|
||||
CommonExpectedState common_state{};
|
||||
DetectorSpecificState detector_specific_state{};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const T &get_detector_specific_state(const ExpectedState &expected_state) {
|
||||
return std::get<T>(expected_state.detector_specific_state);
|
||||
}
|
||||
|
||||
template <typename T> bool is_type(const ExpectedState &e) {
|
||||
return std::holds_alternative<T>(e.detector_specific_state);
|
||||
}
|
||||
|
||||
ExpectedState build_expected_state(
|
||||
const Detector &det,
|
||||
const AcquisitionState &acq_state = default_acquisition_state(),
|
||||
const FileState &file_state = default_file_state(),
|
||||
std::optional<CTBState> ctb_state = std::nullopt);
|
||||
|
||||
int get_expected_image_size(const Detector &det,
|
||||
std::optional<CTBState> ctb_state = std::nullopt);
|
||||
|
||||
} // namespace sls::test::acquire
|
||||
@@ -0,0 +1,100 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
|
||||
#include "sls/Detector.h"
|
||||
#include "sls/logger.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace sls::test::acquire {
|
||||
|
||||
struct FileState {
|
||||
std::string file_path;
|
||||
std::string file_prefix;
|
||||
int64_t file_acq_index;
|
||||
bool file_write;
|
||||
bool file_overwrite;
|
||||
slsDetectorDefs::fileFormat file_format;
|
||||
};
|
||||
|
||||
inline FileState default_file_state() {
|
||||
return {"/tmp", "sls_test", 0, true, true, slsDetectorDefs::BINARY};
|
||||
}
|
||||
|
||||
inline FileState get_file_state(const Detector &det) {
|
||||
return FileState{
|
||||
det.getFilePath().tsquash("Inconsistent file path"),
|
||||
det.getFileNamePrefix().tsquash("Inconsistent file prefix"),
|
||||
det.getAcquisitionIndex().tsquash(
|
||||
"Inconsistent file acquisition index"),
|
||||
det.getFileWrite().tsquash("Inconsistent file write"),
|
||||
det.getFileOverWrite().tsquash("Inconsistent file overwrite"),
|
||||
det.getFileFormat().tsquash("Inconsistent file format")};
|
||||
}
|
||||
|
||||
inline void set_file_state(Detector &det, const FileState &s) {
|
||||
if (!s.file_path.empty())
|
||||
det.setFilePath(s.file_path);
|
||||
det.setFileNamePrefix(s.file_prefix);
|
||||
det.setAcquisitionIndex(s.file_acq_index);
|
||||
det.setFileWrite(s.file_write);
|
||||
det.setFileOverWrite(s.file_overwrite);
|
||||
det.setFileFormat(s.file_format);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
get_master_file_name(const FileState &s = default_file_state()) {
|
||||
auto master_file_prefix = s.file_path + "/" + s.file_prefix + "_master_" +
|
||||
std::to_string(s.file_acq_index);
|
||||
if (s.file_format == defs::BINARY)
|
||||
return master_file_prefix + ".json";
|
||||
return master_file_prefix + ".h5";
|
||||
}
|
||||
|
||||
inline std::string
|
||||
get_virtual_file_name(const FileState &s = default_file_state()) {
|
||||
return s.file_path + "/" + s.file_prefix + "_virtual_" +
|
||||
std::to_string(s.file_acq_index) + ".h5";
|
||||
}
|
||||
|
||||
inline std::string
|
||||
get_first_port_first_file_name(const FileState &s = default_file_state()) {
|
||||
auto file_prefix = s.file_path + "/" + s.file_prefix + "_d0_f0_" +
|
||||
std::to_string(s.file_acq_index);
|
||||
if (s.file_format == defs::BINARY)
|
||||
return file_prefix + ".raw";
|
||||
return file_prefix + ".h5";
|
||||
}
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, const FileState &s) {
|
||||
os << "File State:"
|
||||
<< "\n Path: " << s.file_path << "\n Prefix: " << s.file_prefix
|
||||
<< "\n Acq Index: " << s.file_acq_index << "\n Write: " << s.file_write
|
||||
<< "\n Overwrite: " << s.file_overwrite
|
||||
<< "\n Format: " << ToString(s.file_format)
|
||||
<< "\n Master File: " << get_master_file_name(s)
|
||||
<< "\n Virtual File: " << get_virtual_file_name(s);
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RAII guard for restoring the file state of a detector.
|
||||
*
|
||||
* The constructor saves the current file state and sets a new state, while the
|
||||
* destructor restores the original state.
|
||||
*/
|
||||
class FileStateGuard {
|
||||
public:
|
||||
explicit FileStateGuard(Detector &det, const FileState &new_state)
|
||||
: det(det), saved_(get_file_state(det)) {
|
||||
set_file_state(det, new_state);
|
||||
}
|
||||
~FileStateGuard() { set_file_state(det, saved_); }
|
||||
|
||||
private:
|
||||
Detector &det;
|
||||
FileState saved_;
|
||||
};
|
||||
|
||||
} // namespace sls::test::acquire
|
||||
@@ -0,0 +1,456 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
|
||||
#include "acquire/ExpectedState.h"
|
||||
#include "master_file/Checker.h"
|
||||
|
||||
#include "MasterAttributes.h"
|
||||
|
||||
namespace sls::test::checks {
|
||||
|
||||
namespace acq = sls::test::acquire;
|
||||
namespace mf = sls::test::master_file;
|
||||
|
||||
inline bool operator==(sls::ns lhs, sls::ns rhs) {
|
||||
return lhs.count() == rhs.count();
|
||||
}
|
||||
|
||||
// different values based on file format
|
||||
template <typename CheckerT> void check_version(CheckerT &checker) {
|
||||
#ifdef HDF5C
|
||||
if constexpr (std::is_same_v<CheckerT, mf::Checker<mf::H5Context>>) {
|
||||
checker.template check<double>(MasterAttributes::N_VERSION.data(),
|
||||
HDF5_WRITER_VERSION,
|
||||
mf::AccessType::Attribute);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
checker.template check<double>(MasterAttributes::N_VERSION.data(),
|
||||
BINARY_WRITER_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_detector_type(CheckerT &checker, const defs::detectorType &value) {
|
||||
checker.template check<std::string>(
|
||||
MasterAttributes::N_DETECTOR_TYPE.data(), ToString(value));
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_timing_mode(CheckerT &checker, const defs::timingMode &value) {
|
||||
checker.template check<std::string>(MasterAttributes::N_TIMING_MODE.data(),
|
||||
ToString(value));
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_geometry(CheckerT &checker, const defs::xy &value) {
|
||||
checker.template check<defs::xy>(MasterAttributes::N_GEOMETRY.data(),
|
||||
value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_image_size(CheckerT &checker, const int &value) {
|
||||
checker.template check<int>(MasterAttributes::N_IMAGE_SIZE.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_port_shape(CheckerT &checker, const defs::xy &value) {
|
||||
checker.template check<defs::xy>(MasterAttributes::N_PIXELS.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_frames_per_file(CheckerT &checker, const int &value) {
|
||||
checker.template check<int>(MasterAttributes::N_MAX_FRAMES_PER_FILE.data(),
|
||||
value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_frame_discard_policy(CheckerT &checker,
|
||||
const defs::frameDiscardPolicy &value) {
|
||||
checker.template check<std::string>(
|
||||
MasterAttributes::N_FRAME_DISCARD_POLICY.data(), ToString(value));
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_partial_frames_padding(CheckerT &checker, const bool &value) {
|
||||
checker.template check<int>(MasterAttributes::N_FRAME_PADDING.data(),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_scan_parameters(CheckerT &checker,
|
||||
const defs::scanParameters &value) {
|
||||
checker.template check<defs::scanParameters>(
|
||||
MasterAttributes::N_SCAN_PARAMETERS.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_total_frames(CheckerT &checker, const uint64_t &value) {
|
||||
checker.template check<uint64_t>(MasterAttributes::N_TOTAL_FRAMES.data(),
|
||||
value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_frames_in_file(CheckerT &checker, const uint64_t &value) {
|
||||
checker.template check<uint64_t>(MasterAttributes::N_FRAMES_IN_FILE.data(),
|
||||
value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_additional_json_header(
|
||||
CheckerT &checker, const std::map<std::string, std::string> &value) {
|
||||
checker.template check<std::map<std::string, std::string>>(
|
||||
MasterAttributes::N_ADDITIONAL_JSON_HEADER.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_rois(CheckerT &checker, const std::vector<defs::ROI> &value) {
|
||||
checker.template check<std::vector<defs::ROI>>(
|
||||
MasterAttributes::N_RECEIVER_ROIS.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_exptime(CheckerT &checker, const ns &value) {
|
||||
checker.template check<std::string>(
|
||||
MasterAttributes::N_EXPOSURE_TIME.data(), ToString(value));
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_period(CheckerT &checker, const ns &value) {
|
||||
checker.template check<std::string>(
|
||||
MasterAttributes::N_ACQUISITION_PERIOD.data(), ToString(value));
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_num_udp_interfaces(CheckerT &checker, const int &value) {
|
||||
checker.template check<int>(MasterAttributes::N_NUM_UDP_INTERFACES.data(),
|
||||
value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_read_n_rows(CheckerT &checker, const int &value) {
|
||||
checker.template check<int>(MasterAttributes::N_NUMBER_OF_ROWS.data(),
|
||||
value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_readout_speed(CheckerT &checker, const defs::speedLevel &value) {
|
||||
checker.template check<std::string>(
|
||||
MasterAttributes::N_READOUT_SPEED.data(), ToString(value));
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_dynamic_range(CheckerT &checker, const int &value) {
|
||||
checker.template check<int>(MasterAttributes::N_DYNAMIC_RANGE.data(),
|
||||
value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_ten_giga(CheckerT &checker, const bool &value) {
|
||||
checker.template check<int>(MasterAttributes::N_TEN_GIGA.data(),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_threshold_energy(CheckerT &checker, const int &value) {
|
||||
checker.template check<int>(MasterAttributes::N_THRESHOLD_ENERGY.data(),
|
||||
value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_sub_exptime(CheckerT &checker, const ns &value) {
|
||||
checker.template check<std::string>(
|
||||
MasterAttributes::N_SUB_EXPOSURE_TIME.data(), ToString(value));
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_sub_period(CheckerT &checker, const ns &value) {
|
||||
checker.template check<std::string>(
|
||||
MasterAttributes::N_SUB_ACQUISITION_PERIOD.data(), ToString(value));
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_quad(CheckerT &checker, const bool &value) {
|
||||
checker.template check<int>(MasterAttributes::N_QUAD.data(),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_rate_corrections(CheckerT &checker,
|
||||
const std::vector<int64_t> &value) {
|
||||
checker.template check<std::vector<int64_t>>(
|
||||
MasterAttributes::N_RATE_CORRECTIONS.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_counter_mask(CheckerT &checker, const int &value) {
|
||||
checker.template check<int>(MasterAttributes::N_COUNTER_MASK.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_exptime_array(CheckerT &checker,
|
||||
const std::array<sls::ns, 3UL> &value) {
|
||||
checker.template check<std::array<sls::ns, 3UL>>(
|
||||
MasterAttributes::N_EXPOSURE_TIMES.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_gate_delay_array(CheckerT &checker,
|
||||
const std::array<sls::ns, 3UL> &value) {
|
||||
checker.template check<std::array<sls::ns, 3UL>>(
|
||||
MasterAttributes::N_GATE_DELAYS.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_gates(CheckerT &checker, const int &value) {
|
||||
checker.template check<int>(MasterAttributes::N_GATES.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_threshold_energies(CheckerT &checker,
|
||||
const std::array<int, 3UL> &value) {
|
||||
checker.template check<std::array<int, 3UL>>(
|
||||
MasterAttributes::N_THRESHOLD_ENERGIES.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_burst_mode(CheckerT &checker, const defs::burstMode &value) {
|
||||
checker.template check<std::string>(MasterAttributes::N_BURST_MODE.data(),
|
||||
ToString(value));
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_readout_mode(CheckerT &checker, const defs::readoutMode &value) {
|
||||
auto analog = static_cast<int>(
|
||||
(value == defs::ANALOG_ONLY || value == defs::ANALOG_AND_DIGITAL));
|
||||
auto digital = static_cast<int>(value == defs::DIGITAL_ONLY ||
|
||||
value == defs::ANALOG_AND_DIGITAL ||
|
||||
value == defs::DIGITAL_AND_TRANSCEIVER);
|
||||
auto trans = static_cast<int>(value == defs::DIGITAL_AND_TRANSCEIVER ||
|
||||
value == defs::TRANSCEIVER_ONLY);
|
||||
|
||||
if (analog)
|
||||
checker.template check<int>(MasterAttributes::N_ANALOG.data(),
|
||||
static_cast<int>(analog));
|
||||
if (digital)
|
||||
checker.template check<int>(MasterAttributes::N_DIGITAL.data(),
|
||||
static_cast<int>(digital));
|
||||
if (trans)
|
||||
checker.template check<int>(MasterAttributes::N_TRANSCEIVER.data(),
|
||||
static_cast<int>(trans));
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_analog_samples(CheckerT &checker, const int &value) {
|
||||
checker.template check<int>(MasterAttributes::N_ANALOG_SAMPLES.data(),
|
||||
value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_digital_samples(CheckerT &checker, const int &value) {
|
||||
checker.template check<int>(MasterAttributes::N_DIGITAL_SAMPLES.data(),
|
||||
value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_transceiver_samples(CheckerT &checker, const int &value) {
|
||||
checker.template check<int>(MasterAttributes::N_TRANSCEIVER_SAMPLES.data(),
|
||||
value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_adc_mask(CheckerT &checker, const uint32_t &value) {
|
||||
checker.template check<uint32_t>(MasterAttributes::N_ADC_MASK.data(),
|
||||
value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_dbit_offset(CheckerT &checker, const int &value) {
|
||||
checker.template check<int>(MasterAttributes::N_DBIT_OFFSET.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_dbit_list(CheckerT &checker, const std::vector<int> &value) {
|
||||
uint64_t dbit_bitset = 0;
|
||||
for (auto &i : value) {
|
||||
dbit_bitset |= (static_cast<uint64_t>(1) << i);
|
||||
}
|
||||
checker.template check<uint64_t>(MasterAttributes::N_DBIT_BITSET.data(),
|
||||
dbit_bitset);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_dbit_reorder(CheckerT &checker, const int &value) {
|
||||
checker.template check<int>(MasterAttributes::N_DBIT_REORDER.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_transceiver_mask(CheckerT &checker, const uint32_t &value) {
|
||||
checker.template check<uint32_t>(
|
||||
MasterAttributes::N_TRANSCEIVER_MASK.data(), value);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_common_metadata(CheckerT &checker,
|
||||
const acq::ExpectedState &expected) {
|
||||
check_version(checker);
|
||||
auto st = expected.common_state;
|
||||
check_detector_type(checker, st.det_type);
|
||||
check_geometry(checker, st.geometry);
|
||||
check_image_size(checker, st.image_size);
|
||||
check_port_shape(checker, st.port_shape);
|
||||
check_frames_per_file(checker, st.max_frames_per_file);
|
||||
check_frame_discard_policy(checker, st.frame_discard_policy);
|
||||
check_partial_frames_padding(checker, st.partial_frames_padding);
|
||||
check_scan_parameters(checker, st.scan_parameters);
|
||||
check_total_frames(checker, st.total_frames);
|
||||
check_frames_in_file(checker, st.frames_in_file);
|
||||
check_additional_json_header(checker, st.additional_json_header);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_jungfrau_metadata(CheckerT &checker,
|
||||
const acq::ExpectedState &expected) {
|
||||
const auto &st =
|
||||
std::get<acq::JungfrauExpectedState>(expected.detector_specific_state);
|
||||
check_rois(checker, st.rois);
|
||||
check_exptime(checker, st.exptime);
|
||||
check_period(checker, st.period);
|
||||
check_num_udp_interfaces(checker, st.num_udp_interfaces);
|
||||
check_read_n_rows(checker, st.read_n_rows);
|
||||
check_readout_speed(checker, st.readout_speed);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_moench_metadata(CheckerT &checker,
|
||||
const acq::ExpectedState &expected) {
|
||||
const auto &st =
|
||||
std::get<acq::MoenchExpectedState>(expected.detector_specific_state);
|
||||
check_rois(checker, st.rois);
|
||||
check_exptime(checker, st.exptime);
|
||||
check_period(checker, st.period);
|
||||
check_num_udp_interfaces(checker, st.num_udp_interfaces);
|
||||
check_read_n_rows(checker, st.read_n_rows);
|
||||
check_readout_speed(checker, st.readout_speed);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_eiger_metadata(CheckerT &checker,
|
||||
const acq::ExpectedState &expected) {
|
||||
const auto &st =
|
||||
std::get<acq::EigerExpectedState>(expected.detector_specific_state);
|
||||
check_rois(checker, st.rois);
|
||||
check_dynamic_range(checker, st.dynamic_range);
|
||||
check_ten_giga(checker, st.ten_giga);
|
||||
check_exptime(checker, st.exptime);
|
||||
check_period(checker, st.period);
|
||||
check_threshold_energy(checker, st.threshold_energy);
|
||||
check_sub_exptime(checker, st.sub_exptime);
|
||||
check_sub_period(checker, st.sub_period);
|
||||
check_quad(checker, st.quad);
|
||||
check_read_n_rows(checker, st.read_n_rows);
|
||||
check_rate_corrections(checker, st.rate_corrections);
|
||||
check_readout_speed(checker, st.readout_speed);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_mythen3_metadata(CheckerT &checker,
|
||||
const acq::ExpectedState &expected) {
|
||||
const auto &st =
|
||||
std::get<acq::Mythen3ExpectedState>(expected.detector_specific_state);
|
||||
check_rois(checker, st.rois);
|
||||
check_dynamic_range(checker, st.dynamic_range);
|
||||
check_ten_giga(checker, st.ten_giga);
|
||||
check_period(checker, st.period);
|
||||
check_counter_mask(checker, st.counter_mask);
|
||||
check_exptime_array(checker, st.exp_times);
|
||||
check_gate_delay_array(checker, st.gate_delays);
|
||||
check_gates(checker, st.num_gates);
|
||||
check_threshold_energies(checker, st.threshold_energies);
|
||||
check_readout_speed(checker, st.readout_speed);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_gotthard2_metadata(CheckerT &checker,
|
||||
const acq::ExpectedState &expected) {
|
||||
const auto &st =
|
||||
std::get<acq::Gotthard2ExpectedState>(expected.detector_specific_state);
|
||||
check_rois(checker, st.rois);
|
||||
check_exptime(checker, st.exptime);
|
||||
check_period(checker, st.period);
|
||||
check_burst_mode(checker, st.burst_mode);
|
||||
check_readout_speed(checker, st.readout_speed);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_ctb_metadata(CheckerT &checker, const acq::ExpectedState &expected) {
|
||||
const auto &st =
|
||||
std::get<acq::CTBExpectedState>(expected.detector_specific_state);
|
||||
check_exptime(checker, st.exptime);
|
||||
check_period(checker, st.period);
|
||||
|
||||
// 10g for xilinx, 1g/10g for altera ctb
|
||||
bool ten_giga = true;
|
||||
if (expected.common_state.det_type == defs::CHIPTESTBOARD) {
|
||||
check_ten_giga(checker, st.ctb_acq_state.ten_giga);
|
||||
if (!st.ctb_acq_state.ten_giga) {
|
||||
ten_giga = false;
|
||||
}
|
||||
}
|
||||
if (ten_giga)
|
||||
check_adc_mask(checker, st.ctb_acq_state.adc_enable_10g);
|
||||
else
|
||||
check_adc_mask(checker, st.ctb_acq_state.adc_enable_1g);
|
||||
|
||||
check_readout_mode(checker, st.ctb_acq_state.readout_mode);
|
||||
check_analog_samples(checker, st.ctb_acq_state.num_adc_samples);
|
||||
check_digital_samples(checker, st.ctb_acq_state.num_dbit_samples);
|
||||
check_transceiver_samples(checker, st.ctb_acq_state.num_trans_samples);
|
||||
check_dbit_offset(checker, st.ctb_acq_state.dbit_offset);
|
||||
check_dbit_list(checker, st.ctb_acq_state.dbit_list);
|
||||
check_dbit_reorder(checker, st.ctb_acq_state.dbit_reorder);
|
||||
check_transceiver_mask(checker, st.ctb_acq_state.transceiver_mask);
|
||||
}
|
||||
|
||||
template <typename CheckerT>
|
||||
void check_metadata(CheckerT &checker, const acq::ExpectedState &expected) {
|
||||
check_common_metadata(checker, expected);
|
||||
switch (expected.common_state.det_type) {
|
||||
case defs::JUNGFRAU:
|
||||
check_jungfrau_metadata(checker, expected);
|
||||
break;
|
||||
case defs::MOENCH:
|
||||
check_moench_metadata(checker, expected);
|
||||
break;
|
||||
case defs::EIGER:
|
||||
check_eiger_metadata(checker, expected);
|
||||
break;
|
||||
case defs::MYTHEN3:
|
||||
check_mythen3_metadata(checker, expected);
|
||||
break;
|
||||
case defs::GOTTHARD2:
|
||||
check_gotthard2_metadata(checker, expected);
|
||||
break;
|
||||
case defs::CHIPTESTBOARD:
|
||||
case defs::XILINX_CHIPTESTBOARD:
|
||||
check_ctb_metadata(checker, expected);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error(
|
||||
"Unsupported detector type for metadata checks");
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
check_binary_file_size(const int expected_image_size, const int64_t num_frames,
|
||||
const acq::FileState &st = acq::default_file_state()) {
|
||||
assert(st.file_format == defs::BINARY);
|
||||
auto fname = acq::get_first_port_first_file_name(st);
|
||||
auto expected_file_size =
|
||||
num_frames * (expected_image_size + sizeof(defs::sls_receiver_header));
|
||||
auto actual_file_size = std::filesystem::file_size(fname);
|
||||
REQUIRE(actual_file_size == expected_file_size);
|
||||
}
|
||||
|
||||
} // namespace sls::test::checks
|
||||
@@ -0,0 +1,59 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
|
||||
#include "Readers.h"
|
||||
#include "ReadersJson.h"
|
||||
#ifdef HDF5C
|
||||
#include "ReadersH5.h"
|
||||
#endif
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
namespace sls::test::master_file {
|
||||
|
||||
template <typename Context> class Checker;
|
||||
|
||||
/** JSON Specialization */
|
||||
template <> class Checker<JsonContext> {
|
||||
public:
|
||||
explicit Checker(const std::string &path) : ctx_(path) {}
|
||||
explicit Checker(JsonContext ctx) : ctx_(std::move(ctx)) {}
|
||||
const JsonContext &context() const { return ctx_; }
|
||||
|
||||
template <typename T>
|
||||
void check(const std::string &name, const T &expected,
|
||||
AccessType = AccessType::Dataset) const {
|
||||
CAPTURE(name);
|
||||
REQUIRE(ctx_.doc.HasMember(name.c_str()));
|
||||
auto retval = read<JsonContext, T>(ctx_, name);
|
||||
REQUIRE(retval == expected);
|
||||
}
|
||||
|
||||
private:
|
||||
JsonContext ctx_;
|
||||
};
|
||||
|
||||
/** HDF5 Specialization */
|
||||
#ifdef HDF5C
|
||||
|
||||
template <> class Checker<H5Context> {
|
||||
public:
|
||||
explicit Checker(const std::string &path) : ctx_(path) {}
|
||||
explicit Checker(H5Context ctx) : ctx_(std::move(ctx)) {}
|
||||
const H5Context &context() const { return ctx_; }
|
||||
|
||||
template <typename T>
|
||||
void check(const std::string &name, const T &expected,
|
||||
AccessType access = AccessType::Dataset) const {
|
||||
auto retval = read<H5Context, T>(ctx_, name, access);
|
||||
REQUIRE(retval == expected);
|
||||
}
|
||||
|
||||
private:
|
||||
H5Context ctx_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace sls::test::master_file
|
||||
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#ifdef HDF5C
|
||||
#include "H5Cpp.h"
|
||||
#endif
|
||||
|
||||
namespace sls::test::master_file {
|
||||
|
||||
struct JsonContext {
|
||||
rapidjson::Document doc;
|
||||
|
||||
explicit JsonContext(const std::string &path) {
|
||||
parse_binary_master_attributes(path);
|
||||
}
|
||||
|
||||
private:
|
||||
void parse_binary_master_attributes(const std::string &file_path) {
|
||||
REQUIRE(std::filesystem::exists(file_path));
|
||||
|
||||
std::ifstream file(file_path);
|
||||
REQUIRE(file.is_open());
|
||||
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
|
||||
std::string json_str = buffer.str();
|
||||
|
||||
rapidjson::ParseResult result = doc.Parse(json_str.c_str());
|
||||
|
||||
if (!result) {
|
||||
std::cout << "JSON parse error: " << GetParseError_En(result.Code())
|
||||
<< " (at offset " << result.Offset() << ")" << std::endl;
|
||||
|
||||
size_t offset = result.Offset();
|
||||
std::string context =
|
||||
json_str.substr(std::max(0, (int)offset - 20), 40);
|
||||
std::cout << "Context around error: \"" << context << "\""
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
REQUIRE(result);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef HDF5C
|
||||
struct H5Context {
|
||||
H5::H5File file;
|
||||
explicit H5Context(const std::string &path) : file(path, H5F_ACC_RDONLY) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace sls::test::master_file
|
||||
@@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
|
||||
#include "Context.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
||||
namespace sls::test::master_file {
|
||||
|
||||
template <typename Context, typename T> struct Reader;
|
||||
template <typename Context, typename T> struct AttributeReader;
|
||||
|
||||
enum class AccessType { Dataset, Attribute };
|
||||
|
||||
template <typename Context, typename T>
|
||||
T read(const Context &ctx, const std::string &name,
|
||||
AccessType access = AccessType::Dataset) {
|
||||
return Reader<Context, T>::read(ctx, name, access);
|
||||
}
|
||||
|
||||
inline void check_size(size_t actual, size_t expected, const std::string &name,
|
||||
const std::string &doc) {
|
||||
if (actual != expected) {
|
||||
throw sls::RuntimeError(
|
||||
doc + " array " + name + " has " + std::to_string(actual) +
|
||||
" elements instead of " + std::to_string(expected));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sls::test::master_file
|
||||
@@ -0,0 +1,295 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
|
||||
#include "Readers.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include <iostream>
|
||||
|
||||
#ifdef HDF5C
|
||||
#include "H5Cpp.h"
|
||||
|
||||
namespace sls::test::master_file {
|
||||
using ns = std::chrono::nanoseconds;
|
||||
|
||||
static const std::string HDF5_GROUP = "/entry/instrument/detector/";
|
||||
|
||||
/* --safety checks-- */
|
||||
inline void require_dataset(const H5Context &ctx, const std::string &name) {
|
||||
const std::string full_name = HDF5_GROUP + name;
|
||||
if (H5Lexists(ctx.file.getId(), full_name.c_str(), H5P_DEFAULT) <= 0) {
|
||||
throw sls::RuntimeError("Missing HDF5 dataset: " + full_name);
|
||||
}
|
||||
}
|
||||
|
||||
inline void require_file_attribute(const H5Context &ctx,
|
||||
const std::string &name) {
|
||||
if (!H5Aexists_by_name(ctx.file.getId(), "/", name.c_str(), H5P_DEFAULT)) {
|
||||
throw sls::RuntimeError("Missing HDF5 attribute: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
/* --scalar reads-- */
|
||||
template <> struct Reader<H5Context, int> {
|
||||
static int read(const H5Context &ctx, const std::string &name,
|
||||
AccessType access) {
|
||||
if (access == AccessType::Attribute) {
|
||||
throw RuntimeError("int attribute access not supported for HDF5");
|
||||
}
|
||||
require_dataset(ctx, name);
|
||||
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
|
||||
int out{};
|
||||
ds.read(&out, H5::PredType::NATIVE_INT);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<H5Context, uint32_t> {
|
||||
static uint32_t read(const H5Context &ctx, const std::string &name,
|
||||
AccessType access) {
|
||||
if (access == AccessType::Attribute) {
|
||||
throw RuntimeError(
|
||||
"uint32_t attribute access not supported for HDF5");
|
||||
}
|
||||
require_dataset(ctx, name);
|
||||
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
|
||||
uint32_t out{};
|
||||
ds.read(&out, H5::PredType::STD_U32LE);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<H5Context, uint64_t> {
|
||||
static uint64_t read(const H5Context &ctx, const std::string &name,
|
||||
AccessType access) {
|
||||
if (access == AccessType::Attribute) {
|
||||
throw RuntimeError(
|
||||
"'uint64_t' attribute access not supported for HDF5");
|
||||
}
|
||||
uint64_t out{};
|
||||
require_dataset(ctx, name);
|
||||
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
|
||||
ds.read(&out, H5::PredType::STD_U64LE);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<H5Context, double> {
|
||||
static double read(const H5Context &ctx, const std::string &name,
|
||||
AccessType access) {
|
||||
double out{};
|
||||
if (access == AccessType::Attribute) {
|
||||
require_file_attribute(ctx, name);
|
||||
auto attr = ctx.file.openAttribute(name);
|
||||
attr.read(attr.getDataType(), &out);
|
||||
return out;
|
||||
}
|
||||
// dataset
|
||||
require_dataset(ctx, name);
|
||||
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
|
||||
ds.read(&out, H5::PredType::NATIVE_DOUBLE);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<H5Context, std::string> {
|
||||
static std::string read(const H5Context &ctx, const std::string &name,
|
||||
AccessType access) {
|
||||
if (access == AccessType::Attribute) {
|
||||
throw RuntimeError(
|
||||
"string attribute access not supported for HDF5");
|
||||
}
|
||||
require_dataset(ctx, name);
|
||||
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
|
||||
std::string out{};
|
||||
ds.read(out, ds.getStrType());
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
/** complex types */
|
||||
template <> struct Reader<H5Context, defs::xy> {
|
||||
static defs::xy read(const H5Context &ctx, const std::string &name,
|
||||
AccessType access) {
|
||||
if (access == AccessType::Attribute) {
|
||||
throw RuntimeError(
|
||||
"'defs::xy' attribute access not supported for HDF5");
|
||||
}
|
||||
require_dataset(ctx, name);
|
||||
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
|
||||
// define type
|
||||
H5::CompType type(sizeof(defs::xy));
|
||||
type.insertMember("x", HOFFSET(defs::xy, x), H5::PredType::NATIVE_INT);
|
||||
type.insertMember("y", HOFFSET(defs::xy, y), H5::PredType::NATIVE_INT);
|
||||
// read
|
||||
defs::xy out{};
|
||||
ds.read(&out, type);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
inline hsize_t get_1d_size(const H5::DataSet &ds) {
|
||||
H5::DataSpace space = ds.getSpace();
|
||||
hsize_t dims[1];
|
||||
space.getSimpleExtentDims(dims);
|
||||
return dims[0];
|
||||
}
|
||||
|
||||
template <> struct Reader<H5Context, std::vector<defs::ROI>> {
|
||||
static std::vector<defs::ROI>
|
||||
read(const H5Context &ctx, const std::string &name, AccessType access) {
|
||||
if (access == AccessType::Attribute) {
|
||||
throw RuntimeError("'std::vector<defs::ROI>' attribute access not "
|
||||
"supported for HDF5");
|
||||
}
|
||||
require_dataset(ctx, name);
|
||||
// define type
|
||||
H5::CompType type(sizeof(defs::ROI));
|
||||
type.insertMember("xmin", HOFFSET(defs::ROI, xmin),
|
||||
H5::PredType::NATIVE_INT);
|
||||
type.insertMember("xmax", HOFFSET(defs::ROI, xmax),
|
||||
H5::PredType::NATIVE_INT);
|
||||
type.insertMember("ymin", HOFFSET(defs::ROI, ymin),
|
||||
H5::PredType::NATIVE_INT);
|
||||
type.insertMember("ymax", HOFFSET(defs::ROI, ymax),
|
||||
H5::PredType::NATIVE_INT);
|
||||
// read
|
||||
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
|
||||
auto len = get_1d_size(ds);
|
||||
std::vector<defs::ROI> out{};
|
||||
out.resize(len);
|
||||
ds.read(out.data(), type);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<H5Context, defs::scanParameters> {
|
||||
static defs::scanParameters
|
||||
read(const H5Context &ctx, const std::string &name, AccessType access) {
|
||||
if (access == AccessType::Attribute) {
|
||||
throw RuntimeError("'defs::scanParameters' attribute access not "
|
||||
"supported for HDF5");
|
||||
}
|
||||
require_dataset(ctx, name);
|
||||
// define type
|
||||
H5::CompType type(sizeof(defs::scanParameters));
|
||||
type.insertMember("enable", HOFFSET(defs::scanParameters, enable),
|
||||
H5::PredType::NATIVE_INT);
|
||||
type.insertMember("dacInd", HOFFSET(defs::scanParameters, dacInd),
|
||||
H5::PredType::NATIVE_INT);
|
||||
type.insertMember("startOffset",
|
||||
HOFFSET(defs::scanParameters, startOffset),
|
||||
H5::PredType::NATIVE_INT);
|
||||
type.insertMember("stopOffset",
|
||||
HOFFSET(defs::scanParameters, stopOffset),
|
||||
H5::PredType::NATIVE_INT);
|
||||
type.insertMember("stepSize", HOFFSET(defs::scanParameters, stepSize),
|
||||
H5::PredType::NATIVE_INT);
|
||||
type.insertMember("dacSettleTime_ns",
|
||||
HOFFSET(defs::scanParameters, dacSettleTime_ns),
|
||||
H5::PredType::STD_I64LE);
|
||||
// read
|
||||
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
|
||||
defs::scanParameters out{};
|
||||
ds.read(&out, type);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
/** arrays/vectors/maps */
|
||||
template <> struct Reader<H5Context, std::array<int, 3UL>> {
|
||||
static std::array<int, 3UL>
|
||||
read(const H5Context &ctx, const std::string &name, AccessType access) {
|
||||
if (access == AccessType::Attribute) {
|
||||
throw RuntimeError("'std::array<int, 3UL>' attribute access not "
|
||||
"supported for HDF5");
|
||||
}
|
||||
require_dataset(ctx, name);
|
||||
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
|
||||
auto len = get_1d_size(ds);
|
||||
check_size(len, 3, name, "HDF5");
|
||||
std::array<int, 3UL> out{};
|
||||
ds.read(out.data(), H5::PredType::NATIVE_INT);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<H5Context, std::array<ns, 3UL>> {
|
||||
static std::array<ns, 3UL>
|
||||
read(const H5Context &ctx, const std::string &name, AccessType access) {
|
||||
if (access == AccessType::Attribute) {
|
||||
throw RuntimeError("'std::array<ns, 3UL>' attribute access not "
|
||||
"supported for HDF5");
|
||||
}
|
||||
require_dataset(ctx, name);
|
||||
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
|
||||
auto len = get_1d_size(ds);
|
||||
check_size(len, 3, name, "HDF5");
|
||||
|
||||
// read int raw char buffer
|
||||
std::vector<const char *> raw(len);
|
||||
ds.read(raw.data(), ds.getStrType());
|
||||
|
||||
std::array<ns, 3UL> out{};
|
||||
for (size_t i = 0; i != len; ++i) {
|
||||
out[i] = StringTo<ns>(raw[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<H5Context, std::vector<int64_t>> {
|
||||
static std::vector<int64_t>
|
||||
read(const H5Context &ctx, const std::string &name, AccessType access) {
|
||||
if (access == AccessType::Attribute) {
|
||||
throw RuntimeError("'std::vector<int64_t>' attribute access not "
|
||||
"supported for HDF5");
|
||||
}
|
||||
require_dataset(ctx, name);
|
||||
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
|
||||
auto len = get_1d_size(ds);
|
||||
std::vector<int64_t> out{};
|
||||
out.resize(len);
|
||||
ds.read(out.data(), H5::PredType::STD_I64LE);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<H5Context, std::map<std::string, std::string>> {
|
||||
static std::map<std::string, std::string>
|
||||
read(const H5Context &ctx, const std::string &name, AccessType access) {
|
||||
if (access == AccessType::Attribute) {
|
||||
throw RuntimeError("'std::map<std::string, std::string>' attribute "
|
||||
"access not supported for HDF5");
|
||||
}
|
||||
require_dataset(ctx, name);
|
||||
std::map<std::string, std::string> out{};
|
||||
// dim
|
||||
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
|
||||
auto len = get_1d_size(ds);
|
||||
// empty ds
|
||||
if (len == 0) {
|
||||
return out;
|
||||
}
|
||||
// define type
|
||||
auto strType = ds.getStrType();
|
||||
H5::CompType mapType(sizeof(char *) * 2);
|
||||
mapType.insertMember("key", 0, strType);
|
||||
mapType.insertMember("value", sizeof(char *), strType);
|
||||
struct KeyValue {
|
||||
const char *key;
|
||||
const char *value;
|
||||
};
|
||||
// read
|
||||
std::vector<KeyValue> kv_vector(len);
|
||||
ds.read(kv_vector.data(), mapType);
|
||||
for (const auto &kv : kv_vector) {
|
||||
out[kv.key] = kv.value;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sls::test::master_file
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,145 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
|
||||
#include "Readers.h"
|
||||
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
namespace sls::test::master_file {
|
||||
using ns = std::chrono::nanoseconds;
|
||||
|
||||
/* --scalar reads-- */
|
||||
template <> struct Reader<JsonContext, int> {
|
||||
static int read(const JsonContext &ctx, const std::string &name,
|
||||
AccessType access) {
|
||||
return ctx.doc[name.c_str()].GetInt();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<JsonContext, uint32_t> {
|
||||
static uint32_t read(const JsonContext &ctx, const std::string &name,
|
||||
AccessType access) {
|
||||
return ctx.doc[name.c_str()].GetUint();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<JsonContext, uint64_t> {
|
||||
static uint64_t read(const JsonContext &ctx, const std::string &name,
|
||||
AccessType access) {
|
||||
return ctx.doc[name.c_str()].GetUint64();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<JsonContext, double> {
|
||||
static double read(const JsonContext &ctx, const std::string &name,
|
||||
AccessType access) {
|
||||
return ctx.doc[name.c_str()].GetDouble();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<JsonContext, std::string> {
|
||||
static std::string read(const JsonContext &ctx, const std::string &name,
|
||||
AccessType access) {
|
||||
return ctx.doc[name.c_str()].GetString();
|
||||
}
|
||||
};
|
||||
|
||||
/** complex types */
|
||||
template <> struct Reader<JsonContext, defs::xy> {
|
||||
static defs::xy read(const JsonContext &ctx, const std::string &name,
|
||||
AccessType access) {
|
||||
defs::xy out{};
|
||||
out.x = ctx.doc[name.c_str()]["x"].GetInt();
|
||||
out.y = ctx.doc[name.c_str()]["y"].GetInt();
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<JsonContext, std::vector<defs::ROI>> {
|
||||
static std::vector<defs::ROI>
|
||||
read(const JsonContext &ctx, const std::string &name, AccessType access) {
|
||||
std::vector<defs::ROI> out{};
|
||||
for (const auto &item : ctx.doc[name.c_str()].GetArray()) {
|
||||
defs::ROI r{};
|
||||
r.xmin = item["xmin"].GetInt();
|
||||
r.xmax = item["xmax"].GetInt();
|
||||
r.ymin = item["ymin"].GetInt();
|
||||
r.ymax = item["ymax"].GetInt();
|
||||
out.push_back(r);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<JsonContext, defs::scanParameters> {
|
||||
static defs::scanParameters
|
||||
read(const JsonContext &ctx, const std::string &name, AccessType access) {
|
||||
defs::scanParameters out{};
|
||||
const auto &s = ctx.doc[name.c_str()].GetObject();
|
||||
out.enable = s["enable"].GetInt();
|
||||
out.dacInd = static_cast<defs::dacIndex>(s["dacInd"].GetInt());
|
||||
out.startOffset = s["start offset"].GetInt();
|
||||
out.stopOffset = s["stop offset"].GetInt();
|
||||
out.stepSize = s["step size"].GetInt();
|
||||
out.dacSettleTime_ns = s["dac settle time ns"].GetInt64();
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
/** arrays/vectors/maps */
|
||||
template <> struct Reader<JsonContext, std::array<int, 3UL>> {
|
||||
static std::array<int, 3UL>
|
||||
read(const JsonContext &ctx, const std::string &name, AccessType access) {
|
||||
const auto &arr = ctx.doc[name.c_str()].GetArray();
|
||||
check_size(arr.Size(), 3, name, "JSON");
|
||||
|
||||
std::array<int, 3UL> out{};
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
out[i] = arr[i].GetInt();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<JsonContext, std::array<ns, 3UL>> {
|
||||
static std::array<ns, 3UL>
|
||||
read(const JsonContext &ctx, const std::string &name, AccessType access) {
|
||||
const auto &arr = ctx.doc[name.c_str()].GetArray();
|
||||
check_size(arr.Size(), 3, name, "JSON");
|
||||
|
||||
std::array<ns, 3UL> out{};
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
std::string sval = arr[i].GetString();
|
||||
out[i] = StringTo<ns>(sval);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<JsonContext, std::vector<int64_t>> {
|
||||
static std::vector<int64_t>
|
||||
read(const JsonContext &ctx, const std::string &name, AccessType access) {
|
||||
std::vector<int64_t> out{};
|
||||
for (const auto &item : ctx.doc[name.c_str()].GetArray()) {
|
||||
out.push_back(item.GetInt64());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Reader<JsonContext, std::map<std::string, std::string>> {
|
||||
static std::map<std::string, std::string>
|
||||
read(const JsonContext &ctx, const std::string &name, AccessType access) {
|
||||
std::map<std::string, std::string> out{};
|
||||
for (const auto &m : ctx.doc[name.c_str()].GetObject()) {
|
||||
out[m.name.GetString()] = m.value.GetString();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sls::test::master_file
|
||||
Reference in New Issue
Block a user