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 29 PresenceGpio::~PresenceGpio() 30 { 31 gpioLine.release(); 32 } 33 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 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 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 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