regulators: Add convertFromLinear for sensor monitoring

Add convertFromLinear function.
The function is for converting from linear_11 format to a normal
decimal number.

Signed-off-by: Bob King <Bob_King@wistron.com>
Change-Id: I6bdeaf8e9d9a26ae144c9db3494f758fd9eb48ee
diff --git a/phosphor-regulators/src/pmbus_utils.hpp b/phosphor-regulators/src/pmbus_utils.hpp
index 5e2e270..93d2dce 100644
--- a/phosphor-regulators/src/pmbus_utils.hpp
+++ b/phosphor-regulators/src/pmbus_utils.hpp
@@ -185,6 +185,45 @@
 std::string toString(VoutDataFormat format);
 
 /**
+ * Converts a linear data format value to a double value.
+ *
+ * This data format consists of the following:
+ *   - Two byte value
+ *   - 11-bit two's complement mantissa value stored in the two bytes
+ *   - 5-bit two's complement exponent value stored in the two bytes
+ *
+ * @param value linear data format value
+ * @return double value
+ */
+inline double convertFromLinear(uint16_t value)
+{
+    // extract exponent from most significant 5 bits
+    uint8_t exponentField = value >> 11;
+
+    // extract mantissa from least significant 11 bits
+    uint16_t mantissaField = value & 0x7FFu;
+
+    // sign extend exponent
+    if (exponentField > 0x0Fu)
+    {
+        exponentField |= 0xE0u;
+    }
+
+    // sign extend mantissa
+    if (mantissaField > 0x03FFu)
+    {
+        mantissaField |= 0xF800u;
+    }
+
+    int8_t exponent = static_cast<int8_t>(exponentField);
+    int16_t mantissa = static_cast<int16_t>(mantissaField);
+
+    // compute value as mantissa * 2^(exponent)
+    double decimal = mantissa * std::pow(2.0, exponent);
+    return decimal;
+}
+
+/**
  * Converts a volts value to the linear data format for output voltage.
  *
  * This data format consists of the following:
diff --git a/phosphor-regulators/test/pmbus_utils_tests.cpp b/phosphor-regulators/test/pmbus_utils_tests.cpp
index 4aab7db..96e10bd 100644
--- a/phosphor-regulators/test/pmbus_utils_tests.cpp
+++ b/phosphor-regulators/test/pmbus_utils_tests.cpp
@@ -203,6 +203,57 @@
     }
 }
 
+TEST(PMBusUtilsTests, ConvertFromLinear)
+{
+    uint16_t value;
+
+    // Minimum possible exponent value: -16
+    // mantissa : 511, exponent : -16, decimal = 511 * 2^-16 =
+    // 0.0077972412109375
+    value = 0x81ff;
+    EXPECT_DOUBLE_EQ(pmbus_utils::convertFromLinear(value), 0.0077972412109375);
+
+    // Maximum possible exponent value: 15
+    // mantissa : 2, exponent : 15, decimal = 2 * 2^15 = 65536
+    value = 0x7802;
+    EXPECT_DOUBLE_EQ(pmbus_utils::convertFromLinear(value), 65536);
+
+    // Minimum possible mantissa value: -1024
+    // mantissa : -1024, exponent : 1, decimal = -1024 * 2^1 = -2048
+    value = 0x0c00;
+    EXPECT_DOUBLE_EQ(pmbus_utils::convertFromLinear(value), -2048);
+
+    // Maximum possible mantissa value: 1023
+    // mantissa : 1023, exponent : -11, decimal = 1023 * 2^-11 = 0.49951171875
+    value = 0xabff;
+    EXPECT_DOUBLE_EQ(pmbus_utils::convertFromLinear(value), 0.49951171875);
+
+    // Exponent = 0, mantissa > 0
+    // mantissa : 1, exponent : 0, decimal = 1 * 2^0 = 1
+    value = 0x0001;
+    EXPECT_DOUBLE_EQ(pmbus_utils::convertFromLinear(value), 1);
+
+    // Exponent > 0, mantissa > 0
+    // mantissa : 2, exponent : 1, decimal = 2 * 2^1 = 4
+    value = 0x0802;
+    EXPECT_DOUBLE_EQ(pmbus_utils::convertFromLinear(value), 4);
+
+    // Exponent < 0, mantissa > 0
+    // mantissa : 15, exponent : -1, decimal = 15 * 2^-1 = 7.5
+    value = 0xf80f;
+    EXPECT_DOUBLE_EQ(pmbus_utils::convertFromLinear(value), 7.5);
+
+    // Exponent > 0, mantissa = 0
+    // mantissa : 0, exponent : 3, decimal = 0 * 2^3 = 0
+    value = 0x1800;
+    EXPECT_DOUBLE_EQ(pmbus_utils::convertFromLinear(value), 0);
+
+    // Exponent > 0, mantissa < 0
+    // mantissa : -2, exponent : 3, decimal = -2 * 2^3 = -16
+    value = 0x1ffe;
+    EXPECT_DOUBLE_EQ(pmbus_utils::convertFromLinear(value), -16);
+}
+
 TEST(PMBusUtilsTests, ConvertToVoutLinear)
 {
     double volts;