adcsensor: Add CPU presence checking

This adds a match to catch cpu presence coming from
cpusensor.

Tested: ipmitool sensor list no longer showed ADCs that
monitored  unavailable CPU

Change-Id: I39c067e5da3565c5b229cc19ed4ccf7767c1e85c
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/service_files/xyz.openbmc_project.adcsensor.service b/service_files/xyz.openbmc_project.adcsensor.service
index 666ff16..536b318 100644
--- a/service_files/xyz.openbmc_project.adcsensor.service
+++ b/service_files/xyz.openbmc_project.adcsensor.service
@@ -1,6 +1,7 @@
 [Unit]
 Description=Adc Sensor
 StopWhenUnneeded=false
+Before=xyz.openbmc_project.cpusensor.service
 
 [Service]
 Restart=always
diff --git a/src/ADCSensorMain.cpp b/src/ADCSensorMain.cpp
index 8cfba87..7cb31d0 100644
--- a/src/ADCSensorMain.cpp
+++ b/src/ADCSensorMain.cpp
@@ -17,6 +17,7 @@
 #include <ADCSensor.hpp>
 #include <Utils.hpp>
 #include <VariantVisitors.hpp>
+#include <boost/algorithm/string/case_conv.hpp>
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #include <boost/container/flat_set.hpp>
@@ -35,6 +36,8 @@
     "xyz.openbmc_project.Configuration.ADC"};
 static std::regex inputRegex(R"(in(\d+)_input)");
 
+static boost::container::flat_map<size_t, bool> cpuPresence;
+
 // filter out adc from any other voltage sensor
 bool isAdc(const fs::path& parentPath)
 {
@@ -212,6 +215,21 @@
             setReadState(powerState, readState);
         }
 
+        auto findCPU = baseConfiguration->second.find("CPURequired");
+        if (findCPU != baseConfiguration->second.end())
+        {
+            size_t index = std::visit(VariantToIntVisitor(), findCPU->second);
+            auto presenceFind = cpuPresence.find(index);
+            if (presenceFind == cpuPresence.end())
+            {
+                continue; // no such cpu
+            }
+            if (!presenceFind->second)
+            {
+                continue; // cpu not installed
+            }
+        }
+
         auto findBridgeGpio = baseConfiguration->second.find("BridgeGpio");
         std::optional<int> gpioNum;
 
@@ -221,8 +239,9 @@
                 std::visit(VariantToIntVisitor(), findBridgeGpio->second);
             gpioNum = static_cast<std::optional<int>>(gpioPin);
         }
-
-        sensors[sensorName] = std::make_unique<ADCSensor>(
+        auto& sensor = sensors[sensorName];
+        sensor = nullptr;
+        sensor = std::make_unique<ADCSensor>(
             path.string(), objectServer, dbusConnection, io, sensorName,
             std::move(sensorThresholds), scaleFactor, readState, *interfacePath,
             gpioNum);
@@ -272,6 +291,53 @@
             });
         };
 
+    std::function<void(sdbusplus::message::message&)> cpuPresenceHandler =
+        [&](sdbusplus::message::message& message) {
+            std::string path = message.get_path();
+            boost::to_lower(path);
+
+            if (path.rfind("cpu") == std::string::npos)
+            {
+                return; // not interested
+            }
+            size_t index = 0;
+            try
+            {
+                index = std::stoi(path.substr(path.size() - 1));
+            }
+            catch (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");
+            if (findPresence != values.end())
+            {
+                cpuPresence[index] = std::get<bool>(findPresence->second);
+            }
+
+            // this implicitly cancels the timer
+            filterTimer.expires_from_now(boost::posix_time::seconds(1));
+
+            filterTimer.async_wait([&](const boost::system::error_code& ec) {
+                if (ec == boost::asio::error::operation_aborted)
+                {
+                    /* we were canceled*/
+                    return;
+                }
+                else if (ec)
+                {
+                    std::cerr << "timer error\n";
+                    return;
+                }
+                createSensors(io, objectServer, sensors, systemBus, {});
+            });
+        };
+
     for (const char* type : sensorTypes)
     {
         auto match = std::make_unique<sdbusplus::bus::match::match>(
@@ -281,6 +347,12 @@
             eventHandler);
         matches.emplace_back(std::move(match));
     }
+    matches.emplace_back(std::make_unique<sdbusplus::bus::match::match>(
+        static_cast<sdbusplus::bus::bus&>(*systemBus),
+        "type='signal',member='PropertiesChanged',path_namespace='" +
+            std::string(cpuInventoryPath) +
+            "',arg0namespace='xyz.openbmc_project.Inventory.Item'",
+        cpuPresenceHandler));
 
     io.run();
 }