xref: /openbmc/telemetry/src/numeric_threshold.cpp (revision f535cad6545d39fe58f50d0f23074359f43f8a03)
1 #include "numeric_threshold.hpp"
2 
3 #include <phosphor-logging/log.hpp>
4 
NumericThreshold(boost::asio::io_context & ioc,const std::string & triggerIdIn,Sensors sensorsIn,std::vector<std::unique_ptr<interfaces::TriggerAction>> actionsIn,Milliseconds dwellTimeIn,numeric::Direction directionIn,double thresholdValueIn,numeric::Type typeIn,std::unique_ptr<interfaces::Clock> clockIn)5 NumericThreshold::NumericThreshold(
6     boost::asio::io_context& ioc, const std::string& triggerIdIn,
7     Sensors sensorsIn,
8     std::vector<std::unique_ptr<interfaces::TriggerAction>> actionsIn,
9     Milliseconds dwellTimeIn, numeric::Direction directionIn,
10     double thresholdValueIn, numeric::Type typeIn,
11     std::unique_ptr<interfaces::Clock> clockIn) :
12     ioc(ioc), triggerId(triggerIdIn), actions(std::move(actionsIn)),
13     dwellTime(dwellTimeIn), direction(directionIn),
14     thresholdValue(thresholdValueIn), type(typeIn), clock(std::move(clockIn))
15 {
16     for (const auto& sensor : sensorsIn)
17     {
18         sensorDetails.emplace(sensor, makeDetails(sensor->getName()));
19     }
20 }
21 
initialize()22 void NumericThreshold::initialize()
23 {
24     ThresholdOperations::initialize(this);
25 }
26 
updateSensors(Sensors newSensors)27 void NumericThreshold::updateSensors(Sensors newSensors)
28 {
29     ThresholdOperations::updateSensors(this, std::move(newSensors));
30 }
31 
32 NumericThreshold::ThresholdDetail&
getDetails(const interfaces::Sensor & sensor)33     NumericThreshold::getDetails(const interfaces::Sensor& sensor)
34 {
35     return ThresholdOperations::getDetails(this, sensor);
36 }
37 
38 std::shared_ptr<NumericThreshold::ThresholdDetail>
makeDetails(const std::string & sensorName)39     NumericThreshold::makeDetails(const std::string& sensorName)
40 {
41     return std::make_shared<ThresholdDetail>(sensorName, ioc);
42 }
43 
sensorUpdated(interfaces::Sensor & sensor,Milliseconds timestamp,double value)44 void NumericThreshold::sensorUpdated(interfaces::Sensor& sensor,
45                                      Milliseconds timestamp, double value)
46 {
47     auto& details = getDetails(sensor);
48     auto& prevValue = details.prevValue;
49     auto& prevDirection = details.prevDirection;
50     auto& dwell = details.dwell;
51     auto& timer = details.timer;
52 
53     if (!prevValue)
54     {
55         prevValue = value;
56         return;
57     }
58 
59     bool crossedDecreasing = thresholdValue < prevValue &&
60                              thresholdValue > value;
61     bool crossedIncreasing = thresholdValue > prevValue &&
62                              thresholdValue < value;
63 
64     if (!crossedDecreasing && !crossedIncreasing && thresholdValue == prevValue)
65     {
66         crossedDecreasing = prevDirection == numeric::Direction::decreasing &&
67                             thresholdValue > value;
68         crossedIncreasing = prevDirection == numeric::Direction::increasing &&
69                             thresholdValue < value;
70     }
71 
72     if (dwell && (crossedIncreasing || crossedDecreasing))
73     {
74         timer.cancel();
75         dwell = false;
76     }
77     if ((direction == numeric::Direction::decreasing && crossedDecreasing) ||
78         (direction == numeric::Direction::increasing && crossedIncreasing) ||
79         (direction == numeric::Direction::either &&
80          (crossedIncreasing || crossedDecreasing)))
81     {
82         startTimer(details, value);
83     }
84 
85     prevDirection = value > prevValue   ? numeric::Direction::increasing
86                     : value < prevValue ? numeric::Direction::decreasing
87                                         : numeric::Direction::either;
88     prevValue = value;
89 }
90 
startTimer(NumericThreshold::ThresholdDetail & details,double value)91 void NumericThreshold::startTimer(NumericThreshold::ThresholdDetail& details,
92                                   double value)
93 {
94     auto& sensorName = details.getSensorName();
95     auto& dwell = details.dwell;
96     auto& timer = details.timer;
97 
98     if (dwellTime == Milliseconds::zero())
99     {
100         commit(sensorName, value);
101     }
102     else
103     {
104         dwell = true;
105         timer.expires_after(dwellTime);
106         timer.async_wait([this, &sensorName, &dwell,
107                           value](const boost::system::error_code ec) {
108             if (ec)
109             {
110                 phosphor::logging::log<phosphor::logging::level::DEBUG>(
111                     "Timer has been canceled");
112                 return;
113             }
114             commit(sensorName, value);
115             dwell = false;
116         });
117     }
118 }
119 
commit(const std::string & sensorName,double value)120 void NumericThreshold::commit(const std::string& sensorName, double value)
121 {
122     Milliseconds timestamp = clock->systemTimestamp();
123     for (const auto& action : actions)
124     {
125         action->commit(triggerId, std::nullopt, sensorName, timestamp, value);
126     }
127 }
128 
getThresholdParam() const129 LabeledThresholdParam NumericThreshold::getThresholdParam() const
130 {
131     return numeric::LabeledThresholdParam(type, dwellTime.count(), direction,
132                                           thresholdValue);
133 }
134