convert sysfs gpio usage to libgpiod

Updated Fan presence sensor monitoring call back
to use pin name and gpiod APIs. Number based sysfs
framework is deprecated and replaced by descriptor
based gpiod framework. With named gpio pin,
code is more portable provided the device tree
defines GPIO pin name consistently.

This requires device tree change (225598) and
configuration file change (entity-manager/+/28119)

Tested By:
remove and insert fans and observe fan presence
status change on dbus fan sensor objects

Signed-off-by: Zhikui Ren <zhikui.ren@intel.com>
Change-Id: Ice17a472285373ce866132ccc0da02cd1e70ddbe
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 83c9a76..a28c613 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -165,6 +165,7 @@
 add_executable (fansensor src/FanMain.cpp ${FAN_SRC_FILES})
 add_dependencies (fansensor sdbusplus-project)
 target_link_libraries (fansensor ${SENSOR_LINK_LIBS})
+target_link_libraries (fansensor gpiodcxx)
 
 add_executable (hwmontempsensor src/HwmonTempMain.cpp ${HWMON_TEMP_SRC_FILES})
 add_dependencies (hwmontempsensor sdbusplus-project)
diff --git a/include/TachSensor.hpp b/include/TachSensor.hpp
index c7c1b0e..9ae04e1 100644
--- a/include/TachSensor.hpp
+++ b/include/TachSensor.hpp
@@ -1,5 +1,4 @@
 #pragma once
-
 #include "Thresholds.hpp"
 #include "sensor.hpp"
 
@@ -7,6 +6,7 @@
 
 #include <boost/container/flat_map.hpp>
 #include <boost/container/flat_set.hpp>
+#include <gpiod.hpp>
 #include <memory>
 #include <optional>
 #include <sdbusplus/asio/object_server.hpp>
@@ -17,7 +17,7 @@
 class PresenceSensor
 {
   public:
-    PresenceSensor(const size_t index, bool inverted,
+    PresenceSensor(const std::string& pinName, bool inverted,
                    boost::asio::io_service& io, const std::string& name);
     ~PresenceSensor();
 
@@ -28,8 +28,8 @@
   private:
     bool status = true;
     bool inverted;
-    boost::asio::ip::tcp::socket inputDev;
-    int fd;
+    gpiod::line gpioLine;
+    boost::asio::posix::stream_descriptor gpioFd;
     std::string name;
 };
 
diff --git a/src/FanMain.cpp b/src/FanMain.cpp
index fdd0295..3a3175f 100644
--- a/src/FanMain.cpp
+++ b/src/FanMain.cpp
@@ -159,6 +159,7 @@
                     {
                         continue;
                     }
+
                     auto findIndex = baseConfiguration->second.find("Index");
                     if (findIndex == baseConfiguration->second.end())
                     {
@@ -214,6 +215,7 @@
                 }
 
                 auto findSensorName = baseConfiguration->second.find("Name");
+
                 if (findSensorName == baseConfiguration->second.end())
                 {
                     std::cerr << "could not determine configuration name for "
@@ -222,6 +224,7 @@
                 }
                 std::string sensorName =
                     std::get<std::string>(findSensorName->second);
+
                 // on rescans, only update sensors we were signaled by
                 auto findSensor = tachSensors.find(sensorName);
                 if (!firstScan && findSensor != tachSensors.end())
@@ -258,21 +261,30 @@
                 // presence sensors are optional
                 if (presenceConfig != sensorData->end())
                 {
-                    auto findIndex = presenceConfig->second.find("Index");
                     auto findPolarity = presenceConfig->second.find("Polarity");
+                    auto findPinName = presenceConfig->second.find("PinName");
 
-                    if (findIndex == presenceConfig->second.end() ||
+                    if (findPinName == presenceConfig->second.end() ||
                         findPolarity == presenceConfig->second.end())
                     {
                         std::cerr << "Malformed Presence Configuration\n";
                     }
                     else
                     {
-                        size_t index = std::get<uint64_t>(findIndex->second);
                         bool inverted = std::get<std::string>(
                                             findPolarity->second) == "Low";
-                        presenceSensor = std::make_unique<PresenceSensor>(
-                            index, inverted, io, sensorName);
+                        if (auto pinName =
+                                std::get_if<std::string>(&findPinName->second))
+                        {
+                            presenceSensor = std::make_unique<PresenceSensor>(
+                                *pinName, inverted, io, sensorName);
+                        }
+                        else
+                        {
+                            std::cerr
+                                << "Malformed Presence pinName for sensor "
+                                << sensorName << " \n";
+                        }
                     }
                 }
                 std::optional<RedundancySensor>* redundancy = nullptr;
diff --git a/src/TachSensor.cpp b/src/TachSensor.cpp
index 91a08c1..cc9d37d 100644
--- a/src/TachSensor.cpp
+++ b/src/TachSensor.cpp
@@ -24,6 +24,7 @@
 #include <boost/algorithm/string/replace.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <fstream>
+#include <gpiod.hpp>
 #include <iostream>
 #include <istream>
 #include <limits>
@@ -217,92 +218,84 @@
     }
 }
 
