blob: d917c82fb971955e9d7a172caedc7bd9abdf875e [file] [log] [blame]
/*
// Copyright (c) 2018 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/
#include "PresenceGpio.hpp"
#include <boost/asio/io_context.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <gpiod.hpp>
#include <chrono>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <system_error>
static constexpr unsigned int pollIntervalSec = 1;
PresenceGpio::PresenceGpio(const std::string& deviceType,
const std::string& deviceName,
const std::string& gpioName) :
deviceType(deviceType), deviceName(deviceName), gpioName(gpioName)
{
gpioLine = gpiod::find_line(gpioName);
if (!gpioLine)
{
std::cerr << "Error requesting gpio: " << gpioName << "\n";
throw std::runtime_error("Failed to find GPIO " + gpioName);
}
}
PresenceGpio::~PresenceGpio()
{
gpioLine.release();
}
void PresenceGpio::updateAndTracePresence(int newValue)
{
status = (newValue != 0);
if (status)
{
logPresent(deviceName);
}
else
{
logRemoved(deviceName);
}
}
EventPresenceGpio::EventPresenceGpio(
const std::string& deviceType, const std::string& deviceName,
const std::string& gpioName, bool inverted, boost::asio::io_context& io) :
PresenceGpio(deviceType, deviceName, gpioName), gpioFd(io)
{
try
{
gpioLine.request(
{deviceType + "Sensor", gpiod::line_request::EVENT_BOTH_EDGES,
inverted ? gpiod::line_request::FLAG_ACTIVE_LOW : 0});
updateAndTracePresence(gpioLine.get_value());
}
catch (const std::system_error& e)
{
std::cerr << "Error reading gpio " << gpioName << ": " << e.what()
<< "\n";
throw std::runtime_error("Failed to read GPIO fd " + gpioName);
}
int gpioLineFd = gpioLine.event_get_fd();
if (gpioLineFd < 0)
{
std::cerr << "Failed to get " << gpioName << " fd\n";
throw std::runtime_error("Failed to get GPIO fd " + gpioName);
}
gpioFd.assign(gpioLineFd);
}
void EventPresenceGpio::monitorPresence()
{
std::weak_ptr<EventPresenceGpio> weakRef = weak_from_this();
gpioFd.async_wait(
boost::asio::posix::stream_descriptor::wait_read,
[weakRef](const boost::system::error_code& ec) {
std::shared_ptr<EventPresenceGpio> self = weakRef.lock();
if (!self)
{
std::cerr << "Failed to get lock for eventPresenceGpio: "
<< ec.message() << "\n";
return;
}
if (ec)
{
if (ec != boost::system::errc::bad_file_descriptor)
{
std::cerr
<< "Error on event presence device " << self->deviceName
<< ": " << ec.message() << "\n";
}
return;
}
self->read();
self->monitorPresence();
});
}
void EventPresenceGpio::read()
{
// Read is invoked when an edge event is detected by monitorPresence
gpioLine.event_read();
updateAndTracePresence(gpioLine.get_value());
}
PollingPresenceGpio::PollingPresenceGpio(
const std::string& deviceType, const std::string& deviceName,
const std::string& gpioName, bool inverted, boost::asio::io_context& io) :
PresenceGpio(deviceType, deviceName, gpioName), pollTimer(io)
{
try
{
gpioLine.request(
{deviceType + "Sensor", gpiod::line_request::DIRECTION_INPUT,
inverted ? gpiod::line_request::FLAG_ACTIVE_LOW : 0});
updateAndTracePresence(gpioLine.get_value());
}
catch (const std::system_error& e)
{
std::cerr << "PollingPresenceGpio: Error reading gpio " << gpioName
<< ": " << e.what() << "\n";
status = false;
throw std::runtime_error("Failed to get Polling GPIO fd " + gpioName);
}
}
inline void PollingPresenceGpio::pollTimerHandler(
const std::weak_ptr<PollingPresenceGpio>& weakRef,
const boost::system::error_code& ec)
{
std::shared_ptr<PollingPresenceGpio> self = weakRef.lock();
if (!self)
{
std::cerr << "Failed to get lock for pollingPresenceGpio: "
<< ec.message() << "\n";
return;
}
if (ec)
{
if (ec != boost::system::errc::bad_file_descriptor)
{
std::cerr << "GPIO polling timer failed for " << self->gpioName
<< ": " << ec.what() << ")\n";
}
return;
}
self->monitorPresence();
}
void PollingPresenceGpio::monitorPresence()
{
// Determine if the value has changed
int newStatus = gpioLine.get_value();
if (static_cast<int>(status) != newStatus)
{
updateAndTracePresence(newStatus);
}
std::weak_ptr<PollingPresenceGpio> weakRef = weak_from_this();
pollTimer.expires_after(std::chrono::seconds(pollIntervalSec));
pollTimer.async_wait([weakRef](const boost::system::error_code& ec) {
pollTimerHandler(weakRef, ec);
});
}