// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include #include enum class JFJochExceptionCategory { JSON, InputParameterAboveMax, InputParameterBelowMin, InputParameterInvalid, WrongNumber, WrongUnit, ArrayOutOfBounds, HDF5, IBVerbs, RESTCommandUnknown, WrongDAQState, WrongReceiverState, Detector, MemAllocFailed, AcquisitionDeviceError, GPUCUDAError, GainFileOpenError, MockFileOpenError, Compression, SharedMemory, ZeroMQ, ServiceUndefined, TriggerError, FileWriteError, ZSTDCompressionError, LogstashConnectionFailure, TIFFGeneratorError, gRPCError, PreviewError, HardwareParityError, SpotFinderError, PCIeError, CBORError, UDPError, CommunicationError, SimplonError, CalibrationError }; class JFJochException : public std::exception { protected: std::string msg; JFJochExceptionCategory category; static std::string DecodeCategory(JFJochExceptionCategory category) { switch (category) { case JFJochExceptionCategory::JSON: return "JSON parsing or analysis error"; case JFJochExceptionCategory::InputParameterAboveMax: return "Input parameter above max"; case JFJochExceptionCategory::InputParameterBelowMin: return "Input parameter below min"; case JFJochExceptionCategory::InputParameterInvalid: return "Input parameter invalid"; case JFJochExceptionCategory::WrongNumber: return "Wrong number"; case JFJochExceptionCategory::WrongUnit: return "Wrong unit"; case JFJochExceptionCategory::ArrayOutOfBounds: return "Array out of bounds"; case JFJochExceptionCategory::HDF5: return "HDF5 error"; case JFJochExceptionCategory::IBVerbs: return "Infiniband error"; case JFJochExceptionCategory::RESTCommandUnknown: return "REST command unknown"; case JFJochExceptionCategory::WrongDAQState: return "DAQ state error"; case JFJochExceptionCategory::Detector: return "Detector error"; case JFJochExceptionCategory::MemAllocFailed: return "Memory error"; case JFJochExceptionCategory::AcquisitionDeviceError: return "Acquisition device error"; case JFJochExceptionCategory::GPUCUDAError: return "CUDA (GPU) error"; case JFJochExceptionCategory::GainFileOpenError: return "Gain file open error"; case JFJochExceptionCategory::MockFileOpenError: return "Mock file open error"; case JFJochExceptionCategory::Compression: return "Compression error"; case JFJochExceptionCategory::SharedMemory: return "Shared memory error"; case JFJochExceptionCategory::ZeroMQ: return "ZeroMQ error"; case JFJochExceptionCategory::ServiceUndefined: return "Service undefined error"; case JFJochExceptionCategory::TriggerError: return "Trigger error"; case JFJochExceptionCategory::FileWriteError: return "File writer error"; case JFJochExceptionCategory::ZSTDCompressionError: return "Zstd compressor error"; case JFJochExceptionCategory::LogstashConnectionFailure: return "Logstash connection error"; case JFJochExceptionCategory::TIFFGeneratorError: return "TIFF writer error"; case JFJochExceptionCategory::gRPCError: return "Remote node (gRPC) error"; case JFJochExceptionCategory::PreviewError: return "Preview error"; case JFJochExceptionCategory::HardwareParityError: return "Parity error (HW)"; case JFJochExceptionCategory::SpotFinderError: return "Spot finder"; case JFJochExceptionCategory::PCIeError: return "PCIe driver error"; case JFJochExceptionCategory::CBORError: return "CBOR serialization error"; case JFJochExceptionCategory::UDPError: return "UDP simulator error"; case JFJochExceptionCategory::CommunicationError: return "Communication error"; case JFJochExceptionCategory::SimplonError: return "Simplon API error"; case JFJochExceptionCategory::CalibrationError: return "Detector calibration error"; default: return ""; } } public: JFJochException(JFJochExceptionCategory in_val, const std::string &description) noexcept : category(in_val) { try { msg = DecodeCategory(category) + " (" + description + ")"; } catch (...) {} } JFJochException(const JFJochException &e) noexcept { try { category = e.category; msg = e.msg; } catch (...) {} } [[nodiscard]] const char *what() const noexcept override { return msg.c_str(); } }; class WrongDAQStateException : public JFJochException { public: explicit WrongDAQStateException(const std::string &description) : JFJochException(JFJochExceptionCategory::WrongDAQState, description) {} }; // Thrown when an operation leaves a subsystem (typically the detector) in an undefined state that a // simple retry cannot recover from - the broker must re-initialise. The state machine catches this // separately and goes to the Error state, whereas ordinary acquisition failures return to Idle. class JFJochCriticalException : public JFJochException { public: explicit JFJochCriticalException(const std::string &description, JFJochExceptionCategory in_category = JFJochExceptionCategory::Detector) : JFJochException(in_category, description) {} }; // A PCIe/FPGA hardware fault leaves the acquisition device in an undefined state that a retry cannot // recover from, so it is critical: the state machine forces re-initialisation (Error state) rather // than returning to Idle as it does for ordinary acquisition failures. class PCIeDeviceException : public JFJochCriticalException { public: explicit PCIeDeviceException(const std::string &description) : JFJochCriticalException(description, JFJochExceptionCategory::PCIeError) { msg += " (" + std::string(strerror(errno)) + ")"; } }; // Thrown by JFJochBitShuffleCompressor::Compress when the compressed output does not fit in the // caller-provided destination buffer. Lets callers (e.g. the receiver) drop just that frame. class CompressionBufferTooSmallException : public JFJochException { public: explicit CompressionBufferTooSmallException(const std::string &description) : JFJochException(JFJochExceptionCategory::Compression, description) {} };