Re-factor to use MRW  and Inventory interfaces

The write FRU command now figures out properties to be written for a FRU
via a generated header file, which in turn is generated via scrips
deriving their inputs from MRW and Inventory d-bus interfaces.

Change-Id: I9939aeec24566cf518f4e63dc6ae344b236a541f
Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
diff --git a/frup.cpp b/frup.cpp
index 1740f10..45d052b 100644
--- a/frup.cpp
+++ b/frup.cpp
@@ -46,9 +46,7 @@
 #include <time.h>
 #include <systemd/sd-bus.h>
 #include <ctype.h>
-
-#define uint8_t unsigned char
-#define uint32_t unsigned int
+#include "frup.h"
 
 #define TEXTSTR(a) #a
 # define ASSERT(x) \
@@ -110,61 +108,6 @@
     uint8_t multirec;
 } __attribute__((packed)) ipmi_fru_common_hdr_t;
 
-enum openbmc_vpd_key_id
-{
-  OPENBMC_VPD_KEY_CHASSIS_TYPE = 1, /* not a type/len */
-  OPENBMC_VPD_KEY_CHASSIS_PART_NUM,
-  OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,
-  OPENBMC_VPD_KEY_CHASSIS_CUSTOM1,
-  OPENBMC_VPD_KEY_CHASSIS_CUSTOM2,
-  OPENBMC_VPD_KEY_CHASSIS_CUSTOM3,
-  OPENBMC_VPD_KEY_CHASSIS_CUSTOM4,
-  OPENBMC_VPD_KEY_CHASSIS_CUSTOM5,
-  OPENBMC_VPD_KEY_CHASSIS_CUSTOM6,
-  OPENBMC_VPD_KEY_CHASSIS_CUSTOM7,
-  OPENBMC_VPD_KEY_CHASSIS_CUSTOM8,
-  OPENBMC_VPD_KEY_CHASSIS_MAX = OPENBMC_VPD_KEY_CHASSIS_CUSTOM8,
-  /* TODO: chassis_custom_fields */
-
-  OPENBMC_VPD_KEY_BOARD_MFG_DATE, /* not a type/len */
-  OPENBMC_VPD_KEY_BOARD_MFR,
-  OPENBMC_VPD_KEY_BOARD_NAME,
-  OPENBMC_VPD_KEY_BOARD_SERIAL_NUM,
-  OPENBMC_VPD_KEY_BOARD_PART_NUM,
-  OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID,
-  OPENBMC_VPD_KEY_BOARD_CUSTOM1,
-  OPENBMC_VPD_KEY_BOARD_CUSTOM2,
-  OPENBMC_VPD_KEY_BOARD_CUSTOM3,
-  OPENBMC_VPD_KEY_BOARD_CUSTOM4,
-  OPENBMC_VPD_KEY_BOARD_CUSTOM5,
-  OPENBMC_VPD_KEY_BOARD_CUSTOM6,
-  OPENBMC_VPD_KEY_BOARD_CUSTOM7,
-  OPENBMC_VPD_KEY_BOARD_CUSTOM8,
-  OPENBMC_VPD_KEY_BOARD_MAX = OPENBMC_VPD_KEY_BOARD_CUSTOM8,
-  /* TODO: board_custom_fields */
-
-  OPENBMC_VPD_KEY_PRODUCT_MFR,
-  OPENBMC_VPD_KEY_PRODUCT_NAME,
-  OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM,
-  OPENBMC_VPD_KEY_PRODUCT_VER,
-  OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM,
-  OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG,
-  OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID,
-  OPENBMC_VPD_KEY_PRODUCT_CUSTOM1,
-  OPENBMC_VPD_KEY_PRODUCT_CUSTOM2,
-  OPENBMC_VPD_KEY_PRODUCT_CUSTOM3,
-  OPENBMC_VPD_KEY_PRODUCT_CUSTOM4,
-  OPENBMC_VPD_KEY_PRODUCT_CUSTOM5,
-  OPENBMC_VPD_KEY_PRODUCT_CUSTOM6,
-  OPENBMC_VPD_KEY_PRODUCT_CUSTOM7,
-  OPENBMC_VPD_KEY_PRODUCT_CUSTOM8,
-  OPENBMC_VPD_KEY_PRODUCT_MAX = OPENBMC_VPD_KEY_PRODUCT_CUSTOM8,
-
-  OPENBMC_VPD_KEY_MAX,
-  OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX=8,
-
-};
-
 const char* vpd_key_names [] =
 {
   "Key Names Table Start",
@@ -791,7 +734,7 @@
     char *bin_in_ascii = (char *)malloc(bin_in_ascii_len);
 
     /* For reading byte from the area */
-    size_t val = 0;
+    int val = 0;
 
     char *bin_copy = &((char *)bin_in_ascii)[2];
 
@@ -986,11 +929,11 @@
   return (rv);
 }
 
