blob: 6ac6fb9062ca933c7ea842c9885372b36bfd97fa [file] [log] [blame]
Chris Cain83929002024-03-06 14:20:09 -06001/*
2// Copyright (c) 2018 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
17#include "PresenceGpio.hpp"
18
19#include <boost/asio/io_context.hpp>
20#include <boost/asio/posix/stream_descriptor.hpp>
21#include <gpiod.hpp>
George Liue34e1232025-02-20 11:27:48 +080022#include <phosphor-logging/lg2.hpp>
Chris Cain83929002024-03-06 14:20:09 -060023
Chris Cainc45e18f2024-07-24 15:58:00 -050024#include <chrono>
Chris Cain83929002024-03-06 14:20:09 -060025#include <memory>
26#include <stdexcept>
27#include <string>
28#include <system_error>
29
Chris Cainc45e18f2024-07-24 15:58:00 -050030static constexpr unsigned int pollIntervalSec = 1;
31
32PresenceGpio::PresenceGpio(const std::string& deviceType,
33 const std::string& deviceName,
34 const std::string& gpioName) :
35 deviceType(deviceType), deviceName(deviceName), gpioName(gpioName)
36{
37 gpioLine = gpiod::find_line(gpioName);
38 if (!gpioLine)
39 {
George Liue34e1232025-02-20 11:27:48 +080040 lg2::error("Error requesting gpio: '{NAME}'", "NAME", gpioName);
Chris Cainc45e18f2024-07-24 15:58:00 -050041 throw std::runtime_error("Failed to find GPIO " + gpioName);
42 }
43}
44
Chris Cain83929002024-03-06 14:20:09 -060045PresenceGpio::~PresenceGpio()
46{
47 gpioLine.release();
48}
49
Chris Cainc45e18f2024-07-24 15:58:00 -050050void PresenceGpio::updateAndTracePresence(int newValue)
Chris Cain83929002024-03-06 14:20:09 -060051{
Chris Cainc45e18f2024-07-24 15:58:00 -050052 status = (newValue != 0);
Chris Cain83929002024-03-06 14:20:09 -060053 if (status)
54 {
55 logPresent(deviceName);
56 }
57 else
58 {
59 logRemoved(deviceName);
60 }
61}
62
63EventPresenceGpio::EventPresenceGpio(
Chris Cainc45e18f2024-07-24 15:58:00 -050064 const std::string& deviceType, const std::string& deviceName,
Chris Cain83929002024-03-06 14:20:09 -060065 const std::string& gpioName, bool inverted, boost::asio::io_context& io) :
Chris Cainc45e18f2024-07-24 15:58:00 -050066 PresenceGpio(deviceType, deviceName, gpioName), gpioFd(io)
Chris Cain83929002024-03-06 14:20:09 -060067{
Chris Cain83929002024-03-06 14:20:09 -060068 try
69 {
70 gpioLine.request(
71 {deviceType + "Sensor", gpiod::line_request::EVENT_BOTH_EDGES,
72 inverted ? gpiod::line_request::FLAG_ACTIVE_LOW : 0});
Chris Cainc45e18f2024-07-24 15:58:00 -050073 updateAndTracePresence(gpioLine.get_value());
Chris Cain83929002024-03-06 14:20:09 -060074 }
75 catch (const std::system_error& e)
76 {
George Liue34e1232025-02-20 11:27:48 +080077 lg2::error("Error reading gpio '{NAME}': '{ERR}'", "NAME", gpioName,
78 "ERR", e);
Chris Cainc45e18f2024-07-24 15:58:00 -050079 throw std::runtime_error("Failed to read GPIO fd " + gpioName);
Chris Cain83929002024-03-06 14:20:09 -060080 }
81
Chris Cainc45e18f2024-07-24 15:58:00 -050082 int gpioLineFd = gpioLine.event_get_fd();
83 if (gpioLineFd < 0)
84 {
George Liue34e1232025-02-20 11:27:48 +080085 lg2::error("Failed to get '{NAME}' fd", "NAME", gpioName);
Chris Cainc45e18f2024-07-24 15:58:00 -050086 throw std::runtime_error("Failed to get GPIO fd " + gpioName);
87 }
88
89 gpioFd.assign(gpioLineFd);
Chris Cain83929002024-03-06 14:20:09 -060090}
91
92void EventPresenceGpio::monitorPresence()
93{
94 std::weak_ptr<EventPresenceGpio> weakRef = weak_from_this();
95 gpioFd.async_wait(
96 boost::asio::posix::stream_descriptor::wait_read,
97 [weakRef](const boost::system::error_code& ec) {
98 std::shared_ptr<EventPresenceGpio> self = weakRef.lock();
99 if (!self)
100 {
George Liue34e1232025-02-20 11:27:48 +0800101 lg2::error(
102 "Failed to get lock for eventPresenceGpio: '{ERROR_MESSAGE}'",
103 "ERROR_MESSAGE", ec.message());
Chris Cain83929002024-03-06 14:20:09 -0600104 return;
105 }
106 if (ec)
107 {
108 if (ec != boost::system::errc::bad_file_descriptor)
109 {
George Liue34e1232025-02-20 11:27:48 +0800110 lg2::error(
111 "Error on event presence device '{NAME}': '{ERROR_MESSAGE}'",
112 "NAME", self->deviceName, "ERROR_MESSAGE",
113 ec.message());
Chris Cain83929002024-03-06 14:20:09 -0600114 }
115 return;
116 }
117 self->read();
118 self->monitorPresence();
119 });
120}
121
122void EventPresenceGpio::read()
123{
124 // Read is invoked when an edge event is detected by monitorPresence
125 gpioLine.event_read();
Chris Cainc45e18f2024-07-24 15:58:00 -0500126 updateAndTracePresence(gpioLine.get_value());
127}
128
129PollingPresenceGpio::PollingPresenceGpio(
130 const std::string& deviceType, const std::string& deviceName,
131 const std::string& gpioName, bool inverted, boost::asio::io_context& io) :
132 PresenceGpio(deviceType, deviceName, gpioName), pollTimer(io)
133{
134 try
135 {
136 gpioLine.request(
137 {deviceType + "Sensor", gpiod::line_request::DIRECTION_INPUT,
138 inverted ? gpiod::line_request::FLAG_ACTIVE_LOW : 0});
139 updateAndTracePresence(gpioLine.get_value());
140 }
141 catch (const std::system_error& e)
142 {
George Liue34e1232025-02-20 11:27:48 +0800143 lg2::error("PollingPresenceGpio: Error reading gpio '{NAME}': '{ERR}'",
144 "NAME", gpioName, "ERR", e);
Chris Cainc45e18f2024-07-24 15:58:00 -0500145 status = false;
146 throw std::runtime_error("Failed to get Polling GPIO fd " + gpioName);
147 }
148}
149
150inline void PollingPresenceGpio::pollTimerHandler(
151 const std::weak_ptr<PollingPresenceGpio>& weakRef,
152 const boost::system::error_code& ec)
153{
154 std::shared_ptr<PollingPresenceGpio> self = weakRef.lock();
155 if (!self)
156 {
George Liue34e1232025-02-20 11:27:48 +0800157 lg2::error(
158 "Failed to get lock for pollingPresenceGpio: '{ERROR_MESSAGE}'",
159 "ERROR_MESSAGE", ec.message());
Chris Cainc45e18f2024-07-24 15:58:00 -0500160 return;
161 }
162 if (ec)
163 {
164 if (ec != boost::system::errc::bad_file_descriptor)
165 {
George Liue34e1232025-02-20 11:27:48 +0800166 lg2::error(
167 "GPIO polling timer failed for '{NAME}': '{ERROR_MESSAGE}'",
168 "NAME", self->gpioName, "ERROR_MESSAGE", ec.message());
Chris Cainc45e18f2024-07-24 15:58:00 -0500169 }
170 return;
171 }
172 self->monitorPresence();
173}
174
175void PollingPresenceGpio::monitorPresence()
176{
177 // Determine if the value has changed
178 int newStatus = gpioLine.get_value();
179 if (static_cast<int>(status) != newStatus)
180 {
181 updateAndTracePresence(newStatus);
182 }
183
184 std::weak_ptr<PollingPresenceGpio> weakRef = weak_from_this();
185 pollTimer.expires_after(std::chrono::seconds(pollIntervalSec));
186 pollTimer.async_wait([weakRef](const boost::system::error_code& ec) {
187 pollTimerHandler(weakRef, ec);
188 });
Chris Cain83929002024-03-06 14:20:09 -0600189}