Process system state changes

We are currently subscribed to the systemd to get
a signal notifying us when the obmc-standby.target
is ready.  Things may change in the future but this
is what we have decided to do for now.

Change-Id: I81ecdcb45123feb611cf88916c0f9caadcd82dfe
Signed-off-by: Josh D. King <jdking@us.ibm.com>
diff --git a/bmc_state_manager.cpp b/bmc_state_manager.cpp
index 12a04a4..a0308cd 100644
--- a/bmc_state_manager.cpp
+++ b/bmc_state_manager.cpp
@@ -15,6 +15,9 @@
 
 using namespace phosphor::logging;
 
+constexpr auto obmcStandbyTarget = "obmc-standby.target";
+constexpr auto signalDone = "done";
+
 /* Map a transition to it's systemd target */
 const std::map<server::BMC::Transition, const char*> SYSTEMD_TABLE =
 {
@@ -56,6 +59,43 @@
     return;
 }
 
+int BMC::bmcStateChangeSignal(sd_bus_message *msg, void *userData,
+                              sd_bus_error *retError)
+{
+    return static_cast<BMC*>(userData)->bmcStateChange(msg, retError);
+}
+
+int BMC::bmcStateChange(sd_bus_message *msg,
+                        sd_bus_error *retError)
+{
+    uint32_t newStateID {};
+    sdbusplus::message::object_path newStateObjPath;
+    std::string newStateUnit{};
+    std::string newStateResult{};
+
+    auto sdPlusMsg = sdbusplus::message::message(msg);
+    //Read the msg and populate each variable
+    sdPlusMsg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
+
+    //Caught the signal that indicates the BMC is now BMC_READY
+    if((newStateUnit == obmcStandbyTarget) &&
+       (newStateResult == signalDone))
+    {
+        log<level::INFO>("BMC_READY");
+        this->currentBMCState(BMCState::Ready);
+
+        //Unsubscribe so we stop processing all other signals
+        auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
+                                                SYSTEMD_OBJ_PATH,
+                                                SYSTEMD_INTERFACE,
+                                                "Unsubscribe");
+        this->bus.call(method);
+        this->stateSignal.release();
+    }
+
+    return 0;
+}
+
 BMC::Transition BMC::requestedBMCTransition(Transition value)
 {
     log<level::INFO>(
@@ -67,6 +107,16 @@
     return server::BMC::requestedBMCTransition(value);
 }
 
+BMC::BMCState BMC::currentBMCState(BMCState value)
+{
+    log<level::INFO>(
+            "Setting the BMCState field",
+            entry("CURRENT_BMC_STATE=0x%s",
+                  convertForMessage(value).c_str()));
+
+    return server::BMC::currentBMCState(value);
+}
+
 
 } // namespace manager
 } // namespace state
diff --git a/bmc_state_manager.hpp b/bmc_state_manager.hpp
index 1ddef53..bbace38 100644
--- a/bmc_state_manager.hpp
+++ b/bmc_state_manager.hpp
@@ -21,10 +21,6 @@
     public:
         /** @brief Constructs BMC State Manager
          *
-         *  @note This constructor passes 'true' to the base class in order to
-         *  defer dbus object registration until we can run
-         *  subscribeToSystemdSignals() and set our properties
-         *
          * @param[in] bus       - The Dbus bus object
          * @param[in] busName   - The Dbus name to own
          * @param[in] objPath   - The Dbus object path
@@ -34,7 +30,17 @@
                 sdbusplus::server::object::object<
                     sdbusplus::xyz::openbmc_project::State::server::BMC>(
                         bus, objPath),
-                        bus(bus)
+                            bus(bus),
+                            stateSignal(
+                                std::make_unique<
+                                decltype(stateSignal)::element_type>(
+                                bus,
+                                "type='signal',"
+                                "member='JobRemoved',"
+                                "path='/org/freedesktop/systemd1',"
+                                "interface='org.freedesktop.systemd1.Manager'",
+                                bmcStateChangeSignal,
+                                this))
         {
             subscribeToSystemdSignals();
         };
@@ -42,6 +48,8 @@
         /** @brief Set value of BMCTransition **/
         Transition requestedBMCTransition(Transition value) override;
 
+        /** @brief Set value of CurrentBMCState **/
+        BMCState currentBMCState(BMCState value) override;
 
     private:
         /**
@@ -55,9 +63,34 @@
          */
         void executeTransition(Transition tranReq);
 
+        /** @brief Callback used to direct you into the class
+         *
+         * @param[in]  msg       - Data associated with subscribed signal
+         * @param[in]  userData  - Pointer to this object instance
+         * @param[out] retError  - return error data if any
+         *
+         */
+        static int bmcStateChangeSignal(sd_bus_message* msg,
+                                        void* userData,
+                                        sd_bus_error* retError);
+
+        /** @brief Callback function on bmc state change
+         *
+         * Check if the state is relevant to the BMC and if so, update
+         * corresponding BMC object's state
+         *
+         * @param[in]  msg       - Data associated with subscribed signal
+         * @param[out] retError  - return error data if any
+         *
+         */
+        int bmcStateChange(sd_bus_message* msg,
+                           sd_bus_error* retError);
+
         /** @brief Persistent sdbusplus DBus bus connection. **/
         sdbusplus::bus::bus& bus;
 
+        /** @brief Used to subscribe to dbus system state changes **/
+        std::unique_ptr<sdbusplus::server::match::match> stateSignal;
 };
 
 } // namespace manager