[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/include/ADCSensor.hpp b/include/ADCSensor.hpp
index fbb256b..539e0da 100644
--- a/include/ADCSensor.hpp
+++ b/include/ADCSensor.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <Thresholds.hpp>
+#include <optional>
#include <sdbusplus/asio/object_server.hpp>
#include <sensor.hpp>
@@ -13,7 +14,8 @@
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);
~ADCSensor();
private:
@@ -23,6 +25,7 @@
boost::asio::streambuf readBuf;
int errCount;
double scaleFactor;
+ std::optional<int> bridgeGpio;
PowerState readState;
thresholds::ThresholdTimer thresholdTimer;
void setupRead(void);
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)
{
diff --git a/src/ADCSensorMain.cpp b/src/ADCSensorMain.cpp
index 98b41a0..61ebd6c 100644
--- a/src/ADCSensorMain.cpp
+++ b/src/ADCSensorMain.cpp
@@ -23,6 +23,7 @@
#include <boost/algorithm/string/replace.hpp>
#include <boost/container/flat_set.hpp>
#include <fstream>
+#include <optional>
#include <regex>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
@@ -212,10 +213,20 @@
setReadState(powerState, readState);
}
+ auto findBridgeGpio = baseConfiguration->second.find("BridgeGpio");
+ std::optional<int> gpioNum;
+
+ if (findBridgeGpio != baseConfiguration->second.end())
+ {
+ int gpioPin =
+ std::visit(VariantToIntVisitor(), findBridgeGpio->second);
+ gpioNum = static_cast<std::optional<int>>(gpioPin);
+ }
+
sensors[sensorName] = std::make_unique<ADCSensor>(
path.string(), objectServer, dbusConnection, io, sensorName,
- std::move(sensorThresholds), scaleFactor, readState,
- *interfacePath);
+ std::move(sensorThresholds), scaleFactor, readState, *interfacePath,
+ gpioNum);
}
}