PEL: user header in JSON

The PELTool application is able to convert sections to JSON. This commit
takes care of converting the user header section to JSON.

user header section in JSON sample:

"User Header":[
 {"Section Version": "1"},
 {"Sub-section type": "0"},
 {"Log Committed by": "0x2000"},
 {"Subsystem": "bmc_firmware"},
 {"Event Scope": "entire_platform"},
 {"Event Severity":"unrecoverable"},
 {"Event Type": "na"}
]

Signed-off-by: Aatir Manzur <aatrapps@gmail.com>
Change-Id: I0dca1d87019b9e62d711ee6d034f2e8bc0574c2e
diff --git a/extensions/openpower-pels/pel.cpp b/extensions/openpower-pels/pel.cpp
index babc61b..2345e0e 100644
--- a/extensions/openpower-pels/pel.cpp
+++ b/extensions/openpower-pels/pel.cpp
@@ -206,21 +206,30 @@
 void PEL::printSectionInJSON(const Section& section, std::string& buf) const
 {
     char tmpB[5];
+    uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
+                    static_cast<uint8_t>(section.header().id)};
+    sprintf(tmpB, "%c%c", id[0], id[1]);
+    std::string sectionID(tmpB);
+    std::string sectionName = pv::sectionTitles.count(sectionID)
+                                  ? pv::sectionTitles.at(sectionID)
+                                  : "Unknown Section";
     if (section.valid())
     {
-        uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
-                        static_cast<uint8_t>(section.header().id)};
-        sprintf(tmpB, "%c%c", id[0], id[1]);
-        std::string sectionID(tmpB);
-        std::string sectionName = pv::sectionTitles.count(sectionID)
-                                      ? pv::sectionTitles.at(sectionID)
-                                      : "Unknown Section";
-        buf += "\n\"" + sectionName + "\":[\n ";
-        std::vector<uint8_t> data;
-        Stream s{data};
-        section.flatten(s);
-        std::string dstr = dumpHex(std::data(data), data.size());
-        buf += dstr + "\n],\n";
+        auto json = section.getJSON();
+        if (json)
+        {
+            buf += "\n\"" + sectionName + "\":[\n ";
+            buf += *json + "\n],\n";
+        }
+        else
+        {
+            buf += "\n\"" + sectionName + "\":[\n ";
+            std::vector<uint8_t> data;
+            Stream s{data};
+            section.flatten(s);
+            std::string dstr = dumpHex(std::data(data), data.size());
+            buf += dstr + "],\n";
+        }
     }
     else
     {
diff --git a/extensions/openpower-pels/section.hpp b/extensions/openpower-pels/section.hpp
index 9fe3893..6353e2d 100644
--- a/extensions/openpower-pels/section.hpp
+++ b/extensions/openpower-pels/section.hpp
@@ -1,11 +1,13 @@
 #pragma once
+
 #include "section_header.hpp"
 
+#include <optional>
+
 namespace openpower
 {
 namespace pels
 {
-
 /**
  * @class Section
  *
@@ -46,6 +48,16 @@
      */
     virtual void flatten(Stream& stream) const = 0;
 
+    /**
+     * @brief Get section in JSON. Derived classes to override when required to.
+     * @return std::optional<std::string> - If a section comes with a JSON
+     * repressentation, this would return the string for it.
+     */
+    virtual std::optional<std::string> getJSON() const
+    {
+        return std::nullopt;
+    }
+
   protected:
     /**
      * @brief Returns the flattened size of the section header
diff --git a/extensions/openpower-pels/user_header.cpp b/extensions/openpower-pels/user_header.cpp
index 0014b57..c52d4b5 100644
--- a/extensions/openpower-pels/user_header.cpp
+++ b/extensions/openpower-pels/user_header.cpp
@@ -18,6 +18,7 @@
 #include "pel_types.hpp"
 #include "severity.hpp"
 
+#include <iostream>
 #include <phosphor-logging/log.hpp>
 
 namespace openpower
@@ -126,5 +127,48 @@
     _valid = (failed) ? false : true;
 }
 
+std::string UserHeader::getValue(const uint8_t field,
+                                 const pel_values::PELValues& values) const
+{
+
+    auto tmp = pel_values::findByValue(field, values);
+    if (tmp != values.end())
+    {
+        return std::get<pel_values::registryNamePos>(*tmp);
+    }
+    else
+    {
+        return "invalid";
+    }
+}
+std::optional<std::string> UserHeader::getJSON() const
+{
+    std::string severity;
+    std::string subsystem;
+    std::string eventScope;
+    std::string eventType;
+    severity = getValue(_eventSeverity, pel_values::severityValues);
+    subsystem = getValue(_eventSubsystem, pel_values::subsystemValues);
+    eventScope = getValue(_eventScope, pel_values::eventScopeValues);
+    eventType = getValue(_eventType, pel_values::eventTypeValues);
+    char tmpUhVal[8];
+    sprintf(tmpUhVal, "%d", userHeaderVersion);
+    std::string uhVerStr(tmpUhVal);
+    sprintf(tmpUhVal, "0x%X", _header.componentID);
+    std::string uhCbStr(tmpUhVal);
+    sprintf(tmpUhVal, "%d", _header.subType);
+    std::string uhStStr(tmpUhVal);
+
+    std::string uh = "{\"Section Version\": \"" + uhVerStr +
+                     "\"}, \n {\"Sub-section type\": \"" + uhStStr +
+                     "\"}, \n "
+                     "{\"Log Committed by\": \"" +
+                     uhCbStr + "\"}, \n {\"Subsystem\": \"" + subsystem +
+                     "\"},\n "
+                     "{\"Event Scope\": \"" +
+                     eventScope + "\"}, \n {\"Event Severity\":\"" + severity +
+                     "\"},\n {\"Event Type\": \"" + eventType + "\"}";
+    return uh;
+}
 } // namespace pels
 } // namespace openpower
diff --git a/extensions/openpower-pels/user_header.hpp b/extensions/openpower-pels/user_header.hpp
index a1873f5..5689a1c 100644
--- a/extensions/openpower-pels/user_header.hpp
+++ b/extensions/openpower-pels/user_header.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "elog_entry.hpp"
+#include "pel_values.hpp"
 #include "registry.hpp"
 #include "section.hpp"
 #include "stream.hpp"
@@ -165,6 +166,13 @@
                sizeof(_actionFlags) + sizeof(_reserved4Byte2);
     }
 
+    /**
+     * @brief Get section in JSON.
+     * @return std::optional<std::string> - If a section comes with a JSON
+     * repressentation, this would return the string for it.
+     */
+    std::optional<std::string> getJSON() const override;
+
   private:
     /**
      * @brief Fills in the object from the stream data
@@ -224,6 +232,15 @@
      * @brief The second reserved word placeholder.
      */
     uint32_t _reserved4Byte2;
+
+    /**
+     * @brief Helper function to get values from lookup tables.
+     * @return std::string - the value
+     * @param[in] uint8_t - field to get value for
+     * @param[in] PELValues - lookup table
+     */
+    std::string getValue(const uint8_t field,
+                         const pel_values::PELValues& values) const;
 };
 
 } // namespace pels