Implement basic queue for sending multiple commands

Sends dbus signal upon completion of command

Change-Id: Ic507f35af0b38305eecd5558c55738f2d283aac5
Signed-off-by: Andrew Geissler <andrewg@us.ibm.com>
diff --git a/systemintfcmds.cpp b/systemintfcmds.cpp
index 62d9524..999e710 100644
--- a/systemintfcmds.cpp
+++ b/systemintfcmds.cpp
@@ -1,26 +1,21 @@
 #include "systemintfcmds.h"
 #include "host-ipmid/ipmid-api.h"
 #include "config.h"
+#include "host-interface.hpp"
 
 #include <stdio.h>
 #include <mapper.h>
 
 void register_netfn_app_functions() __attribute__((constructor));
 
-//-------------------------------------------------------------------
-// Called by Host post response from Get_Message_Flags
-//-------------------------------------------------------------------
-ipmi_ret_t ipmi_app_read_event(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
-                             ipmi_request_t request, ipmi_response_t response,
-                             ipmi_data_len_t data_len, ipmi_context_t context)
+using namespace sdbusplus::xyz::openbmc_project::Control::server;
+
+// Internal function to get next host command
+Host::Command getNextHostCmd();
+
+// Notify SofPowerOff application that host is responding to command
+void notifySoftOff()
 {
-    ipmi_ret_t rc = IPMI_CC_OK;
-
-    printf("IPMI APP READ EVENT command received\n");
-
-    // TODO : For now, this is catering only to the Soft Power Off via OEM SEL
-    //        mechanism. If we need to make this generically used for some
-    //        other conditions, then we can take advantage of context pointer.
 
     constexpr auto iface          = "org.freedesktop.DBus.Properties";
     constexpr auto soft_off_iface = "xyz.openbmc_project.Ipmi.Internal."
@@ -31,9 +26,6 @@
                                     "SoftPowerOff.HostResponse.SoftOffReceived";
     char *busname = nullptr;
 
-    struct oem_sel_timestamped soft_off = {0};
-    *data_len = sizeof(struct oem_sel_timestamped);
-
     // Get the system bus where most system services are provided.
     auto bus = ipmid_get_sd_bus_connection();
 
@@ -56,31 +48,58 @@
     }
     else
     {
-            printf("Soft Power Off object is not available. Ignoring watchdog refresh");
+        printf("Soft Power Off object is not available. Ignoring watchdog \
+                refresh");
     }
+}
+
+//-------------------------------------------------------------------
+// Called by Host post response from Get_Message_Flags
+//-------------------------------------------------------------------
+ipmi_ret_t ipmi_app_read_event(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+        ipmi_request_t request, ipmi_response_t response,
+        ipmi_data_len_t data_len, ipmi_context_t context)
+{
+    ipmi_ret_t rc = IPMI_CC_OK;
+
+    printf("IPMI APP READ EVENT command received\n");
+
+    struct oem_sel_timestamped oem_sel = {0};
+    *data_len = sizeof(struct oem_sel_timestamped);
 
     // either id[0] -or- id[1] can be filled in. We will use id[0]
-    soft_off.id[0]   = SEL_OEM_ID_0;
-    soft_off.id[1]   = SEL_OEM_ID_0;
-    soft_off.type    = SEL_RECORD_TYPE_OEM;
+    oem_sel.id[0]   = SEL_OEM_ID_0;
+    oem_sel.id[1]   = SEL_OEM_ID_0;
+    oem_sel.type    = SEL_RECORD_TYPE_OEM;
 
     // Following 3 bytes are from IANA Manufactre_Id field. See below
-    soft_off.manuf_id[0]= 0x41;
-    soft_off.manuf_id[1]= 0xA7;
-    soft_off.manuf_id[2]= 0x00;
+    oem_sel.manuf_id[0]= 0x41;
+    oem_sel.manuf_id[1]= 0xA7;
+    oem_sel.manuf_id[2]= 0x00;
 
     // per IPMI spec NetFuntion for OEM
-    soft_off.netfun  = 0x3A;
+    oem_sel.netfun  = 0x3A;
 
-    // Mechanism to kick start soft shutdown.
-    soft_off.cmd     = CMD_POWER;
-    soft_off.data[0] = SOFT_OFF;
+    // Read from the queue to see what our response is here
+    Host::Command hCmd = getNextHostCmd();
+    switch (hCmd)
+    {
+    case Host::Command::SoftOff:
+        notifySoftOff();
+        oem_sel.cmd     = CMD_POWER;
+        oem_sel.data[0] = SOFT_OFF;
+        break;
+    case Host::Command::Heartbeat:
+        oem_sel.cmd     = CMD_HEARTBEAT;
+        oem_sel.data[0] = 0x00;
+        break;
+    }
 
     // All '0xFF' since unused.
-    memset(&soft_off.data[1], 0xFF, 3);
+    memset(&oem_sel.data[1], 0xFF, 3);
 
     // Pack the actual response
-    memcpy(response, &soft_off, *data_len);
+    memcpy(response, &oem_sel, *data_len);
     return rc;
 }
 
@@ -125,6 +144,13 @@
     return rc;
 }
 
+// Globals to keep the object alive during process life
+std::unique_ptr<sdbusplus::bus::bus> sdbus = nullptr;
+// TODO openbmc/openbmc#1581 - unique_ptr causes seg fault
+phosphor::host::Host* host = nullptr;
+
+
+#include <unistd.h>
 void register_netfn_app_functions()
 {
 
@@ -144,5 +170,27 @@
     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_MSG_FLAGS, NULL, ipmi_app_get_msg_flags,
                            SYSTEM_INTERFACE);
 
+    // Gets a hook onto SYSTEM bus used by host-ipmid
+    sd_bus *bus = ipmid_get_sd_bus_connection();
+
+    sdbus = std::make_unique<sdbusplus::bus::bus>(bus);
+
+    // Create new xyz.openbmc_project.host object on the bus
+    auto objPathInst = std::string{CONTROL_HOST_OBJPATH} + '0';
+
+    // Add sdbusplus ObjectManager.
+    sdbusplus::server::manager::manager objManager(*sdbus,
+                                                   objPathInst.c_str());
+
+    host = new phosphor::host::Host(*sdbus,
+                                    objPathInst.c_str());
+
+    sdbus->request_name(CONTROL_HOST_BUSNAME);
+
     return;
 }
+
+Host::Command getNextHostCmd()
+{
+    return(host->getNextCommand());
+}