PCIe: Implement "PcieType" PCIe device property

This commit publishes PCIe device property "PcieType" which
defined in the Redfish PCIeDevice schema.

New property:
PCIeType   : The PCIe interface generation in use by the device.

Dbus interfaces dependency PR:
https://gerrit.openbmc-project.xyz/c/openbmc/phosphor-dbus-interfaces/+/46437

Peci-pcie dependency PR:
https://gerrit.openbmc-project.xyz/c/openbmc/peci-pcie/+/46438

Sample output:

/redfish/v1/Systems/systemPCIeDevices/S0B1D0/
{
  "@odata.id": "/redfish/v1/Systems/system/PCIeDevices/S0B1D0",
  "@odata.type": "#PCIeDevice.v1_4_0.PCIeDevice",
  "DeviceType": "SingleFunction",
  "Id": "S0B1D0",
  "Manufacturer": "PLDA",
  "Name": "PCIe Device",
  "PCIeFunctions": {
    "@odata.id": "/redfish/v1/Systems/system/PCIeDevices/S0B1D0/PCIeFunctions"
  },
  "PCIeInterface": {
    "PcieType": "Gen2"
  }
}

Signed-off-by: Spencer Ku <Spencer.Ku@quantatw.com>
Signed-off-by: Ed Tanous <edtanous@google.com>
Change-Id: I550a9ca8a266cf1d2e1bff5b6a03656a3f1f0281
diff --git a/redfish-core/lib/pcie.hpp b/redfish-core/lib/pcie.hpp
index e534434..1872c02 100644
--- a/redfish-core/lib/pcie.hpp
+++ b/redfish-core/lib/pcie.hpp
@@ -94,6 +94,45 @@
             });
 }
 
+inline std::optional<std::string>
+    redfishPcieGenerationFromDbus(const std::string& generationInUse)
+{
+    if (generationInUse ==
+        "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
+    {
+        return "Gen1";
+    }
+    if (generationInUse ==
+        "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
+    {
+        return "Gen2";
+    }
+    if (generationInUse ==
+        "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
+    {
+        return "Gen3";
+    }
+    if (generationInUse ==
+        "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
+    {
+        return "Gen4";
+    }
+    if (generationInUse ==
+        "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
+    {
+        return "Gen5";
+    }
+    if (generationInUse.empty() ||
+        generationInUse ==
+            "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
+    {
+        return "";
+    }
+
+    // The value is not unknown or Gen1-5, need return an internal error.
+    return std::nullopt;
+}
+
 inline void requestRoutesSystemPCIeDevice(App& app)
 {
     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/")
@@ -150,6 +189,25 @@
                         asyncResp->res.jsonValue["DeviceType"] = *property;
                     }
 
+                    if (std::string* property = std::get_if<std::string>(
+                            &pcieDevProperties["GenerationInUse"]);
+                        property)
+                    {
+                        std::optional<std::string> generationInUse =
+                            redfishPcieGenerationFromDbus(*property);
+                        if (!generationInUse)
+                        {
+                            messages::internalError(asyncResp->res);
+                            return;
+                        }
+                        if (*generationInUse == "")
+                        {
+                            // unknown, no need to handle
+                            return;
+                        }
+                        asyncResp->res.jsonValue["PCIeInterface"]["PcieType"] =
+                            *generationInUse;
+                    }
                     asyncResp->res.jsonValue["PCIeFunctions"] = {
                         {"@odata.id",
                          "/redfish/v1/Systems/system/PCIeDevices/" + device +