#pragma once #include #include #include #include class DaliQueryException : public std::exception { public: enum class Code { busUnavailable, gatewayTimeout, deviceNoResponse, invalidFrame, invalidGatewayFrame, unknown, }; DaliQueryException(Code code, std::string message, std::optional addr = std::nullopt, std::optional cmd = std::nullopt) : code_(code), message_(std::move(message)), addr_(addr), cmd_(cmd) {} const char* what() const noexcept override { return message_.c_str(); } Code code() const { return code_; } const std::optional& addr() const { return addr_; } const std::optional& cmd() const { return cmd_; } private: Code code_ = Code::unknown; std::string message_; std::optional addr_; std::optional cmd_; }; class DaliBusUnavailableException : public DaliQueryException { public: explicit DaliBusUnavailableException(std::optional addr = std::nullopt, std::optional cmd = std::nullopt) : DaliQueryException(Code::busUnavailable, "Bus unavailable", addr, cmd) {} }; class DaliGatewayTimeoutException : public DaliQueryException { public: explicit DaliGatewayTimeoutException(std::optional addr = std::nullopt, std::optional cmd = std::nullopt) : DaliQueryException(Code::gatewayTimeout, "Gateway no response", addr, cmd) {} }; class DaliDeviceNoResponseException : public DaliQueryException { public: explicit DaliDeviceNoResponseException(std::optional addr = std::nullopt, std::optional cmd = std::nullopt) : DaliQueryException(Code::deviceNoResponse, "Device no response", addr, cmd) {} }; class DaliInvalidFrameException : public DaliQueryException { public: explicit DaliInvalidFrameException(std::optional addr = std::nullopt, std::optional cmd = std::nullopt) : DaliQueryException(Code::invalidFrame, "Invalid frame", addr, cmd) {} }; class DaliInvalidGatewayFrameException : public DaliQueryException { public: explicit DaliInvalidGatewayFrameException(std::optional addr = std::nullopt, std::optional cmd = std::nullopt) : DaliQueryException(Code::invalidGatewayFrame, "Invalid gateway frame", addr, cmd) {} }; inline std::string mapDaliErrorToMessage(const DaliQueryException& e) { switch (e.code()) { case DaliQueryException::Code::busUnavailable: return "dali.error.bus_unavailable"; case DaliQueryException::Code::gatewayTimeout: return "dali.error.gateway_timeout"; case DaliQueryException::Code::deviceNoResponse: return "dali.error.device_no_response"; case DaliQueryException::Code::invalidFrame: return "dali.error.invalid_frame"; case DaliQueryException::Code::invalidGatewayFrame: return "dali.error.invalid_gateway_frame"; case DaliQueryException::Code::unknown: default: break; } return "dali.error.unknown"; } template std::optional daliSafe(const std::function& action, const std::function& onError = nullptr, bool rethrowOthers = false) { #if defined(__cpp_exceptions) try { return action(); } catch (const DaliQueryException& e) { if (onError) onError(mapDaliErrorToMessage(e)); return std::nullopt; } catch (...) { if (rethrowOthers) throw; if (onError) onError("Unexpected error"); return std::nullopt; } #else (void)onError; (void)rethrowOthers; return action(); #endif }