1 /*
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
23 #include <iostream>
24 #include <memory>
25 #include <stdexcept>
26 #include <string>
27 #include <system_error>
28
~PresenceGpio()29 PresenceGpio::~PresenceGpio()
30 {
31 gpioLine.release();
32 }
33
updateAndTracePresence()34 void PresenceGpio::updateAndTracePresence()
35 {
36 status = (gpioLine.get_value() != 0);
37 if (status)
38 {
39 logPresent(deviceName);
40 }
41 else
42 {
43 logRemoved(deviceName);
44 }
45 }
46
EventPresenceGpio(const std::string & iDeviceType,const std::string & iDeviceName,const std::string & gpioName,bool inverted,boost::asio::io_context & io)47 EventPresenceGpio::EventPresenceGpio(
48 const std::string& iDeviceType, const std::string& iDeviceName,
49 const std::string& gpioName, bool inverted, boost::asio::io_context& io) :
50 PresenceGpio(iDeviceType, iDeviceName), gpioFd(io)
51 {
52 gpioLine = gpiod::find_line(gpioName);
53 if (!gpioLine)
54 {
55 std::cerr << "Error requesting gpio: " << gpioName << "\n";
56 return;
57 }
58
59 try
60 {
61 gpioLine.request(
62 {deviceType + "Sensor", gpiod::line_request::EVENT_BOTH_EDGES,
63 inverted ? gpiod::line_request::FLAG_ACTIVE_LOW : 0});
64 updateAndTracePresence();
65
66 int gpioLineFd = gpioLine.event_get_fd();
67 if (gpioLineFd < 0)
68 {
69 std::cerr << "Failed to get " << gpioName << " fd\n";
70 throw std::runtime_error("Failed to get GPIO fd " + gpioName);
71 }
72
73 gpioFd.assign(gpioLineFd);
74 }
75 catch (const std::system_error& e)
76 {
77 std::cerr << "Error reading gpio " << gpioName << ": " << e.what()
78 << "\n";
79 return;
80 }
81
82 monitorPresence();
83 }
84
monitorPresence()85 void EventPresenceGpio::monitorPresence()
86 {
87 std::weak_ptr<EventPresenceGpio> weakRef = weak_from_this();
88 gpioFd.async_wait(
89 boost::asio::posix::stream_descriptor::wait_read,
90 [weakRef](const boost::system::error_code& ec) {
91 std::shared_ptr<EventPresenceGpio> self = weakRef.lock();
92 if (!self)
93 {
94 std::cerr << "Failed to get lock for eventPresenceGpio: "
95 << ec.message() << "\n";
96 return;
97 }
98 if (ec)
99 {
100 if (ec != boost::system::errc::bad_file_descriptor)
101 {
102 std::cerr
103 << "Error on event presence device " << self->deviceName
104 << ": " << ec.message() << "\n";
105 }
106 return;
107 }
108 self->read();
109 self->monitorPresence();
110 });
111 }
112
read()113 void EventPresenceGpio::read()
114 {
115 // Read is invoked when an edge event is detected by monitorPresence
116 gpioLine.event_read();
117 updateAndTracePresence();
118 }
119