-int parse_fru_area (const uint8_t area, const void* msgbuf, const size_t len, sd_bus_message* vpdtbl)
+int parse_fru_area (const uint8_t area, const void* msgbuf,
+                    const size_t len, IPMIFruInfo& info)
 {
   int rv = -1;
   int i = 0;
-  int sdr = 0;
 
   /* Chassis */
   uint8_t chassis_type;
@@ -1008,7 +951,6 @@
   //uint8_t* hdr = NULL;
 
   ASSERT (msgbuf);
-  ASSERT (vpdtbl);
 
   for (i=0; i<OPENBMC_VPD_KEY_MAX; i++)
   {
@@ -1038,15 +980,14 @@
 #if IPMI_FRU_PARSER_DEBUG
                 printf ("Chassis : Appending [%s] = [%d]\n", vpd_key_names[i], chassis_type);
 #endif
-                sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "y", chassis_type);
+                info[i] = std::make_pair(vpd_key_names[i],
+                                         std::to_string(chassis_type));
                 continue;
             }
+            info[i] = std::make_pair(vpd_key_names[i],
+                      std::string(reinterpret_cast<char*>
+                                 (vpd_info[i].type_length_field)));
 
-            _append_to_dict (i, vpd_info[i].type_length_field, vpdtbl);
-/*
-            ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
-            sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
-*/
           }
         break;
     case IPMI_FRU_AREA_BOARD_INFO:
@@ -1074,21 +1015,14 @@
 #if IPMI_FRU_PARSER_DEBUG
                     printf ("Board : Appending [%s] = [%d]\n", vpd_key_names[i], timestr);
 #endif
-                    sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", timestr);
-                    if (sdr < 0)
-                    {
-#if IPMI_FRU_PARSER_DEBUG
-                        printf ("ipmi_fru_board_info_area : sd_bus_message_append Failed [ %d ] for [%s]\n", sdr, vpd_key_names[i]);
-#endif
-                    }
+                    info[i] = std::make_pair(vpd_key_names[i],
+                                             std::string(timestr));
                     continue;
                 }
+                info[i] = std::make_pair(vpd_key_names[i],
+                          std::string(reinterpret_cast<char*>
+                                     (vpd_info[i].type_length_field)));
 
-                _append_to_dict (i, vpd_info[i].type_length_field, vpdtbl);
-/*
-                ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
-                sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
-*/
             }
             break;
     case IPMI_FRU_AREA_PRODUCT_INFO:
@@ -1110,7 +1044,9 @@
 
             for (i=OPENBMC_VPD_KEY_PRODUCT_MFR; i<=OPENBMC_VPD_KEY_PRODUCT_MAX; i++)
             {
-                _append_to_dict (i, vpd_info[i].type_length_field, vpdtbl);
+                info[i] = std::make_pair(vpd_key_names[i],
+                          std::string(reinterpret_cast<char*>
+                                     (vpd_info[i].type_length_field)));
             }
             break;
     default:
