blob: 0b60dac848809069f509962c2dc5e0f9df9207c6 [file] [log] [blame]
#include "numeric_threshold.hpp"
#include <phosphor-logging/log.hpp>
NumericThreshold::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) :
ioc(ioc),
triggerId(triggerIdIn), actions(std::move(actionsIn)),
dwellTime(dwellTimeIn), direction(directionIn),
thresholdValue(thresholdValueIn), type(typeIn), clock(std::move(clockIn))
{
for (const auto& sensor : sensorsIn)
{
sensorDetails.emplace(sensor, makeDetails(sensor->getName()));
}
}
void NumericThreshold::initialize()
{
ThresholdOperations::initialize(this);
}
void NumericThreshold::updateSensors(Sensors newSensors)
{
ThresholdOperations::updateSensors(this, std::move(newSensors));
}
NumericThreshold::ThresholdDetail&
NumericThreshold::getDetails(const interfaces::Sensor& sensor)
{
return ThresholdOperations::getDetails(this, sensor);
}
std::shared_ptr<NumericThreshold::ThresholdDetail>
NumericThreshold::makeDetails(const std::string& sensorName)
{
return std::make_shared<ThresholdDetail>(sensorName, ioc);
}
void NumericThreshold::sensorUpdated(interfaces::Sensor& sensor,
Milliseconds timestamp, double value)
{
auto& details = getDetails(sensor);
auto& prevValue = details.prevValue;
auto& prevDirection = details.prevDirection;
auto& dwell = details.dwell;
auto& timer = details.timer;
if (!prevValue)
{
prevValue = value;
return;
}
bool crossedDecreasing =
thresholdValue < prevValue && thresholdValue > value;
bool crossedIncreasing =
thresholdValue > prevValue && thresholdValue < value;
if (!crossedDecreasing && !crossedIncreasing && thresholdValue == prevValue)
{
crossedDecreasing = prevDirection == numeric::Direction::decreasing &&
thresholdValue > value;
crossedIncreasing = prevDirection == numeric::Direction::increasing &&
thresholdValue < value;
}
if (dwell && (crossedIncreasing || crossedDecreasing))
{
timer.cancel();
dwell = false;
}
if ((direction == numeric::Direction::decreasing && crossedDecreasing) ||
(direction == numeric::Direction::increasing && crossedIncreasing) ||
(direction == numeric::Direction::either &&
(crossedIncreasing || crossedDecreasing)))
{
startTimer(details, value);
}
prevDirection = value > prevValue ? numeric::Direction::increasing
: value < prevValue ? numeric::Direction::decreasing
: numeric::Direction::either;
prevValue = value;
}
void NumericThreshold::startTimer(NumericThreshold::ThresholdDetail& details,
double value)
{
auto& sensorName = details.getSensorName();
auto& dwell = details.dwell;
auto& timer = details.timer;
if (dwellTime == Milliseconds::zero())
{
commit(sensorName, value);
}
else
{
dwell = true;
timer.expires_after(dwellTime);
timer.async_wait([this, &sensorName, &dwell,
value](const boost::system::error_code ec) {
if (ec)
{
phosphor::logging::log<phosphor::logging::level::DEBUG>(
"Timer has been canceled");
return;
}
commit(sensorName, value);
dwell = false;
});
}
}
void NumericThreshold::commit(const std::string& sensorName, double value)
{
Milliseconds timestamp = clock->systemTimestamp();
for (const auto& action : actions)
{
action->commit(triggerId, std::nullopt, sensorName, timestamp, value);
}
}
LabeledThresholdParam NumericThreshold::getThresholdParam() const
{
return numeric::LabeledThresholdParam(type, dwellTime.count(), direction,
thresholdValue);
}