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