blob: d917c82fb971955e9d7a172caedc7bd9abdf875e [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>
22
Chris Cainc45e18f2024-07-24 15:58:00 -050023#include <chrono>
Chris Cain83929002024-03-06 14:20:09 -060024#include <iostream>
25#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 {
40 std::cerr << "Error requesting gpio: " << gpioName << "\n";
41 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 {
77 std::cerr << "Error reading gpio " << gpioName << ": " << e.what()
78 << "\n";
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 {
85 std::cerr << "Failed to get " << gpioName << " fd\n";
86 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 {
101 std::cerr << "Failed to get lock for eventPresenceGpio: "
102 << ec.message() << "\n";
103 return;
104 }
105 if (ec)
106 {
107 if (ec != boost::system::errc::bad_file_descriptor)
108 {
109 std::cerr
110 << "Error on event presence device " << self->deviceName
111 << ": " << ec.message() << "\n";
112 }
113 return;
114 }
115 self->read();
116 self->monitorPresence();
117 });
118}
119
120void EventPresenceGpio::read()
121{
122 // Read is invoked when an edge event is detected by monitorPresence
123 gpioLine.event_read();
Chris Cainc45e18f2024-07-24 15:58:00 -0500124 updateAndTracePresence(gpioLine.get_value());
125}
126
127PollingPresenceGpio::PollingPresenceGpio(
128 const std::string& deviceType, const std::string& deviceName,
129 const std::string& gpioName, bool inverted, boost::asio::io_context& io) :
130 PresenceGpio(deviceType, deviceName, gpioName), pollTimer(io)
131{
132 try
133 {
134 gpioLine.request(
135 {deviceType + "Sensor", gpiod::line_request::DIRECTION_INPUT,
136 inverted ? gpiod::line_request::FLAG_ACTIVE_LOW : 0});
137 updateAndTracePresence(gpioLine.get_value());
138 }
139 catch (const std::system_error& e)
140 {
141 std::cerr << "PollingPresenceGpio: Error reading gpio " << gpioName
142 << ": " << e.what() << "\n";
143 status = false;
144 throw std::runtime_error("Failed to get Polling GPIO fd " + gpioName);
145 }
146}
147
148inline void PollingPresenceGpio::pollTimerHandler(
149 const std::weak_ptr<PollingPresenceGpio>& weakRef,
150 const boost::system::error_code& ec)
151{
152 std::shared_ptr<PollingPresenceGpio> self = weakRef.lock();
153 if (!self)
154 {
155 std::cerr << "Failed to get lock for pollingPresenceGpio: "
156 << ec.message() << "\n";
157 return;
158 }
159 if (ec)
160 {
161 if (ec != boost::system::errc::bad_file_descriptor)
162 {
163 std::cerr << "GPIO polling timer failed for " << self->gpioName
164 << ": " << ec.what() << ")\n";
165 }
166 return;
167 }
168 self->monitorPresence();
169}
170
171void PollingPresenceGpio::monitorPresence()
172{
173 // Determine if the value has changed
174 int newStatus = gpioLine.get_value();
175 if (static_cast<int>(status) != newStatus)
176 {
177 updateAndTracePresence(newStatus);
178 }
179
180 std::weak_ptr<PollingPresenceGpio> weakRef = weak_from_this();
181 pollTimer.expires_after(std::chrono::seconds(pollIntervalSec));
182 pollTimer.async_wait([weakRef](const boost::system::error_code& ec) {
183 pollTimerHandler(weakRef, ec);
184 });
Chris Cain83929002024-03-06 14:20:09 -0600185}