blob: f278212a8c7cc1ec11ad6bf8606c2c3cf255b548 [file] [log] [blame]
James Feist8fd8a582018-11-16 11:10:46 -08001#pragma once
Bruce Lee1263c3d2021-06-04 15:16:33 +08002#include "dbus-sensor_config.h"
James Feist8fd8a582018-11-16 11:10:46 -08003
Ed Tanous6cb732a2021-02-18 15:33:51 -08004#include <SensorPaths.hpp>
Ed Tanous8a57ec02020-10-09 12:46:52 -07005#include <Thresholds.hpp>
6#include <Utils.hpp>
James Feist38fb5982020-05-28 10:09:54 -07007#include <sdbusplus/asio/object_server.hpp>
Jonathan Doman256d8c12022-06-03 13:01:08 -07008#include <sdbusplus/exception.hpp>
James Feist38fb5982020-05-28 10:09:54 -07009
Patrick Venturefd6ba732019-10-31 14:27:39 -070010#include <limits>
11#include <memory>
Patrick Venturefd6ba732019-10-31 14:27:39 -070012#include <string>
13#include <vector>
James Feist8fd8a582018-11-16 11:10:46 -080014
James Feist1169eb42018-10-31 10:08:47 -070015constexpr size_t sensorFailedPollTimeMs = 5000;
James Feista5e58722019-04-22 14:43:11 -070016
Josh Lehan3bcd8232020-10-29 00:22:12 -070017// Enable useful logging with sensor instrumentation
18// This is intentionally not DEBUG, avoid clash with usage in .cpp files
19constexpr bool enableInstrumentation = false;
20
James Feista5e58722019-04-22 14:43:11 -070021constexpr const char* sensorValueInterface = "xyz.openbmc_project.Sensor.Value";
Jie Yang3291b9c2021-07-29 14:46:51 -070022constexpr const char* valueMutabilityInterfaceName =
23 "xyz.openbmc_project.Sensor.ValueMutability";
James Feist67601bd2020-06-16 17:14:44 -070024constexpr const char* availableInterfaceName =
25 "xyz.openbmc_project.State.Decorator.Availability";
James Feist961bf092020-07-01 16:38:12 -070026constexpr const char* operationalInterfaceName =
27 "xyz.openbmc_project.State.Decorator.OperationalStatus";
28constexpr const size_t errorThreshold = 5;
29
Josh Lehan3bcd8232020-10-29 00:22:12 -070030struct SensorInstrumentation
31{
32 // These are for instrumentation for debugging
33 int numCollectsGood = 0;
34 int numCollectsMiss = 0;
35 int numStreakGreats = 0;
36 int numStreakMisses = 0;
37 double minCollected = 0.0;
38 double maxCollected = 0.0;
39};
40
Jonathan Doman256d8c12022-06-03 13:01:08 -070041struct SetSensorError : sdbusplus::exception_t
42{
43 const char* name() const noexcept override
44 {
45 return "xyz.openbmc_project.Common.Errors.NotAllowed";
46 }
47 const char* description() const noexcept override
48 {
49 return "Not allowed to set property value.";
50 }
51 int get_errno() const noexcept override
52 {
53 return EACCES;
54 }
55};
56
James Feist8fd8a582018-11-16 11:10:46 -080057struct Sensor
58{
James Feist930fcde2019-05-28 12:58:43 -070059 Sensor(const std::string& name,
James Feistd8705872019-02-08 13:26:09 -080060 std::vector<thresholds::Threshold>&& thresholdData,
61 const std::string& configurationPath, const std::string& objectType,
Jie Yang3291b9c2021-07-29 14:46:51 -070062 bool isSettable, bool isMutable, const double max, const double min,
James Feiste3338522020-09-15 15:40:30 -070063 std::shared_ptr<sdbusplus::asio::connection>& conn,
James Feist961bf092020-07-01 16:38:12 -070064 PowerState readState = PowerState::always) :
Ed Tanous6cb732a2021-02-18 15:33:51 -080065 name(sensor_paths::escapePathForDbus(name)),
Zev Weiss054aad82022-08-18 01:37:34 -070066 configurationPath(configurationPath),
67 objectType(configInterfaceName(objectType)),
Jie Yang3291b9c2021-07-29 14:46:51 -070068 isSensorSettable(isSettable), isValueMutable(isMutable), maxValue(max),
69 minValue(min), thresholds(std::move(thresholdData)),
Josh Lehan883fb3a2020-02-27 14:41:39 -080070 hysteresisTrigger((max - min) * 0.01),
James Feiste3338522020-09-15 15:40:30 -070071 hysteresisPublish((max - min) * 0.0001), dbusConnection(conn),
Ed Tanousb429f312022-06-27 16:09:53 -070072 readState(readState),
Josh Lehan3bcd8232020-10-29 00:22:12 -070073 instrumentation(enableInstrumentation
74 ? std::make_unique<SensorInstrumentation>()
75 : nullptr)
James Feist38fb5982020-05-28 10:09:54 -070076 {}
James Feist8fd8a582018-11-16 11:10:46 -080077 virtual ~Sensor() = default;
James Feistce3fca42018-11-21 12:58:24 -080078 virtual void checkThresholds(void) = 0;
James Feistdc6c55f2018-10-31 12:53:20 -070079 std::string name;
James Feistce3fca42018-11-21 12:58:24 -080080 std::string configurationPath;
81 std::string objectType;
Bruce Lee1263c3d2021-06-04 15:16:33 +080082 bool isSensorSettable;
Jie Yang3291b9c2021-07-29 14:46:51 -070083
84 /* A flag indicates if properties of xyz.openbmc_project.Sensor.Value
85 * interface are mutable. If mutable, then
86 * xyz.openbmc_project.Sensor.ValueMutability interface will be
87 * instantiated.
88 */
89 bool isValueMutable;
James Feistce3fca42018-11-21 12:58:24 -080090 double maxValue;
91 double minValue;
James Feist8fd8a582018-11-16 11:10:46 -080092 std::vector<thresholds::Threshold> thresholds;
93 std::shared_ptr<sdbusplus::asio::dbus_interface> sensorInterface;
James Feist078f2322019-03-08 11:09:05 -080094 std::shared_ptr<sdbusplus::asio::dbus_interface> association;
James Feist67601bd2020-06-16 17:14:44 -070095 std::shared_ptr<sdbusplus::asio::dbus_interface> availableInterface;
James Feist961bf092020-07-01 16:38:12 -070096 std::shared_ptr<sdbusplus::asio::dbus_interface> operationalInterface;
Jie Yang3291b9c2021-07-29 14:46:51 -070097 std::shared_ptr<sdbusplus::asio::dbus_interface> valueMutabilityInterface;
James Feist8fd8a582018-11-16 11:10:46 -080098 double value = std::numeric_limits<double>::quiet_NaN();
Zhikui Rend3da1282020-09-11 17:02:01 -070099 double rawValue = std::numeric_limits<double>::quiet_NaN();
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530100 bool overriddenState = false;
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530101 bool internalSet = false;
Josh Lehan883fb3a2020-02-27 14:41:39 -0800102 double hysteresisTrigger;
103 double hysteresisPublish;
James Feiste3338522020-09-15 15:40:30 -0700104 std::shared_ptr<sdbusplus::asio::connection> dbusConnection;
James Feist961bf092020-07-01 16:38:12 -0700105 PowerState readState;
Ed Tanousb429f312022-06-27 16:09:53 -0700106 size_t errCount{0};
Josh Lehan3bcd8232020-10-29 00:22:12 -0700107 std::unique_ptr<SensorInstrumentation> instrumentation;
108
Josh Lehanffe18342021-03-17 13:29:51 -0700109 // This member variable provides a hook that can be used to receive
110 // notification whenever this Sensor's value is externally set via D-Bus.
111 // If interested, assign your own lambda to this variable, during
112 // construction of your Sensor subclass. See ExternalSensor for example.
113 std::function<void()> externalSetHook;
114
Ed Tanousc8fed202022-01-12 14:24:45 -0800115 using Level = thresholds::Level;
116 using Direction = thresholds::Direction;
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530117
Ed Tanousc8fed202022-01-12 14:24:45 -0800118 std::array<std::shared_ptr<sdbusplus::asio::dbus_interface>,
119 thresholds::thresProp.size()>
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530120 thresholdInterfaces;
121
122 std::shared_ptr<sdbusplus::asio::dbus_interface>
Ed Tanousc8fed202022-01-12 14:24:45 -0800123 getThresholdInterface(Level lev)
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530124 {
125 size_t index = static_cast<size_t>(lev);
126 if (index >= thresholdInterfaces.size())
127 {
128 std::cout << "Unknown threshold level \n";
129 return nullptr;
130 }
131 std::shared_ptr<sdbusplus::asio::dbus_interface> interface =
132 thresholdInterfaces[index];
133 return interface;
134 }
135
Ed Tanous2049bd22022-07-09 07:20:26 -0700136 void updateInstrumentation(double readValue) const
Josh Lehan3bcd8232020-10-29 00:22:12 -0700137 {
138 // Do nothing if this feature is not enabled
139 if constexpr (!enableInstrumentation)
140 {
141 return;
142 }
143 if (!instrumentation)
144 {
145 return;
146 }
147
148 // Save some typing
149 auto& inst = *instrumentation;
150
151 // Show constants if first reading (even if unsuccessful)
152 if ((inst.numCollectsGood == 0) && (inst.numCollectsMiss == 0))
153 {
154 std::cerr << "Sensor " << name << ": Configuration min=" << minValue
155 << ", max=" << maxValue << ", type=" << objectType
156 << ", path=" << configurationPath << "\n";
157 }
158
159 // Sensors can use "nan" to indicate unavailable reading
160 if (!std::isfinite(readValue))
161 {
162 // Only show this if beginning a new streak
163 if (inst.numStreakMisses == 0)
164 {
165 std::cerr << "Sensor " << name
166 << ": Missing reading, Reading counts good="
167 << inst.numCollectsGood
168 << ", miss=" << inst.numCollectsMiss
169 << ", Prior good streak=" << inst.numStreakGreats
170 << "\n";
171 }
172
173 inst.numStreakGreats = 0;
174 ++(inst.numCollectsMiss);
175 ++(inst.numStreakMisses);
176
177 return;
178 }
179
180 // Only show this if beginning a new streak and not the first time
181 if ((inst.numStreakGreats == 0) && (inst.numCollectsGood != 0))
182 {
183 std::cerr << "Sensor " << name
184 << ": Recovered reading, Reading counts good="
185 << inst.numCollectsGood
186 << ", miss=" << inst.numCollectsMiss
187 << ", Prior miss streak=" << inst.numStreakMisses << "\n";
188 }
189
190 // Initialize min/max if the first successful reading
191 if (inst.numCollectsGood == 0)
192 {
193 std::cerr << "Sensor " << name << ": First reading=" << readValue
194 << "\n";
195
196 inst.minCollected = readValue;
197 inst.maxCollected = readValue;
198 }
199
200 inst.numStreakMisses = 0;
201 ++(inst.numCollectsGood);
202 ++(inst.numStreakGreats);
203
204 // Only provide subsequent output if new min/max established
205 if (readValue < inst.minCollected)
206 {
207 std::cerr << "Sensor " << name << ": Lowest reading=" << readValue
208 << "\n";
209
210 inst.minCollected = readValue;
211 }
212
213 if (readValue > inst.maxCollected)
214 {
215 std::cerr << "Sensor " << name << ": Highest reading=" << readValue
216 << "\n";
217
218 inst.maxCollected = readValue;
219 }
220 }
James Feistce3fca42018-11-21 12:58:24 -0800221
James Feistd8705872019-02-08 13:26:09 -0800222 int setSensorValue(const double& newValue, double& oldValue)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530223 {
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +0530224 if (!internalSet)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530225 {
Jonathan Doman256d8c12022-06-03 13:01:08 -0700226 if (insecureSensorOverride == 0 && !isSensorSettable &&
227 !getManufacturingMode())
228 {
229 throw SetSensorError();
Bruce Lee1263c3d2021-06-04 15:16:33 +0800230 }
231
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530232 oldValue = newValue;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530233 overriddenState = true;
234 // check thresholds for external set
235 value = newValue;
236 checkThresholds();
Josh Lehanffe18342021-03-17 13:29:51 -0700237
238 // Trigger the hook, as an external set has just happened
239 if (externalSetHook)
240 {
241 externalSetHook();
242 }
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530243 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530244 else if (!overriddenState)
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +0530245 {
246 oldValue = newValue;
247 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700248 return 1;
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530249 }
James Feistce3fca42018-11-21 12:58:24 -0800250
Andrei Kartashev39287412022-02-04 16:04:47 +0300251 void setInitialProperties(const std::string& unit,
252 const std::string& label = std::string(),
253 size_t thresholdSize = 0)
James Feistce3fca42018-11-21 12:58:24 -0800254 {
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700255 if (readState == PowerState::on || readState == PowerState::biosPost ||
256 readState == PowerState::chassisOn)
James Feist961bf092020-07-01 16:38:12 -0700257 {
Andrei Kartashev39287412022-02-04 16:04:47 +0300258 setupPowerMatch(dbusConnection);
James Feist961bf092020-07-01 16:38:12 -0700259 }
260
James Feist82bac4c2019-03-11 11:16:53 -0700261 createAssociation(association, configurationPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +0530262
Zev Weiss6b6891c2021-04-22 02:46:21 -0500263 sensorInterface->register_property("Unit", unit);
James Feistce3fca42018-11-21 12:58:24 -0800264 sensorInterface->register_property("MaxValue", maxValue);
265 sensorInterface->register_property("MinValue", minValue);
266 sensorInterface->register_property(
Jonathan Doman256d8c12022-06-03 13:01:08 -0700267 "Value", value, [this](const double& newValue, double& oldValue) {
James Feistce3fca42018-11-21 12:58:24 -0800268 return setSensorValue(newValue, oldValue);
269 });
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300270
271 fillMissingThresholds();
272
James Feistd8705872019-02-08 13:26:09 -0800273 for (auto& threshold : thresholds)
James Feistce3fca42018-11-21 12:58:24 -0800274 {
Rashmica Gupta1e34cec2021-08-31 16:47:39 +1000275 if (std::isnan(threshold.hysteresis))
276 {
277 threshold.hysteresis = hysteresisTrigger;
278 }
Ed Tanous17551b82022-01-26 16:47:17 -0800279
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530280 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
281 getThresholdInterface(threshold.level);
282
James Feistce3fca42018-11-21 12:58:24 -0800283 if (!iface)
284 {
285 std::cout << "trying to set uninitialized interface\n";
286 continue;
287 }
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800288
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530289 std::string level =
290 propertyLevel(threshold.level, threshold.direction);
291 std::string alarm =
292 propertyAlarm(threshold.level, threshold.direction);
293
294 if ((level.empty()) || (alarm.empty()))
295 {
296 continue;
297 }
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800298 size_t thresSize =
299 label.empty() ? thresholds.size() : thresholdSize;
James Feistce3fca42018-11-21 12:58:24 -0800300 iface->register_property(
301 level, threshold.value,
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800302 [&, label, thresSize](const double& request, double& oldValue) {
Ed Tanousbb679322022-05-16 16:10:00 -0700303 oldValue = request; // todo, just let the config do this?
304 threshold.value = request;
305 thresholds::persistThreshold(configurationPath, objectType,
306 threshold, dbusConnection,
307 thresSize, label);
308 // Invalidate previously remembered value,
309 // so new thresholds will be checked during next update,
310 // even if sensor reading remains unchanged.
311 value = std::numeric_limits<double>::quiet_NaN();
Josh Lehan883fb3a2020-02-27 14:41:39 -0800312
Ed Tanousbb679322022-05-16 16:10:00 -0700313 // Although tempting, don't call checkThresholds() from here
314 // directly. Let the regular sensor monitor call the same
315 // using updateValue(), which can check conditions like
316 // poweron, etc., before raising any event.
317 return 1;
James Feistce3fca42018-11-21 12:58:24 -0800318 });
319 iface->register_property(alarm, false);
320 }
321 if (!sensorInterface->initialize())
322 {
323 std::cerr << "error initializing value interface\n";
324 }
James Feistce3fca42018-11-21 12:58:24 -0800325
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530326 for (auto& thresIface : thresholdInterfaces)
James Feistce3fca42018-11-21 12:58:24 -0800327 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530328 if (thresIface)
329 {
330 if (!thresIface->initialize(true))
331 {
332 std::cerr << "Error initializing threshold interface \n";
333 }
334 }
James Feistce3fca42018-11-21 12:58:24 -0800335 }
James Feist67601bd2020-06-16 17:14:44 -0700336
Jie Yang3291b9c2021-07-29 14:46:51 -0700337 if (isValueMutable)
338 {
339 valueMutabilityInterface =
340 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300341 dbusConnection, sensorInterface->get_object_path(),
Jie Yang3291b9c2021-07-29 14:46:51 -0700342 valueMutabilityInterfaceName);
343 valueMutabilityInterface->register_property("Mutable", true);
344 if (!valueMutabilityInterface->initialize())
345 {
346 std::cerr
347 << "error initializing sensor value mutability interface\n";
348 valueMutabilityInterface = nullptr;
349 }
350 }
351
James Feist67601bd2020-06-16 17:14:44 -0700352 if (!availableInterface)
353 {
354 availableInterface =
355 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300356 dbusConnection, sensorInterface->get_object_path(),
James Feist67601bd2020-06-16 17:14:44 -0700357 availableInterfaceName);
358 availableInterface->register_property(
359 "Available", true, [this](const bool propIn, bool& old) {
360 if (propIn == old)
361 {
362 return 1;
363 }
James Feist961bf092020-07-01 16:38:12 -0700364 old = propIn;
James Feist67601bd2020-06-16 17:14:44 -0700365 if (!propIn)
366 {
367 updateValue(std::numeric_limits<double>::quiet_NaN());
368 }
James Feist67601bd2020-06-16 17:14:44 -0700369 return 1;
370 });
371 availableInterface->initialize();
372 }
James Feist961bf092020-07-01 16:38:12 -0700373 if (!operationalInterface)
374 {
375 operationalInterface =
376 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300377 dbusConnection, sensorInterface->get_object_path(),
James Feist961bf092020-07-01 16:38:12 -0700378 operationalInterfaceName);
379 operationalInterface->register_property("Functional", true);
380 operationalInterface->initialize();
381 }
382 }
383
Ed Tanous2049bd22022-07-09 07:20:26 -0700384 static std::string propertyLevel(const Level lev, const Direction dir)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530385 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800386 for (const thresholds::ThresholdDefinition& prop :
387 thresholds::thresProp)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530388 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800389 if (prop.level == lev)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530390 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800391 if (dir == Direction::HIGH)
392 {
393 return std::string(prop.levelName) + "High";
394 }
395 if (dir == Direction::LOW)
396 {
397 return std::string(prop.levelName) + "Low";
398 }
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530399 }
400 }
401 return "";
402 }
403
Ed Tanous2049bd22022-07-09 07:20:26 -0700404 static std::string propertyAlarm(const Level lev, const Direction dir)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530405 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800406 for (const thresholds::ThresholdDefinition& prop :
407 thresholds::thresProp)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530408 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800409 if (prop.level == lev)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530410 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800411 if (dir == Direction::HIGH)
412 {
413 return std::string(prop.levelName) + "AlarmHigh";
414 }
415 if (dir == Direction::LOW)
416 {
417 return std::string(prop.levelName) + "AlarmLow";
418 }
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530419 }
420 }
421 return "";
422 }
423
Ed Tanous2049bd22022-07-09 07:20:26 -0700424 bool readingStateGood() const
James Feist961bf092020-07-01 16:38:12 -0700425 {
Zev Weissece5c862022-08-05 14:34:59 -0700426 return ::readingStateGood(readState);
James Feist961bf092020-07-01 16:38:12 -0700427 }
428
429 void markFunctional(bool isFunctional)
430 {
431 if (operationalInterface)
432 {
433 operationalInterface->set_property("Functional", isFunctional);
434 }
435 if (isFunctional)
436 {
437 errCount = 0;
438 }
439 else
440 {
441 updateValue(std::numeric_limits<double>::quiet_NaN());
442 }
443 }
444
445 void markAvailable(bool isAvailable)
446 {
447 if (availableInterface)
448 {
449 availableInterface->set_property("Available", isAvailable);
450 errCount = 0;
451 }
452 }
453
454 void incrementError()
455 {
456 if (!readingStateGood())
457 {
458 markAvailable(false);
459 return;
460 }
461
462 if (errCount >= errorThreshold)
463 {
464 return;
465 }
466
467 errCount++;
468 if (errCount == errorThreshold)
469 {
470 std::cerr << "Sensor " << name << " reading error!\n";
471 markFunctional(false);
472 }
James Feistce3fca42018-11-21 12:58:24 -0800473 }
474
Ed Tanous2049bd22022-07-09 07:20:26 -0700475 bool inError() const
Andrew Jefferyfad36052022-03-15 21:44:44 +1030476 {
477 return errCount >= errorThreshold;
478 }
479
James Feistd8705872019-02-08 13:26:09 -0800480 void updateValue(const double& newValue)
James Feistce3fca42018-11-21 12:58:24 -0800481 {
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530482 // Ignore if overriding is enabled
James Feist961bf092020-07-01 16:38:12 -0700483 if (overriddenState)
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530484 {
Josh Lehan883fb3a2020-02-27 14:41:39 -0800485 return;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530486 }
Josh Lehan883fb3a2020-02-27 14:41:39 -0800487
James Feist961bf092020-07-01 16:38:12 -0700488 if (!readingStateGood())
489 {
490 markAvailable(false);
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200491 updateValueProperty(std::numeric_limits<double>::quiet_NaN());
James Feist961bf092020-07-01 16:38:12 -0700492 return;
493 }
494
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200495 updateValueProperty(newValue);
Josh Lehan3bcd8232020-10-29 00:22:12 -0700496 updateInstrumentation(newValue);
Josh Lehan883fb3a2020-02-27 14:41:39 -0800497
498 // Always check thresholds after changing the value,
499 // as the test against hysteresisTrigger now takes place in
500 // the thresholds::checkThresholds() method,
501 // which is called by checkThresholds() below,
502 // in all current implementations of sensors that have thresholds.
503 checkThresholds();
James Feist961bf092020-07-01 16:38:12 -0700504 if (!std::isnan(newValue))
505 {
506 markFunctional(true);
507 markAvailable(true);
508 }
James Feistce3fca42018-11-21 12:58:24 -0800509 }
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200510
511 void updateProperty(
512 std::shared_ptr<sdbusplus::asio::dbus_interface>& interface,
Ed Tanous2049bd22022-07-09 07:20:26 -0700513 double& oldValue, const double& newValue,
514 const char* dbusPropertyName) const
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200515 {
516 if (requiresUpdate(oldValue, newValue))
517 {
518 oldValue = newValue;
Jae Hyun Yoo1a540b82020-07-30 23:33:18 -0700519 if (interface &&
520 !(interface->set_property(dbusPropertyName, newValue)))
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200521 {
522 std::cerr << "error setting property " << dbusPropertyName
523 << " to " << newValue << "\n";
524 }
525 }
526 }
527
Ed Tanous2049bd22022-07-09 07:20:26 -0700528 bool requiresUpdate(const double& lVal, const double& rVal) const
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200529 {
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000530 const auto lNan = std::isnan(lVal);
531 const auto rNan = std::isnan(rVal);
532 if (lNan || rNan)
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200533 {
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000534 return (lNan != rNan);
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200535 }
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000536 return std::abs(lVal - rVal) > hysteresisPublish;
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200537 }
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200538
539 private:
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300540 // If one of the thresholds for a dbus interface is provided
541 // we have to set the other one as dbus properties are never
542 // optional.
543 void fillMissingThresholds()
544 {
545 for (thresholds::Threshold& thisThreshold : thresholds)
546 {
547 bool foundOpposite = false;
548 thresholds::Direction opposite = thresholds::Direction::HIGH;
549 if (thisThreshold.direction == thresholds::Direction::HIGH)
550 {
551 opposite = thresholds::Direction::LOW;
552 }
553 for (thresholds::Threshold& otherThreshold : thresholds)
554 {
555 if (thisThreshold.level != otherThreshold.level)
556 {
557 continue;
558 }
559 if (otherThreshold.direction != opposite)
560 {
561 continue;
562 }
563 foundOpposite = true;
564 break;
565 }
566 if (foundOpposite)
567 {
568 continue;
569 }
570 thresholds.emplace_back(thisThreshold.level, opposite,
571 std::numeric_limits<double>::quiet_NaN());
572 }
573 }
574
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200575 void updateValueProperty(const double& newValue)
576 {
577 // Indicate that it is internal set call, not an external overwrite
578 internalSet = true;
579 updateProperty(sensorInterface, value, newValue, "Value");
580 internalSet = false;
581 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530582};