| /* |
| // 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_context& 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 |