blob: 68233c0af60d21c9576623e16afbc94577e7675f [file] [log] [blame]
Andrew Jefferye73bd0a2023-01-25 10:39:57 +10301#include "Thresholds.hpp"
2
Ed Tanouseacbfdd2024-04-04 12:00:24 -07003#include "Utils.hpp"
Andrew Jefferye73bd0a2023-01-25 10:39:57 +10304#include "VariantVisitors.hpp"
5#include "sensor.hpp"
6
James Feist6714a252018-09-10 15:26:18 -07007#include <boost/algorithm/string/replace.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -07008#include <boost/asio/error.hpp>
9#include <boost/asio/steady_timer.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070010#include <boost/container/flat_map.hpp>
George Liu61984352025-02-24 14:47:34 +080011#include <phosphor-logging/lg2.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070012#include <sdbusplus/asio/connection.hpp>
13#include <sdbusplus/asio/object_server.hpp>
14#include <sdbusplus/exception.hpp>
15#include <sdbusplus/message.hpp>
James Feist38fb5982020-05-28 10:09:54 -070016
17#include <array>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070018#include <chrono>
19#include <cstddef>
20#include <cstdint>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070021#include <limits>
Patrick Venture96e97db2019-10-31 13:44:38 -070022#include <memory>
Patrick Venture96e97db2019-10-31 13:44:38 -070023#include <string>
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020024#include <tuple>
Patrick Venture96e97db2019-10-31 13:44:38 -070025#include <utility>
26#include <variant>
27#include <vector>
James Feist6714a252018-09-10 15:26:18 -070028
Ed Tanous8a57ec02020-10-09 12:46:52 -070029static constexpr bool debug = false;
James Feist6714a252018-09-10 15:26:18 -070030namespace thresholds
31{
Ed Tanousc8fed202022-01-12 14:24:45 -080032Level findThresholdLevel(uint8_t sev)
James Feist6714a252018-09-10 15:26:18 -070033{
Ed Tanousc8fed202022-01-12 14:24:45 -080034 for (const ThresholdDefinition& prop : thresProp)
James Feist6714a252018-09-10 15:26:18 -070035 {
Ed Tanousc8fed202022-01-12 14:24:45 -080036 if (prop.sevOrder == sev)
James Feist6714a252018-09-10 15:26:18 -070037 {
Jayashree Dhanapal45f27022021-12-07 12:56:35 +053038 return prop.level;
James Feist6714a252018-09-10 15:26:18 -070039 }
40 }
Jayashree Dhanapal45f27022021-12-07 12:56:35 +053041 return Level::ERROR;
James Feist6714a252018-09-10 15:26:18 -070042}
43
Ed Tanousc8fed202022-01-12 14:24:45 -080044Direction findThresholdDirection(const std::string& direct)
James Feist6714a252018-09-10 15:26:18 -070045{
Ed Tanousc8fed202022-01-12 14:24:45 -080046 if (direct == "greater than")
James Feist6714a252018-09-10 15:26:18 -070047 {
Ed Tanousc8fed202022-01-12 14:24:45 -080048 return Direction::HIGH;
49 }
50 if (direct == "less than")
51 {
52 return Direction::LOW;
James Feist6714a252018-09-10 15:26:18 -070053 }
Jayashree Dhanapal45f27022021-12-07 12:56:35 +053054 return Direction::ERROR;
James Feist6714a252018-09-10 15:26:18 -070055}
56
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070057bool parseThresholdsFromConfig(
James Feistd8705872019-02-08 13:26:09 -080058 const SensorData& sensorData,
59 std::vector<thresholds::Threshold>& thresholdVector,
Matt Spinler5636d522021-03-17 14:52:18 -050060 const std::string* matchLabel, const int* sensorIndex)
James Feist6714a252018-09-10 15:26:18 -070061{
Zev Weissf783c692022-08-12 18:21:02 -070062 for (const auto& [intf, cfg] : sensorData)
James Feist6714a252018-09-10 15:26:18 -070063 {
Zev Weissf783c692022-08-12 18:21:02 -070064 if (intf.find("Thresholds") == std::string::npos)
James Feist6714a252018-09-10 15:26:18 -070065 {
66 continue;
67 }
68 if (matchLabel != nullptr)
69 {
Zev Weissf783c692022-08-12 18:21:02 -070070 auto labelFind = cfg.find("Label");
71 if (labelFind == cfg.end())
Ed Tanous8a57ec02020-10-09 12:46:52 -070072 {
James Feist6714a252018-09-10 15:26:18 -070073 continue;
Ed Tanous8a57ec02020-10-09 12:46:52 -070074 }
James Feist3eb82622019-02-08 13:10:22 -080075 if (std::visit(VariantToStringVisitor(), labelFind->second) !=
76 *matchLabel)
Ed Tanous8a57ec02020-10-09 12:46:52 -070077 {
James Feist6714a252018-09-10 15:26:18 -070078 continue;
Ed Tanous8a57ec02020-10-09 12:46:52 -070079 }
James Feist6714a252018-09-10 15:26:18 -070080 }
Matt Spinler5636d522021-03-17 14:52:18 -050081
82 if (sensorIndex != nullptr)
83 {
Zev Weissf783c692022-08-12 18:21:02 -070084 auto indexFind = cfg.find("Index");
Matt Spinler5636d522021-03-17 14:52:18 -050085
86 // If we're checking for index 1, a missing Index is OK.
Zev Weissf783c692022-08-12 18:21:02 -070087 if ((indexFind == cfg.end()) && (*sensorIndex != 1))
Matt Spinler5636d522021-03-17 14:52:18 -050088 {
89 continue;
90 }
91
Zev Weissf783c692022-08-12 18:21:02 -070092 if ((indexFind != cfg.end()) &&
Matt Spinler5636d522021-03-17 14:52:18 -050093 (std::visit(VariantToIntVisitor(), indexFind->second) !=
94 *sensorIndex))
95 {
96 continue;
97 }
98 }
99
Rashmica Gupta1e34cec2021-08-31 16:47:39 +1000100 double hysteresis = std::numeric_limits<double>::quiet_NaN();
Zev Weissf783c692022-08-12 18:21:02 -0700101 auto hysteresisFind = cfg.find("Hysteresis");
102 if (hysteresisFind != cfg.end())
Rashmica Gupta1e34cec2021-08-31 16:47:39 +1000103 {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400104 hysteresis =
105 std::visit(VariantToDoubleVisitor(), hysteresisFind->second);
Rashmica Gupta1e34cec2021-08-31 16:47:39 +1000106 }
107
Zev Weissf783c692022-08-12 18:21:02 -0700108 auto directionFind = cfg.find("Direction");
109 auto severityFind = cfg.find("Severity");
110 auto valueFind = cfg.find("Value");
111 if (valueFind == cfg.end() || severityFind == cfg.end() ||
112 directionFind == cfg.end())
James Feist6714a252018-09-10 15:26:18 -0700113 {
George Liu61984352025-02-24 14:47:34 +0800114 lg2::error(
115 "Malformed threshold on configuration interface: '{INTERFACE}'",
116 "INTERFACE", intf);
James Feist6714a252018-09-10 15:26:18 -0700117 return false;
118 }
Patrick Williams2aaf7172024-08-16 15:20:40 -0400119 unsigned int severity =
120 std::visit(VariantToUnsignedIntVisitor(), severityFind->second);
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530121
Patrick Williams2aaf7172024-08-16 15:20:40 -0400122 std::string directions =
123 std::visit(VariantToStringVisitor(), directionFind->second);
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530124
Ed Tanousc8fed202022-01-12 14:24:45 -0800125 Level level = findThresholdLevel(severity);
126 Direction direction = findThresholdDirection(directions);
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530127
Jayashree Dhanapal091c92c2022-01-11 14:55:20 +0530128 if ((level == Level::ERROR) || (direction == Direction::ERROR))
James Feist6714a252018-09-10 15:26:18 -0700129 {
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530130 continue;
James Feist6714a252018-09-10 15:26:18 -0700131 }
James Feist13f340b2019-03-07 16:36:11 -0800132 double val = std::visit(VariantToDoubleVisitor(), valueFind->second);
James Feist6714a252018-09-10 15:26:18 -0700133
Rashmica Gupta1e34cec2021-08-31 16:47:39 +1000134 thresholdVector.emplace_back(level, direction, val, hysteresis);
James Feist6714a252018-09-10 15:26:18 -0700135 }
136 return true;
137}
138
James Feistd8705872019-02-08 13:26:09 -0800139void persistThreshold(const std::string& path, const std::string& baseInterface,
140 const thresholds::Threshold& threshold,
James Feista222ba72019-03-01 15:57:51 -0800141 std::shared_ptr<sdbusplus::asio::connection>& conn,
Cheng C Yang6b1247a2020-03-09 23:48:39 +0800142 size_t thresholdCount, const std::string& labelMatch)
James Feist6714a252018-09-10 15:26:18 -0700143{
Brad Bishopfbb44ad2019-11-08 09:42:37 -0500144 for (size_t ii = 0; ii < thresholdCount; ii++)
James Feist6714a252018-09-10 15:26:18 -0700145 {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400146 std::string thresholdInterface =
147 baseInterface + ".Thresholds" + std::to_string(ii);
James Feist6714a252018-09-10 15:26:18 -0700148 conn->async_method_call(
Zev Weissafd15042022-07-18 12:28:40 -0700149 [&, path, threshold, thresholdInterface,
150 labelMatch](const boost::system::error_code& ec,
151 const SensorBaseConfigMap& result) {
Ed Tanousbb679322022-05-16 16:10:00 -0700152 if (ec)
153 {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400154 return; // threshold not supported
Ed Tanousbb679322022-05-16 16:10:00 -0700155 }
Patrick Williams2aaf7172024-08-16 15:20:40 -0400156
157 if (!labelMatch.empty())
158 {
159 auto labelFind = result.find("Label");
160 if (labelFind == result.end())
161 {
George Liu61984352025-02-24 14:47:34 +0800162 lg2::error("No label in threshold configuration");
Patrick Williams2aaf7172024-08-16 15:20:40 -0400163 return;
164 }
165 std::string label =
166 std::visit(VariantToStringVisitor(), labelFind->second);
167 if (label != labelMatch)
168 {
169 return;
170 }
171 }
172
173 auto directionFind = result.find("Direction");
174 auto severityFind = result.find("Severity");
175 auto valueFind = result.find("Value");
176 if (valueFind == result.end() || severityFind == result.end() ||
177 directionFind == result.end())
178 {
George Liu61984352025-02-24 14:47:34 +0800179 lg2::error("Malformed threshold in configuration");
Patrick Williams2aaf7172024-08-16 15:20:40 -0400180 return;
181 }
182 unsigned int severity = std::visit(
183 VariantToUnsignedIntVisitor(), severityFind->second);
184
185 std::string dir =
186 std::visit(VariantToStringVisitor(), directionFind->second);
187 if ((findThresholdLevel(severity) != threshold.level) ||
188 (findThresholdDirection(dir) != threshold.direction))
189 {
190 return; // not the droid we're looking for
191 }
192
193 std::variant<double> value(threshold.value);
194 conn->async_method_call(
195 [](const boost::system::error_code& ec) {
196 if (ec)
197 {
George Liu61984352025-02-24 14:47:34 +0800198 lg2::error(
199 "Error setting threshold: '{ERROR_MESSAGE}'",
200 "ERROR_MESSAGE", ec.message());
Patrick Williams2aaf7172024-08-16 15:20:40 -0400201 }
202 },
203 entityManagerName, path, "org.freedesktop.DBus.Properties",
204 "Set", thresholdInterface, "Value", value);
Patrick Williams597e8422023-10-20 11:19:01 -0500205 },
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700206 entityManagerName, path, "org.freedesktop.DBus.Properties",
James Feist6714a252018-09-10 15:26:18 -0700207 "GetAll", thresholdInterface);
208 }
209}
210
Jae Hyun Yoo95b8a2d2019-02-25 20:15:09 -0800211void updateThresholds(Sensor* sensor)
212{
Jae Hyun Yoo95b8a2d2019-02-25 20:15:09 -0800213 for (const auto& threshold : sensor->thresholds)
214 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530215 std::shared_ptr<sdbusplus::asio::dbus_interface> interface =
216 sensor->getThresholdInterface(threshold.level);
217
Jae Hyun Yoo95b8a2d2019-02-25 20:15:09 -0800218 if (!interface)
219 {
220 continue;
221 }
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530222
Patrick Williams2aaf7172024-08-16 15:20:40 -0400223 std::string property =
224 Sensor::propertyLevel(threshold.level, threshold.direction);
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530225 if (property.empty())
226 {
227 continue;
228 }
Jae Hyun Yoo95b8a2d2019-02-25 20:15:09 -0800229 interface->set_property(property, threshold.value);
230 }
231}
232
Josh Lehan883fb3a2020-02-27 14:41:39 -0800233// Debugging counters
234static int cHiTrue = 0;
235static int cHiFalse = 0;
236static int cHiMidstate = 0;
237static int cLoTrue = 0;
238static int cLoFalse = 0;
239static int cLoMidstate = 0;
240static int cDebugThrottle = 0;
Zhikui Rend3da1282020-09-11 17:02:01 -0700241static constexpr int assertLogCount = 10;
Josh Lehan883fb3a2020-02-27 14:41:39 -0800242
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700243struct ChangeParam
James Feist251c7822018-09-12 12:54:15 -0700244{
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700245 ChangeParam(Threshold whichThreshold, bool status, double value) :
246 threshold(whichThreshold), asserted(status), assertValue(value)
247 {}
248
249 Threshold threshold;
250 bool asserted;
251 double assertValue;
252};
253
254static std::vector<ChangeParam> checkThresholds(Sensor* sensor, double value)
255{
256 std::vector<ChangeParam> thresholdChanges;
James Feist251c7822018-09-12 12:54:15 -0700257 if (sensor->thresholds.empty())
258 {
James Feist46342ec2019-03-06 14:03:41 -0800259 return thresholdChanges;
James Feist251c7822018-09-12 12:54:15 -0700260 }
James Feist46342ec2019-03-06 14:03:41 -0800261
James Feistd8705872019-02-08 13:26:09 -0800262 for (auto& threshold : sensor->thresholds)
James Feist251c7822018-09-12 12:54:15 -0700263 {
Josh Lehan883fb3a2020-02-27 14:41:39 -0800264 // Use "Schmitt trigger" logic to avoid threshold trigger spam,
265 // if value is noisy while hovering very close to a threshold.
266 // When a threshold is crossed, indicate true immediately,
267 // but require more distance to be crossed the other direction,
268 // before resetting the indicator back to false.
James Feist46342ec2019-03-06 14:03:41 -0800269 if (threshold.direction == thresholds::Direction::HIGH)
James Feistdc6c55f2018-10-31 12:53:20 -0700270 {
James Feist551087a2019-12-09 11:17:12 -0800271 if (value >= threshold.value)
James Feist251c7822018-09-12 12:54:15 -0700272 {
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700273 thresholdChanges.emplace_back(threshold, true, value);
Zhikui Rend3da1282020-09-11 17:02:01 -0700274 if (++cHiTrue < assertLogCount)
275 {
George Liu61984352025-02-24 14:47:34 +0800276 lg2::info(
277 "Sensor name: {NAME}, high threshold: {THRESHOLD}, "
278 "assert value: {VALUE}, raw data: {RAW_DATA}",
279 "NAME", sensor->name, "THRESHOLD", threshold.value,
280 "VALUE", value, "RAW_DATA", sensor->rawValue);
Zhikui Rend3da1282020-09-11 17:02:01 -0700281 }
Josh Lehan883fb3a2020-02-27 14:41:39 -0800282 }
Rashmica Gupta1e34cec2021-08-31 16:47:39 +1000283 else if (value < (threshold.value - threshold.hysteresis))
Josh Lehan883fb3a2020-02-27 14:41:39 -0800284 {
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700285 thresholdChanges.emplace_back(threshold, false, value);
Josh Lehan883fb3a2020-02-27 14:41:39 -0800286 ++cHiFalse;
James Feist251c7822018-09-12 12:54:15 -0700287 }
Patrick Venture66235d42019-10-11 08:31:27 -0700288 else
James Feist251c7822018-09-12 12:54:15 -0700289 {
Josh Lehan883fb3a2020-02-27 14:41:39 -0800290 ++cHiMidstate;
James Feist251c7822018-09-12 12:54:15 -0700291 }
292 }
Josh Lehan883fb3a2020-02-27 14:41:39 -0800293 else if (threshold.direction == thresholds::Direction::LOW)
James Feist251c7822018-09-12 12:54:15 -0700294 {
James Feist551087a2019-12-09 11:17:12 -0800295 if (value <= threshold.value)
James Feist251c7822018-09-12 12:54:15 -0700296 {
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700297 thresholdChanges.emplace_back(threshold, true, value);
Zhikui Rend3da1282020-09-11 17:02:01 -0700298 if (++cLoTrue < assertLogCount)
299 {
George Liu61984352025-02-24 14:47:34 +0800300 lg2::info(
301 "Sensor name: {NAME}, low threshold: {THRESHOLD}, "
302 "assert value: {VALUE}, raw data: {RAW_DATA}",
303 "NAME", sensor->name, "THRESHOLD", threshold.value,
304 "VALUE", value, "RAW_DATA", sensor->rawValue);
Zhikui Rend3da1282020-09-11 17:02:01 -0700305 }
Josh Lehan883fb3a2020-02-27 14:41:39 -0800306 }
Rashmica Gupta1e34cec2021-08-31 16:47:39 +1000307 else if (value > (threshold.value + threshold.hysteresis))
Josh Lehan883fb3a2020-02-27 14:41:39 -0800308 {
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700309 thresholdChanges.emplace_back(threshold, false, value);
Josh Lehan883fb3a2020-02-27 14:41:39 -0800310 ++cLoFalse;
James Feist251c7822018-09-12 12:54:15 -0700311 }
Patrick Venture66235d42019-10-11 08:31:27 -0700312 else
James Feist251c7822018-09-12 12:54:15 -0700313 {
Josh Lehan883fb3a2020-02-27 14:41:39 -0800314 ++cLoMidstate;
James Feist251c7822018-09-12 12:54:15 -0700315 }
316 }
Josh Lehan883fb3a2020-02-27 14:41:39 -0800317 else
318 {
George Liu61984352025-02-24 14:47:34 +0800319 lg2::error("Error determining threshold direction");
Josh Lehan883fb3a2020-02-27 14:41:39 -0800320 }
James Feist251c7822018-09-12 12:54:15 -0700321 }
Josh Lehan883fb3a2020-02-27 14:41:39 -0800322
Ed Tanous8a17c302021-09-02 15:07:11 -0700323 // Throttle debug output, so that it does not continuously spam
324 ++cDebugThrottle;
325 if (cDebugThrottle >= 1000)
Josh Lehan883fb3a2020-02-27 14:41:39 -0800326 {
Ed Tanous8a17c302021-09-02 15:07:11 -0700327 cDebugThrottle = 0;
328 if constexpr (debug)
Josh Lehan883fb3a2020-02-27 14:41:39 -0800329 {
George Liu61984352025-02-24 14:47:34 +0800330 lg2::error("checkThresholds: High T= {HIGH_TRUE}, F= {HIGH_FALSE},"
331 " M= {HIGH_MIDSTATE}, Low T= {LOW_TRUE}, F= {LOW_FALSE},"
332 " M= {LOW_MIDSTATE}",
333 "HIGH_TRUE", cHiTrue, "HIGH_FALSE", cHiFalse,
334 "HIGH_MIDSTATE", cHiMidstate, "LOW_TRUE", cLoTrue,
335 "LOW_FALSE", cLoFalse, "LOW_MIDSTATE", cLoMidstate);
Josh Lehan883fb3a2020-02-27 14:41:39 -0800336 }
337 }
338
James Feist46342ec2019-03-06 14:03:41 -0800339 return thresholdChanges;
340}
341
Zhikui Ren12c2c0e2021-04-28 17:21:21 -0700342void ThresholdTimer::startTimer(const std::weak_ptr<Sensor>& weakSensor,
343 const Threshold& threshold, bool assert,
Jeff Lind9cd7042020-11-20 15:49:28 +0800344 double assertValue)
345{
346 struct TimerUsed timerUsed = {};
347 constexpr const size_t waitTime = 5;
348 TimerPair* pair = nullptr;
349
350 for (TimerPair& timer : timers)
351 {
352 if (!timer.first.used)
353 {
354 pair = &timer;
355 break;
356 }
357 }
358 if (pair == nullptr)
359 {
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700360 pair = &timers.emplace_back(timerUsed, boost::asio::steady_timer(io));
Jeff Lind9cd7042020-11-20 15:49:28 +0800361 }
362
363 pair->first.used = true;
364 pair->first.level = threshold.level;
365 pair->first.direction = threshold.direction;
366 pair->first.assert = assert;
Ed Tanous83db50c2023-03-01 10:20:24 -0800367 pair->second.expires_after(std::chrono::seconds(waitTime));
Zhikui Ren12c2c0e2021-04-28 17:21:21 -0700368 pair->second.async_wait([weakSensor, pair, threshold, assert,
Jeff Lind9cd7042020-11-20 15:49:28 +0800369 assertValue](boost::system::error_code ec) {
Zhikui Ren12c2c0e2021-04-28 17:21:21 -0700370 auto sensorPtr = weakSensor.lock();
371 if (!sensorPtr)
372 {
373 return; // owner sensor has been destructed
374 }
375 // pair is valid as long as sensor is valid
Jeff Lind9cd7042020-11-20 15:49:28 +0800376 pair->first.used = false;
377
378 if (ec == boost::asio::error::operation_aborted)
379 {
380 return; // we're being canceled
381 }
382 if (ec)
383 {
George Liu61984352025-02-24 14:47:34 +0800384 lg2::error("timer error: '{ERROR_MESSAGE}'", "ERROR_MESSAGE",
385 ec.message());
Jeff Lind9cd7042020-11-20 15:49:28 +0800386 return;
387 }
Zhikui Ren12c2c0e2021-04-28 17:21:21 -0700388 if (sensorPtr->readingStateGood())
Jeff Lind9cd7042020-11-20 15:49:28 +0800389 {
Zhikui Ren12c2c0e2021-04-28 17:21:21 -0700390 assertThresholds(sensorPtr.get(), assertValue, threshold.level,
Jeff Lind9cd7042020-11-20 15:49:28 +0800391 threshold.direction, assert);
392 }
393 });
394}
395
James Feist46342ec2019-03-06 14:03:41 -0800396bool checkThresholds(Sensor* sensor)
397{
James Feist7b18b1e2019-05-14 13:42:09 -0700398 bool status = true;
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700399 std::vector<ChangeParam> changes = checkThresholds(sensor, sensor->value);
400 for (const auto& change : changes)
James Feist46342ec2019-03-06 14:03:41 -0800401 {
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700402 assertThresholds(sensor, change.assertValue, change.threshold.level,
403 change.threshold.direction, change.asserted);
404 if (change.threshold.level == thresholds::Level::CRITICAL &&
405 change.asserted)
James Feist46342ec2019-03-06 14:03:41 -0800406 {
James Feist7b18b1e2019-05-14 13:42:09 -0700407 status = false;
James Feist46342ec2019-03-06 14:03:41 -0800408 }
409 }
410
James Feistdc6c55f2018-10-31 12:53:20 -0700411 return status;
James Feist251c7822018-09-12 12:54:15 -0700412}
413
Zhikui Ren12c2c0e2021-04-28 17:21:21 -0700414void checkThresholdsPowerDelay(const std::weak_ptr<Sensor>& weakSensor,
415 ThresholdTimer& thresholdTimer)
James Feist46342ec2019-03-06 14:03:41 -0800416{
Zhikui Ren12c2c0e2021-04-28 17:21:21 -0700417 auto sensorPtr = weakSensor.lock();
418 if (!sensorPtr)
419 {
420 return; // sensor is destructed, should never be here
421 }
James Feist46342ec2019-03-06 14:03:41 -0800422
Zhikui Ren12c2c0e2021-04-28 17:21:21 -0700423 Sensor* sensor = sensorPtr.get();
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700424 std::vector<ChangeParam> changes = checkThresholds(sensor, sensor->value);
425 for (const auto& change : changes)
James Feist46342ec2019-03-06 14:03:41 -0800426 {
Zhikui Renbf7cbc82020-07-02 08:44:00 -0700427 // When CPU is powered off, some volatges are expected to
428 // go below low thresholds. Filter these events with thresholdTimer.
429 // 1. always delay the assertion of low events to see if they are
430 // caused by power off event.
431 // 2. conditional delay the de-assertion of low events if there is
432 // an existing timer for assertion.
433 // 3. no delays for de-assert of low events if there is an existing
434 // de-assert for low event. This means 2nd de-assert would happen
435 // first and when timer expires for the previous one, no additional
436 // signal will be logged.
437 // 4. no delays for all high events.
438 if (change.threshold.direction == thresholds::Direction::LOW)
James Feist46342ec2019-03-06 14:03:41 -0800439 {
Zhikui Renbf7cbc82020-07-02 08:44:00 -0700440 if (change.asserted || thresholdTimer.hasActiveTimer(
441 change.threshold, !change.asserted))
442 {
Zhikui Ren12c2c0e2021-04-28 17:21:21 -0700443 thresholdTimer.startTimer(weakSensor, change.threshold,
444 change.asserted, change.assertValue);
Zhikui Renbf7cbc82020-07-02 08:44:00 -0700445 continue;
446 }
James Feist46342ec2019-03-06 14:03:41 -0800447 }
Zhikui Renbf7cbc82020-07-02 08:44:00 -0700448 assertThresholds(sensor, change.assertValue, change.threshold.level,
449 change.threshold.direction, change.asserted);
James Feist46342ec2019-03-06 14:03:41 -0800450 }
451}
452
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700453void assertThresholds(Sensor* sensor, double assertValue,
454 thresholds::Level level, thresholds::Direction direction,
455 bool assert)
James Feist251c7822018-09-12 12:54:15 -0700456{
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530457 std::shared_ptr<sdbusplus::asio::dbus_interface> interface =
458 sensor->getThresholdInterface(level);
459
James Feist251c7822018-09-12 12:54:15 -0700460 if (!interface)
461 {
George Liu61984352025-02-24 14:47:34 +0800462 lg2::info("trying to set uninitialized interface");
James Feist251c7822018-09-12 12:54:15 -0700463 return;
464 }
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700465
Ed Tanous2049bd22022-07-09 07:20:26 -0700466 std::string property = Sensor::propertyAlarm(level, direction);
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530467 if (property.empty())
468 {
George Liu61984352025-02-24 14:47:34 +0800469 lg2::info("Alarm property is empty");
Jayashree Dhanapal45f27022021-12-07 12:56:35 +0530470 return;
471 }
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700472 if (interface->set_property<bool, true>(property, assert))
473 {
474 try
475 {
476 // msg.get_path() is interface->get_object_path()
Patrick Williams92f8f512022-07-22 19:26:55 -0500477 sdbusplus::message_t msg =
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700478 interface->new_signal("ThresholdAsserted");
479
480 msg.append(sensor->name, interface->get_interface_name(), property,
481 assert, assertValue);
482 msg.signal_send();
483 }
Patrick Williams92f8f512022-07-22 19:26:55 -0500484 catch (const sdbusplus::exception_t& e)
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700485 {
George Liu61984352025-02-24 14:47:34 +0800486 lg2::error(
487 "Failed to send thresholdAsserted signal with assertValue");
Zhikui Ren59b8b9e2020-06-26 18:34:22 -0700488 }
489 }
James Feist251c7822018-09-12 12:54:15 -0700490}
491
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700492bool parseThresholdsFromAttr(
James Feistd8705872019-02-08 13:26:09 -0800493 std::vector<thresholds::Threshold>& thresholdVector,
Vijay Khemka86dea2b2019-06-06 11:14:37 -0700494 const std::string& inputPath, const double& scaleFactor,
Chris Sidesa3279232023-04-24 16:08:13 -0500495 const double& offset, const double& hysteresis)
James Feist6714a252018-09-10 15:26:18 -0700496{
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +0200497 const boost::container::flat_map<
498 std::string, std::vector<std::tuple<const char*, thresholds::Level,
499 thresholds::Direction, double>>>
500 map = {
501 {"average",
502 {
503 std::make_tuple("average_min", Level::WARNING, Direction::LOW,
504 0.0),
505 std::make_tuple("average_max", Level::WARNING, Direction::HIGH,
506 0.0),
507 }},
508 {"input",
509 {
510 std::make_tuple("min", Level::WARNING, Direction::LOW, 0.0),
511 std::make_tuple("max", Level::WARNING, Direction::HIGH, 0.0),
512 std::make_tuple("lcrit", Level::CRITICAL, Direction::LOW, 0.0),
513 std::make_tuple("crit", Level::CRITICAL, Direction::HIGH,
514 offset),
515 }},
516 };
517
518 if (auto fileParts = splitFileName(inputPath))
James Feist6714a252018-09-10 15:26:18 -0700519 {
Zbigniew Kurzynskidbfd4662020-09-28 18:06:00 +0200520 auto& [type, nr, item] = *fileParts;
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +0200521 if (map.count(item) != 0)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700522 {
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +0200523 for (const auto& t : map.at(item))
524 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700525 const auto& [suffix, level, direction, offset] = t;
Patrick Williams2aaf7172024-08-16 15:20:40 -0400526 auto attrPath =
527 boost::replace_all_copy(inputPath, item, suffix);
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +0200528 if (auto val = readFile(attrPath, scaleFactor))
529 {
530 *val += offset;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700531 if (debug)
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +0200532 {
George Liu61984352025-02-24 14:47:34 +0800533 lg2::info("Threshold: '{PATH}': '{VALUE}'", "PATH",
534 attrPath, "VALUE", *val);
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +0200535 }
Chris Sidesa3279232023-04-24 16:08:13 -0500536 thresholdVector.emplace_back(level, direction, *val,
537 hysteresis);
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +0200538 }
539 }
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700540 }
James Feist6714a252018-09-10 15:26:18 -0700541 }
James Feist6714a252018-09-10 15:26:18 -0700542 return true;
543}
544
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530545std::string getInterface(const Level thresholdLevel)
James Feist6714a252018-09-10 15:26:18 -0700546{
Ed Tanousc8fed202022-01-12 14:24:45 -0800547 for (const ThresholdDefinition& thresh : thresProp)
James Feist6714a252018-09-10 15:26:18 -0700548 {
Ed Tanousc8fed202022-01-12 14:24:45 -0800549 if (thresh.level == thresholdLevel)
550 {
551 return std::string("xyz.openbmc_project.Sensor.Threshold.") +
552 thresh.levelName;
553 }
James Feist6714a252018-09-10 15:26:18 -0700554 }
Ed Tanousc8fed202022-01-12 14:24:45 -0800555 return "";
James Feist6714a252018-09-10 15:26:18 -0700556}
557} // namespace thresholds