
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 <boost/asio/basic_io_object.hpp> #include <boost/asio/ip/udp.hpp> 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<gpio_interrupt_service> { 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 <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <fcntl.h> 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<socket_service_type>(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!