summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDeepak Kodihalli <dkodihal@in.ibm.com>2018-01-24 04:57:10 -0600
committerDeepak Kodihalli <dkodihal@in.ibm.com>2018-02-01 02:47:19 -0600
commitb1e8fba50af2310136c6f92ab8765bf27aa5cec2 (patch)
tree88214f05a4d760c52381fc68f430a5ad38672af6
parentee717d71a2f294a8de5d1e17c9106b65af59d310 (diff)
downloadphosphor-host-ipmid-b1e8fba50af2310136c6f92ab8765bf27aa5cec2.tar.gz
phosphor-host-ipmid-b1e8fba50af2310136c6f92ab8765bf27aa5cec2.zip
dcmi: get temperature readings: read temp sensors
This commit adds the code to read temperatures from various sensors. A JSON config file tells what D-Bus object(s) to look up for a specific temperature reading. Resolves openbmc/openbmc#2626 Change-Id: Ic357ec2a53ff250a2517d68defe5850ef353568a Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
-rw-r--r--dcmihandler.cpp172
-rw-r--r--dcmihandler.hpp25
2 files changed, 192 insertions, 5 deletions
diff --git a/dcmihandler.cpp b/dcmihandler.cpp
index e5a5384..8b47845 100644
--- a/dcmihandler.cpp
+++ b/dcmihandler.cpp
@@ -9,7 +9,7 @@
#include <stdint.h>
#include <fstream>
#include <bitset>
-#include "nlohmann/json.hpp"
+#include <cmath>
#include "xyz/openbmc_project/Common/error.hpp"
using namespace phosphor::logging;
@@ -736,18 +736,180 @@ namespace dcmi
namespace temp_readings
{
+Json parseConfig()
+{
+ std::ifstream jsonFile(configFile);
+ if (!jsonFile.is_open())
+ {
+ log<level::ERR>("Temperature readings JSON file not found");
+ elog<InternalFailure>();
+ }
+
+ auto data = Json::parse(jsonFile, nullptr, false);
+ if (data.is_discarded())
+ {
+ log<level::ERR>("Temperature readings JSON parser failure");
+ elog<InternalFailure>();
+ }
+
+ return data;
+}
+
+Temperature readTemp(const std::string& dbusService,
+ const std::string& dbusPath)
+{
+ // Read the temperature value from d-bus object. Need some conversion.
+ // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
+ // is an int64_t and in degrees C. It needs to be scaled by using the
+ // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
+ // with a separate single bit for the sign.
+
+ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
+ auto result = ipmi::getAllDbusProperties(bus, dbusService, dbusPath,
+ "xyz.openbmc_project.Sensor.Value");
+ auto temperature = result.at("Value").get<int64_t>();
+ uint64_t absTemp = std::abs(temperature);
+
+ auto factor = result.at("Scale").get<int64_t>();
+ uint64_t scale = std::pow(10, factor); // pow() returns float/double
+ unsigned long long tempDegrees = 0;
+ // Overflow safe multiplication when the scale is > 0
+ if (scale && __builtin_umulll_overflow(
+ absTemp, scale, &tempDegrees))
+ {
+ log<level::ERR>("Multiplication overflow detected",
+ entry("TEMP_VALUE=%llu", absTemp),
+ entry("SCALE_FACTOR=%llu", scale));
+ elog<InternalFailure>();
+ }
+ else
+ {
+ // The (uint64_t)scale value is 0, effectively this is division
+ tempDegrees = absTemp * std::pow(10, factor);
+ }
+ // Max absolute temp as per ipmi spec is 128.
+ if (tempDegrees > maxTemp)
+ {
+ tempDegrees = maxTemp;
+ }
+
+ return std::make_tuple(static_cast<uint8_t>(tempDegrees),
+ (temperature < 0));
+}
+
std::tuple<Response, NumInstances> read(const std::string& type,
uint8_t instance)
{
- Response empty{};
- return std::make_tuple(empty, 0);
+ Response response{};
+ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
+
+ if (!instance)
+ {
+ log<level::ERR>("Expected non-zero instance");
+ elog<InternalFailure>();
+ }
+
+ auto data = parseConfig();
+ static const std::vector<Json> empty{};
+ std::vector<Json> readings = data.value(type, empty);
+ size_t numInstances = readings.size();
+ for (const auto& j : readings)
+ {
+ uint8_t instanceNum = j.value("instance", 0);
+ // Not the instance we're interested in
+ if (instanceNum != instance)
+ {
+ continue;
+ }
+
+ std::string path = j.value("dbus", "");
+ std::string service;
+ try
+ {
+ service =
+ ipmi::getService(bus,
+ "xyz.openbmc_project.Sensor.Value",
+ path);
+ }
+ catch (std::exception& e)
+ {
+ log<level::DEBUG>(e.what());
+ return std::make_tuple(response, numInstances);
+ }
+
+ response.instance = instance;
+ uint8_t temp{};
+ bool sign{};
+ std::tie(temp, sign) = readTemp(service, path);
+ response.temperature = temp;
+ response.sign = sign;
+
+ // Found the instance we're interested in
+ break;
+ }
+
+ if (numInstances > maxInstances)
+ {
+ numInstances = maxInstances;
+ }
+ return std::make_tuple(response, numInstances);
}
std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
uint8_t instanceStart)
{
- ResponseList empty{};
- return std::make_tuple(empty, 0);
+ ResponseList response{};
+ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
+
+ size_t numInstances = 0;
+ auto data = parseConfig();
+ static const std::vector<Json> empty{};
+ std::vector<Json> readings = data.value(type, empty);
+ numInstances = readings.size();
+ for (const auto& j : readings)
+ {
+ try
+ {
+ // Max of 8 response data sets
+ if (response.size() == maxDataSets)
+ {
+ break;
+ }
+
+ uint8_t instanceNum = j.value("instance", 0);
+ // Not in the instance range we're interested in
+ if (instanceNum < instanceStart)
+ {
+ continue;
+ }
+
+ std::string path = j.value("dbus", "");
+ auto service =
+ ipmi::getService(bus,
+ "xyz.openbmc_project.Sensor.Value",
+ path);
+
+ Response r{};
+ r.instance = instanceNum;
+ uint8_t temp{};
+ bool sign{};
+ std::tie(temp, sign) = readTemp(service, path);
+ r.temperature = temp;
+ r.sign = sign;
+ response.push_back(r);
+ }
+ catch (std::exception& e)
+ {
+ log<level::DEBUG>(e.what());
+ continue;
+ }
+ }
+
+ if (numInstances > maxInstances)
+ {
+ numInstances = maxInstances;
+ }
+ return std::make_tuple(response, numInstances);
}
} // namsespace temp_readings
diff --git a/dcmihandler.hpp b/dcmihandler.hpp
index a7cfe8a..e23c8da 100644
--- a/dcmihandler.hpp
+++ b/dcmihandler.hpp
@@ -5,6 +5,7 @@
#include <string>
#include <vector>
#include <sdbusplus/bus.hpp>
+#include "nlohmann/json.hpp"
namespace dcmi
{
@@ -50,6 +51,8 @@ namespace temp_readings
static constexpr auto maxDataSets = 8;
static constexpr auto maxInstances = 255;
static constexpr auto maxTemp = 128; // degrees C
+ static constexpr auto configFile =
+ "/usr/share/ipmi-providers/dcmi_temp_readings.json";
/** @struct Response
*
@@ -70,6 +73,10 @@ namespace temp_readings
using ResponseList = std::vector<Response>;
using NumInstances = size_t;
+ using Value = uint8_t;
+ using Sign = bool;
+ using Temperature = std::tuple<Value, Sign>;
+ using Json = nlohmann::json;
}
static constexpr auto groupExtId = 0xDC;
@@ -375,6 +382,24 @@ struct GetTempReadingsResponseHdr
namespace temp_readings
{
+ /** @brief Read temperature from a d-bus object, scale it as per dcmi
+ * get temperature reading requirements.
+ *
+ * @param[in] dbusService - the D-Bus service
+ * @param[in] dbusPath - the D-Bus path
+ *
+ * @return A temperature reading
+ */
+ Temperature readTemp(const std::string& dbusService,
+ const std::string& dbusPath);
+
+ /** @brief Parse out JSON config file containing information
+ * related to temperature readings.
+ *
+ * @return A json object
+ */
+ Json parseConfig();
+
/** @brief Read temperatures and fill up DCMI response for the Get
* Temperature Readings command. This looks at a specific
* instance.
OpenPOWER on IntegriCloud