pldmtool: Add GetBIOSAttributeCurrentValueByHandle command

Tested: Tested on fp5280g2.
$ ./pldmtool bios getbiosattributecurrentvaluebyhandle -a Model
CurrentValue: powersupply0

$ ./pldmtool bios getbiosattributecurrentvaluebyhandle -a str_example3
CurrentValue: ef

$ ./pldmtool bios getbiosattributecurrentvaluebyhandle -a OUTLET
CurrentValue: 0

$ ./pldmtool bios getbiosattributecurrentvaluebyhandle -a Led
CurrentValue: Off

Signed-off-by: Adair Li <lichao.lc01@inspur.com>
Change-Id: I4e50159f82dc2a1a34c1f36a1eb3a541d60cbd4a
diff --git a/tool/pldm_bios_cmd.cpp b/tool/pldm_bios_cmd.cpp
index 60a7239..126642f 100644
--- a/tool/pldm_bios_cmd.cpp
+++ b/tool/pldm_bios_cmd.cpp
@@ -160,31 +160,38 @@
     uint64_t tmData;
 };
 
-class GetBIOSTable : public CommandInterface
+class GetBIOSTableHandler : public CommandInterface
 {
   public:
-    ~GetBIOSTable() = default;
-    GetBIOSTable() = delete;
-    GetBIOSTable(const GetBIOSTable&) = delete;
-    GetBIOSTable(GetBIOSTable&&) = default;
-    GetBIOSTable& operator=(const GetBIOSTable&) = delete;
-    GetBIOSTable& operator=(GetBIOSTable&&) = default;
+    ~GetBIOSTableHandler() = default;
+    GetBIOSTableHandler() = delete;
+    GetBIOSTableHandler(const GetBIOSTableHandler&) = delete;
+    GetBIOSTableHandler(GetBIOSTableHandler&&) = delete;
+    GetBIOSTableHandler& operator=(const GetBIOSTableHandler&) = delete;
+    GetBIOSTableHandler& operator=(GetBIOSTableHandler&&) = delete;
 
     using Table = std::vector<uint8_t>;
 
-    explicit GetBIOSTable(const char* type, const char* name, CLI::App* app) :
-        CommandInterface(type, name, app)
-    {
-        app->add_option("-t,--type", pldmBIOSTableType, "pldm bios table type")
-            ->required()
-            ->transform(
-                CLI::CheckedTransformer(pldmBIOSTableTypes, CLI::ignore_case));
-    }
+    using CommandInterface::CommandInterface;
+
+    static inline const std::map<pldm_bios_attribute_type, const char*>
+        attrTypeMap = {
+            {PLDM_BIOS_ENUMERATION, "BIOSEnumeration"},
+            {PLDM_BIOS_ENUMERATION_READ_ONLY, "BIOSEnumerationReadOnly"},
+            {PLDM_BIOS_STRING, "BIOSString"},
+            {PLDM_BIOS_STRING_READ_ONLY, "BIOSStringReadOnly"},
+            {PLDM_BIOS_PASSWORD, "BIOSPassword"},
+            {PLDM_BIOS_PASSWORD_READ_ONLY, "BIOSPasswordReadOnly"},
+            {PLDM_BIOS_INTEGER, "BIOSInteger"},
+            {PLDM_BIOS_INTEGER_READ_ONLY, "BIOSIntegerReadOnly"},
+
+        };
 
     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
     {
         return {PLDM_ERROR, {}};
     }
+
     void parseResponseMsg(pldm_msg*, size_t) override
     {
     }
@@ -235,53 +242,33 @@
         return std::make_optional<Table>(tableData, tableData + tableSize);
     }
 
-    void exec() override
+    std::optional<uint16_t> findAttrHandleByName(const std::string& name,
+                                                 const Table& attrTable,
+                                                 const Table& stringTable)
     {
-
-        switch (pldmBIOSTableType)
+        auto stringEntry = pldm_bios_table_string_find_by_string(
+            stringTable.data(), stringTable.size(), name.c_str());
+        if (stringEntry == nullptr)
         {
-            case PLDM_BIOS_STRING_TABLE:
-            {
-                auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
-                decodeStringTable(stringTable);
-                break;
-            }
-            case PLDM_BIOS_ATTR_TABLE:
-            {
-                auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
-                auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+            return std::nullopt;
+        }
 
-                decodeAttributeTable(attrTable, stringTable);
-            }
-            break;
-            case PLDM_BIOS_ATTR_VAL_TABLE:
-            {
-                auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
-                auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
-                auto attrValTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
+        auto nameHandle =
+            pldm_bios_table_string_entry_decode_handle(stringEntry);
 
-                decodeAttributeValueTable(attrValTable, attrTable, stringTable);
-                break;
+        for (auto attr : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable.data(),
+                                                             attrTable.size()))
+        {
+            auto attrNameHandle =
+                pldm_bios_table_attr_entry_decode_string_handle(attr);
+            if (attrNameHandle == nameHandle)
+            {
+                return pldm_bios_table_attr_entry_decode_attribute_handle(attr);
             }
         }
+        return std::nullopt;
     }
 
