1 #pragma once 2 3 #include <sdbusplus/bus.hpp> 4 #include <sdbusplus/message.hpp> 5 #include <phosphor-logging/log.hpp> 6 #include <phosphor-logging/elog.hpp> 7 #include <phosphor-logging/elog-errors.hpp> 8 #include <xyz/openbmc_project/Common/error.hpp> 9 10 namespace util 11 { 12 namespace detail 13 { 14 namespace errors = sdbusplus::xyz::openbmc_project::Common::Error; 15 } // namespace detail 16 17 /** @brief Alias for PropertiesChanged signal callbacks. */ 18 template <typename... T> 19 using Properties = std::map<std::string, sdbusplus::message::variant<T...>>; 20 21 namespace sdbusplus 22 { 23 24 /** @brief Get the bus connection. */ 25 static auto& getBus() __attribute__((pure)); 26 static auto& getBus() 27 { 28 static auto bus = ::sdbusplus::bus::new_default(); 29 return bus; 30 } 31 32 /** @brief Invoke a method. */ 33 template <typename... Args> 34 static auto callMethod(::sdbusplus::bus::bus& bus, const std::string& busName, 35 const std::string& path, const std::string& interface, 36 const std::string& method, Args&&... args) 37 { 38 auto reqMsg = bus.new_method_call(busName.c_str(), path.c_str(), 39 interface.c_str(), method.c_str()); 40 reqMsg.append(std::forward<Args>(args)...); 41 auto respMsg = bus.call(reqMsg); 42 43 if (respMsg.is_method_error()) 44 { 45 phosphor::logging::log<phosphor::logging::level::INFO>( 46 "Failed to invoke DBus method.", 47 phosphor::logging::entry("PATH=%s", path.c_str()), 48 phosphor::logging::entry("INTERFACE=%s", interface.c_str()), 49 phosphor::logging::entry("METHOD=%s", method.c_str())); 50 phosphor::logging::elog<detail::errors::InternalFailure>(); 51 } 52 53 return respMsg; 54 } 55 56 /** @brief Invoke a method. */ 57 template <typename... Args> 58 static auto callMethod(const std::string& busName, const std::string& path, 59 const std::string& interface, const std::string& method, 60 Args&&... args) 61 { 62 return callMethod(getBus(), busName, path, interface, method, 63 std::forward<Args>(args)...); 64 } 65 66 /** @brief Invoke a method and read the response. */ 67 template <typename Ret, typename... Args> 68 static auto 69 callMethodAndRead(::sdbusplus::bus::bus& bus, const std::string& busName, 70 const std::string& path, const std::string& interface, 71 const std::string& method, Args&&... args) 72 { 73 ::sdbusplus::message::message respMsg = callMethod<Args...>( 74 bus, busName, path, interface, method, std::forward<Args>(args)...); 75 Ret resp; 76 respMsg.read(resp); 77 return resp; 78 } 79 80 /** @brief Invoke a method and read the response. */ 81 template <typename Ret, typename... Args> 82 static auto callMethodAndRead(const std::string& busName, 83 const std::string& path, 84 const std::string& interface, 85 const std::string& method, Args&&... args) 86 { 87 return callMethodAndRead<Ret>(getBus(), busName, path, interface, method, 88 std::forward<Args>(args)...); 89 } 90 91 /** @brief Get service from the mapper. */ 92 static auto getService(::sdbusplus::bus::bus& bus, const std::string& path, 93 const std::string& interface) 94 { 95 using namespace std::literals::string_literals; 96 using GetObject = std::map<std::string, std::vector<std::string>>; 97 98 auto mapperResp = callMethodAndRead<GetObject>( 99 bus, "xyz.openbmc_project.ObjectMapper"s, 100 "/xyz/openbmc_project/object_mapper"s, 101 "xyz.openbmc_project.ObjectMapper"s, "GetObject"s, path, 102 GetObject::mapped_type{interface}); 103 104 if (mapperResp.empty()) 105 { 106 phosphor::logging::log<phosphor::logging::level::INFO>( 107 "Object not found.", 108 phosphor::logging::entry("PATH=%s", path.c_str()), 109 phosphor::logging::entry("INTERFACE=%s", interface.c_str())); 110 phosphor::logging::elog<detail::errors::InternalFailure>(); 111 } 112 return mapperResp.begin()->first; 113 } 114 115 /** @brief Get a property without mapper lookup. */ 116 template <typename Property> 117 static auto getProperty(::sdbusplus::bus::bus& bus, const std::string& busName, 118 const std::string& path, const std::string& interface, 119 const std::string& property) 120 { 121 using namespace std::literals::string_literals; 122 123 auto msg = 124 callMethod(bus, busName, path, "org.freedesktop.DBus.Properties"s, 125 "Get"s, interface, property); 126 ::sdbusplus::message::variant<Property> value; 127 msg.read(value); 128 return value.template get<Property>(); 129 } 130 131 /** @brief Get a property without mapper lookup. */ 132 template <typename Property> 133 static auto getProperty(const std::string& busName, const std::string& path, 134 const std::string& interface, 135 const std::string& property) 136 { 137 return getProperty<Property>(getBus(), busName, path, interface, property); 138 } 139 140 /** @brief Get a property with mapper lookup. */ 141 template <typename Property> 142 static auto getProperty(::sdbusplus::bus::bus& bus, const std::string& path, 143 const std::string& interface, 144 const std::string& property) 145 { 146 return getProperty<Property>(bus, getService(bus, path, interface), path, 147 interface, property); 148 } 149 150 /** @brief Get a property with mapper lookup. */ 151 template <typename Property> 152 static auto getProperty(const std::string& path, const std::string& interface, 153 const std::string& property) 154 { 155 return getProperty<Property>(getBus(), path, interface, property); 156 } 157 158 } // namespace sdbusplus 159 } // namespace util 160