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