summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGunnar Mills <gmills@us.ibm.com>2017-07-06 14:17:44 -0500
committerGunnar Mills <gmills@us.ibm.com>2017-07-26 13:06:36 -0500
commit765725e057046784ceb4e7595e44f2e4c2ef6ae2 (patch)
tree4f95629e589735c4225df4ebf00f77bf3d1cbe96
parent80292bbed705d47d319dd44e0862126b86a22de2 (diff)
downloadphosphor-gpio-monitor-765725e057046784ceb4e7595e44f2e4c2ef6ae2.tar.gz
phosphor-gpio-monitor-765725e057046784ceb4e7595e44f2e4c2ef6ae2.zip
Monitor for GPIO state change
Use libevdev to monitor for GPIO state change and update item present accordingly. Change-Id: I1959a5ea09a7570c096b05d78a190394767a5ddd Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
-rw-r--r--presence/gpio_presence.cpp72
-rw-r--r--presence/gpio_presence.hpp61
-rw-r--r--presence/main.cpp27
3 files changed, 157 insertions, 3 deletions
diff --git a/presence/gpio_presence.cpp b/presence/gpio_presence.cpp
index ba897d0..0390af6 100644
--- a/presence/gpio_presence.cpp
+++ b/presence/gpio_presence.cpp
@@ -119,6 +119,59 @@ void Presence::determinePresence()
updateInventory(present);
}
+// Callback handler when there is an activity on the FD
+int Presence::processEvents(sd_event_source* es, int fd,
+ uint32_t revents, void* userData)
+{
+ auto presence = static_cast<Presence*>(userData);
+
+ presence->analyzeEvent();
+ return 0;
+}
+
+
+// Analyzes the GPIO event
+void Presence::analyzeEvent()
+{
+
+ // Data returned
+ struct input_event ev {};
+ int rc = 0;
+
+ // While testing, observed that not having a loop here was leading
+ // into events being missed.
+ while (rc >= 0)
+ {
+ // Wait until no more events are available on the device.
+ rc = libevdev_next_event(devicePtr.get(),
+ LIBEVDEV_READ_FLAG_NORMAL, &ev);
+ if (rc < 0)
+ {
+ // There was an error waiting for events, mostly that there are no
+ // events to be read.. So continue waiting...
+ return;
+ }
+
+ if (rc == LIBEVDEV_READ_STATUS_SUCCESS)
+ {
+ if (ev.type == EV_SYN && ev.code == SYN_REPORT)
+ {
+ continue;
+ }
+ else if (ev.code == key)
+ {
+ auto present = false;
+ if (ev.value > 0)
+ {
+ present = true;
+ }
+ updateInventory(present);
+ }
+ }
+ }
+
+ return;
+}
Presence::ObjectMap Presence::getObjectMap(bool present)
{
@@ -139,6 +192,10 @@ void Presence::updateInventory(bool present)
{
ObjectMap invObj = getObjectMap(present);
+ log<level::INFO>("Updating inventory present property",
+ entry("PRESENT=%d", present),
+ entry("PATH=%s", inventory));
+
auto invService = getService(INVENTORY_PATH, INVENTORY_INTF, bus);
// Update inventory
@@ -156,6 +213,21 @@ void Presence::updateInventory(bool present)
}
}
+// Attaches the FD to event loop and registers the callback handler
+void Presence::registerCallback()
+{
+ decltype(eventSource.get()) sourcePtr = nullptr;
+ auto rc = sd_event_add_io(event.get(), &sourcePtr, (fd)(),
+ EPOLLIN, callbackHandler, this);
+ eventSource.reset(sourcePtr);
+
+ if (rc < 0)
+ {
+ log<level::ERR>("Failed to register callback handler",
+ entry("ERROR=%s", strerror(-rc)));
+ elog<InternalFailure>();
+ }
+}
} // namespace presence
} // namespace gpio
diff --git a/presence/gpio_presence.hpp b/presence/gpio_presence.hpp
index 47d2dc7..e8f68ca 100644
--- a/presence/gpio_presence.hpp
+++ b/presence/gpio_presence.hpp
@@ -1,5 +1,6 @@
#pragma once
#include <string>
+#include <systemd/sd-event.h>
#include <libevdev/libevdev.h>
#include "file.hpp"
@@ -10,6 +11,26 @@ namespace gpio
namespace presence
{
+/* Need a custom deleter for freeing up sd_event */
+struct EventDeleter
+{
+ void operator()(sd_event* event) const
+ {
+ event = sd_event_unref(event);
+ }
+};
+using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
+
+/* Need a custom deleter for freeing up sd_event_source */
+struct EventSourceDeleter
+{
+ void operator()(sd_event_source* eventSource) const
+ {
+ eventSource = sd_event_source_unref(eventSource);
+ }
+};
+using EventSourcePtr = std::unique_ptr<sd_event_source, EventSourceDeleter>;
+
/* Need a custom deleter for freeing up evdev struct */
struct FreeEvDev
{
@@ -55,23 +76,46 @@ class Presence
to determine presence of inventory item
* @param[in] key - GPIO key to monitor
* @param[in] name - Pretty name of the inventory item
+ * @param[in] event - sd_event handler
+ * @param[in] handler - IO callback handler. Defaults to one in this
+ * class
*/
Presence(sdbusplus::bus::bus& bus,
const std::string& inventory,
const std::string& path,
const unsigned int key,
- const std::string& name) :
+ const std::string& name,
+ EventPtr& event,
+ sd_event_io_handler_t handler = Presence::processEvents) :
bus(bus),
inventory(inventory),
path(path),
key(key),
name(name),
+ event(event),
+ callbackHandler(handler),
fd(openDevice())
+
{
initEvDev();
determinePresence();
+ // Register callback handler when FD has some data
+ registerCallback();
}
+ /** @brief Callback handler when the FD has some activity on it
+ *
+ * @param[in] es - Populated event source
+ * @param[in] fd - Associated File descriptor
+ * @param[in] revents - Type of event
+ * @param[in] userData - User data that was passed during registration
+ *
+ * @return - 0 or positive number on success and negative
+ * errno otherwise
+ */
+ static int processEvents(sd_event_source* es, int fd,
+ uint32_t revents, void* userData);
+
private:
/**
* @brief Update the present property for the inventory item.
@@ -114,12 +158,27 @@ class Presence
/** @brief Event structure */
EvdevPtr devicePtr;
+ /** @brief Monitor to sd_event */
+ EventPtr& event;
+
+ /** @brief Callback handler when the FD has some data */
+ sd_event_io_handler_t callbackHandler;
+
+ /** @brief event source */
+ EventSourcePtr eventSource;
+
/** @brief Opens the device and populates the descriptor */
int openDevice();
+ /** @brief attaches FD to events and sets up callback handler */
+ void registerCallback();
+
/** @brief File descriptor manager */
FileDescriptor fd;
+ /** @brief Analyzes the GPIO event and update present property*/
+ void analyzeEvent();
+
/** @brief Initializes evdev handle with the fd */
void initEvDev();
};
diff --git a/presence/main.cpp b/presence/main.cpp
index f6cb665..6116540 100644
--- a/presence/main.cpp
+++ b/presence/main.cpp
@@ -1,4 +1,5 @@
#include <iostream>
+#include <systemd/sd-event.h>
#include <phosphor-logging/log.hpp>
#include "argument.hpp"
#include "gpio_presence.hpp"
@@ -39,9 +40,31 @@ int main(int argc, char* argv[])
}
auto bus = sdbusplus::bus::new_default();
+ auto rc = 0;
+ sd_event* event = nullptr;
+ rc = sd_event_default(&event);
+ if (rc < 0)
+ {
+ log<level::ERR>("Error creating a default sd_event handler");
+ return rc;
+ }
+ EventPtr eventP{event};
+ event = nullptr;
+
auto name = options["name"];
- Presence presence(bus, inventory, path, std::stoul(key), name);
+ Presence presence(bus, inventory, path, std::stoul(key), name, eventP);
- return 0;
+ while (true)
+ {
+ // -1 denotes wait forever
+ rc = sd_event_run(eventP.get(), (uint64_t) - 1);
+ if (rc < 0)
+ {
+ log<level::ERR>("Failure in processing request",
+ entry("ERROR=%s", strerror(-rc)));
+ break;
+ }
+ }
+ return rc;
}
OpenPOWER on IntegriCloud