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