| #ifndef THIRD_PARTY_GBMCWEB_REDFISH_CORE_LIB_CONTROL_H_ |
| #define THIRD_PARTY_GBMCWEB_REDFISH_CORE_LIB_CONTROL_H_ |
| |
| #include <array> |
| #include <cstdint> |
| #include <functional> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <string_view> |
| #include <variant> |
| |
| #include "absl/functional/any_invocable.h" // IWYU pragma: keep |
| #include "absl/strings/str_cat.h" |
| #include "app.hpp" |
| #include "http_request.hpp" |
| #include "logging.hpp" |
| #include "utility.hpp" |
| #include "async_resp.hpp" |
| #include "dbus_utility.hpp" |
| #include "error_messages.hpp" |
| #include "query.hpp" |
| #include "registries/privilege_registry.hpp" |
| #include "collection.hpp" |
| #include "json_utils.hpp" |
| #include <nlohmann/json.hpp> |
| #include "managed_store.hpp" |
| #include "managed_store_types.hpp" |
| |
| namespace redfish { |
| |
| inline void getControlCollection( |
| App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& chassisId) { |
| if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { |
| return; |
| } |
| asyncResp->res.jsonValue["@odata.type"] = |
| "#ControlCollection.v1_0_0.ControlCollection"; |
| boost::urls::url collectionUrl = crow::utility::urlFromPieces( |
| "redfish", "v1", "Chassis", chassisId, "Controls"); |
| asyncResp->res.jsonValue["@odata.id"] = collectionUrl; |
| asyncResp->res.jsonValue["Name"] = "Control Collection"; |
| |
| asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); |
| asyncResp->res.jsonValue["Members@odata.count"] = 0; |
| constexpr std::array<std::string_view, 1> interfaces = { |
| "xyz.openbmc_project.Chassis.Control"}; |
| std::string subtreePath = |
| absl::StrCat("/xyz/openbmc_project/control/", chassisId); |
| collection_util::getCollectionMembers(asyncResp, collectionUrl, interfaces, |
| subtreePath.c_str()); |
| } |
| |
| inline void populateControlProperties( |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& chassisId, const std::string& controlId, |
| const boost::system::error_code& ec, |
| const dbus::utility::DBusPropertiesMap& properties) { |
| if (ec) { |
| messages::internalError(asyncResp->res); |
| return; |
| } |
| |
| asyncResp->res.jsonValue["@odata.type"] = "#Control.v1_5_1.Control"; |
| asyncResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( |
| "redfish", "v1", "Chassis", chassisId, "Controls", controlId); |
| asyncResp->res.jsonValue["Id"] = controlId; |
| asyncResp->res.jsonValue["Name"] = |
| absl::StrCat("Chassis Control ", controlId); |
| |
| uint32_t currentSetPoint = 0; |
| for (const auto& [propName, propValue] : properties) { |
| if (propName == "SetPoint") { |
| const uint32_t* value = std::get_if<uint32_t>(&propValue); |
| if (value != nullptr) { |
| currentSetPoint = *value; |
| } |
| } else if (propName == "SetPointUnits") { |
| const std::string* value = std::get_if<std::string>(&propValue); |
| if (value != nullptr) { |
| asyncResp->res.jsonValue["SetPointUnits"] = *value; |
| } |
| } else if (propName == "ControlType") { |
| const std::string* value = std::get_if<std::string>(&propValue); |
| if (value != nullptr) { |
| asyncResp->res.jsonValue["ControlType"] = *value; |
| } |
| } else if (propName == "PhysicalContext") { |
| const std::string* value = std::get_if<std::string>(&propValue); |
| if (value != nullptr) { |
| asyncResp->res.jsonValue["PhysicalContext"] = *value; |
| } |
| } |
| } |
| |
| if (currentSetPoint == 0) { |
| asyncResp->res.jsonValue["ControlMode"] = "Disabled"; |
| asyncResp->res.jsonValue.erase("SetPointUnits"); |
| } else { |
| asyncResp->res.jsonValue["ControlMode"] = "Manual"; |
| asyncResp->res.jsonValue["SetPoint"] = currentSetPoint; |
| } |
| } |
| |
| inline void handleControlObject( |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& chassisId, const std::string& controlId, |
| const std::string& objectPath, |
| const managedStore::ManagedObjectStoreContext& requestContext, |
| const boost::system::error_code& ec, |
| const dbus::utility::MapperGetObject& object) { |
| if (ec || object.empty()) { |
| messages::resourceNotFound(asyncResp->res, "Control", controlId); |
| return; |
| } |
| const std::string& serviceName = object.begin()->first; |
| managedStore::GetManagedObjectStore()->getAllProperties( |
| serviceName, objectPath, "xyz.openbmc_project.Chassis.Control", |
| requestContext, |
| std::bind_front(populateControlProperties, asyncResp, chassisId, |
| controlId)); |
| } |
| |
| inline void getControlConfiguration( |
| App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& chassisId, const std::string& controlId) { |
| if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { |
| return; |
| } |
| |
| std::string objectPath = |
| absl::StrCat("/xyz/openbmc_project/control/", chassisId, "/", controlId); |
| constexpr std::array<std::string_view, 1> interfaces = { |
| "xyz.openbmc_project.Chassis.Control"}; |
| managedStore::ManagedObjectStoreContext requestContext(asyncResp); |
| |
| managedStore::GetManagedObjectStore()->getDbusObject( |
| objectPath, interfaces, requestContext, |
| std::bind_front(handleControlObject, asyncResp, chassisId, controlId, |
| objectPath, requestContext)); |
| } |
| |
| inline void handlePatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& controlId, |
| const std::string& objectPath, uint32_t setPointValue, |
| const boost::system::error_code& ec, |
| const dbus::utility::MapperGetObject& object) { |
| if (ec) { |
| BMCWEB_LOG_ERROR << "Failed to get SetPoint property: " << ec; |
| messages::internalError(asyncResp->res); |
| return; |
| } |
| |
| if (object.empty()) { |
| messages::resourceNotFound(asyncResp->res, "Control", controlId); |
| return; |
| } |
| |
| const std::string& serviceName = object.begin()->first; |
| const std::string interface = "org.freedesktop.DBus.Properties"; |
| const std::string method = "Set"; |
| const std::string controlInterface = "xyz.openbmc_project.Chassis.Control"; |
| const std::string propertyName = "SetPoint"; |
| |
| managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( |
| asyncResp->strand_, |
| absl::AnyInvocable<void(const boost::system::error_code&)>( |
| [asyncResp](const boost::system::error_code& ec) { |
| if (ec) { |
| BMCWEB_LOG_ERROR << "Failed to set SetPoint property: " << ec; |
| messages::internalError(asyncResp->res); |
| return; |
| } |
| messages::success(asyncResp->res); |
| }), |
| serviceName, objectPath, interface, method, controlInterface, |
| propertyName, dbus::utility::DbusVariantType(setPointValue)); |
| } |
| |
| inline void patchControlConfiguration( |
| App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& chassisId, const std::string& controlId) { |
| if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { |
| return; |
| } |
| |
| std::optional<uint32_t> setPoint; |
| if (!json_util::readJsonPatch(req, asyncResp->res, "SetPoint", setPoint)) { |
| return; |
| } |
| |
| std::string objectPath = |
| absl::StrCat("/xyz/openbmc_project/control/", chassisId, "/", controlId); |
| constexpr std::array<std::string_view, 1> interfaces = { |
| "xyz.openbmc_project.Chassis.Control"}; |
| |
| managedStore::ManagedObjectStoreContext requestContext(asyncResp); |
| |
| managedStore::GetManagedObjectStore()->getDbusObject( |
| objectPath, interfaces, requestContext, |
| std::bind_front(handlePatch, asyncResp, controlId, objectPath, |
| *setPoint)); |
| } |
| |
| inline void requestRoutesControl(App& app) { |
| BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Controls/") |
| .privileges(redfish::privileges::getControlCollection) |
| .methods(boost::beast::http::verb::get)( |
| std::bind_front(getControlCollection, std::ref(app))); |
| BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Controls/<str>/") |
| .privileges(redfish::privileges::getControl) |
| .methods(boost::beast::http::verb::get)( |
| std::bind_front(getControlConfiguration, std::ref(app))); |
| BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Controls/<str>/") |
| .privileges(redfish::privileges::patchControl) |
| .methods(boost::beast::http::verb::patch)( |
| std::bind_front(patchControlConfiguration, std::ref(app))); |
| } |
| |
| } // namespace redfish |
| |
| #endif // THIRD_PARTY_GBMCWEB_REDFISH_CORE_LIB_CONTROL_H_ |