#pragma once #include #include #include #include #include #include #include namespace phosphor { namespace fan { namespace util { namespace detail { namespace errors = sdbusplus::xyz::openbmc_project::Common::Error; } // namespace detail /** @brief Alias for PropertiesChanged signal callbacks. */ template using Properties = std::map>; /** @class SDBusPlus * @brief DBus access delegate implementation for sdbusplus. */ class SDBusPlus { public: /** @brief Get the bus connection. */ static auto& getBus() __attribute__((pure)) { static auto bus = sdbusplus::bus::new_default(); return bus; } /** @brief Invoke a method. */ template static auto callMethod( sdbusplus::bus::bus& bus, const std::string& busName, const std::string& path, const std::string& interface, const std::string& method, Args&& ... args) { auto reqMsg = bus.new_method_call( busName.c_str(), path.c_str(), interface.c_str(), method.c_str()); reqMsg.append(std::forward(args)...); auto respMsg = bus.call(reqMsg); if (respMsg.is_method_error()) { phosphor::logging::log( "Failed to invoke DBus method.", phosphor::logging::entry("PATH=%s", path.c_str()), phosphor::logging::entry( "INTERFACE=%s", interface.c_str()), phosphor::logging::entry("METHOD=%s", method.c_str())); phosphor::logging::elog(); } return respMsg; } /** @brief Invoke a method. */ template static auto callMethod( const std::string& busName, const std::string& path, const std::string& interface, const std::string& method, Args&& ... args) { return callMethod( getBus(), busName, path, interface, method, std::forward(args)...); } /** @brief Invoke a method and read the response. */ template static auto callMethodAndRead( sdbusplus::bus::bus& bus, const std::string& busName, const std::string& path, const std::string& interface, const std::string& method, Args&& ... args) { sdbusplus::message::message respMsg = callMethod( bus, busName, path, interface, method, std::forward(args)...); Ret resp; respMsg.read(resp); return resp; } /** @brief Invoke a method and read the response. */ template static auto callMethodAndRead( const std::string& busName, const std::string& path, const std::string& interface, const std::string& method, Args&& ... args) { return callMethodAndRead( getBus(), busName, path, interface, method, std::forward(args)...); } /** @brief Get service from the mapper. */ static auto getService( sdbusplus::bus::bus& bus, const std::string& path, const std::string& interface) { using namespace std::literals::string_literals; using GetObject = std::map>; auto mapperResp = callMethodAndRead( bus, "xyz.openbmc_project.ObjectMapper"s, "/xyz/openbmc_project/object_mapper"s, "xyz.openbmc_project.ObjectMapper"s, "GetObject"s, path, GetObject::mapped_type{interface}); if (mapperResp.empty()) { phosphor::logging::log( "Object not found.", phosphor::logging::entry("PATH=%s", path.c_str()), phosphor::logging::entry( "INTERFACE=%s", interface.c_str())); phosphor::logging::elog(); } return mapperResp.begin()->first; } /** @brief Get service from the mapper. */ static auto getService( const std::string& path, const std::string& interface) { return getService( getBus(), path, interface); } /** @brief Get a property with mapper lookup. */ template static auto getProperty( sdbusplus::bus::bus& bus, const std::string& path, const std::string& interface, const std::string& property) { using namespace std::literals::string_literals; auto msg = callMethod( bus, getService(bus, path, interface), path, "org.freedesktop.DBus.Properties"s, "Get"s, interface, property); sdbusplus::message::variant value; msg.read(value); return value.template get(); } /** @brief Get a property with mapper lookup. */ template static auto getProperty( const std::string& path, const std::string& interface, const std::string& property) { return getProperty( getBus(), path, interface, property); } /** @brief Set a property with mapper lookup. */ template static void setProperty( sdbusplus::bus::bus& bus, const std::string& path, const std::string& interface, const std::string& property, Property&& value) { using namespace std::literals::string_literals; sdbusplus::message::variant varValue( std::forward(value)); callMethod( bus, getService(bus, path, interface), path, "org.freedesktop.DBus.Properties"s, "Set"s, interface, property, varValue); } /** @brief Set a property with mapper lookup. */ template static void setProperty( const std::string& path, const std::string& interface, const std::string& property, Property&& value) { return setProperty( getBus(), path, interface, property, std::forward(value)); } /** @brief Invoke method with mapper lookup. */ template static auto lookupAndCallMethod( sdbusplus::bus::bus& bus, const std::string& path, const std::string& interface, const std::string& method, Args&& ... args) { return callMethod( bus, getService(bus, path, interface), path, interface, method, std::forward(args)...); } /** @brief Invoke method with mapper lookup. */ template static auto lookupAndCallMethod( const std::string& path, const std::string& interface, const std::string& method, Args&& ... args) { return lookupAndCallMethod( getBus(), path, interface, method, std::forward(args)...); } /** @brief Invoke method and read with mapper lookup. */ template static auto lookupCallMethodAndRead( sdbusplus::bus::bus& bus, const std::string& path, const std::string& interface, const std::string& method, Args&& ... args) { return callMethodAndRead( bus, getService(bus, path, interface), path, interface, method, std::forward(args)...); } /** @brief Invoke method and read with mapper lookup. */ template static auto lookupCallMethodAndRead( const std::string& path, const std::string& interface, const std::string& method, Args&& ... args) { return lookupCallMethodAndRead( getBus(), path, interface, method, std::forward(args)...); } }; } // namespace util } // namespace fan } // namespace phosphor