Add base GPIO class for the new architecture
New architecture is intended to improve flexibility for which
signals are monitored in a system and how they are handled.
Change-Id: I97b1e26c2b15a5bd75c4e18a3f2a9cd0d52c970d
Signed-off-by: Jason M. Bills <jason.m.bills@intel.com>
diff --git a/include/error_monitors/base_gpio_monitor.hpp b/include/error_monitors/base_gpio_monitor.hpp
new file mode 100644
index 0000000..40bd1bc
--- /dev/null
+++ b/include/error_monitors/base_gpio_monitor.hpp
@@ -0,0 +1,183 @@
+/*
+// Copyright (c) 2021 Intel Corporation
+//
+// 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.
+*/
+#pragma once
+#include <boost/asio/posix/stream_descriptor.hpp>
+#include <error_monitors/base_monitor.hpp>
+#include <gpiod.hpp>
+#include <host_error_monitor.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+
+#include <iostream>
+
+namespace host_error_monitor::base_gpio_monitor
+{
+static constexpr bool debug = false;
+
+enum class AssertValue
+{
+ lowAssert = 0,
+ highAssert = 1,
+};
+
+class BaseGPIOMonitor : public host_error_monitor::base_monitor::BaseMonitor
+{
+ AssertValue assertValue;
+ int assertEvent;
+
+ gpiod::line line;
+ boost::asio::posix::stream_descriptor event;
+
+ virtual void logEvent()
+ {}
+
+ bool requestEvents()
+ {
+ line = gpiod::find_line(signalName);
+ if (!line)
+ {
+ std::cerr << "Failed to find the " << signalName << " line\n";
+ return false;
+ }
+
+ try
+ {
+ line.request(
+ {"host-error-monitor", gpiod::line_request::EVENT_BOTH_EDGES});
+ }
+ catch (std::exception&)
+ {
+ std::cerr << "Failed to request events for " << signalName << "\n";
+ return false;
+ }
+
+ int lineFd = line.event_get_fd();
+ if (lineFd < 0)
+ {
+ std::cerr << "Failed to get " << signalName << " fd\n";
+ return false;
+ }
+
+ event.assign(lineFd);
+
+ return true;
+ }
+
+ bool asserted()
+ {
+ if constexpr (debug)
+ {
+ std::cerr << "Checking " << signalName << " state\n";
+ }
+
+ return (line.get_value() == static_cast<int>(assertValue));
+ }
+
+ void checkEvent(bool assertEvent)
+ {
+ if (assertEvent)
+ {
+ if constexpr (debug)
+ {
+ std::cerr << signalName << " asserted\n";
+ }
+
+ assertHandler();
+ }
+ else
+ {
+ if constexpr (debug)
+ {
+ std::cerr << signalName << " deasserted\n";
+ }
+
+ deassertHandler();
+ }
+ }
+
+ public:
+ virtual void assertHandler()
+ {
+ std::cerr << signalName << " asserted\n";
+ logEvent();
+ }
+
+ virtual void deassertHandler()
+ {}
+
+ private:
+ void waitForEvent()
+ {
+ if constexpr (debug)
+ {
+ std::cerr << "Wait for " << signalName << "\n";
+ }
+
+ event.async_wait(
+ boost::asio::posix::stream_descriptor::wait_read,
+ [this](const boost::system::error_code ec) {
+ if (ec)
+ {
+ // operation_aborted is expected if wait is canceled.
+ if (ec != boost::asio::error::operation_aborted)
+ {
+ std::cerr << signalName
+ << " wait error: " << ec.message() << "\n";
+ }
+ return;
+ }
+
+ if constexpr (debug)
+ {
+ std::cerr << signalName << " event ready\n";
+ }
+
+ gpiod::line_event gpioLineEvent = line.event_read();
+
+ checkEvent(gpioLineEvent.event_type == assertEvent);
+ waitForEvent();
+ });
+ }
+
+ public:
+ void startMonitoring()
+ {
+ if constexpr (debug)
+ {
+ std::cerr << "Monitoring " << signalName << "\n";
+ }
+
+ checkEvent(asserted());
+ waitForEvent();
+ }
+
+ BaseGPIOMonitor(boost::asio::io_service& io,
+ std::shared_ptr<sdbusplus::asio::connection> conn,
+ const std::string& signalName, AssertValue assertValue) :
+ BaseMonitor(io, conn, signalName),
+ event(io), assertValue(assertValue)
+ {
+ assertEvent = (assertValue == AssertValue::lowAssert)
+ ? gpiod::line_event::FALLING_EDGE
+ : gpiod::line_event::RISING_EDGE;
+
+ if (!requestEvents())
+ {
+ return;
+ }
+ valid = true;
+ }
+};
+} // namespace host_error_monitor::base_gpio_monitor