platform-mc: sensor: Support HardShutdown threshold in pldm sensors

To support UNR in pldm sensors, add fatal_high/fatal_low bit
of PDR, and then the values will update to ThresholdHardShutdown
interface for pldm sensors.

Tested:
- Check the UNR of the pldm sensors

root@bmc:~# mfg-tool sensor-display 2>/dev/null | table-sensor-display
sensor                                  ...  units    ... UNR
----------------------------------------...  -------- ... -------
SENTINEL_DOME_SLOT_1_MB_SSD_BOOT_TEMP_C      DegreesC     85
SENTINEL_DOME_SLOT_1_MB_SSD_DATA_TEMP_C      DegreesC     85
SENTINEL_DOME_SLOT_1_MB_VR_CPU0_TEMP_C       DegreesC     125
SENTINEL_DOME_SLOT_1_MB_VR_CPU1_TEMP_C       DegreesC     125
SENTINEL_DOME_SLOT_1_MB_VR_PVDD11_TEMP_C     DegreesC     125
SENTINEL_DOME_SLOT_1_MB_VR_PVDDIO_TEMP_C     DegreesC     125

Change-Id: If146a6191fc864988218c39f36038abff1f5d772
Signed-off-by: Zoey YJ Chung <zoey.yj.chung.wiwynn@gmail.com>
diff --git a/platform-mc/numeric_sensor.cpp b/platform-mc/numeric_sensor.cpp
index a0d5dbb..e501ed6 100644
--- a/platform-mc/numeric_sensor.cpp
+++ b/platform-mc/numeric_sensor.cpp
@@ -215,10 +215,13 @@
 
     bool hasCriticalThresholds = false;
     bool hasWarningThresholds = false;
+    bool hasFatalThresholds = false;
     double criticalHigh = std::numeric_limits<double>::quiet_NaN();
     double criticalLow = std::numeric_limits<double>::quiet_NaN();
     double warningHigh = std::numeric_limits<double>::quiet_NaN();
     double warningLow = std::numeric_limits<double>::quiet_NaN();
+    double fatalHigh = std::numeric_limits<double>::quiet_NaN();
+    double fatalLow = std::numeric_limits<double>::quiet_NaN();
 
     if (pdr->supported_thresholds.bits.bit0)
     {
@@ -247,6 +250,17 @@
         criticalLow =
             getRangeFieldValue(pdr->range_field_format, pdr->critical_low);
     }
+    if (pdr->supported_thresholds.bits.bit2)
+    {
+        hasFatalThresholds = true;
+        fatalHigh =
+            getRangeFieldValue(pdr->range_field_format, pdr->fatal_high);
+    }
+    if (pdr->supported_thresholds.bits.bit5)
+    {
+        hasFatalThresholds = true;
+        fatalLow = getRangeFieldValue(pdr->range_field_format, pdr->fatal_low);
+    }
 
     resolution = pdr->resolution;
     offset = pdr->offset;
@@ -373,6 +387,25 @@
         thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
         thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
     }
+
+    if (hasFatalThresholds && !useMetricInterface)
+    {
+        try
+        {
+            thresholdHardShutdownIntf =
+                std::make_unique<ThresholdHardShutdownIntf>(bus, path.c_str());
+        }
+        catch (const sdbusplus::exception_t& e)
+        {
+            lg2::error(
+                "Failed to create HardShutdown threshold interface for numeric sensor {PATH} error - {ERROR}",
+                "PATH", path, "ERROR", e);
+            throw sdbusplus::xyz::openbmc_project::Common::Error::
+                InvalidArgument();
+        }
+        thresholdHardShutdownIntf->hardShutdownHigh(unitModifier(fatalHigh));
+        thresholdHardShutdownIntf->hardShutdownLow(unitModifier(fatalLow));
+    }
 }
 
 NumericSensor::NumericSensor(
@@ -434,10 +467,13 @@
     double minValue = std::numeric_limits<double>::quiet_NaN();
     bool hasWarningThresholds = false;
     bool hasCriticalThresholds = false;
+    bool hasFatalThresholds = false;
     double criticalHigh = std::numeric_limits<double>::quiet_NaN();
     double criticalLow = std::numeric_limits<double>::quiet_NaN();
     double warningHigh = std::numeric_limits<double>::quiet_NaN();
     double warningLow = std::numeric_limits<double>::quiet_NaN();
+    double fatalHigh = std::numeric_limits<double>::quiet_NaN();
+    double fatalLow = std::numeric_limits<double>::quiet_NaN();
 
     if (pdr->range_field_support.bits.bit0)
     {
@@ -461,6 +497,16 @@
         hasCriticalThresholds = true;
         criticalLow = pdr->critical_low;
     }
+    if (pdr->range_field_support.bits.bit4)
+    {
+        hasFatalThresholds = true;
+        fatalHigh = pdr->fatal_high;
+    }
+    if (pdr->range_field_support.bits.bit5)
+    {
+        hasFatalThresholds = true;
+        fatalLow = pdr->fatal_low;
+    }
 
     resolution = std::numeric_limits<double>::quiet_NaN();
     offset = std::numeric_limits<double>::quiet_NaN();
@@ -584,6 +630,25 @@
         thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
         thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
     }
