Handle power state changes

We need to check if power is on as the hsbp goes away
during power off. This copies the power logic from
dbus-sensors and uses it to avoid scanning when power
is off.

Tested: Warnings go away

Change-Id: Ie949e7a98eb70592318710f3eecdfe766f71f110
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/hsbp-manager/include/utils.hpp b/hsbp-manager/include/utils.hpp
index 986c3b2..0b47a54 100644
--- a/hsbp-manager/include/utils.hpp
+++ b/hsbp-manager/include/utils.hpp
@@ -14,7 +14,13 @@
 // limitations under the License.
 */
 
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/asio/io_context.hpp>
+#include <boost/asio/steady_timer.hpp>
+#include <boost/container/flat_map.hpp>
 #include <cstdint>
+#include <iostream>
+#include <sdbusplus/asio/connection.hpp>
 #include <string>
 #include <variant>
 #include <vector>
@@ -51,6 +57,20 @@
 constexpr const char* asserted = "Asserted";
 } // namespace ledGroup
 
+namespace properties
+{
+constexpr const char* interface = "org.freedesktop.DBus.Properties";
+constexpr const char* get = "Get";
+} // namespace properties
+
+namespace power
+{
+const static constexpr char* busname = "xyz.openbmc_project.State.Host";
+const static constexpr char* interface = "xyz.openbmc_project.State.Host";
+const static constexpr char* path = "/xyz/openbmc_project/state/host0";
+const static constexpr char* property = "CurrentHostState";
+} // namespace power
+
 namespace hsbp
 {
 enum class registers : uint8_t
@@ -82,3 +102,79 @@
 };
 
 } // namespace hsbp
+
+static std::unique_ptr<sdbusplus::bus::match::match> powerMatch = nullptr;
+static bool powerStatusOn = false;
+
+bool isPowerOn(void)
+{
+    if (!powerMatch)
+    {
+        throw std::runtime_error("Power Match Not Created");
+    }
+    return powerStatusOn;
+}
+
+void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn)
+{
+    static boost::asio::steady_timer timer(conn->get_io_context());
+    // create a match for powergood changes, first time do a method call to
+    // cache the correct value
+    if (powerMatch)
+    {
+        return;
+    }
+
+    powerMatch = std::make_unique<sdbusplus::bus::match::match>(
+        static_cast<sdbusplus::bus::bus&>(*conn),
+        "type='signal',interface='" + std::string(properties::interface) +
+            "',path='" + std::string(power::path) + "',arg0='" +
+            std::string(power::interface) + "'",
+        [](sdbusplus::message::message& message) {
+            std::string objectName;
+            boost::container::flat_map<std::string, std::variant<std::string>>
+                values;
+            message.read(objectName, values);
+            auto findState = values.find(power::property);
+            if (findState != values.end())
+            {
+                bool on = boost::ends_with(
+                    std::get<std::string>(findState->second), "Running");
+                if (!on)
+                {
+                    timer.cancel();
+                    powerStatusOn = false;
+                    return;
+                }
+                // on comes too quickly
+                timer.expires_after(std::chrono::seconds(10));
+                timer.async_wait([](boost::system::error_code ec) {
+                    if (ec == boost::asio::error::operation_aborted)
+                    {
+                        return;
+                    }
+                    else if (ec)
+                    {
+                        std::cerr << "Timer error " << ec.message() << "\n";
+                        return;
+                    }
+                    powerStatusOn = true;
+                });
+            }
+        });
+
+    conn->async_method_call(
+        [](boost::system::error_code ec,
+           const std::variant<std::string>& state) {
+            if (ec)
+            {
+                // we commonly come up before power control, we'll capture the
+                // property change later
+                return;
+            }
+            powerStatusOn =
+                boost::ends_with(std::get<std::string>(state), "Running");
+        },
+        power::busname, power::path, properties::interface, properties::get,
+        power::interface, power::property);
+}