| #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_ |