blob: 82798dc241ed9e3300d7d1a5fca524256250497f [file] [log] [blame]
James Feist8fd8a582018-11-16 11:10:46 -08001#pragma once
Andrew Jefferye73bd0a2023-01-25 10:39:57 +10302
Bruce Lee1263c3d2021-06-04 15:16:33 +08003#include "dbus-sensor_config.h"
James Feist8fd8a582018-11-16 11:10:46 -08004
Andrew Jefferye73bd0a2023-01-25 10:39:57 +10305#include "SensorPaths.hpp"
6#include "Thresholds.hpp"
7#include "Utils.hpp"
8
James Feist38fb5982020-05-28 10:09:54 -07009#include <sdbusplus/asio/object_server.hpp>
Jonathan Doman256d8c12022-06-03 13:01:08 -070010#include <sdbusplus/exception.hpp>
James Feist38fb5982020-05-28 10:09:54 -070011
Patrick Venturefd6ba732019-10-31 14:27:39 -070012#include <limits>
13#include <memory>
Patrick Venturefd6ba732019-10-31 14:27:39 -070014#include <string>
15#include <vector>
James Feist8fd8a582018-11-16 11:10:46 -080016
James Feist1169eb42018-10-31 10:08:47 -070017constexpr size_t sensorFailedPollTimeMs = 5000;
James Feista5e58722019-04-22 14:43:11 -070018
Josh Lehan3bcd8232020-10-29 00:22:12 -070019// Enable useful logging with sensor instrumentation
20// This is intentionally not DEBUG, avoid clash with usage in .cpp files
21constexpr bool enableInstrumentation = false;
22
James Feista5e58722019-04-22 14:43:11 -070023constexpr const char* sensorValueInterface = "xyz.openbmc_project.Sensor.Value";
Jie Yang3291b9c2021-07-29 14:46:51 -070024constexpr const char* valueMutabilityInterfaceName =
25 "xyz.openbmc_project.Sensor.ValueMutability";
James Feist67601bd2020-06-16 17:14:44 -070026constexpr const char* availableInterfaceName =
27 "xyz.openbmc_project.State.Decorator.Availability";
James Feist961bf092020-07-01 16:38:12 -070028constexpr const char* operationalInterfaceName =
29 "xyz.openbmc_project.State.Decorator.OperationalStatus";
30constexpr const size_t errorThreshold = 5;
31
Josh Lehan3bcd8232020-10-29 00:22:12 -070032struct SensorInstrumentation
33{
34 // These are for instrumentation for debugging
35 int numCollectsGood = 0;
36 int numCollectsMiss = 0;
37 int numStreakGreats = 0;
38 int numStreakMisses = 0;
39 double minCollected = 0.0;
40 double maxCollected = 0.0;
41};
42
Jonathan Doman256d8c12022-06-03 13:01:08 -070043struct SetSensorError : sdbusplus::exception_t
44{
45 const char* name() const noexcept override
46 {
47 return "xyz.openbmc_project.Common.Errors.NotAllowed";
48 }
49 const char* description() const noexcept override
50 {
51 return "Not allowed to set property value.";
52 }
53 int get_errno() const noexcept override
54 {
55 return EACCES;
56 }
57};
58
James Feist8fd8a582018-11-16 11:10:46 -080059struct Sensor
60{
James Feist930fcde2019-05-28 12:58:43 -070061 Sensor(const std::string& name,
James Feistd8705872019-02-08 13:26:09 -080062 std::vector<thresholds::Threshold>&& thresholdData,
63 const std::string& configurationPath, const std::string& objectType,
Jie Yang3291b9c2021-07-29 14:46:51 -070064 bool isSettable, bool isMutable, const double max, const double min,
James Feiste3338522020-09-15 15:40:30 -070065 std::shared_ptr<sdbusplus::asio::connection>& conn,
James Feist961bf092020-07-01 16:38:12 -070066 PowerState readState = PowerState::always) :
Ed Tanous6cb732a2021-02-18 15:33:51 -080067 name(sensor_paths::escapePathForDbus(name)),
Zev Weiss054aad82022-08-18 01:37:34 -070068 configurationPath(configurationPath),
Matt Spinler55832f32023-06-07 10:24:00 -050069 configInterface(configInterfaceName(objectType)),
Jie Yang3291b9c2021-07-29 14:46:51 -070070 isSensorSettable(isSettable), isValueMutable(isMutable), maxValue(max),
71 minValue(min), thresholds(std::move(thresholdData)),
Josh Lehan883fb3a2020-02-27 14:41:39 -080072 hysteresisTrigger((max - min) * 0.01),
James Feiste3338522020-09-15 15:40:30 -070073 hysteresisPublish((max - min) * 0.0001), dbusConnection(conn),
Ed Tanousb429f312022-06-27 16:09:53 -070074 readState(readState),
Josh Lehan3bcd8232020-10-29 00:22:12 -070075 instrumentation(enableInstrumentation
76 ? std::make_unique<SensorInstrumentation>()
77 : nullptr)
James Feist38fb5982020-05-28 10:09:54 -070078 {}
James Feist8fd8a582018-11-16 11:10:46 -080079 virtual ~Sensor() = default;
Ed Tanous201a1012024-04-03 18:07:28 -070080 virtual void checkThresholds() = 0;
James Feistdc6c55f2018-10-31 12:53:20 -070081 std::string name;
James Feistce3fca42018-11-21 12:58:24 -080082 std::string configurationPath;
Matt Spinler55832f32023-06-07 10:24:00 -050083 std::string configInterface;
Bruce Lee1263c3d2021-06-04 15:16:33 +080084 bool isSensorSettable;
Jie Yang3291b9c2021-07-29 14:46:51 -070085
86 /* A flag indicates if properties of xyz.openbmc_project.Sensor.Value
87 * interface are mutable. If mutable, then
88 * xyz.openbmc_project.Sensor.ValueMutability interface will be
89 * instantiated.
90 */
91 bool isValueMutable;
James Feistce3fca42018-11-21 12:58:24 -080092 double maxValue;
93 double minValue;
James Feist8fd8a582018-11-16 11:10:46 -080094 std::vector<thresholds::Threshold> thresholds;
95 std::shared_ptr<sdbusplus::asio::dbus_interface> sensorInterface;
James Feist078f2322019-03-08 11:09:05 -080096 std::shared_ptr<sdbusplus::asio::dbus_interface> association;
James Feist67601bd2020-06-16 17:14:44 -070097 std::shared_ptr<sdbusplus::asio::dbus_interface> availableInterface;
James Feist961bf092020-07-01 16:38:12 -070098 std::shared_ptr<sdbusplus::asio::dbus_interface> operationalInterface;
Jie Yang3291b9c2021-07-29 14:46:51 -070099 std::shared_ptr<sdbusplus::asio::dbus_interface> valueMutabilityInterface;
James Feist8fd8a582018-11-16 11:10:46 -0800100 double value = std::numeric_limits<double>::quiet_NaN();
Zhikui Rend3da1282020-09-11 17:02:01 -0700101 double rawValue = std::numeric_limits<double>::quiet_NaN();
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530102 bool overriddenState = false;
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530103 bool internalSet = false;
Josh Lehan883fb3a2020-02-27 14:41:39 -0800104 double hysteresisTrigger;
105 double hysteresisPublish;
James Feiste3338522020-09-15 15:40:30 -0700106 std::shared_ptr<sdbusplus::asio::connection> dbusConnection;
James Feist961bf092020-07-01 16:38:12 -0700107 PowerState readState;
Ed Tanousb429f312022-06-27 16:09:53 -0700108 size_t errCount{0};
Josh Lehan3bcd8232020-10-29 00:22:12 -0700109 std::unique_ptr<SensorInstrumentation> instrumentation;
110
Josh Lehanffe18342021-03-17 13:29:51 -0700111 // This member variable provides a hook that can be used to receive
112 // notification whenever this Sensor's value is externally set via D-Bus.
113 // If interested, assign your own lambda to this variable, during
114 // construction of your Sensor subclass. See ExternalSensor for example.
115 std::function<void()> externalSetHook;
116
Ed Tanousc8fed202022-01-12 14:24:45 -0800117 using Level = thresholds::Level;
118 using Direction = thresholds::Direction;
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530119
Ed Tanousc8fed202022-01-12 14:24:45 -0800120 std::array<std::shared_ptr<sdbusplus::asio::dbus_interface>,
121 thresholds::thresProp.size()>
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530122 thresholdInterfaces;
123
124 std::shared_ptr<sdbusplus::asio::dbus_interface>
Ed Tanousc8fed202022-01-12 14:24:45 -0800125 getThresholdInterface(Level lev)
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530126 {
127 size_t index = static_cast<size_t>(lev);
128 if (index >= thresholdInterfaces.size())
129 {
130 std::cout << "Unknown threshold level \n";
131 return nullptr;
132 }
133 std::shared_ptr<sdbusplus::asio::dbus_interface> interface =
134 thresholdInterfaces[index];
135 return interface;
136 }
137
Ed Tanous2049bd22022-07-09 07:20:26 -0700138 void updateInstrumentation(double readValue) const
Josh Lehan3bcd8232020-10-29 00:22:12 -0700139 {
140 // Do nothing if this feature is not enabled
141 if constexpr (!enableInstrumentation)
142 {
143 return;
144 }
145 if (!instrumentation)
146 {
147 return;
148 }
149
150 // Save some typing
151 auto& inst = *instrumentation;
152
153 // Show constants if first reading (even if unsuccessful)
154 if ((inst.numCollectsGood == 0) && (inst.numCollectsMiss == 0))
155 {
156 std::cerr << "Sensor " << name << ": Configuration min=" << minValue
Matt Spinler55832f32023-06-07 10:24:00 -0500157 << ", max=" << maxValue << ", type=" << configInterface
Josh Lehan3bcd8232020-10-29 00:22:12 -0700158 << ", path=" << configurationPath << "\n";
159 }
160
161 // Sensors can use "nan" to indicate unavailable reading
162 if (!std::isfinite(readValue))
163 {
164 // Only show this if beginning a new streak
165 if (inst.numStreakMisses == 0)
166 {
167 std::cerr << "Sensor " << name
168 << ": Missing reading, Reading counts good="
169 << inst.numCollectsGood
170 << ", miss=" << inst.numCollectsMiss
171 << ", Prior good streak=" << inst.numStreakGreats
172 << "\n";
173 }
174
175 inst.numStreakGreats = 0;
176 ++(inst.numCollectsMiss);
177 ++(inst.numStreakMisses);
178
179 return;
180 }
181
182 // Only show this if beginning a new streak and not the first time
183 if ((inst.numStreakGreats == 0) && (inst.numCollectsGood != 0))
184 {
185 std::cerr << "Sensor " << name
186 << ": Recovered reading, Reading counts good="
187 << inst.numCollectsGood
188 << ", miss=" << inst.numCollectsMiss
189 << ", Prior miss streak=" << inst.numStreakMisses << "\n";
190 }
191
192 // Initialize min/max if the first successful reading
193 if (inst.numCollectsGood == 0)
194 {
195 std::cerr << "Sensor " << name << ": First reading=" << readValue
196 << "\n";
197
198 inst.minCollected = readValue;
199 inst.maxCollected = readValue;
200 }
201
202 inst.numStreakMisses = 0;
203 ++(inst.numCollectsGood);
204 ++(inst.numStreakGreats);
205
206 // Only provide subsequent output if new min/max established
207 if (readValue < inst.minCollected)
208 {
209 std::cerr << "Sensor " << name << ": Lowest reading=" << readValue
210 << "\n";
211
212 inst.minCollected = readValue;
213 }
214
215 if (readValue > inst.maxCollected)
216 {
217 std::cerr << "Sensor " << name << ": Highest reading=" << readValue
218 << "\n";
219
220 inst.maxCollected = readValue;
221 }
222 }
James Feistce3fca42018-11-21 12:58:24 -0800223
James Feistd8705872019-02-08 13:26:09 -0800224 int setSensorValue(const double& newValue, double& oldValue)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530225 {
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +0530226 if (!internalSet)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530227 {
Jonathan Doman256d8c12022-06-03 13:01:08 -0700228 if (insecureSensorOverride == 0 && !isSensorSettable &&
229 !getManufacturingMode())
230 {
231 throw SetSensorError();
Bruce Lee1263c3d2021-06-04 15:16:33 +0800232 }
233
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530234 oldValue = newValue;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530235 overriddenState = true;
236 // check thresholds for external set
237 value = newValue;
238 checkThresholds();
Josh Lehanffe18342021-03-17 13:29:51 -0700239
240 // Trigger the hook, as an external set has just happened
241 if (externalSetHook)
242 {
243 externalSetHook();
244 }
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530245 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530246 else if (!overriddenState)
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +0530247 {
248 oldValue = newValue;
249 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700250 return 1;
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530251 }
James Feistce3fca42018-11-21 12:58:24 -0800252
Andrei Kartashev39287412022-02-04 16:04:47 +0300253 void setInitialProperties(const std::string& unit,
254 const std::string& label = std::string(),
255 size_t thresholdSize = 0)
James Feistce3fca42018-11-21 12:58:24 -0800256 {
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700257 if (readState == PowerState::on || readState == PowerState::biosPost ||
258 readState == PowerState::chassisOn)
James Feist961bf092020-07-01 16:38:12 -0700259 {
Andrei Kartashev39287412022-02-04 16:04:47 +0300260 setupPowerMatch(dbusConnection);
James Feist961bf092020-07-01 16:38:12 -0700261 }
262
James Feist82bac4c2019-03-11 11:16:53 -0700263 createAssociation(association, configurationPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +0530264
Zev Weiss6b6891c2021-04-22 02:46:21 -0500265 sensorInterface->register_property("Unit", unit);
James Feistce3fca42018-11-21 12:58:24 -0800266 sensorInterface->register_property("MaxValue", maxValue);
267 sensorInterface->register_property("MinValue", minValue);
268 sensorInterface->register_property(
Jonathan Doman256d8c12022-06-03 13:01:08 -0700269 "Value", value, [this](const double& newValue, double& oldValue) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400270 return setSensorValue(newValue, oldValue);
271 });
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300272
273 fillMissingThresholds();
274
James Feistd8705872019-02-08 13:26:09 -0800275 for (auto& threshold : thresholds)
James Feistce3fca42018-11-21 12:58:24 -0800276 {
Rashmica Gupta1e34cec2021-08-31 16:47:39 +1000277 if (std::isnan(threshold.hysteresis))
278 {
279 threshold.hysteresis = hysteresisTrigger;
280 }
Ed Tanous17551b82022-01-26 16:47:17 -0800281
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530282 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
283 getThresholdInterface(threshold.level);
284
James Feistce3fca42018-11-21 12:58:24 -0800285 if (!iface)
286 {
287 std::cout << "trying to set uninitialized interface\n";
288 continue;
289 }
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800290
Patrick Williams2aaf7172024-08-16 15:20:40 -0400291 std::string level =
292 propertyLevel(threshold.level, threshold.direction);
293 std::string alarm =
294 propertyAlarm(threshold.level, threshold.direction);
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530295
296 if ((level.empty()) || (alarm.empty()))
297 {
298 continue;
299 }
Patrick Williams2aaf7172024-08-16 15:20:40 -0400300 size_t thresSize =
301 label.empty() ? thresholds.size() : thresholdSize;
James Feistce3fca42018-11-21 12:58:24 -0800302 iface->register_property(
303 level, threshold.value,
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800304 [&, label, thresSize](const double& request, double& oldValue) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400305 oldValue = request; // todo, just let the config do this?
306 threshold.value = request;
307 thresholds::persistThreshold(
308 configurationPath, configInterface, threshold,
309 dbusConnection, thresSize, label);
310 // Invalidate previously remembered value,
311 // so new thresholds will be checked during next update,
312 // even if sensor reading remains unchanged.
313 value = std::numeric_limits<double>::quiet_NaN();
Josh Lehan883fb3a2020-02-27 14:41:39 -0800314
Patrick Williams2aaf7172024-08-16 15:20:40 -0400315 // Although tempting, don't call checkThresholds() from here
316 // directly. Let the regular sensor monitor call the same
317 // using updateValue(), which can check conditions like
318 // poweron, etc., before raising any event.
319 return 1;
320 });
James Feistce3fca42018-11-21 12:58:24 -0800321 iface->register_property(alarm, false);
322 }
323 if (!sensorInterface->initialize())
324 {
325 std::cerr << "error initializing value interface\n";
326 }
James Feistce3fca42018-11-21 12:58:24 -0800327
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530328 for (auto& thresIface : thresholdInterfaces)
James Feistce3fca42018-11-21 12:58:24 -0800329 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530330 if (thresIface)
331 {
332 if (!thresIface->initialize(true))
333 {
334 std::cerr << "Error initializing threshold interface \n";
335 }
336 }
James Feistce3fca42018-11-21 12:58:24 -0800337 }
James Feist67601bd2020-06-16 17:14:44 -0700338
Jie Yang3291b9c2021-07-29 14:46:51 -0700339 if (isValueMutable)
340 {
341 valueMutabilityInterface =
342 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300343 dbusConnection, sensorInterface->get_object_path(),
Jie Yang3291b9c2021-07-29 14:46:51 -0700344 valueMutabilityInterfaceName);
345 valueMutabilityInterface->register_property("Mutable", true);
346 if (!valueMutabilityInterface->initialize())
347 {
348 std::cerr
349 << "error initializing sensor value mutability interface\n";
350 valueMutabilityInterface = nullptr;
351 }
352 }
353
James Feist67601bd2020-06-16 17:14:44 -0700354 if (!availableInterface)
355 {
356 availableInterface =
357 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300358 dbusConnection, sensorInterface->get_object_path(),
James Feist67601bd2020-06-16 17:14:44 -0700359 availableInterfaceName);
360 availableInterface->register_property(
361 "Available", true, [this](const bool propIn, bool& old) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400362 if (propIn == old)
363 {
364 return 1;
365 }
366 old = propIn;
367 if (!propIn)
368 {
369 updateValue(std::numeric_limits<double>::quiet_NaN());
370 }
James Feist67601bd2020-06-16 17:14:44 -0700371 return 1;
Patrick Williams2aaf7172024-08-16 15:20:40 -0400372 });
James Feist67601bd2020-06-16 17:14:44 -0700373 availableInterface->initialize();
374 }
James Feist961bf092020-07-01 16:38:12 -0700375 if (!operationalInterface)
376 {
377 operationalInterface =
378 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300379 dbusConnection, sensorInterface->get_object_path(),
James Feist961bf092020-07-01 16:38:12 -0700380 operationalInterfaceName);
381 operationalInterface->register_property("Functional", true);
382 operationalInterface->initialize();
383 }
384 }
385
Ed Tanous2049bd22022-07-09 07:20:26 -0700386 static std::string propertyLevel(const Level lev, const Direction dir)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530387 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800388 for (const thresholds::ThresholdDefinition& prop :
389 thresholds::thresProp)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530390 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800391 if (prop.level == lev)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530392 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800393 if (dir == Direction::HIGH)
394 {
395 return std::string(prop.levelName) + "High";
396 }
397 if (dir == Direction::LOW)
398 {
399 return std::string(prop.levelName) + "Low";
400 }
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530401 }
402 }
403 return "";
404 }
405
Ed Tanous2049bd22022-07-09 07:20:26 -0700406 static std::string propertyAlarm(const Level lev, const Direction dir)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530407 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800408 for (const thresholds::ThresholdDefinition& prop :
409 thresholds::thresProp)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530410 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800411 if (prop.level == lev)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530412 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800413 if (dir == Direction::HIGH)
414 {
415 return std::string(prop.levelName) + "AlarmHigh";
416 }
417 if (dir == Direction::LOW)
418 {
419 return std::string(prop.levelName) + "AlarmLow";
420 }
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530421 }
422 }
423 return "";
424 }
425
Ed Tanous2049bd22022-07-09 07:20:26 -0700426 bool readingStateGood() const
James Feist961bf092020-07-01 16:38:12 -0700427 {
Zev Weissece5c862022-08-05 14:34:59 -0700428 return ::readingStateGood(readState);
James Feist961bf092020-07-01 16:38:12 -0700429 }
430
431 void markFunctional(bool isFunctional)
432 {
433 if (operationalInterface)
434 {
435 operationalInterface->set_property("Functional", isFunctional);
436 }
437 if (isFunctional)
438 {
439 errCount = 0;
440 }
441 else
442 {
443 updateValue(std::numeric_limits<double>::quiet_NaN());
444 }
445 }
446
447 void markAvailable(bool isAvailable)
448 {
449 if (availableInterface)
450 {
451 availableInterface->set_property("Available", isAvailable);
452 errCount = 0;
453 }
454 }
455
456 void incrementError()
457 {
458 if (!readingStateGood())
459 {
460 markAvailable(false);
461 return;
462 }
463
464 if (errCount >= errorThreshold)
465 {
466 return;
467 }
468
469 errCount++;
470 if (errCount == errorThreshold)
471 {
472 std::cerr << "Sensor " << name << " reading error!\n";
473 markFunctional(false);
474 }
James Feistce3fca42018-11-21 12:58:24 -0800475 }
476
Ed Tanous2049bd22022-07-09 07:20:26 -0700477 bool inError() const
Andrew Jefferyfad36052022-03-15 21:44:44 +1030478 {
479 return errCount >= errorThreshold;
480 }
481
James Feistd8705872019-02-08 13:26:09 -0800482 void updateValue(const double& newValue)
James Feistce3fca42018-11-21 12:58:24 -0800483 {
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530484 // Ignore if overriding is enabled
James Feist961bf092020-07-01 16:38:12 -0700485 if (overriddenState)
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530486 {
Josh Lehan883fb3a2020-02-27 14:41:39 -0800487 return;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530488 }
Josh Lehan883fb3a2020-02-27 14:41:39 -0800489
James Feist961bf092020-07-01 16:38:12 -0700490 if (!readingStateGood())
491 {
492 markAvailable(false);
Konstantin Aladysheve4569252023-03-23 11:08:14 +0300493 for (auto& threshold : thresholds)
494 {
495 assertThresholds(this, value, threshold.level,
496 threshold.direction, false);
497 }
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200498 updateValueProperty(std::numeric_limits<double>::quiet_NaN());
James Feist961bf092020-07-01 16:38:12 -0700499 return;
500 }
501
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200502 updateValueProperty(newValue);
Josh Lehan3bcd8232020-10-29 00:22:12 -0700503 updateInstrumentation(newValue);
Josh Lehan883fb3a2020-02-27 14:41:39 -0800504
505 // Always check thresholds after changing the value,
506 // as the test against hysteresisTrigger now takes place in
507 // the thresholds::checkThresholds() method,
508 // which is called by checkThresholds() below,
509 // in all current implementations of sensors that have thresholds.
510 checkThresholds();
James Feist961bf092020-07-01 16:38:12 -0700511 if (!std::isnan(newValue))
512 {
513 markFunctional(true);
514 markAvailable(true);
515 }
James Feistce3fca42018-11-21 12:58:24 -0800516 }
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200517
518 void updateProperty(
519 std::shared_ptr<sdbusplus::asio::dbus_interface>& interface,
Ed Tanous2049bd22022-07-09 07:20:26 -0700520 double& oldValue, const double& newValue,
521 const char* dbusPropertyName) const
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200522 {
523 if (requiresUpdate(oldValue, newValue))
524 {
525 oldValue = newValue;
Jae Hyun Yoo1a540b82020-07-30 23:33:18 -0700526 if (interface &&
527 !(interface->set_property(dbusPropertyName, newValue)))
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200528 {
529 std::cerr << "error setting property " << dbusPropertyName
530 << " to " << newValue << "\n";
531 }
532 }
533 }
534
Ed Tanous2049bd22022-07-09 07:20:26 -0700535 bool requiresUpdate(const double& lVal, const double& rVal) const
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200536 {
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000537 const auto lNan = std::isnan(lVal);
538 const auto rNan = std::isnan(rVal);
539 if (lNan || rNan)
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200540 {
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000541 return (lNan != rNan);
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200542 }
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000543 return std::abs(lVal - rVal) > hysteresisPublish;
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200544 }
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200545
546 private:
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300547 // If one of the thresholds for a dbus interface is provided
548 // we have to set the other one as dbus properties are never
549 // optional.
550 void fillMissingThresholds()
551 {
Vikash Chandola2d5ee502023-07-06 15:57:09 +0530552 const std::size_t thresholdsLen = thresholds.size();
553 for (std::size_t index = 0; index < thresholdsLen; ++index)
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300554 {
Vikash Chandola2d5ee502023-07-06 15:57:09 +0530555 const thresholds::Threshold& thisThreshold = thresholds[index];
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300556 bool foundOpposite = false;
557 thresholds::Direction opposite = thresholds::Direction::HIGH;
558 if (thisThreshold.direction == thresholds::Direction::HIGH)
559 {
560 opposite = thresholds::Direction::LOW;
561 }
562 for (thresholds::Threshold& otherThreshold : thresholds)
563 {
564 if (thisThreshold.level != otherThreshold.level)
565 {
566 continue;
567 }
568 if (otherThreshold.direction != opposite)
569 {
570 continue;
571 }
572 foundOpposite = true;
573 break;
574 }
575 if (foundOpposite)
576 {
577 continue;
578 }
579 thresholds.emplace_back(thisThreshold.level, opposite,
580 std::numeric_limits<double>::quiet_NaN());
581 }
582 }
583
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200584 void updateValueProperty(const double& newValue)
585 {
586 // Indicate that it is internal set call, not an external overwrite
587 internalSet = true;
588 updateProperty(sensorInterface, value, newValue, "Value");
589 internalSet = false;
590 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530591};