| #pragma once |
| |
| #include <sdbusplus/bus.hpp> |
| #include <sdbusplus/message.hpp> |
| #include <phosphor-logging/log.hpp> |
| #include <phosphor-logging/elog.hpp> |
| #include <phosphor-logging/elog-errors.hpp> |
| #include <xyz/openbmc_project/Common/error.hpp> |
| |
| namespace util |
| { |
| namespace detail |
| { |
| namespace errors = sdbusplus::xyz::openbmc_project::Common::Error; |
| } // namespace detail |
| |
| /** @brief Alias for PropertiesChanged signal callbacks. */ |
| template <typename ...T> |
| using Properties = std::map<std::string, sdbusplus::message::variant<T...>>; |
| |
| namespace sdbusplus |
| { |
| |
| /** @brief Get the bus connection. */ |
| static auto& getBus() __attribute__((pure)); |
| static auto& getBus() |
| { |
| static auto bus = ::sdbusplus::bus::new_default(); |
| return bus; |
| } |
| |
| /** @brief Invoke a method. */ |
| template <typename ...Args> |
| 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>(args)...); |
| auto respMsg = bus.call(reqMsg); |
| |
| if (respMsg.is_method_error()) |
| { |
| phosphor::logging::log<phosphor::logging::level::INFO>( |
| "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<detail::errors::InternalFailure>(); |
| } |
| |
| return respMsg; |
| } |
| |
| /** @brief Invoke a method. */ |
| template <typename ...Args> |
| 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>(args)...); |
| } |
| |
| /** @brief Invoke a method and read the response. */ |
| template <typename Ret, typename ...Args> |
| 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<Args...>( |
| bus, |
| busName, |
| path, |
| interface, |
| method, |
| std::forward<Args>(args)...); |
| Ret resp; |
| respMsg.read(resp); |
| return resp; |
| } |
| |
| /** @brief Invoke a method and read the response. */ |
| template <typename Ret, typename ...Args> |
| static auto callMethodAndRead( |
| const std::string& busName, |
| const std::string& path, |
| const std::string& interface, |
| const std::string& method, |
| Args&& ... args) |
| { |
| return callMethodAndRead<Ret>( |
| getBus(), |
| busName, |
| path, |
| interface, |
| method, |
| std::forward<Args>(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<std::string, std::vector<std::string>>; |
| |
| auto mapperResp = callMethodAndRead<GetObject>( |
| 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<phosphor::logging::level::INFO>( |
| "Object not found.", |
| phosphor::logging::entry("PATH=%s", path.c_str()), |
| phosphor::logging::entry( |
| "INTERFACE=%s", interface.c_str())); |
| phosphor::logging::elog<detail::errors::InternalFailure>(); |
| } |
| return mapperResp.begin()->first; |
| } |
| |
| /** @brief Get a property without mapper lookup. */ |
| template <typename Property> |
| static auto getProperty( |
| ::sdbusplus::bus::bus& bus, |
| const std::string& busName, |
| const std::string& path, |
| const std::string& interface, |
| const std::string& property) |
| { |
| using namespace std::literals::string_literals; |
| |
| auto msg = callMethod( |
| bus, |
| busName, |
| path, |
| "org.freedesktop.DBus.Properties"s, |
| "Get"s, |
| interface, |
| property); |
| ::sdbusplus::message::variant<Property> value; |
| msg.read(value); |
| return value.template get<Property>(); |
| } |
| |
| /** @brief Get a property without mapper lookup. */ |
| template <typename Property> |
| static auto getProperty( |
| const std::string& busName, |
| const std::string& path, |
| const std::string& interface, |
| const std::string& property) |
| { |
| return getProperty<Property>( |
| getBus(), |
| busName, |
| path, |
| interface, |
| property); |
| } |
| |
| /** @brief Get a property with mapper lookup. */ |
| template <typename Property> |
| static auto getProperty( |
| ::sdbusplus::bus::bus& bus, |
| const std::string& path, |
| const std::string& interface, |
| const std::string& property) |
| { |
| return getProperty<Property>( |
| bus, |
| getService(bus, path, interface), |
| path, |
| interface, |
| property); |
| } |
| |
| /** @brief Get a property with mapper lookup. */ |
| template <typename Property> |
| static auto getProperty( |
| const std::string& path, |
| const std::string& interface, |
| const std::string& property) |
| { |
| return getProperty<Property>( |
| getBus(), |
| path, |
| interface, |
| property); |
| } |
| |
| } // namespace sdbusplus |
| } // namespace util |