psusensor: Add extra CPU presence logic

In the case of the psusensor service restarting we still need to check
for CPU presence.  This adds a handler that will get the number of CPUs
that the BMC has in inventory.

Tested:
CPU presence map gets populated correctly.

Change-Id: I17caba6cb602d34852270035fbbf71f3095b96be
Signed-off-by: Matt Simmering <matthew.simmering@intel.com>
diff --git a/src/PSUSensorMain.cpp b/src/PSUSensorMain.cpp
index 663567d..aceb094 100644
--- a/src/PSUSensorMain.cpp
+++ b/src/PSUSensorMain.cpp
@@ -993,6 +993,73 @@
     }
 }
 
+static void
+    getPresentCpus(std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
+{
+    static const int depth = 2;
+    static const int numKeys = 1;
+    GetSubTreeType cpuSubTree;
+
+    try
+    {
+        auto getItems = dbusConnection->new_method_call(
+            mapper::busName, mapper::path, mapper::interface, mapper::subtree);
+        getItems.append(cpuInventoryPath, static_cast<int32_t>(depth),
+                        std::array<const char*, numKeys>{
+                            "xyz.openbmc_project.Inventory.Item"});
+        auto getItemsResp = dbusConnection->call(getItems);
+        getItemsResp.read(cpuSubTree);
+    }
+    catch (sdbusplus::exception_t& e)
+    {
+        std::cerr << "error getting inventory item subtree: " << e.what()
+                  << "\n";
+        return;
+    }
+
+    for (const auto& [path, objDict] : cpuSubTree)
+    {
+        auto obj = sdbusplus::message::object_path(path).filename();
+        if (!obj.starts_with("cpu") || objDict.empty())
+        {
+            continue;
+        }
+        const std::string& owner = objDict.begin()->first;
+
+        std::variant<bool> respValue;
+        try
+        {
+            auto getPresence = dbusConnection->new_method_call(
+                owner.c_str(), path.c_str(), "org.freedesktop.DBus.Properties",
+                "Get");
+            getPresence.append("xyz.openbmc_project.Inventory.Item", "Present");
+            auto resp = dbusConnection->call(getPresence);
+            resp.read(respValue);
+        }
+        catch (sdbusplus::exception_t& e)
+        {
+            std::cerr << "Error in getting CPU presence: " << e.what() << "\n";
+            continue;
+        }
+
+        auto* present = std::get_if<bool>(&respValue);
+        if (present != nullptr && *present)
+        {
+            int cpuIndex = 0;
+            try
+            {
+                cpuIndex = std::stoi(obj.substr(obj.find_last_of("cpu") + 1));
+            }
+            catch (const std::exception& e)
+            {
+                std::cerr << "Error converting CPU index, " << e.what() << '\n';
+                continue;
+            }
+            cpuPresence[cpuIndex + 1] = *present;
+        }
+    }
+}
+
 void createSensors(
     boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
     std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
@@ -1278,6 +1345,8 @@
             "',arg0namespace='xyz.openbmc_project.Inventory.Item'",
         cpuPresenceHandler));
 
+    getPresentCpus(systemBus);
+
     setupManufacturingModeMatch(*systemBus);
     io.run();
 }