platform-mc: Create Numeric sensor D-Bus object

Added numeric_sensor class. The NumericSensor class will create the
Numeric sensor D-Bus object. The class also handles sensor status and
exports its status to D-Bus interfaces.

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: Thu Nguyen <thu@os.amperecomputing.com>
Change-Id: I1c7de2e74100ed787ed2119896d3c5b36098dd96
diff --git a/platform-mc/terminus.cpp b/platform-mc/terminus.cpp
index 2892dc1..5b2ab3c 100644
--- a/platform-mc/terminus.cpp
+++ b/platform-mc/terminus.cpp
@@ -82,6 +82,30 @@
     return std::nullopt;
 }
 
+bool Terminus::createInventoryPath(std::string tName)
+{
+    if (tName.empty())
+    {
+        return false;
+    }
+
+    inventoryPath = "/xyz/openbmc_project/inventory/system/board/" + tName;
+    try
+    {
+        inventoryItemBoardInft = std::make_unique<InventoryItemBoardIntf>(
+            utils::DBusHandler::getBus(), inventoryPath.c_str());
+        return true;
+    }
+    catch (const sdbusplus::exception_t& e)
+    {
+        lg2::error(
+            "Failed to create Inventory Board interface for device {PATH}",
+            "PATH", inventoryPath);
+    }
+
+    return false;
+}
+
 void Terminus::parseTerminusPDRs()
 {
     std::vector<std::shared_ptr<pldm_numeric_sensor_value_pdr>>
@@ -177,6 +201,30 @@
                   "NAME", tName.value());
         terminusName = static_cast<std::string>(tName.value());
     }
+
+    if (terminusName.empty() &&
+        (numericSensorPdrs.size() || compactNumericSensorPdrs.size()))
+    {
+        lg2::error(
+            "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
+            "TID", tid);
+        return;
+    }
+
+    if (createInventoryPath(terminusName))
+    {
+        lg2::error("Terminus ID {TID}: Created Inventory path.", "TID", tid);
+    }
+
+    for (auto pdr : numericSensorPdrs)
+    {
+        addNumericSensor(pdr);
+    }
+
+    for (auto pdr : compactNumericSensorPdrs)
+    {
+        addCompactNumericSensor(pdr);
+    }
 }
 
 std::shared_ptr<SensorAuxiliaryNames>
@@ -329,6 +377,55 @@
     return parsedPdr;
 }
 
+void Terminus::addNumericSensor(
+    const std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr)
+{
+    uint16_t sensorId = pdr->sensor_id;
+    if (terminusName.empty())
+    {
+        lg2::error(
+            "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
+            "TID", tid);
+        return;
+    }
+    std::string sensorName = terminusName + "_" + "Sensor_" +
+                             std::to_string(pdr->sensor_id);
+
+    if (pdr->sensor_auxiliary_names_pdr)
+    {
+        auto sensorAuxiliaryNames = getSensorAuxiliaryNames(sensorId);
+        if (sensorAuxiliaryNames)
+        {
+            const auto& [sensorId, sensorCnt,
+                         sensorNames] = *sensorAuxiliaryNames;
+            if (sensorCnt == 1)
+            {
+                for (const auto& [languageTag, name] : sensorNames[0])
+                {
+                    if (languageTag == "en" && !name.empty())
+                    {
+                        sensorName = terminusName + "_" + name;
+                    }
+                }
+            }
+        }
+    }
+
+    try
+    {
+        auto sensor = std::make_shared<NumericSensor>(
+            tid, true, pdr, sensorName, inventoryPath);
+        lg2::info("Created NumericSensor {NAME}", "NAME", sensorName);
+        numericSensors.emplace_back(sensor);
+    }
+    catch (const sdbusplus::exception_t& e)
+    {
+        lg2::error(
+            "Failed to create NumericSensor. error - {ERROR} sensorname - {NAME}",
+            "ERROR", e, "NAME", sensorName);
+    }
+}
+
 std::shared_ptr<SensorAuxiliaryNames>
     Terminus::parseCompactNumericSensorNames(const std::vector<uint8_t>& sPdr)
 {
@@ -393,5 +490,50 @@
     return parsedPdr;
 }
 
+void Terminus::addCompactNumericSensor(
+    const std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr)
+{
+    uint16_t sensorId = pdr->sensor_id;
+    if (terminusName.empty())
+    {
+        lg2::error(
+            "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
+            "TID", tid);
+        return;
+    }
+    std::string sensorName = terminusName + "_" + "Sensor_" +
+                             std::to_string(pdr->sensor_id);
+
+    auto sensorAuxiliaryNames = getSensorAuxiliaryNames(sensorId);
+    if (sensorAuxiliaryNames)
+    {
+        const auto& [sensorId, sensorCnt, sensorNames] = *sensorAuxiliaryNames;
+        if (sensorCnt == 1)
+        {
+            for (const auto& [languageTag, name] : sensorNames[0])
+            {
+                if (languageTag == "en" && !name.empty())
+                {
+                    sensorName = terminusName + "_" + name;
+                }
+            }
+        }
+    }
+
+    try
+    {
+        auto sensor = std::make_shared<NumericSensor>(
+            tid, true, pdr, sensorName, inventoryPath);
+        lg2::info("Created Compact NumericSensor {NAME}", "NAME", sensorName);
+        numericSensors.emplace_back(sensor);
+    }
+    catch (const sdbusplus::exception_t& e)
+    {
+        lg2::error(
+            "Failed to create Compact NumericSensor. error - {ERROR} sensorname - {NAME}",
+            "ERROR", e, "NAME", sensorName);
+    }
+}
+
 } // namespace platform_mc
 } // namespace pldm