1 #include "discrete_threshold.hpp"
2 
3 #include "utils/conversion_trigger.hpp"
4 #include "utils/to_short_enum.hpp"
5 
6 #include <phosphor-logging/log.hpp>
7 
8 DiscreteThreshold::DiscreteThreshold(
9     boost::asio::io_context& ioc, const std::string& triggerIdIn,
10     Sensors sensorsIn,
11     std::vector<std::unique_ptr<interfaces::TriggerAction>> actionsIn,
12     Milliseconds dwellTimeIn, const std::string& thresholdValueIn,
13     const std::string& nameIn, const discrete::Severity severityIn,
14     std::unique_ptr<interfaces::Clock> clockIn) :
15     ioc(ioc),
16     triggerId(triggerIdIn), actions(std::move(actionsIn)),
17     dwellTime(dwellTimeIn), thresholdValue(thresholdValueIn),
18     numericThresholdValue(utils::stodStrict(thresholdValue)),
19     severity(severityIn), name(getNonEmptyName(nameIn)),
20     clock(std::move(clockIn))
21 {
22     for (const auto& sensor : sensorsIn)
23     {
24         sensorDetails.emplace(sensor, makeDetails(sensor->getName()));
25     }
26 }
27 
28 void DiscreteThreshold::initialize()
29 {
30     ThresholdOperations::initialize(this);
31 }
32 
33 void DiscreteThreshold::updateSensors(Sensors newSensors)
34 {
35     ThresholdOperations::updateSensors(this, std::move(newSensors));
36 }
37 
38 DiscreteThreshold::ThresholdDetail&
39     DiscreteThreshold::getDetails(const interfaces::Sensor& sensor)
40 {
41     return ThresholdOperations::getDetails(this, sensor);
42 }
43 
44 std::shared_ptr<DiscreteThreshold::ThresholdDetail>
45     DiscreteThreshold::makeDetails(const std::string& sensorName)
46 {
47     return std::make_shared<ThresholdDetail>(sensorName, ioc);
48 }
49 
50 void DiscreteThreshold::sensorUpdated(interfaces::Sensor& sensor,
51                                       Milliseconds timestamp, double value)
52 {
53     auto& details = getDetails(sensor);
54     auto& dwell = details.dwell;
55     auto& timer = details.timer;
56 
57     if (dwell && value != numericThresholdValue)
58     {
59         timer.cancel();
60         dwell = false;
61     }
62     else if (value == numericThresholdValue)
63     {
64         startTimer(details, value);
65     }
66 }
67 
68 void DiscreteThreshold::startTimer(DiscreteThreshold::ThresholdDetail& details,
69                                    double value)
70 {
71     auto& sensorName = details.getSensorName();
72     auto& dwell = details.dwell;
73     auto& timer = details.timer;
74 
75     if (dwellTime == Milliseconds::zero())
76     {
77         commit(sensorName, value);
78     }
79     else
80     {
81         dwell = true;
82         timer.expires_after(dwellTime);
83         timer.async_wait([this, &sensorName, &dwell,
84                           value](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, value);
92             dwell = false;
93         });
94     }
95 }
96 
97 void DiscreteThreshold::commit(const std::string& sensorName, double value)
98 {
99     Milliseconds timestamp = clock->systemTimestamp();
100     for (const auto& action : actions)
101     {
102         action->commit(triggerId, std::cref(name), sensorName, timestamp,
103                        thresholdValue);
104     }
105 }
106 
107 LabeledThresholdParam DiscreteThreshold::getThresholdParam() const
108 {
109     return discrete::LabeledThresholdParam(name, severity, dwellTime.count(),
110                                            thresholdValue);
111 }
112 
113 std::string DiscreteThreshold::getNonEmptyName(const std::string& nameIn) const
114 {
115     if (nameIn.empty())
116     {
117         return std::string(utils::toShortEnum(utils::enumToString(severity))) +
118                " condition";
119     }
120     return nameIn;
121 }
122