bios: Implement BIOSIntegerAttribute

Implement BIOSIntegerAttribute, most of the code is copied from
bios/bios_parser.cpp.

Implement SetAttrValueOnDbus and constructEntry for integer attribute

Signed-off-by: John Wang <wangzqbj@inspur.com>
Change-Id: I57d5b5dbcb74f9a404f5133426208f4c6851dea2
diff --git a/libpldmresponder/bios_config.cpp b/libpldmresponder/bios_config.cpp
index d5c39ba..90b2ad2 100644
--- a/libpldmresponder/bios_config.cpp
+++ b/libpldmresponder/bios_config.cpp
@@ -1,5 +1,6 @@
 #include "bios_config.hpp"
 
+#include "bios_integer_attribute.hpp"
 #include "bios_string_attribute.hpp"
 
 #include <fstream>
@@ -65,6 +66,9 @@
     load(jsonDir / stringJsonFile, [this](const Json& entry) {
         constructAttribute<BIOSStringAttribute>(entry);
     });
+    load(jsonDir / stringJsonFile, [this](const Json& entry) {
+        constructAttribute<BIOSIntegerAttribute>(entry);
+    });
 }
 
 void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable)
diff --git a/libpldmresponder/bios_integer_attribute.cpp b/libpldmresponder/bios_integer_attribute.cpp
new file mode 100644
index 0000000..90667a2
--- /dev/null
+++ b/libpldmresponder/bios_integer_attribute.cpp
@@ -0,0 +1,177 @@
+#include "bios_integer_attribute.hpp"
+
+#include "utils.hpp"
+
+namespace pldm
+{
+namespace responder
+{
+namespace bios
+{
+
+BIOSIntegerAttribute::BIOSIntegerAttribute(const Json& entry,
+                                           DBusHandler* const dbusHandler) :
+    BIOSAttribute(entry, dbusHandler)
+{
+    std::string attr = entry.at("attribute_name");
+
+    integerInfo.lowerBound = entry.at("lower_bound");
+    integerInfo.upperBound = entry.at("upper_bound");
+    integerInfo.scalarIncrement = entry.at("scalar_increment");
+    integerInfo.defaultValue = entry.at("default_value");
+    pldm_bios_table_attr_entry_integer_info info = {
+        0,
+        readOnly,
+        integerInfo.lowerBound,
+        integerInfo.upperBound,
+        integerInfo.scalarIncrement,
+        integerInfo.defaultValue,
+    };
+    const char* errmsg = nullptr;
+    auto rc = pldm_bios_table_attr_entry_integer_info_check(&info, &errmsg);
+    if (rc != PLDM_SUCCESS)
+    {
+        std::cerr << "Wrong filed for integer attribute, ATTRIBUTE_NAME="
+                  << attr.c_str() << " ERRMSG=" << errmsg
+                  << " LOWER_BOUND=" << integerInfo.lowerBound
+                  << " UPPER_BOUND=" << integerInfo.upperBound
+                  << " DEFAULT_VALUE=" << integerInfo.defaultValue
+                  << " SCALAR_INCREMENT=" << integerInfo.scalarIncrement
+                  << "\n";
+        throw std::invalid_argument("Wrong field for integer attribute");
+    }
+}
+
+void BIOSIntegerAttribute::setAttrValueOnDbus(
+    const pldm_bios_attr_val_table_entry* attrValueEntry,
+    const pldm_bios_attr_table_entry*, const BIOSStringTable&)
+{
+    if (readOnly)
+    {
+        return;
+    }
+    auto currentValue =
+        table::attribute_value::decodeIntegerEntry(attrValueEntry);
+
+    if (dBusMap->propertyType == "uint8_t")
+    {
+        return dbusHandler->setDbusProperty(*dBusMap,
+                                            static_cast<uint8_t>(currentValue));
+    }
+    else if (dBusMap->propertyType == "uint16_t")
+    {
+        return dbusHandler->setDbusProperty(
+            *dBusMap, static_cast<uint16_t>(currentValue));
+    }
+    else if (dBusMap->propertyType == "int16_t")
+    {
+        return dbusHandler->setDbusProperty(*dBusMap,
+                                            static_cast<int16_t>(currentValue));
+    }
+    else if (dBusMap->propertyType == "uint32_t")
+    {
+        return dbusHandler->setDbusProperty(
+            *dBusMap, static_cast<uint32_t>(currentValue));
+    }
+    else if (dBusMap->propertyType == "int32_t")
+    {
+        return dbusHandler->setDbusProperty(*dBusMap,
+                                            static_cast<int32_t>(currentValue));
+    }
+    else if (dBusMap->propertyType == "uint64_t")
+    {
+        return dbusHandler->setDbusProperty(*dBusMap, currentValue);
+    }
+    else if (dBusMap->propertyType == "int64_t")
+    {
+        return dbusHandler->setDbusProperty(*dBusMap,
+                                            static_cast<int64_t>(currentValue));
+    }
+
+    std::cerr << "Unsupported property type on dbus: " << dBusMap->propertyType
+              << std::endl;
+    throw std::invalid_argument("dbus type error");
+}
+
+void BIOSIntegerAttribute::constructEntry(const BIOSStringTable& stringTable,
+                                          Table& attrTable,
+                                          Table& attrValueTable)
+{
+
+    pldm_bios_table_attr_entry_integer_info info = {
+        stringTable.findHandle(name), readOnly,
+        integerInfo.lowerBound,       integerInfo.upperBound,
+        integerInfo.scalarIncrement,  integerInfo.defaultValue,
+    };
+
+    auto attrTableEntry =
+        table::attribute::constructIntegerEntry(attrTable, &info);
+
+    auto [attrHandle, attrType, _] =
+        table::attribute::decodeHeader(attrTableEntry);
+
+    auto currentValue = getAttrValue();
+    table::attribute_value::constructIntegerEntry(attrValueTable, attrHandle,
+                                                  attrType, currentValue);
+}
+
+uint64_t BIOSIntegerAttribute::getAttrValue(PropertyValue propertyValue)
+{
+    uint64_t value;
+    if (dBusMap->propertyType == "uint8_t")
+    {
+        value = std::get<uint8_t>(propertyValue);
+    }
+    else if (dBusMap->propertyType == "uint16_t")
+    {
+        value = std::get<uint16_t>(propertyValue);
+    }
+    else if (dBusMap->propertyType == "int16_t")
+    {
+        value = std::get<int16_t>(propertyValue);
+    }
+    else if (dBusMap->propertyType == "uint32_t")
+    {
+        value = std::get<uint32_t>(propertyValue);
+    }
+    else if (dBusMap->propertyType == "int32_t")
+    {
+        value = std::get<int32_t>(propertyValue);
+    }
+    else if (dBusMap->propertyType == "uint64_t")
+    {
+        value = std::get<uint64_t>(propertyValue);
+    }
+    else if (dBusMap->propertyType == "int64_t")
+    {
+        value = std::get<int64_t>(propertyValue);
+    }
+    return value;
+}
+
+uint64_t BIOSIntegerAttribute::getAttrValue()
+{
+    if (readOnly)
+    {
+        return integerInfo.defaultValue;
+    }
+
+    try
+    {
+        auto propertyValue = dbusHandler->getDbusPropertyVariant(
+            dBusMap->objectPath.c_str(), dBusMap->propertyName.c_str(),
+            dBusMap->interface.c_str());
+
+        return getAttrValue(propertyValue);
+    }
+    catch (const std::exception& e)
+    {
+        std::cerr << "Get Integer Attribute Value Error: AttributeName = "
+                  << name << std::endl;
+        return integerInfo.defaultValue;
+    }
+}
+
+} // namespace bios
+} // namespace responder
+} // namespace pldm
\ No newline at end of file
diff --git a/libpldmresponder/bios_integer_attribute.hpp b/libpldmresponder/bios_integer_attribute.hpp
new file mode 100644
index 0000000..83fa53d
--- /dev/null
+++ b/libpldmresponder/bios_integer_attribute.hpp
@@ -0,0 +1,63 @@
+#pragma once
+
+#include "bios_attribute.hpp"
+
+class TestBIOSIntegerAttribute;
+
+namespace pldm
+{
+namespace responder
+{
+namespace bios
+{
+
+/** @class BIOSIntegerAttribute
+ *  @brief Associate integer entry(attr table and attribute value table) and
+ *         dbus attribute
+ */
+class BIOSIntegerAttribute : public BIOSAttribute
+{
+  public:
+    friend class ::TestBIOSIntegerAttribute;
+
+    /** @brief Construct a bios integer attribute
+     *  @param[in] entry - Json Object
+     *  @param[in] dbusHandler - Dbus Handler
+     */
+    BIOSIntegerAttribute(const Json& entry, DBusHandler* const dbusHandler);
+
+    /** @brief Set Attribute value On Dbus according to the attribute value
+     *         entry
+     *  @param[in] attrValueEntry - The attribute value entry
+     *  @param[in] attrEntry - The attribute entry corresponding to the
+     *                         attribute value entry
+     *  @param[in] stringTable - The string table
+     */
+    void
+        setAttrValueOnDbus(const pldm_bios_attr_val_table_entry* attrValueEntry,
+                           const pldm_bios_attr_table_entry* attrEntry,
+                           const BIOSStringTable& stringTable) override;
+
+    /** @brief Construct corresponding entries at the end of the attribute table
+     *         and attribute value tables
+     *  @param[in] stringTable - The string Table
+     *  @param[in,out] attrTable - The attribute table
+     *  @param[in,out] attrValueTable - The attribute value table
+     */
+    void constructEntry(const BIOSStringTable& stringTable, Table& attrTable,
+                        Table& attrValueTable) override;
+
+  private:
+    /** @brief Integer field from json */
+    table::attribute::IntegerField integerInfo;
+
+    /** @brief Get pldm value from dbus propertyValue */
+    uint64_t getAttrValue(PropertyValue value);
+
+    /** @brief Get value on dbus */
+    uint64_t getAttrValue();
+};
+
+} // namespace bios
+} // namespace responder
+} // namespace pldm
\ No newline at end of file
diff --git a/libpldmresponder/bios_table.cpp b/libpldmresponder/bios_table.cpp
index 4a190f0..67dfb0e 100644
--- a/libpldmresponder/bios_table.cpp
+++ b/libpldmresponder/bios_table.cpp
@@ -155,6 +155,19 @@
                                                          tableSize);
 }
 