diff --git a/frup.h b/frup.h
index 64a0562..ca5fa96 100644
--- a/frup.h
+++ b/frup.h
@@ -2,19 +2,8 @@
 #define OPENBMC_IPMI_FRU_PARSER_H
 
 #include <systemd/sd-bus.h>
+#include <array>
 
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-/* Parse an IPMI write fru data message into a dictionary containing name value pair of VPD entries.*/
-int parse_fru (const void* msgbuf, sd_bus_message* vpdtbl);
-int parse_fru_area (const uint8_t area, const void* msgbuf, const size_t len, sd_bus_message* vpdtbl);
-
-#ifdef __cplusplus
-}
-#endif
 
 enum ipmi_fru_area_type
 {
@@ -26,4 +15,70 @@
     IPMI_FRU_AREA_TYPE_MAX
 };
 
+
+enum openbmc_vpd_key_id
+{
+  OPENBMC_VPD_KEY_CHASSIS_TYPE = 1, /* not a type/len */
+  OPENBMC_VPD_KEY_CHASSIS_PART_NUM,
+  OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM1,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM2,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM3,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM4,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM5,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM6,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM7,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM8,
+  OPENBMC_VPD_KEY_CHASSIS_MAX = OPENBMC_VPD_KEY_CHASSIS_CUSTOM8,
+  /* TODO: chassis_custom_fields */
+
+  OPENBMC_VPD_KEY_BOARD_MFG_DATE, /* not a type/len */
+  OPENBMC_VPD_KEY_BOARD_MFR,
+  OPENBMC_VPD_KEY_BOARD_NAME,
+  OPENBMC_VPD_KEY_BOARD_SERIAL_NUM,
+  OPENBMC_VPD_KEY_BOARD_PART_NUM,
+  OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM1,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM2,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM3,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM4,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM5,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM6,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM7,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM8,
+  OPENBMC_VPD_KEY_BOARD_MAX = OPENBMC_VPD_KEY_BOARD_CUSTOM8,
+  /* TODO: board_custom_fields */
+
+  OPENBMC_VPD_KEY_PRODUCT_MFR,
+  OPENBMC_VPD_KEY_PRODUCT_NAME,
+  OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM,
+  OPENBMC_VPD_KEY_PRODUCT_VER,
+  OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM,
+  OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG,
+  OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM1,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM2,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM3,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM4,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM5,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM6,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM7,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM8,
+  OPENBMC_VPD_KEY_PRODUCT_MAX = OPENBMC_VPD_KEY_PRODUCT_CUSTOM8,
+
+  OPENBMC_VPD_KEY_MAX,
+  OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX=8,
+
+};
+
+using IPMIFruInfo = std::array<std::pair<std::string,std::string>,
+                           OPENBMC_VPD_KEY_MAX>;
+
+
+/* Parse an IPMI write fru data message into a dictionary containing name value pair of VPD entries.*/
+int parse_fru (const void* msgbuf, sd_bus_message* vpdtbl);
+
+int parse_fru_area (const uint8_t area, const void* msgbuf,
+                    const size_t len, IPMIFruInfo& info);
+
 #endif
diff --git a/writefrudata.cpp b/writefrudata.cpp
index 3619966..3e09bc8 100644
--- a/writefrudata.cpp
+++ b/writefrudata.cpp
@@ -14,11 +14,22 @@
 #include <mapper.h>
 #include "frup.h"
 #include "fru-area.hpp"
+#include "fru-gen.hpp"
 
 // OpenBMC System Manager dbus framework
 const char  *sys_object_name   =  "/org/openbmc/managers/System";
 const char  *sys_intf_name     =  "org.openbmc.managers.System";
 
+extern const FruMap frus;
+
+// Association between interface and the dbus property
+using InterfaceList = std::map<std::string,
+                               std::map<std::string, std::string>>;
+
+// Association between property and its value
+using PropertiesList = std::map<std::string, std::string>;
+
+
 //----------------------------------------------------------------
 // Constructor
 //----------------------------------------------------------------