+
+    if (hasFatalThresholds && !useMetricInterface)
+    {
+        try
+        {
+            thresholdHardShutdownIntf =
+                std::make_unique<ThresholdHardShutdownIntf>(bus, path.c_str());
+        }
+        catch (const sdbusplus::exception_t& e)
+        {
+            lg2::error(
+                "Failed to create HardShutdown threshold interface for numeric sensor {PATH} error - {ERROR}",
+                "PATH", path, "ERROR", e);
+            throw sdbusplus::xyz::openbmc_project::Common::Error::
+                InvalidArgument();
+        }
+        thresholdHardShutdownIntf->hardShutdownHigh(unitModifier(fatalHigh));
+        thresholdHardShutdownIntf->hardShutdownLow(unitModifier(fatalLow));
+    }
 }
 
 double NumericSensor::conversionFormula(double value)
@@ -819,6 +884,50 @@
             }
         }
     }
+
+    if (thresholdHardShutdownIntf &&
+        std::isfinite(thresholdHardShutdownIntf->hardShutdownHigh()))
+    {
+        auto threshold = thresholdHardShutdownIntf->hardShutdownHigh();
+        auto alarm = thresholdHardShutdownIntf->hardShutdownAlarmHigh();
+        auto newAlarm =
+            checkThreshold(alarm, true, value, threshold, hysteresis);
+        if (alarm != newAlarm)
+        {
+            thresholdHardShutdownIntf->hardShutdownAlarmHigh(newAlarm);
+            if (newAlarm)
+            {
+                thresholdHardShutdownIntf->hardShutdownHighAlarmAsserted(value);
+            }
+            else
+            {
+                thresholdHardShutdownIntf->hardShutdownHighAlarmDeasserted(
+                    value);
+            }
+        }
+    }
+
+    if (thresholdHardShutdownIntf &&
+        std::isfinite(thresholdHardShutdownIntf->hardShutdownLow()))
+    {
+        auto threshold = thresholdHardShutdownIntf->hardShutdownLow();
+        auto alarm = thresholdHardShutdownIntf->hardShutdownAlarmLow();
+        auto newAlarm =
+            checkThreshold(alarm, false, value, threshold, hysteresis);
+        if (alarm != newAlarm)
+        {
+            thresholdHardShutdownIntf->hardShutdownAlarmLow(newAlarm);
+            if (newAlarm)
+            {
+                thresholdHardShutdownIntf->hardShutdownLowAlarmAsserted(value);
+            }
+            else
+            {
+                thresholdHardShutdownIntf->hardShutdownLowAlarmDeasserted(
+                    value);
+            }
+        }
+    }
 }
 
 int NumericSensor::triggerThresholdEvent(
diff --git a/platform-mc/numeric_sensor.hpp b/platform-mc/numeric_sensor.hpp
index f085b07..37f4695 100644
--- a/platform-mc/numeric_sensor.hpp
+++ b/platform-mc/numeric_sensor.hpp
@@ -11,6 +11,7 @@
 #include <xyz/openbmc_project/Inventory/Source/PLDM/Entity/server.hpp>
 #include <xyz/openbmc_project/Metric/Value/server.hpp>
 #include <xyz/openbmc_project/Sensor/Threshold/Critical/server.hpp>
+#include <xyz/openbmc_project/Sensor/Threshold/HardShutdown/server.hpp>
 #include <xyz/openbmc_project/Sensor/Threshold/Warning/server.hpp>
 #include <xyz/openbmc_project/Sensor/Value/server.hpp>
 #include <xyz/openbmc_project/State/Decorator/Availability/server.hpp>
@@ -36,6 +37,8 @@
     sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Warning>;
 using ThresholdCriticalIntf = sdbusplus::server::object_t<
     sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Critical>;
+using ThresholdHardShutdownIntf = sdbusplus::server::object_t<
+    sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::HardShutdown>;
 using OperationalStatusIntf =
     sdbusplus::server::object_t<sdbusplus::xyz::openbmc_project::State::
                                     Decorator::server::OperationalStatus>;
@@ -177,6 +180,38 @@
         }
     };
 
+    /** @brief Get Upper HardShutdown threshold
+     *
+     *  @return double - Upper HardShutdown threshold
+     */
+    double getThresholdUpperHardShutdown()
+    {
+        if (thresholdHardShutdownIntf)
+        {
+            return thresholdHardShutdownIntf->hardShutdownHigh();
+        }
+        else
+        {
+            return std::numeric_limits<double>::quiet_NaN();
+        }
+    };
+
+    /** @brief Get Lower HardShutdown threshold
+     *
+     *  @return double - Lower HardShutdown threshold
+     */
+    double getThresholdLowerHardShutdownl()
+    {
+        if (thresholdHardShutdownIntf)
+        {
+            return thresholdHardShutdownIntf->hardShutdownLow();
+        }
+        else
+        {
+            return std::numeric_limits<double>::quiet_NaN();
+        }
+    };
+
     /** @brief Check if value is over threshold.
      *
      *  @param[in] eventType - event level in pldm::utils::Level
@@ -243,6 +278,8 @@
     std::unique_ptr<ValueIntf> valueIntf = nullptr;
     std::unique_ptr<ThresholdWarningIntf> thresholdWarningIntf = nullptr;
     std::unique_ptr<ThresholdCriticalIntf> thresholdCriticalIntf = nullptr;
+    std::unique_ptr<ThresholdHardShutdownIntf> thresholdHardShutdownIntf =
+        nullptr;
     std::unique_ptr<AvailabilityIntf> availabilityIntf = nullptr;
     std::unique_ptr<OperationalStatusIntf> operationalStatusIntf = nullptr;
     std::unique_ptr<AssociationDefinitionsInft> associationDefinitionsIntf =