sensordatahandler: clamp the values instead of removing the sensor

Clamping the sensor values to prevent sensors from going missing.

Based on
https://github.com/openbmc/phosphor-host-ipmid/blob/5aae092cab08279d45c7914c466314b356164b7c/dbus-sdr/sensorutils.cpp#L258-L304

Clamping the threshold value to correct the result of negative threshold
value.

Tested:
Set 'sensorUnits1: 0x80' in config for sensor cpu0_abcd_cur which has
low threshold -1 and high threshold 7.6.
Before:
~# ipmitool sensor | grep cpu0_abcd_cur
cpu0_abcd_cur | 0.022      | Amps       | ok    | na        | 4.020     | 4.020     | 7.587     | 7.587     | na
After:
~# ipmitool sensor | grep cpu0_abcd_cur
cpu0_abcd_cur | -0.135     | Amps       | ok    | na        | -0.998    | -0.998    | 7.587     | 7.587     | na

Change-Id: Ie5af79ccbe8ab9660755f1c9d281e49a08d01309
Signed-off-by: Willy Tu <wltu@google.com>
Signed-off-by: JeffLin <JeffLin2@quantatw.com>
Signed-off-by: Willy Tu <wltu@google.com>
diff --git a/sensorhandler.cpp b/sensorhandler.cpp
index 30cee8b..e04319c 100644
--- a/sensorhandler.cpp
+++ b/sensorhandler.cpp
@@ -690,6 +690,21 @@
     ipmi::PropertyMap warnThresholds;
     ec = ipmi::getAllDbusProperties(ctx, service, info.sensorPath,
                                     warningThreshIntf, warnThresholds);
+    int32_t minClamp;
+    int32_t maxClamp;
+    int32_t rawData;
+    constexpr uint8_t sensorUnitsSignedBits = 2 << 6;
+    constexpr uint8_t signedDataFormat = 0x80;
+    if ((info.sensorUnits1 & sensorUnitsSignedBits) == signedDataFormat)
+    {
+        minClamp = std::numeric_limits<int8_t>::lowest();
+        maxClamp = std::numeric_limits<int8_t>::max();
+    }
+    else
+    {
+        minClamp = std::numeric_limits<uint8_t>::lowest();
+        maxClamp = std::numeric_limits<uint8_t>::max();
+    }
     if (!ec)
     {
         double warnLow = ipmi::mappedVariant<double>(
@@ -702,8 +717,9 @@
         if (std::isfinite(warnLow))
         {
             warnLow *= std::pow(10, info.scale - info.exponentR);
-            resp.lowerNonCritical = static_cast<uint8_t>(
-                round((warnLow - info.scaledOffset) / info.coefficientM));
+            rawData = round((warnLow - info.scaledOffset) / info.coefficientM);
+            resp.lowerNonCritical =
+                static_cast<uint8_t>(std::clamp(rawData, minClamp, maxClamp));
             resp.validMask |= static_cast<uint8_t>(
                 ipmi::sensor::ThresholdMask::NON_CRITICAL_LOW_MASK);
         }
@@ -711,8 +727,9 @@
         if (std::isfinite(warnHigh))
         {
             warnHigh *= std::pow(10, info.scale - info.exponentR);
-            resp.upperNonCritical = static_cast<uint8_t>(
-                round((warnHigh - info.scaledOffset) / info.coefficientM));
+            rawData = round((warnHigh - info.scaledOffset) / info.coefficientM);
+            resp.upperNonCritical =
+                static_cast<uint8_t>(std::clamp(rawData, minClamp, maxClamp));
             resp.validMask |= static_cast<uint8_t>(
                 ipmi::sensor::ThresholdMask::NON_CRITICAL_HIGH_MASK);
         }
@@ -733,8 +750,9 @@
         if (std::isfinite(critLow))
         {
             critLow *= std::pow(10, info.scale - info.exponentR);
-            resp.lowerCritical = static_cast<uint8_t>(
-                round((critLow - info.scaledOffset) / info.coefficientM));
+            rawData = round((critLow - info.scaledOffset) / info.coefficientM);
+            resp.lowerCritical =
+                static_cast<uint8_t>(std::clamp(rawData, minClamp, maxClamp));
             resp.validMask |= static_cast<uint8_t>(
                 ipmi::sensor::ThresholdMask::CRITICAL_LOW_MASK);
         }
@@ -742,8 +760,9 @@
         if (std::isfinite(critHigh))
         {
             critHigh *= std::pow(10, info.scale - info.exponentR);
-            resp.upperCritical = static_cast<uint8_t>(
-                round((critHigh - info.scaledOffset) / info.coefficientM));
+            rawData = round((critHigh - info.scaledOffset) / info.coefficientM);
+            resp.upperCritical =
+                static_cast<uint8_t>(std::clamp(rawData, minClamp, maxClamp));
             resp.validMask |= static_cast<uint8_t>(
                 ipmi::sensor::ThresholdMask::CRITICAL_HIGH_MASK);
         }