PEL: Print SRC section into JSON

For BMC created errors, look up the reason code in
the message registry for error description and also
meaning of data stored in hexwords 6-9 (if any).

Added registry message field in peltool list output.

"Primary SRC": {
    "Section Version":          "1",
    "Sub-section type":         "1",
    "Created by":               "0x1000",
    "SRC Version":              "0x02",
    "SRC Format":               "0x55",
    "Power Control Net Fault":  "False",
    "Error Details": {
        "Message":              "PS 0x64 had a PGOOD Fault",
        "PS_NUM":               "0x64"
    },
    "Valid Word Count":         "0x09",
    "Reference Code":           "BD8D1001",
    "Hex Word 2":               "00000055",
    "Hex Word 3":               "00000010",
    "Hex Word 4":               "00000000",
    "Hex Word 5":               "00000000",
    "Hex Word 6":               "00000064",
    "Hex Word 7":               "00000000",
    "Hex Word 8":               "00000000",
    "Hex Word 9":               "00000000"
}

"Primary SRC": {
    "Section Version":          "1",
    "Sub-section type":         "0",
    "Created by":               "0x4552",
    "SRC Version":              "0x02",
    "SRC Format":               "0x2008000",
    "Power Control Net Fault":  "False",
    "Valid Word Count":         "0x04",
    "Reference Code":           "B2001020",
    "Hex Word 2":               "02008000",
    "Hex Word 3":               "00000000",
    "Hex Word 4":               "00000012",
    "Callout Section": {
        "Callout Count":        "1",
        "Callouts": [{
            "FRU Type":         "Symbolic FRU",
            "Priority":         "Medium Priority",
            "Part Number":      "NEXTLVL"
        }]
    }
}

Testing: Manually run peltool and verified out. All unit tests passed.
Signed-off-by: Harisuddin Mohamed Isa <harisuddin@gmail.com>
Change-Id: I124627ba785413ebda02305b7d9f95431922e714
diff --git a/extensions/openpower-pels/registry.cpp b/extensions/openpower-pels/registry.cpp
index d749ab9..3c4e016 100644
--- a/extensions/openpower-pels/registry.cpp
+++ b/extensions/openpower-pels/registry.cpp
@@ -264,37 +264,34 @@
 
 } // namespace helper
 
-std::optional<Entry> Registry::lookup(const std::string& name)
+std::optional<Entry> Registry::lookup(const std::string& name, LookupType type,
+                                      bool toCache)
 {
-    // Look in /etc first in case someone put a test file there
-    fs::path debugFile{fs::path{debugFilePath} / registryFileName};
-    nlohmann::json registry;
-    std::ifstream file;
-
-    if (fs::exists(debugFile))
+    std::optional<nlohmann::json> registryTmp;
+    auto& registryOpt = (_registry) ? _registry : registryTmp;
+    if (!registryOpt)
     {
-        log<level::INFO>("Using debug PEL message registry");
-        file.open(debugFile);
+        registryOpt = readRegistry(_registryFile);
+        if (!registryOpt)
+        {
+            return std::nullopt;
+        }
+        else if (toCache)
+        {
+            // Save message registry in memory for peltool
+            _registry = std::move(registryTmp);
+        }
     }
-    else
-    {
-        file.open(_registryFile);
-    }
-
-    try
-    {
-        registry = nlohmann::json::parse(file);
-    }
-    catch (std::exception& e)
-    {
-        log<level::ERR>("Error parsing message registry JSON",
-                        entry("JSON_ERROR=%s", e.what()));
-        return std::nullopt;
-    }
-
+    auto& reg = (_registry) ? _registry : registryTmp;
+    const auto& registry = reg.value();
     // Find an entry with this name in the PEL array.
-    auto e = std::find_if(registry["PELs"].begin(), registry["PELs"].end(),
-                          [&name](const auto& j) { return name == j["Name"]; });
+    auto e = std::find_if(
+        registry["PELs"].begin(), registry["PELs"].end(),
+        [&name, &type](const auto& j) {
+            return ((name == j["Name"] && type == LookupType::name) ||
+                    (name == j["SRC"]["ReasonCode"] &&
+                     type == LookupType::reasonCode));
+        });
 
     if (e != registry["PELs"].end())
     {
@@ -371,6 +368,14 @@
                 entry.src.powerFault = src["PowerFault"];
             }
 
+            auto& doc = (*e)["Documentation"];
+            entry.doc.message = doc["Message"];
+            entry.doc.description = doc["Description"];
+            if (doc.find("MessageArgSources") != doc.end())
+            {
+                entry.doc.messageArgSources = doc["MessageArgSources"];
+            }
+
             return entry;
         }
         catch (std::exception& e)
@@ -383,6 +388,37 @@
     return std::nullopt;
 }
 
+std::optional<nlohmann::json>
+    Registry::readRegistry(const std::filesystem::path& registryFile)
+{
+    // Look in /etc first in case someone put a test file there
+    fs::path debugFile{fs::path{debugFilePath} / registryFileName};
+    nlohmann::json registry;
+    std::ifstream file;
+
+    if (fs::exists(debugFile))
+    {
+        log<level::INFO>("Using debug PEL message registry");
+        file.open(debugFile);
+    }
+    else
+    {
+        file.open(registryFile);
+    }
+
+    try
+    {
+        registry = nlohmann::json::parse(file);
+    }
+    catch (std::exception& e)
+    {
+        log<level::ERR>("Error parsing message registry JSON",
+                        entry("JSON_ERROR=%s", e.what()));
+        return std::nullopt;
+    }
+    return registry;
+}
+
 } // namespace message
 } // namespace pels
 } // namespace openpower