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