summaryrefslogtreecommitdiff
path: root/gpiodaemon
diff options
context:
space:
mode:
authorRichard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>2019-03-21 19:12:03 +0300
committerRichard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>2019-03-21 19:12:03 +0300
commitb708f28e43b85fd51c0f68670e7614dc3d7dbe50 (patch)
treec95e378c878ef69e7ae89878fe117d04c40e7e86 /gpiodaemon
parentc927781ad3ca1408cd7fb0b7cc2538ea10ded76b (diff)
downloadprovingground-b708f28e43b85fd51c0f68670e7614dc3d7dbe50.tar.xz
gpio daemon: Support added
Simplified Gpio daemon service and it's corresponding members. Buttons must use these gpio daemon instead of directly queriying gpio. Daemon will send out properties changed signal, when there is change in gpio value. Introduced Ignore property, if set true will return cached values for the specified gpio. Gpio daemon will query objects from entity manager and initialize accordignly. Restarting gpio daemon, will re-init these pins as per the entity manager. Tested: 1. Verified the properties of Power button & Reset button 2. Performed FP buttons operation and made sure power button & reset button properties changed signals are properly sent out 3. Testd against updated buttons code (which uses gpio daemon) and verified basic power operations both from front panel and from ipmitool power 4. Verified object creation, during gpio daemon restart and also on entity-manager restart Change-Id: I89ad04d58c74ebd534712f38be53549ec2c39662 Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
Diffstat (limited to 'gpiodaemon')
-rw-r--r--gpiodaemon/include/gpiodaemon.hpp94
-rw-r--r--gpiodaemon/src/gpiodaemon.cpp311
2 files changed, 175 insertions, 230 deletions
diff --git a/gpiodaemon/include/gpiodaemon.hpp b/gpiodaemon/include/gpiodaemon.hpp
index 424bf99..b3d461e 100644
--- a/gpiodaemon/include/gpiodaemon.hpp
+++ b/gpiodaemon/include/gpiodaemon.hpp
@@ -15,55 +15,25 @@
*/
#pragma once
+#include "gpioutils.hpp"
+
#include <boost/asio.hpp>
#include <experimental/filesystem>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/asio/object_server.hpp>
-class GpioEn
+class GpioState
{
- std::string name;
+ const std::string name;
uint16_t number;
+ const bool inverted;
bool enabled;
bool value;
+ std::string direction;
+ bool ignore = false;
+ bool internalSet = false;
- public:
- GpioEn(const std::string& name_, uint16_t number_, bool enabled_) :
- name(name_), number(number_), enabled(enabled_){};
-
- std::string getName() const
- {
- return name;
- }
- uint16_t getNumber() const
- {
- return number;
- }
- bool getEnabled() const
- {
- return enabled;
- }
- void setEnabled(bool value)
- {
- enabled = value;
- }
- bool getValue() const
- {
- return value;
- }
- void setvalue(bool val)
- {
- value = val;
- }
-};
-
-class GpioState
-{
- bool state = true;
- const bool inverted;
- const std::string gpioName;
int fdValue;
-
boost::asio::ip::tcp::socket inputDev;
std::shared_ptr<sdbusplus::asio::dbus_interface> iface;
@@ -71,21 +41,12 @@ class GpioState
void readValue(void);
public:
- GpioState(const std::string gpioName, const uint16_t gpioNumber,
- const bool inverted, boost::asio::io_service& io,
- std::shared_ptr<sdbusplus::asio::dbus_interface>& iface);
- GpioState(GpioState&&) = default;
- GpioState& operator=(GpioState&&) = default;
+ GpioState(const std::string& name_, const uint16_t number_,
+ const bool inverted_, const bool enabled_,
+ const std::string& direction_, boost::asio::io_service& io_,
+ std::shared_ptr<sdbusplus::asio::dbus_interface>& iface_);
~GpioState();
-
- std::string getName() const
- {
- return gpioName;
- }
- bool getValue(void) const
- {
- return state;
- }
+ Gpio gpio;
};
class GpioManager
@@ -95,34 +56,7 @@ class GpioManager
std::shared_ptr<sdbusplus::asio::connection> conn;
std::shared_ptr<sdbusplus::asio::dbus_interface> iface;
- std::vector<GpioEn> gpioEnableList;
- std::vector<std::unique_ptr<GpioState>> gpioMonitorList;
-
- GpioEn* findGpioObj(const std::string& gpioName)
- {
- auto el = std::find_if(gpioEnableList.begin(), gpioEnableList.end(),
- [&gpioName](const GpioEn& obj) {
- return obj.getName() == gpioName;
- });
- if (el != gpioEnableList.end())
- {
- return &(*el);
- }
- return nullptr;
- }
-
- bool getGpioStateValue(const std::string& gpioName, bool& value)
- {
- for (const auto& gpio : gpioMonitorList)
- {
- if (gpio->getName() == gpioName)
- {
- value = gpio->getValue();
- return true;
- }
- }
- return false;
- }
+ std::map<std::string, std::unique_ptr<GpioState>> gpioMonitorList;
public:
GpioManager(boost::asio::io_service& io,
diff --git a/gpiodaemon/src/gpiodaemon.cpp b/gpiodaemon/src/gpiodaemon.cpp
index f762656..cd742e2 100644
--- a/gpiodaemon/src/gpiodaemon.cpp
+++ b/gpiodaemon/src/gpiodaemon.cpp
@@ -16,11 +16,9 @@
#include "gpiodaemon.hpp"
-#include "gpioutils.hpp"
-
+#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <regex>
-
static constexpr const char* entityMgrService =
"xyz.openbmc_project.EntityManager";
static constexpr const char* gpioService = "xyz.openbmc_project.Gpio";
@@ -35,8 +33,6 @@ static constexpr const char* objPath = "/xyz/openbmc_project/object_mapper";
static constexpr const char* objService = "xyz.openbmc_project.ObjectMapper";
static constexpr const char* objInterface = "xyz.openbmc_project.ObjectMapper";
-const static constexpr size_t waitTime = 2; // seconds
-
using BasicVariantType =
sdbusplus::message::variant<std::string, int64_t, uint64_t, double, int32_t,
uint32_t, int16_t, uint16_t, uint8_t, bool>;
@@ -58,9 +54,11 @@ void GpioManager::addObject(const std::string& path)
auto nameFind = result.find("Name");
auto indexFind = result.find("Index");
auto polarityFind = result.find("Polarity");
+ auto directionFind = result.find("Direction");
if (nameFind == result.end() || indexFind == result.end() ||
- polarityFind == result.end())
+ polarityFind == result.end() ||
+ directionFind == result.end())
{
phosphor::logging::log<phosphor::logging::level::INFO>(
"ERROR accessing entity manager.");
@@ -75,130 +73,29 @@ void GpioManager::addObject(const std::string& path)
bool inverted =
sdbusplus::message::variant_ns::get<std::string>(
polarityFind->second) == "Low";
+ std::string direction =
+ sdbusplus::message::variant_ns::get<std::string>(
+ directionFind->second);
boost::replace_all(gpioName, " ", "_");
-
- // Add gpio entries to be managed by gpiodaemon
- gpioEnableList.push_back(
- GpioEn(gpioName, (uint16_t)index, false));
-
- // Read present gpio data from /sys/class/gpio/...
- Gpio gpio = Gpio(std::to_string(index));
-
+ boost::algorithm::to_lower(direction);
+ if (gpioMonitorList.find(gpioName) != gpioMonitorList.end())
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "ERROR Object already preset",
+ phosphor::logging::entry("GPIO_NAME=%s",
+ gpioName.c_str()));
+ return;
+ }
// Add path to server object
iface =
server.add_interface(gpioPath + gpioName, gpioInterface);
- /////////////////////////////
- // Set generic properties:
- // - enabled - when set to false other properties like
- // value and direction
- // cannot be overriden
- // - value
- // - direction
- // - polarity
- /////////////////////////////
- iface->register_property(
- "Enabled", true,
- [this, gpioName](const bool& req, bool& propertyValue) {
- GpioEn* dbusGpio = findGpioObj(gpioName);
- if (dbusGpio)
- {
- dbusGpio->setEnabled(req);
- propertyValue = req;
- return 1;
- }
- return 0;
- });
-
- bool value = static_cast<bool>(gpio.getValue());
- if (inverted)
- {
- value = !value;
- }
- iface->register_property(
- "Value", value,
- // Override set
- [this, gpioName, inverted](const bool& req,
- bool& propertyValue) {
- GpioEn* dbusGpio = findGpioObj(gpioName);
-
- if (dbusGpio)
- {
- // If Gpio enabled property is set as true and
- // direction is out then handle the set request
- Gpio gpio =
- Gpio(std::to_string(dbusGpio->getNumber()));
- if (dbusGpio->getEnabled() &&
- gpio.getDirection() == "out")
- {
- bool setVal = req;
- if (inverted)
- {
- setVal = !setVal;
- }
- gpio.setValue(static_cast<GpioValue>(setVal));
-
- propertyValue = setVal;
- return 1;
- }
- return 0;
- }
- return 0;
- },
- // Override get
- [this, gpioName](const bool& propertyValue) {
- bool value;
- if (getGpioStateValue(gpioName, value))
- {
- return value;
- }
- else // Gpio with direction "out" are not monitored.
- // Return last know state.
- {
- GpioEn* dbuGpio = findGpioObj(gpioName);
- if (dbuGpio)
- {
- return dbuGpio->getValue();
- }
- }
- });
-
- iface->register_property(
- "Direction", gpio.getDirection(),
- // Override set
- [this, gpioName](const std::string& req,
- std::string& propertyValue) {
- GpioEn* dbusGpio = findGpioObj(gpioName);
-
- if (dbusGpio)
- {
- // If Gpio enabled property is set as true then
- // handle the request
- if (dbusGpio->getEnabled())
- {
- Gpio gpio =
- Gpio(std::to_string(dbusGpio->getNumber()));
- gpio.setDirection(req);
-
- propertyValue = req;
- return 1;
- }
- return 0;
- }
- return 0;
- },
- // Override get
- [this, index](const std::string& propertyDirection) {
- // Read present gpio data from /sys/class/gpio/...
- Gpio gpio = Gpio(std::to_string(index));
- return gpio.getDirection();
- });
- iface->initialize();
-
// Monitor gpio value changes
- gpioMonitorList.push_back(std::make_unique<GpioState>(
- gpioName, index, inverted, io, iface));
+ gpioMonitorList.emplace(
+ gpioName,
+ std::make_unique<GpioState>(gpioName, index, inverted,
+ false, direction, io, iface));
}
},
entityMgrService, path, propInterface, "GetAll", gpioConfigInterface);
@@ -245,15 +142,120 @@ GpioManager::GpioManager(boost::asio::io_service& io_,
std::vector<std::string>());
}
-GpioState::GpioState(const std::string gpioName_, const uint16_t gpioNumber,
- const bool inverted_, boost::asio::io_service& io_,
+GpioState::GpioState(const std::string& name_, const uint16_t number_,
+ const bool inverted_, const bool enabled_,
+ const std::string& direction_,
+ boost::asio::io_service& io_,
std::shared_ptr<sdbusplus::asio::dbus_interface>& iface_) :
- gpioName(gpioName_),
- inverted(inverted_), inputDev(io_), iface(iface_)
+ name(name_),
+ number(number_), inverted(inverted_), enabled(enabled_),
+ direction(direction_), inputDev(io_), iface(iface_),
+ gpio(std::to_string(number_))
{
- // todo: implement gpio device character access
- std::string device = sysGpioPath + std::to_string(gpioNumber);
+ // Initialize gpio direction as specified by entity-manager
+ gpio.setDirection(direction);
+
+ // Property used to control whether gpio pin monitoring / control
+ // has to be ignored. Once set to true, gpio daemon will
+ // return the cached value. Any real sampling of data can be perfomed
+ // by reading the gpio lower level API directly.
+ // TODO: When set to ignore disable pass-through by default??
+ iface->register_property(
+ "Ignore", ignore,
+ // Override set
+ [this](const bool& req, bool& propertyValue) {
+ // If Gpio enabled property is set as true then
+ // handle the request
+ if (ignore != req)
+ {
+ ignore = req;
+ propertyValue = req;
+ return 1;
+ }
+ return 0;
+ },
+ // Override get
+ [this](const bool& propertyDirection) { return ignore; });
+ iface->register_property(
+ "Direction", direction,
+ // Override set
+ [this](const std::string& req, std::string& propertyValue) {
+ // If Gpio enabled property is set as true then
+ // handle the request
+ if (!ignore && enabled && direction != req)
+ {
+ direction = req;
+ this->gpio.setDirection(req);
+
+ propertyValue = req;
+ return 1;
+ }
+ return 0;
+ },
+ // Override get
+ [this](const std::string& propertyValue) {
+ if (!ignore)
+ {
+ direction = this->gpio.getDirection();
+ }
+ return direction;
+ });
+
+ // TODO: Determine whether we require this one? ignore should be fine
+ // Decide and remove the same
+
+ // Enabled is used to control the set property of Value & direction
+ iface->register_property(
+ "Enabled", enabled,
+ [this](const bool& req, bool& propertyValue) {
+ if (!ignore && enabled != req)
+ {
+ enabled = req;
+ propertyValue = req;
+ return 1;
+ }
+ return 0;
+ },
+ [this](const bool& propertyValue) { return enabled; });
+ value = static_cast<bool>(gpio.getValue());
+ if (inverted)
+ {
+ value = !value;
+ }
+ iface->register_property(
+ "Value", value,
+ // Override set
+ [this](const bool& req, bool& propertyValue) {
+ if ((!ignore && enabled && this->gpio.getDirection() == "out") ||
+ internalSet)
+ {
+ bool setVal = req;
+ if (inverted)
+ {
+ setVal = !setVal;
+ }
+ if (value != setVal)
+ {
+ value = setVal;
+ propertyValue = setVal;
+ if (!internalSet)
+ {
+ this->gpio.setValue(static_cast<GpioValue>(setVal));
+ }
+ return 1;
+ }
+ }
+ return 0;
+ },
+ // Override get
+ [this](const bool& propertyValue) { return value; });
+
+ iface->initialize();
+
+ // TODO: implement gpio device character access in gpioutils.cpp
+ // and make use of gpioutils file to read directly
+ std::string device = sysGpioPath + std::to_string(number);
fdValue = open((device + "/value").c_str(), O_RDONLY);
if (fdValue < 0)
{
@@ -261,8 +263,6 @@ GpioState::GpioState(const std::string gpioName_, const uint16_t gpioNumber,
("GpioState: Error opening " + device).c_str());
return;
}
-
- Gpio gpio = Gpio(std::to_string(gpioNumber));
if (gpio.getDirection() == "in")
{
std::ofstream deviceFileEdge(device + "/edge");
@@ -275,7 +275,6 @@ GpioState::GpioState(const std::string gpioName_, const uint16_t gpioNumber,
deviceFileEdge << "both";
deviceFileEdge.close();
}
-
inputDev.assign(boost::asio::ip::tcp::v4(), fdValue);
monitor();
readValue();
@@ -311,22 +310,21 @@ void GpioState::monitor(void)
void GpioState::readValue(void)
{
+ if (ignore)
+ {
+ return;
+ }
constexpr size_t readSize = sizeof("0");
std::string readBuf;
readBuf.resize(readSize);
lseek(fdValue, 0, SEEK_SET);
-
size_t r = ::read(fdValue, readBuf.data(), readSize);
- bool value = std::stoi(readBuf);
- if (inverted)
- {
- value = !value;
- }
- state = value;
-
- // Broadcast value changed property signal
- iface->signal_property("Value");
+ bool state = std::stoi(readBuf);
+ internalSet = true;
+ // Update the property value
+ iface->set_property("Value", state);
+ internalSet = false;
}
int main()
@@ -337,19 +335,32 @@ int main()
sdbusplus::asio::object_server server(systemBus);
GpioManager gpioMgr(io, server, systemBus);
+ // TODO: Expose a manager object to handle disable / enable passthrough ?
static auto match = std::make_unique<sdbusplus::bus::match::match>(
static_cast<sdbusplus::bus::bus&>(*systemBus),
- "type='signal',member='PropertiesChanged',"
- "arg0namespace='" +
- std::string(gpioConfigInterface) + "'",
+ "type='signal',member='InterfacesAdded',sender='xyz.openbmc_project."
+ "EntityManager'",
[&gpioMgr](sdbusplus::message::message& message) {
- phosphor::logging::log<phosphor::logging::level::INFO>(
- "New configuration detected. Updating gpiodaemon.");
-
- gpioMgr.addObject(std::string(message.get_path()));
+ using EntityMgrObjectTypes =
+ std::map<std::string,
+ std::vector<std::pair<std::string, BasicVariantType>>>;
+ sdbusplus::message::object_path objectPath;
+ EntityMgrObjectTypes objects;
+ message.read(objectPath, objects);
+ for (const auto& objectInterfaces : objects)
+ {
+ if (gpioConfigInterface == objectInterfaces.first)
+ {
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "New configuration detected. Updating gpiodaemon.");
+ gpioMgr.addObject(objectPath.str);
+ }
+ }
// TODO: Distinct and handle adequately whether entity-manager is
- // adding or deleting gpio related entries. For now just addObject.
+ // adding or deleting gpio related entries. For now just registered
+ // for
+ //.InterfacesAdded signal alone.
});
io.run();