platform-mc: Add sensor manager

Added sensor_manager class. The sensor_manager class manages the timing
of sensor polling.

tested: Verified on ast2600 EVB which is connected to a PLDM device
over I2C. bmcweb can display the state of numeric sensor.

Signed-off-by: Gilbert Chen <gilbert.chen@arm.com>
Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Change-Id: I4257f823ea26d7fdb322cc82d847e94db056258c
diff --git a/platform-mc/numeric_sensor.cpp b/platform-mc/numeric_sensor.cpp
index ad563fd..af6efad 100644
--- a/platform-mc/numeric_sensor.cpp
+++ b/platform-mc/numeric_sensor.cpp
@@ -15,11 +15,10 @@
 namespace platform_mc
 {
 
-NumericSensor::NumericSensor(const pldm_tid_t tid, const bool sensorDisabled,
-                             std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr,
-                             std::string& sensorName,
-                             std::string& associationPath) :
-    tid(tid), sensorName(sensorName), isPriority(false)
+NumericSensor::NumericSensor(
+    const pldm_tid_t tid, const bool sensorDisabled,
+    std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr, std::string& sensorName,
+    std::string& associationPath) : tid(tid), sensorName(sensorName)
 {
     if (!pdr)
     {
@@ -264,6 +263,7 @@
     resolution = pdr->resolution;
     offset = pdr->offset;
     baseUnitModifier = pdr->unit_modifier;
+    timeStamp = 0;
 
     /**
      * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
@@ -362,7 +362,7 @@
     const pldm_tid_t tid, const bool sensorDisabled,
     std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr,
     std::string& sensorName, std::string& associationPath) :
-    tid(tid), sensorName(sensorName), isPriority(false)
+    tid(tid), sensorName(sensorName)
 {
     if (!pdr)
     {
@@ -478,6 +478,7 @@
     resolution = std::numeric_limits<double>::quiet_NaN();
     offset = std::numeric_limits<double>::quiet_NaN();
     baseUnitModifier = pdr->unit_modifier;
+    timeStamp = 0;
 
     /**
      * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
@@ -579,5 +580,175 @@
 {
     return std::isnan(value) ? value : value * std::pow(10, baseUnitModifier);
 }
+
+void NumericSensor::updateReading(bool available, bool functional, double value)
+{
+    if (!availabilityIntf || !operationalStatusIntf || !valueIntf)
+    {
+        lg2::error(
+            "Failed to update sensor {NAME} D-Bus interface don't exist.",
+            "NAME", sensorName);
+        return;
+    }
+    availabilityIntf->available(available);
+    operationalStatusIntf->functional(functional);
+    double curValue = valueIntf->value();
+    double newValue = std::numeric_limits<double>::quiet_NaN();
+    if (functional && available)
+    {
+        newValue = unitModifier(conversionFormula(value));
+        if (newValue != curValue &&
+            (!std::isnan(newValue) || !std::isnan(curValue)))
+        {
+            valueIntf->value(newValue);
+            updateThresholds();
+        }
+    }
+    else
+    {
+        if (newValue != curValue &&
+            (!std::isnan(newValue) || !std::isnan(curValue)))
+        {
+            valueIntf->value(std::numeric_limits<double>::quiet_NaN());
+        }
+    }
+}
+
+void NumericSensor::handleErrGetSensorReading()
+{
+    if (!operationalStatusIntf || !valueIntf)
+    {
+        lg2::error(
+            "Failed to update sensor {NAME} D-Bus interfaces don't exist.",
+            "NAME", sensorName);
+        return;
+    }
+    operationalStatusIntf->functional(false);
+    valueIntf->value(std::numeric_limits<double>::quiet_NaN());
+}
+
+bool NumericSensor::checkThreshold(bool alarm, bool direction, double value,
+                                   double threshold, double hyst)
+{
+    if (direction)
+    {
+        if (value >= threshold)
+        {
+            return true;
+        }
+        if (value < (threshold - hyst))
+        {
+            return false;
+        }
+    }
+    else
+    {
+        if (value <= threshold)
+        {
+            return true;
+        }
+        if (value > (threshold + hyst))
+        {
+            return false;
+        }
+    }
+    return alarm;
+}
+
+void NumericSensor::updateThresholds()
+{
+    if (!valueIntf)
+    {
+        lg2::error(
+            "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
+            "NAME", sensorName);
+        return;
+    }
+
+    auto value = valueIntf->value();
+
+    if (thresholdWarningIntf &&
+        !std::isnan(thresholdWarningIntf->warningHigh()))
+    {
+        auto threshold = thresholdWarningIntf->warningHigh();
+        auto alarm = thresholdWarningIntf->warningAlarmHigh();
+        auto newAlarm =
+            checkThreshold(alarm, true, value, threshold, hysteresis);
+        if (alarm != newAlarm)
+        {
+            thresholdWarningIntf->warningAlarmHigh(newAlarm);
+            if (newAlarm)
+            {
+                thresholdWarningIntf->warningHighAlarmAsserted(value);
+            }
+            else
+            {
+                thresholdWarningIntf->warningHighAlarmDeasserted(value);
+            }
+        }
+    }
+
+    if (thresholdWarningIntf && !std::isnan(thresholdWarningIntf->warningLow()))
+    {
+        auto threshold = thresholdWarningIntf->warningLow();
+        auto alarm = thresholdWarningIntf->warningAlarmLow();
+        auto newAlarm =
+            checkThreshold(alarm, false, value, threshold, hysteresis);
+        if (alarm != newAlarm)
+        {
+            thresholdWarningIntf->warningAlarmLow(newAlarm);
+            if (newAlarm)
+            {
+                thresholdWarningIntf->warningLowAlarmAsserted(value);
+            }
+            else
+            {
+                thresholdWarningIntf->warningLowAlarmDeasserted(value);
+            }
+        }
+    }
+
+    if (thresholdCriticalIntf &&
+        !std::isnan(thresholdCriticalIntf->criticalHigh()))
+    {
+        auto threshold = thresholdCriticalIntf->criticalHigh();
+        auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
+        auto newAlarm =
+            checkThreshold(alarm, true, value, threshold, hysteresis);
+        if (alarm != newAlarm)
+        {
+            thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
+            if (newAlarm)
+            {
+                thresholdCriticalIntf->criticalHighAlarmAsserted(value);
+            }
+            else
+            {
+                thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
+            }
+        }
+    }
+
+    if (thresholdCriticalIntf &&
+        !std::isnan(thresholdCriticalIntf->criticalLow()))
+    {
+        auto threshold = thresholdCriticalIntf->criticalLow();
+        auto alarm = thresholdCriticalIntf->criticalAlarmLow();
+        auto newAlarm =
+            checkThreshold(alarm, false, value, threshold, hysteresis);
+        if (alarm != newAlarm)
+        {
+            thresholdCriticalIntf->criticalAlarmLow(newAlarm);
+            if (newAlarm)
+            {
+                thresholdCriticalIntf->criticalLowAlarmAsserted(value);
+            }
+            else
+            {
+                thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
+            }
+        }
+    }
+}
 } // namespace platform_mc
 } // namespace pldm