blob: 3c4706fa9b619c14c23cf23daafd15d80cb8a114 [file] [log] [blame]
James Feist8fd8a582018-11-16 11:10:46 -08001#pragma once
2
Patrick Ventureca44b2f2019-10-31 11:02:26 -07003#include "Thresholds.hpp"
4
Patrick Venturefd6ba732019-10-31 14:27:39 -07005#include <limits>
6#include <memory>
James Feist8fd8a582018-11-16 11:10:46 -08007#include <sdbusplus/asio/object_server.hpp>
Patrick Venturefd6ba732019-10-31 14:27:39 -07008#include <string>
9#include <vector>
James Feist8fd8a582018-11-16 11:10:46 -080010
James Feist1169eb42018-10-31 10:08:47 -070011constexpr size_t sensorFailedPollTimeMs = 5000;
James Feista5e58722019-04-22 14:43:11 -070012
13constexpr const char* sensorValueInterface = "xyz.openbmc_project.Sensor.Value";
James Feist8fd8a582018-11-16 11:10:46 -080014struct Sensor
15{
James Feist930fcde2019-05-28 12:58:43 -070016 Sensor(const std::string& name,
James Feistd8705872019-02-08 13:26:09 -080017 std::vector<thresholds::Threshold>&& thresholdData,
18 const std::string& configurationPath, const std::string& objectType,
James Feistce3fca42018-11-21 12:58:24 -080019 const double max, const double min) :
James Feistdc6c55f2018-10-31 12:53:20 -070020 name(name),
James Feist930fcde2019-05-28 12:58:43 -070021 configurationPath(configurationPath), objectType(objectType),
Brad Bishopfbb44ad2019-11-08 09:42:37 -050022 maxValue(max), minValue(min), thresholds(std::move(thresholdData)),
Josh Lehan883fb3a2020-02-27 14:41:39 -080023 hysteresisTrigger((max - min) * 0.01),
24 hysteresisPublish((max - min) * 0.0001)
James Feistdc6c55f2018-10-31 12:53:20 -070025 {
26 }
James Feist8fd8a582018-11-16 11:10:46 -080027 virtual ~Sensor() = default;
James Feistce3fca42018-11-21 12:58:24 -080028 virtual void checkThresholds(void) = 0;
James Feistdc6c55f2018-10-31 12:53:20 -070029 std::string name;
James Feistce3fca42018-11-21 12:58:24 -080030 std::string configurationPath;
31 std::string objectType;
32 double maxValue;
33 double minValue;
James Feist8fd8a582018-11-16 11:10:46 -080034 std::vector<thresholds::Threshold> thresholds;
35 std::shared_ptr<sdbusplus::asio::dbus_interface> sensorInterface;
36 std::shared_ptr<sdbusplus::asio::dbus_interface> thresholdInterfaceWarning;
37 std::shared_ptr<sdbusplus::asio::dbus_interface> thresholdInterfaceCritical;
James Feist078f2322019-03-08 11:09:05 -080038 std::shared_ptr<sdbusplus::asio::dbus_interface> association;
James Feist8fd8a582018-11-16 11:10:46 -080039 double value = std::numeric_limits<double>::quiet_NaN();
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +053040 bool overriddenState = false;
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +053041 bool internalSet = false;
Josh Lehan883fb3a2020-02-27 14:41:39 -080042 double hysteresisTrigger;
43 double hysteresisPublish;
James Feistce3fca42018-11-21 12:58:24 -080044
James Feistd8705872019-02-08 13:26:09 -080045 int setSensorValue(const double& newValue, double& oldValue)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +053046 {
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +053047 if (!internalSet)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +053048 {
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +053049 oldValue = newValue;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +053050 overriddenState = true;
51 // check thresholds for external set
52 value = newValue;
53 checkThresholds();
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +053054 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +053055 else if (!overriddenState)
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +053056 {
57 oldValue = newValue;
58 }
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +053059 return 1;
60 }
James Feistce3fca42018-11-21 12:58:24 -080061
62 void
Cheng C Yang6b1247a2020-03-09 23:48:39 +080063 setInitialProperties(std::shared_ptr<sdbusplus::asio::connection>& conn,
64 const std::string label = std::string(),
65 size_t thresholdSize = 0)
James Feistce3fca42018-11-21 12:58:24 -080066 {
James Feist82bac4c2019-03-11 11:16:53 -070067 createAssociation(association, configurationPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +053068
James Feistce3fca42018-11-21 12:58:24 -080069 sensorInterface->register_property("MaxValue", maxValue);
70 sensorInterface->register_property("MinValue", minValue);
71 sensorInterface->register_property(
James Feistd8705872019-02-08 13:26:09 -080072 "Value", value, [&](const double& newValue, double& oldValue) {
James Feistce3fca42018-11-21 12:58:24 -080073 return setSensorValue(newValue, oldValue);
74 });
James Feistd8705872019-02-08 13:26:09 -080075 for (auto& threshold : thresholds)
James Feistce3fca42018-11-21 12:58:24 -080076 {
77 std::shared_ptr<sdbusplus::asio::dbus_interface> iface;
78 std::string level;
79 std::string alarm;
80 if (threshold.level == thresholds::Level::CRITICAL)
81 {
82 iface = thresholdInterfaceCritical;
83 if (threshold.direction == thresholds::Direction::HIGH)
84 {
85 level = "CriticalHigh";
86 alarm = "CriticalAlarmHigh";
87 }
88 else
89 {
90 level = "CriticalLow";
91 alarm = "CriticalAlarmLow";
92 }
93 }
94 else if (threshold.level == thresholds::Level::WARNING)
95 {
96 iface = thresholdInterfaceWarning;
97 if (threshold.direction == thresholds::Direction::HIGH)
98 {
99 level = "WarningHigh";
100 alarm = "WarningAlarmHigh";
101 }
102 else
103 {
104 level = "WarningLow";
105 alarm = "WarningAlarmLow";
106 }
107 }
108 else
109 {
110 std::cerr << "Unknown threshold level" << threshold.level
111 << "\n";
112 continue;
113 }
114 if (!iface)
115 {
116 std::cout << "trying to set uninitialized interface\n";
117 continue;
118 }
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800119
120 size_t thresSize =
121 label.empty() ? thresholds.size() : thresholdSize;
James Feistce3fca42018-11-21 12:58:24 -0800122 iface->register_property(
123 level, threshold.value,
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800124 [&, label, thresSize](const double& request, double& oldValue) {
James Feistce3fca42018-11-21 12:58:24 -0800125 oldValue = request; // todo, just let the config do this?
126 threshold.value = request;
127 thresholds::persistThreshold(configurationPath, objectType,
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800128 threshold, conn, thresSize,
129 label);
Josh Lehan883fb3a2020-02-27 14:41:39 -0800130 // Invalidate previously remembered value,
131 // so new thresholds will be checked during next update,
132 // even if sensor reading remains unchanged.
133 value = std::numeric_limits<double>::quiet_NaN();
134
135 // Although tempting, don't call checkThresholds() from here
136 // directly. Let the regular sensor monitor call the same
137 // using updateValue(), which can check conditions like
138 // poweron, etc., before raising any event.
James Feistce3fca42018-11-21 12:58:24 -0800139 return 1;
140 });
141 iface->register_property(alarm, false);
142 }
143 if (!sensorInterface->initialize())
144 {
145 std::cerr << "error initializing value interface\n";
146 }
147 if (thresholdInterfaceWarning &&
148 !thresholdInterfaceWarning->initialize())
149 {
150 std::cerr << "error initializing warning threshold interface\n";
151 }
152
153 if (thresholdInterfaceCritical &&
154 !thresholdInterfaceCritical->initialize())
155 {
156 std::cerr << "error initializing critical threshold interface\n";
157 }
158 }
159
James Feistd8705872019-02-08 13:26:09 -0800160 void updateValue(const double& newValue)
James Feistce3fca42018-11-21 12:58:24 -0800161 {
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530162 // Ignore if overriding is enabled
Josh Lehan883fb3a2020-02-27 14:41:39 -0800163 if (overriddenState)
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530164 {
Josh Lehan883fb3a2020-02-27 14:41:39 -0800165 return;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530166 }
Josh Lehan883fb3a2020-02-27 14:41:39 -0800167
168 bool isChanged = false;
169
170 // Avoid floating-point equality comparison,
171 // by instead comparing against a very small hysteresis range.
172 if (std::isnan(value) || std::isnan(newValue))
173 {
174 // If one or the other is NAN,
175 // either we are intentionally invalidating a sensor reading,
176 // or initializing for the very first time,
177 // either way we should always publish this.
178 isChanged = true;
179 }
180 else
181 {
182 // This essentially does "if (value != newValue)",
183 // but safely against floating-point background noise.
184 double diff = std::abs(value - newValue);
185 if (diff > hysteresisPublish)
186 {
187 isChanged = true;
188 }
189 }
190
191 // Ignore if the change is so small as to be deemed unchanged
192 if (!isChanged)
193 {
194 return;
195 }
196
197 // The value will be changed, keep track of it for next time
198 value = newValue;
199
200 // Indicate that it is internal set call
201 internalSet = true;
202 if (!(sensorInterface->set_property("Value", newValue)))
203 {
204 std::cerr << "error setting property to " << newValue << "\n";
205 }
206 internalSet = false;
207
208 // Always check thresholds after changing the value,
209 // as the test against hysteresisTrigger now takes place in
210 // the thresholds::checkThresholds() method,
211 // which is called by checkThresholds() below,
212 // in all current implementations of sensors that have thresholds.
213 checkThresholds();
James Feistce3fca42018-11-21 12:58:24 -0800214 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530215};