Adding support for power sensor and average values in CPU domain.
Current implementation of CPUSensor exposes on dbus only temperature sensors.
This change allows it to expose also power values under a new object
path: /xyz/openbmc_project/sensors/power/
It also introduce support for the average values and their thresholds.
Tested:
After applying this change the same CPU sensors and their thresholds
values are visible on dbus.
Plus additional power sensor appears when available in system.
Signed-off-by: Zbigniew Kurzynski <zbigniew.kurzynski@intel.com>
Change-Id: I0eeadca841ccb279bbd26d16b0b41f66a44f22cd
diff --git a/include/Thresholds.hpp b/include/Thresholds.hpp
index 20ce69e..2205c5e 100644
--- a/include/Thresholds.hpp
+++ b/include/Thresholds.hpp
@@ -100,6 +100,11 @@
Sensor* sensor;
};
+// The common scheme for sysfs files naming is: <type><number>_<item>.
+// This function returns optionally these 3 elements as a tuple.
+std::optional<std::tuple<std::string, std::string, std::string>>
+ splitFileName(const std::filesystem::path& filePath);
+
bool parseThresholdsFromConfig(
const SensorData& sensorData,
std::vector<thresholds::Threshold>& thresholdVector,
diff --git a/src/CPUSensor.cpp b/src/CPUSensor.cpp
index d3789fd..241b14f 100644
--- a/src/CPUSensor.cpp
+++ b/src/CPUSensor.cpp
@@ -53,26 +53,39 @@
if (show)
{
- sensorInterface = objectServer.add_interface(
- "/xyz/openbmc_project/sensors/temperature/" + name,
- "xyz.openbmc_project.Sensor.Value");
- if (thresholds::hasWarningInterface(thresholds))
+ if (auto fileParts = thresholds::splitFileName(path))
{
- thresholdInterfaceWarning = objectServer.add_interface(
- "/xyz/openbmc_project/sensors/temperature/" + name,
- "xyz.openbmc_project.Sensor.Threshold.Warning");
- }
- if (thresholds::hasCriticalInterface(thresholds))
- {
- thresholdInterfaceCritical = objectServer.add_interface(
- "/xyz/openbmc_project/sensors/temperature/" + name,
- "xyz.openbmc_project.Sensor.Threshold.Critical");
- }
- association = objectServer.add_interface(
- "/xyz/openbmc_project/sensors/temperature/" + name,
- association::interface);
+ auto [type, nr, item] = *fileParts;
+ std::string interfacePath;
+ if (type.compare("power") == 0)
+ {
+ interfacePath = "/xyz/openbmc_project/sensors/power/" + name;
+ }
+ else
+ {
+ interfacePath =
+ "/xyz/openbmc_project/sensors/temperature/" + name;
+ }
- setInitialProperties(conn);
+ sensorInterface = objectServer.add_interface(
+ interfacePath, "xyz.openbmc_project.Sensor.Value");
+ if (thresholds::hasWarningInterface(thresholds))
+ {
+ thresholdInterfaceWarning = objectServer.add_interface(
+ interfacePath,
+ "xyz.openbmc_project.Sensor.Threshold.Warning");
+ }
+ if (thresholds::hasCriticalInterface(thresholds))
+ {
+ thresholdInterfaceCritical = objectServer.add_interface(
+ interfacePath,
+ "xyz.openbmc_project.Sensor.Threshold.Critical");
+ }
+ association = objectServer.add_interface(interfacePath,
+ association::interface);
+
+ setInitialProperties(conn);
+ }
}
setupPowerMatch(conn);
setupRead();
diff --git a/src/CPUSensorMain.cpp b/src/CPUSensorMain.cpp
index 60820de..15a5a37 100644
--- a/src/CPUSensorMain.cpp
+++ b/src/CPUSensorMain.cpp
@@ -267,7 +267,8 @@
auto directory = hwmonNamePath.parent_path();
std::vector<fs::path> inputPaths;
- if (!findFiles(directory, R"(temp\d+_input$)", inputPaths, 0))
+ if (!findFiles(directory, R"((temp|power)\d+_(input|average)$)",
+ inputPaths, 0))
{
std::cerr << "No temperature sensors in system\n";
continue;
@@ -276,9 +277,15 @@
// iterate through all found temp sensors
for (const auto& inputPath : inputPaths)
{
+ auto fileParts = thresholds::splitFileName(inputPath);
+ if (!fileParts)
+ {
+ continue;
+ }
+ auto [type, nr, item] = *fileParts;
auto inputPathStr = inputPath.string();
auto labelPath =
- boost::replace_all_copy(inputPathStr, "input", "label");
+ boost::replace_all_copy(inputPathStr, item, "label");
std::ifstream labelFile(labelPath);
if (!labelFile.good())
{
diff --git a/src/Thresholds.cpp b/src/Thresholds.cpp
index b5e8685..965b626 100644
--- a/src/Thresholds.cpp
+++ b/src/Thresholds.cpp
@@ -13,6 +13,7 @@
#include <memory>
#include <stdexcept>
#include <string>
+#include <tuple>
#include <utility>
#include <variant>
#include <vector>
@@ -396,68 +397,97 @@
interface->set_property(property, assert);
}
-static constexpr std::array<const char*, 4> attrTypes = {"lcrit", "min", "max",
- "crit"};
+std::optional<double> readFile(const std::string& thresholdFile,
+ const double& scaleFactor)
+{
+ std::string line;
+ std::ifstream labelFile(thresholdFile);
+ if (labelFile.good())
+ {
+ std::getline(labelFile, line);
+ labelFile.close();
+
+ try
+ {
+ return std::stod(line) / scaleFactor;
+ }
+ catch (const std::invalid_argument&)
+ {
+ return std::nullopt;
+ }
+ }
+ return std::nullopt;
+}
+
+std::optional<std::tuple<std::string, std::string, std::string>>
+ splitFileName(const std::filesystem::path& filePath)
+{
+ if (filePath.has_filename())
+ {
+ const auto fileName = filePath.filename().string();
+ const std::regex rx(R"((\w+)(\d+)_(.*))");
+ std::smatch mr;
+
+ if (std::regex_search(fileName, mr, rx))
+ {
+ if (mr.size() == 4)
+ {
+ return std::make_optional(std::make_tuple(mr[1], mr[2], mr[3]));
+ }
+ }
+ }
+ return std::nullopt;
+}
bool parseThresholdsFromAttr(
std::vector<thresholds::Threshold>& thresholdVector,
const std::string& inputPath, const double& scaleFactor,
const double& offset)
{
- for (const std::string& type : attrTypes)
+ const boost::container::flat_map<
+ std::string, std::vector<std::tuple<const char*, thresholds::Level,
+ thresholds::Direction, double>>>
+ map = {
+ {"average",
+ {
+ std::make_tuple("average_min", Level::WARNING, Direction::LOW,
+ 0.0),
+ std::make_tuple("average_max", Level::WARNING, Direction::HIGH,
+ 0.0),
+ }},
+ {"input",
+ {
+ std::make_tuple("min", Level::WARNING, Direction::LOW, 0.0),
+ std::make_tuple("max", Level::WARNING, Direction::HIGH, 0.0),
+ std::make_tuple("lcrit", Level::CRITICAL, Direction::LOW, 0.0),
+ std::make_tuple("crit", Level::CRITICAL, Direction::HIGH,
+ offset),
+ }},
+ };
+
+ if (auto fileParts = splitFileName(inputPath))
{
- auto attrPath = boost::replace_all_copy(inputPath, "input", type);
- std::ifstream attrFile(attrPath);
- if (!attrFile.good())
+ auto [type, nr, item] = *fileParts;
+ if (map.count(item) != 0)
{
- continue;
+ for (const auto& t : map.at(item))
+ {
+ auto [suffix, level, direction, offset] = t;
+ auto attrPath =
+ boost::replace_all_copy(inputPath, item, suffix);
+ if (auto val = readFile(attrPath, scaleFactor))
+ {
+ *val += offset;
+ if (DEBUG)
+ {
+ std::cout << "Threshold: " << attrPath << ": " << *val
+ << "\n";
+ }
+ thresholdVector.emplace_back(level, direction, *val);
+ }
+ }
}
- std::string attr;
- std::getline(attrFile, attr);
- attrFile.close();
-
- Level level;
- Direction direction;
- double val;
- try
- {
- val = std::stod(attr) / scaleFactor;
- }
- catch (const std::invalid_argument&)
- {
- return false;
- }
-
- if (type == "min" || type == "max")
- {
- level = Level::WARNING;
- }
- else
- {
- level = Level::CRITICAL;
- }
- if (type == "min" || type == "lcrit")
- {
- direction = Direction::LOW;
- }
- else
- {
- direction = Direction::HIGH;
- }
-
- if (type == "crit")
- {
- val += offset;
- }
-
- if (DEBUG)
- {
- std::cout << "Threshold: " << attrPath << ": " << val << "\n";
- }
-
- thresholdVector.emplace_back(level, direction, val);
}
- // no thresholds is allowed, not an error so return true.
return true;
}