854 lines
30 KiB
C++
854 lines
30 KiB
C++
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include <thread>
|
|
|
|
#include "JFJochStateMachine.h"
|
|
#include "../preview/JFJochTIFF.h"
|
|
#include "pistache/net.h"
|
|
|
|
JFJochStateMachine::JFJochStateMachine(JFJochServices &in_services, Logger &in_logger)
|
|
: logger(in_logger),
|
|
services(in_services),
|
|
pixel_mask(experiment),
|
|
current_detector_setup(0),
|
|
data_processing_settings(DiffractionExperiment::DefaultDataProcessingSettings()),
|
|
pixel_mask_statistics({0, 0, 0}) {
|
|
SupressTIFFErrors();
|
|
}
|
|
|
|
bool JFJochStateMachine::ImportPedestalG0(const JFJochReceiverOutput &receiver_output) {
|
|
if (receiver_output.pedestal_result.empty())
|
|
return false;
|
|
|
|
if (receiver_output.pedestal_result.size() != experiment.GetModulesNum() * experiment.GetStorageCellNumber())
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mismatch in pedestal output");
|
|
|
|
size_t gain_level = experiment.IsFixedGainG1() ? 1 : 0;
|
|
|
|
for (int s = 0; s < experiment.GetStorageCellNumber(); s++) {
|
|
for (int module = 0; module < experiment.GetModulesNum(); module++)
|
|
calibration->Pedestal(module, gain_level, s)
|
|
= receiver_output.pedestal_result[module + s * experiment.GetModulesNum()];
|
|
}
|
|
SetCalibrationStatistics(calibration->GetModuleStatistics());
|
|
return true;
|
|
}
|
|
|
|
bool JFJochStateMachine::ImportPedestalG1G2(const JFJochReceiverOutput &receiver_output, size_t gain_level,
|
|
size_t storage_cell) {
|
|
if (receiver_output.pedestal_result.empty())
|
|
return false;
|
|
|
|
if (receiver_output.pedestal_result.size() != experiment.GetModulesNum())
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mismatch in pedestal output");
|
|
|
|
for (int i = 0; i < receiver_output.pedestal_result.size(); i++)
|
|
calibration->Pedestal(i, gain_level, storage_cell) = receiver_output.pedestal_result[i];
|
|
SetCalibrationStatistics(calibration->GetModuleStatistics());
|
|
return true;
|
|
}
|
|
|
|
void JFJochStateMachine::TakePedestalInternalAll(std::unique_lock<std::mutex> &ul) {
|
|
if (experiment.GetDetectorSetup().GetDetectorType() == DetectorType::EIGER) {
|
|
try {
|
|
logger.Info("EIGER configuration");
|
|
services.ConfigureDetector(experiment);
|
|
logger.Info(" ... done ");
|
|
SetState(JFJochState::Idle,
|
|
"EIGER detector configured",
|
|
BrokerStatus::MessageSeverity::Success);
|
|
return;
|
|
} catch (const std::exception &e) {
|
|
logger.Error("EIGER configuration error {}", e.what());
|
|
SetState(JFJochState::Error, e.what(), BrokerStatus::MessageSeverity::Error);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
calibration = std::make_unique<JFCalibration>(experiment);
|
|
|
|
if (!gain_calibration.empty()) {
|
|
if (gain_calibration.size() != experiment.GetModulesNum())
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mismatch in gain files number");
|
|
for (int i = 0; i < gain_calibration.size(); i++)
|
|
calibration->GainCalibration(i) = gain_calibration[i];
|
|
}
|
|
|
|
cancel_sequence = false;
|
|
|
|
logger.Info("Pedestal sequence started");
|
|
|
|
try {
|
|
TakePedestalInternalG0(ul);
|
|
if (!experiment.IsFixedGainG1()) {
|
|
for (int i = 0; i < experiment.GetStorageCellNumber(); i++) {
|
|
TakePedestalInternalG1(ul, i);
|
|
TakePedestalInternalG2(ul, i);
|
|
}
|
|
}
|
|
SetState(JFJochState::Idle,
|
|
"Pedestal sequence done",
|
|
BrokerStatus::MessageSeverity::Success);
|
|
services.ConfigureDetector(experiment);
|
|
pixel_mask.LoadDetectorBadPixelMask(experiment, calibration.get());
|
|
UpdatePixelMaskStatistics(pixel_mask.GetStatistics());
|
|
} catch (const std::exception &e) {
|
|
logger.Error("Pedestal sequence error {}", e.what());
|
|
SetState(JFJochState::Error, e.what(), BrokerStatus::MessageSeverity::Error);
|
|
throw;
|
|
}
|
|
logger.Info("Pedestal sequence done");
|
|
}
|
|
|
|
|
|
void JFJochStateMachine::TakePedestalInternalG0(std::unique_lock<std::mutex> &ul) {
|
|
DiffractionExperiment local_experiment(experiment);
|
|
std::string message;
|
|
if (local_experiment.IsFixedGainG1()) {
|
|
local_experiment.Mode(DetectorMode::PedestalG1);
|
|
message = "Pedestal G1";
|
|
} else {
|
|
local_experiment.Mode(DetectorMode::PedestalG0);
|
|
message = "Pedestal G0";
|
|
}
|
|
|
|
if (local_experiment.GetStorageCellNumber() == 1)
|
|
local_experiment.StorageCellStart(15);
|
|
else
|
|
local_experiment.StorageCellStart(0);
|
|
|
|
if (cancel_sequence) {
|
|
SetState(JFJochState::Inactive,
|
|
"Pedestal sequence cancelled",
|
|
BrokerStatus::MessageSeverity::Warning);
|
|
return;
|
|
}
|
|
|
|
if (local_experiment.GetPedestalG0Frames() == 0)
|
|
return;
|
|
|
|
SetState(JFJochState::Pedestal, message, BrokerStatus::MessageSeverity::Info);
|
|
services.ConfigureDetector(local_experiment);
|
|
services.Start(local_experiment, pixel_mask, *calibration);
|
|
|
|
services.Trigger();
|
|
|
|
ul.unlock();
|
|
// Allow to cancel/abort during the pedestal data collection
|
|
// Must ensure that while state is Pedestal, nothing can take lock for longer time, to avoid deadlock
|
|
auto pedestal_output = services.Stop();
|
|
ul.lock();
|
|
|
|
if (ImportPedestalG0(pedestal_output.receiver_output))
|
|
SetState(JFJochState::Idle);
|
|
else
|
|
SetState(JFJochState::Error,
|
|
"Pedestal not collected properly",
|
|
BrokerStatus::MessageSeverity::Error);
|
|
}
|
|
|
|
void JFJochStateMachine::TakePedestalInternalG1(std::unique_lock<std::mutex> &ul, int32_t storage_cell) {
|
|
DiffractionExperiment local_experiment(experiment);
|
|
local_experiment.Mode(DetectorMode::PedestalG1);
|
|
|
|
if (local_experiment.GetStorageCellNumber() == 2)
|
|
local_experiment.StorageCellStart((storage_cell + 15) % 16); // one previous
|
|
else
|
|
local_experiment.StorageCellStart(15);
|
|
|
|
|
|
if (cancel_sequence) {
|
|
SetState(JFJochState::Inactive,
|
|
"Pedestal sequence cancelled",
|
|
BrokerStatus::MessageSeverity::Warning);
|
|
return;
|
|
}
|
|
|
|
if (local_experiment.GetPedestalG1Frames() == 0)
|
|
return;
|
|
|
|
|
|
SetState(JFJochState::Pedestal,
|
|
"Pedestal G1 SC" + std::to_string(storage_cell),
|
|
BrokerStatus::MessageSeverity::Info);
|
|
services.ConfigureDetector(local_experiment);
|
|
services.Start(local_experiment, pixel_mask, *calibration);
|
|
|
|
services.Trigger();
|
|
|
|
ul.unlock();
|
|
// Allow to cancel/abort during the pedestal data collection
|
|
// Must ensure that while state is Pedestal, nothing can take lock for longer time, to avoid deadlock
|
|
auto pedestal_output = services.Stop();
|
|
ul.lock();
|
|
|
|
if (!ImportPedestalG1G2(pedestal_output.receiver_output, 1, storage_cell))
|
|
SetState(JFJochState::Error,
|
|
"Pedestal not collected properly",
|
|
BrokerStatus::MessageSeverity::Error);
|
|
}
|
|
|
|
void JFJochStateMachine::TakePedestalInternalG2(std::unique_lock<std::mutex> &ul, int32_t storage_cell) {
|
|
DiffractionExperiment local_experiment(experiment);
|
|
local_experiment.Mode(DetectorMode::PedestalG2);
|
|
|
|
if (local_experiment.GetStorageCellNumber() == 2)
|
|
local_experiment.StorageCellStart((storage_cell + 15) % 16); // one previous
|
|
else
|
|
local_experiment.StorageCellStart(15);
|
|
|
|
if (cancel_sequence) {
|
|
SetState(JFJochState::Inactive,
|
|
"Pedestal sequence cancelled",
|
|
BrokerStatus::MessageSeverity::Warning);
|
|
return;
|
|
}
|
|
|
|
if (local_experiment.GetPedestalG2Frames() == 0)
|
|
return;
|
|
|
|
|
|
SetState(JFJochState::Pedestal,
|
|
"Pedestal G2 SC" + std::to_string(storage_cell),
|
|
BrokerStatus::MessageSeverity::Info);
|
|
services.ConfigureDetector(local_experiment);
|
|
services.Start(local_experiment, pixel_mask, *calibration);
|
|
|
|
services.Trigger();
|
|
|
|
ul.unlock();
|
|
// Allow to cancel/abort during the pedestal data collection
|
|
// Must ensure that while state is Pedestal, nothing can take lock for longer time, to avoid deadlock
|
|
auto pedestal_output = services.Stop();
|
|
ul.lock();
|
|
|
|
if (!ImportPedestalG1G2(pedestal_output.receiver_output, 2, storage_cell))
|
|
SetState(JFJochState::Error,
|
|
"Pedestal not collected properly",
|
|
BrokerStatus::MessageSeverity::Error);
|
|
}
|
|
|
|
void JFJochStateMachine::Initialize() {
|
|
std::unique_lock ul(m);
|
|
|
|
if (IsRunning())
|
|
throw WrongDAQStateException("Cannot initialize during measurement");
|
|
|
|
if (detector_setup.empty())
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Detector information not provided");
|
|
|
|
ResetError(); // Clear error, we don't care what was it
|
|
|
|
logger.Info("Initialize");
|
|
|
|
SetState(JFJochState::Busy, "Configuring detector", BrokerStatus::MessageSeverity::Info);
|
|
|
|
measurement = std::async(std::launch::async, &JFJochStateMachine::InitializeThread, this, std::move(ul));
|
|
}
|
|
|
|
void JFJochStateMachine::Pedestal() {
|
|
std::unique_lock ul(m);
|
|
|
|
if (state != JFJochState::Idle)
|
|
throw WrongDAQStateException("Must be idle to take pedestal");
|
|
|
|
measurement = std::async(std::launch::async, &JFJochStateMachine::PedestalThread, this, std::move(ul));
|
|
}
|
|
|
|
|
|
void JFJochStateMachine::PedestalThread(std::unique_lock<std::mutex> ul) {
|
|
TakePedestalInternalAll(ul);
|
|
}
|
|
|
|
void JFJochStateMachine::InitializeThread(std::unique_lock<std::mutex> ul) {
|
|
try {
|
|
services.On(experiment);
|
|
} catch (const std::exception &e) {
|
|
SetState(JFJochState::Error, e.what(), BrokerStatus::MessageSeverity::Error);
|
|
throw;
|
|
}
|
|
TakePedestalInternalAll(ul);
|
|
}
|
|
|
|
void JFJochStateMachine::Trigger() {
|
|
std::unique_lock ul(m);
|
|
if (state == JFJochState::Measuring)
|
|
services.Trigger();
|
|
}
|
|
|
|
void JFJochStateMachine::Start(const DatasetSettings &settings) {
|
|
std::unique_lock ul(m);
|
|
|
|
if (state != JFJochState::Idle)
|
|
throw WrongDAQStateException("Must be idle to start measurement");
|
|
|
|
if (measurement.valid())
|
|
measurement.get(); // In case measurement was running - clear thread
|
|
|
|
experiment.ImportDatasetSettings(settings);
|
|
|
|
cancel_sequence = false;
|
|
if (experiment.GetStorageCellNumber() == 1)
|
|
experiment.StorageCellStart(15);
|
|
else
|
|
experiment.StorageCellStart(0);
|
|
|
|
experiment.IncrementRunNumber();
|
|
|
|
try {
|
|
SetState(JFJochState::Busy, "Preparing measurement", BrokerStatus::MessageSeverity::Info);
|
|
services.SetSpotFindingSettings(GetSpotFindingSettings());
|
|
services.Start(experiment, pixel_mask, *calibration);
|
|
|
|
SetState(JFJochState::Measuring, "Measuring ...", BrokerStatus::MessageSeverity::Info);
|
|
measurement = std::async(std::launch::async, &JFJochStateMachine::MeasurementThread, this);
|
|
} catch (const std::exception &e) {
|
|
SetState(JFJochState::Error, e.what(), BrokerStatus::MessageSeverity::Error);
|
|
services.Cancel();
|
|
throw;
|
|
}
|
|
}
|
|
|
|
void JFJochStateMachine::UpdatePixelMaskStatistics(const PixelMaskStatistics &input) {
|
|
std::unique_lock ul(pixel_mask_statistics_mutex);
|
|
pixel_mask_statistics = input;
|
|
}
|
|
|
|
PixelMaskStatistics JFJochStateMachine::GetPixelMaskStatistics() const {
|
|
std::unique_lock ul(pixel_mask_statistics_mutex);
|
|
return pixel_mask_statistics;
|
|
}
|
|
|
|
void JFJochStateMachine::MeasurementThread() {
|
|
try {
|
|
auto tmp_output = services.Stop(); {
|
|
std::unique_lock ul(m);
|
|
|
|
if (tmp_output.receiver_output.writer_queue_full_warning)
|
|
SetState(JFJochState::Idle,
|
|
"Stream receiver (writer or downstream analysis) cannot cope with data; reduce frame rate",
|
|
BrokerStatus::MessageSeverity::Warning);
|
|
else if (tmp_output.receiver_output.status.cancelled)
|
|
SetState(JFJochState::Idle,
|
|
"Data collection cancelled",
|
|
BrokerStatus::MessageSeverity::Info);
|
|
else if (tmp_output.receiver_output.efficiency != 1.0)
|
|
SetState(JFJochState::Idle,
|
|
"Missing packets in data collection; reduce frame rate",
|
|
BrokerStatus::MessageSeverity::Error);
|
|
else
|
|
SetState(JFJochState::Idle,
|
|
"Data collection without problems",
|
|
BrokerStatus::MessageSeverity::Success);
|
|
}
|
|
} catch (const std::exception &e) {
|
|
std::unique_lock ul(m);
|
|
SetState(JFJochState::Error, e.what(), BrokerStatus::MessageSeverity::Error);
|
|
}
|
|
c.notify_all();
|
|
}
|
|
|
|
void JFJochStateMachine::Cancel() {
|
|
// This is inconsistency in naming - need to solve later
|
|
std::unique_lock ul(m);
|
|
if ((state == JFJochState::Pedestal) || (state == JFJochState::Measuring)) {
|
|
services.Cancel();
|
|
cancel_sequence = true;
|
|
}
|
|
}
|
|
|
|
void JFJochStateMachine::DebugOnly_SetState(JFJochState in_state,
|
|
const std::optional<std::string> &message,
|
|
BrokerStatus::MessageSeverity message_severity) {
|
|
std::unique_lock ul(m);
|
|
SetState(in_state, message, message_severity);
|
|
}
|
|
|
|
void JFJochStateMachine::Deactivate() {
|
|
std::unique_lock ul(m);
|
|
try {
|
|
if (measurement.valid())
|
|
measurement.get();
|
|
services.Off();
|
|
SetState(JFJochState::Inactive,
|
|
"Detector safe to turn off",
|
|
BrokerStatus::MessageSeverity::Info);
|
|
} catch (const std::exception &e) {
|
|
SetState(JFJochState::Error,
|
|
e.what(),
|
|
BrokerStatus::MessageSeverity::Error);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
JFJochStateMachine::~JFJochStateMachine() {
|
|
ResetError();
|
|
}
|
|
|
|
std::optional<MeasurementStatistics> JFJochStateMachine::GetMeasurementStatistics() const {
|
|
MeasurementStatistics tmp{};
|
|
|
|
tmp.file_prefix = experiment.GetFilePrefix();
|
|
tmp.run_number = experiment.GetRunNumber();
|
|
tmp.experiment_group = experiment.GetExperimentGroup();
|
|
|
|
tmp.detector_width = experiment.GetXPixelsNum();
|
|
tmp.detector_height = experiment.GetYPixelsNum();
|
|
tmp.detector_pixel_depth = experiment.GetByteDepthImage();
|
|
tmp.images_expected = experiment.GetImageNum();
|
|
tmp.unit_cell = experiment.GetUnitCellString();
|
|
|
|
auto rcv_status = services.GetReceiverStatus();
|
|
if (rcv_status) {
|
|
tmp.compression_ratio = rcv_status->compressed_ratio;
|
|
tmp.images_collected = rcv_status->images_collected;
|
|
tmp.images_sent = rcv_status->images_sent;
|
|
tmp.images_skipped = rcv_status->images_skipped;
|
|
tmp.cancelled = rcv_status->cancelled;
|
|
tmp.max_image_number_sent = rcv_status->max_image_number_sent;
|
|
tmp.max_receive_delay = rcv_status->max_receive_delay;
|
|
tmp.indexing_rate = rcv_status->indexing_rate;
|
|
tmp.bkg_estimate = rcv_status->bkg_estimate;
|
|
tmp.collection_efficiency = rcv_status->efficiency;
|
|
tmp.error_pixels = rcv_status->error_pixels;
|
|
tmp.saturated_pixels = rcv_status->saturated_pixels;
|
|
tmp.roi_beam_sum = rcv_status->roi_beam_sum;
|
|
tmp.roi_beam_npixel = rcv_status->roi_beam_npixel;
|
|
}
|
|
return tmp;
|
|
}
|
|
|
|
std::vector<JFCalibrationModuleStatistics> JFJochStateMachine::GetCalibrationStatistics() const {
|
|
std::unique_lock ul(calibration_statistics_mutex);
|
|
return calibration_statistics;
|
|
}
|
|
|
|
void JFJochStateMachine::SetCalibrationStatistics(const std::vector<JFCalibrationModuleStatistics> &input) {
|
|
std::unique_lock ul(calibration_statistics_mutex);
|
|
calibration_statistics = input;
|
|
}
|
|
|
|
DetectorSettings JFJochStateMachine::GetDetectorSettings() const {
|
|
std::unique_lock ul(experiment_detector_settings_mutex);
|
|
return experiment.GetDetectorSettings();
|
|
}
|
|
|
|
void JFJochStateMachine::ImportDetectorSettings(const DetectorSettings &input) {
|
|
std::unique_lock ul(experiment_detector_settings_mutex);
|
|
experiment.ImportDetectorSettings(input);
|
|
}
|
|
|
|
void JFJochStateMachine::LoadDetectorSettings(const DetectorSettings &settings) {
|
|
std::unique_lock ul(m);
|
|
switch (state) {
|
|
case JFJochState::Inactive:
|
|
case JFJochState::Error:
|
|
ImportDetectorSettings(settings);
|
|
break;
|
|
case JFJochState::Idle:
|
|
SetState(JFJochState::Busy, "Loading settings", BrokerStatus::MessageSeverity::Info);
|
|
ImportDetectorSettings(settings);
|
|
measurement = std::async(std::launch::async, &JFJochStateMachine::PedestalThread, this, std::move(ul));
|
|
break;
|
|
case JFJochState::Measuring:
|
|
case JFJochState::Busy:
|
|
case JFJochState::Pedestal:
|
|
throw WrongDAQStateException("Cannot change detector settings during data collection");
|
|
}
|
|
}
|
|
|
|
DiffractionExperiment &JFJochStateMachine::NotThreadSafe_Experiment() {
|
|
return experiment;
|
|
}
|
|
|
|
BrokerStatus JFJochStateMachine::GetStatus() const {
|
|
std::unique_lock ul(broker_status_mutex);
|
|
BrokerStatus ret = broker_status;
|
|
ret.progress = services.GetReceiverProgress();
|
|
return ret;
|
|
}
|
|
|
|
void JFJochStateMachine::SetState(JFJochState curr_state,
|
|
const std::optional<std::string> &message,
|
|
BrokerStatus::MessageSeverity message_severity) {
|
|
std::unique_lock ul(broker_status_mutex);
|
|
state = curr_state;
|
|
broker_status = BrokerStatus{
|
|
.state = curr_state,
|
|
.message = message,
|
|
.message_severity = message_severity
|
|
};
|
|
}
|
|
|
|
MultiLinePlot JFJochStateMachine::GetPlots(const PlotRequest &request) const {
|
|
return services.GetPlots(request);
|
|
}
|
|
|
|
void JFJochStateMachine::SetSpotFindingSettings(const SpotFindingSettings &settings) {
|
|
std::unique_lock ul(data_processing_settings_mutex);
|
|
DiffractionExperiment::CheckDataProcessingSettings(settings);
|
|
data_processing_settings = settings;
|
|
services.SetSpotFindingSettings(settings);
|
|
}
|
|
|
|
SpotFindingSettings JFJochStateMachine::GetSpotFindingSettings() const {
|
|
std::unique_lock ul(data_processing_settings_mutex);
|
|
return data_processing_settings;
|
|
}
|
|
|
|
void JFJochStateMachine::AddDetectorSetup(const DetectorSetup &setup) {
|
|
// Not thread safe, only during setup
|
|
|
|
if (detector_setup.empty()) {
|
|
experiment.Detector(setup);
|
|
UpdateROIDefinition();
|
|
gain_calibration = setup.GetGainCalibration();
|
|
current_detector_setup = 0;
|
|
pixel_mask = PixelMask(experiment);
|
|
}
|
|
detector_setup.emplace_back(setup);
|
|
}
|
|
|
|
DetectorList JFJochStateMachine::GetDetectorsList() const {
|
|
DetectorList ret;
|
|
|
|
for (const auto &i: detector_setup) {
|
|
DetectorListElement tmp;
|
|
tmp.description = i.GetDescription();
|
|
tmp.nmodules = i.GetModulesNum();
|
|
tmp.width = i.GetGeometry().GetWidth();
|
|
tmp.height = i.GetGeometry().GetHeight();
|
|
tmp.serial_number = i.GetSerialNumber();
|
|
tmp.base_ipv4_addr = i.GetBaseIPv4Addr();
|
|
tmp.udp_interface_count = i.GetUDPInterfaceCount();
|
|
tmp.min_frame_time = i.GetMinFrameTime();
|
|
tmp.min_count_time = i.GetMinCountTime();
|
|
tmp.readout_time = i.GetReadOutTime();
|
|
ret.detector.emplace_back(std::move(tmp));
|
|
}
|
|
{
|
|
std::unique_lock ul(current_detector_setup_mutex);
|
|
ret.current_id = current_detector_setup;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
std::optional<DetectorStatus> JFJochStateMachine::GetDetectorStatus() const {
|
|
return services.GetDetectorStatus();
|
|
}
|
|
|
|
void JFJochStateMachine::SelectDetector(int64_t id) {
|
|
std::unique_lock ul(m);
|
|
|
|
if ((id < 0) || (id >= detector_setup.size()))
|
|
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Detector doesn't exist");
|
|
|
|
if (IsRunning())
|
|
throw WrongDAQStateException("Cannot change detector during data collection");
|
|
|
|
try {
|
|
experiment.Detector(detector_setup[id]);
|
|
UpdateROIDefinition();
|
|
gain_calibration = detector_setup[id].GetGainCalibration();
|
|
pixel_mask = PixelMask(experiment);
|
|
SetState(JFJochState::Inactive, detector_setup[id].GetDescription() + " selected; please initialize");
|
|
{
|
|
std::unique_lock ul(current_detector_setup_mutex);
|
|
current_detector_setup = id;
|
|
}
|
|
} catch (const JFJochException &e) {
|
|
logger.ErrorException(e);
|
|
SetState(JFJochState::Error, e.what(), BrokerStatus::MessageSeverity::Error);
|
|
throw; // re-throw the exception, so it is populated to caller
|
|
}
|
|
}
|
|
|
|
void JFJochStateMachine::SetRadialIntegrationSettings(const AzimuthalIntegrationSettings &settings) {
|
|
std::unique_lock ul(m);
|
|
|
|
if (IsRunning())
|
|
throw WrongDAQStateException("Cannot change radial integration settings during data collection");
|
|
{
|
|
std::unique_lock ul(experiment_azimuthal_integration_settings_mutex);
|
|
experiment.ImportAzimuthalIntegrationSettings(settings);
|
|
}
|
|
}
|
|
|
|
AzimuthalIntegrationSettings JFJochStateMachine::GetRadialIntegrationSettings() const {
|
|
std::unique_lock ul(experiment_azimuthal_integration_settings_mutex);
|
|
return experiment.GetAzimuthalIntegrationSettings();
|
|
}
|
|
|
|
bool JFJochStateMachine::IsRunning() const {
|
|
switch (state) {
|
|
case JFJochState::Inactive:
|
|
case JFJochState::Error:
|
|
case JFJochState::Idle:
|
|
return false;
|
|
case JFJochState::Measuring:
|
|
case JFJochState::Busy:
|
|
case JFJochState::Pedestal:
|
|
return true;
|
|
default:
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "State unknown");
|
|
}
|
|
}
|
|
|
|
BrokerStatus JFJochStateMachine::WaitTillMeasurementDone() {
|
|
std::unique_lock ul(m);
|
|
|
|
c.wait(ul, [&] { return !IsRunning(); });
|
|
|
|
return GetStatus();
|
|
}
|
|
|
|
BrokerStatus JFJochStateMachine::WaitTillMeasurementDone(std::chrono::milliseconds timeout) {
|
|
std::unique_lock ul(m);
|
|
|
|
c.wait_for(ul, timeout, [&] { return !IsRunning(); });
|
|
|
|
return GetStatus();
|
|
}
|
|
|
|
void JFJochStateMachine::ResetError() noexcept {
|
|
try {
|
|
if (measurement.valid())
|
|
measurement.get();
|
|
} catch (...) {
|
|
}
|
|
}
|
|
|
|
std::string JFJochStateMachine::GetPreviewJPEG(const PreviewJPEGSettings &settings) const {
|
|
return services.GetPreviewJPEG(settings);
|
|
}
|
|
|
|
std::string JFJochStateMachine::GetPreviewTIFF(bool calibration) const {
|
|
return services.GetPreviewTIFF(calibration);
|
|
}
|
|
|
|
std::string JFJochStateMachine::GetPedestalTIFF(size_t gain_level, size_t sc) const {
|
|
std::unique_lock ul(m);
|
|
|
|
if (state != JFJochState::Idle)
|
|
throw WrongDAQStateException("Pedestal can be only retrieved in Idle state");
|
|
|
|
if ((experiment.GetDetectorSetup().GetDetectorType() == DetectorType::JUNGFRAU) && calibration) {
|
|
auto tmp = calibration->GetPedestal(gain_level, sc);
|
|
return WriteTIFFToString(tmp.data(), RAW_MODULE_COLS, RAW_MODULE_LINES * experiment.GetModulesNum(),
|
|
sizeof(uint16_t), false);
|
|
} else
|
|
return {};
|
|
}
|
|
|
|
void JFJochStateMachine::LoadInternalGeneratorImage(const void *data, size_t size, uint64_t image_number) {
|
|
std::unique_lock ul(m);
|
|
|
|
if (state != JFJochState::Idle)
|
|
throw WrongDAQStateException("Can change internal generator image only when detector in Idle state");
|
|
|
|
if ((size != experiment.GetPixelsNum() * sizeof(uint16_t))
|
|
&& (size != experiment.GetModulesNum() * RAW_MODULE_SIZE * sizeof(uint16_t)))
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
|
"Image size doesn't match current detector");
|
|
|
|
if (image_number >= experiment.GetInternalPacketGeneratorImages())
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
|
"Image for internal generator out of bounds");
|
|
|
|
std::vector<uint16_t> image(size / sizeof(uint16_t));
|
|
memcpy(image.data(), data, size);
|
|
|
|
services.LoadInternalGeneratorImage(experiment, image, image_number);
|
|
}
|
|
|
|
void JFJochStateMachine::LoadInternalGeneratorImageTIFF(const std::string &s, uint64_t image_number) {
|
|
std::unique_lock ul(m);
|
|
|
|
if (state != JFJochState::Idle)
|
|
throw WrongDAQStateException("Can change internal generator image only when detector in Idle state");
|
|
|
|
uint32_t cols, lines;
|
|
auto v = ReadTIFFFromString16(s, cols, lines);
|
|
if (((cols == experiment.GetXPixelsNum()) && (lines == experiment.GetYPixelsNum()))
|
|
|| ((cols == RAW_MODULE_SIZE) && (lines == RAW_MODULE_LINES * experiment.GetModulesNum())))
|
|
services.LoadInternalGeneratorImage(experiment, v, image_number);
|
|
else
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
|
"Image size doesn't match current detector");
|
|
}
|
|
|
|
void JFJochStateMachine::UpdateROIDefinition() {
|
|
std::unique_lock ul(roi_mutex);
|
|
roi = experiment.ROI().GetROIDefinition();
|
|
}
|
|
|
|
void JFJochStateMachine::SetROIDefinition(const ROIDefinition &input) {
|
|
std::unique_lock ul(m);
|
|
|
|
if (IsRunning())
|
|
throw WrongDAQStateException("ROI can be modified only when detector is not running");
|
|
|
|
experiment.ROI().SetROI(input);
|
|
UpdateROIDefinition();
|
|
}
|
|
|
|
ROIDefinition JFJochStateMachine::GetROIDefintion() const {
|
|
std::unique_lock ul(roi_mutex);
|
|
return roi;
|
|
}
|
|
|
|
std::vector<uint64_t> JFJochStateMachine::GetXFELPulseID() const {
|
|
std::vector<uint64_t> ret;
|
|
services.GetXFELPulseID(ret);
|
|
return ret;
|
|
}
|
|
|
|
std::vector<uint64_t> JFJochStateMachine::GetXFELEventCode() const {
|
|
std::vector<uint64_t> ret;
|
|
services.GetXFELEventCode(ret);
|
|
return ret;
|
|
}
|
|
|
|
std::string JFJochStateMachine::GetFullPixelMaskTIFF() const {
|
|
std::unique_lock ul(m);
|
|
std::vector v = pixel_mask.GetMask(experiment);
|
|
return WriteTIFFToString(v.data(), experiment.GetXPixelsNum(), experiment.GetYPixelsNum(),
|
|
sizeof(uint32_t), false);
|
|
}
|
|
|
|
std::string JFJochStateMachine::GetUserPixelMaskTIFF() const {
|
|
std::unique_lock ul(m);
|
|
std::vector v = pixel_mask.GetUserMask(experiment);
|
|
return WriteTIFFToString(v.data(), experiment.GetXPixelsNum(), experiment.GetYPixelsNum(),
|
|
sizeof(uint32_t), false);
|
|
}
|
|
|
|
std::vector<uint32_t> JFJochStateMachine::GetFullPixelMask() const {
|
|
std::unique_lock ul(m);
|
|
return pixel_mask.GetMask(experiment);
|
|
}
|
|
|
|
std::vector<uint32_t> JFJochStateMachine::GetUserPixelMask() const {
|
|
std::unique_lock ul(m);
|
|
return pixel_mask.GetUserMask(experiment);
|
|
}
|
|
|
|
void JFJochStateMachine::SetUserPixelMask(const std::vector<uint32_t> &v) {
|
|
std::unique_lock ul(m);
|
|
|
|
if (state != JFJochState::Idle)
|
|
throw WrongDAQStateException("User mask can be only modified in Idle state");
|
|
|
|
try {
|
|
pixel_mask.LoadUserMask(experiment, v);
|
|
UpdatePixelMaskStatistics(pixel_mask.GetStatistics());
|
|
} catch (const JFJochException &e) {
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
|
"Problem handling user mask " + std::string(e.what()));
|
|
}
|
|
}
|
|
|
|
InstrumentMetadata JFJochStateMachine::GetInstrumentMetadata() const {
|
|
std::unique_lock ul(m);
|
|
return experiment.GetInstrumentMetadata();
|
|
}
|
|
|
|
void JFJochStateMachine::LoadInstrumentMetadata(const InstrumentMetadata &settings) {
|
|
std::unique_lock ul(m);
|
|
|
|
if (IsRunning())
|
|
throw WrongDAQStateException("Cannot change instrument metadata during data collection");
|
|
|
|
experiment.ImportInstrumentMetadata(settings);
|
|
}
|
|
|
|
ImageFormatSettings JFJochStateMachine::GetImageFormatSettings() const {
|
|
std::unique_lock ul(m);
|
|
return experiment.GetImageFormatSettings();
|
|
}
|
|
|
|
void JFJochStateMachine::LoadImageFormatSettings(const ImageFormatSettings &settings) {
|
|
std::unique_lock ul(m);
|
|
|
|
if (IsRunning())
|
|
throw WrongDAQStateException("Cannot change image format settings during data collection");
|
|
|
|
experiment.ImportImageFormatSettings(settings);
|
|
pixel_mask.Update(settings);
|
|
UpdatePixelMaskStatistics(pixel_mask.GetStatistics());
|
|
}
|
|
|
|
void JFJochStateMachine::RawImageFormatSettings() {
|
|
std::unique_lock ul(m);
|
|
|
|
if (IsRunning())
|
|
throw WrongDAQStateException("Cannot change instrument metadata during data collection");
|
|
|
|
experiment.Raw();
|
|
}
|
|
|
|
void JFJochStateMachine::ConvImageFormatSettings() {
|
|
std::unique_lock ul(m);
|
|
|
|
if (IsRunning())
|
|
throw WrongDAQStateException("Cannot change instrument metadata during data collection");
|
|
|
|
experiment.Conversion();
|
|
}
|
|
|
|
std::vector<DeviceStatus> JFJochStateMachine::GetDeviceStatus() const {
|
|
return services.GetDeviceStatus();
|
|
}
|
|
|
|
void JFJochStateMachine::SetPreviewSocketSettings(const ZMQPreviewSettings &input) {
|
|
services.SetPreviewSocketSettings(input);
|
|
}
|
|
|
|
ZMQPreviewSettings JFJochStateMachine::GetPreviewSocketSettings() {
|
|
return services.GetPreviewSocketSettings();
|
|
}
|
|
|
|
void JFJochStateMachine::SetMetadataSocketSettings(const ZMQMetadataSettings &input) {
|
|
services.SetMetadataSocketSettings(input);
|
|
}
|
|
|
|
ZMQMetadataSettings JFJochStateMachine::GetMetadataSocketSettings() {
|
|
return services.GetMetadataSocketSettings();
|
|
}
|
|
|
|
void JFJochStateMachine::GetStartMessageFromBuffer(std::vector<uint8_t> &v) {
|
|
return services.GetStartMessageFromBuffer(v);
|
|
}
|
|
|
|
void JFJochStateMachine::GetImageFromBuffer(std::vector<uint8_t> &v, int64_t image_number) {
|
|
return services.GetImageFromBuffer(v, image_number);
|
|
}
|
|
|
|
ImageBufferStatus JFJochStateMachine::GetImageBufferStatus() const {
|
|
return services.GetImageBufferStatus();
|
|
}
|
|
|
|
void JFJochStateMachine::ClearImageBuffer() const {
|
|
std::unique_lock ul(m);
|
|
|
|
if (IsRunning())
|
|
throw WrongDAQStateException("Cannot clear image buffer during data collection");
|
|
|
|
services.ClearImageBuffer();
|
|
}
|
|
|
|
FileWriterSettings JFJochStateMachine::GetFileWriterSettings() const {
|
|
std::unique_lock ul(m);
|
|
return experiment.GetFileWriterSettings();
|
|
}
|
|
|
|
void JFJochStateMachine::LoadFileWriterSettings(const FileWriterSettings &settings) {
|
|
std::unique_lock ul(m);
|
|
|
|
if (IsRunning())
|
|
throw WrongDAQStateException("Cannot change instrument metadata during data collection");
|
|
|
|
experiment.ImportFileWriterSettings(settings);
|
|
}
|