PEL: Add 3 state fields to PEL UserData section

Add the following to the system info UserData section that gets added
for PELs created by BMC code:

* CurrentBMCState on /xyz/openbmc_project/state/bmc0
* CurrentHostState on /xyz/openbmc_project/state/host0
* CurrentPowerState on /xyz/openbmc_project/state/chassis0

The RequestedPowerTransition property is also read along with the
CurrentPowerState property since it's on the same interface and will
be used in a future commit.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Icdc225f2c9bb6d91e67a4cbe608df97803ccee6c
diff --git a/extensions/openpower-pels/data_interface.cpp b/extensions/openpower-pels/data_interface.cpp
index 8b63726..351805c 100644
--- a/extensions/openpower-pels/data_interface.cpp
+++ b/extensions/openpower-pels/data_interface.cpp
@@ -34,6 +34,8 @@
 {
 constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
 constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
+constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
+constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
 constexpr auto hostState = "/xyz/openbmc_project/state/host0";
 constexpr auto pldm = "/xyz/openbmc_project/pldm";
 constexpr auto enableHostPELs =
@@ -48,6 +50,9 @@
 constexpr auto osStatus = "xyz.openbmc_project.State.OperatingSystem.Status";
 constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
 constexpr auto enable = "xyz.openbmc_project.Object.Enable";
+constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
+constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
+constexpr auto hostState = "xyz.openbmc_project.State.Host";
 } // namespace interface
 
 using namespace sdbusplus::xyz::openbmc_project::State::OperatingSystem::server;
@@ -85,11 +90,11 @@
             if ((status == Status::OSStatus::BootComplete) ||
                 (status == Status::OSStatus::Standby))
             {
-                setHostState(true);
+                setHostUp(true);
             }
             else
             {
-                setHostState(false);
+                setHostUp(false);
             }
         }));
 
@@ -99,6 +104,37 @@
         [this](const auto& value) {
             this->_sendPELsToHost = std::get<bool>(value);
         }));
+
+    // Watch the BMCState property
+    _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
+        bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
+        *this, [this](const auto& value) {
+            this->_bmcState = std::get<std::string>(value);
+        }));
+
+    // Watch the chassis current and requested power state properties
+    _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
+        bus, object_path::chassisState, interface::chassisState, *this,
+        [this](const auto& properties) {
+            auto state = properties.find("CurrentPowerState");
+            if (state != properties.end())
+            {
+                this->_chassisState = std::get<std::string>(state->second);
+            }
+
+            auto trans = properties.find("RequestedPowerTransition");
+            if (trans != properties.end())
+            {
+                this->_chassisTransition = std::get<std::string>(trans->second);
+            }
+        }));
+
+    // Watch the CurrentHostState property
+    _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
+        bus, object_path::hostState, interface::hostState, "CurrentHostState",
+        *this, [this](const auto& value) {
+            this->_hostState = std::get<std::string>(value);
+        }));
 }
 
 DBusPropertyMap
diff --git a/extensions/openpower-pels/data_interface.hpp b/extensions/openpower-pels/data_interface.hpp
index b3ed60d..19da482 100644
--- a/extensions/openpower-pels/data_interface.hpp
+++ b/extensions/openpower-pels/data_interface.hpp
@@ -173,16 +173,57 @@
         return _sendPELsToHost;
     }
 
+    /**
+     * @brief Returns the BMC state
+     *
+     * @return std::string - The BMC state property value
+     */
+    virtual std::string getBMCState() const
+    {
+        return _bmcState;
+    }
+
+    /**
+     * @brief Returns the Chassis state
+     *
+     * @return std::string - The chassis state property value
+     */
+    virtual std::string getChassisState() const
+    {
+        return _chassisState;
+    }
+
+    /**
+     * @brief Returns the chassis requested power
+     *        transition value.
+     *
+     * @return std::string - The chassis transition property
+     */
+    virtual std::string getChassisTransition() const
+    {
+        return _chassisTransition;
+    }
+
+    /**
+     * @brief Returns the Host state
+     *
+     * @return std::string - The Host state property value
+     */
+    virtual std::string getHostState() const
+    {
+        return _hostState;
+    }
+
   protected:
     /**
      * @brief Sets the host on/off state and runs any
      *        callback functions (if there was a change).
      */
-    void setHostState(bool newState)
+    void setHostUp(bool hostUp)
     {
-        if (_hostUp != newState)
+        if (_hostUp != hostUp)
         {
-            _hostUp = newState;
+            _hostUp = hostUp;
 
             for (auto& [name, func] : _hostChangeCallbacks)
             {
@@ -248,6 +289,26 @@
      * This is usually set to false in manufacturing test.
      */
     bool _sendPELsToHost = true;
+
+    /**
+     * @brief The BMC state property
+     */
+    std::string _bmcState;
+
+    /**
+     * @brief The Chassis current power state property
+     */
+    std::string _chassisState;
+
+    /**
+     * @brief The Chassis requested power transition property
+     */
+    std::string _chassisTransition;
+
+    /**
+     * @brief The host state property
+     */
+    std::string _hostState;
 };
 
 /**
diff --git a/extensions/openpower-pels/pel.cpp b/extensions/openpower-pels/pel.cpp
index e560d5e..60821b6 100644
--- a/extensions/openpower-pels/pel.cpp
+++ b/extensions/openpower-pels/pel.cpp
@@ -377,6 +377,24 @@
     json["BMC Version ID"] = std::move(id);
 }
 
+std::string lastSegment(char separator, std::string data)
+{
+    auto pos = data.find_last_of(separator);
+    if (pos != std::string::npos)
+    {
+        data = data.substr(pos + 1);
+    }
+
+    return data;
+}
+
+void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
+{
+    json["BMCState"] = lastSegment('.', dataIface.getBMCState());
+    json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
+    json["HostState"] = lastSegment('.', dataIface.getHostState());
+}
+
 std::unique_ptr<UserData>
     makeSysInfoUserDataSection(const AdditionalData& ad,
                                const DataInterfaceBase& dataIface)
@@ -385,6 +403,7 @@
 
     addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
     addBMCFWVersionIDToJSON(json, dataIface);
+    addStatesToJSON(json, dataIface);
 
     return makeJSONUserDataSection(json);
 }