blob: 2bc55f526361f85c84c2173d4f7304729afa08ff [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)),
James Feist930fcde2019-05-28 12:58:43 -070066 configurationPath(configurationPath), objectType(objectType),
Jie Yang3291b9c2021-07-29 14:46:51 -070067 isSensorSettable(isSettable), isValueMutable(isMutable), maxValue(max),
68 minValue(min), thresholds(std::move(thresholdData)),
Josh Lehan883fb3a2020-02-27 14:41:39 -080069 hysteresisTrigger((max - min) * 0.01),
James Feiste3338522020-09-15 15:40:30 -070070 hysteresisPublish((max - min) * 0.0001), dbusConnection(conn),
Ed Tanousb429f312022-06-27 16:09:53 -070071 readState(readState),
Josh Lehan3bcd8232020-10-29 00:22:12 -070072 instrumentation(enableInstrumentation
73 ? std::make_unique<SensorInstrumentation>()
74 : nullptr)
James Feist38fb5982020-05-28 10:09:54 -070075 {}
James Feist8fd8a582018-11-16 11:10:46 -080076 virtual ~Sensor() = default;
James Feistce3fca42018-11-21 12:58:24 -080077 virtual void checkThresholds(void) = 0;
James Feistdc6c55f2018-10-31 12:53:20 -070078 std::string name;
James Feistce3fca42018-11-21 12:58:24 -080079 std::string configurationPath;
80 std::string objectType;
Bruce Lee1263c3d2021-06-04 15:16:33 +080081 bool isSensorSettable;
Jie Yang3291b9c2021-07-29 14:46:51 -070082
83 /* A flag indicates if properties of xyz.openbmc_project.Sensor.Value
84 * interface are mutable. If mutable, then
85 * xyz.openbmc_project.Sensor.ValueMutability interface will be
86 * instantiated.
87 */
88 bool isValueMutable;
James Feistce3fca42018-11-21 12:58:24 -080089 double maxValue;
90 double minValue;
James Feist8fd8a582018-11-16 11:10:46 -080091 std::vector<thresholds::Threshold> thresholds;
92 std::shared_ptr<sdbusplus::asio::dbus_interface> sensorInterface;
James Feist078f2322019-03-08 11:09:05 -080093 std::shared_ptr<sdbusplus::asio::dbus_interface> association;
James Feist67601bd2020-06-16 17:14:44 -070094 std::shared_ptr<sdbusplus::asio::dbus_interface> availableInterface;
James Feist961bf092020-07-01 16:38:12 -070095 std::shared_ptr<sdbusplus::asio::dbus_interface> operationalInterface;
Jie Yang3291b9c2021-07-29 14:46:51 -070096 std::shared_ptr<sdbusplus::asio::dbus_interface> valueMutabilityInterface;
James Feist8fd8a582018-11-16 11:10:46 -080097 double value = std::numeric_limits<double>::quiet_NaN();
Zhikui Rend3da1282020-09-11 17:02:01 -070098 double rawValue = std::numeric_limits<double>::quiet_NaN();
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +053099 bool overriddenState = false;
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530100 bool internalSet = false;
Josh Lehan883fb3a2020-02-27 14:41:39 -0800101 double hysteresisTrigger;
102 double hysteresisPublish;
James Feiste3338522020-09-15 15:40:30 -0700103 std::shared_ptr<sdbusplus::asio::connection> dbusConnection;
James Feist961bf092020-07-01 16:38:12 -0700104 PowerState readState;
Ed Tanousb429f312022-06-27 16:09:53 -0700105 size_t errCount{0};
Josh Lehan3bcd8232020-10-29 00:22:12 -0700106 std::unique_ptr<SensorInstrumentation> instrumentation;
107
Josh Lehanffe18342021-03-17 13:29:51 -0700108 // This member variable provides a hook that can be used to receive
109 // notification whenever this Sensor's value is externally set via D-Bus.
110 // If interested, assign your own lambda to this variable, during
111 // construction of your Sensor subclass. See ExternalSensor for example.
112 std::function<void()> externalSetHook;
113
Ed Tanousc8fed202022-01-12 14:24:45 -0800114 using Level = thresholds::Level;
115 using Direction = thresholds::Direction;
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530116
Ed Tanousc8fed202022-01-12 14:24:45 -0800117 std::array<std::shared_ptr<sdbusplus::asio::dbus_interface>,
118 thresholds::thresProp.size()>
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530119 thresholdInterfaces;
120
121 std::shared_ptr<sdbusplus::asio::dbus_interface>
Ed Tanousc8fed202022-01-12 14:24:45 -0800122 getThresholdInterface(Level lev)
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530123 {
124 size_t index = static_cast<size_t>(lev);
125 if (index >= thresholdInterfaces.size())
126 {
127 std::cout << "Unknown threshold level \n";
128 return nullptr;
129 }
130 std::shared_ptr<sdbusplus::asio::dbus_interface> interface =
131 thresholdInterfaces[index];
132 return interface;
133 }
134
Ed Tanous2049bd22022-07-09 07:20:26 -0700135 void updateInstrumentation(double readValue) const
Josh Lehan3bcd8232020-10-29 00:22:12 -0700136 {
137 // Do nothing if this feature is not enabled
138 if constexpr (!enableInstrumentation)
139 {
140 return;
141 }
142 if (!instrumentation)
143 {
144 return;
145 }
146
147 // Save some typing
148 auto& inst = *instrumentation;
149
150 // Show constants if first reading (even if unsuccessful)
151 if ((inst.numCollectsGood == 0) && (inst.numCollectsMiss == 0))
152 {
153 std::cerr << "Sensor " << name << ": Configuration min=" << minValue
154 << ", max=" << maxValue << ", type=" << objectType
155 << ", path=" << configurationPath << "\n";
156 }
157
158 // Sensors can use "nan" to indicate unavailable reading
159 if (!std::isfinite(readValue))
160 {
161 // Only show this if beginning a new streak
162 if (inst.numStreakMisses == 0)
163 {
164 std::cerr << "Sensor " << name
165 << ": Missing reading, Reading counts good="
166 << inst.numCollectsGood
167 << ", miss=" << inst.numCollectsMiss
168 << ", Prior good streak=" << inst.numStreakGreats
169 << "\n";
170 }
171
172 inst.numStreakGreats = 0;
173 ++(inst.numCollectsMiss);
174 ++(inst.numStreakMisses);
175
176 return;
177 }
178
179 // Only show this if beginning a new streak and not the first time
180 if ((inst.numStreakGreats == 0) && (inst.numCollectsGood != 0))
181 {
182 std::cerr << "Sensor " << name
183 << ": Recovered reading, Reading counts good="
184 << inst.numCollectsGood
185 << ", miss=" << inst.numCollectsMiss
186 << ", Prior miss streak=" << inst.numStreakMisses << "\n";
187 }
188
189 // Initialize min/max if the first successful reading
190 if (inst.numCollectsGood == 0)
191 {
192 std::cerr << "Sensor " << name << ": First reading=" << readValue
193 << "\n";
194
195 inst.minCollected = readValue;
196 inst.maxCollected = readValue;
197 }
198
199 inst.numStreakMisses = 0;
200 ++(inst.numCollectsGood);
201 ++(inst.numStreakGreats);
202
203 // Only provide subsequent output if new min/max established
204 if (readValue < inst.minCollected)
205 {
206 std::cerr << "Sensor " << name << ": Lowest reading=" << readValue
207 << "\n";
208
209 inst.minCollected = readValue;
210 }
211
212 if (readValue > inst.maxCollected)
213 {
214 std::cerr << "Sensor " << name << ": Highest reading=" << readValue
215 << "\n";
216
217 inst.maxCollected = readValue;
218 }
219 }
James Feistce3fca42018-11-21 12:58:24 -0800220
James Feistd8705872019-02-08 13:26:09 -0800221 int setSensorValue(const double& newValue, double& oldValue)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530222 {
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +0530223 if (!internalSet)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530224 {
Jonathan Doman256d8c12022-06-03 13:01:08 -0700225 if (insecureSensorOverride == 0 && !isSensorSettable &&
226 !getManufacturingMode())
227 {
228 throw SetSensorError();
Bruce Lee1263c3d2021-06-04 15:16:33 +0800229 }
230
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530231 oldValue = newValue;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530232 overriddenState = true;
233 // check thresholds for external set
234 value = newValue;
235 checkThresholds();
Josh Lehanffe18342021-03-17 13:29:51 -0700236
237 // Trigger the hook, as an external set has just happened
238 if (externalSetHook)
239 {
240 externalSetHook();
241 }
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530242 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530243 else if (!overriddenState)
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +0530244 {
245 oldValue = newValue;
246 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700247 return 1;
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530248 }
James Feistce3fca42018-11-21 12:58:24 -0800249
Andrei Kartashev39287412022-02-04 16:04:47 +0300250 void setInitialProperties(const std::string& unit,
251 const std::string& label = std::string(),
252 size_t thresholdSize = 0)
James Feistce3fca42018-11-21 12:58:24 -0800253 {
James Feist961bf092020-07-01 16:38:12 -0700254 if (readState == PowerState::on || readState == PowerState::biosPost)
255 {
Andrei Kartashev39287412022-02-04 16:04:47 +0300256 setupPowerMatch(dbusConnection);
James Feist961bf092020-07-01 16:38:12 -0700257 }
258
James Feist82bac4c2019-03-11 11:16:53 -0700259 createAssociation(association, configurationPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +0530260
Zev Weiss6b6891c2021-04-22 02:46:21 -0500261 sensorInterface->register_property("Unit", unit);
James Feistce3fca42018-11-21 12:58:24 -0800262 sensorInterface->register_property("MaxValue", maxValue);
263 sensorInterface->register_property("MinValue", minValue);
264 sensorInterface->register_property(
Jonathan Doman256d8c12022-06-03 13:01:08 -0700265 "Value", value, [this](const double& newValue, double& oldValue) {
James Feistce3fca42018-11-21 12:58:24 -0800266 return setSensorValue(newValue, oldValue);
267 });
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300268
269 fillMissingThresholds();
270
James Feistd8705872019-02-08 13:26:09 -0800271 for (auto& threshold : thresholds)
James Feistce3fca42018-11-21 12:58:24 -0800272 {
Rashmica Gupta1e34cec2021-08-31 16:47:39 +1000273 if (std::isnan(threshold.hysteresis))
274 {
275 threshold.hysteresis = hysteresisTrigger;
276 }
Ed Tanous17551b82022-01-26 16:47:17 -0800277
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530278 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
279 getThresholdInterface(threshold.level);
280
James Feistce3fca42018-11-21 12:58:24 -0800281 if (!iface)
282 {
283 std::cout << "trying to set uninitialized interface\n";
284 continue;
285 }
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800286
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530287 std::string level =
288 propertyLevel(threshold.level, threshold.direction);
289 std::string alarm =
290 propertyAlarm(threshold.level, threshold.direction);
291
292 if ((level.empty()) || (alarm.empty()))
293 {
294 continue;
295 }
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800296 size_t thresSize =
297 label.empty() ? thresholds.size() : thresholdSize;
James Feistce3fca42018-11-21 12:58:24 -0800298 iface->register_property(
299 level, threshold.value,
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800300 [&, label, thresSize](const double& request, double& oldValue) {
Ed Tanousbb679322022-05-16 16:10:00 -0700301 oldValue = request; // todo, just let the config do this?
302 threshold.value = request;
303 thresholds::persistThreshold(configurationPath, objectType,
304 threshold, dbusConnection,
305 thresSize, label);
306 // Invalidate previously remembered value,
307 // so new thresholds will be checked during next update,
308 // even if sensor reading remains unchanged.
309 value = std::numeric_limits<double>::quiet_NaN();
Josh Lehan883fb3a2020-02-27 14:41:39 -0800310
Ed Tanousbb679322022-05-16 16:10:00 -0700311 // Although tempting, don't call checkThresholds() from here
312 // directly. Let the regular sensor monitor call the same
313 // using updateValue(), which can check conditions like
314 // poweron, etc., before raising any event.
315 return 1;
James Feistce3fca42018-11-21 12:58:24 -0800316 });
317 iface->register_property(alarm, false);
318 }
319 if (!sensorInterface->initialize())
320 {
321 std::cerr << "error initializing value interface\n";
322 }
James Feistce3fca42018-11-21 12:58:24 -0800323
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530324 for (auto& thresIface : thresholdInterfaces)
James Feistce3fca42018-11-21 12:58:24 -0800325 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530326 if (thresIface)
327 {
328 if (!thresIface->initialize(true))
329 {
330 std::cerr << "Error initializing threshold interface \n";
331 }
332 }
James Feistce3fca42018-11-21 12:58:24 -0800333 }
James Feist67601bd2020-06-16 17:14:44 -0700334
Jie Yang3291b9c2021-07-29 14:46:51 -0700335 if (isValueMutable)
336 {
337 valueMutabilityInterface =
338 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300339 dbusConnection, sensorInterface->get_object_path(),
Jie Yang3291b9c2021-07-29 14:46:51 -0700340 valueMutabilityInterfaceName);
341 valueMutabilityInterface->register_property("Mutable", true);
342 if (!valueMutabilityInterface->initialize())
343 {
344 std::cerr
345 << "error initializing sensor value mutability interface\n";
346 valueMutabilityInterface = nullptr;
347 }
348 }
349
James Feist67601bd2020-06-16 17:14:44 -0700350 if (!availableInterface)
351 {
352 availableInterface =
353 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300354 dbusConnection, sensorInterface->get_object_path(),
James Feist67601bd2020-06-16 17:14:44 -0700355 availableInterfaceName);
356 availableInterface->register_property(
357 "Available", true, [this](const bool propIn, bool& old) {
358 if (propIn == old)
359 {
360 return 1;
361 }
James Feist961bf092020-07-01 16:38:12 -0700362 old = propIn;
James Feist67601bd2020-06-16 17:14:44 -0700363 if (!propIn)
364 {
365 updateValue(std::numeric_limits<double>::quiet_NaN());
366 }
James Feist67601bd2020-06-16 17:14:44 -0700367 return 1;
368 });
369 availableInterface->initialize();
370 }
James Feist961bf092020-07-01 16:38:12 -0700371 if (!operationalInterface)
372 {
373 operationalInterface =
374 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300375 dbusConnection, sensorInterface->get_object_path(),
James Feist961bf092020-07-01 16:38:12 -0700376 operationalInterfaceName);
377 operationalInterface->register_property("Functional", true);
378 operationalInterface->initialize();
379 }
380 }
381
Ed Tanous2049bd22022-07-09 07:20:26 -0700382 static std::string propertyLevel(const Level lev, const Direction dir)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530383 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800384 for (const thresholds::ThresholdDefinition& prop :
385 thresholds::thresProp)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530386 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800387 if (prop.level == lev)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530388 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800389 if (dir == Direction::HIGH)
390 {
391 return std::string(prop.levelName) + "High";
392 }
393 if (dir == Direction::LOW)
394 {
395 return std::string(prop.levelName) + "Low";
396 }
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530397 }
398 }
399 return "";
400 }
401
Ed Tanous2049bd22022-07-09 07:20:26 -0700402 static std::string propertyAlarm(const Level lev, const Direction dir)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530403 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800404 for (const thresholds::ThresholdDefinition& prop :
405 thresholds::thresProp)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530406 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800407 if (prop.level == lev)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530408 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800409 if (dir == Direction::HIGH)
410 {
411 return std::string(prop.levelName) + "AlarmHigh";
412 }
413 if (dir == Direction::LOW)
414 {
415 return std::string(prop.levelName) + "AlarmLow";
416 }
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530417 }
418 }
419 return "";
420 }
421
Ed Tanous2049bd22022-07-09 07:20:26 -0700422 bool readingStateGood() const
James Feist961bf092020-07-01 16:38:12 -0700423 {
424 if (readState == PowerState::on && !isPowerOn())
425 {
426 return false;
427 }
428 if (readState == PowerState::biosPost &&
429 (!hasBiosPost() || !isPowerOn()))
430 {
431 return false;
432 }
433
434 return true;
435 }
436
437 void markFunctional(bool isFunctional)
438 {
439 if (operationalInterface)
440 {
441 operationalInterface->set_property("Functional", isFunctional);
442 }
443 if (isFunctional)
444 {
445 errCount = 0;
446 }
447 else
448 {
449 updateValue(std::numeric_limits<double>::quiet_NaN());
450 }
451 }
452
453 void markAvailable(bool isAvailable)
454 {
455 if (availableInterface)
456 {
457 availableInterface->set_property("Available", isAvailable);
458 errCount = 0;
459 }
460 }
461
462 void incrementError()
463 {
464 if (!readingStateGood())
465 {
466 markAvailable(false);
467 return;
468 }
469
470 if (errCount >= errorThreshold)
471 {
472 return;
473 }
474
475 errCount++;
476 if (errCount == errorThreshold)
477 {
478 std::cerr << "Sensor " << name << " reading error!\n";
479 markFunctional(false);
480 }
James Feistce3fca42018-11-21 12:58:24 -0800481 }
482
Ed Tanous2049bd22022-07-09 07:20:26 -0700483 bool inError() const
Andrew Jefferyfad36052022-03-15 21:44:44 +1030484 {
485 return errCount >= errorThreshold;
486 }
487
James Feistd8705872019-02-08 13:26:09 -0800488 void updateValue(const double& newValue)
James Feistce3fca42018-11-21 12:58:24 -0800489 {
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530490 // Ignore if overriding is enabled
James Feist961bf092020-07-01 16:38:12 -0700491 if (overriddenState)
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530492 {
Josh Lehan883fb3a2020-02-27 14:41:39 -0800493 return;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530494 }
Josh Lehan883fb3a2020-02-27 14:41:39 -0800495
James Feist961bf092020-07-01 16:38:12 -0700496 if (!readingStateGood())
497 {
498 markAvailable(false);
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200499 updateValueProperty(std::numeric_limits<double>::quiet_NaN());
James Feist961bf092020-07-01 16:38:12 -0700500 return;
501 }
502
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200503 updateValueProperty(newValue);
Josh Lehan3bcd8232020-10-29 00:22:12 -0700504 updateInstrumentation(newValue);
Josh Lehan883fb3a2020-02-27 14:41:39 -0800505
506 // Always check thresholds after changing the value,
507 // as the test against hysteresisTrigger now takes place in
508 // the thresholds::checkThresholds() method,
509 // which is called by checkThresholds() below,
510 // in all current implementations of sensors that have thresholds.
511 checkThresholds();
James Feist961bf092020-07-01 16:38:12 -0700512 if (!std::isnan(newValue))
513 {
514 markFunctional(true);
515 markAvailable(true);
516 }
James Feistce3fca42018-11-21 12:58:24 -0800517 }
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200518
519 void updateProperty(
520 std::shared_ptr<sdbusplus::asio::dbus_interface>& interface,
Ed Tanous2049bd22022-07-09 07:20:26 -0700521 double& oldValue, const double& newValue,
522 const char* dbusPropertyName) const
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200523 {
524 if (requiresUpdate(oldValue, newValue))
525 {
526 oldValue = newValue;
Jae Hyun Yoo1a540b82020-07-30 23:33:18 -0700527 if (interface &&
528 !(interface->set_property(dbusPropertyName, newValue)))
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200529 {
530 std::cerr << "error setting property " << dbusPropertyName
531 << " to " << newValue << "\n";
532 }
533 }
534 }
535
Ed Tanous2049bd22022-07-09 07:20:26 -0700536 bool requiresUpdate(const double& lVal, const double& rVal) const
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200537 {
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000538 const auto lNan = std::isnan(lVal);
539 const auto rNan = std::isnan(rVal);
540 if (lNan || rNan)
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200541 {
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000542 return (lNan != rNan);
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200543 }
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000544 return std::abs(lVal - rVal) > hysteresisPublish;
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200545 }
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200546
547 private:
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300548 // If one of the thresholds for a dbus interface is provided
549 // we have to set the other one as dbus properties are never
550 // optional.
551 void fillMissingThresholds()
552 {
553 for (thresholds::Threshold& thisThreshold : thresholds)
554 {
555 bool foundOpposite = false;
556 thresholds::Direction opposite = thresholds::Direction::HIGH;
557 if (thisThreshold.direction == thresholds::Direction::HIGH)
558 {
559 opposite = thresholds::Direction::LOW;
560 }
561 for (thresholds::Threshold& otherThreshold : thresholds)
562 {
563 if (thisThreshold.level != otherThreshold.level)
564 {
565 continue;
566 }
567 if (otherThreshold.direction != opposite)
568 {
569 continue;
570 }
571 foundOpposite = true;
572 break;
573 }
574 if (foundOpposite)
575 {
576 continue;
577 }
578 thresholds.emplace_back(thisThreshold.level, opposite,
579 std::numeric_limits<double>::quiet_NaN());
580 }
581 }
582
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200583 void updateValueProperty(const double& newValue)
584 {
585 // Indicate that it is internal set call, not an external overwrite
586 internalSet = true;
587 updateProperty(sensorInterface, value, newValue, "Value");
588 internalSet = false;
589 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530590};