Allow setting setpoint based on dynamic thresholds
As we allow dynamic thresholds in dbus-sensors to track
the t-control of dimms etc, we want to be able to set a
setpoint based on a offset from a threshold. This adds
the ability to create a "SetPointOffset" that is a
threshold of the given sensor. For instance a "SetPointOffset"
of "WarningHigh" would get the sensors "WarningHigh" value
then add the "SetPoint" value to it (commonly negative for
WarningHigh/CriticalHigh).
Tested: Turned on debug print and saw correct setpoint being
loaded into config
Change-Id: Idb9760ea5a66347f24573fb26937f8f278834a19
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/dbus/dbusconfiguration.cpp b/dbus/dbusconfiguration.cpp
index 7641eaf..e68c852 100644
--- a/dbus/dbusconfiguration.cpp
+++ b/dbus/dbusconfiguration.cpp
@@ -50,9 +50,24 @@
constexpr const char* sensorInterface = "xyz.openbmc_project.Sensor.Value";
constexpr const char* pwmInterface = "xyz.openbmc_project.Control.FanPwm";
+namespace thresholds
+{
+constexpr const char* warningInterface =
+ "xyz.openbmc_project.Sensor.Threshold.Warning";
+constexpr const char* criticalInterface =
+ "xyz.openbmc_project.Sensor.Threshold.Critical";
+const std::array<const char*, 4> types = {"CriticalLow", "CriticalHigh",
+ "WarningLow", "WarningHigh"};
+
+} // namespace thresholds
+
namespace dbus_configuration
{
+using DbusVariantType =
+ std::variant<uint64_t, int64_t, double, std::string,
+ std::vector<std::string>, std::vector<double>>;
+
bool findSensors(const std::unordered_map<std::string, std::string>& sensors,
const std::string& search,
std::vector<std::pair<std::string, std::string>>& matches)
@@ -276,6 +291,97 @@
eventHandler, &timer);
}
+void populatePidInfo(
+ sdbusplus::bus::bus& bus,
+ const std::unordered_map<std::string, DbusVariantType>& base,
+ struct conf::ControllerInfo& info, const std::string* thresholdProperty)
+{
+
+ info.type = std::get<std::string>(base.at("Class"));
+
+ if (info.type == "fan")
+ {
+ info.setpoint = 0;
+ }
+ else
+ {
+ info.setpoint =
+ std::visit(VariantToDoubleVisitor(), base.at("SetPoint"));
+ }
+
+ if (thresholdProperty != nullptr)
+ {
+ std::string interface;
+ if (*thresholdProperty == "WarningHigh" ||
+ *thresholdProperty == "WarningLow")
+ {
+ interface = thresholds::warningInterface;
+ }
+ else
+ {
+ interface = thresholds::criticalInterface;
+ }
+ const std::string& path = sensorConfig[info.inputs.front()].readPath;
+
+ DbusHelper helper;
+ std::string service = helper.getService(bus, interface, path);
+ double reading = 0;
+ try
+ {
+ helper.getProperty(bus, service, path, interface,
+ *thresholdProperty, reading);
+ }
+ catch (const sdbusplus::exception::SdBusError& ex)
+ {
+ // unsupported threshold, leaving reading at 0
+ }
+
+ info.setpoint += reading;
+ }
+
+ info.pidInfo.ts = 1.0; // currently unused
+ info.pidInfo.proportionalCoeff =
+ std::visit(VariantToDoubleVisitor(), base.at("PCoefficient"));
+ info.pidInfo.integralCoeff =
+ std::visit(VariantToDoubleVisitor(), base.at("ICoefficient"));
+ info.pidInfo.feedFwdOffset =
+ std::visit(VariantToDoubleVisitor(), base.at("FFOffCoefficient"));
+ info.pidInfo.feedFwdGain =
+ std::visit(VariantToDoubleVisitor(), base.at("FFGainCoefficient"));
+ info.pidInfo.integralLimit.max =
+ std::visit(VariantToDoubleVisitor(), base.at("ILimitMax"));
+ info.pidInfo.integralLimit.min =
+ std::visit(VariantToDoubleVisitor(), base.at("ILimitMin"));
+ info.pidInfo.outLim.max =
+ std::visit(VariantToDoubleVisitor(), base.at("OutLimitMax"));
+ info.pidInfo.outLim.min =
+ std::visit(VariantToDoubleVisitor(), base.at("OutLimitMin"));
+ info.pidInfo.slewNeg =
+ std::visit(VariantToDoubleVisitor(), base.at("SlewNeg"));
+ info.pidInfo.slewPos =
+ std::visit(VariantToDoubleVisitor(), base.at("SlewPos"));
+ double negativeHysteresis = 0;
+ double positiveHysteresis = 0;
+
+ auto findNeg = base.find("NegativeHysteresis");
+ auto findPos = base.find("PositiveHysteresis");
+
+ if (findNeg != base.end())
+ {
+ negativeHysteresis =
+ std::visit(VariantToDoubleVisitor(), findNeg->second);
+ }
+
+ if (findPos != base.end())
+ {
+ positiveHysteresis =
+ std::visit(VariantToDoubleVisitor(), findPos->second);
+ }
+
+ info.pidInfo.negativeHysteresis = negativeHysteresis;
+ info.pidInfo.positiveHysteresis = positiveHysteresis;
+}
+
bool init(sdbusplus::bus::bus& bus, boost::asio::steady_timer& timer)
{
@@ -558,61 +664,43 @@
continue;
}
- struct conf::ControllerInfo& info =
- conf[std::get<std::string>(base.at("Name"))];
- info.inputs = std::move(inputs);
+ std::string offsetType;
- info.type = std::get<std::string>(base.at("Class"));
- // todo: auto generation yaml -> c script seems to discard this
- // value for fans, verify this is okay
- if (info.type == "fan")
+ // SetPointOffset is a threshold value to pull from the sensor
+ // to apply an offset. For upper thresholds this means the
+ // setpoint is usually negative.
+ auto findSetpointOffset = base.find("SetPointOffset");
+ if (findSetpointOffset != base.end())
{
- info.setpoint = 0;
+ offsetType =
+ std::get<std::string>(findSetpointOffset->second);
+ if (std::find(thresholds::types.begin(),
+ thresholds::types.end(),
+ offsetType) == thresholds::types.end())
+ {
+ throw std::runtime_error("Unsupported type: " +
+ offsetType);
+ }
+ }
+
+ if (offsetType.empty())
+ {
+ struct conf::ControllerInfo& info =
+ conf[std::get<std::string>(base.at("Name"))];
+ info.inputs = std::move(inputs);
+ populatePidInfo(bus, base, info, nullptr);
}
else
{
- info.setpoint = std::visit(VariantToDoubleVisitor(),
- base.at("SetPoint"));
+ // we have to split up the inputs, as in practice t-control
+ // values will differ, making setpoints differ
+ for (const std::string& input : inputs)
+ {
+ struct conf::ControllerInfo& info = conf[input];
+ info.inputs.emplace_back(input);
+ populatePidInfo(bus, base, info, &offsetType);
+ }
}
- info.pidInfo.ts = 1.0; // currently unused
- info.pidInfo.proportionalCoeff = std::visit(
- VariantToDoubleVisitor(), base.at("PCoefficient"));
- info.pidInfo.integralCoeff = std::visit(
- VariantToDoubleVisitor(), base.at("ICoefficient"));
- info.pidInfo.feedFwdOffset = std::visit(
- VariantToDoubleVisitor(), base.at("FFOffCoefficient"));
- info.pidInfo.feedFwdGain = std::visit(
- VariantToDoubleVisitor(), base.at("FFGainCoefficient"));
- info.pidInfo.integralLimit.max =
- std::visit(VariantToDoubleVisitor(), base.at("ILimitMax"));
- info.pidInfo.integralLimit.min =
- std::visit(VariantToDoubleVisitor(), base.at("ILimitMin"));
- info.pidInfo.outLim.max = std::visit(VariantToDoubleVisitor(),
- base.at("OutLimitMax"));
- info.pidInfo.outLim.min = std::visit(VariantToDoubleVisitor(),
- base.at("OutLimitMin"));
- info.pidInfo.slewNeg =
- std::visit(VariantToDoubleVisitor(), base.at("SlewNeg"));
- info.pidInfo.slewPos =
- std::visit(VariantToDoubleVisitor(), base.at("SlewPos"));
- double negativeHysteresis = 0;
- double positiveHysteresis = 0;
-
- auto findNeg = base.find("NegativeHysteresis");
- auto findPos = base.find("PositiveHysteresis");
- if (findNeg != base.end())
- {
- negativeHysteresis =
- std::visit(VariantToDoubleVisitor(), findNeg->second);
- }
-
- if (findPos != base.end())
- {
- positiveHysteresis =
- std::visit(VariantToDoubleVisitor(), findPos->second);
- }
- info.pidInfo.negativeHysteresis = negativeHysteresis;
- info.pidInfo.positiveHysteresis = positiveHysteresis;
}
}
auto findStepwise =
diff --git a/util.hpp b/util.hpp
index f472bf8..e40b61f 100644
--- a/util.hpp
+++ b/util.hpp
@@ -3,6 +3,7 @@
#include "pid/ec/pid.hpp"
#include <limits>
+#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus.hpp>
#include <string>
@@ -117,6 +118,34 @@
bool thresholdsAsserted(sdbusplus::bus::bus& bus,
const std::string& service,
const std::string& path) override;
+
+ template <typename T>
+ void getProperty(sdbusplus::bus::bus& bus, const std::string& service,
+ const std::string& path, const std::string& interface,
+ const std::string& propertyName, T& prop)
+ {
+ namespace log = phosphor::logging;
+
+ auto msg = bus.new_method_call(service.c_str(), path.c_str(),
+ propertiesintf.c_str(), "Get");
+
+ msg.append(interface, propertyName);
+
+ std::variant<T> result;
+ try
+ {
+ auto valueResponseMsg = bus.call(msg);
+ valueResponseMsg.read(result);
+ }
+ catch (const sdbusplus::exception::SdBusError& ex)
+ {
+ log::log<log::level::ERR>("Get Property Failed",
+ log::entry("WHAT=%s", ex.what()));
+ throw;
+ }
+
+ prop = std::get<T>(result);
+ }
};
std::string getSensorPath(const std::string& type, const std::string& id);