@@ -343,98 +354,145 @@
 }
 
 //------------------------------------------------------------------------
+// Gets the value of the key from the fru dictionary of the given section.
+// FRU dictionary is parsed fru data for all the sections.
+//------------------------------------------------------------------------
+
+std::string getFRUValue(const std::string& section,
+                        const std::string& key,
+                        IPMIFruInfo& fruData)
+{
+
+    auto minIndexValue = 0;
+    auto maxIndexValue = 0;
+    std::string fruValue = "";
+    if (section == "Board")
+    {
+        minIndexValue = OPENBMC_VPD_KEY_BOARD_MFG_DATE;
+        maxIndexValue = OPENBMC_VPD_KEY_BOARD_MAX;
+    }
+    else if (section == "Product")
+    {
+        minIndexValue = OPENBMC_VPD_KEY_PRODUCT_MFR;
+        maxIndexValue = OPENBMC_VPD_KEY_PRODUCT_MAX;
+
+    }
+    else if (section == "Chassis")
+    {
+        minIndexValue = OPENBMC_VPD_KEY_CHASSIS_TYPE;
+        maxIndexValue = OPENBMC_VPD_KEY_CHASSIS_MAX;
+    }
+
+    auto first = fruData.cbegin() + minIndexValue;
+    auto last = first + (maxIndexValue - minIndexValue) + 1;
+
+    auto itr = std::find_if(first, last,
+            [&key](auto& e){ return key == e.first; });
+
+    if (itr != last)
+    {
+        fruValue = itr->second;
+    }
+    return fruValue;
+
+}
+
+// TODO: Remove once the call to inventory manager is added
+auto print = [](const InterfaceList& object, const std::string& path)
+{
+    std::cout << "\n";
+    std::cout << path << "\n";
+    std::cout << "\n";
+    for(const auto& o : object)
+    {
+        std::cout << o.first << "\n";
+        for(const auto& i : o.second)
+        {
+            std::cout << i.first << " : " << i.second << "\n";
+        }
+        std::cout << "\n";
+    }
+};
+
+//------------------------------------------------------------------------
 // Takes FRU data, invokes Parser for each fru record area and updates
 // Inventory
 //------------------------------------------------------------------------
