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