// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include "JFJochServices.h" #include "../common/JFJochException.h" #include "../detector_control/SLSDetectorWrapper.h" #include "../detector_control/DectrisDetectorWrapper.h" JFJochServices::JFJochServices(Logger &in_logger) : logger(in_logger) {} void JFJochServices::Start(const DiffractionExperiment& experiment, const PixelMask &pixel_mask, const JFCalibration *calibration) { logger.Info("Measurement start for: {}", experiment.GetFilePrefix()); cannot_stop_detector = false; if (receiver != nullptr) { logger.Info(" ... receiver start"); if (image_puller) image_puller->ResumeAndClear(); receiver->Start(experiment, pixel_mask, calibration, image_puller); { std::shared_lock ul(detector_mutex); if (detector && !experiment.IsUsingInternalPacketGen()) { logger.Info(" ... detector start"); detector->Start(experiment); } } } logger.Info(" Done!"); } void JFJochServices::Off() { image_puller.reset(); std::unique_ptr old_detector; { std::unique_lock ul(detector_mutex); old_detector = std::move(detector); } if (old_detector) { old_detector->Deactivate(); // destroyed here, outside lock } } void JFJochServices::On(DiffractionExperiment &x) { if (x.IsUsingInternalPacketGen() || (receiver == nullptr)) { std::unique_lock ul(detector_mutex); detector.reset(); } else { logger.Info("Detector on"); std::unique_ptr new_detector; switch (x.GetDetectorType()) { case DetectorType::EIGER: case DetectorType::JUNGFRAU: new_detector = std::make_unique(); image_puller.reset(); break; case DetectorType::DECTRIS: new_detector = std::make_unique(); image_puller = std::make_shared(x.GetDetectorSetup().GetDECTRISStream2Addr()); image_puller->Suspend(); break; } new_detector->Initialize(x, receiver->GetNetworkConfig()); { std::unique_lock ul(detector_mutex); detector = std::move(new_detector); } logger.Info(" ... done"); } } JFJochServicesOutput JFJochServices::Stop() { JFJochServicesOutput ret; std::unique_ptr exception; bool detector_error = false; if (receiver != nullptr) { try { { std::shared_lock ul(detector_mutex); if (detector) { logger.Info("Wait for detector idle"); DetectorState state = detector->GetState(); while ((!cannot_stop_detector) && ((state == DetectorState::WAITING) || (state == DetectorState::BUSY))) { // check detector state every 5 ms std::this_thread::sleep_for(std::chrono::milliseconds(5)); state = detector->GetState(); } if (state == DetectorState::IDLE) { logger.Info(" ... detector idle"); receiver->Cancel(true); // cancel silently } else { logger.Error(" ... detector in error state"); receiver->Cancel(false); detector_error = true; } } } logger.Info("Wait for receiver done"); ret.receiver_output = receiver->Stop(); if (image_puller) image_puller->Suspend(); logger.Info(" ... Receiver efficiency: {} % Max delay: {} Compression ratio {}x", static_cast(ret.receiver_output.efficiency * 100.0), ret.receiver_output.status.max_receive_delay.value_or(0), static_cast(std::round(ret.receiver_output.status.compressed_ratio.value_or(1)))); if (ret.receiver_output.efficiency < 1.0) { for (int i = 0; i < ret.receiver_output.received_packets.size(); i++) { if (ret.receiver_output.received_packets[i] != ret.receiver_output.expected_packets[i]) logger.Info(" ... Module: {} Packets received: {} out of {}", i, ret.receiver_output.received_packets[i], ret.receiver_output.expected_packets[i]); } } logger.Info(" ... finished with success"); } catch (const JFJochException &e) { logger.Error(" ... finished with error {}", e.what()); exception = std::make_unique(e); } } else { logger.Info("No receiver - sleeping for 30 seconds"); std::this_thread::sleep_for(std::chrono::seconds(30)); logger.Info("Sleep done"); } if (exception) throw JFJochException(*exception); if (detector_error) throw JFJochException(JFJochExceptionCategory::Detector, "Error in detector operation"); return ret; } void JFJochServices::Cancel() { std::shared_lock ul(detector_mutex); if (detector) { // Best effort - if detector cannot be stopped, this is OK, important to still stop receiver try { detector->Stop(); } catch (...) { cannot_stop_detector = true; } } if (receiver != nullptr) receiver->Cancel(false); } JFJochServices &JFJochServices::Receiver(JFJochReceiverService *input) { receiver = input; return *this; } std::optional JFJochServices::GetReceiverStatus() const { if (receiver == nullptr) return {}; return receiver->GetStatus(); } std::optional JFJochServices::GetReceiverProgress() const { if (receiver == nullptr) return {}; return receiver->GetProgress(); } MultiLinePlot JFJochServices::GetPlots(const PlotRequest &request) { if (receiver == nullptr) return {}; return receiver->GetDataProcessingPlot(request); } void JFJochServices::GetPlotRaw(std::vector &v, PlotType type, const std::string &roi) { if (receiver != nullptr) receiver->GetPlotRaw(v, type, roi); } void JFJochServices::SetSpotFindingSettings(const SpotFindingSettings &settings) { if (receiver) receiver->SetSpotFindingSettings(settings); } void JFJochServices::Trigger() { std::shared_lock ul(detector_mutex); if (detector && (receiver != nullptr)) detector->Trigger(); } std::optional JFJochServices::GetDetectorStatus() const { std::shared_lock ul(detector_mutex, std::defer_lock); if (ul.try_lock_for(std::chrono::milliseconds(500)) && detector) return detector->GetStatus(); return {}; } std::string JFJochServices::GetPreviewJPEG(const PreviewImageSettings &settings, int64_t image_number) const { if (receiver != nullptr) return receiver->GetJPEGFromBuffer(settings, image_number); else return {}; } std::string JFJochServices::GetPreviewTIFF(int64_t image_number) const { if (receiver != nullptr) return receiver->GetTIFFFromBuffer(image_number); else return ""; } void JFJochServices::ConfigureDetector(const DiffractionExperiment &experiment) { std::unique_lock ul(detector_mutex); // While configuring detector ensure exclusive access (even though pointer is not modified here) if (detector) detector->Configure(experiment); } void JFJochServices::LoadInternalGeneratorImage(const DiffractionExperiment &experiment, const std::vector &image, uint64_t image_number) { if (receiver) receiver->LoadInternalGeneratorImage(experiment, image, image_number); } void JFJochServices::GetXFELPulseID(std::vector &v) const { if (receiver) receiver->GetXFELPulseID(v); } void JFJochServices::GetXFELEventCode(std::vector &v) const { if (receiver) receiver->GetXFELEventCode(v); } std::vector JFJochServices::GetDeviceStatus() const { std::vector ret; if (receiver) ret = receiver->GetDeviceStatus(); return ret; } ZMQPreviewSettings JFJochServices::GetPreviewSocketSettings() { if (receiver) return receiver->GetPreviewSocketSettings(); return {}; } ZMQMetadataSettings JFJochServices::GetMetadataSocketSettings() { if (receiver) return receiver->GetMetadataSocketSettings(); return {}; } void JFJochServices::SetPreviewSocketSettings(const ZMQPreviewSettings &input) { if (receiver) receiver->PreviewSocketSettings(input); } void JFJochServices::SetMetadataSocketSettings(const ZMQMetadataSettings &input) { if (receiver) receiver->MetadataSocketSettings(input); } void JFJochServices::GetStartMessageFromBuffer(std::vector &v) { if (receiver) return receiver->GetStartMessageFromBuffer(v); } bool JFJochServices::GetImageFromBuffer(std::vector &v, int64_t image_number) { if (receiver) return receiver->GetImageFromBuffer(v, image_number); return false; } ImageBufferStatus JFJochServices::GetImageBufferStatus() const { if (receiver) return receiver->GetImageBufferStatus(); else return ImageBufferStatus{.total_slots = 0, .available_slots = 0}; } void JFJochServices::ClearImageBuffer() const { if (receiver) receiver->ClearImageBuffer(); } void JFJochServices::LoadDetectorPixelMask(PixelMask &mask) { std::shared_lock ul(detector_mutex); if (detector) detector->LoadPixelMask(mask); } void JFJochServices::SetupIndexing(const IndexingSettings &input) { if (receiver) receiver->Indexing(input); } ImagePusherStatus JFJochServices::GetImagePusherStatus() const { if (receiver) return receiver->GetImagePusherStatus(); return { .pusher_type = ImagePusherType::None, .address = {}, .connected_writers = 0 }; }