pldmtool: Map completion codes to readable strings

Add helper utility to map numeric PLDM completion codes
to human-readable strings. This enhances readability
and debugging when interpreting PLDM responses.

Change-Id: I6dfe98741fe51203c26562ae988d74d8fd093f09
Signed-off-by: Rajeev Ranjan <ranjan.rajeev1609@gmail.com>
diff --git a/pldmtool/pldm_cmd_helper.cpp b/pldmtool/pldm_cmd_helper.cpp
index 1de5b8d..cbcf827 100644
--- a/pldmtool/pldm_cmd_helper.cpp
+++ b/pldmtool/pldm_cmd_helper.cpp
@@ -3,6 +3,7 @@
 #include "common/transport.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
 
+#include <libpldm/firmware_update.h>
 #include <libpldm/transport.h>
 #include <libpldm/transport/af-mctp.h>
 #include <libpldm/transport/mctp-demux.h>
@@ -21,6 +22,70 @@
 namespace helper
 {
 
+static const std::map<uint8_t, std::string> genericCompletionCodes{
+    {PLDM_SUCCESS, "SUCCESS"},
+    {PLDM_ERROR, "ERROR"},
+    {PLDM_ERROR_INVALID_DATA, "ERROR_INVALID_DATA"},
+    {PLDM_ERROR_INVALID_LENGTH, "ERROR_INVALID_LENGTH"},
+    {PLDM_ERROR_NOT_READY, "ERROR_NOT_READY"},
+    {PLDM_ERROR_UNSUPPORTED_PLDM_CMD, "ERROR_UNSUPPORTED_PLDM_CMD"},
+    {PLDM_ERROR_INVALID_PLDM_TYPE, "ERROR_INVALID_PLDM_TYPE"},
+    {PLDM_INVALID_TRANSFER_OPERATION_FLAG, "INVALID_TRANSFER_OPERATION_FLAG"}};
+
+static const std::map<uint8_t, std::string> fwupdateCompletionCodes{
+    {PLDM_FWUP_NOT_IN_UPDATE_MODE, "NOT_IN_UPDATE_MODE"},
+    {PLDM_FWUP_ALREADY_IN_UPDATE_MODE, "ALREADY_IN_UPDATE_MODE"},
+    {PLDM_FWUP_DATA_OUT_OF_RANGE, "DATA_OUT_OF_RANGE"},
+    {PLDM_FWUP_INVALID_TRANSFER_LENGTH, "INVALID_TRANSFER_LENGTH"},
+    {PLDM_FWUP_INVALID_STATE_FOR_COMMAND, "INVALID_STATE_FOR_COMMAND"},
+    {PLDM_FWUP_INCOMPLETE_UPDATE, "INCOMPLETE_UPDATE"},
+    {PLDM_FWUP_BUSY_IN_BACKGROUND, "BUSY_IN_BACKGROUND"},
+    {PLDM_FWUP_CANCEL_PENDING, "CANCEL_PENDING"},
+    {PLDM_FWUP_COMMAND_NOT_EXPECTED, "COMMAND_NOT_EXPECTED"},
+    {PLDM_FWUP_RETRY_REQUEST_FW_DATA, "RETRY_REQUEST_FW_DATA"},
+    {PLDM_FWUP_UNABLE_TO_INITIATE_UPDATE, "UNABLE_TO_INITIATE_UPDATE"},
+    {PLDM_FWUP_ACTIVATION_NOT_REQUIRED, "ACTIVATION_NOT_REQUIRED"},
+    {PLDM_FWUP_SELF_CONTAINED_ACTIVATION_NOT_PERMITTED,
+     "SELF_CONTAINED_ACTIVATION_NOT_PERMITTED"},
+    {PLDM_FWUP_NO_DEVICE_METADATA, "NO_DEVICE_METADATA"},
+    {PLDM_FWUP_RETRY_REQUEST_UPDATE, "RETRY_REQUEST_UPDATE"},
+    {PLDM_FWUP_NO_PACKAGE_DATA, "NO_PACKAGE_DATA"},
+    {PLDM_FWUP_INVALID_TRANSFER_HANDLE, "INVALID_TRANSFER_HANDLE"},
+    {PLDM_FWUP_INVALID_TRANSFER_OPERATION_FLAG,
+     "INVALID_TRANSFER_OPERATION_FLAG"},
+    {PLDM_FWUP_ACTIVATE_PENDING_IMAGE_NOT_PERMITTED,
+     "ACTIVATE_PENDING_IMAGE_NOT_PERMITTED"},
+    {PLDM_FWUP_PACKAGE_DATA_ERROR, "PACKAGE_DATA_ERROR"}};
+
+void fillCompletionCode(uint8_t completionCode, ordered_json& data,
+                        uint8_t pldmType)
+{
+    // Check generic completion codes first for all PLDM types
+    auto it = genericCompletionCodes.find(completionCode);
+    if (it != genericCompletionCodes.end())
+    {
+        data["CompletionCode"] = it->second;
+        return;
+    }
+
+    // If not a generic code, check type-specific codes
+    switch (pldmType)
+    {
+        case PLDM_FWUP:
+        {
+            auto typeIt = fwupdateCompletionCodes.find(completionCode);
+            if (typeIt != fwupdateCompletionCodes.end())
+            {
+                data["CompletionCode"] = typeIt->second;
+                return;
+            }
+            break;
+        }
+    }
+
+    data["CompletionCode"] = "UNKNOWN_COMPLETION_CODE";
+}
+
 void CommandInterface::exec()
 {
     instanceId = instanceIdDb.next(mctp_eid);
diff --git a/pldmtool/pldm_cmd_helper.hpp b/pldmtool/pldm_cmd_helper.hpp
index e668974..de33d53 100644
--- a/pldmtool/pldm_cmd_helper.hpp
+++ b/pldmtool/pldm_cmd_helper.hpp
@@ -60,6 +60,16 @@
     std::cout << data.dump(4) << std::endl;
 }
 
+/**
+ * @brief Maps numeric PLDM completion codes to human-readable strings
+ *
+ * @param[in] completionCode - Numeric PLDM completion code returned in response
+ * @param[in] data - The JSON data to which the completion code is added.
+ * @param[in] pldmType - PLDM type
+ */
+void fillCompletionCode(uint8_t completionCode, ordered_json& data,
+                        uint8_t pldmType);
+
 /** @brief MCTP socket read/receive
  *
  *  @param[in]  requestMsg - Request message to compare against loopback