1 #include "numeric_threshold.hpp"
2 
3 #include <phosphor-logging/log.hpp>
4 
5 NumericThreshold::NumericThreshold(
6     boost::asio::io_context& ioc,
7     std::vector<std::shared_ptr<interfaces::Sensor>> sensorsIn,
8     std::vector<std::string> sensorNames,
9     std::vector<std::unique_ptr<interfaces::TriggerAction>> actionsIn,
10     std::chrono::milliseconds dwellTimeIn, numeric::Direction direction,
11     double thresholdValueIn) :
12     ioc(ioc),
13     sensors(std::move(sensorsIn)), actions(std::move(actionsIn)),
14     dwellTime(dwellTimeIn), direction(direction),
15     thresholdValue(thresholdValueIn)
16 {
17     details.reserve(sensors.size());
18     for (size_t i = 0; i < sensors.size(); i++)
19     {
20         details.emplace_back(sensorNames[i], thresholdValue, false, ioc);
21     }
22 }
23 
24 NumericThreshold::~NumericThreshold()
25 {}
26 
27 void NumericThreshold::initialize()
28 {
29     for (auto& sensor : sensors)
30     {
31         sensor->registerForUpdates(weak_from_this());
32     }
33 }
34 
35 NumericThreshold::ThresholdDetail&
36     NumericThreshold::getDetails(interfaces::Sensor& sensor)
37 {
38     auto it =
39         std::find_if(sensors.begin(), sensors.end(),
40                      [&sensor](const auto& x) { return &sensor == x.get(); });
41     auto index = std::distance(sensors.begin(), it);
42     return details.at(index);
43 }
44 
45 void NumericThreshold::sensorUpdated(interfaces::Sensor& sensor,
46                                      uint64_t timestamp)
47 {}
48 
49 void NumericThreshold::sensorUpdated(interfaces::Sensor& sensor,
50                                      uint64_t timestamp, double value)
51 {
52     auto& [sensorName, prevValue, dwell, timer] = getDetails(sensor);
53     bool decreasing = thresholdValue < prevValue && thresholdValue > value;
54     bool increasing = thresholdValue > prevValue && thresholdValue < value;
55 
56     if (dwell && (increasing || decreasing))
57     {
58         timer.cancel();
59         dwell = false;
60     }
61     if ((direction == numeric::Direction::decreasing && decreasing) ||
62         (direction == numeric::Direction::increasing && increasing) ||
63         (direction == numeric::Direction::either && (increasing || decreasing)))
64     {
65         startTimer(sensorName, timestamp, value, dwell, timer);
66     }
67 
68     prevValue = value;
69 }
70 
71 void NumericThreshold::startTimer(const std::string& sensorName,
72                                   uint64_t timestamp, double value, bool& dwell,
73                                   boost::asio::steady_timer& timer)
74 {
75     if (dwellTime == std::chrono::milliseconds::zero())
76     {
77         commit(sensorName, timestamp, value);
78     }
79     else
80     {
81         dwell = true;
82         timer.expires_after(dwellTime);
83         timer.async_wait([this, sensorName, timestamp, value,
84                           &dwell](const boost::system::error_code ec) {
85             if (ec)
86             {
87                 phosphor::logging::log<phosphor::logging::level::DEBUG>(
88                     "Timer has been canceled");
89                 return;
90             }
91             commit(sensorName, timestamp, value);
92             dwell = false;
93         });
94     }
95 }
96 
97 void NumericThreshold::commit(const std::string& sensorName, uint64_t timestamp,
98                               double value)
99 {
100     for (const auto& action : actions)
101     {
102         action->commit(sensorName, timestamp, value);
103     }
104 }
105