blob: 2eab853b1258bcacaa8cc16a1decf52973b66842 [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
Ed Tanous18b61862025-01-30 10:56:28 -08009#include <sdbusplus/asio/connection.hpp>
James Feist38fb5982020-05-28 10:09:54 -070010#include <sdbusplus/asio/object_server.hpp>
Jonathan Doman256d8c12022-06-03 13:01:08 -070011#include <sdbusplus/exception.hpp>
James Feist38fb5982020-05-28 10:09:54 -070012
Ed Tanous18b61862025-01-30 10:56:28 -080013#include <array>
14#include <cerrno>
15#include <cmath>
16#include <cstddef>
17#include <cstdlib>
18#include <functional>
19#include <iostream>
Patrick Venturefd6ba732019-10-31 14:27:39 -070020#include <limits>
21#include <memory>
Patrick Venturefd6ba732019-10-31 14:27:39 -070022#include <string>
Ed Tanous18b61862025-01-30 10:56:28 -080023#include <utility>
Patrick Venturefd6ba732019-10-31 14:27:39 -070024#include <vector>
James Feist8fd8a582018-11-16 11:10:46 -080025
James Feist1169eb42018-10-31 10:08:47 -070026constexpr size_t sensorFailedPollTimeMs = 5000;
James Feista5e58722019-04-22 14:43:11 -070027
Josh Lehan3bcd8232020-10-29 00:22:12 -070028// Enable useful logging with sensor instrumentation
29// This is intentionally not DEBUG, avoid clash with usage in .cpp files
30constexpr bool enableInstrumentation = false;
31
James Feista5e58722019-04-22 14:43:11 -070032constexpr const char* sensorValueInterface = "xyz.openbmc_project.Sensor.Value";
Jie Yang3291b9c2021-07-29 14:46:51 -070033constexpr const char* valueMutabilityInterfaceName =
34 "xyz.openbmc_project.Sensor.ValueMutability";
James Feist67601bd2020-06-16 17:14:44 -070035constexpr const char* availableInterfaceName =
36 "xyz.openbmc_project.State.Decorator.Availability";
James Feist961bf092020-07-01 16:38:12 -070037constexpr const char* operationalInterfaceName =
38 "xyz.openbmc_project.State.Decorator.OperationalStatus";
39constexpr const size_t errorThreshold = 5;
40
Josh Lehan3bcd8232020-10-29 00:22:12 -070041struct SensorInstrumentation
42{
43 // These are for instrumentation for debugging
44 int numCollectsGood = 0;
45 int numCollectsMiss = 0;
46 int numStreakGreats = 0;
47 int numStreakMisses = 0;
48 double minCollected = 0.0;
49 double maxCollected = 0.0;
50};
51
Jonathan Doman256d8c12022-06-03 13:01:08 -070052struct SetSensorError : sdbusplus::exception_t
53{
54 const char* name() const noexcept override
55 {
56 return "xyz.openbmc_project.Common.Errors.NotAllowed";
57 }
58 const char* description() const noexcept override
59 {
60 return "Not allowed to set property value.";
61 }
62 int get_errno() const noexcept override
63 {
64 return EACCES;
65 }
66};
67
James Feist8fd8a582018-11-16 11:10:46 -080068struct Sensor
69{
James Feist930fcde2019-05-28 12:58:43 -070070 Sensor(const std::string& name,
James Feistd8705872019-02-08 13:26:09 -080071 std::vector<thresholds::Threshold>&& thresholdData,
72 const std::string& configurationPath, const std::string& objectType,
Jie Yang3291b9c2021-07-29 14:46:51 -070073 bool isSettable, bool isMutable, const double max, const double min,
James Feiste3338522020-09-15 15:40:30 -070074 std::shared_ptr<sdbusplus::asio::connection>& conn,
James Feist961bf092020-07-01 16:38:12 -070075 PowerState readState = PowerState::always) :
Ed Tanous6cb732a2021-02-18 15:33:51 -080076 name(sensor_paths::escapePathForDbus(name)),
Zev Weiss054aad82022-08-18 01:37:34 -070077 configurationPath(configurationPath),
Matt Spinler55832f32023-06-07 10:24:00 -050078 configInterface(configInterfaceName(objectType)),
Jie Yang3291b9c2021-07-29 14:46:51 -070079 isSensorSettable(isSettable), isValueMutable(isMutable), maxValue(max),
80 minValue(min), thresholds(std::move(thresholdData)),
Josh Lehan883fb3a2020-02-27 14:41:39 -080081 hysteresisTrigger((max - min) * 0.01),
James Feiste3338522020-09-15 15:40:30 -070082 hysteresisPublish((max - min) * 0.0001), dbusConnection(conn),
Ed Tanousb429f312022-06-27 16:09:53 -070083 readState(readState),
Josh Lehan3bcd8232020-10-29 00:22:12 -070084 instrumentation(enableInstrumentation
85 ? std::make_unique<SensorInstrumentation>()
86 : nullptr)
James Feist38fb5982020-05-28 10:09:54 -070087 {}
James Feist8fd8a582018-11-16 11:10:46 -080088 virtual ~Sensor() = default;
Ed Tanous201a1012024-04-03 18:07:28 -070089 virtual void checkThresholds() = 0;
James Feistdc6c55f2018-10-31 12:53:20 -070090 std::string name;
James Feistce3fca42018-11-21 12:58:24 -080091 std::string configurationPath;
Matt Spinler55832f32023-06-07 10:24:00 -050092 std::string configInterface;
Bruce Lee1263c3d2021-06-04 15:16:33 +080093 bool isSensorSettable;
Jie Yang3291b9c2021-07-29 14:46:51 -070094
95 /* A flag indicates if properties of xyz.openbmc_project.Sensor.Value
96 * interface are mutable. If mutable, then
97 * xyz.openbmc_project.Sensor.ValueMutability interface will be
98 * instantiated.
99 */
100 bool isValueMutable;
James Feistce3fca42018-11-21 12:58:24 -0800101 double maxValue;
102 double minValue;
James Feist8fd8a582018-11-16 11:10:46 -0800103 std::vector<thresholds::Threshold> thresholds;
104 std::shared_ptr<sdbusplus::asio::dbus_interface> sensorInterface;
James Feist078f2322019-03-08 11:09:05 -0800105 std::shared_ptr<sdbusplus::asio::dbus_interface> association;
James Feist67601bd2020-06-16 17:14:44 -0700106 std::shared_ptr<sdbusplus::asio::dbus_interface> availableInterface;
James Feist961bf092020-07-01 16:38:12 -0700107 std::shared_ptr<sdbusplus::asio::dbus_interface> operationalInterface;
Jie Yang3291b9c2021-07-29 14:46:51 -0700108 std::shared_ptr<sdbusplus::asio::dbus_interface> valueMutabilityInterface;
James Feist8fd8a582018-11-16 11:10:46 -0800109 double value = std::numeric_limits<double>::quiet_NaN();
Zhikui Rend3da1282020-09-11 17:02:01 -0700110 double rawValue = std::numeric_limits<double>::quiet_NaN();
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530111 bool overriddenState = false;
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530112 bool internalSet = false;
Josh Lehan883fb3a2020-02-27 14:41:39 -0800113 double hysteresisTrigger;
114 double hysteresisPublish;
James Feiste3338522020-09-15 15:40:30 -0700115 std::shared_ptr<sdbusplus::asio::connection> dbusConnection;
James Feist961bf092020-07-01 16:38:12 -0700116 PowerState readState;
Ed Tanousb429f312022-06-27 16:09:53 -0700117 size_t errCount{0};
Josh Lehan3bcd8232020-10-29 00:22:12 -0700118 std::unique_ptr<SensorInstrumentation> instrumentation;
119
Josh Lehanffe18342021-03-17 13:29:51 -0700120 // This member variable provides a hook that can be used to receive
121 // notification whenever this Sensor's value is externally set via D-Bus.
122 // If interested, assign your own lambda to this variable, during
123 // construction of your Sensor subclass. See ExternalSensor for example.
124 std::function<void()> externalSetHook;
125
Ed Tanousc8fed202022-01-12 14:24:45 -0800126 using Level = thresholds::Level;
127 using Direction = thresholds::Direction;
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530128
Ed Tanousc8fed202022-01-12 14:24:45 -0800129 std::array<std::shared_ptr<sdbusplus::asio::dbus_interface>,
130 thresholds::thresProp.size()>
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530131 thresholdInterfaces;
132
Patrick Williams556e04b2025-02-01 08:22:22 -0500133 std::shared_ptr<sdbusplus::asio::dbus_interface> getThresholdInterface(
134 Level lev)
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530135 {
136 size_t index = static_cast<size_t>(lev);
137 if (index >= thresholdInterfaces.size())
138 {
139 std::cout << "Unknown threshold level \n";
140 return nullptr;
141 }
142 std::shared_ptr<sdbusplus::asio::dbus_interface> interface =
143 thresholdInterfaces[index];
144 return interface;
145 }
146
Ed Tanous2049bd22022-07-09 07:20:26 -0700147 void updateInstrumentation(double readValue) const
Josh Lehan3bcd8232020-10-29 00:22:12 -0700148 {
149 // Do nothing if this feature is not enabled
150 if constexpr (!enableInstrumentation)
151 {
152 return;
153 }
154 if (!instrumentation)
155 {
156 return;
157 }
158
159 // Save some typing
160 auto& inst = *instrumentation;
161
162 // Show constants if first reading (even if unsuccessful)
163 if ((inst.numCollectsGood == 0) && (inst.numCollectsMiss == 0))
164 {
165 std::cerr << "Sensor " << name << ": Configuration min=" << minValue
Matt Spinler55832f32023-06-07 10:24:00 -0500166 << ", max=" << maxValue << ", type=" << configInterface
Josh Lehan3bcd8232020-10-29 00:22:12 -0700167 << ", path=" << configurationPath << "\n";
168 }
169
170 // Sensors can use "nan" to indicate unavailable reading
171 if (!std::isfinite(readValue))
172 {
173 // Only show this if beginning a new streak
174 if (inst.numStreakMisses == 0)
175 {
176 std::cerr << "Sensor " << name
177 << ": Missing reading, Reading counts good="
178 << inst.numCollectsGood
179 << ", miss=" << inst.numCollectsMiss
180 << ", Prior good streak=" << inst.numStreakGreats
181 << "\n";
182 }
183
184 inst.numStreakGreats = 0;
185 ++(inst.numCollectsMiss);
186 ++(inst.numStreakMisses);
187
188 return;
189 }
190
191 // Only show this if beginning a new streak and not the first time
192 if ((inst.numStreakGreats == 0) && (inst.numCollectsGood != 0))
193 {
194 std::cerr << "Sensor " << name
195 << ": Recovered reading, Reading counts good="
196 << inst.numCollectsGood
197 << ", miss=" << inst.numCollectsMiss
198 << ", Prior miss streak=" << inst.numStreakMisses << "\n";
199 }
200
201 // Initialize min/max if the first successful reading
202 if (inst.numCollectsGood == 0)
203 {
204 std::cerr << "Sensor " << name << ": First reading=" << readValue
205 << "\n";
206
207 inst.minCollected = readValue;
208 inst.maxCollected = readValue;
209 }
210
211 inst.numStreakMisses = 0;
212 ++(inst.numCollectsGood);
213 ++(inst.numStreakGreats);
214
215 // Only provide subsequent output if new min/max established
216 if (readValue < inst.minCollected)
217 {
218 std::cerr << "Sensor " << name << ": Lowest reading=" << readValue
219 << "\n";
220
221 inst.minCollected = readValue;
222 }
223
224 if (readValue > inst.maxCollected)
225 {
226 std::cerr << "Sensor " << name << ": Highest reading=" << readValue
227 << "\n";
228
229 inst.maxCollected = readValue;
230 }
231 }
James Feistce3fca42018-11-21 12:58:24 -0800232
James Feistd8705872019-02-08 13:26:09 -0800233 int setSensorValue(const double& newValue, double& oldValue)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530234 {
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +0530235 if (!internalSet)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530236 {
Jonathan Doman256d8c12022-06-03 13:01:08 -0700237 if (insecureSensorOverride == 0 && !isSensorSettable &&
238 !getManufacturingMode())
239 {
240 throw SetSensorError();
Bruce Lee1263c3d2021-06-04 15:16:33 +0800241 }
242
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530243 oldValue = newValue;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530244 overriddenState = true;
245 // check thresholds for external set
246 value = newValue;
247 checkThresholds();
Josh Lehanffe18342021-03-17 13:29:51 -0700248
249 // Trigger the hook, as an external set has just happened
250 if (externalSetHook)
251 {
252 externalSetHook();
253 }
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530254 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530255 else if (!overriddenState)
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +0530256 {
257 oldValue = newValue;
258 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700259 return 1;
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530260 }
James Feistce3fca42018-11-21 12:58:24 -0800261
Andrei Kartashev39287412022-02-04 16:04:47 +0300262 void setInitialProperties(const std::string& unit,
263 const std::string& label = std::string(),
264 size_t thresholdSize = 0)
James Feistce3fca42018-11-21 12:58:24 -0800265 {
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700266 if (readState == PowerState::on || readState == PowerState::biosPost ||
267 readState == PowerState::chassisOn)
James Feist961bf092020-07-01 16:38:12 -0700268 {
Andrei Kartashev39287412022-02-04 16:04:47 +0300269 setupPowerMatch(dbusConnection);
James Feist961bf092020-07-01 16:38:12 -0700270 }
271
James Feist82bac4c2019-03-11 11:16:53 -0700272 createAssociation(association, configurationPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +0530273
Zev Weiss6b6891c2021-04-22 02:46:21 -0500274 sensorInterface->register_property("Unit", unit);
James Feistce3fca42018-11-21 12:58:24 -0800275 sensorInterface->register_property("MaxValue", maxValue);
276 sensorInterface->register_property("MinValue", minValue);
277 sensorInterface->register_property(
Jonathan Doman256d8c12022-06-03 13:01:08 -0700278 "Value", value, [this](const double& newValue, double& oldValue) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400279 return setSensorValue(newValue, oldValue);
280 });
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300281
282 fillMissingThresholds();
283
James Feistd8705872019-02-08 13:26:09 -0800284 for (auto& threshold : thresholds)
James Feistce3fca42018-11-21 12:58:24 -0800285 {
Rashmica Gupta1e34cec2021-08-31 16:47:39 +1000286 if (std::isnan(threshold.hysteresis))
287 {
288 threshold.hysteresis = hysteresisTrigger;
289 }
Ed Tanous17551b82022-01-26 16:47:17 -0800290
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530291 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
292 getThresholdInterface(threshold.level);
293
James Feistce3fca42018-11-21 12:58:24 -0800294 if (!iface)
295 {
296 std::cout << "trying to set uninitialized interface\n";
297 continue;
298 }
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800299
Patrick Williams2aaf7172024-08-16 15:20:40 -0400300 std::string level =
301 propertyLevel(threshold.level, threshold.direction);
302 std::string alarm =
303 propertyAlarm(threshold.level, threshold.direction);
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530304
305 if ((level.empty()) || (alarm.empty()))
306 {
307 continue;
308 }
Patrick Williams2aaf7172024-08-16 15:20:40 -0400309 size_t thresSize =
310 label.empty() ? thresholds.size() : thresholdSize;
James Feistce3fca42018-11-21 12:58:24 -0800311 iface->register_property(
312 level, threshold.value,
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800313 [&, label, thresSize](const double& request, double& oldValue) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400314 oldValue = request; // todo, just let the config do this?
315 threshold.value = request;
316 thresholds::persistThreshold(
317 configurationPath, configInterface, threshold,
318 dbusConnection, thresSize, label);
319 // Invalidate previously remembered value,
320 // so new thresholds will be checked during next update,
321 // even if sensor reading remains unchanged.
322 value = std::numeric_limits<double>::quiet_NaN();
Josh Lehan883fb3a2020-02-27 14:41:39 -0800323
Patrick Williams2aaf7172024-08-16 15:20:40 -0400324 // Although tempting, don't call checkThresholds() from here
325 // directly. Let the regular sensor monitor call the same
326 // using updateValue(), which can check conditions like
327 // poweron, etc., before raising any event.
328 return 1;
329 });
James Feistce3fca42018-11-21 12:58:24 -0800330 iface->register_property(alarm, false);
331 }
332 if (!sensorInterface->initialize())
333 {
334 std::cerr << "error initializing value interface\n";
335 }
James Feistce3fca42018-11-21 12:58:24 -0800336
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530337 for (auto& thresIface : thresholdInterfaces)
James Feistce3fca42018-11-21 12:58:24 -0800338 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530339 if (thresIface)
340 {
341 if (!thresIface->initialize(true))
342 {
343 std::cerr << "Error initializing threshold interface \n";
344 }
345 }
James Feistce3fca42018-11-21 12:58:24 -0800346 }
James Feist67601bd2020-06-16 17:14:44 -0700347
Jie Yang3291b9c2021-07-29 14:46:51 -0700348 if (isValueMutable)
349 {
350 valueMutabilityInterface =
351 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300352 dbusConnection, sensorInterface->get_object_path(),
Jie Yang3291b9c2021-07-29 14:46:51 -0700353 valueMutabilityInterfaceName);
354 valueMutabilityInterface->register_property("Mutable", true);
355 if (!valueMutabilityInterface->initialize())
356 {
357 std::cerr
358 << "error initializing sensor value mutability interface\n";
359 valueMutabilityInterface = nullptr;
360 }
361 }
362
James Feist67601bd2020-06-16 17:14:44 -0700363 if (!availableInterface)
364 {
365 availableInterface =
366 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300367 dbusConnection, sensorInterface->get_object_path(),
James Feist67601bd2020-06-16 17:14:44 -0700368 availableInterfaceName);
369 availableInterface->register_property(
370 "Available", true, [this](const bool propIn, bool& old) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400371 if (propIn == old)
372 {
373 return 1;
374 }
375 old = propIn;
376 if (!propIn)
377 {
378 updateValue(std::numeric_limits<double>::quiet_NaN());
379 }
James Feist67601bd2020-06-16 17:14:44 -0700380 return 1;
Patrick Williams2aaf7172024-08-16 15:20:40 -0400381 });
James Feist67601bd2020-06-16 17:14:44 -0700382 availableInterface->initialize();
383 }
James Feist961bf092020-07-01 16:38:12 -0700384 if (!operationalInterface)
385 {
386 operationalInterface =
387 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300388 dbusConnection, sensorInterface->get_object_path(),
James Feist961bf092020-07-01 16:38:12 -0700389 operationalInterfaceName);
390 operationalInterface->register_property("Functional", true);
391 operationalInterface->initialize();
392 }
393 }
394
Ed Tanous2049bd22022-07-09 07:20:26 -0700395 static std::string propertyLevel(const Level lev, const Direction dir)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530396 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800397 for (const thresholds::ThresholdDefinition& prop :
398 thresholds::thresProp)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530399 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800400 if (prop.level == lev)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530401 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800402 if (dir == Direction::HIGH)
403 {
404 return std::string(prop.levelName) + "High";
405 }
406 if (dir == Direction::LOW)
407 {
408 return std::string(prop.levelName) + "Low";
409 }
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530410 }
411 }
412 return "";
413 }
414
Ed Tanous2049bd22022-07-09 07:20:26 -0700415 static std::string propertyAlarm(const Level lev, const Direction dir)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530416 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800417 for (const thresholds::ThresholdDefinition& prop :
418 thresholds::thresProp)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530419 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800420 if (prop.level == lev)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530421 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800422 if (dir == Direction::HIGH)
423 {
424 return std::string(prop.levelName) + "AlarmHigh";
425 }
426 if (dir == Direction::LOW)
427 {
428 return std::string(prop.levelName) + "AlarmLow";
429 }
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530430 }
431 }
432 return "";
433 }
434
Ed Tanous2049bd22022-07-09 07:20:26 -0700435 bool readingStateGood() const
James Feist961bf092020-07-01 16:38:12 -0700436 {
Zev Weissece5c862022-08-05 14:34:59 -0700437 return ::readingStateGood(readState);
James Feist961bf092020-07-01 16:38:12 -0700438 }
439
440 void markFunctional(bool isFunctional)
441 {
442 if (operationalInterface)
443 {
444 operationalInterface->set_property("Functional", isFunctional);
445 }
446 if (isFunctional)
447 {
448 errCount = 0;
449 }
450 else
451 {
452 updateValue(std::numeric_limits<double>::quiet_NaN());
453 }
454 }
455
456 void markAvailable(bool isAvailable)
457 {
458 if (availableInterface)
459 {
460 availableInterface->set_property("Available", isAvailable);
461 errCount = 0;
462 }
463 }
464
465 void incrementError()
466 {
467 if (!readingStateGood())
468 {
469 markAvailable(false);
470 return;
471 }
472
473 if (errCount >= errorThreshold)
474 {
475 return;
476 }
477
478 errCount++;
479 if (errCount == errorThreshold)
480 {
481 std::cerr << "Sensor " << name << " reading error!\n";
482 markFunctional(false);
483 }
James Feistce3fca42018-11-21 12:58:24 -0800484 }
485
Ed Tanous2049bd22022-07-09 07:20:26 -0700486 bool inError() const
Andrew Jefferyfad36052022-03-15 21:44:44 +1030487 {
488 return errCount >= errorThreshold;
489 }
490
James Feistd8705872019-02-08 13:26:09 -0800491 void updateValue(const double& newValue)
James Feistce3fca42018-11-21 12:58:24 -0800492 {
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530493 // Ignore if overriding is enabled
James Feist961bf092020-07-01 16:38:12 -0700494 if (overriddenState)
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530495 {
Josh Lehan883fb3a2020-02-27 14:41:39 -0800496 return;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530497 }
Josh Lehan883fb3a2020-02-27 14:41:39 -0800498
James Feist961bf092020-07-01 16:38:12 -0700499 if (!readingStateGood())
500 {
501 markAvailable(false);
Konstantin Aladysheve4569252023-03-23 11:08:14 +0300502 for (auto& threshold : thresholds)
503 {
504 assertThresholds(this, value, threshold.level,
505 threshold.direction, false);
506 }
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200507 updateValueProperty(std::numeric_limits<double>::quiet_NaN());
James Feist961bf092020-07-01 16:38:12 -0700508 return;
509 }
510
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200511 updateValueProperty(newValue);
Josh Lehan3bcd8232020-10-29 00:22:12 -0700512 updateInstrumentation(newValue);
Josh Lehan883fb3a2020-02-27 14:41:39 -0800513
514 // Always check thresholds after changing the value,
515 // as the test against hysteresisTrigger now takes place in
516 // the thresholds::checkThresholds() method,
517 // which is called by checkThresholds() below,
518 // in all current implementations of sensors that have thresholds.
519 checkThresholds();
James Feist961bf092020-07-01 16:38:12 -0700520 if (!std::isnan(newValue))
521 {
522 markFunctional(true);
523 markAvailable(true);
524 }
James Feistce3fca42018-11-21 12:58:24 -0800525 }
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200526
527 void updateProperty(
528 std::shared_ptr<sdbusplus::asio::dbus_interface>& interface,
Ed Tanous2049bd22022-07-09 07:20:26 -0700529 double& oldValue, const double& newValue,
530 const char* dbusPropertyName) const
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200531 {
532 if (requiresUpdate(oldValue, newValue))
533 {
534 oldValue = newValue;
Jae Hyun Yoo1a540b82020-07-30 23:33:18 -0700535 if (interface &&
536 !(interface->set_property(dbusPropertyName, newValue)))
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200537 {
538 std::cerr << "error setting property " << dbusPropertyName
539 << " to " << newValue << "\n";
540 }
541 }
542 }
543
Ed Tanous2049bd22022-07-09 07:20:26 -0700544 bool requiresUpdate(const double& lVal, const double& rVal) const
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200545 {
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000546 const auto lNan = std::isnan(lVal);
547 const auto rNan = std::isnan(rVal);
548 if (lNan || rNan)
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200549 {
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000550 return (lNan != rNan);
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200551 }
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000552 return std::abs(lVal - rVal) > hysteresisPublish;
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200553 }
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200554
555 private:
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300556 // If one of the thresholds for a dbus interface is provided
557 // we have to set the other one as dbus properties are never
558 // optional.
559 void fillMissingThresholds()
560 {
Vikash Chandola2d5ee502023-07-06 15:57:09 +0530561 const std::size_t thresholdsLen = thresholds.size();
562 for (std::size_t index = 0; index < thresholdsLen; ++index)
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300563 {
Vikash Chandola2d5ee502023-07-06 15:57:09 +0530564 const thresholds::Threshold& thisThreshold = thresholds[index];
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300565 bool foundOpposite = false;
566 thresholds::Direction opposite = thresholds::Direction::HIGH;
567 if (thisThreshold.direction == thresholds::Direction::HIGH)
568 {
569 opposite = thresholds::Direction::LOW;
570 }
571 for (thresholds::Threshold& otherThreshold : thresholds)
572 {
573 if (thisThreshold.level != otherThreshold.level)
574 {
575 continue;
576 }
577 if (otherThreshold.direction != opposite)
578 {
579 continue;
580 }
581 foundOpposite = true;
582 break;
583 }
584 if (foundOpposite)
585 {
586 continue;
587 }
588 thresholds.emplace_back(thisThreshold.level, opposite,
589 std::numeric_limits<double>::quiet_NaN());
590 }
591 }
592
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200593 void updateValueProperty(const double& newValue)
594 {
595 // Indicate that it is internal set call, not an external overwrite
596 internalSet = true;
597 updateProperty(sensorInterface, value, newValue, "Value");
598 internalSet = false;
599 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530600};