boot-progress: support LastState property

This commit provides initial support for the LastState property within
the Redfish BootProgress object.

The design details of OpenBMC's implementation of this can be found
here:
https://github.com/openbmc/docs/blob/master/designs/boot-progress.md

Tested:
- Set each possible value for the D-Bus BootProgress property and
  verified the Redfish API returned the expected value. This includes
  setting it to MotherboardInit and verifying "None" was returned
  because this does not have a mapping to the new Redfish enumeration.
- Verified Redfish Validator passed

Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
Change-Id: I8bc6e7012f4afc3152a0af2c5ebf8a55b1112773
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index 89a8ad5..2817d92 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -780,6 +780,107 @@
     }
     return 0;
 }
+/**
+ * @brief Retrieves boot progress of the system
+ *
+ * @param[in] aResp  Shared pointer for generating response message.
+ *
+ * @return None.
+ */
+inline void getBootProgress(const std::shared_ptr<AsyncResp>& aResp)
+{
+    crow::connections::systemBus->async_method_call(
+        [aResp](const boost::system::error_code ec,
+                const std::variant<std::string>& bootProgress) {
+            if (ec)
+            {
+                // BootProgress is an optional object so just do nothing if
+                // not found
+                return;
+            }
+
+            const std::string* bootProgressStr =
+                std::get_if<std::string>(&bootProgress);
+
+            if (!bootProgressStr)
+            {
+                // Interface implemented but property not found, return error
+                // for that
+                messages::internalError(aResp->res);
+                return;
+            }
+
+            BMCWEB_LOG_DEBUG << "Boot Progress: " << *bootProgressStr;
+
+            // Now convert the D-Bus BootProgress to the appropriate Redfish
+            // enum
+            std::string rfBpLastState = "None";
+            if (*bootProgressStr == "xyz.openbmc_project.State.Boot.Progress."
+                                    "ProgressStages.Unspecified")
+            {
+                rfBpLastState = "None";
+            }
+            else if (*bootProgressStr ==
+                     "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
+                     "PrimaryProcInit")
+            {
+                rfBpLastState = "PrimaryProcessorInitializationStarted";
+            }
+            else if (*bootProgressStr ==
+                     "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
+                     "BusInit")
+            {
+                rfBpLastState = "BusInitializationStarted";
+            }
+            else if (*bootProgressStr ==
+                     "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
+                     "MemoryInit")
+            {
+                rfBpLastState = "MemoryInitializationStarted";
+            }
+            else if (*bootProgressStr ==
+                     "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
+                     "SecondaryProcInit")
+            {
+                rfBpLastState = "SecondaryProcessorInitializationStarted";
+            }
+            else if (*bootProgressStr ==
+                     "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
+                     "PCIInit")
+            {
+                rfBpLastState = "PCIResourceConfigStarted";
+            }
+            else if (*bootProgressStr ==
+                     "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
+                     "SystemInitComplete")
+            {
+                rfBpLastState = "SystemHardwareInitializationComplete";
+            }
+            else if (*bootProgressStr ==
+                     "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
+                     "OSStart")
+            {
+                rfBpLastState = "OSBootStarted";
+            }
+            else if (*bootProgressStr ==
+                     "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
+                     "OSRunning")
+            {
+                rfBpLastState = "OSRunning";
+            }
+            else
+            {
+                BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress "
+                                 << *bootProgressStr;
+                // Just return the default
+            }
+
+            aResp->res.jsonValue["BootProgress"]["LastState"] = rfBpLastState;
+        },
+        "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
+        "org.freedesktop.DBus.Properties", "Get",
+        "xyz.openbmc_project.State.Boot.Progress", "BootProgress");
+}
 
 /**
  * @brief Retrieves boot mode over DBUS and fills out the response
@@ -2047,6 +2148,7 @@
         getComputerSystem(asyncResp, health);
         getHostState(asyncResp);
         getBootProperties(asyncResp);
+        getBootProgress(asyncResp);
         getPCIeDeviceList(asyncResp, "PCIeDevices");
         getHostWatchdogTimer(asyncResp);
         getPowerRestorePolicy(asyncResp);