PEL: Support eventId property

Support eventId property to add SRC and the hex words to the property

Tested by creating the PEL log and to make sure that the eventId
property was updated properly with 9 words and then its present in the
right format when the logging daemon is restarted

Test result:
root@rainier# busctl get-property xyz.openbmc_project.Logging
/xyz/openbmc_project/logging/entry/1 xyz.openbmc_project.Logging.Entry EventId
s "BD8D1001 00000055 2E2D0010 00000000 00000000 00000000 00000000
   00000000 00000000"

Also tested with old version of error log and new version with the
eventId property to make sure we don't have issues in serialization

Change-Id: I8e39804cd3d47f0e321c1cf533b97bf165c07518
Signed-off-by: Vijay Lobo <vijaylobo@gmail.com>
diff --git a/config.h.meson b/config.h.meson
index 7fd16a7..e1cda46 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -33,6 +33,7 @@
 
 static constexpr auto FIRST_CEREAL_CLASS_VERSION_WITH_FWLEVEL = "2";
 static constexpr auto FIRST_CEREAL_CLASS_VERSION_WITH_UPDATE_TS = "3";
-static constexpr size_t CLASS_VERSION = 3;
+static constexpr auto FIRST_CEREAL_CLASS_VERSION_WITH_EVENTID= "4";
+static constexpr size_t CLASS_VERSION = 4;
 
 // vim: ft=cpp
diff --git a/elog_entry.cpp b/elog_entry.cpp
index 8a19d86..f0b3e45 100644
--- a/elog_entry.cpp
+++ b/elog_entry.cpp
@@ -41,6 +41,21 @@
     return current;
 }
 
