Files
Jungfraujoch/broker/JFJochStateMachine.cpp
2025-09-27 12:29:56 +02:00

985 lines
35 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"
#include "../common/CUDAWrapper.h"
JFJochStateMachine::JFJochStateMachine(const DiffractionExperiment& in_experiment,
JFJochServices &in_services,
Logger &in_logger)
: experiment(in_experiment),
logger(in_logger),
services(in_services),
pixel_mask(experiment),
current_detector_setup(0),
data_processing_settings(DiffractionExperiment::DefaultDataProcessingSettings()),
pixel_mask_statistics({0, 0, 0}),
gpu_count(get_gpu_count()) {
indexing_possible = (get_gpu_count() >= 0);
if (!indexing_possible)
data_processing_settings.indexing = false;
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::JUNGFRAU) {
try {
calibration.reset();
logger.Info("EIGER configuration");
services.ConfigureDetector(experiment);
logger.Info(" ... done ");
SetState(JFJochState::Idle,
"Detector configured",
BrokerStatus::MessageSeverity::Success);
return;
} catch (const std::exception &e) {
logger.Error("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);
}
}
services.ConfigureDetector(experiment);
pixel_mask.LoadDetectorBadPixelMask(experiment, calibration.get());
UpdatePixelMaskStatistics(pixel_mask.GetStatistics());
SetState(JFJochState::Idle, "Pedestal sequence done", BrokerStatus::MessageSeverity::Success);
} 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");
try {
services.SetupIndexing(experiment.GetIndexingSettings());
} catch (const JFJochException &e) {
SetState(JFJochState::Error,
e.what(),
BrokerStatus::MessageSeverity::Error);
throw;
}
SetState(JFJochState::Busy, "Configuring detector", BrokerStatus::MessageSeverity::Info);
scan_result = {}; // Clear scan result
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 can potentially take a lot of time, so better to unlock main mutex
// Since On might modify the experiment (reads DECTRIS configuration), one has to have a local copy for unlocked part
DiffractionExperiment local_experiment(experiment);
if (state != JFJochState::Busy)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"State must be busy for safe operation");
ul.unlock();
services.On(local_experiment);
ul.lock();
experiment = local_experiment;
detector_setup[current_detector_setup] = experiment.GetDetectorSetup();
pixel_mask = PixelMask(experiment);
services.LoadDetectorPixelMask(pixel_mask);
UpdatePixelMaskStatistics(pixel_mask.GetStatistics());
} catch (const std::exception &e) {
logger.Error("Initialize error {}", e.what());
SetState(JFJochState::Error, e.what(), BrokerStatus::MessageSeverity::Error);
throw;
}
TakePedestalInternalAll(ul);
}
void JFJochStateMachine::Trigger() {
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);
scan_result = tmp_output.receiver_output.scan_result;
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 if (!tmp_output.receiver_output.writer_err.empty())
SetState(JFJochState::Idle,
tmp_output.receiver_output.writer_err,
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();
}
bool JFJochStateMachine::ImportDetectorSettings(const DetectorSettings &input) {
std::unique_lock ul(experiment_detector_settings_mutex);
// For JUNGFRAU detector, if detector settings changes key parameters
// need to recalibrate the detector
bool recalib = input.NeedsJUNGFRAURecalibration(experiment.GetDetectorSettings())
&& experiment.GetDetectorType() == DetectorType::JUNGFRAU;
experiment.ImportDetectorSettings(input);
return recalib;
}
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:
if (ImportDetectorSettings(settings)) {
SetState(JFJochState::Busy, "Loading settings", BrokerStatus::MessageSeverity::Info);
measurement = std::async(std::launch::async, &JFJochStateMachine::PedestalThread, this, std::move(ul));
} else {
try {
SetState(JFJochState::Busy, "Configure detector", BrokerStatus::MessageSeverity::Info);
services.ConfigureDetector(experiment);
SetState(JFJochState::Idle, "Detector configured", BrokerStatus::MessageSeverity::Info);
} catch (const std::exception &e) {
logger.Error("Detector configuration error {}", e.what());
SetState(JFJochState::Error, e.what(), BrokerStatus::MessageSeverity::Error);
}
}
break;
case JFJochState::Measuring:
case JFJochState::Busy:
case JFJochState::Pedestal:
throw WrongDAQStateException("Cannot change detector settings during data collection");
}
}
DiffractionExperiment JFJochStateMachine::Experiment() {
return experiment;
}
BrokerStatus JFJochStateMachine::GetStatus() const {
std::unique_lock ul(broker_status_mutex);
BrokerStatus ret = broker_status;
ret.progress = services.GetReceiverProgress();
ret.gpu_count = gpu_count;
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;
// If there is no capability to use the features, make sure these are disabled
if (!indexing_possible)
data_processing_settings.indexing = false;
services.SetSpotFindingSettings(data_processing_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(true);
tmp.height = i.GetGeometry().GetHeight(true);
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();
tmp.detector_type = i.GetDetectorType();
tmp.pixel_size_mm = i.GetPixelSize_mm();
ret.detector.emplace_back(std::move(tmp));
}
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");
// Do nothing if this is the same detector as currently used
if (id == current_detector_setup)
return;
// Try to deactivate current detector (if actually running)
if (state != JFJochState::Inactive) {
try {
SetState(JFJochState::Busy, "Deactivating existing detector");
ul.unlock();
services.Off();
ul.lock();
} catch (const std::exception &e) {
logger.ErrorException(e);
logger.Warning("Cannot turn off existing detector - proceeding anyway");
}
}
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");
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 ul2(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 PreviewImageSettings &settings, int64_t image_number) const {
return services.GetPreviewJPEG(settings, image_number);
}
std::string JFJochStateMachine::GetPreviewTIFF(int64_t image_number) const {
return services.GetPreviewTIFF(image_number);
}
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);
CompressedImage image(tmp, RAW_MODULE_COLS, RAW_MODULE_LINES * experiment.GetModulesNum());
return WriteTIFFToString(image);
} 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);
if (state == JFJochState::Inactive)
return {};
std::vector v = pixel_mask.GetMask(experiment);
CompressedImage mask_image(v, experiment.GetXPixelsNum(), experiment.GetYPixelsNum());
return WriteTIFFToString(mask_image);
}
std::string JFJochStateMachine::GetUserPixelMaskTIFF() const {
std::unique_lock ul(m);
if (state == JFJochState::Inactive)
return {};
std::vector v = pixel_mask.GetUserMask(experiment);
CompressedImage mask_image(v, experiment.GetXPixelsNum(), experiment.GetYPixelsNum());
return WriteTIFFToString(mask_image);
}
std::vector<uint32_t> JFJochStateMachine::GetFullPixelMask() const {
std::unique_lock ul(m);
if (state == JFJochState::Inactive)
return {};
return pixel_mask.GetMask(experiment);
}
std::vector<uint32_t> JFJochStateMachine::GetUserPixelMask() const {
std::unique_lock ul(m);
if (state == JFJochState::Inactive)
return {};
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(experiment_instrument_metadata_mutex);
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");
{
std::unique_lock ul2(experiment_instrument_metadata_mutex);
experiment.ImportInstrumentMetadata(settings);
}
}
ImageFormatSettings JFJochStateMachine::GetImageFormatSettings() const {
std::unique_lock ul(experiment_image_format_settings_mutex);
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");
bool recalc_mask = (experiment.GetPedestalG0RMSLimit() != settings.GetPedestalG0RMSLimit());
{
std::unique_lock ul2(experiment_image_format_settings_mutex);
experiment.ImportImageFormatSettings(settings);
}
if (recalc_mask)
pixel_mask.LoadDetectorBadPixelMask(experiment, calibration.get());
else
pixel_mask.CalcEdgePixels(experiment);
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) {
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(experiment_file_writer_settings_mutex);
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");
{
std::unique_lock ul2(experiment_file_writer_settings_mutex);
experiment.ImportFileWriterSettings(settings);
}
}
IndexingSettings JFJochStateMachine::GetIndexingSettings() const {
std::unique_lock ul(experiment_indexing_settings_mutex);
return experiment.GetIndexingSettings();
}
void JFJochStateMachine::SetIndexingSettings(const IndexingSettings &input) {
std::unique_lock ul(m);
if (IsRunning())
throw WrongDAQStateException("Cannot change instrument metadata during data collection");
{
std::unique_lock ul2(experiment_indexing_settings_mutex);
experiment.ImportIndexingSettings(input);
try {
services.SetupIndexing(input);
} catch (const JFJochException &e) {
logger.ErrorException(e);
SetState(JFJochState::Error,
e.what(),
BrokerStatus::MessageSeverity::Error);
throw;
}
}
}
std::optional<ScanResult> JFJochStateMachine::GetScanResult() const {
std::unique_lock ul(m);
if (IsRunning())
throw WrongDAQStateException("Cannot check scan result, when running");
return scan_result;
}