-  private:
-    pldm_bios_table_types pldmBIOSTableType;
-
-    static inline const std::map<pldm_bios_attribute_type, const char*>
-        attrTypeMap = {
-            {PLDM_BIOS_ENUMERATION, "BIOSEnumeration"},
-            {PLDM_BIOS_ENUMERATION_READ_ONLY, "BIOSEnumerationReadOnly"},
-            {PLDM_BIOS_STRING, "BIOSString"},
-            {PLDM_BIOS_STRING_READ_ONLY, "BIOSStringReadOnly"},
-            {PLDM_BIOS_PASSWORD, "BIOSPassword"},
-            {PLDM_BIOS_PASSWORD_READ_ONLY, "BIOSPasswordReadOnly"},
-            {PLDM_BIOS_INTEGER, "BIOSInteger"},
-            {PLDM_BIOS_INTEGER_READ_ONLY, "BIOSIntegerReadOnly"},
-
-        };
-
     std::string decodeStringFromStringEntry(
         const pldm_bios_string_table_entry* stringEntry)
     {
@@ -295,7 +282,8 @@
     }
 
     std::string displayStringHandle(uint16_t handle,
-                                    const std::optional<Table>& stringTable)
+                                    const std::optional<Table>& stringTable,
+                                    bool displayHandle = true)
     {
         std::string displayString = std::to_string(handle);
         if (!stringTable)
@@ -309,8 +297,13 @@
             return displayString;
         }
 
-        return displayString + "(" + decodeStringFromStringEntry(stringEntry) +
-               ")";
+        auto decodedStr = decodeStringFromStringEntry(stringEntry);
+        if (!displayHandle)
+        {
+            return decodedStr;
+        }
+
+        return displayString + "(" + decodedStr + ")";
     }
 
     std::string displayEnumValueByIndex(uint16_t attrHandle, uint8_t index,
@@ -333,9 +326,125 @@
         std::vector<uint16_t> pvHandls(pvNum);
         pldm_bios_table_attr_entry_enum_decode_pv_hdls(
             attrEntry, pvHandls.data(), pvHandls.size());
-        return displayStringHandle(pvHandls[index], stringTable);
+        return displayStringHandle(pvHandls[index], stringTable, false);
     }
 