+const pldm_bios_attr_table_entry*
+    constructIntegerEntry(Table& table,
+                          pldm_bios_table_attr_entry_integer_info* info)
+{
+    auto entryLength = pldm_bios_table_attr_entry_integer_encode_length();
+    auto tableSize = table.size();
+    table.resize(tableSize + entryLength, 0);
+    pldm_bios_table_attr_entry_integer_encode(table.data() + tableSize,
+                                              entryLength, info);
+    return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() +
+                                                         tableSize);
+}
+
 StringField decodeStringEntry(const pldm_bios_attr_table_entry* entry)
 {
     auto strType = pldm_bios_table_attr_entry_string_decode_string_type(entry);
@@ -170,6 +183,16 @@
             std::string(buffer.data(), buffer.data() + defLength)};
 }
 
+IntegerField decodeIntegerEntry(const pldm_bios_attr_table_entry* entry)
+{
+    uint64_t lower, upper, def;
+    uint32_t scalar;
+
+    pldm_bios_table_attr_entry_integer_decode(entry, &lower, &upper, &scalar,
+                                              &def);
+    return {lower, upper, scalar, def};
+}
+
 } // namespace attribute
 
 namespace attribute_value
@@ -192,6 +215,11 @@
                        currentString.ptr + currentString.length);
 }
 
