Add redundancy sensor and cleanup

Add fan redundancy sensor and move some class members
into the base class. Asio now protects against setting
the same number twice, allow it now to simplify code.

Change-Id: Idb6b5ff4746da92be62c4756fe442d5a5ed23f4f
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/sensors/src/FanMain.cpp b/sensors/src/FanMain.cpp
index 542ca78..8401343 100644
--- a/sensors/src/FanMain.cpp
+++ b/sensors/src/FanMain.cpp
@@ -34,8 +34,13 @@
 namespace variant_ns = sdbusplus::message::variant_ns;
 static constexpr std::array<const char*, 1> sensorTypes = {
     "xyz.openbmc_project.Configuration.AspeedFan"};
+constexpr const char* redundancyConfiguration =
+    "xyz.openbmc_project.Configuration.FanRedundancy";
 static std::regex inputRegex(R"(fan(\d+)_input)");
 
+// todo: power supply fan redundancy
+std::unique_ptr<RedundancySensor> systemRedundancy = nullptr;
+
 void createSensors(
     boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
     boost::container::flat_map<std::string, std::unique_ptr<TachSensor>>&
@@ -241,7 +246,7 @@
 
         tachSensors[sensorName] = std::make_unique<TachSensor>(
             path.string(), objectServer, dbusConnection,
-            std::move(presenceSensor), io, sensorName,
+            std::move(presenceSensor), systemRedundancy, io, sensorName,
             std::move(sensorThresholds), *interfacePath);
     }
     std::vector<fs::path> pwms;
@@ -259,6 +264,56 @@
     }
 }
 
+void createRedundancySensor(
+    const boost::container::flat_map<std::string, std::unique_ptr<TachSensor>>&
+        sensors,
+    std::shared_ptr<sdbusplus::asio::connection> conn,
+    sdbusplus::asio::object_server& objectServer)
+{
+
+    conn->async_method_call(
+        [&objectServer, &sensors](boost::system::error_code& ec,
+                                  const ManagedObjectType managedObj) {
+            if (ec)
+            {
+                std::cerr << "Error calling entity manager \n";
+                return;
+            }
+            for (const auto& pathPair : managedObj)
+            {
+                for (const auto& interfacePair : pathPair.second)
+                {
+                    if (interfacePair.first == redundancyConfiguration)
+                    {
+                        // currently only support one
+                        auto findCount =
+                            interfacePair.second.find("AllowedFailures");
+                        if (findCount == interfacePair.second.end())
+                        {
+                            std::cerr << "Malformed redundancy record \n";
+                            return;
+                        }
+                        std::vector<std::string> sensorList;
+
+                        for (const auto& sensor : sensors)
+                        {
+                            sensorList.push_back(
+                                "/xyz/openbmc_project/sensors/fan_tach/" +
+                                sensor.second->name);
+                        }
+                        systemRedundancy = std::make_unique<RedundancySensor>(
+                            variant_ns::get<uint64_t>(findCount->second),
+                            sensorList, objectServer);
+
+                        return;
+                    }
+                }
+            }
+        },
+        "xyz.openbmc_project.EntityManager", "/",
+        "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+}
+
 int main(int argc, char** argv)
 {
     boost::asio::io_service io;
@@ -276,6 +331,7 @@
     io.post([&]() {
         createSensors(io, objectServer, tachSensors, pwmSensors, systemBus,
                       nullptr);
+        createRedundancySensor(tachSensors, systemBus, objectServer);
     });
 
     boost::asio::deadline_timer filterTimer(io);
@@ -316,5 +372,19 @@
         matches.emplace_back(std::move(match));
     }
 
+    // redundancy sensor
+    std::function<void(sdbusplus::message::message&)> redundancyHandler =
+        [&tachSensors, &systemBus,
+         &objectServer](sdbusplus::message::message& message) {
+            createRedundancySensor(tachSensors, systemBus, objectServer);
+        };
+    auto match = std::make_unique<sdbusplus::bus::match::match>(
+        static_cast<sdbusplus::bus::bus&>(*systemBus),
+        "type='signal',member='PropertiesChanged',path_namespace='" +
+            std::string(inventoryPath) + "',arg0namespace='" +
+            redundancyConfiguration + "'",
+        redundancyHandler);
+    matches.emplace_back(std::move(match));
+
     io.run();
 }