On Tue, 2015-03-10 at 20:35 +0100, svante karlsson wrote:
If you got it working by wrapping the file descriptor - post it and
I'll give it a shot on tidying it up.
Here's what I've got. It works pretty well so far.
/////////////////////////
// gpio_interrupt.hpp: //
/////////////////////////
#ifndef GPIO_INTERRUPT_HPP
#define GPIO_INTERRUPT_HPP
#include
#include
class gpio_interrupt_service : public boost::asio::io_service::service {
private:
typedef boost::asio::ip::udp::socket socket_type;
typedef socket_type::service_type socket_service_type;
typedef socket_type::implementation_type socket_implementation_type;
public:
class implementation_type {
private:
friend class gpio_interrupt_service;
socket_implementation_type underlying_impl_;
};
static boost::asio::io_service::id id;
gpio_interrupt_service(boost::asio::io_service &io_service);
void construct(implementation_type &impl);
void destroy(implementation_type &impl);
boost::system::error_code open(implementation_type &impl, unsigned int
number, boost::system::error_code &ec);
boost::system::error_code close(implementation_type &impl,
boost::system::error_code &ec);
template<typename Handler>
void async_wait(implementation_type &impl, Handler handler)
{
bound_handler<Handler> bound(*this, impl, handler);
socket_service_.async_receive(impl.underlying_impl_,
boost::asio::null_buffers(), socket_type::message_out_of_band, bound);
}
boost::system::error_code cancel(implementation_type &impl,
boost::system::error_code &ec);
private:
template<typename Handler>
class bound_handler {
public:
bound_handler(gpio_interrupt_service &service, implementation_type
&impl, Handler handler) :
service_(service),
impl_(impl),
handler_(std::move(handler)) {}
bound_handler(const bound_handler &other) :
service_(other.service_),
impl_(other.impl_),
handler_(other.handler_) {}
bound_handler(bound_handler &&other) :
service_(other.service_),
impl_(other.impl_),
handler_(std::move(other.handler_)) {}
void operator()(const boost::system::error_code &ec, std::size_t
bytes_transferred)
{
service_.reset_descriptor(impl_, ec);
handler_(ec);
}
private:
gpio_interrupt_service &service_;
implementation_type &impl_;
Handler handler_;
};
socket_service_type &socket_service_;
virtual void shutdown_service();
void reset_descriptor(implementation_type &impl, const
boost::system::error_code &ec);
};
class gpio_interrupt : public
boost::asio::basic_io_object {
public:
gpio_interrupt(boost::asio::io_service &io_service);
void open(unsigned int number);
boost::system::error_code open(unsigned int number,
boost::system::error_code &ec);
void close();
boost::system::error_code close(boost::system::error_code &ec);
template<typename Handler>
void async_wait(Handler &&handler)
{
this->get_service().async_wait(this->get_implementation(),
std::forward<Handler>(handler));
}
void cancel();
boost::system::error_code cancel(boost::system::error_code &ec);
};
#endif // GPIO_INTERRUPT_HPP
/////////////////////////
// gpio_interrupt.cpp: //
/////////////////////////
#include "gpio_interrupt.hpp"
#include
#include
#include
boost::asio::io_service::id gpio_interrupt_service::id;
gpio_interrupt_service::gpio_interrupt_service(boost::asio::io_service
&io_service) :
service(io_service),
socket_service_(boost::asio::use_service(io_service))
{
}
void gpio_interrupt_service::construct(implementation_type &impl)
{
socket_service_.construct(impl.underlying_impl_);
}
void gpio_interrupt_service::destroy(implementation_type &impl)
{
socket_service_.destroy(impl.underlying_impl_);
}
boost::system::error_code
gpio_interrupt_service::open(implementation_type &impl, unsigned int
number, boost::system::error_code &ec)
{
std::ostringstream filename;
filename << "/sys/class/gpio/gpio" << number << "/value";
int fd = ::open(filename.str().c_str(), O_RDONLY | O_NONBLOCK);
if (fd < 0) {
ec = boost::system::error_code(errno,
boost::asio::error::get_system_category());
return ec;
}
reset_descriptor(impl, ec);
return socket_service_.assign(impl.underlying_impl_,
boost::asio::ip::udp::v4(), fd, ec);
}
boost::system::error_code
gpio_interrupt_service::close(implementation_type &impl,
boost::system::error_code &ec)
{
return socket_service_.close(impl.underlying_impl_, ec);
}
boost::system::error_code
gpio_interrupt_service::cancel(implementation_type &impl,
boost::system::error_code &ec)
{
return socket_service_.cancel(impl.underlying_impl_, ec);
}
void gpio_interrupt_service::shutdown_service()
{
}
void gpio_interrupt_service::reset_descriptor(implementation_type &impl,
const boost::system::error_code &ec)
{
if (ec)
return;
int fd = socket_service_.native_handle(impl.underlying_impl_);
lseek(fd, 0, SEEK_SET);
char buf[2];
read(fd, buf, 2);
}
gpio_interrupt::gpio_interrupt(boost::asio::io_service &io_service) :
basic_io_object(io_service)
{
}
void gpio_interrupt::open(unsigned int number)
{
boost::system::error_code ec;
this->get_service().open(this->get_implementation(), number, ec);
boost::asio::detail::throw_error(ec, "open");
}
boost::system::error_code gpio_interrupt::open(unsigned int number,
boost::system::error_code &ec)
{
return this->get_service().open(this->get_implementation(), number,
ec);
}
void gpio_interrupt::close()
{
boost::system::error_code ec;
this->get_service().close(this->get_implementation(), ec);
boost::asio::detail::throw_error(ec, "close");
}
boost::system::error_code
gpio_interrupt::close(boost::system::error_code &ec)
{
return this->get_service().close(this->get_implementation(), ec);
}
void gpio_interrupt::cancel()
{
boost::system::error_code ec;
this->get_service().cancel(this->get_implementation(), ec);
boost::asio::detail::throw_error(ec, "cancel");
}
boost::system::error_code
gpio_interrupt::cancel(boost::system::error_code &ec)
{
return this->get_service().cancel(this->get_implementation(), ec);
}
/////////////////////////////////
OT: Bjorn, I took a look at your Aware project, and it actually looks
like something I might be able to use. Thank you!