Fix numeric threshold
There was an issue when sensor value reach threshold set by the user.
Example: given numeric threshold, set as increasing with value of 20.0,
and following sensor updates: 20 -> 30 -> 40, trigger action would not
start, which is clearly a defect, as 30 is crossed.
Testing done:
- numeric threshold now works with example given above.
- UTs were updated and are passing.
Signed-off-by: Szymon Dompke <szymon.dompke@intel.com>
Change-Id: I955876e076f2286efd98d187cae775a7ab2f4e28
diff --git a/src/discrete_threshold.cpp b/src/discrete_threshold.cpp
index 2acb2bf..ad3b153 100644
--- a/src/discrete_threshold.cpp
+++ b/src/discrete_threshold.cpp
@@ -43,14 +43,15 @@
std::shared_ptr<DiscreteThreshold::ThresholdDetail>
DiscreteThreshold::makeDetails(const std::string& sensorName)
{
- return std::make_shared<ThresholdDetail>(sensorName, false, ioc);
+ return std::make_shared<ThresholdDetail>(sensorName, ioc);
}
void DiscreteThreshold::sensorUpdated(interfaces::Sensor& sensor,
Milliseconds timestamp, double value)
{
auto& details = getDetails(sensor);
- auto& [sensorName, dwell, timer] = details;
+ auto& dwell = details.dwell;
+ auto& timer = details.timer;
if (dwell && value != numericThresholdValue)
{
@@ -66,7 +67,7 @@
void DiscreteThreshold::startTimer(DiscreteThreshold::ThresholdDetail& details,
double value)
{
- const auto& sensorName = details.sensorName;
+ auto& sensorName = details.getSensorName();
auto& dwell = details.dwell;
auto& timer = details.timer;
diff --git a/src/discrete_threshold.hpp b/src/discrete_threshold.hpp
index 48510de..3b0d101 100644
--- a/src/discrete_threshold.hpp
+++ b/src/discrete_threshold.hpp
@@ -51,17 +51,24 @@
struct ThresholdDetail
{
- std::string sensorName;
- bool dwell;
+ bool dwell = false;
boost::asio::steady_timer timer;
- ThresholdDetail(const std::string& name, bool dwell,
+ ThresholdDetail(const std::string& sensorNameIn,
boost::asio::io_context& ioc) :
- sensorName(name),
- dwell(dwell), timer(ioc)
+ timer(ioc),
+ sensorName(sensorNameIn)
{}
ThresholdDetail(const ThresholdDetail&) = delete;
ThresholdDetail(ThresholdDetail&&) = delete;
+
+ const std::string& getSensorName()
+ {
+ return sensorName;
+ }
+
+ private:
+ std::string sensorName;
};
using SensorDetails =
std::unordered_map<std::shared_ptr<interfaces::Sensor>,
diff --git a/src/numeric_threshold.cpp b/src/numeric_threshold.cpp
index 24683a2..0b60dac 100644
--- a/src/numeric_threshold.cpp
+++ b/src/numeric_threshold.cpp
@@ -39,37 +39,60 @@
std::shared_ptr<NumericThreshold::ThresholdDetail>
NumericThreshold::makeDetails(const std::string& sensorName)
{
- return std::make_shared<ThresholdDetail>(sensorName, thresholdValue, false,
- ioc);
+ return std::make_shared<ThresholdDetail>(sensorName, ioc);
}
void NumericThreshold::sensorUpdated(interfaces::Sensor& sensor,
Milliseconds timestamp, double value)
{
auto& details = getDetails(sensor);
- auto& [sensorName, prevValue, dwell, timer] = details;
- bool decreasing = thresholdValue < prevValue && thresholdValue > value;
- bool increasing = thresholdValue > prevValue && thresholdValue < value;
+ auto& prevValue = details.prevValue;
+ auto& prevDirection = details.prevDirection;
+ auto& dwell = details.dwell;
+ auto& timer = details.timer;
- if (dwell && (increasing || decreasing))
+ 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 && decreasing) ||
- (direction == numeric::Direction::increasing && increasing) ||
- (direction == numeric::Direction::either && (increasing || decreasing)))
+ 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)
{
- const auto& sensorName = details.sensorName;
+ auto& sensorName = details.getSensorName();
auto& dwell = details.dwell;
auto& timer = details.timer;
diff --git a/src/numeric_threshold.hpp b/src/numeric_threshold.hpp
index 4e47721..4b861a3 100644
--- a/src/numeric_threshold.hpp
+++ b/src/numeric_threshold.hpp
@@ -50,18 +50,26 @@
struct ThresholdDetail
{
- std::string sensorName;
- double prevValue;
- bool dwell;
+ std::optional<double> prevValue = std::nullopt;
+ numeric::Direction prevDirection = numeric::Direction::either;
+ bool dwell = false;
boost::asio::steady_timer timer;
- ThresholdDetail(const std::string& name, double prevValue, bool dwell,
+ ThresholdDetail(const std::string& sensorNameIn,
boost::asio::io_context& ioc) :
- sensorName(name),
- prevValue(prevValue), dwell(dwell), timer(ioc)
+ timer(ioc),
+ sensorName(sensorNameIn)
{}
ThresholdDetail(const ThresholdDetail&) = delete;
ThresholdDetail(ThresholdDetail&&) = delete;
+
+ const std::string& getSensorName()
+ {
+ return sensorName;
+ }
+
+ private:
+ std::string sensorName;
};
using SensorDetails =
std::unordered_map<std::shared_ptr<interfaces::Sensor>,
diff --git a/tests/src/test_numeric_threshold.cpp b/tests/src/test_numeric_threshold.cpp
index 69ad0de..902e72f 100644
--- a/tests/src/test_numeric_threshold.cpp
+++ b/tests/src/test_numeric_threshold.cpp
@@ -320,7 +320,43 @@
.Direction(numeric::Direction::either)
.InitialValues({100.0, 80.0})
.Updates({{0, 85.0}, {1, 91.0}})
- .Expected({{0, 85.0}, {1, 91.0}})));
+ .Expected({{0, 85.0}, {1, 91.0}}),
+ NumericParams()
+ .ThresholdValue(30.0)
+ .Direction(numeric::Direction::decreasing)
+ .InitialValues({40.0})
+ .Updates({{0, 30.0}, {0, 20.0}})
+ .Expected({{0, 20.0}}),
+ NumericParams()
+ .ThresholdValue(30.0)
+ .Direction(numeric::Direction::decreasing)
+ .InitialValues({20.0})
+ .Updates({{0, 30.0}, {0, 20.0}})
+ .Expected({}),
+ NumericParams()
+ .ThresholdValue(30.0)
+ .Direction(numeric::Direction::either)
+ .InitialValues({20.0})
+ .Updates({{0, 30.0}, {0, 20.0}})
+ .Expected({}),
+ NumericParams()
+ .ThresholdValue(30.0)
+ .Direction(numeric::Direction::increasing)
+ .InitialValues({20.0})
+ .Updates({{0, 30.0}, {0, 40.0}})
+ .Expected({{0, 40.0}}),
+ NumericParams()
+ .ThresholdValue(30.0)
+ .Direction(numeric::Direction::increasing)
+ .InitialValues({40.0})
+ .Updates({{0, 30.0}, {0, 40.0}})
+ .Expected({}),
+ NumericParams()
+ .ThresholdValue(30.0)
+ .Direction(numeric::Direction::either)
+ .InitialValues({40.0})
+ .Updates({{0, 30.0}, {0, 40.0}})
+ .Expected({})));
TEST_P(TestNumericThresholdNoDwellTime, senorsIsUpdatedMultipleTimes)
{