1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // Copyright (c) 2018 Ampere Computing LLC 4 / 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 */ 17 #pragma once 18 19 #include "node.hpp" 20 #include "sensors.hpp" 21 22 namespace redfish 23 { 24 25 class Power : public Node 26 { 27 public: 28 Power(CrowApp& app) : 29 Node((app), "/redfish/v1/Chassis/<str>/Power/", std::string()) 30 { 31 entityPrivileges = { 32 {boost::beast::http::verb::get, {{"Login"}}}, 33 {boost::beast::http::verb::head, {{"Login"}}}, 34 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 35 {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 36 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 37 {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 38 } 39 40 private: 41 std::vector<const char*> typeList = {"/xyz/openbmc_project/sensors/voltage", 42 "/xyz/openbmc_project/sensors/power"}; 43 void doGet(crow::Response& res, const crow::Request& req, 44 const std::vector<std::string>& params) override 45 { 46 if (params.size() != 1) 47 { 48 res.result(boost::beast::http::status::internal_server_error); 49 res.end(); 50 return; 51 } 52 const std::string& chassis_name = params[0]; 53 54 res.jsonValue["PowerControl"] = nlohmann::json::array(); 55 56 auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>( 57 res, chassis_name, typeList, "Power"); 58 59 getChassisData(sensorAsyncResp); 60 61 // This callback verifies that the power limit is only provided for the 62 // chassis that implements the Chassis inventory item. This prevents 63 // things like power supplies providing the chassis power limit 64 auto chassisHandler = [sensorAsyncResp]( 65 const boost::system::error_code e, 66 const std::vector<std::string>& 67 chassisPaths) { 68 if (e) 69 { 70 BMCWEB_LOG_ERROR 71 << "Power Limit GetSubTreePaths handler Dbus error " << e; 72 return; 73 } 74 75 bool found = false; 76 for (const std::string& chassis : chassisPaths) 77 { 78 size_t len = std::string::npos; 79 size_t lastPos = chassis.rfind("/"); 80 if (lastPos == std::string::npos) 81 { 82 continue; 83 } 84 85 if (lastPos == chassis.size() - 1) 86 { 87 size_t end = lastPos; 88 lastPos = chassis.rfind("/", lastPos - 1); 89 if (lastPos == std::string::npos) 90 { 91 continue; 92 } 93 94 len = end - (lastPos + 1); 95 } 96 97 std::string interfaceChassisName = 98 chassis.substr(lastPos + 1, len); 99 if (!interfaceChassisName.compare(sensorAsyncResp->chassisId)) 100 { 101 found = true; 102 break; 103 } 104 } 105 106 if (!found) 107 { 108 BMCWEB_LOG_DEBUG << "Power Limit not present for " 109 << sensorAsyncResp->chassisId; 110 return; 111 } 112 113 auto valueHandler = 114 [sensorAsyncResp]( 115 const boost::system::error_code ec, 116 const std::vector<std::pair<std::string, SensorVariant>>& 117 properties) { 118 if (ec) 119 { 120 messages::internalError(sensorAsyncResp->res); 121 BMCWEB_LOG_ERROR 122 << "Power Limit GetAll handler: Dbus error " << ec; 123 return; 124 } 125 126 nlohmann::json& tempArray = 127 sensorAsyncResp->res.jsonValue["PowerControl"]; 128 129 // Put multiple "sensors" into a single PowerControl, 0, so 130 // only create the first one 131 if (tempArray.empty()) 132 { 133 // Mandatory properties odata.id and MemberId 134 // A warning without a odata.type 135 tempArray.push_back( 136 {{"@odata.type", "#Power.v1_0_0.PowerControl"}, 137 {"@odata.id", "/redfish/v1/Chassis/" + 138 sensorAsyncResp->chassisId + 139 "/Power#/PowerControl/0"}, 140 {"Name", "Chassis Power Control"}, 141 {"MemberId", "0"}}); 142 } 143 144 nlohmann::json& sensorJson = tempArray.back(); 145 bool enabled = false; 146 double powerCap = 0.0; 147 int64_t scale = 0; 148 149 for (const std::pair<std::string, SensorVariant>& property : 150 properties) 151 { 152 if (!property.first.compare("Scale")) 153 { 154 const int64_t* i = 155 sdbusplus::message::variant_ns::get_if<int64_t>( 156 &property.second); 157 158 if (i) 159 { 160 scale = *i; 161 } 162 } 163 else if (!property.first.compare("PowerCap")) 164 { 165 const double* d = 166 sdbusplus::message::variant_ns::get_if<double>( 167 &property.second); 168 const int64_t* i = 169 sdbusplus::message::variant_ns::get_if<int64_t>( 170 &property.second); 171 const uint32_t* u = 172 sdbusplus::message::variant_ns::get_if< 173 uint32_t>(&property.second); 174 175 if (d) 176 { 177 powerCap = *d; 178 } 179 else if (i) 180 { 181 powerCap = static_cast<double>(*i); 182 } 183 else if (u) 184 { 185 powerCap = *u; 186 } 187 } 188 else if (!property.first.compare("PowerCapEnable")) 189 { 190 const bool* b = 191 sdbusplus::message::variant_ns::get_if<bool>( 192 &property.second); 193 194 if (b) 195 { 196 enabled = *b; 197 } 198 } 199 } 200 201 nlohmann::json& value = 202 sensorJson["PowerLimit"]["LimitInWatts"]; 203 204 if (enabled) 205 { 206 // Redfish specification indicates PowerLimit should be 207 // null if the limit is not enabled. 208 value = powerCap * std::pow(10, scale); 209 } 210 }; 211 212 crow::connections::systemBus->async_method_call( 213 std::move(valueHandler), "xyz.openbmc_project.Settings", 214 "/xyz/openbmc_project/control/host0/power_cap", 215 "org.freedesktop.DBus.Properties", "GetAll", 216 "xyz.openbmc_project.Control.Power.Cap"); 217 }; 218 219 crow::connections::systemBus->async_method_call( 220 std::move(chassisHandler), "xyz.openbmc_project.ObjectMapper", 221 "/xyz/openbmc_project/object_mapper", 222 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 223 "/xyz/openbmc_project/inventory", 0, 224 std::array<const char*, 1>{ 225 "xyz.openbmc_project.Inventory.Item.Chassis"}); 226 } 227 void doPatch(crow::Response& res, const crow::Request& req, 228 const std::vector<std::string>& params) override 229 { 230 setSensorOverride(res, req, params, typeList, "Power"); 231 } 232 }; 233 234 } // namespace redfish 235