1 #pragma once 2 3 #include <sdbusplus/bus.hpp> 4 #include <sdbusplus/message.hpp> 5 #include <sdbusplus/bus/match.hpp> 6 #include <phosphor-logging/log.hpp> 7 #include <phosphor-logging/elog.hpp> 8 #include <phosphor-logging/elog-errors.hpp> 9 #include <xyz/openbmc_project/Common/error.hpp> 10 11 namespace phosphor 12 { 13 namespace fan 14 { 15 namespace util 16 { 17 namespace detail 18 { 19 namespace errors = sdbusplus::xyz::openbmc_project::Common::Error; 20 } // namespace detail 21 22 /** @brief Alias for PropertiesChanged signal callbacks. */ 23 template <typename ...T> 24 using Properties = std::map<std::string, sdbusplus::message::variant<T...>>; 25 26 /** @class SDBusPlus 27 * @brief DBus access delegate implementation for sdbusplus. 28 */ 29 class SDBusPlus 30 { 31 32 public: 33 /** @brief Get the bus connection. */ 34 static auto& getBus() __attribute__((pure)) 35 { 36 static auto bus = sdbusplus::bus::new_default(); 37 return bus; 38 } 39 40 /** @brief Invoke a method. */ 41 template <typename ...Args> 42 static auto callMethod( 43 sdbusplus::bus::bus& bus, 44 const std::string& busName, 45 const std::string& path, 46 const std::string& interface, 47 const std::string& method, 48 Args&& ... args) 49 { 50 auto reqMsg = bus.new_method_call( 51 busName.c_str(), 52 path.c_str(), 53 interface.c_str(), 54 method.c_str()); 55 reqMsg.append(std::forward<Args>(args)...); 56 auto respMsg = bus.call(reqMsg); 57 58 if (respMsg.is_method_error()) 59 { 60 phosphor::logging::log<phosphor::logging::level::INFO>( 61 "Failed to invoke DBus method.", 62 phosphor::logging::entry("PATH=%s", path.c_str()), 63 phosphor::logging::entry( 64 "INTERFACE=%s", interface.c_str()), 65 phosphor::logging::entry("METHOD=%s", method.c_str())); 66 phosphor::logging::elog<detail::errors::InternalFailure>(); 67 } 68 69 return respMsg; 70 } 71 72 /** @brief Invoke a method. */ 73 template <typename ...Args> 74 static auto callMethod( 75 const std::string& busName, 76 const std::string& path, 77 const std::string& interface, 78 const std::string& method, 79 Args&& ... args) 80 { 81 return callMethod( 82 getBus(), 83 busName, 84 path, 85 interface, 86 method, 87 std::forward<Args>(args)...); 88 } 89 90 /** @brief Invoke a method and read the response. */ 91 template <typename Ret, typename ...Args> 92 static auto callMethodAndRead( 93 sdbusplus::bus::bus& bus, 94 const std::string& busName, 95 const std::string& path, 96 const std::string& interface, 97 const std::string& method, 98 Args&& ... args) 99 { 100 sdbusplus::message::message respMsg = 101 callMethod<Args...>( 102 bus, 103 busName, 104 path, 105 interface, 106 method, 107 std::forward<Args>(args)...); 108 Ret resp; 109 respMsg.read(resp); 110 return resp; 111 } 112 113 /** @brief Invoke a method and read the response. */ 114 template <typename Ret, typename ...Args> 115 static auto callMethodAndRead( 116 const std::string& busName, 117 const std::string& path, 118 const std::string& interface, 119 const std::string& method, 120 Args&& ... args) 121 { 122 return callMethodAndRead<Ret>( 123 getBus(), 124 busName, 125 path, 126 interface, 127 method, 128 std::forward<Args>(args)...); 129 } 130 131 132 /** @brief Get service from the mapper. */ 133 static auto getService( 134 sdbusplus::bus::bus& bus, 135 const std::string& path, 136 const std::string& interface) 137 { 138 using namespace std::literals::string_literals; 139 using GetObject = std::map<std::string, std::vector<std::string>>; 140 141 auto mapperResp = callMethodAndRead<GetObject>( 142 bus, 143 "xyz.openbmc_project.ObjectMapper"s, 144 "/xyz/openbmc_project/object_mapper"s, 145 "xyz.openbmc_project.ObjectMapper"s, 146 "GetObject"s, 147 path, 148 GetObject::mapped_type{interface}); 149 150 if (mapperResp.empty()) 151 { 152 phosphor::logging::log<phosphor::logging::level::INFO>( 153 "Object not found.", 154 phosphor::logging::entry("PATH=%s", path.c_str()), 155 phosphor::logging::entry( 156 "INTERFACE=%s", interface.c_str())); 157 phosphor::logging::elog<detail::errors::InternalFailure>(); 158 } 159 return mapperResp.begin()->first; 160 } 161 162 /** @brief Get service from the mapper. */ 163 static auto getService( 164 const std::string& path, 165 const std::string& interface) 166 { 167 return getService( 168 getBus(), 169 path, 170 interface); 171 } 172 173 /** @brief Get a property with mapper lookup. */ 174 template <typename Property> 175 static auto getProperty( 176 sdbusplus::bus::bus& bus, 177 const std::string& path, 178 const std::string& interface, 179 const std::string& property) 180 { 181 using namespace std::literals::string_literals; 182 183 auto msg = callMethod( 184 bus, 185 getService(bus, path, interface), 186 path, 187 "org.freedesktop.DBus.Properties"s, 188 "Get"s, 189 interface, 190 property); 191 sdbusplus::message::variant<Property> value; 192 msg.read(value); 193 return value.template get<Property>(); 194 } 195 196 /** @brief Get a property with mapper lookup. */ 197 template <typename Property> 198 static auto getProperty( 199 const std::string& path, 200 const std::string& interface, 201 const std::string& property) 202 { 203 return getProperty<Property>( 204 getBus(), 205 path, 206 interface, 207 property); 208 } 209 210 /** @brief Set a property with mapper lookup. */ 211 template <typename Property> 212 static void setProperty( 213 sdbusplus::bus::bus& bus, 214 const std::string& path, 215 const std::string& interface, 216 const std::string& property, 217 Property&& value) 218 { 219 using namespace std::literals::string_literals; 220 221 sdbusplus::message::variant<Property> varValue( 222 std::forward<Property>(value)); 223 224 callMethod( 225 bus, 226 getService(bus, path, interface), 227 path, 228 "org.freedesktop.DBus.Properties"s, 229 "Set"s, 230 interface, 231 property, 232 varValue); 233 } 234 235 /** @brief Set a property with mapper lookup. */ 236 template <typename Property> 237 static void setProperty( 238 const std::string& path, 239 const std::string& interface, 240 const std::string& property, 241 Property&& value) 242 { 243 return setProperty( 244 getBus(), 245 path, 246 interface, 247 property, 248 std::forward<Property>(value)); 249 } 250 251 /** @brief Invoke method with mapper lookup. */ 252 template <typename ...Args> 253 static auto lookupAndCallMethod( 254 sdbusplus::bus::bus& bus, 255 const std::string& path, 256 const std::string& interface, 257 const std::string& method, 258 Args&& ... args) 259 { 260 return callMethod( 261 bus, 262 getService(bus, path, interface), 263 path, 264 interface, 265 method, 266 std::forward<Args>(args)...); 267 } 268 269 /** @brief Invoke method with mapper lookup. */ 270 template <typename ...Args> 271 static auto lookupAndCallMethod( 272 const std::string& path, 273 const std::string& interface, 274 const std::string& method, 275 Args&& ... args) 276 { 277 return lookupAndCallMethod( 278 getBus(), 279 path, 280 interface, 281 method, 282 std::forward<Args>(args)...); 283 } 284 285 /** @brief Invoke method and read with mapper lookup. */ 286 template <typename Ret, typename ...Args> 287 static auto lookupCallMethodAndRead( 288 sdbusplus::bus::bus& bus, 289 const std::string& path, 290 const std::string& interface, 291 const std::string& method, 292 Args&& ... args) 293 { 294 return callMethodAndRead( 295 bus, 296 getService(bus, path, interface), 297 path, 298 interface, 299 method, 300 std::forward<Args>(args)...); 301 } 302 303 /** @brief Invoke method and read with mapper lookup. */ 304 template <typename Ret, typename ...Args> 305 static auto lookupCallMethodAndRead( 306 const std::string& path, 307 const std::string& interface, 308 const std::string& method, 309 Args&& ... args) 310 { 311 return lookupCallMethodAndRead<Ret>( 312 getBus(), 313 path, 314 interface, 315 method, 316 std::forward<Args>(args)...); 317 } 318 }; 319 320 } // namespace util 321 } // namespace fan 322 } // namespace phosphor 323