+    void displayAttributeValueEntry(
+        const pldm_bios_attr_val_table_entry* tableEntry,
+        const std::optional<Table>& attrTable,
+        const std::optional<Table>& stringTable)
+    {
+        auto attrHandle =
+            pldm_bios_table_attr_value_entry_decode_attribute_handle(
+                tableEntry);
+        auto attrType = static_cast<pldm_bios_attribute_type>(
+            pldm_bios_table_attr_value_entry_decode_attribute_type(tableEntry));
+        switch (attrType)
+        {
+            case PLDM_BIOS_ENUMERATION:
+            case PLDM_BIOS_ENUMERATION_READ_ONLY:
+            {
+                auto count =
+                    pldm_bios_table_attr_value_entry_enum_decode_number(
+                        tableEntry);
+                std::vector<uint8_t> handles(count);
+                pldm_bios_table_attr_value_entry_enum_decode_handles(
+                    tableEntry, handles.data(), handles.size());
+                for (size_t i = 0; i < handles.size(); i++)
+                {
+                    std::cout << "CurrentValue: "
+                              << displayEnumValueByIndex(attrHandle, handles[i],
+                                                         attrTable, stringTable)
+                              << std::endl;
+                }
+                break;
+            }
+            case PLDM_BIOS_INTEGER:
+            case PLDM_BIOS_INTEGER_READ_ONLY:
+            {
+                auto cv = pldm_bios_table_attr_value_entry_integer_decode_cv(
+                    tableEntry);
+                std::cout << "CurrentValue: " << cv << std::endl;
+                break;
+            }
+            case PLDM_BIOS_STRING:
+            case PLDM_BIOS_STRING_READ_ONLY:
+            {
+                variable_field currentString;
+                pldm_bios_table_attr_value_entry_string_decode_string(
+                    tableEntry, &currentString);
+                std::cout << "CurrentValue: "
+                          << std::string(reinterpret_cast<const char*>(
+                                             currentString.ptr),
+                                         currentString.length)
+                          << std::endl;
+
+                break;
+            }
+            case PLDM_BIOS_PASSWORD:
+            case PLDM_BIOS_PASSWORD_READ_ONLY:
+            {
+                std::cout << "Password attribute: Not Supported" << std::endl;
+                break;
+            }
+        }
+    }
+};
+
+class GetBIOSTable : public GetBIOSTableHandler
+{
+  public:
+    ~GetBIOSTable() = default;
+    GetBIOSTable() = delete;
+    GetBIOSTable(const GetBIOSTable&) = delete;
+    GetBIOSTable(GetBIOSTable&&) = default;
+    GetBIOSTable& operator=(const GetBIOSTable&) = delete;
+    GetBIOSTable& operator=(GetBIOSTable&&) = default;
+
+    using Table = std::vector<uint8_t>;
+
+    explicit GetBIOSTable(const char* type, const char* name, CLI::App* app) :
+        GetBIOSTableHandler(type, name, app)
+    {
+        app->add_option("-t,--type", pldmBIOSTableType, "pldm bios table type")
+            ->required()
+            ->transform(
+                CLI::CheckedTransformer(pldmBIOSTableTypes, CLI::ignore_case));
+    }
+
+    void exec() override
+    {
+        switch (pldmBIOSTableType)
+        {
+            case PLDM_BIOS_STRING_TABLE:
+            {
+                auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+                decodeStringTable(stringTable);
+                break;
+            }
+            case PLDM_BIOS_ATTR_TABLE:
+            {
+                auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+                auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+
+                decodeAttributeTable(attrTable, stringTable);
+                break;
+            }
+            case PLDM_BIOS_ATTR_VAL_TABLE:
+            {
+                auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+                auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+                auto attrValTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
+
+                decodeAttributeValueTable(attrValTable, attrTable, stringTable);
+                break;
+            }
+        }
+    }
+
+  private:
+    pldm_bios_table_types pldmBIOSTableType;
+
     void decodeStringTable(const std::optional<Table>& stringTable)
     {
         if (!stringTable)
@@ -479,77 +588,95 @@
         for (auto tableEntry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(
                  attrValTable->data(), attrValTable->size()))
         {
-            auto attrHandle =
-                pldm_bios_table_attr_value_entry_decode_attribute_handle(
-                    tableEntry);
-            auto attrType = static_cast<pldm_bios_attribute_type>(
-                pldm_bios_table_attr_value_entry_decode_attribute_type(
-                    tableEntry));
-            std::cout << "AttributeHandle: " << attrHandle << std::endl;
-            std::cout << "\tAttributeType: " << attrTypeMap.at(attrType)
-                      << std::endl;
-            switch (attrType)
-            {
-                case PLDM_BIOS_ENUMERATION:
-                case PLDM_BIOS_ENUMERATION_READ_ONLY:
-                {
-
-                    auto count =
-                        pldm_bios_table_attr_value_entry_enum_decode_number(
-                            tableEntry);
-                    std::vector<uint8_t> handles(count);
-                    pldm_bios_table_attr_value_entry_enum_decode_handles(
-                        tableEntry, handles.data(), handles.size());
-                    std::cout << "\tNumberOfCurrentValues: " << (int)count
-                              << std::endl;
-                    for (size_t i = 0; i < handles.size(); i++)
-                    {
-                        std::cout
-                            << "\tCurrentValueStringHandleIndex[" << i
-                            << "] = " << (int)handles[i] << ", StringHandle = "
-                            << displayEnumValueByIndex(attrHandle, handles[i],
-                                                       attrTable, stringTable)
-                            << std::endl;
-                    }
-                    break;
-                }
-                case PLDM_BIOS_INTEGER:
-                case PLDM_BIOS_INTEGER_READ_ONLY:
-                {
-                    auto cv =
-                        pldm_bios_table_attr_value_entry_integer_decode_cv(
-                            tableEntry);
-                    std::cout << "\tCurrentValue: " << cv << std::endl;
-                    break;
-                }
-                case PLDM_BIOS_STRING:
-                case PLDM_BIOS_STRING_READ_ONLY:
-                {
-                    auto stringLength =
-                        pldm_bios_table_attr_value_entry_string_decode_length(
-                            tableEntry);
-                    variable_field currentString;
-                    pldm_bios_table_attr_value_entry_string_decode_string(
-                        tableEntry, &currentString);
-                    std::cout << "\tCurrentStringLength: " << stringLength
-                              << std::endl
-                              << "\tCurrentString: "
-                              << std::string(reinterpret_cast<const char*>(
-                                                 currentString.ptr),
-                                             currentString.length)
-                              << std::endl;
-
-                    break;
-                }
-                case PLDM_BIOS_PASSWORD:
-                case PLDM_BIOS_PASSWORD_READ_ONLY:
-                    std::cout << "Password attribute: Not Supported"
-                              << std::endl;
-            }
+            displayAttributeValueEntry(tableEntry, attrTable, stringTable);
         }
     }
 };
 