-int ipmi_update_inventory(fru_area_vec_t & area_vec)
+int ipmi_update_inventory(fru_area_vec_t& area_vec)
 {
     // Generic error reporter
     int rc = 0;
-
-    // Dictionary object to hold Name:Value pair
-    sd_bus_message *fru_dict = NULL;
-
-    // SD Bus error report mechanism.
-    sd_bus_error bus_error = SD_BUS_ERROR_NULL;
-
-    // Response from sd bus calls
-    sd_bus_message *response = NULL;
+    uint8_t fruid = 0;
+    IPMIFruInfo fruData;
 
     // For each FRU area, extract the needed data , get it parsed and update
     // the Inventory.
-    for(auto& iter : area_vec)
+    for (const auto& fruArea : area_vec)
     {
-        // Start fresh on each.
-        sd_bus_error_free(&bus_error);
-        sd_bus_message_unref(response);
-        sd_bus_message_unref(fru_dict);
-
-        // Constructor to allow further initializations and customization.
-        rc = sd_bus_message_new_method_call((iter)->get_bus_type(),
-                                            &fru_dict,
-                                            (iter)->get_bus_name(),
-                                            (iter)->get_obj_path(),
-                                            (iter)->get_intf_name(),
-                                            "update");
-        if(rc < 0)
-        {
-            fprintf(stderr,"ERROR: creating a update method call for bus_name:[%s]\n",
-                    (iter)->get_bus_name());
-            break;
-        }
-
-        // A Dictionary ({}) having (string, variant)
-        rc = sd_bus_message_open_container(fru_dict, 'a', "{sv}");
-        if(rc < 0)
-        {
-            fprintf(stderr,"ERROR:[%d] creating a dict container:\n",errno);
-            break;
-        }
-
+        fruid = fruArea->get_fruid();
         // Fill the container with information
-        rc = parse_fru_area((iter)->get_type(), (void *)(iter)->get_data(), (iter)->get_len(), fru_dict);
-        if(rc < 0)
+        rc = parse_fru_area((fruArea)->get_type(), (void*)(fruArea)->get_data(),
+                            (fruArea)->get_len(), fruData);
+        if (rc < 0)
         {
-            fprintf(stderr,"ERROR parsing FRU records\n");
-            break;
-        }
-
-        sd_bus_message_close_container(fru_dict);
-
-        // Now, Make the actual call to update the FRU inventory database with the
-        // dictionary given by FRU Parser. There is no response message expected for
-        // this.
-        rc = sd_bus_call((iter)->get_bus_type(),     // On the System Bus
-                         fru_dict,                   // With the Name:value dictionary array
-                         0,                          //
-                         &bus_error,                 // Object to return error.
-                         &response);                 // Response message if any.
-
-        if(rc < 0)
-        {
-            fprintf(stderr, "ERROR:[%s] updating FRU inventory for ID:[0x%X]\n",
-                    bus_error.message, (iter)->get_fruid());
-            break;
-        }
-        else if((iter)->is_bmc_fru())
-        {
-            // For FRUs that are accessible by HostBoot, host boot does all of
-            // these.
-            printf("SUCCESS: Updated:[%s_%d] successfully. Setting Valid bit\n",
-                    (iter)->get_name(), (iter)->get_fruid());
-
-            (iter)->set_valid(true);
-        }
-        else
-        {
-            printf("SUCCESS: Updated:[%s_%d] successfully\n",
-                        (iter)->get_name(), (iter)->get_fruid());
+            std::cerr << "ERROR parsing FRU records\n";
+            return rc;
         }
     } // END walking the vector of areas and updating
 
-    sd_bus_error_free(&bus_error);
-    sd_bus_message_unref(response);
-    sd_bus_message_unref(fru_dict);
+    // For each Fru we have the list of instances which needs to be updated.
+    // Each instance object implements certain interfaces.
+    // Each Interface is having Dbus properties.
+    // Each Dbus Property would be having metaData(eg section,VpdPropertyName).
+
+    // Here we are just printing the object,interface and the properties.
+    // which needs to be called with the new inventory manager implementation.
+    // TODO:- Call the new Inventory Manager.
+    auto iter = frus.find(fruid);
+    if (iter == frus.end())
+    {
+        std::cerr << "ERROR Unable to get the fru info for FRU=" << fruid << "\n";
+        return -1;
+    }
+    auto& instanceList = iter->second;
+
+    if (instanceList.size() <= 0)
+    {
+        std::cout << "Object List empty for this FRU=" << fruid << "\n";
+    }
+    for (auto& instance : instanceList)
+    {
+        InterfaceList interfaces;
+
+        for (auto& interfaceList : instance.second)
+        {
+            PropertiesList prop;//store all the properties
+            for (auto& properties : interfaceList.second)
+            {
+                std::string section, property, value;
+                for (auto& info : properties.second)
+                {
+                    if (info.first == "IPMIFruSection")
+                    {
+                        section = std::move(info.second);
+                    }
+                    if (info.first == "IPMIFruProperty")
+                    {
+                        property = std::move(info.second);
+                    }
+                }
+
+                if (!section.empty() && !property.empty())
+                {
+                    value = getFRUValue(section, property, fruData);
+                }
+                prop.emplace(std::move(properties.first), std::move(value));
+            }
+            interfaces.emplace(std::move(interfaceList.first), std::move(prop));
+        }
+        //TODO:- remove it later with the inventory manager call.
+        print(interfaces, instance.first);
+    }
 
     return rc;
 }