blob: 37929084a8e6f3cf911b6cd2dfc1dae3cad1ce2d [file] [log] [blame]
#pragma once
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus.hpp>
#include <sdbusplus/message.hpp>
#include <xyz/openbmc_project/Common/error.hpp>
#include <string>
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, std::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);
::std::variant<Property> value;
msg.read(value);
return std::get<Property>(value);
}
/** @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