Add sensor deassert tracking

Get sensor event status command needs this information.

Tested: Used sensor override and made fan cross a threshold,
then go back. Get sensor event status command had correct
bits set.

Change-Id: I8d8c7203ea6cb1d0e467f6267445e2d7395426a6
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/include/sensorcommands.hpp b/include/sensorcommands.hpp
index 2a67d0c..e5bed10 100644
--- a/include/sensorcommands.hpp
+++ b/include/sensorcommands.hpp
@@ -74,9 +74,8 @@
     uint8_t enabled;
     uint8_t assertionsLSB;
     uint8_t assertionsMSB;
-    // deassertion events currently not supported
-    // uint8_t deassertionsLSB;
-    // uint8_t deassertionsMSB;
+    uint8_t deassertionsLSB;
+    uint8_t deassertionsMSB;
 };
 #pragma pack(pop)
 
diff --git a/src/sensorcommands.cpp b/src/sensorcommands.cpp
index 85238ef..1666d0b 100644
--- a/src/sensorcommands.cpp
+++ b/src/sensorcommands.cpp
@@ -94,6 +94,56 @@
                             .count();
     });
 
+// this keeps track of deassertions for sensor event status command. A
+// deasertion can only happen if an assertion was seen first.
+static boost::container::flat_map<
+    std::string, boost::container::flat_map<std::string, std::optional<bool>>>
+    thresholdDeassertMap;
+
+static sdbusplus::bus::match::match thresholdChanged(
+    dbus,
+    "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
+    "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
+    [](sdbusplus::message::message &m) {
+        boost::container::flat_map<std::string, std::variant<bool, double>>
+            values;
+        m.read(std::string(), values);
+
+        auto findAssert =
+            std::find_if(values.begin(), values.end(), [](const auto &pair) {
+                return pair.first.find("Alarm") != std::string::npos;
+            });
+        if (findAssert != values.end())
+        {
+            auto ptr = std::get_if<bool>(&(findAssert->second));
+            if (ptr == nullptr)
+            {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    "thresholdChanged: Assert non bool");
+                return;
+            }
+            if (*ptr)
+            {
+                phosphor::logging::log<phosphor::logging::level::INFO>(
+                    "thresholdChanged: Assert",
+                    phosphor::logging::entry("SENSOR=%s", m.get_path()));
+                thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
+            }
+            else
+            {
+                auto &value =
+                    thresholdDeassertMap[m.get_path()][findAssert->first];
+                if (value)
+                {
+                    phosphor::logging::log<phosphor::logging::level::INFO>(
+                        "thresholdChanged: deassert",
+                        phosphor::logging::entry("SENSOR=%s", m.get_path()));
+                    value = *ptr;
+                }
+            }
+        }
+    });
+
 static void
     getSensorMaxMin(const std::map<std::string, DbusVariant> &sensorPropertyMap,
                     double &max, double &min)
@@ -694,6 +744,36 @@
     resp->enabled =
         static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
 
+    std::optional<bool> criticalDeassertHigh =
+        thresholdDeassertMap[path]["CriticalAlarmHigh"];
+    std::optional<bool> criticalDeassertLow =
+        thresholdDeassertMap[path]["CriticalAlarmLow"];
+    std::optional<bool> warningDeassertHigh =
+        thresholdDeassertMap[path]["WarningAlarmHigh"];
+    std::optional<bool> warningDeassertLow =
+        thresholdDeassertMap[path]["WarningAlarmLow"];
+
+    if (criticalDeassertHigh && !*criticalDeassertHigh)
+    {
+        resp->deassertionsMSB |= static_cast<uint8_t>(
+            IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
+    }
+    if (criticalDeassertLow && !*criticalDeassertLow)
+    {
+        resp->deassertionsMSB |= static_cast<uint8_t>(
+            IPMISensorEventEnableThresholds::upperCriticalGoingLow);
+    }
+    if (warningDeassertHigh && !*warningDeassertHigh)
+    {
+        resp->deassertionsLSB |= static_cast<uint8_t>(
+            IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
+    }
+    if (warningDeassertLow && !*warningDeassertLow)
+    {
+        resp->deassertionsLSB |= static_cast<uint8_t>(
+            IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
+    }
+
     if ((warningInterface != sensorMap.end()) ||
         (criticalInterface != sensorMap.end()))
     {