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