1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3 // SPDX-FileCopyrightText: Copyright 2019 Intel Corporation 4 #pragma once 5 6 #include "async_resp.hpp" 7 #include "dbus_singleton.hpp" 8 #include "dbus_utility.hpp" 9 #include "error_messages.hpp" 10 #include "generated/enums/chassis.hpp" 11 #include "logging.hpp" 12 #include "utils/dbus_utils.hpp" 13 14 #include <asm-generic/errno.h> 15 16 #include <boost/system/error_code.hpp> 17 #include <sdbusplus/asio/property.hpp> 18 #include <sdbusplus/message/native_types.hpp> 19 20 #include <array> 21 #include <functional> 22 #include <memory> 23 #include <string_view> 24 #include <utility> 25 26 namespace redfish 27 { 28 static constexpr std::array<std::string_view, 1> ledGroupInterface = { 29 "xyz.openbmc_project.Led.Group"}; 30 /** 31 * @brief Retrieves identify led group properties over dbus 32 * 33 * @param[in] asyncResp Shared pointer for generating response message. 34 * 35 * @return None. 36 */ 37 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 38 inline void getIndicatorLedState( 39 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 40 { 41 BMCWEB_LOG_DEBUG("Get led groups"); 42 dbus::utility::getProperty<bool>( 43 "xyz.openbmc_project.LED.GroupManager", 44 "/xyz/openbmc_project/led/groups/enclosure_identify_blink", 45 "xyz.openbmc_project.Led.Group", "Asserted", 46 [asyncResp](const boost::system::error_code& ec, const bool blinking) { 47 // Some systems may not have enclosure_identify_blink object so 48 // proceed to get enclosure_identify state. 49 if (ec == boost::system::errc::invalid_argument) 50 { 51 BMCWEB_LOG_DEBUG( 52 "Get identity blinking LED failed, mismatch in property type"); 53 messages::internalError(asyncResp->res); 54 return; 55 } 56 57 // Blinking ON, no need to check enclosure_identify assert. 58 if (!ec && blinking) 59 { 60 asyncResp->res.jsonValue["IndicatorLED"] = 61 chassis::IndicatorLED::Blinking; 62 return; 63 } 64 65 dbus::utility::getProperty<bool>( 66 "xyz.openbmc_project.LED.GroupManager", 67 "/xyz/openbmc_project/led/groups/enclosure_identify", 68 "xyz.openbmc_project.Led.Group", "Asserted", 69 [asyncResp](const boost::system::error_code& ec2, 70 const bool ledOn) { 71 if (ec2 == boost::system::errc::invalid_argument) 72 { 73 BMCWEB_LOG_DEBUG( 74 "Get enclosure identity led failed, mismatch in property type"); 75 messages::internalError(asyncResp->res); 76 return; 77 } 78 79 if (ec2) 80 { 81 return; 82 } 83 84 if (ledOn) 85 { 86 asyncResp->res.jsonValue["IndicatorLED"] = 87 chassis::IndicatorLED::Lit; 88 } 89 else 90 { 91 asyncResp->res.jsonValue["IndicatorLED"] = 92 chassis::IndicatorLED::Off; 93 } 94 }); 95 }); 96 } 97 98 /** 99 * @brief Sets identify led group properties 100 * 101 * @param[in] asyncResp Shared pointer for generating response message. 102 * @param[in] ledState LED state passed from request 103 * 104 * @return None. 105 */ 106 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 107 inline void setIndicatorLedState( 108 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 109 const std::string& ledState) 110 { 111 BMCWEB_LOG_DEBUG("Set led groups"); 112 bool ledOn = false; 113 bool ledBlinkng = false; 114 115 if (ledState == "Lit") 116 { 117 ledOn = true; 118 } 119 else if (ledState == "Blinking") 120 { 121 ledBlinkng = true; 122 } 123 else if (ledState != "Off") 124 { 125 messages::propertyValueNotInList(asyncResp->res, ledState, 126 "IndicatorLED"); 127 return; 128 } 129 130 sdbusplus::asio::setProperty( 131 *crow::connections::systemBus, "xyz.openbmc_project.LED.GroupManager", 132 "/xyz/openbmc_project/led/groups/enclosure_identify_blink", 133 "xyz.openbmc_project.Led.Group", "Asserted", ledBlinkng, 134 [asyncResp, ledOn, 135 ledBlinkng](const boost::system::error_code& ec) mutable { 136 if (ec) 137 { 138 // Some systems may not have enclosure_identify_blink object so 139 // Lets set enclosure_identify state to true if Blinking is 140 // true. 141 if (ledBlinkng) 142 { 143 ledOn = true; 144 } 145 } 146 setDbusProperty( 147 asyncResp, "IndicatorLED", 148 "xyz.openbmc_project.LED.GroupManager", 149 sdbusplus::message::object_path( 150 "/xyz/openbmc_project/led/groups/enclosure_identify"), 151 "xyz.openbmc_project.Led.Group", "Asserted", ledBlinkng); 152 }); 153 } 154 155 /** 156 * @brief Retrieves identify system led group properties over dbus 157 * 158 * @param[in] asyncResp Shared pointer for generating response message. 159 * 160 * @return None. 161 */ 162 inline void getSystemLocationIndicatorActive( 163 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 164 { 165 BMCWEB_LOG_DEBUG("Get LocationIndicatorActive"); 166 dbus::utility::getProperty<bool>( 167 "xyz.openbmc_project.LED.GroupManager", 168 "/xyz/openbmc_project/led/groups/enclosure_identify_blink", 169 "xyz.openbmc_project.Led.Group", "Asserted", 170 [asyncResp](const boost::system::error_code& ec, const bool blinking) { 171 // Some systems may not have enclosure_identify_blink object so 172 // proceed to get enclosure_identify state. 173 if (ec == boost::system::errc::invalid_argument) 174 { 175 BMCWEB_LOG_DEBUG( 176 "Get identity blinking LED failed, mismatch in property type"); 177 messages::internalError(asyncResp->res); 178 return; 179 } 180 181 // Blinking ON, no need to check enclosure_identify assert. 182 if (!ec && blinking) 183 { 184 asyncResp->res.jsonValue["LocationIndicatorActive"] = true; 185 return; 186 } 187 188 dbus::utility::getProperty<bool>( 189 "xyz.openbmc_project.LED.GroupManager", 190 "/xyz/openbmc_project/led/groups/enclosure_identify", 191 "xyz.openbmc_project.Led.Group", "Asserted", 192 [asyncResp](const boost::system::error_code& ec2, 193 const bool ledOn) { 194 if (ec2 == boost::system::errc::invalid_argument) 195 { 196 BMCWEB_LOG_DEBUG( 197 "Get enclosure identity led failed, mismatch in property type"); 198 messages::internalError(asyncResp->res); 199 return; 200 } 201 202 if (ec2) 203 { 204 return; 205 } 206 207 asyncResp->res.jsonValue["LocationIndicatorActive"] = ledOn; 208 }); 209 }); 210 } 211 212 /** 213 * @brief Sets identify system led group properties 214 * 215 * @param[in] asyncResp Shared pointer for generating response message. 216 * @param[in] ledState LED state passed from request 217 * 218 * @return None. 219 */ 220 inline void setSystemLocationIndicatorActive( 221 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const bool ledState) 222 { 223 BMCWEB_LOG_DEBUG("Set LocationIndicatorActive"); 224 225 sdbusplus::asio::setProperty( 226 *crow::connections::systemBus, "xyz.openbmc_project.LED.GroupManager", 227 "/xyz/openbmc_project/led/groups/enclosure_identify_blink", 228 "xyz.openbmc_project.Led.Group", "Asserted", ledState, 229 [asyncResp, ledState](const boost::system::error_code& ec) { 230 if (ec) 231 { 232 // Some systems may not have enclosure_identify_blink object so 233 // lets set enclosure_identify state also if 234 // enclosure_identify_blink failed 235 setDbusProperty( 236 asyncResp, "LocationIndicatorActive", 237 "xyz.openbmc_project.LED.GroupManager", 238 sdbusplus::message::object_path( 239 "/xyz/openbmc_project/led/groups/enclosure_identify"), 240 "xyz.openbmc_project.Led.Group", "Asserted", ledState); 241 } 242 }); 243 } 244 245 inline void handleLedGroupSubtree( 246 const std::string& objPath, const boost::system::error_code& ec, 247 const dbus::utility::MapperGetSubTreeResponse& subtree, 248 const std::function<void(const boost::system::error_code& ec, 249 const std::string& ledGroupPath, 250 const std::string& service)>& callback) 251 { 252 if (ec) 253 { 254 // Callback will handle the error 255 callback(ec, "", ""); 256 return; 257 } 258 259 if (subtree.empty()) 260 { 261 // Callback will handle the error 262 BMCWEB_LOG_DEBUG( 263 "No LED group associated with the specified object path: {}", 264 objPath); 265 callback(ec, "", ""); 266 return; 267 } 268 269 if (subtree.size() > 1) 270 { 271 // Callback will handle the error 272 BMCWEB_LOG_DEBUG( 273 "More than one LED group associated with the object {}: {}", 274 objPath, subtree.size()); 275 callback(ec, "", ""); 276 return; 277 } 278 279 const auto& [ledGroupPath, serviceMap] = *subtree.begin(); 280 const auto& [service, interfaces] = *serviceMap.begin(); 281 callback(ec, ledGroupPath, service); 282 } 283 284 inline void getLedGroupPath( 285 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 286 const std::string& objPath, 287 std::function<void(const boost::system::error_code& ec, 288 const std::string& ledGroupPath, 289 const std::string& service)>&& callback) 290 { 291 static constexpr const char* ledObjectPath = 292 "/xyz/openbmc_project/led/groups"; 293 sdbusplus::message::object_path ledGroupAssociatedPath = 294 objPath + "/identifying"; 295 296 dbus::utility::getAssociatedSubTree( 297 ledGroupAssociatedPath, sdbusplus::message::object_path(ledObjectPath), 298 0, ledGroupInterface, 299 [asyncResp, objPath, callback{std::move(callback)}]( 300 const boost::system::error_code& ec, 301 const dbus::utility::MapperGetSubTreeResponse& subtree) { 302 handleLedGroupSubtree(objPath, ec, subtree, callback); 303 }); 304 } 305 306 inline void afterGetLedState( 307 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 308 const boost::system::error_code& ec, bool assert) 309 { 310 if (ec) 311 { 312 if (ec.value() != EBADR) 313 { 314 BMCWEB_LOG_ERROR("DBUS response error for get ledState {}", 315 ec.value()); 316 messages::internalError(asyncResp->res); 317 } 318 return; 319 } 320 321 asyncResp->res.jsonValue["LocationIndicatorActive"] = assert; 322 } 323 324 inline void getLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 325 const boost::system::error_code& ec, 326 const std::string& ledGroupPath, 327 const std::string& service) 328 { 329 if (ec) 330 { 331 if (ec.value() != EBADR) 332 { 333 BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); 334 messages::internalError(asyncResp->res); 335 } 336 return; 337 } 338 339 if (ledGroupPath.empty() || service.empty()) 340 { 341 // No LED group associated, not an error 342 return; 343 } 344 345 sdbusplus::asio::getProperty<bool>( 346 *crow::connections::systemBus, service, ledGroupPath, 347 "xyz.openbmc_project.Led.Group", "Asserted", 348 std::bind_front(afterGetLedState, asyncResp)); 349 } 350 351 /** 352 * @brief Retrieves identify led group properties over dbus 353 * 354 * @param[in] asyncResp Shared pointer for generating response 355 * message. 356 * @param[in] objPath Object path on PIM 357 * 358 * @return None. 359 */ 360 inline void getLocationIndicatorActive( 361 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 362 const std::string& objPath) 363 { 364 BMCWEB_LOG_DEBUG("Get LocationIndicatorActive for {}", objPath); 365 getLedGroupPath(asyncResp, objPath, 366 [asyncResp](const boost::system::error_code& ec, 367 const std::string& ledGroupPath, 368 const std::string& service) { 369 getLedState(asyncResp, ec, ledGroupPath, service); 370 }); 371 } 372 373 inline void setLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 374 bool ledState, const boost::system::error_code& ec, 375 const std::string& ledGroupPath, 376 const std::string& service) 377 { 378 if (ec) 379 { 380 if (ec.value() == EBADR) 381 { 382 messages::propertyUnknown(asyncResp->res, 383 "LocationIndicatorActive"); 384 return; 385 } 386 BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); 387 messages::internalError(asyncResp->res); 388 return; 389 } 390 391 if (ledGroupPath.empty() || service.empty()) 392 { 393 messages::propertyUnknown(asyncResp->res, "LocationIndicatorActive"); 394 return; 395 } 396 397 setDbusProperty(asyncResp, "LocationIndicatorActive", service, ledGroupPath, 398 "xyz.openbmc_project.Led.Group", "Asserted", ledState); 399 } 400 401 /** 402 * @brief Sets identify led group properties 403 * 404 * @param[in] asyncResp Shared pointer for generating response 405 * message. 406 * @param[in] objPath Object path on PIM 407 * @param[in] ledState LED state passed from request 408 * 409 * @return None. 410 */ 411 inline void setLocationIndicatorActive( 412 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 413 const std::string& objPath, bool ledState) 414 { 415 BMCWEB_LOG_DEBUG("Set LocationIndicatorActive for {}", objPath); 416 getLedGroupPath( 417 asyncResp, objPath, 418 [asyncResp, ledState](const boost::system::error_code& ec, 419 const std::string& ledGroupPath, 420 const std::string& service) { 421 setLedState(asyncResp, ledState, ec, ledGroupPath, service); 422 }); 423 } 424 425 } // namespace redfish 426