1*08777fb0SLewanczyk, Dawid /* 2*08777fb0SLewanczyk, Dawid // Copyright (c) 2018 Intel Corporation 3*08777fb0SLewanczyk, Dawid // 4*08777fb0SLewanczyk, Dawid // Licensed under the Apache License, Version 2.0 (the "License"); 5*08777fb0SLewanczyk, Dawid // you may not use this file except in compliance with the License. 6*08777fb0SLewanczyk, Dawid // You may obtain a copy of the License at 7*08777fb0SLewanczyk, Dawid // 8*08777fb0SLewanczyk, Dawid // http://www.apache.org/licenses/LICENSE-2.0 9*08777fb0SLewanczyk, Dawid // 10*08777fb0SLewanczyk, Dawid // Unless required by applicable law or agreed to in writing, software 11*08777fb0SLewanczyk, Dawid // distributed under the License is distributed on an "AS IS" BASIS, 12*08777fb0SLewanczyk, Dawid // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*08777fb0SLewanczyk, Dawid // See the License for the specific language governing permissions and 14*08777fb0SLewanczyk, Dawid // limitations under the License. 15*08777fb0SLewanczyk, Dawid */ 16*08777fb0SLewanczyk, Dawid #pragma once 17*08777fb0SLewanczyk, Dawid 18*08777fb0SLewanczyk, Dawid #include <math.h> 19*08777fb0SLewanczyk, Dawid #include <dbus_singleton.hpp> 20*08777fb0SLewanczyk, Dawid #include <boost/algorithm/string/predicate.hpp> 21*08777fb0SLewanczyk, Dawid #include <boost/algorithm/string/split.hpp> 22*08777fb0SLewanczyk, Dawid #include <boost/container/flat_map.hpp> 23*08777fb0SLewanczyk, Dawid #include <boost/range/algorithm/replace_copy_if.hpp> 24*08777fb0SLewanczyk, Dawid #include <boost/variant.hpp> 25*08777fb0SLewanczyk, Dawid #include <boost/variant/get.hpp> 26*08777fb0SLewanczyk, Dawid 27*08777fb0SLewanczyk, Dawid namespace redfish { 28*08777fb0SLewanczyk, Dawid 29*08777fb0SLewanczyk, Dawid constexpr const char* DBUS_SENSOR_PREFIX = "/xyz/openbmc_project/Sensors/"; 30*08777fb0SLewanczyk, Dawid 31*08777fb0SLewanczyk, Dawid using GetSubTreeType = std::vector< 32*08777fb0SLewanczyk, Dawid std::pair<std::string, 33*08777fb0SLewanczyk, Dawid std::vector<std::pair<std::string, std::vector<std::string>>>>>; 34*08777fb0SLewanczyk, Dawid 35*08777fb0SLewanczyk, Dawid using ManagedObjectsVectorType = std::vector<std::pair< 36*08777fb0SLewanczyk, Dawid dbus::object_path, 37*08777fb0SLewanczyk, Dawid boost::container::flat_map< 38*08777fb0SLewanczyk, Dawid std::string, 39*08777fb0SLewanczyk, Dawid boost::container::flat_map<dbus::string, dbus::dbus_variant>>>>; 40*08777fb0SLewanczyk, Dawid 41*08777fb0SLewanczyk, Dawid /** 42*08777fb0SLewanczyk, Dawid * AsyncResp 43*08777fb0SLewanczyk, Dawid * Gathers data needed for response processing after async calls are done 44*08777fb0SLewanczyk, Dawid */ 45*08777fb0SLewanczyk, Dawid class AsyncResp { 46*08777fb0SLewanczyk, Dawid public: 47*08777fb0SLewanczyk, Dawid AsyncResp(crow::response& response, const std::string& chassisId, 48*08777fb0SLewanczyk, Dawid const std::initializer_list<const char*> types) 49*08777fb0SLewanczyk, Dawid : chassisId(chassisId), res(response), types(types) { 50*08777fb0SLewanczyk, Dawid res.json_value["@odata.id"] = 51*08777fb0SLewanczyk, Dawid "/redfish/v1/Chassis/" + chassisId + "/Thermal"; 52*08777fb0SLewanczyk, Dawid } 53*08777fb0SLewanczyk, Dawid 54*08777fb0SLewanczyk, Dawid ~AsyncResp() { 55*08777fb0SLewanczyk, Dawid if (res.code != static_cast<int>(HttpRespCode::OK)) { 56*08777fb0SLewanczyk, Dawid // Reset the json object to clear out any data that made it in before the 57*08777fb0SLewanczyk, Dawid // error happened 58*08777fb0SLewanczyk, Dawid // todo(ed) handle error condition with proper code 59*08777fb0SLewanczyk, Dawid res.json_value = nlohmann::json::object(); 60*08777fb0SLewanczyk, Dawid } 61*08777fb0SLewanczyk, Dawid res.end(); 62*08777fb0SLewanczyk, Dawid } 63*08777fb0SLewanczyk, Dawid void setErrorStatus() { 64*08777fb0SLewanczyk, Dawid res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR); 65*08777fb0SLewanczyk, Dawid } 66*08777fb0SLewanczyk, Dawid 67*08777fb0SLewanczyk, Dawid std::string chassisId{}; 68*08777fb0SLewanczyk, Dawid crow::response& res; 69*08777fb0SLewanczyk, Dawid const std::vector<const char*> types; 70*08777fb0SLewanczyk, Dawid }; 71*08777fb0SLewanczyk, Dawid 72*08777fb0SLewanczyk, Dawid /** 73*08777fb0SLewanczyk, Dawid * @brief Creates connections necessary for chassis sensors 74*08777fb0SLewanczyk, Dawid * @param asyncResp Pointer to object holding response data 75*08777fb0SLewanczyk, Dawid * @param sensorNames Sensors retrieved from chassis 76*08777fb0SLewanczyk, Dawid * @param callback Callback for processing gathered connections 77*08777fb0SLewanczyk, Dawid */ 78*08777fb0SLewanczyk, Dawid template <typename Callback> 79*08777fb0SLewanczyk, Dawid void getConnections(const std::shared_ptr<AsyncResp>& asyncResp, 80*08777fb0SLewanczyk, Dawid const boost::container::flat_set<std::string>& sensorNames, 81*08777fb0SLewanczyk, Dawid Callback&& callback) { 82*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "getConnections"; 83*08777fb0SLewanczyk, Dawid const std::string path = "/xyz/openbmc_project/Sensors"; 84*08777fb0SLewanczyk, Dawid const std::array<std::string, 1> interfaces = { 85*08777fb0SLewanczyk, Dawid "xyz.openbmc_project.Sensor.Value"}; 86*08777fb0SLewanczyk, Dawid const dbus::endpoint object_mapper( 87*08777fb0SLewanczyk, Dawid "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper", 88*08777fb0SLewanczyk, Dawid "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 89*08777fb0SLewanczyk, Dawid 90*08777fb0SLewanczyk, Dawid // Response handler for parsing objects subtree 91*08777fb0SLewanczyk, Dawid auto resp_handler = [ callback{std::move(callback)}, asyncResp, sensorNames ]( 92*08777fb0SLewanczyk, Dawid const boost::system::error_code ec, const GetSubTreeType& subtree) { 93*08777fb0SLewanczyk, Dawid if (ec != 0) { 94*08777fb0SLewanczyk, Dawid asyncResp->setErrorStatus(); 95*08777fb0SLewanczyk, Dawid CROW_LOG_ERROR << "Dbus error " << ec; 96*08777fb0SLewanczyk, Dawid return; 97*08777fb0SLewanczyk, Dawid } 98*08777fb0SLewanczyk, Dawid 99*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "Found " << subtree.size() << " subtrees"; 100*08777fb0SLewanczyk, Dawid 101*08777fb0SLewanczyk, Dawid // Make unique list of connections only for requested sensor types and 102*08777fb0SLewanczyk, Dawid // found in the chassis 103*08777fb0SLewanczyk, Dawid boost::container::flat_set<std::string> connections; 104*08777fb0SLewanczyk, Dawid // Intrinsic to avoid malloc. Most systems will have < 8 sensor producers 105*08777fb0SLewanczyk, Dawid connections.reserve(8); 106*08777fb0SLewanczyk, Dawid 107*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "sensorNames list cout: " << sensorNames.size(); 108*08777fb0SLewanczyk, Dawid for (const std::string& tsensor : sensorNames) { 109*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "Sensor to find: " << tsensor; 110*08777fb0SLewanczyk, Dawid } 111*08777fb0SLewanczyk, Dawid 112*08777fb0SLewanczyk, Dawid for (const std::pair< 113*08777fb0SLewanczyk, Dawid std::string, 114*08777fb0SLewanczyk, Dawid std::vector<std::pair<std::string, std::vector<std::string>>>>& 115*08777fb0SLewanczyk, Dawid object : subtree) { 116*08777fb0SLewanczyk, Dawid for (const char* type : asyncResp->types) { 117*08777fb0SLewanczyk, Dawid if (boost::starts_with(object.first, type)) { 118*08777fb0SLewanczyk, Dawid auto lastPos = object.first.rfind('/'); 119*08777fb0SLewanczyk, Dawid if (lastPos != std::string::npos) { 120*08777fb0SLewanczyk, Dawid std::string sensorName = object.first.substr(lastPos + 1); 121*08777fb0SLewanczyk, Dawid 122*08777fb0SLewanczyk, Dawid if (sensorNames.find(sensorName) != sensorNames.end()) { 123*08777fb0SLewanczyk, Dawid // For each connection name 124*08777fb0SLewanczyk, Dawid for (const std::pair<std::string, std::vector<std::string>>& 125*08777fb0SLewanczyk, Dawid objData : object.second) { 126*08777fb0SLewanczyk, Dawid connections.insert(objData.first); 127*08777fb0SLewanczyk, Dawid } 128*08777fb0SLewanczyk, Dawid } 129*08777fb0SLewanczyk, Dawid } 130*08777fb0SLewanczyk, Dawid break; 131*08777fb0SLewanczyk, Dawid } 132*08777fb0SLewanczyk, Dawid } 133*08777fb0SLewanczyk, Dawid } 134*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "Found " << connections.size() << " connections"; 135*08777fb0SLewanczyk, Dawid callback(std::move(connections)); 136*08777fb0SLewanczyk, Dawid }; 137*08777fb0SLewanczyk, Dawid 138*08777fb0SLewanczyk, Dawid // Make call to ObjectMapper to find all sensors objects 139*08777fb0SLewanczyk, Dawid crow::connections::system_bus->async_method_call(resp_handler, object_mapper, 140*08777fb0SLewanczyk, Dawid path, 2, interfaces); 141*08777fb0SLewanczyk, Dawid } 142*08777fb0SLewanczyk, Dawid 143*08777fb0SLewanczyk, Dawid /** 144*08777fb0SLewanczyk, Dawid * @brief Retrieves requested chassis sensors and redundancy data from DBus . 145*08777fb0SLewanczyk, Dawid * @param asyncResp Pointer to object holding response data 146*08777fb0SLewanczyk, Dawid * @param callback Callback for next step in gathered sensor processing 147*08777fb0SLewanczyk, Dawid */ 148*08777fb0SLewanczyk, Dawid template <typename Callback> 149*08777fb0SLewanczyk, Dawid void getChassis(const std::shared_ptr<AsyncResp>& asyncResp, 150*08777fb0SLewanczyk, Dawid Callback&& callback) { 151*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "getChassis Done"; 152*08777fb0SLewanczyk, Dawid const dbus::endpoint entityManager = { 153*08777fb0SLewanczyk, Dawid "xyz.openbmc_project.EntityManager", 154*08777fb0SLewanczyk, Dawid "/xyz/openbmc_project/Inventory/Item/Chassis", 155*08777fb0SLewanczyk, Dawid "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"}; 156*08777fb0SLewanczyk, Dawid 157*08777fb0SLewanczyk, Dawid // Process response from EntityManager and extract chassis data 158*08777fb0SLewanczyk, Dawid auto resp_handler = [ callback{std::move(callback)}, asyncResp ]( 159*08777fb0SLewanczyk, Dawid const boost::system::error_code ec, ManagedObjectsVectorType& resp) { 160*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "getChassis resp_handler called back Done"; 161*08777fb0SLewanczyk, Dawid if (ec) { 162*08777fb0SLewanczyk, Dawid CROW_LOG_ERROR << "getChassis resp_handler got error " << ec; 163*08777fb0SLewanczyk, Dawid asyncResp->setErrorStatus(); 164*08777fb0SLewanczyk, Dawid return; 165*08777fb0SLewanczyk, Dawid } 166*08777fb0SLewanczyk, Dawid boost::container::flat_set<std::string> sensorNames; 167*08777fb0SLewanczyk, Dawid const std::string chassis_prefix = 168*08777fb0SLewanczyk, Dawid "/xyz/openbmc_project/Inventory/Item/Chassis/" + asyncResp->chassisId + 169*08777fb0SLewanczyk, Dawid '/'; 170*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "Chassis Prefix " << chassis_prefix; 171*08777fb0SLewanczyk, Dawid bool foundChassis = false; 172*08777fb0SLewanczyk, Dawid for (const auto& objDictEntry : resp) { 173*08777fb0SLewanczyk, Dawid if (boost::starts_with(objDictEntry.first.value, chassis_prefix)) { 174*08777fb0SLewanczyk, Dawid foundChassis = true; 175*08777fb0SLewanczyk, Dawid const std::string sensorName = 176*08777fb0SLewanczyk, Dawid objDictEntry.first.value.substr(chassis_prefix.size()); 177*08777fb0SLewanczyk, Dawid // Make sure this isn't a subobject (like a threshold) 178*08777fb0SLewanczyk, Dawid const std::size_t sensorPos = sensorName.find('/'); 179*08777fb0SLewanczyk, Dawid if (sensorPos == std::string::npos) { 180*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "Adding sensor " << sensorName; 181*08777fb0SLewanczyk, Dawid 182*08777fb0SLewanczyk, Dawid sensorNames.emplace(sensorName); 183*08777fb0SLewanczyk, Dawid } 184*08777fb0SLewanczyk, Dawid } 185*08777fb0SLewanczyk, Dawid }; 186*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "Found " << sensorNames.size() << " Sensor names"; 187*08777fb0SLewanczyk, Dawid 188*08777fb0SLewanczyk, Dawid if (!foundChassis) { 189*08777fb0SLewanczyk, Dawid CROW_LOG_INFO << "Unable to find chassis named " << asyncResp->chassisId; 190*08777fb0SLewanczyk, Dawid asyncResp->res.code = static_cast<int>(HttpRespCode::NOT_FOUND); 191*08777fb0SLewanczyk, Dawid } else { 192*08777fb0SLewanczyk, Dawid callback(sensorNames); 193*08777fb0SLewanczyk, Dawid } 194*08777fb0SLewanczyk, Dawid }; 195*08777fb0SLewanczyk, Dawid 196*08777fb0SLewanczyk, Dawid // Make call to EntityManager to find all chassis objects 197*08777fb0SLewanczyk, Dawid crow::connections::system_bus->async_method_call(resp_handler, entityManager); 198*08777fb0SLewanczyk, Dawid } 199*08777fb0SLewanczyk, Dawid 200*08777fb0SLewanczyk, Dawid /** 201*08777fb0SLewanczyk, Dawid * @brief Builds a json sensor representation of a sensor. 202*08777fb0SLewanczyk, Dawid * @param sensorName The name of the sensor to be built 203*08777fb0SLewanczyk, Dawid * @param sensorType The type (temperature, fan_tach, ect) of the sensor to 204*08777fb0SLewanczyk, Dawid * build 205*08777fb0SLewanczyk, Dawid * @param interfacesDict A dictionary of the interfaces and properties of said 206*08777fb0SLewanczyk, Dawid * interfaces to be built from 207*08777fb0SLewanczyk, Dawid * @param sensor_json The json object to fill 208*08777fb0SLewanczyk, Dawid */ 209*08777fb0SLewanczyk, Dawid void objectInterfacesToJson( 210*08777fb0SLewanczyk, Dawid const std::string& sensorName, const std::string& sensorType, 211*08777fb0SLewanczyk, Dawid const boost::container::flat_map< 212*08777fb0SLewanczyk, Dawid std::string, 213*08777fb0SLewanczyk, Dawid boost::container::flat_map<dbus::string, dbus::dbus_variant>>& 214*08777fb0SLewanczyk, Dawid interfacesDict, 215*08777fb0SLewanczyk, Dawid nlohmann::json& sensor_json) { 216*08777fb0SLewanczyk, Dawid // We need a value interface before we can do anything with it 217*08777fb0SLewanczyk, Dawid auto value_it = interfacesDict.find("xyz.openbmc_project.Sensor.Value"); 218*08777fb0SLewanczyk, Dawid if (value_it == interfacesDict.end()) { 219*08777fb0SLewanczyk, Dawid CROW_LOG_ERROR << "Sensor doesn't have a value interface"; 220*08777fb0SLewanczyk, Dawid return; 221*08777fb0SLewanczyk, Dawid } 222*08777fb0SLewanczyk, Dawid 223*08777fb0SLewanczyk, Dawid // Assume values exist as is (10^0 == 1) if no scale exists 224*08777fb0SLewanczyk, Dawid int64_t scaleMultiplier = 0; 225*08777fb0SLewanczyk, Dawid 226*08777fb0SLewanczyk, Dawid auto scale_it = value_it->second.find("Scale"); 227*08777fb0SLewanczyk, Dawid // If a scale exists, pull value as int64, and use the scaling. 228*08777fb0SLewanczyk, Dawid if (scale_it != value_it->second.end()) { 229*08777fb0SLewanczyk, Dawid const int64_t* int64Value = boost::get<int64_t>(&scale_it->second); 230*08777fb0SLewanczyk, Dawid if (int64Value != nullptr) { 231*08777fb0SLewanczyk, Dawid scaleMultiplier = *int64Value; 232*08777fb0SLewanczyk, Dawid } 233*08777fb0SLewanczyk, Dawid } 234*08777fb0SLewanczyk, Dawid 235*08777fb0SLewanczyk, Dawid sensor_json["MemberId"] = sensorName; 236*08777fb0SLewanczyk, Dawid sensor_json["Name"] = sensorName; 237*08777fb0SLewanczyk, Dawid sensor_json["Status"]["State"] = "Enabled"; 238*08777fb0SLewanczyk, Dawid sensor_json["Status"]["Health"] = "OK"; 239*08777fb0SLewanczyk, Dawid 240*08777fb0SLewanczyk, Dawid // Parameter to set to override the type we get from dbus, and force it to 241*08777fb0SLewanczyk, Dawid // int, regardless of what is available. This is used for schemas like fan, 242*08777fb0SLewanczyk, Dawid // that require integers, not floats. 243*08777fb0SLewanczyk, Dawid bool forceToInt = false; 244*08777fb0SLewanczyk, Dawid 245*08777fb0SLewanczyk, Dawid const char* unit = "Reading"; 246*08777fb0SLewanczyk, Dawid if (sensorType == "temperature") { 247*08777fb0SLewanczyk, Dawid unit = "ReadingCelsius"; 248*08777fb0SLewanczyk, Dawid // TODO(ed) Documentation says that path should be type fan_tach, 249*08777fb0SLewanczyk, Dawid // implementation seems to implement fan 250*08777fb0SLewanczyk, Dawid } else if (sensorType == "fan" || sensorType == "fan_tach") { 251*08777fb0SLewanczyk, Dawid unit = "Reading"; 252*08777fb0SLewanczyk, Dawid sensor_json["ReadingUnits"] = "RPM"; 253*08777fb0SLewanczyk, Dawid forceToInt = true; 254*08777fb0SLewanczyk, Dawid } else if (sensorType == "voltage") { 255*08777fb0SLewanczyk, Dawid unit = "ReadingVolts"; 256*08777fb0SLewanczyk, Dawid } else { 257*08777fb0SLewanczyk, Dawid CROW_LOG_ERROR << "Redfish cannot map object type for " << sensorName; 258*08777fb0SLewanczyk, Dawid return; 259*08777fb0SLewanczyk, Dawid } 260*08777fb0SLewanczyk, Dawid // Map of dbus interface name, dbus property name and redfish property_name 261*08777fb0SLewanczyk, Dawid std::vector<std::tuple<const char*, const char*, const char*>> properties; 262*08777fb0SLewanczyk, Dawid properties.reserve(7); 263*08777fb0SLewanczyk, Dawid 264*08777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit); 265*08777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning", 266*08777fb0SLewanczyk, Dawid "WarningHigh", "UpperThresholdNonCritical"); 267*08777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning", 268*08777fb0SLewanczyk, Dawid "WarningLow", "LowerThresholdNonCritical"); 269*08777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical", 270*08777fb0SLewanczyk, Dawid "CriticalHigh", "UpperThresholdCritical"); 271*08777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical", 272*08777fb0SLewanczyk, Dawid "CriticalLow", "LowerThresholdCritical"); 273*08777fb0SLewanczyk, Dawid 274*08777fb0SLewanczyk, Dawid if (sensorType == "temperature") { 275*08777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue", 276*08777fb0SLewanczyk, Dawid "MinReadingRangeTemp"); 277*08777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue", 278*08777fb0SLewanczyk, Dawid "MaxReadingRangeTemp"); 279*08777fb0SLewanczyk, Dawid } else { 280*08777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue", 281*08777fb0SLewanczyk, Dawid "MinReadingRange"); 282*08777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue", 283*08777fb0SLewanczyk, Dawid "MaxReadingRange"); 284*08777fb0SLewanczyk, Dawid } 285*08777fb0SLewanczyk, Dawid 286*08777fb0SLewanczyk, Dawid for (const std::tuple<const char*, const char*, const char*>& p : 287*08777fb0SLewanczyk, Dawid properties) { 288*08777fb0SLewanczyk, Dawid auto interfaceProperties = interfacesDict.find(std::get<0>(p)); 289*08777fb0SLewanczyk, Dawid if (interfaceProperties != interfacesDict.end()) { 290*08777fb0SLewanczyk, Dawid auto value_it = interfaceProperties->second.find(std::get<1>(p)); 291*08777fb0SLewanczyk, Dawid if (value_it != interfaceProperties->second.end()) { 292*08777fb0SLewanczyk, Dawid const dbus::dbus_variant& valueVariant = value_it->second; 293*08777fb0SLewanczyk, Dawid nlohmann::json& value_it = sensor_json[std::get<2>(p)]; 294*08777fb0SLewanczyk, Dawid // Attempt to pull the int64 directly 295*08777fb0SLewanczyk, Dawid const int64_t* int64Value = boost::get<int64_t>(&valueVariant); 296*08777fb0SLewanczyk, Dawid 297*08777fb0SLewanczyk, Dawid if (int64Value != nullptr) { 298*08777fb0SLewanczyk, Dawid if (forceToInt || scaleMultiplier >= 0) { 299*08777fb0SLewanczyk, Dawid value_it = *int64Value * std::pow(10, scaleMultiplier); 300*08777fb0SLewanczyk, Dawid } else { 301*08777fb0SLewanczyk, Dawid value_it = *int64Value * 302*08777fb0SLewanczyk, Dawid std::pow(10, static_cast<double>(scaleMultiplier)); 303*08777fb0SLewanczyk, Dawid } 304*08777fb0SLewanczyk, Dawid } 305*08777fb0SLewanczyk, Dawid // Attempt to pull the float directly 306*08777fb0SLewanczyk, Dawid const double* doubleValue = boost::get<double>(&valueVariant); 307*08777fb0SLewanczyk, Dawid 308*08777fb0SLewanczyk, Dawid if (doubleValue != nullptr) { 309*08777fb0SLewanczyk, Dawid if (!forceToInt) { 310*08777fb0SLewanczyk, Dawid value_it = *doubleValue * 311*08777fb0SLewanczyk, Dawid std::pow(10, static_cast<double>(scaleMultiplier)); 312*08777fb0SLewanczyk, Dawid } else { 313*08777fb0SLewanczyk, Dawid value_it = static_cast<int64_t>(*doubleValue * 314*08777fb0SLewanczyk, Dawid std::pow(10, scaleMultiplier)); 315*08777fb0SLewanczyk, Dawid } 316*08777fb0SLewanczyk, Dawid } 317*08777fb0SLewanczyk, Dawid } 318*08777fb0SLewanczyk, Dawid } 319*08777fb0SLewanczyk, Dawid } 320*08777fb0SLewanczyk, Dawid } 321*08777fb0SLewanczyk, Dawid 322*08777fb0SLewanczyk, Dawid /** 323*08777fb0SLewanczyk, Dawid * @brief Entry point for retrieving sensors data related to requested 324*08777fb0SLewanczyk, Dawid * chassis. 325*08777fb0SLewanczyk, Dawid * @param asyncResp Pointer to object holding response data 326*08777fb0SLewanczyk, Dawid */ 327*08777fb0SLewanczyk, Dawid void getChassisData(const std::shared_ptr<AsyncResp>& asyncResp) { 328*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "getChassisData"; 329*08777fb0SLewanczyk, Dawid auto getChassisCb = [&, asyncResp](boost::container::flat_set<std::string>& 330*08777fb0SLewanczyk, Dawid sensorNames) { 331*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "getChassisCb Done"; 332*08777fb0SLewanczyk, Dawid auto getConnectionCb = 333*08777fb0SLewanczyk, Dawid [&, asyncResp, sensorNames]( 334*08777fb0SLewanczyk, Dawid const boost::container::flat_set<std::string>& connections) { 335*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "getConnectionCb Done"; 336*08777fb0SLewanczyk, Dawid // Get managed objects from all services exposing sensors 337*08777fb0SLewanczyk, Dawid for (const std::string& connection : connections) { 338*08777fb0SLewanczyk, Dawid // Response handler to process managed objects 339*08777fb0SLewanczyk, Dawid auto getManagedObjectsCb = [&, asyncResp, sensorNames]( 340*08777fb0SLewanczyk, Dawid const boost::system::error_code ec, 341*08777fb0SLewanczyk, Dawid ManagedObjectsVectorType& resp) { 342*08777fb0SLewanczyk, Dawid // Go through all objects and update response with 343*08777fb0SLewanczyk, Dawid // sensor data 344*08777fb0SLewanczyk, Dawid for (const auto& objDictEntry : resp) { 345*08777fb0SLewanczyk, Dawid const std::string& objPath = objDictEntry.first.value; 346*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "getManagedObjectsCb parsing object " 347*08777fb0SLewanczyk, Dawid << objPath; 348*08777fb0SLewanczyk, Dawid if (!boost::starts_with(objPath, DBUS_SENSOR_PREFIX)) { 349*08777fb0SLewanczyk, Dawid CROW_LOG_ERROR << "Got path that isn't in sensor namespace: " 350*08777fb0SLewanczyk, Dawid << objPath; 351*08777fb0SLewanczyk, Dawid continue; 352*08777fb0SLewanczyk, Dawid } 353*08777fb0SLewanczyk, Dawid std::vector<std::string> split; 354*08777fb0SLewanczyk, Dawid // Reserve space for 355*08777fb0SLewanczyk, Dawid // /xyz/openbmc_project/Sensors/<name>/<subname> 356*08777fb0SLewanczyk, Dawid split.reserve(6); 357*08777fb0SLewanczyk, Dawid boost::algorithm::split(split, objPath, boost::is_any_of("/")); 358*08777fb0SLewanczyk, Dawid if (split.size() < 6) { 359*08777fb0SLewanczyk, Dawid CROW_LOG_ERROR << "Got path that isn't long enough " 360*08777fb0SLewanczyk, Dawid << objPath; 361*08777fb0SLewanczyk, Dawid continue; 362*08777fb0SLewanczyk, Dawid } 363*08777fb0SLewanczyk, Dawid // These indexes aren't intuitive, as boost::split puts an empty 364*08777fb0SLewanczyk, Dawid // string at the beggining 365*08777fb0SLewanczyk, Dawid const std::string& sensorType = split[4]; 366*08777fb0SLewanczyk, Dawid const std::string& sensorName = split[5]; 367*08777fb0SLewanczyk, Dawid CROW_LOG_DEBUG << "sensorName " << sensorName << " sensorType " 368*08777fb0SLewanczyk, Dawid << sensorType; 369*08777fb0SLewanczyk, Dawid if (sensorNames.find(sensorName) == sensorNames.end()) { 370*08777fb0SLewanczyk, Dawid CROW_LOG_ERROR << sensorName << " not in sensor list "; 371*08777fb0SLewanczyk, Dawid continue; 372*08777fb0SLewanczyk, Dawid } 373*08777fb0SLewanczyk, Dawid 374*08777fb0SLewanczyk, Dawid const char* fieldName = nullptr; 375*08777fb0SLewanczyk, Dawid if (sensorType == "temperature") { 376*08777fb0SLewanczyk, Dawid fieldName = "Temperatures"; 377*08777fb0SLewanczyk, Dawid } else if (sensorType == "fan" || sensorType == "fan_tach") { 378*08777fb0SLewanczyk, Dawid fieldName = "Fans"; 379*08777fb0SLewanczyk, Dawid } else if (sensorType == "voltage") { 380*08777fb0SLewanczyk, Dawid fieldName = "Voltages"; 381*08777fb0SLewanczyk, Dawid } else if (sensorType == "current") { 382*08777fb0SLewanczyk, Dawid fieldName = "PowerSupply"; 383*08777fb0SLewanczyk, Dawid } else if (sensorType == "power") { 384*08777fb0SLewanczyk, Dawid fieldName = "PowerSupply"; 385*08777fb0SLewanczyk, Dawid } else { 386*08777fb0SLewanczyk, Dawid CROW_LOG_ERROR << "Unsure how to handle sensorType " 387*08777fb0SLewanczyk, Dawid << sensorType; 388*08777fb0SLewanczyk, Dawid continue; 389*08777fb0SLewanczyk, Dawid } 390*08777fb0SLewanczyk, Dawid 391*08777fb0SLewanczyk, Dawid nlohmann::json& temp_array = 392*08777fb0SLewanczyk, Dawid asyncResp->res.json_value[fieldName]; 393*08777fb0SLewanczyk, Dawid 394*08777fb0SLewanczyk, Dawid // Create the array if it doesn't yet exist 395*08777fb0SLewanczyk, Dawid if (temp_array.is_array() == false) { 396*08777fb0SLewanczyk, Dawid temp_array = nlohmann::json::array(); 397*08777fb0SLewanczyk, Dawid } 398*08777fb0SLewanczyk, Dawid 399*08777fb0SLewanczyk, Dawid temp_array.push_back(nlohmann::json::object()); 400*08777fb0SLewanczyk, Dawid nlohmann::json& sensor_json = temp_array.back(); 401*08777fb0SLewanczyk, Dawid sensor_json["@odata.id"] = "/redfish/v1/Chassis/" + 402*08777fb0SLewanczyk, Dawid asyncResp->chassisId + "/Thermal#/" + 403*08777fb0SLewanczyk, Dawid sensorName; 404*08777fb0SLewanczyk, Dawid objectInterfacesToJson(sensorName, sensorType, 405*08777fb0SLewanczyk, Dawid objDictEntry.second, sensor_json); 406*08777fb0SLewanczyk, Dawid } 407*08777fb0SLewanczyk, Dawid }; 408*08777fb0SLewanczyk, Dawid 409*08777fb0SLewanczyk, Dawid dbus::endpoint ep(connection, "/xyz/openbmc_project/Sensors", 410*08777fb0SLewanczyk, Dawid "org.freedesktop.DBus.ObjectManager", 411*08777fb0SLewanczyk, Dawid "GetManagedObjects"); 412*08777fb0SLewanczyk, Dawid crow::connections::system_bus->async_method_call( 413*08777fb0SLewanczyk, Dawid getManagedObjectsCb, ep); 414*08777fb0SLewanczyk, Dawid }; 415*08777fb0SLewanczyk, Dawid }; 416*08777fb0SLewanczyk, Dawid // Get connections and then pass it to get sensors 417*08777fb0SLewanczyk, Dawid getConnections(asyncResp, sensorNames, std::move(getConnectionCb)); 418*08777fb0SLewanczyk, Dawid }; 419*08777fb0SLewanczyk, Dawid 420*08777fb0SLewanczyk, Dawid // Get chassis information related to sensors 421*08777fb0SLewanczyk, Dawid getChassis(asyncResp, std::move(getChassisCb)); 422*08777fb0SLewanczyk, Dawid }; 423*08777fb0SLewanczyk, Dawid 424*08777fb0SLewanczyk, Dawid } // namespace redfish 425