| // SPDX-License-Identifier: Apache-2.0 |
| // SPDX-FileCopyrightText: Copyright OpenBMC Authors |
| // SPDX-FileCopyrightText: Copyright 2019 Intel Corporation |
| #pragma once |
| |
| #include "async_resp.hpp" |
| #include "dbus_singleton.hpp" |
| #include "dbus_utility.hpp" |
| #include "error_messages.hpp" |
| #include "generated/enums/chassis.hpp" |
| #include "logging.hpp" |
| #include "utils/dbus_utils.hpp" |
| |
| #include <asm-generic/errno.h> |
| |
| #include <boost/system/error_code.hpp> |
| #include <sdbusplus/asio/property.hpp> |
| #include <sdbusplus/message/native_types.hpp> |
| |
| #include <array> |
| #include <functional> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <utility> |
| |
| namespace redfish |
| { |
| static constexpr std::array<std::string_view, 1> ledGroupInterface = { |
| "xyz.openbmc_project.Led.Group"}; |
| /** |
| * @brief Retrieves identify led group properties over dbus |
| * |
| * @param[in] asyncResp Shared pointer for generating response message. |
| * |
| * @return None. |
| */ |
| // TODO (Gunnar): Remove IndicatorLED after enough time has passed |
| inline void getIndicatorLedState( |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| BMCWEB_LOG_DEBUG("Get led groups"); |
| dbus::utility::getProperty<bool>( |
| "xyz.openbmc_project.LED.GroupManager", |
| "/xyz/openbmc_project/led/groups/enclosure_identify_blink", |
| "xyz.openbmc_project.Led.Group", "Asserted", |
| [asyncResp](const boost::system::error_code& ec, const bool blinking) { |
| // Some systems may not have enclosure_identify_blink object so |
| // proceed to get enclosure_identify state. |
| if (ec == boost::system::errc::invalid_argument) |
| { |
| BMCWEB_LOG_DEBUG( |
| "Get identity blinking LED failed, mismatch in property type"); |
| messages::internalError(asyncResp->res); |
| return; |
| } |
| |
| // Blinking ON, no need to check enclosure_identify assert. |
| if (!ec && blinking) |
| { |
| asyncResp->res.jsonValue["IndicatorLED"] = |
| chassis::IndicatorLED::Blinking; |
| return; |
| } |
| |
| dbus::utility::getProperty<bool>( |
| "xyz.openbmc_project.LED.GroupManager", |
| "/xyz/openbmc_project/led/groups/enclosure_identify", |
| "xyz.openbmc_project.Led.Group", "Asserted", |
| [asyncResp](const boost::system::error_code& ec2, |
| const bool ledOn) { |
| if (ec2 == boost::system::errc::invalid_argument) |
| { |
| BMCWEB_LOG_DEBUG( |
| "Get enclosure identity led failed, mismatch in property type"); |
| messages::internalError(asyncResp->res); |
| return; |
| } |
| |
| if (ec2) |
| { |
| return; |
| } |
| |
| if (ledOn) |
| { |
| asyncResp->res.jsonValue["IndicatorLED"] = |
| chassis::IndicatorLED::Lit; |
| } |
| else |
| { |
| asyncResp->res.jsonValue["IndicatorLED"] = |
| chassis::IndicatorLED::Off; |
| } |
| }); |
| }); |
| } |
| |
| /** |
| * @brief Sets identify led group properties |
| * |
| * @param[in] asyncResp Shared pointer for generating response message. |
| * @param[in] ledState LED state passed from request |
| * |
| * @return None. |
| */ |
| // TODO (Gunnar): Remove IndicatorLED after enough time has passed |
| inline void setIndicatorLedState( |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& ledState) |
| { |
| BMCWEB_LOG_DEBUG("Set led groups"); |
| bool ledOn = false; |
| bool ledBlinkng = false; |
| |
| if (ledState == "Lit") |
| { |
| ledOn = true; |
| } |
| else if (ledState == "Blinking") |
| { |
| ledBlinkng = true; |
| } |
| else if (ledState != "Off") |
| { |
| messages::propertyValueNotInList(asyncResp->res, ledState, |
| "IndicatorLED"); |
| return; |
| } |
| |
| sdbusplus::asio::setProperty( |
| *crow::connections::systemBus, "xyz.openbmc_project.LED.GroupManager", |
| "/xyz/openbmc_project/led/groups/enclosure_identify_blink", |
| "xyz.openbmc_project.Led.Group", "Asserted", ledBlinkng, |
| [asyncResp, ledOn, |
| ledBlinkng](const boost::system::error_code& ec) mutable { |
| if (ec) |
| { |
| // Some systems may not have enclosure_identify_blink object so |
| // Lets set enclosure_identify state to true if Blinking is |
| // true. |
| if (ledBlinkng) |
| { |
| ledOn = true; |
| } |
| } |
| setDbusProperty( |
| asyncResp, "IndicatorLED", |
| "xyz.openbmc_project.LED.GroupManager", |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/led/groups/enclosure_identify"), |
| "xyz.openbmc_project.Led.Group", "Asserted", ledBlinkng); |
| }); |
| } |
| |
| /** |
| * @brief Retrieves identify system led group properties over dbus |
| * |
| * @param[in] asyncResp Shared pointer for generating response message. |
| * |
| * @return None. |
| */ |
| inline void getSystemLocationIndicatorActive( |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| BMCWEB_LOG_DEBUG("Get LocationIndicatorActive"); |
| dbus::utility::getProperty<bool>( |
| "xyz.openbmc_project.LED.GroupManager", |
| "/xyz/openbmc_project/led/groups/enclosure_identify_blink", |
| "xyz.openbmc_project.Led.Group", "Asserted", |
| [asyncResp](const boost::system::error_code& ec, const bool blinking) { |
| // Some systems may not have enclosure_identify_blink object so |
| // proceed to get enclosure_identify state. |
| if (ec == boost::system::errc::invalid_argument) |
| { |
| BMCWEB_LOG_DEBUG( |
| "Get identity blinking LED failed, mismatch in property type"); |
| messages::internalError(asyncResp->res); |
| return; |
| } |
| |
| // Blinking ON, no need to check enclosure_identify assert. |
| if (!ec && blinking) |
| { |
| asyncResp->res.jsonValue["LocationIndicatorActive"] = true; |
| return; |
| } |
| |
| dbus::utility::getProperty<bool>( |
| "xyz.openbmc_project.LED.GroupManager", |
| "/xyz/openbmc_project/led/groups/enclosure_identify", |
| "xyz.openbmc_project.Led.Group", "Asserted", |
| [asyncResp](const boost::system::error_code& ec2, |
| const bool ledOn) { |
| if (ec2 == boost::system::errc::invalid_argument) |
| { |
| BMCWEB_LOG_DEBUG( |
| "Get enclosure identity led failed, mismatch in property type"); |
| messages::internalError(asyncResp->res); |
| return; |
| } |
| |
| if (ec2) |
| { |
| return; |
| } |
| |
| asyncResp->res.jsonValue["LocationIndicatorActive"] = ledOn; |
| }); |
| }); |
| } |
| |
| /** |
| * @brief Sets identify system led group properties |
| * |
| * @param[in] asyncResp Shared pointer for generating response message. |
| * @param[in] ledState LED state passed from request |
| * |
| * @return None. |
| */ |
| inline void setSystemLocationIndicatorActive( |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const bool ledState) |
| { |
| BMCWEB_LOG_DEBUG("Set LocationIndicatorActive"); |
| |
| sdbusplus::asio::setProperty( |
| *crow::connections::systemBus, "xyz.openbmc_project.LED.GroupManager", |
| "/xyz/openbmc_project/led/groups/enclosure_identify_blink", |
| "xyz.openbmc_project.Led.Group", "Asserted", ledState, |
| [asyncResp, ledState](const boost::system::error_code& ec) { |
| if (ec) |
| { |
| // Some systems may not have enclosure_identify_blink object so |
| // lets set enclosure_identify state also if |
| // enclosure_identify_blink failed |
| setDbusProperty( |
| asyncResp, "LocationIndicatorActive", |
| "xyz.openbmc_project.LED.GroupManager", |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/led/groups/enclosure_identify"), |
| "xyz.openbmc_project.Led.Group", "Asserted", ledState); |
| } |
| }); |
| } |
| |
| inline void handleLedGroupSubtree( |
| const std::string& objPath, const boost::system::error_code& ec, |
| const dbus::utility::MapperGetSubTreeResponse& subtree, |
| const std::function<void(const boost::system::error_code& ec, |
| const std::string& ledGroupPath, |
| const std::string& service)>& callback) |
| { |
| if (ec) |
| { |
| // Callback will handle the error |
| callback(ec, "", ""); |
| return; |
| } |
| |
| if (subtree.empty()) |
| { |
| // Callback will handle the error |
| BMCWEB_LOG_DEBUG( |
| "No LED group associated with the specified object path: {}", |
| objPath); |
| callback(ec, "", ""); |
| return; |
| } |
| |
| if (subtree.size() > 1) |
| { |
| // Callback will handle the error |
| BMCWEB_LOG_DEBUG( |
| "More than one LED group associated with the object {}: {}", |
| objPath, subtree.size()); |
| callback(ec, "", ""); |
| return; |
| } |
| |
| const auto& [ledGroupPath, serviceMap] = *subtree.begin(); |
| const auto& [service, interfaces] = *serviceMap.begin(); |
| callback(ec, ledGroupPath, service); |
| } |
| |
| inline void getLedGroupPath( |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& objPath, |
| std::function<void(const boost::system::error_code& ec, |
| const std::string& ledGroupPath, |
| const std::string& service)>&& callback) |
| { |
| static constexpr const char* ledObjectPath = |
| "/xyz/openbmc_project/led/groups"; |
| sdbusplus::message::object_path ledGroupAssociatedPath = |
| objPath + "/identifying"; |
| |
| dbus::utility::getAssociatedSubTree( |
| ledGroupAssociatedPath, sdbusplus::message::object_path(ledObjectPath), |
| 0, ledGroupInterface, |
| [asyncResp, objPath, callback{std::move(callback)}]( |
| const boost::system::error_code& ec, |
| const dbus::utility::MapperGetSubTreeResponse& subtree) { |
| handleLedGroupSubtree(objPath, ec, subtree, callback); |
| }); |
| } |
| |
| inline void afterGetLedState( |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const boost::system::error_code& ec, bool assert) |
| { |
| if (ec) |
| { |
| if (ec.value() != EBADR) |
| { |
| BMCWEB_LOG_ERROR("DBUS response error for get ledState {}", |
| ec.value()); |
| messages::internalError(asyncResp->res); |
| } |
| return; |
| } |
| |
| asyncResp->res.jsonValue["LocationIndicatorActive"] = assert; |
| } |
| |
| inline void getLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const boost::system::error_code& ec, |
| const std::string& ledGroupPath, |
| const std::string& service) |
| { |
| if (ec) |
| { |
| if (ec.value() != EBADR) |
| { |
| BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); |
| messages::internalError(asyncResp->res); |
| } |
| return; |
| } |
| |
| if (ledGroupPath.empty() || service.empty()) |
| { |
| // No LED group associated, not an error |
| return; |
| } |
| |
| sdbusplus::asio::getProperty<bool>( |
| *crow::connections::systemBus, service, ledGroupPath, |
| "xyz.openbmc_project.Led.Group", "Asserted", |
| std::bind_front(afterGetLedState, asyncResp)); |
| } |
| |
| /** |
| * @brief Retrieves identify led group properties over dbus |
| * |
| * @param[in] asyncResp Shared pointer for generating response |
| * message. |
| * @param[in] objPath Object path on PIM |
| * |
| * @return None. |
| */ |
| inline void getLocationIndicatorActive( |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& objPath) |
| { |
| BMCWEB_LOG_DEBUG("Get LocationIndicatorActive for {}", objPath); |
| getLedGroupPath(asyncResp, objPath, |
| [asyncResp](const boost::system::error_code& ec, |
| const std::string& ledGroupPath, |
| const std::string& service) { |
| getLedState(asyncResp, ec, ledGroupPath, service); |
| }); |
| } |
| |
| inline void setLedState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| bool ledState, const boost::system::error_code& ec, |
| const std::string& ledGroupPath, |
| const std::string& service) |
| { |
| if (ec) |
| { |
| if (ec.value() == EBADR) |
| { |
| messages::propertyUnknown(asyncResp->res, |
| "LocationIndicatorActive"); |
| return; |
| } |
| BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); |
| messages::internalError(asyncResp->res); |
| return; |
| } |
| |
| if (ledGroupPath.empty() || service.empty()) |
| { |
| messages::propertyUnknown(asyncResp->res, "LocationIndicatorActive"); |
| return; |
| } |
| |
| setDbusProperty(asyncResp, "LocationIndicatorActive", service, ledGroupPath, |
| "xyz.openbmc_project.Led.Group", "Asserted", ledState); |
| } |
| |
| /** |
| * @brief Sets identify led group properties |
| * |
| * @param[in] asyncResp Shared pointer for generating response |
| * message. |
| * @param[in] objPath Object path on PIM |
| * @param[in] ledState LED state passed from request |
| * |
| * @return None. |
| */ |
| inline void setLocationIndicatorActive( |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& objPath, bool ledState) |
| { |
| BMCWEB_LOG_DEBUG("Set LocationIndicatorActive for {}", objPath); |
| getLedGroupPath( |
| asyncResp, objPath, |
| [asyncResp, ledState](const boost::system::error_code& ec, |
| const std::string& ledGroupPath, |
| const std::string& service) { |
| setLedState(asyncResp, ledState, ec, ledGroupPath, service); |
| }); |
| } |
| |
| } // namespace redfish |