+uint64_t decodeIntegerEntry(const pldm_bios_attr_val_table_entry* entry)
+{
+    return pldm_bios_table_attr_value_entry_integer_decode_cv(entry);
+}
+
 const pldm_bios_attr_val_table_entry*
     constructStringEntry(Table& table, uint16_t attrHandle, uint8_t attrType,
                          const std::string& str)
@@ -207,6 +235,22 @@
     return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() +
                                                              tableSize);
 }
+
+const pldm_bios_attr_val_table_entry* constructIntegerEntry(Table& table,
+                                                            uint16_t attrHandle,
+                                                            uint8_t attrType,
+                                                            uint64_t value)
+{
+    auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length();
+
+    auto tableSize = table.size();
+    table.resize(tableSize + entryLength);
+    pldm_bios_table_attr_value_entry_encode_integer(
+        table.data() + tableSize, entryLength, attrHandle, attrType, value);
+    return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() +
+                                                             tableSize);
+}
+
 std::optional<Table> updateTable(const Table& table, const void* entry,
                                  size_t size)
 {
diff --git a/libpldmresponder/bios_table.hpp b/libpldmresponder/bios_table.hpp
index 4a482db..aab6f53 100644
--- a/libpldmresponder/bios_table.hpp
+++ b/libpldmresponder/bios_table.hpp
@@ -225,6 +225,33 @@
     constructStringEntry(Table& table,
                          pldm_bios_table_attr_entry_string_info* info);
 
+/** @struct IntegerField
+ *  @brief Integer field of attribute table
+ */
+struct IntegerField
+{
+    uint64_t lowerBound;
+    uint64_t upperBound;
+    uint32_t scalarIncrement;
+    uint64_t defaultValue;
+};
+
+/** @brief construct integer entry of attribute table at the end of the
+ *         given table
+ *  @param[in,out] table - The given table
+ *  @param[in] info - integer info
+ *  @return pointer to the constructed entry
+ */
+const pldm_bios_attr_table_entry*
+    constructIntegerEntry(Table& table,
+                          pldm_bios_table_attr_entry_integer_info* info);
+
+/** @brief decode integer entry of attribute table
+ *  @param[in] entry - Pointer to an attribute table entry
+ *  @return Integer field of the entry
+ */
+IntegerField decodeIntegerEntry(const pldm_bios_attr_table_entry* entry);
+
 } // namespace attribute
 
 namespace attribute_value