-PresenceSensor::PresenceSensor(const size_t index, bool inverted,
+PresenceSensor::PresenceSensor(const std::string& gpioName, bool inverted,
                                boost::asio::io_service& io,
                                const std::string& name) :
     inverted(inverted),
-    inputDev(io), name(name)
+    gpioLine(gpiod::find_line(gpioName)), gpioFd(io), name(name)
 {
-    // todo: use gpiodaemon
-    std::string device = gpioPath + std::string("gpio") + std::to_string(index);
-    fd = open((device + "/value").c_str(), O_RDONLY);
-    if (fd < 0)
+    if (!gpioLine)
     {
-        std::cerr << "Error opening gpio " << index << "\n";
+        std::cerr << "Error requesting gpio: " << gpioName << "\n";
+        status = false;
         return;
     }
 
-    std::ofstream deviceFile(device + "/edge");
-    if (!deviceFile.good())
+    try
     {
-        std::cerr << "Error setting edge " << device << "\n";
+        gpioLine.request({"FanSensor", gpiod::line_request::EVENT_BOTH_EDGES,
+                          inverted ? gpiod::line_request::FLAG_ACTIVE_LOW : 0});
+        status = gpioLine.get_value();
+
+        int gpioLineFd = gpioLine.event_get_fd();
+        if (gpioLineFd < 0)
+        {
+            std::cerr << "Failed to get " << gpioName << " fd\n";
+            return;
+        }
+
+        gpioFd.assign(gpioLineFd);
+    }
+    catch (std::system_error&)
+    {
+        std::cerr << "Error reading gpio: " << gpioName << "\n";
+        status = false;
         return;
     }
-    deviceFile << "both";
-    deviceFile.close();
 
-    inputDev.assign(boost::asio::ip::tcp::v4(), fd);
     monitorPresence();
-    read();
 }
 
 PresenceSensor::~PresenceSensor()
 {
-    inputDev.close();
-    close(fd);
+    gpioFd.close();
+    gpioLine.release();
 }
 
 void PresenceSensor::monitorPresence(void)
 {
-    inputDev.async_wait(boost::asio::ip::tcp::socket::wait_error,
-                        [this](const boost::system::error_code& ec) {
-                            if (ec == boost::system::errc::bad_file_descriptor)
-                            {
-                                return; // we're being destroyed
-                            }
-                            else if (ec)
-                            {
-                                std::cerr
-                                    << "Error on presence sensor socket\n";
-                            }
-                            else
-                            {
-                                read();
-                            }
-                            monitorPresence();
-                        });
+    gpioFd.async_wait(boost::asio::posix::stream_descriptor::wait_read,
+                      [this](const boost::system::error_code& ec) {
+                          if (ec == boost::system::errc::bad_file_descriptor)
+                          {
+                              return; // we're being destroyed
+                          }
+                          else if (ec)
+                          {
+                              std::cerr << "Error on presence sensor " << name
+                                        << " \n";
+                              ;
+                          }
+                          else
+                          {
+                              read();
+                          }
+                          monitorPresence();
+                      });
 }
 
 void PresenceSensor::read(void)
 {
-    constexpr size_t readSize = sizeof("0");
-    std::string readBuf;
-    readBuf.resize(readSize);
-    lseek(fd, 0, SEEK_SET);
-    size_t r = ::read(fd, readBuf.data(), readSize);
-    if (r != readSize)
+    gpioLine.event_read();
+    status = gpioLine.get_value();
+    // Read is invoked when an edge event is detected by monitorPresence
+    if (status)
     {
-        std::cerr << "Error reading gpio\n";
+        logFanInserted(name);
     }
     else
     {
-        bool value = std::stoi(readBuf);
-        if (inverted)
-        {
-            value = !value;
-        }
-        if (value != status)
-        {
-            status = value;
-            if (status)
-            {
-                logFanInserted(name);
-            }
-            else
-            {
-                logFanRemoved(name);
-            }
-        }
+        logFanRemoved(name);
     }
 }