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), 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 22 void NumericThreshold::initialize() 23 { 24 ThresholdOperations::initialize(this); 25 } 26 27 void NumericThreshold::updateSensors(Sensors newSensors) 28 { 29 ThresholdOperations::updateSensors(this, std::move(newSensors)); 30 } 31 32 NumericThreshold::ThresholdDetail& 33 NumericThreshold::getDetails(const interfaces::Sensor& sensor) 34 { 35 return ThresholdOperations::getDetails(this, sensor); 36 } 37 38 std::shared_ptr<NumericThreshold::ThresholdDetail> 39 NumericThreshold::makeDetails(const std::string& sensorName) 40 { 41 return std::make_shared<ThresholdDetail>(sensorName, ioc); 42 } 43 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 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 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 129 LabeledThresholdParam NumericThreshold::getThresholdParam() const 130 { 131 return numeric::LabeledThresholdParam(type, dwellTime.count(), direction, 132 thresholdValue); 133 } 134