GPIO Monitor with multiple lines and libgpiod
Added a new GPIO monitor (phosphor-multi-gpio-monitor) which monitors
multiple gpio lines based on their line name or offset. GPIO details
need to be defined in a JSON file and needs to be passed to this daemon.
This uses libgpiod for accessing gpio lines and also uses CLI11 for
parsing input parameter.
Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
Change-Id: I843e6df8c1159888f2ca628d1f69c1d2294d29d6
diff --git a/gpioMon.cpp b/gpioMon.cpp
new file mode 100644
index 0000000..2ab079a
--- /dev/null
+++ b/gpioMon.cpp
@@ -0,0 +1,123 @@
+/**
+ * Copyright © 2019 Facebook
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gpioMon.hpp"
+
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/bus.hpp>
+
+namespace phosphor
+{
+namespace gpio
+{
+
+/* systemd service to kick start a target. */
+constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
+constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1";
+constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
+
+using namespace phosphor::logging;
+
+void GpioMonitor::scheduleEventHandler()
+{
+
+ gpioEventDescriptor.async_wait(
+ boost::asio::posix::stream_descriptor::wait_read,
+ [this](const boost::system::error_code& ec) {
+ if (ec)
+ {
+ std::string msg = gpioLineMsg + "event handler error" +
+ std::string(ec.message());
+ log<level::ERR>(msg.c_str());
+ return;
+ }
+ gpioEventHandler();
+ });
+}
+
+void GpioMonitor::gpioEventHandler()
+{
+ gpiod_line_event gpioLineEvent;
+
+ if (gpiod_line_event_read_fd(gpioEventDescriptor.native_handle(),
+ &gpioLineEvent) < 0)
+ {
+ log<level::ERR>("Failed to read gpioLineEvent from fd",
+ entry("GPIO_LINE=%s", gpioLineMsg.c_str()));
+ return;
+ }
+
+ std::string logMessage =
+ gpioLineMsg + (gpioLineEvent.event_type == GPIOD_LINE_EVENT_RISING_EDGE
+ ? " Asserted"
+ : " Deasserted");
+
+ log<level::INFO>(logMessage.c_str());
+
+ /* Execute the target if it is defined. */
+ if (!target.empty())
+ {
+ auto bus = sdbusplus::bus::new_default();
+ auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT,
+ SYSTEMD_INTERFACE, "StartUnit");
+ method.append(target);
+ method.append("replace");
+
+ bus.call_noreply(method);
+ }
+
+ /* if not required to continue monitoring then return */
+ if (!continueAfterEvent)
+ {
+ return;
+ }
+
+ /* Schedule a wait event */
+ scheduleEventHandler();
+}
+
+int GpioMonitor::requestGPIOEvents()
+{
+
+ /* Request an event to monitor for respected gpio line */
+ if (gpiod_line_request(gpioLine, &gpioConfig, 0) < 0)
+ {
+ log<level::ERR>("Failed to request gpioLineEvent",
+ entry("GPIO_LINE=%s", gpioLineMsg.c_str()));
+ return -1;
+ }
+
+ int gpioLineFd = gpiod_line_event_get_fd(gpioLine);
+ if (gpioLineFd < 0)
+ {
+ log<level::ERR>("Failed to get fd for gpioLineEvent",
+ entry("GPIO_LINE=%s", gpioLineMsg.c_str()));
+ return -1;
+ }
+
+ std::string logMsg = gpioLineMsg + " monitoring started";
+ log<level::INFO>(logMsg.c_str());
+
+ /* Assign line fd to descriptor for monitoring */
+ gpioEventDescriptor.assign(gpioLineFd);
+
+ /* Schedule a wait event */
+ scheduleEventHandler();
+
+ return 0;
+}
+} // namespace gpio
+} // namespace phosphor