Enable dynamic presence detect of FRUs

This commit enables presence detect of FRUs at runtime.
Anytime any FRU can get attached or de-attached,
this code will detect it and will enable/disable the corresponding
output I2C pin respectively.
Right now we have only one FRU- op-panel, which is attachable or
de-attachable at runtime.

Test- Tested on Simics:
>> 2timers keep running, as part of vpd-manager-
./vpd-manager

keep checking for event occurance...
hasEventOccurred ?
keep checking for event occurance...
hasEventOccurred ?

>> changed signal at presence-pin of FRU2
keep checking for event occurance...
hasEventOccurred ?
keep checking for event occurance...
hasEventOccurred ?
Yes, togggle the gpio            <---------------------event on 2nd timer

>> Again, changed signal at presence-pin of FRU2
keep checking for event occurance...
hasEventOccurred ?
keep checking for event occurance...
hasEventOccurred ?
Yes, togggle the gpio             <---------------------event on 2nd timer

>> changed signal at presence-pin of FRU1
keep checking for event occurance...
hasEventOccurred ?
Yes, togggle the gpio             <---------------------event on 1st timer
keep checking for event occurance...
hasEventOccurred ?

>> Again changed signal at presence-pin of FRU1
keep checking for event occurance...
hasEventOccurred ?
Yes, togggle the gpio             <---------------------event on 1st timer
keep checking for event occurance...
hasEventOccurred ?

>> Noticed change on output gpio after every signal change.
   As of now for testing, output gpio is same for both of these FRUs-

>> Effects on i2c-
 i2cdetect -y 7
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
50: UU UU UU -- -- -- -- -- -- -- 5a -- -- -- -- --
60: UU UU UU -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- UU --

 i2cdetect -y 7
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
50: UU 51 UU -- -- -- -- -- -- -- 5a -- -- -- -- --
60: UU UU UU -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- UU --

Also tested for write functionality, shouldn't be affected due to this change
It looks fine.
root@p10bmc:~# busctl introspect  xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard |grep PN
.PN                                                  property  ay        7 48 50 87 71 54 55 56                   emits-change writable

root@p10bmc:~# busctl call com.ibm.VPD.Manager /com/ibm/VPD/Manager com.ibm.VPD.Manager WriteKeyword ossay  "/system/chassis/motherboard" "VINI" "PN" 1 80

root@p10bmc:~# busctl introspect  xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard |grep PN
.PN                                                  property  ay        7 80 50 87 71 54 55 56                   emits-change writable

root@p10bmc:~# busctl call com.ibm.VPD.Manager /com/ibm/VPD/Manager com.ibm.VPD.Manager WriteKeyword ossay  "/system/chassis/motherboard" "VINI" "PN" 1 48

root@p10bmc:~# busctl introspect  xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard |grep PN
.PN                                                  property  ay        7 48 50 87 71 54 55 56                   emits-change writable

