support to parse RAS data signatures and actions

Change-Id: I114e62f11f962fa9f5b1d7cf52219984e5800f86
Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
diff --git a/analyzer/ras-data/ras-data-definition.md b/analyzer/ras-data/ras-data-definition.md
index b55886e..6603494 100644
--- a/analyzer/ras-data/ras-data-definition.md
+++ b/analyzer/ras-data/ras-data-definition.md
@@ -160,7 +160,6 @@
 | name        | The `<bus_name>` as defined by the `buses` keyword.            |
 | rx_priority | Optional priority of the receiving side endpoint               |
 | tx_priority | Optional priority of the transfer side endpoint                |
-| name        | The `<bus_name>` as defined by the `buses` keyword.            |
 | guard       | See `guard` table above.                                       |
 
 #### 5.1.6) action type `callout_clock`
diff --git a/analyzer/ras-data/ras-data-parser.cpp b/analyzer/ras-data/ras-data-parser.cpp
index d1315dc..6386b6b 100644
--- a/analyzer/ras-data/ras-data-parser.cpp
+++ b/analyzer/ras-data/ras-data-parser.cpp
@@ -14,11 +14,13 @@
 //------------------------------------------------------------------------------
 
 std::shared_ptr<Resolution>
-    RasDataParser::getResolution(const libhei::Signature&)
+    RasDataParser::getResolution(const libhei::Signature& i_signature)
 {
-    // TODO: Default to level 2 support callout until fully implemented.
-    return std::make_shared<ProcedureCalloutResolution>(
-        ProcedureCallout::NEXTLVL, Callout::HIGH);
+    const auto data = iv_dataFiles.at(i_signature.getChip().getType());
+
+    const auto action = parseSignature(data, i_signature);
+
+    return parseAction(data, action);
 }
 
 //------------------------------------------------------------------------------
@@ -96,4 +98,161 @@
 
 //------------------------------------------------------------------------------
 
