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 inline void handleLedGroupSubtree( 157 const std::string& objPath, const boost::system::error_code& ec, 158 const dbus::utility::MapperGetSubTreeResponse& subtree, 159 const std::function<void(const boost::system::error_code& ec, 160 const std::string& ledGroupPath, 161 const std::string& service)>& callback) 162 { 163 if (ec) 164 { 165 // Callback will handle the error 166 callback(ec, "", ""); 167 return; 168 } 169 170 if (subtree.empty()) 171 { 172 // Callback will handle the error 173 BMCWEB_LOG_DEBUG( 174 "No LED group associated with the specified object path: {}", 175 objPath); 176 callback(ec, "", ""); 177 return; 178 } 179 180 if (subtree.size() > 1) 181 { 182 // Callback will handle the error 183 BMCWEB_LOG_DEBUG( 184 "More than one LED group associated with the object {}: {}", 185 objPath, subtree.size()); 186 callback(ec, "", ""); 187 return; 188 } 189 190 const auto& [ledGroupPath, serviceMap] = *subtree.begin(); 191 const auto& [service, interfaces] = *serviceMap.begin(); 192 callback(ec, ledGroupPath, service); 193 } 194 195 inline void getLedGroupPath( 196 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 197 const std::string& objPath, 198 std::function<void(const boost::system::error_code& ec, 199 const std::string& ledGroupPath, 200 const std::string& service)>&& callback) 201 { 202 static constexpr const char* ledObjectPath = 203 "/xyz/openbmc_project/led/groups"; 204 sdbusplus::message::object_path ledGroupAssociatedPath = 205 objPath + "/identifying"; 206 207 dbus::utility::getAssociatedSubTree( 208 ledGroupAssociatedPath, sdbusplus::message::object_path(ledObjectPath), 209 0, ledGroupInterface, 210 [asyncResp, objPath, callback{std::move(callback)}]( 211 const boost::system::error_code& ec, 212 const dbus::utility::MapperGetSubTreeResponse& subtree) { 213 handleLedGroupSubtree(objPath, ec, subtree, callback); 214 }); 215 } 216 217 inline void afterGetLedState( 218 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 219 const boost::system::error_code& ec, bool assert) 220 { 221 if (ec) 222 { 223 if (ec.value() != EBADR) 224 { 225 BMCWEB_LOG_ERROR("DBUS response error for get ledState {}", 226 ec.value()); 227 messages::internalError(asyncResp->res); 228 } 229 return; 230 } 231 232 asyncResp->res.jsonValue["LocationIndicatorActive"] = assert; 233 } 234 235 inline void getLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 236 const boost::system::error_code& ec, 237 const std::string& ledGroupPath, 238 const std::string& service) 239 { 240 if (ec) 241 { 242 if (ec.value() != EBADR) 243 { 244 BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); 245 messages::internalError(asyncResp->res); 246 } 247 return; 248 } 249 250 if (ledGroupPath.empty() || service.empty()) 251 { 252 // No LED group associated, not an error 253 return; 254 } 255 256 sdbusplus::asio::getProperty<bool>( 257 *crow::connections::systemBus, service, ledGroupPath, 258 "xyz.openbmc_project.Led.Group", "Asserted", 259 std::bind_front(afterGetLedState, asyncResp)); 260 } 261 262 /** 263 * @brief Retrieves identify led group properties over dbus 264 * 265 * @param[in] asyncResp Shared pointer for generating response 266 * message. 267 * @param[in] objPath Object path on PIM 268 * 269 * @return None. 270 */ 271 inline void getLocationIndicatorActive( 272 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 273 const std::string& objPath) 274 { 275 BMCWEB_LOG_DEBUG("Get LocationIndicatorActive for {}", objPath); 276 getLedGroupPath(asyncResp, objPath, 277 [asyncResp](const boost::system::error_code& ec, 278 const std::string& ledGroupPath, 279 const std::string& service) { 280 getLedState(asyncResp, ec, ledGroupPath, service); 281 }); 282 } 283 284 inline void setLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 285 bool ledState, const boost::system::error_code& ec, 286 const std::string& ledGroupPath, 287 const std::string& service) 288 { 289 if (ec) 290 { 291 if (ec.value() == EBADR) 292 { 293 messages::propertyUnknown(asyncResp->res, 294 "LocationIndicatorActive"); 295 return; 296 } 297 BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); 298 messages::internalError(asyncResp->res); 299 return; 300 } 301 302 if (ledGroupPath.empty() || service.empty()) 303 { 304 messages::propertyUnknown(asyncResp->res, "LocationIndicatorActive"); 305 return; 306 } 307 308 setDbusProperty(asyncResp, "LocationIndicatorActive", service, ledGroupPath, 309 "xyz.openbmc_project.Led.Group", "Asserted", ledState); 310 } 311 312 /** 313 * @brief Sets identify led group properties 314 * 315 * @param[in] asyncResp Shared pointer for generating response 316 * message. 317 * @param[in] objPath Object path on PIM 318 * @param[in] ledState LED state passed from request 319 * 320 * @return None. 321 */ 322 inline void setLocationIndicatorActive( 323 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 324 const std::string& objPath, bool ledState) 325 { 326 BMCWEB_LOG_DEBUG("Set LocationIndicatorActive for {}", objPath); 327 getLedGroupPath( 328 asyncResp, objPath, 329 [asyncResp, ledState](const boost::system::error_code& ec, 330 const std::string& ledGroupPath, 331 const std::string& service) { 332 setLedState(asyncResp, ledState, ec, ledGroupPath, service); 333 }); 334 } 335 336 } // namespace redfish 337