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(