PEL: Support resolution property

Support resolution property to add callouts

Tested: Created new PEL using busctl and checked for the property to
see if the value is updated. The error log daemon was restarted and the
property is checked again to make sure the value is restored.

Verified serialization of new error log by recreating it on a old code
version to make sure logs are created w/o the new property and the
daemon did not crash.

Result:
root@rainier:~# busctl get-property xyz.openbmc_project.Logging \
 /xyz/openbmc_project/logging/entry/1 xyz.openbmc_project.Logging.\
 Entry Resolution
s "1. Priority: High, Procedure: BMCSP02\n2. Priority: Medium, PN: \
SVCDOCS\n"

Test with location Code:
root@p10bmc:~# busctl get-property xyz.openbmc_project.Logging \
/xyz/openbmc_project/logging/entry/3 xyz.openbmc_project.Logging.Entry \
Resolution
s "1. Location Code: U78DA.ND0.1234567-P0, Priority: Medium, PN: SVCDOCS\n2. \
Priority: Low, Procedure: BMCSP02\n"

Signed-off-by: Vijay Lobo <vijaylobo@gmail.com>
Change-Id: I44eebbf794efeb8e752fff98de7c638c927982cd
diff --git a/extensions/openpower-pels/manager.cpp b/extensions/openpower-pels/manager.cpp
index c90cacc..3387970 100644
--- a/extensions/openpower-pels/manager.cpp
+++ b/extensions/openpower-pels/manager.cpp
@@ -172,6 +172,7 @@
         // Check if firmware should quiesce system due to error
         checkPelAndQuiesce(pel);
         updateEventId(pel);
+        updateResolution(pel);
     }
     else
     {
@@ -369,6 +370,7 @@
     // Check if firmware should quiesce system due to error
     checkPelAndQuiesce(pel);
     updateEventId(pel);
+    updateResolution(pel);
 }
 
 sdbusplus::message::unix_fd Manager::getPEL(uint32_t pelID)
@@ -666,6 +668,82 @@
     }
 }
 
+std::string Manager::getResolution(const openpower::pels::PEL& pel) const
+{
+    std::string str;
+    std::string resolution;
+    auto src = pel.primarySRC();
+    if (src)
+    {
+        // First extract the callout pointer and then go through
+        const auto& callouts = (*src)->callouts();
+        namespace pv = openpower::pels::pel_values;
+        // All PELs dont have callout, check before parsing callout data
+        if (callouts)
+        {
+            const auto& entries = callouts->callouts();
+            // Entry starts with index 1
+            uint8_t index = 1;
+            for (auto& entry : entries)
+            {
+                resolution += std::to_string(index) + ". ";
+                // Adding Location code to resolution
+                if (!entry->locationCode().empty())
+                    resolution +=
+                        "Location Code: " + entry->locationCode() + ", ";
+                if (entry->fruIdentity())
+                {
+                    // Get priority and set the resolution string
+                    str = pv::getValue(entry->priority(),
+                                       pel_values::calloutPriorityValues,
+                                       pel_values::registryNamePos);
+                    str[0] = toupper(str[0]);
+                    resolution += "Priority: " + str + ", ";
+                    if (entry->fruIdentity()->getPN().has_value())
+                    {
+                        resolution +=
+                            "PN: " + entry->fruIdentity()->getPN().value() +
+                            ", ";
+                    }
+                    if (entry->fruIdentity()->getSN().has_value())
+                    {
+                        resolution +=
+                            "SN: " + entry->fruIdentity()->getSN().value() +
+                            ", ";
+                    }
+                    if (entry->fruIdentity()->getCCIN().has_value())
+                    {
+                        resolution +=
+                            "CCIN: " + entry->fruIdentity()->getCCIN().value() +
+                            ", ";
+                    }
+                    // Add the maintenance procedure
+                    if (entry->fruIdentity()->getMaintProc().has_value())
+                    {
+                        resolution +=
+                            "Procedure: " +
+                            entry->fruIdentity()->getMaintProc().value() + ", ";
+                    }
+                }
+                resolution.resize(resolution.size() - 2);
+                resolution += "\n";
+                index++;
+            }
+        }
+    }
+    return resolution;
+}
+
+void Manager::updateResolution(std::unique_ptr<openpower::pels::PEL>& pel)
+{
+    std::string callouts = getResolution(*pel);
+    auto entryN = _logManager.entries.find(pel->obmcLogID());
+    if (entryN != _logManager.entries.end())
+    {
+        entryN->second->resolution(callouts);
+    }
+}
+
 void Manager::setEntryPath(uint32_t obmcLogID)
 {
     Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};