@@ -251,6 +278,12 @@
  */
 std::string decodeStringEntry(const pldm_bios_attr_val_table_entry* entry);
 
+/** @brief Decode integer entry of attribute value table
+ *  @param[in] entry - Pointer to an attribute value table entry
+ *  @return The decoded integer
+ */
+uint64_t decodeIntegerEntry(const pldm_bios_attr_val_table_entry* entry);
+
 /** @brief Construct string entry of attribute value table at the end of the
  *         given table
  *  @param[in] table - The given table
@@ -263,6 +296,19 @@
     constructStringEntry(Table& table, uint16_t attrHandle, uint8_t attrType,
                          const std::string& str);
 
+/** @brief Construct integer entry of attribute value table at the end of
+ *         the given table
+ *  @param[in] table - The given table
+ *  @param[in] attrHandle - attribute handle
+ *  @param[in] attrType - attribute type
+ *  @param[in] value - The integer
+ *  @return Pointer to the constructed entry
+ */
+const pldm_bios_attr_val_table_entry* constructIntegerEntry(Table& table,
+                                                            uint16_t attrHandle,
+                                                            uint8_t attrType,
+                                                            uint64_t value);
+
 /** @brief construct a table with an new entry
  *  @param[in] table - the table need to be updated
  *  @param[in] entry - the new attribute value entry
diff --git a/libpldmresponder/meson.build b/libpldmresponder/meson.build
index 0a5bfa2..9e073eb 100644
--- a/libpldmresponder/meson.build
+++ b/libpldmresponder/meson.build
@@ -12,6 +12,7 @@
   'bios_parser.cpp',
   'bios_attribute.cpp',
   'bios_string_attribute.cpp',
+  'bios_integer_attribute.cpp',
   'bios_config.cpp',
   'pdr_utils.cpp',
   'pdr.cpp',