+std::string RasDataParser::parseSignature(const nlohmann::json& i_data,
+                                          const libhei::Signature& i_signature)
+{
+    // Get the signature keys. All are hex (lower case) with no prefix.
+    char buf[5];
+    sprintf(buf, "%04x", i_signature.getId());
+    std::string id{buf};
+
+    sprintf(buf, "%02x", i_signature.getBit());
+    std::string bit{buf};
+
+    sprintf(buf, "%02x", i_signature.getInstance());
+    std::string inst{buf};
+
+    // Return the action.
+    return i_data.at("signatures").at(id).at(bit).at(inst).get<std::string>();
+}
+
+//------------------------------------------------------------------------------
+
+std::shared_ptr<Resolution>
+    RasDataParser::parseAction(const nlohmann::json& i_data,
+                               const std::string& i_action)
+{
+    auto o_list = std::make_shared<ResolutionList>();
+
+    // This function will be called recursively and we want to prevent cyclic
+    // recursion.
+    static std::vector<std::string> stack;
+    assert(stack.end() == std::find(stack.begin(), stack.end(), i_action));
+    stack.push_back(i_action);
+
+    // Iterate the action list and apply the changes.
+    for (const auto& a : i_data.at("actions").at(i_action))
+    {
+        auto type = a.at("type").get<std::string>();
+
+        if ("action" == type)
+        {
+            auto name = a.at("name").get<std::string>();
+
+            o_list->push(parseAction(i_data, name));
+        }
+        else if ("callout_self" == type)
+        {
+            auto priority = a.at("priority").get<std::string>();
+            auto guard    = a.at("guard").get<bool>();
+
+            // TODO
+            trace::inf("callout_self: priority=%s guard=%c", priority.c_str(),
+                       guard ? 'T' : 'F');
+        }
+        else if ("callout_unit" == type)
+        {
+            auto name     = a.at("name").get<std::string>();
+            auto priority = a.at("priority").get<std::string>();
+            auto guard    = a.at("guard").get<bool>();
+
+            // TODO
+            trace::inf("callout_unit: name=%s priority=%s guard=%c",
+                       name.c_str(), priority.c_str(), guard ? 'T' : 'F');
+        }
+        else if ("callout_connected" == type)
+        {
+            auto name     = a.at("name").get<std::string>();
+            auto priority = a.at("priority").get<std::string>();
+            auto guard    = a.at("guard").get<bool>();
+
+            // TODO
+            trace::inf("callout_connected: name=%s priority=%s guard=%c",
+                       name.c_str(), priority.c_str(), guard ? 'T' : 'F');
+        }
+        else if ("callout_bus" == type)
+        {
+            auto name = a.at("name").get<std::string>();
+            // auto rx_priority = a.at("rx_priority").get<std::string>();
+            // auto tx_priority = a.at("tx_priority").get<std::string>();
+            auto guard = a.at("guard").get<bool>();
+
+            // TODO
+            trace::inf("callout_bus: name=%s guard=%c", name.c_str(),
+                       guard ? 'T' : 'F');
+        }
+        else if ("callout_clock" == type)
+        {
+            auto position = a.at("position").get<unsigned int>();
+            auto priority = a.at("priority").get<std::string>();
+            auto guard    = a.at("guard").get<bool>();
+
+            // TODO
+            trace::inf("callout_clock: position=%u priority=%s guard=%c",
+                       position, priority.c_str(), guard ? 'T' : 'F');
+        }
+        else if ("callout_procedure" == type)
+        {
+            auto name     = a.at("name").get<std::string>();
+            auto priority = a.at("priority").get<std::string>();
+
+            // clang-format off
+            static const std::map<std::string, ProcedureCallout::Type> m =
+            {
+                {"LEVEL2", ProcedureCallout::NEXTLVL},
+            };
+            // clang-format on
+
+            o_list->push(std::make_shared<ProcedureCalloutResolution>(
+                m.at(name), getPriority(priority)));
+        }
+        else if ("callout_part" == type)
+        {
+            auto name     = a.at("name").get<std::string>();
+            auto priority = a.at("priority").get<std::string>();
+
+            // TODO
+            trace::inf("callout_part: name=%s priority=%s", name.c_str(),
+                       priority.c_str());
+        }
+        else if ("plugin" == type)
+        {
+            auto name = a.at("name").get<std::string>();
+
+            // TODO
+            trace::inf("plugin: name=%s", name.c_str());
+        }
+        else
+        {
+            throw std::logic_error("Unsupported action type: " + type);
+        }
+    }
+
+    // Done with this action pop it off the stack.
+    stack.pop_back();
+
+    return o_list;
+}
+
+//------------------------------------------------------------------------------
+
+Callout::Priority RasDataParser::getPriority(const std::string& i_priority)
+{
+    // clang-format off
+    static const std::map<std::string, Callout::Priority> m =
+    {
+        {"HIGH",  Callout::HIGH},
+        {"MED",   Callout::MED},
+        {"MED_A", Callout::MED_A},
+        {"MED_B", Callout::MED_B},
+        {"MED_C", Callout::MED_C},
+        {"LOW",   Callout::LOW},
+    };
+    // clang-format on
+
+    return m.at(i_priority);
+}
+
+//------------------------------------------------------------------------------
+
 } // namespace analyzer
diff --git a/analyzer/ras-data/ras-data-parser.hpp b/analyzer/ras-data/ras-data-parser.hpp
index e484167..6d45ad2 100644
--- a/analyzer/ras-data/ras-data-parser.hpp
+++ b/analyzer/ras-data/ras-data-parser.hpp
@@ -41,6 +41,40 @@
      *        the associated schema.
      */
     void initDataFiles();
+
+    /**
+     * @brief  Parses a signature in the given data file and returns a string
+     *         representing the target action for the signature.
+     * @param  i_data      The parsed RAS data file associated with the
+     *                     signature's chip type.
+     * @param  i_signature The target signature.
+     * @return A string representing the target action for the signature.
+     */
+    std::string parseSignature(const nlohmann::json& i_data,
+                               const libhei::Signature& i_signature);
+
+    /**
+     * @brief  Parses an action in the given data file and returns the
+     *         corresponding resolution.
+     * @param  i_data   The parsed RAS data file associated with the signature's
+     *                  chip type.
+     * @param  i_action The target action to parse from the given RAS data.
+     * @return A resolution (or nested resolutions) representing the given
+     *         action.
+     * @note   This function is called recursively because an action could
+     *         reference another action. This function will maintain a stack of
+     *         parsed actions and will assert that the same action cannot be
+     *         parsed more than once in the recursion stack.
+     */
+    std::shared_ptr<Resolution> parseAction(const nlohmann::json& i_data,
+                                            const std::string& i_action);
+
+    /**
+     * @brief  Returns a callout priority enum value for the given string.
+     * @param  i_priority The priority string.
+     * @return A callout priority enum value.
+     */
+    Callout::Priority getPriority(const std::string& i_priority);
 };
 
 } // namespace analyzer