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