[ADC-GPIO]Enabling ADC-Gpio Bridge

Commit 2: bridge
In case a channel has a bridge circuit,
we have to turn the bridge on prior to reading a value at least for one scan cycle
to get a valid value.
Add support for ADC channel controlled by GPIO.
For example,ADC channel8, connected to CMOS battery, is controlled by a GPIO.
Need set 1 to gpio when Channel8 sampling, and set 0 to gpio when finish sampling.

Another Commit 1:Enable ADC Gpio bridge configuration

Tested:
P3VBAT previous value is 0.4V
P3VBAT sensor reading  now:3.0843V

Change-Id: I64325845dfd4a931d0beda28993f6b15fa31ae95
Signed-off-by: Zhu, Yunge <yunge.zhu@linux.intel.com>
diff --git a/src/ADCSensor.cpp b/src/ADCSensor.cpp
index 505bbfa..a8d98ae 100644
--- a/src/ADCSensor.cpp
+++ b/src/ADCSensor.cpp
@@ -20,21 +20,41 @@
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
+#include <filesystem>
+#include <fstream>
 #include <iostream>
 #include <limits>
+#include <optional>
 #include <sdbusplus/asio/connection.hpp>
 #include <sdbusplus/asio/object_server.hpp>
 #include <string>
-
 static constexpr unsigned int sensorPollMs = 500;
 static constexpr size_t warnAfterErrorCount = 10;
-
+static constexpr unsigned int gpioBridgeEnableMs = 20;
 // scaling factor from hwmon
 static constexpr unsigned int sensorScaleFactor = 1000;
 
 static constexpr double roundFactor = 10000; // 3 decimal places
 static constexpr double maxReading = 20;
 static constexpr double minReading = 0;
+static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio";
+static constexpr const char* postfixValue = "/value";
+
+void setGpio(int gpioN, int value)
+{
+    std::string device = sysGpioPath + std::to_string(gpioN) + postfixValue;
+    std::fstream gpioFile;
+
+    gpioFile.open(device, std::ios::out);
+
+    if (!gpioFile.good())
+    {
+        std::cerr << "Error opening device " << device << "\n";
+        return;
+    }
+    gpioFile << std::to_string(value);
+    gpioFile.close();
+}
 
 ADCSensor::ADCSensor(const std::string& path,
                      sdbusplus::asio::object_server& objectServer,
@@ -42,13 +62,14 @@
                      boost::asio::io_service& io, const std::string& sensorName,
                      std::vector<thresholds::Threshold>&& _thresholds,
                      const double scaleFactor, PowerState readState,
-                     const std::string& sensorConfiguration) :
+                     const std::string& sensorConfiguration,
+                     std::optional<int> bridgeGpio) :
     Sensor(boost::replace_all_copy(sensorName, " ", "_"), path,
            std::move(_thresholds), sensorConfiguration,
            "xyz.openbmc_project.Configuration.ADC", maxReading, minReading),
     objServer(objectServer), scaleFactor(scaleFactor),
     readState(std::move(readState)), inputDev(io, open(path.c_str(), O_RDONLY)),
-    waitTimer(io), errCount(0), thresholdTimer(io, this)
+    waitTimer(io), errCount(0), thresholdTimer(io, this), bridgeGpio(bridgeGpio)
 {
     sensorInterface = objectServer.add_interface(
         "/xyz/openbmc_project/sensors/voltage/" + name,
@@ -88,10 +109,33 @@
 
 void ADCSensor::setupRead(void)
 {
-    boost::asio::async_read_until(
-        inputDev, readBuf, '\n',
-        [&](const boost::system::error_code& ec,
-            std::size_t /*bytes_transfered*/) { handleResponse(ec); });
+    if (bridgeGpio.has_value())
+    {
+        setGpio(*bridgeGpio, 1);
+        // In case a channel has a bridge circuit,we have to turn the bridge on
+        // prior to reading a value at least for one scan cycle to get a valid
+        // value. Guarantee that the HW signal can be stable, the HW signal
+        // could be instability.
+        waitTimer.expires_from_now(
+            boost::posix_time::milliseconds(gpioBridgeEnableMs));
+        waitTimer.async_wait([&](const boost::system::error_code& ec) {
+            if (ec == boost::asio::error::operation_aborted)
+            {
+                return; // we're being canceled
+            }
+            boost::asio::async_read_until(
+                inputDev, readBuf, '\n',
+                [&](const boost::system::error_code& ec,
+                    std::size_t /*bytes_transfered*/) { handleResponse(ec); });
+        });
+    }
+    else
+    {
+        boost::asio::async_read_until(
+            inputDev, readBuf, '\n',
+            [&](const boost::system::error_code& ec,
+                std::size_t /*bytes_transfered*/) { handleResponse(ec); });
+    }
 }
 
 void ADCSensor::handleResponse(const boost::system::error_code& err)
@@ -145,6 +189,10 @@
 
     responseStream.clear();
     inputDev.close();
+    if (bridgeGpio.has_value())
+    {
+        setGpio(*bridgeGpio, 0);
+    }
     int fd = open(path.c_str(), O_RDONLY);
     if (fd <= 0)
     {