Change-Id: If7d311d36bf56ece751afe393a9ba2d83be5df11
Signed-off-by: Alpana Kumari <alpankum@in.ibm.com>
diff --git a/vpd-manager/gpioMonitor.cpp b/vpd-manager/gpioMonitor.cpp
new file mode 100644
index 0000000..b57d52c
--- /dev/null
+++ b/vpd-manager/gpioMonitor.cpp
@@ -0,0 +1,173 @@
+#include "gpioMonitor.hpp"
+
+#include "common_utility.hpp"
+#include "ibm_vpd_utils.hpp"
+
+#include <systemd/sd-event.h>
+
+#include <chrono>
+#include <gpiod.hpp>
+#include <sdeventplus/clock.hpp>
+#include <sdeventplus/utility/timer.hpp>
+
+using namespace std;
+using namespace openpower::vpd::constants;
+using sdeventplus::ClockId;
+using sdeventplus::Event;
+using Timer = sdeventplus::utility::Timer<ClockId::Monotonic>;
+using namespace std::chrono_literals;
+
+namespace openpower
+{
+namespace vpd
+{
+namespace manager
+{
+
+bool GpioEventHandler::getPresencePinValue()
+{
+    Byte gpioData = 1;
+    gpiod::line presenceLine = gpiod::find_line(presencePin);
+    if (!presenceLine)
+    {
+        cerr << "Error getPresencePinValue: couldn't find presence line:"
+             << presencePin << " on GPIO \n";
+        // return previous state as we couldn't read current state
+        return prevPresPinValue;
+    }
+
+    presenceLine.request(
+        {"Op-panel presence line", gpiod::line_request::DIRECTION_INPUT, 0});
+
+    gpioData = presenceLine.get_value();
+
+    return gpioData;
+}
+
+void GpioMonitor::initGpioInfos(Event& event)
+{
+    Byte outputValue = 0;
+    Byte presenceValue = 0;
+    string presencePinName{}, outputPinName{};
+    string devNameAddr{}, driverType{}, busType{}, objectPath{};
+
+    for (const auto& eachFRU : jsonFile["frus"].items())
+    {
+        for (const auto& eachInventory : eachFRU.value())
+        {
+            objectPath = eachInventory["inventoryPath"];
+
+            if ((eachInventory.find("presence") != eachInventory.end()) &&
+                (eachInventory.find("preAction") != eachInventory.end()))
+            {
+                for (const auto& presStatus : eachInventory["presence"].items())
+                {
+                    if (presStatus.key() == "pin")
+                    {
+                        presencePinName = presStatus.value();
+                    }
+                    else if (presStatus.key() == "value")
+                    {
+                        presenceValue = presStatus.value();
+                    }
+                }
+
+                // Based on presence pin value, preAction pin will be set/reset
+                // This action will be taken before vpd collection.
+                for (const auto& preAction : eachInventory["preAction"].items())
+                {
+                    if (preAction.key() == "pin")
+                    {
+                        outputPinName = preAction.value();
+                    }
+                    else if (preAction.key() == "value")
+                    {
+                        outputValue = preAction.value();
+                    }
+                }
+
+                devNameAddr = eachInventory["devAddress"];
+                driverType = eachInventory["driverType"];
+                busType = eachInventory["busType"];
+
+                // Init all Gpio info variables
+                std::shared_ptr<GpioEventHandler> gpioObj =
+                    make_shared<GpioEventHandler>(
+                        presencePinName, presenceValue, outputPinName,
+                        outputValue, devNameAddr, driverType, busType,
+                        objectPath, event);
+
+                gpioObjects.push_back(gpioObj);
+            }
+        }
+    }
+}
+
+void GpioEventHandler::toggleGpio()
+{
+    bool presPinVal = getPresencePinValue();
+    bool isPresent = false;
+
+    // preserve the new value
+    prevPresPinValue = presPinVal;
+
+    if (presPinVal == presenceValue)
+    {
+        isPresent = true;
+    }
+
+    // if FRU went away set the present property to false
+    if (!isPresent)
+    {
+        inventory::ObjectMap objects;
+        inventory::InterfaceMap interfaces;
+        inventory::PropertyMap presProp;
+
+        presProp.emplace("Present", false);
+        interfaces.emplace("xyz.openbmc_project.Inventory.Item", presProp);
+        objects.emplace(objectPath, move(interfaces));
+
+        common::utility::callPIM(move(objects));
+    }
+
+    gpiod::line outputLine = gpiod::find_line(outputPin);
+    if (!outputLine)
+    {
+        cerr << "Error: toggleGpio: couldn't find output line:" << outputPin
+             << ". Skipping update\n";
+
+        return;
+    }
+
+    outputLine.request({"FRU presence: update the output GPIO pin",
+                        gpiod::line_request::DIRECTION_OUTPUT, 0},
+                       isPresent ? outputValue : (!outputValue));
+
+    string cmnd = createBindUnbindDriverCmnd(devNameAddr, busType, driverType,
+                                             isPresent ? "bind" : "unbind");
+
+    cout << cmnd << endl;
+    executeCmd(cmnd);
+}
+
+void GpioEventHandler::doEventAndTimerSetup(sdeventplus::Event& event)
+{
+    prevPresPinValue = getPresencePinValue();
+
+    static vector<shared_ptr<Timer>> timers;
+    shared_ptr<Timer> timer = make_shared<Timer>(
+        event,
+        [this](Timer&) {
+            if (hasEventOccurred())
+            {
+                toggleGpio();
+            }
+        },
+        std::chrono::seconds{5s});
+
+    timers.push_back(timer);
+}
+
+} // namespace manager
+} // namespace vpd
+} // namespace openpower
\ No newline at end of file