+class GetBIOSAttributeCurrentValueByHandle : public GetBIOSTableHandler
+{
+  public:
+    ~GetBIOSAttributeCurrentValueByHandle() = default;
+    GetBIOSAttributeCurrentValueByHandle(
+        const GetBIOSAttributeCurrentValueByHandle&) = delete;
+    GetBIOSAttributeCurrentValueByHandle(
+        GetBIOSAttributeCurrentValueByHandle&&) = delete;
+    GetBIOSAttributeCurrentValueByHandle&
+        operator=(const GetBIOSAttributeCurrentValueByHandle&) = delete;
+    GetBIOSAttributeCurrentValueByHandle&
+        operator=(GetBIOSAttributeCurrentValueByHandle&&) = delete;
+
+    explicit GetBIOSAttributeCurrentValueByHandle(const char* type,
+                                                  const char* name,
+                                                  CLI::App* app) :
+        GetBIOSTableHandler(type, name, app)
+    {
+        app->add_option("-a, --attribute", attrName, "pldm bios attribute name")
+            ->required();
+    }
+
+    void exec()
+    {
+        auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+        auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+
+        if (!stringTable || !attrTable)
+        {
+            std::cout << "StringTable/AttrTable Unavaliable" << std::endl;
+            return;
+        }
+
+        auto handle = findAttrHandleByName(attrName, *attrTable, *stringTable);
+
+        std::vector<uint8_t> requestMsg(
+            sizeof(pldm_msg_hdr) +
+            PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_REQ_BYTES);
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+        auto rc = encode_get_bios_attribute_current_value_by_handle_req(
+            instanceId, 0, PLDM_GET_FIRSTPART, *handle, request);
+        if (rc != PLDM_SUCCESS)
+        {
+            std::cerr << "PLDM: Request Message Error, rc =" << rc << std::endl;
+            return;
+        }
+
+        std::vector<uint8_t> responseMsg;
+        rc = pldmSendRecv(requestMsg, responseMsg);
+        if (rc != PLDM_SUCCESS)
+        {
+            std::cerr << "PLDM: Communication Error, rc =" << rc << std::endl;
+            return;
+        }
+
+        uint8_t cc = 0, transferFlag = 0;
+        uint32_t nextTransferHandle = 0;
+        struct variable_field attributeData;
+        auto responsePtr =
+            reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+        auto payloadLength = responseMsg.size() - sizeof(pldm_msg_hdr);
+
+        rc = decode_get_bios_attribute_current_value_by_handle_resp(
+            responsePtr, payloadLength, &cc, &nextTransferHandle, &transferFlag,
+            &attributeData);
+        if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)cc << std::endl;
+            return;
+        }
+
+        auto tableEntry =
+            reinterpret_cast<const struct pldm_bios_attr_val_table_entry*>(
+                attributeData.ptr);
+
+        displayAttributeValueEntry(tableEntry, attrTable, stringTable);
+    }
+
+  private:
+    std::string attrName;
+};
+
 void registerCommand(CLI::App& app)
 {
     auto bios = app.add_subcommand("bios", "bios type command");
@@ -566,6 +693,13 @@
     auto getBIOSTable = bios->add_subcommand("GetBIOSTable", "get bios table");
     commands.push_back(
         std::make_unique<GetBIOSTable>("bios", "GetBIOSTable", getBIOSTable));
+
+    auto getBIOSAttributeCurrentValueByHandle =
+        bios->add_subcommand("GetBIOSAttributeCurrentValueByHandle",
+                             "get bios attribute current value by handle");
+    commands.push_back(std::make_unique<GetBIOSAttributeCurrentValueByHandle>(
+        "bios", "GetBIOSAttributeCurrentValueByHandle",
+        getBIOSAttributeCurrentValueByHandle));
 }
 
 } // namespace bios