blob: 40bd1bc908c2504ee388e217fc4fa172b55580ac [file] [log] [blame]
Jason M. Bills1ed0cb32020-12-10 16:53:41 -08001/*
2// Copyright (c) 2021 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17#include <boost/asio/posix/stream_descriptor.hpp>
18#include <error_monitors/base_monitor.hpp>
19#include <gpiod.hpp>
20#include <host_error_monitor.hpp>
21#include <sdbusplus/asio/object_server.hpp>
22
23#include <iostream>
24
25namespace host_error_monitor::base_gpio_monitor
26{
27static constexpr bool debug = false;
28
29enum class AssertValue
30{
31 lowAssert = 0,
32 highAssert = 1,
33};
34
35class BaseGPIOMonitor : public host_error_monitor::base_monitor::BaseMonitor
36{
37 AssertValue assertValue;
38 int assertEvent;
39
40 gpiod::line line;
41 boost::asio::posix::stream_descriptor event;
42
43 virtual void logEvent()
44 {}
45
46 bool requestEvents()
47 {
48 line = gpiod::find_line(signalName);
49 if (!line)
50 {
51 std::cerr << "Failed to find the " << signalName << " line\n";
52 return false;
53 }
54
55 try
56 {
57 line.request(
58 {"host-error-monitor", gpiod::line_request::EVENT_BOTH_EDGES});
59 }
60 catch (std::exception&)
61 {
62 std::cerr << "Failed to request events for " << signalName << "\n";
63 return false;
64 }
65
66 int lineFd = line.event_get_fd();
67 if (lineFd < 0)
68 {
69 std::cerr << "Failed to get " << signalName << " fd\n";
70 return false;
71 }
72
73 event.assign(lineFd);
74
75 return true;
76 }
77
78 bool asserted()
79 {
80 if constexpr (debug)
81 {
82 std::cerr << "Checking " << signalName << " state\n";
83 }
84
85 return (line.get_value() == static_cast<int>(assertValue));
86 }
87
88 void checkEvent(bool assertEvent)
89 {
90 if (assertEvent)
91 {
92 if constexpr (debug)
93 {
94 std::cerr << signalName << " asserted\n";
95 }
96
97 assertHandler();
98 }
99 else
100 {
101 if constexpr (debug)
102 {
103 std::cerr << signalName << " deasserted\n";
104 }
105
106 deassertHandler();
107 }
108 }
109
110 public:
111 virtual void assertHandler()
112 {
113 std::cerr << signalName << " asserted\n";
114 logEvent();
115 }
116
117 virtual void deassertHandler()
118 {}
119
120 private:
121 void waitForEvent()
122 {
123 if constexpr (debug)
124 {
125 std::cerr << "Wait for " << signalName << "\n";
126 }
127
128 event.async_wait(
129 boost::asio::posix::stream_descriptor::wait_read,
130 [this](const boost::system::error_code ec) {
131 if (ec)
132 {
133 // operation_aborted is expected if wait is canceled.
134 if (ec != boost::asio::error::operation_aborted)
135 {
136 std::cerr << signalName
137 << " wait error: " << ec.message() << "\n";
138 }
139 return;
140 }
141
142 if constexpr (debug)
143 {
144 std::cerr << signalName << " event ready\n";
145 }
146
147 gpiod::line_event gpioLineEvent = line.event_read();
148
149 checkEvent(gpioLineEvent.event_type == assertEvent);
150 waitForEvent();
151 });
152 }
153
154 public:
155 void startMonitoring()
156 {
157 if constexpr (debug)
158 {
159 std::cerr << "Monitoring " << signalName << "\n";
160 }
161
162 checkEvent(asserted());
163 waitForEvent();
164 }
165
166 BaseGPIOMonitor(boost::asio::io_service& io,
167 std::shared_ptr<sdbusplus::asio::connection> conn,
168 const std::string& signalName, AssertValue assertValue) :
169 BaseMonitor(io, conn, signalName),
170 event(io), assertValue(assertValue)
171 {
172 assertEvent = (assertValue == AssertValue::lowAssert)
173 ? gpiod::line_event::FALLING_EDGE
174 : gpiod::line_event::RISING_EDGE;
175
176 if (!requestEvents())
177 {
178 return;
179 }
180 valid = true;
181 }
182};
183} // namespace host_error_monitor::base_gpio_monitor