Only create buttons when their GPIOs are defined

Look in /etc/default/obmc/gpio/gpio_defs.json to see
if the GPIO for a button is defined, and only create
the button object if it is.

This is how a system implementer can specify which
button objects are needed for their particular system.

Change-Id: I359f87875b6bb5741fdf4718b30b0f5b4552a528
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/inc/gpio.hpp b/inc/gpio.hpp
index 98df21b..ca83082 100644
--- a/inc/gpio.hpp
+++ b/inc/gpio.hpp
@@ -19,3 +19,10 @@
 
 int configGpio(const char* gpioName, int* fd, sdbusplus::bus::bus& bus);
 void closeGpio(int fd);
+bool gpioDefined(const std::string& gpioName);
+
+template <typename T>
+bool hasGpio()
+{
+    return gpioDefined(T::getGpioName());
+}
diff --git a/inc/id_button.hpp b/inc/id_button.hpp
index a5c4180..af100ef 100644
--- a/inc/id_button.hpp
+++ b/inc/id_button.hpp
@@ -70,6 +70,11 @@
 
     void simPress() override;
 
+    static const char* getGpioName()
+    {
+        return ID_BUTTON;
+    }
+
     static int EventHandler(sd_event_source* es, int fd, uint32_t revents,
                             void* userdata)
     {
diff --git a/inc/power_button.hpp b/inc/power_button.hpp
index d00f1c6..e4cc660 100644
--- a/inc/power_button.hpp
+++ b/inc/power_button.hpp
@@ -71,6 +71,11 @@
     void simPress() override;
     void simLongPress() override;
 
+    static const char* getGpioName()
+    {
+        return POWER_BUTTON;
+    }
+
     static int EventHandler(sd_event_source* es, int fd, uint32_t revents,
                             void* userdata)
     {
diff --git a/inc/reset_button.hpp b/inc/reset_button.hpp
index b10f241..d0534e8 100644
--- a/inc/reset_button.hpp
+++ b/inc/reset_button.hpp
@@ -70,6 +70,11 @@
 
     void simPress() override;
 
+    static const char* getGpioName()
+    {
+        return RESET_BUTTON;
+    }
+
     static int EventHandler(sd_event_source* es, int fd, uint32_t revents,
                             void* userdata)
     {
diff --git a/src/gpio.cpp b/src/gpio.cpp
index b78d2bc..27fc74d 100644
--- a/src/gpio.cpp
+++ b/src/gpio.cpp
@@ -21,13 +21,19 @@
 
 #include <experimental/filesystem>
 #include <fstream>
+#include <nlohmann/json.hpp>
 #include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
 #include <xyz/openbmc_project/Common/error.hpp>
 
 const static constexpr char* SYSMGR_SERVICE = "org.openbmc.managers.System";
 const static constexpr char* SYSMGR_OBJ_PATH = "/org/openbmc/managers/System";
 const static constexpr char* SYSMGR_INTERFACE = "org.openbmc.managers.System";
 
+static constexpr auto gpioDefs = "/etc/default/obmc/gpio/gpio_defs.json";
+
+using namespace phosphor::logging;
+
 void closeGpio(int fd)
 {
     if (fd > 0)
@@ -36,6 +42,32 @@
     }
 }
 
+bool gpioDefined(const std::string& gpioName)
+{
+    try
+    {
+        std::ifstream gpios{gpioDefs};
+        auto json = nlohmann::json::parse(gpios, nullptr, true);
+        auto defs = json["gpio_definitions"];
+
+        auto gpio =
+            std::find_if(defs.begin(), defs.end(), [&gpioName](const auto g) {
+                return gpioName == g["name"];
+            });
+
+        if (gpio != defs.end())
+        {
+            return true;
+        }
+    }
+    catch (std::exception& e)
+    {
+        log<level::ERR>("Error parsing GPIO JSON", entry("ERROR=%s", e.what()),
+                        entry("GPIO_NAME=%s", gpioName.c_str()));
+    }
+    return false;
+}
+
 int configGpio(const char* gpioName, int* fd, sdbusplus::bus::bus& bus)
 {
     auto method = bus.new_method_call(SYSMGR_SERVICE, SYSMGR_OBJ_PATH,
@@ -47,8 +79,7 @@
 
     if (result.is_method_error())
     {
-        phosphor::logging::log<phosphor::logging::level::ERR>(
-            "bus call error!");
+        log<level::ERR>("bus call error!");
         return -1;
     }
 
@@ -71,9 +102,7 @@
 
     if (std::experimental::filesystem::exists(fullPath))
     {
-        phosphor::logging::log<phosphor::logging::level::INFO>(
-            "GPIO exported",
-            phosphor::logging::entry("PATH=%s", devPath.c_str()));
+        log<level::INFO>("GPIO exported", entry("PATH=%s", devPath.c_str()));
     }
     else
     {
@@ -89,10 +118,9 @@
 
         catch (const std::exception& e)
         {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "Error in writing!",
-                phosphor::logging::entry("PATH=%s", devPath.c_str()),
-                phosphor::logging::entry("NUM=%d", gpioNum));
+            log<level::ERR>("Error in writing!",
+                            entry("PATH=%s", devPath.c_str()),
+                            entry("NUM=%d", gpioNum));
             return -1;
         }
     }
@@ -113,9 +141,8 @@
 
         catch (const std::exception& e)
         {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "Error in reading!",
-                phosphor::logging::entry("PATH=%s", devPath.c_str()));
+            log<level::ERR>("Error in reading!",
+                            entry("PATH=%s", devPath.c_str()));
             return -1;
         }
 
@@ -133,8 +160,7 @@
 
         catch (const std::exception& e)
         {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "Error in writing!");
+            log<level::ERR>("Error in writing!");
             return -1;
         }
     }
@@ -152,8 +178,7 @@
 
         catch (const std::exception& e)
         {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "Error in writing!");
+            log<level::ERR>("Error in writing!");
             return -1;
         }
     }
@@ -174,8 +199,7 @@
 
         catch (const std::exception& e)
         {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "Error in writing!");
+            log<level::ERR>("Error in writing!");
             return -1;
         }
     }
@@ -187,7 +211,7 @@
 
     if (*fd < 0)
     {
-        phosphor::logging::log<phosphor::logging::level::ERR>("open error!");
+        log<level::ERR>("open error!");
         return -1;
     }
 
diff --git a/src/main.cpp b/src/main.cpp
index 6107949..eb96b13 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -42,11 +42,23 @@
 
     bus.request_name("xyz.openbmc_project.Chassis.Buttons");
 
-    PowerButton powerButton{bus, POWER_DBUS_OBJECT_NAME, eventP};
+    std::unique_ptr<PowerButton> pb;
+    if (hasGpio<PowerButton>())
+    {
+        pb = std::make_unique<PowerButton>(bus, POWER_DBUS_OBJECT_NAME, eventP);
+    }
 
-    ResetButton resetButton{bus, RESET_DBUS_OBJECT_NAME, eventP};
+    std::unique_ptr<ResetButton> rb;
+    if (hasGpio<ResetButton>())
+    {
+        rb = std::make_unique<ResetButton>(bus, RESET_DBUS_OBJECT_NAME, eventP);
+    }
 
-    IDButton idButton{bus, ID_DBUS_OBJECT_NAME, eventP};
+    std::unique_ptr<IDButton> ib;
+    if (hasGpio<IDButton>())
+    {
+        ib = std::make_unique<IDButton>(bus, ID_DBUS_OBJECT_NAME, eventP);
+    }
 
     try
     {