blob: b21df1ed79194a86584af42e1aee22eacf7429b2 [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
George Liu61984352025-02-24 14:47:34 +08009#include <phosphor-logging/lg2.hpp>
Ed Tanous18b61862025-01-30 10:56:28 -080010#include <sdbusplus/asio/connection.hpp>
James Feist38fb5982020-05-28 10:09:54 -070011#include <sdbusplus/asio/object_server.hpp>
Jonathan Doman256d8c12022-06-03 13:01:08 -070012#include <sdbusplus/exception.hpp>
James Feist38fb5982020-05-28 10:09:54 -070013
Ed Tanous18b61862025-01-30 10:56:28 -080014#include <array>
15#include <cerrno>
16#include <cmath>
17#include <cstddef>
18#include <cstdlib>
19#include <functional>
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)),
Ed Tanousaba6fca2025-09-29 13:53:20 -070081 dbusConnection(conn), readState(readState),
Josh Lehan3bcd8232020-10-29 00:22:12 -070082 instrumentation(enableInstrumentation
83 ? std::make_unique<SensorInstrumentation>()
84 : nullptr)
Ed Tanousaba6fca2025-09-29 13:53:20 -070085 {
86 // These inits confuse tidy because they're doing constructor params
87 // math on member variables that tidy suggests should be default
88 // initialized. NOLINTBEGIN(cppcoreguidelines-prefer-member-initializer)
89 hysteresisTrigger = (max - min) * 0.01;
90 hysteresisPublish = (max - min) * 0.0001;
91 // NOLINTEND(cppcoreguidelines-prefer-member-initializer)
92 }
James Feist8fd8a582018-11-16 11:10:46 -080093 virtual ~Sensor() = default;
Ed Tanous201a1012024-04-03 18:07:28 -070094 virtual void checkThresholds() = 0;
James Feistdc6c55f2018-10-31 12:53:20 -070095 std::string name;
James Feistce3fca42018-11-21 12:58:24 -080096 std::string configurationPath;
Matt Spinler55832f32023-06-07 10:24:00 -050097 std::string configInterface;
Bruce Lee1263c3d2021-06-04 15:16:33 +080098 bool isSensorSettable;
Jie Yang3291b9c2021-07-29 14:46:51 -070099
100 /* A flag indicates if properties of xyz.openbmc_project.Sensor.Value
101 * interface are mutable. If mutable, then
102 * xyz.openbmc_project.Sensor.ValueMutability interface will be
103 * instantiated.
104 */
105 bool isValueMutable;
James Feistce3fca42018-11-21 12:58:24 -0800106 double maxValue;
107 double minValue;
James Feist8fd8a582018-11-16 11:10:46 -0800108 std::vector<thresholds::Threshold> thresholds;
109 std::shared_ptr<sdbusplus::asio::dbus_interface> sensorInterface;
James Feist078f2322019-03-08 11:09:05 -0800110 std::shared_ptr<sdbusplus::asio::dbus_interface> association;
James Feist67601bd2020-06-16 17:14:44 -0700111 std::shared_ptr<sdbusplus::asio::dbus_interface> availableInterface;
James Feist961bf092020-07-01 16:38:12 -0700112 std::shared_ptr<sdbusplus::asio::dbus_interface> operationalInterface;
Jie Yang3291b9c2021-07-29 14:46:51 -0700113 std::shared_ptr<sdbusplus::asio::dbus_interface> valueMutabilityInterface;
James Feist8fd8a582018-11-16 11:10:46 -0800114 double value = std::numeric_limits<double>::quiet_NaN();
Zhikui Rend3da1282020-09-11 17:02:01 -0700115 double rawValue = std::numeric_limits<double>::quiet_NaN();
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530116 bool overriddenState = false;
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530117 bool internalSet = false;
Ed Tanousaba6fca2025-09-29 13:53:20 -0700118 double hysteresisTrigger = 1.0;
119 double hysteresisPublish = 1.0;
James Feiste3338522020-09-15 15:40:30 -0700120 std::shared_ptr<sdbusplus::asio::connection> dbusConnection;
James Feist961bf092020-07-01 16:38:12 -0700121 PowerState readState;
Ed Tanousb429f312022-06-27 16:09:53 -0700122 size_t errCount{0};
Josh Lehan3bcd8232020-10-29 00:22:12 -0700123 std::unique_ptr<SensorInstrumentation> instrumentation;
124
Josh Lehanffe18342021-03-17 13:29:51 -0700125 // This member variable provides a hook that can be used to receive
126 // notification whenever this Sensor's value is externally set via D-Bus.
127 // If interested, assign your own lambda to this variable, during
128 // construction of your Sensor subclass. See ExternalSensor for example.
129 std::function<void()> externalSetHook;
130
Ed Tanousc8fed202022-01-12 14:24:45 -0800131 using Level = thresholds::Level;
132 using Direction = thresholds::Direction;
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530133
Ed Tanousc8fed202022-01-12 14:24:45 -0800134 std::array<std::shared_ptr<sdbusplus::asio::dbus_interface>,
135 thresholds::thresProp.size()>
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530136 thresholdInterfaces;
137
Patrick Williams556e04b2025-02-01 08:22:22 -0500138 std::shared_ptr<sdbusplus::asio::dbus_interface> getThresholdInterface(
139 Level lev)
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530140 {
141 size_t index = static_cast<size_t>(lev);
142 if (index >= thresholdInterfaces.size())
143 {
George Liu61984352025-02-24 14:47:34 +0800144 lg2::info("Unknown threshold level");
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530145 return nullptr;
146 }
147 std::shared_ptr<sdbusplus::asio::dbus_interface> interface =
148 thresholdInterfaces[index];
149 return interface;
150 }
151
Ed Tanous2049bd22022-07-09 07:20:26 -0700152 void updateInstrumentation(double readValue) const
Josh Lehan3bcd8232020-10-29 00:22:12 -0700153 {
154 // Do nothing if this feature is not enabled
155 if constexpr (!enableInstrumentation)
156 {
157 return;
158 }
159 if (!instrumentation)
160 {
161 return;
162 }
163
164 // Save some typing
165 auto& inst = *instrumentation;
166
167 // Show constants if first reading (even if unsuccessful)
168 if ((inst.numCollectsGood == 0) && (inst.numCollectsMiss == 0))
169 {
George Liu61984352025-02-24 14:47:34 +0800170 lg2::info(
171 "Sensor name: {NAME}, min: {MIN}, max: {MAX}, type: {TYPE}, path: {PATH}",
172 "NAME", name, "MIN", minValue, "MAX", maxValue, "TYPE",
173 configInterface, "PATH", configurationPath);
Josh Lehan3bcd8232020-10-29 00:22:12 -0700174 }
175
176 // Sensors can use "nan" to indicate unavailable reading
177 if (!std::isfinite(readValue))
178 {
179 // Only show this if beginning a new streak
180 if (inst.numStreakMisses == 0)
181 {
George Liu61984352025-02-24 14:47:34 +0800182 lg2::warning(
183 "Sensor name: {NAME}, Missing reading, Reading counts good= {NUM_COLLECTS_GOOD},"
184 " miss= {NUM_COLLECTS_MISS}, Prior good streak= {NUM_STREAK_GREATS}",
185 "NAME", name, "NUM_COLLECTS_GOOD", inst.numCollectsGood,
186 "NUM_COLLECTS_MISS", inst.numCollectsMiss,
187 "NUM_STREAK_GREATS", inst.numStreakGreats);
Josh Lehan3bcd8232020-10-29 00:22:12 -0700188 }
189
190 inst.numStreakGreats = 0;
191 ++(inst.numCollectsMiss);
192 ++(inst.numStreakMisses);
193
194 return;
195 }
196
197 // Only show this if beginning a new streak and not the first time
198 if ((inst.numStreakGreats == 0) && (inst.numCollectsGood != 0))
199 {
George Liu61984352025-02-24 14:47:34 +0800200 lg2::info(
201 "Sensor name: {NAME}, Recovered reading, Reading counts good= {NUM_COLLECTS_GOOD},"
202 " miss= {NUM_COLLECTS_MISS}, Prior good streak= {NUM_STREAK_GREATS}",
203 "NAME", name, "NUM_COLLECTS_GOOD", inst.numCollectsGood,
204 "NUM_COLLECTS_MISS", inst.numCollectsMiss, "NUM_STREAK_GREATS",
205 inst.numStreakGreats);
Josh Lehan3bcd8232020-10-29 00:22:12 -0700206 }
207
208 // Initialize min/max if the first successful reading
209 if (inst.numCollectsGood == 0)
210 {
George Liu61984352025-02-24 14:47:34 +0800211 lg2::info("Sensor name: {NAME}, First reading: {VALUE}", "NAME",
212 name, "VALUE", readValue);
Josh Lehan3bcd8232020-10-29 00:22:12 -0700213
214 inst.minCollected = readValue;
215 inst.maxCollected = readValue;
216 }
217
218 inst.numStreakMisses = 0;
219 ++(inst.numCollectsGood);
220 ++(inst.numStreakGreats);
221
222 // Only provide subsequent output if new min/max established
223 if (readValue < inst.minCollected)
224 {
George Liu61984352025-02-24 14:47:34 +0800225 lg2::info("Sensor name: {NAME}, Lowest reading: {VALUE}", "NAME",
226 name, "VALUE", readValue);
Josh Lehan3bcd8232020-10-29 00:22:12 -0700227
228 inst.minCollected = readValue;
229 }
230
231 if (readValue > inst.maxCollected)
232 {
George Liu61984352025-02-24 14:47:34 +0800233 lg2::info("Sensor name: {NAME}, Highest reading: {VALUE}", "NAME",
234 name, "VALUE", readValue);
Josh Lehan3bcd8232020-10-29 00:22:12 -0700235
236 inst.maxCollected = readValue;
237 }
238 }
James Feistce3fca42018-11-21 12:58:24 -0800239
James Feistd8705872019-02-08 13:26:09 -0800240 int setSensorValue(const double& newValue, double& oldValue)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530241 {
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +0530242 if (!internalSet)
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530243 {
Jonathan Doman256d8c12022-06-03 13:01:08 -0700244 if (insecureSensorOverride == 0 && !isSensorSettable &&
245 !getManufacturingMode())
246 {
247 throw SetSensorError();
Bruce Lee1263c3d2021-06-04 15:16:33 +0800248 }
249
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530250 oldValue = newValue;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530251 overriddenState = true;
252 // check thresholds for external set
253 value = newValue;
254 checkThresholds();
Josh Lehanffe18342021-03-17 13:29:51 -0700255
256 // Trigger the hook, as an external set has just happened
257 if (externalSetHook)
258 {
259 externalSetHook();
260 }
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530261 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530262 else if (!overriddenState)
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +0530263 {
264 oldValue = newValue;
265 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700266 return 1;
Richard Marian Thomaiyar87219222018-11-06 20:25:38 +0530267 }
James Feistce3fca42018-11-21 12:58:24 -0800268
Andrei Kartashev39287412022-02-04 16:04:47 +0300269 void setInitialProperties(const std::string& unit,
270 const std::string& label = std::string(),
271 size_t thresholdSize = 0)
James Feistce3fca42018-11-21 12:58:24 -0800272 {
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700273 if (readState == PowerState::on || readState == PowerState::biosPost ||
274 readState == PowerState::chassisOn)
James Feist961bf092020-07-01 16:38:12 -0700275 {
Andrei Kartashev39287412022-02-04 16:04:47 +0300276 setupPowerMatch(dbusConnection);
James Feist961bf092020-07-01 16:38:12 -0700277 }
278
James Feist82bac4c2019-03-11 11:16:53 -0700279 createAssociation(association, configurationPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +0530280
Zev Weiss6b6891c2021-04-22 02:46:21 -0500281 sensorInterface->register_property("Unit", unit);
James Feistce3fca42018-11-21 12:58:24 -0800282 sensorInterface->register_property("MaxValue", maxValue);
283 sensorInterface->register_property("MinValue", minValue);
284 sensorInterface->register_property(
Jonathan Doman256d8c12022-06-03 13:01:08 -0700285 "Value", value, [this](const double& newValue, double& oldValue) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400286 return setSensorValue(newValue, oldValue);
287 });
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300288
289 fillMissingThresholds();
290
James Feistd8705872019-02-08 13:26:09 -0800291 for (auto& threshold : thresholds)
James Feistce3fca42018-11-21 12:58:24 -0800292 {
Rashmica Gupta1e34cec2021-08-31 16:47:39 +1000293 if (std::isnan(threshold.hysteresis))
294 {
295 threshold.hysteresis = hysteresisTrigger;
296 }
Ed Tanous17551b82022-01-26 16:47:17 -0800297
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530298 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
299 getThresholdInterface(threshold.level);
300
James Feistce3fca42018-11-21 12:58:24 -0800301 if (!iface)
302 {
George Liu61984352025-02-24 14:47:34 +0800303 lg2::info("trying to set uninitialized interface");
James Feistce3fca42018-11-21 12:58:24 -0800304 continue;
305 }
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800306
Patrick Williams2aaf7172024-08-16 15:20:40 -0400307 std::string level =
308 propertyLevel(threshold.level, threshold.direction);
309 std::string alarm =
310 propertyAlarm(threshold.level, threshold.direction);
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530311
312 if ((level.empty()) || (alarm.empty()))
313 {
314 continue;
315 }
Patrick Williams2aaf7172024-08-16 15:20:40 -0400316 size_t thresSize =
317 label.empty() ? thresholds.size() : thresholdSize;
James Feistce3fca42018-11-21 12:58:24 -0800318 iface->register_property(
319 level, threshold.value,
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800320 [&, label, thresSize](const double& request, double& oldValue) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400321 oldValue = request; // todo, just let the config do this?
322 threshold.value = request;
323 thresholds::persistThreshold(
324 configurationPath, configInterface, threshold,
325 dbusConnection, thresSize, label);
326 // Invalidate previously remembered value,
327 // so new thresholds will be checked during next update,
328 // even if sensor reading remains unchanged.
329 value = std::numeric_limits<double>::quiet_NaN();
Josh Lehan883fb3a2020-02-27 14:41:39 -0800330
Patrick Williams2aaf7172024-08-16 15:20:40 -0400331 // Although tempting, don't call checkThresholds() from here
332 // directly. Let the regular sensor monitor call the same
333 // using updateValue(), which can check conditions like
334 // poweron, etc., before raising any event.
335 return 1;
336 });
James Feistce3fca42018-11-21 12:58:24 -0800337 iface->register_property(alarm, false);
338 }
339 if (!sensorInterface->initialize())
340 {
George Liu61984352025-02-24 14:47:34 +0800341 lg2::error("error initializing value interface");
James Feistce3fca42018-11-21 12:58:24 -0800342 }
James Feistce3fca42018-11-21 12:58:24 -0800343
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530344 for (auto& thresIface : thresholdInterfaces)
James Feistce3fca42018-11-21 12:58:24 -0800345 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530346 if (thresIface)
347 {
348 if (!thresIface->initialize(true))
349 {
George Liu61984352025-02-24 14:47:34 +0800350 lg2::error("Error initializing threshold interface");
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530351 }
352 }
James Feistce3fca42018-11-21 12:58:24 -0800353 }
James Feist67601bd2020-06-16 17:14:44 -0700354
Jie Yang3291b9c2021-07-29 14:46:51 -0700355 if (isValueMutable)
356 {
357 valueMutabilityInterface =
358 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300359 dbusConnection, sensorInterface->get_object_path(),
Jie Yang3291b9c2021-07-29 14:46:51 -0700360 valueMutabilityInterfaceName);
361 valueMutabilityInterface->register_property("Mutable", true);
362 if (!valueMutabilityInterface->initialize())
363 {
George Liu61984352025-02-24 14:47:34 +0800364 lg2::error(
365 "error initializing sensor value mutability interface");
Jie Yang3291b9c2021-07-29 14:46:51 -0700366 valueMutabilityInterface = nullptr;
367 }
368 }
369
James Feist67601bd2020-06-16 17:14:44 -0700370 if (!availableInterface)
371 {
372 availableInterface =
373 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300374 dbusConnection, sensorInterface->get_object_path(),
James Feist67601bd2020-06-16 17:14:44 -0700375 availableInterfaceName);
376 availableInterface->register_property(
377 "Available", true, [this](const bool propIn, bool& old) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400378 if (propIn == old)
379 {
380 return 1;
381 }
382 old = propIn;
383 if (!propIn)
384 {
385 updateValue(std::numeric_limits<double>::quiet_NaN());
386 }
James Feist67601bd2020-06-16 17:14:44 -0700387 return 1;
Patrick Williams2aaf7172024-08-16 15:20:40 -0400388 });
James Feist67601bd2020-06-16 17:14:44 -0700389 availableInterface->initialize();
390 }
James Feist961bf092020-07-01 16:38:12 -0700391 if (!operationalInterface)
392 {
393 operationalInterface =
394 std::make_shared<sdbusplus::asio::dbus_interface>(
Andrei Kartashev39287412022-02-04 16:04:47 +0300395 dbusConnection, sensorInterface->get_object_path(),
James Feist961bf092020-07-01 16:38:12 -0700396 operationalInterfaceName);
397 operationalInterface->register_property("Functional", true);
398 operationalInterface->initialize();
399 }
400 }
401
Ed Tanous2049bd22022-07-09 07:20:26 -0700402 static std::string propertyLevel(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) + "High";
412 }
413 if (dir == Direction::LOW)
414 {
415 return std::string(prop.levelName) + "Low";
416 }
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530417 }
418 }
419 return "";
420 }
421
Ed Tanous2049bd22022-07-09 07:20:26 -0700422 static std::string propertyAlarm(const Level lev, const Direction dir)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530423 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800424 for (const thresholds::ThresholdDefinition& prop :
425 thresholds::thresProp)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530426 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800427 if (prop.level == lev)
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530428 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800429 if (dir == Direction::HIGH)
430 {
431 return std::string(prop.levelName) + "AlarmHigh";
432 }
433 if (dir == Direction::LOW)
434 {
435 return std::string(prop.levelName) + "AlarmLow";
436 }
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530437 }
438 }
439 return "";
440 }
441
Ed Tanous2049bd22022-07-09 07:20:26 -0700442 bool readingStateGood() const
James Feist961bf092020-07-01 16:38:12 -0700443 {
Zev Weissece5c862022-08-05 14:34:59 -0700444 return ::readingStateGood(readState);
James Feist961bf092020-07-01 16:38:12 -0700445 }
446
447 void markFunctional(bool isFunctional)
448 {
449 if (operationalInterface)
450 {
451 operationalInterface->set_property("Functional", isFunctional);
452 }
453 if (isFunctional)
454 {
455 errCount = 0;
456 }
457 else
458 {
459 updateValue(std::numeric_limits<double>::quiet_NaN());
460 }
461 }
462
463 void markAvailable(bool isAvailable)
464 {
465 if (availableInterface)
466 {
467 availableInterface->set_property("Available", isAvailable);
468 errCount = 0;
469 }
470 }
471
472 void incrementError()
473 {
474 if (!readingStateGood())
475 {
476 markAvailable(false);
477 return;
478 }
479
480 if (errCount >= errorThreshold)
481 {
482 return;
483 }
484
485 errCount++;
486 if (errCount == errorThreshold)
487 {
George Liu61984352025-02-24 14:47:34 +0800488 lg2::error("Sensor name: {NAME}, reading error!", "NAME", name);
James Feist961bf092020-07-01 16:38:12 -0700489 markFunctional(false);
490 }
James Feistce3fca42018-11-21 12:58:24 -0800491 }
492
Ed Tanous2049bd22022-07-09 07:20:26 -0700493 bool inError() const
Andrew Jefferyfad36052022-03-15 21:44:44 +1030494 {
495 return errCount >= errorThreshold;
496 }
497
James Feistd8705872019-02-08 13:26:09 -0800498 void updateValue(const double& newValue)
James Feistce3fca42018-11-21 12:58:24 -0800499 {
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530500 // Ignore if overriding is enabled
James Feist961bf092020-07-01 16:38:12 -0700501 if (overriddenState)
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530502 {
Josh Lehan883fb3a2020-02-27 14:41:39 -0800503 return;
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530504 }
Josh Lehan883fb3a2020-02-27 14:41:39 -0800505
James Feist961bf092020-07-01 16:38:12 -0700506 if (!readingStateGood())
507 {
508 markAvailable(false);
Konstantin Aladysheve4569252023-03-23 11:08:14 +0300509 for (auto& threshold : thresholds)
510 {
511 assertThresholds(this, value, threshold.level,
512 threshold.direction, false);
513 }
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200514 updateValueProperty(std::numeric_limits<double>::quiet_NaN());
James Feist961bf092020-07-01 16:38:12 -0700515 return;
516 }
517
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200518 updateValueProperty(newValue);
Josh Lehan3bcd8232020-10-29 00:22:12 -0700519 updateInstrumentation(newValue);
Josh Lehan883fb3a2020-02-27 14:41:39 -0800520
521 // Always check thresholds after changing the value,
522 // as the test against hysteresisTrigger now takes place in
523 // the thresholds::checkThresholds() method,
524 // which is called by checkThresholds() below,
525 // in all current implementations of sensors that have thresholds.
526 checkThresholds();
James Feist961bf092020-07-01 16:38:12 -0700527 if (!std::isnan(newValue))
528 {
529 markFunctional(true);
530 markAvailable(true);
531 }
James Feistce3fca42018-11-21 12:58:24 -0800532 }
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200533
534 void updateProperty(
535 std::shared_ptr<sdbusplus::asio::dbus_interface>& interface,
Ed Tanous2049bd22022-07-09 07:20:26 -0700536 double& oldValue, const double& newValue,
537 const char* dbusPropertyName) const
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200538 {
539 if (requiresUpdate(oldValue, newValue))
540 {
541 oldValue = newValue;
Jae Hyun Yoo1a540b82020-07-30 23:33:18 -0700542 if (interface &&
543 !(interface->set_property(dbusPropertyName, newValue)))
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200544 {
George Liu61984352025-02-24 14:47:34 +0800545 lg2::error("error setting property '{NAME}' to '{VALUE}'",
546 "NAME", dbusPropertyName, "VALUE", newValue);
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200547 }
548 }
549 }
550
Ed Tanous2049bd22022-07-09 07:20:26 -0700551 bool requiresUpdate(const double& lVal, const double& rVal) const
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200552 {
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000553 const auto lNan = std::isnan(lVal);
554 const auto rNan = std::isnan(rVal);
555 if (lNan || rNan)
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200556 {
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000557 return (lNan != rNan);
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200558 }
chaul.ampere2a5e2dc2022-07-21 06:03:18 +0000559 return std::abs(lVal - rVal) > hysteresisPublish;
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200560 }
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200561
562 private:
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300563 // If one of the thresholds for a dbus interface is provided
564 // we have to set the other one as dbus properties are never
565 // optional.
566 void fillMissingThresholds()
567 {
Vikash Chandola2d5ee502023-07-06 15:57:09 +0530568 const std::size_t thresholdsLen = thresholds.size();
569 for (std::size_t index = 0; index < thresholdsLen; ++index)
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300570 {
Vikash Chandola2d5ee502023-07-06 15:57:09 +0530571 const thresholds::Threshold& thisThreshold = thresholds[index];
Konstantin Aladyshev75872ef2021-05-13 11:17:58 +0300572 bool foundOpposite = false;
573 thresholds::Direction opposite = thresholds::Direction::HIGH;
574 if (thisThreshold.direction == thresholds::Direction::HIGH)
575 {
576 opposite = thresholds::Direction::LOW;
577 }
578 for (thresholds::Threshold& otherThreshold : thresholds)
579 {
580 if (thisThreshold.level != otherThreshold.level)
581 {
582 continue;
583 }
584 if (otherThreshold.direction != opposite)
585 {
586 continue;
587 }
588 foundOpposite = true;
589 break;
590 }
591 if (foundOpposite)
592 {
593 continue;
594 }
595 thresholds.emplace_back(thisThreshold.level, opposite,
596 std::numeric_limits<double>::quiet_NaN());
597 }
598 }
599
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200600 void updateValueProperty(const double& newValue)
601 {
602 // Indicate that it is internal set call, not an external overwrite
603 internalSet = true;
604 updateProperty(sensorInterface, value, newValue, "Value");
605 internalSet = false;
606 }
Richard Marian Thomaiyarc0ca7ee2019-04-24 21:22:52 +0530607};