+std::string Entry::eventId(std::string value)
+{
+    auto current =
+        sdbusplus::xyz::openbmc_project::Logging::server::Entry::eventId();
+    if (value != current)
+    {
+        current =
+            sdbusplus::xyz::openbmc_project::Logging::server::Entry::eventId(
+                value);
+        serialize(*this);
+    }
+
+    return current;
+}
+
 sdbusplus::message::unix_fd Entry::getEntry()
 {
     FILE* fp = fopen(path().c_str(), "rb");
diff --git a/elog_entry.hpp b/elog_entry.hpp
index 0a100f4..45e8aac 100644
--- a/elog_entry.hpp
+++ b/elog_entry.hpp
@@ -113,6 +113,14 @@
 
     using sdbusplus::xyz::openbmc_project::Logging::server::Entry::resolved;
 
+    /** @brief Update eventId string of the error.
+     *  @param[in] value - The eventID
+     *  @returns New property value
+     */
+    std::string eventId(std::string value) override;
+
+    using sdbusplus::xyz::openbmc_project::Logging::server::Entry::eventId;
+
     /** @brief Delete this d-bus object.
      */
     void delete_() override;
diff --git a/elog_serialize.cpp b/elog_serialize.cpp
index 8af349d..fce433d 100644
--- a/elog_serialize.cpp
+++ b/elog_serialize.cpp
@@ -30,7 +30,8 @@
 void save(Archive& a, const Entry& e, const std::uint32_t /*version*/)
 {
     a(e.id(), e.severity(), e.timestamp(), e.message(), e.additionalData(),
-      e.associations(), e.resolved(), e.version(), e.updateTimestamp());
+      e.associations(), e.resolved(), e.version(), e.updateTimestamp(),
+      e.eventId());
 }
 
 /** @brief Function required by Cereal to perform deserialization.
@@ -54,6 +55,7 @@
     AssociationList associations{};
     std::string fwVersion{};
     uint64_t updateTimestamp{};
+    std::string eventId{};
 
     if (version < std::stoul(FIRST_CEREAL_CLASS_VERSION_WITH_FWLEVEL))
     {
@@ -67,11 +69,16 @@
           resolved, fwVersion);
         updateTimestamp = timestamp;
     }
-    else
+    else if (version < std::stoul(FIRST_CEREAL_CLASS_VERSION_WITH_EVENTID))
     {
         a(id, severity, timestamp, message, additionalData, associations,
           resolved, fwVersion, updateTimestamp);
     }
+    else
+    {
+        a(id, severity, timestamp, message, additionalData, associations,
+          resolved, fwVersion, updateTimestamp, eventId);
+    }
 
     e.id(id);
     e.severity(severity);
@@ -85,6 +92,7 @@
     e.purpose(sdbusplus::xyz::openbmc_project::Software::server::Version::
                   VersionPurpose::BMC);
     e.updateTimestamp(updateTimestamp);
+    e.eventId(eventId);
 }
 
 fs::path serialize(const Entry& e, const fs::path& dir)
diff --git a/extensions/openpower-pels/manager.cpp b/extensions/openpower-pels/manager.cpp
index 33854e2..afd7eb0 100644
--- a/extensions/openpower-pels/manager.cpp
+++ b/extensions/openpower-pels/manager.cpp
@@ -164,6 +164,7 @@
 
         // Check if firmware should quiesce system due to error
         checkPelAndQuiesce(pel);
+        updateEventId(pel);
     }
     else
     {
@@ -360,6 +361,7 @@
 
     // Check if firmware should quiesce system due to error
     checkPelAndQuiesce(pel);
+    updateEventId(pel);
 }
 
 sdbusplus::message::unix_fd Manager::getPEL(uint32_t pelID)
@@ -621,6 +623,42 @@
     }
 }
 
+std::string Manager::getEventId(const openpower::pels::PEL& pel) const
+{
+    std::string str;
+    auto src = pel.primarySRC();
+    if (src)
+    {
+        const auto& hexwords = (*src)->hexwordData();
+
+        std::string refcode = (*src)->asciiString();
+        size_t pos = refcode.find_last_not_of(0x20);
+        if (pos != std::string::npos)
+        {
+            refcode.erase(pos + 1);
+        }
+        str = refcode;
+
+        for (auto& value : hexwords)
+        {
+            str += " ";
+            str += getNumberString("%08X", value);
+        }
+    }
+    return str;
+}
+
+void Manager::updateEventId(std::unique_ptr<openpower::pels::PEL>& pel)
+{
+    std::string eventIdStr = getEventId(*pel);
+
+    auto entryN = _logManager.entries.find(pel->obmcLogID());
+    if (entryN != _logManager.entries.end())
+    {
+        entryN->second->eventId(eventIdStr);
+    }
+}
+
 void Manager::setEntryPath(uint32_t obmcLogID)
 {
     Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
diff --git a/extensions/openpower-pels/manager.hpp b/extensions/openpower-pels/manager.hpp
index c9d05f8..dbadf9e 100644
--- a/extensions/openpower-pels/manager.hpp
+++ b/extensions/openpower-pels/manager.hpp
@@ -210,6 +210,13 @@
      */
     static std::vector<uint8_t> eselToRawData(const std::string& esel);
 
+    /**
+     * @brief Generate event ID from the PEL
+     *
+     * @param[in] pel - The PEL to use
+     */
+    std::string getEventId(const openpower::pels::PEL& pel) const;
+
   private:
     /**
      * @brief Adds a received raw PEL to the PEL repository
@@ -329,6 +336,16 @@
     void checkPelAndQuiesce(std::unique_ptr<openpower::pels::PEL>& pel);
 
     /**
+     * @brief Update eventId D-bus property for this error log
+     *
+     * Update the eventId property of D-bus with SRC and hexwords from the
+     * PEL created
+     *
+     * @param[in] pel - The PEL to use
+     */
+    void updateEventId(std::unique_ptr<openpower::pels::PEL>& pel);
+
+    /**
      * @brief Sets the FilePath of the specified error log entry to the PEL file
      *        path.
      *
diff --git a/test/openpower-pels/pel_manager_test.cpp b/test/openpower-pels/pel_manager_test.cpp
index 4ddf81b..9285c13 100644
--- a/test/openpower-pels/pel_manager_test.cpp
+++ b/test/openpower-pels/pel_manager_test.cpp
@@ -290,6 +290,10 @@
     EXPECT_EQ(pel.obmcLogID(), 33);
     EXPECT_EQ(pel.primarySRC().value()->asciiString(),
               "BD612030                        ");
+    // Check if the eventId creation is good
+    EXPECT_EQ(manager.getEventId(pel),
+              "BD612030 00000055 00000010 00000000 00000000 00000000 00000000 "
+              "00000000 00000000");
 
     // Remove it
     manager.erase(33);