psusensor: Add CPU presence detection in psusensor

Add same CPU presence that's in ADCSensorMain into PSUSensorMain

Tested:
Sensors with non-present CPUs are not being added.
Sensors with present CPU or no CPURequired field still being added.

Change-Id: I772175a9eb3c0c6337f7fdc79c2de71e19a77349
Signed-off-by: Matt Simmering <matthew.simmering@intel.com>
diff --git a/src/PSUSensorMain.cpp b/src/PSUSensorMain.cpp
index 07802cd..be45dce 100644
--- a/src/PSUSensorMain.cpp
+++ b/src/PSUSensorMain.cpp
@@ -19,6 +19,7 @@
 #include "PSUSensor.hpp"
 #include "Utils.hpp"
 
+#include <boost/algorithm/string/case_conv.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #include <boost/container/flat_map.hpp>
 #include <boost/container/flat_set.hpp>
@@ -111,6 +112,7 @@
     limitEventMatch;
 
 static std::vector<PSUProperty> psuProperties;
+static boost::container::flat_map<size_t, bool> cpuPresence;
 
 // Function CheckEvent will check each attribute from eventMatch table in the
 // sysfs. If the attributes exists in sysfs, then store the complete path
@@ -441,6 +443,18 @@
             continue;
         }
 
+        auto findCPU = baseConfig->find("CPURequired");
+        if (findCPU != baseConfig->end())
+        {
+            size_t index =
+                std::visit(VariantToIntVisitor(), findCPU->second);
+            auto presenceFind = cpuPresence.find(index);
+            if (presenceFind == cpuPresence.end() || !presenceFind->second)
+            {
+                continue;
+            }
+        }
+
         // on rescans, only update sensors we were signaled by
         if (!firstScan)
         {
@@ -1076,8 +1090,71 @@
         });
     };
 
+    boost::asio::steady_timer cpuFilterTimer(io);
+    std::function<void(sdbusplus::message_t&)> cpuPresenceHandler =
+        [&](sdbusplus::message_t& message) {
+        std::string path = message.get_path();
+        boost::to_lower(path);
+
+        sdbusplus::message::object_path cpuPath(path);
+        std::string cpuName = cpuPath.filename();
+        if (!cpuName.starts_with("cpu"))
+        {
+            return;
+        }
+        size_t index = 0;
+        try
+        {
+            index = std::stoi(path.substr(path.size() - 1));
+        }
+        catch (const std::invalid_argument&)
+        {
+            std::cerr << "Found invalid path " << path << "\n";
+            return;
+        }
+
+        std::string objectName;
+        boost::container::flat_map<std::string, std::variant<bool>> values;
+        message.read(objectName, values);
+        auto findPresence = values.find("Present");
+        try
+        {
+            cpuPresence[index] = std::get<bool>(findPresence->second);
+        }
+        catch(const std::bad_variant_access& err)
+        {
+            return;
+        }
+
+        if(!cpuPresence[index])
+        {
+            return;
+        }
+        cpuFilterTimer.expires_after(std::chrono::seconds(1));
+        cpuFilterTimer.async_wait([&](const boost::system::error_code& ec) {
+            if (ec == boost::asio::error::operation_aborted)
+            {
+                return;
+            }
+            if (ec)
+            {
+                std::cerr << "timer error\n";
+                return;
+            }
+            createSensors(io, objectServer, systemBus, nullptr);
+        });
+    };
+
     std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
         setupPropertiesChangedMatches(*systemBus, sensorTypes, eventHandler);
+
+    matches.emplace_back(std::make_unique<sdbusplus::bus::match_t>(
+        static_cast<sdbusplus::bus_t&>(*systemBus),
+        "type='signal',member='PropertiesChanged',path_namespace='" +
+            std::string(cpuInventoryPath) +
+            "',arg0namespace='xyz.openbmc_project.Inventory.Item'",
+        cpuPresenceHandler));
+
     setupManufacturingModeMatch(*systemBus);
     io.run();
 }