mirror of
https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
synced 2026-10-25 12:39:18 +03:00
bindings: implement C++ bindings
Wrap the C API in a set of C++ classes which allow to use all libgpiod functionalities in an object-oriented manner. Include simplified reimplementations of gpio-tools and a set of tests/examples showing how to use the C++ interface. The C++ API is fully documented in doxygen. Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
This commit is contained in:
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
!.gitignore
|
||||
libgpiod.la
|
||||
libgpiodcxx.la
|
||||
libtools-common.la
|
||||
gpiodetect
|
||||
gpioinfo
|
||||
@@ -7,6 +8,13 @@ gpioget
|
||||
gpioset
|
||||
gpiomon
|
||||
gpiofind
|
||||
gpio_cxx_tests
|
||||
gpiodetectcxx
|
||||
gpiofindcxx
|
||||
gpiogetcxx
|
||||
gpioinfocxx
|
||||
gpiomoncxx
|
||||
gpiosetcxx
|
||||
*.o
|
||||
*.lo
|
||||
doc
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
SUBDIRS = include src
|
||||
SUBDIRS = include src bindings
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libgpiod.pc
|
||||
@@ -23,7 +23,9 @@ endif
|
||||
if HAS_DOXYGEN
|
||||
|
||||
doc:
|
||||
@(cat Doxyfile; echo PROJECT_NUMBER = $(VERSION_STR)) | doxygen -
|
||||
@(cat Doxyfile; \
|
||||
echo PROJECT_NUMBER = $(VERSION_STR); \
|
||||
echo INPUT += bindings/cxx/gpiod.hpp) | doxygen -
|
||||
.PHONY: doc
|
||||
|
||||
EXTRA_DIST = Doxyfile
|
||||
|
||||
16
bindings/Makefile.am
Normal file
16
bindings/Makefile.am
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
# your option) any later version.
|
||||
#
|
||||
|
||||
SUBDIRS = .
|
||||
|
||||
if WITH_BINDINGS_CXX
|
||||
|
||||
SUBDIRS += cxx
|
||||
|
||||
endif
|
||||
19
bindings/cxx/Makefile.am
Normal file
19
bindings/cxx/Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
#
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
# your option) any later version.
|
||||
#
|
||||
|
||||
lib_LTLIBRARIES = libgpiodcxx.la
|
||||
libgpiodcxx_la_SOURCES = chip.cpp iter.cpp line.cpp line_bulk.cpp
|
||||
libgpiodcxx_la_CPPFLAGS = -Wall -Wextra -g -std=gnu++11
|
||||
libgpiodcxx_la_CPPFLAGS += -fvisibility=hidden -I$(top_srcdir)/include/
|
||||
libgpiodcxx_la_LDFLAGS = -version-number $(subst .,:,$(PACKAGE_VERSION))
|
||||
libgpiodcxx_la_LDFLAGS += -lgpiod -L$(top_builddir)/src/lib
|
||||
|
||||
include_HEADERS = gpiod.hpp
|
||||
|
||||
SUBDIRS = . examples
|
||||
192
bindings/cxx/chip.cpp
Normal file
192
bindings/cxx/chip.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
#include <gpiod.hpp>
|
||||
|
||||
#include <system_error>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <map>
|
||||
|
||||
namespace gpiod {
|
||||
|
||||
namespace {
|
||||
|
||||
::gpiod_chip* open_lookup(const ::std::string& device)
|
||||
{
|
||||
return ::gpiod_chip_open_lookup(device.c_str());
|
||||
}
|
||||
|
||||
::gpiod_chip* open_by_path(const ::std::string& device)
|
||||
{
|
||||
return ::gpiod_chip_open(device.c_str());
|
||||
}
|
||||
|
||||
::gpiod_chip* open_by_name(const ::std::string& device)
|
||||
{
|
||||
return ::gpiod_chip_open_by_name(device.c_str());
|
||||
}
|
||||
|
||||
::gpiod_chip* open_by_label(const ::std::string& device)
|
||||
{
|
||||
return ::gpiod_chip_open_by_label(device.c_str());
|
||||
}
|
||||
|
||||
::gpiod_chip* open_by_number(const ::std::string& device)
|
||||
{
|
||||
return ::gpiod_chip_open_by_number(::std::stoul(device));
|
||||
}
|
||||
|
||||
using open_func = ::std::function<::gpiod_chip* (const ::std::string&)>;
|
||||
|
||||
const ::std::map<int, open_func> open_funcs = {
|
||||
{ chip::OPEN_LOOKUP, open_lookup, },
|
||||
{ chip::OPEN_BY_PATH, open_by_path, },
|
||||
{ chip::OPEN_BY_NAME, open_by_name, },
|
||||
{ chip::OPEN_BY_LABEL, open_by_label, },
|
||||
{ chip::OPEN_BY_NUMBER, open_by_number, },
|
||||
};
|
||||
|
||||
void chip_deleter(::gpiod_chip* chip)
|
||||
{
|
||||
::gpiod_chip_close(chip);
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
chip::chip(const ::std::string& device, int how)
|
||||
: _m_chip()
|
||||
{
|
||||
this->open(device, how);
|
||||
}
|
||||
|
||||
chip::chip(::gpiod_chip* chip)
|
||||
: _m_chip(chip, chip_deleter)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void chip::open(const ::std::string& device, int how)
|
||||
{
|
||||
auto func = open_funcs.at(how);
|
||||
|
||||
::gpiod_chip *chip = func(device);
|
||||
if (!chip)
|
||||
throw ::std::system_error(errno, ::std::system_category(),
|
||||
"cannot open GPIO device " + device);
|
||||
|
||||
this->_m_chip.reset(chip, chip_deleter);
|
||||
}
|
||||
|
||||
void chip::reset(void) noexcept
|
||||
{
|
||||
this->_m_chip.reset();
|
||||
}
|
||||
|
||||
::std::string chip::name(void) const
|
||||
{
|
||||
this->throw_if_noref();
|
||||
|
||||
const char* name = ::gpiod_chip_name(this->_m_chip.get());
|
||||
|
||||
return ::std::move(name ? ::std::string(name) : ::std::string());
|
||||
}
|
||||
|
||||
::std::string chip::label(void) const
|
||||
{
|
||||
this->throw_if_noref();
|
||||
|
||||
const char* label = ::gpiod_chip_label(this->_m_chip.get());
|
||||
|
||||
return ::std::move(label ? ::std::string(label) : ::std::string());
|
||||
}
|
||||
|
||||
unsigned int chip::num_lines(void) const
|
||||
{
|
||||
this->throw_if_noref();
|
||||
|
||||
return ::gpiod_chip_num_lines(this->_m_chip.get());
|
||||
}
|
||||
|
||||
line chip::get_line(unsigned int offset) const
|
||||
{
|
||||
this->throw_if_noref();
|
||||
|
||||
if (offset >= this->num_lines())
|
||||
throw ::std::out_of_range("line offset greater than the number of lines");
|
||||
|
||||
::gpiod_line* line_handle = ::gpiod_chip_get_line(this->_m_chip.get(), offset);
|
||||
if (!line_handle)
|
||||
throw ::std::system_error(errno, ::std::system_category(),
|
||||
"error getting GPIO line from chip");
|
||||
|
||||
return ::std::move(line(line_handle, *this));
|
||||
}
|
||||
|
||||
line chip::find_line(const ::std::string& name) const
|
||||
{
|
||||
this->throw_if_noref();
|
||||
|
||||
::gpiod_line* handle = ::gpiod_chip_find_line(this->_m_chip.get(), name.c_str());
|
||||
if (!handle && errno != ENOENT)
|
||||
throw ::std::system_error(errno, ::std::system_category(),
|
||||
"error looking up GPIO line by name");
|
||||
|
||||
return ::std::move(handle ? line(handle, *this) : line());
|
||||
}
|
||||
|
||||
line_bulk chip::get_lines(const ::std::vector<unsigned int>& offsets) const
|
||||
{
|
||||
line_bulk lines;
|
||||
|
||||
for (auto& it: offsets)
|
||||
lines.add(this->get_line(it));
|
||||
|
||||
return ::std::move(lines);
|
||||
}
|
||||
|
||||
line_bulk chip::find_lines(const ::std::vector<::std::string>& names) const
|
||||
{
|
||||
line_bulk lines;
|
||||
|
||||
for (auto& it: names)
|
||||
lines.add(this->find_line(it));
|
||||
|
||||
return ::std::move(lines);
|
||||
}
|
||||
|
||||
bool chip::operator==(const chip& rhs) const noexcept
|
||||
{
|
||||
return this->_m_chip.get() == rhs._m_chip.get();
|
||||
}
|
||||
|
||||
bool chip::operator!=(const chip& rhs) const noexcept
|
||||
{
|
||||
return this->_m_chip.get() != rhs._m_chip.get();
|
||||
}
|
||||
|
||||
chip::operator bool(void) const noexcept
|
||||
{
|
||||
return this->_m_chip.get() != nullptr;
|
||||
}
|
||||
|
||||
bool chip::operator!(void) const noexcept
|
||||
{
|
||||
return this->_m_chip.get() == nullptr;
|
||||
}
|
||||
|
||||
void chip::throw_if_noref(void) const
|
||||
{
|
||||
if (!this->_m_chip.get())
|
||||
throw ::std::logic_error("object not associated with an open GPIO chip");
|
||||
}
|
||||
|
||||
} /* namespace gpiod */
|
||||
34
bindings/cxx/examples/Makefile.am
Normal file
34
bindings/cxx/examples/Makefile.am
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
# your option) any later version.
|
||||
#
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/bindings/cxx/ -I$(top_srcdir)/include
|
||||
AM_CPPFLAGS += -Wall -Wextra -g -std=gnu++11
|
||||
AM_LDFLAGS = -lgpiodcxx -L$(top_builddir)/bindings/cxx/
|
||||
|
||||
check_PROGRAMS = gpio_cxx_tests \
|
||||
gpiodetectcxx \
|
||||
gpiofindcxx \
|
||||
gpiogetcxx \
|
||||
gpioinfocxx \
|
||||
gpiomoncxx \
|
||||
gpiosetcxx
|
||||
|
||||
gpio_cxx_tests_SOURCES = gpio_cxx_tests.cpp
|
||||
|
||||
gpiodetectcxx_SOURCES = gpiodetectcxx.cpp
|
||||
|
||||
gpiofindcxx_SOURCES = gpiofindcxx.cpp
|
||||
|
||||
gpiogetcxx_SOURCES = gpiogetcxx.cpp
|
||||
|
||||
gpioinfocxx_SOURCES = gpioinfocxx.cpp
|
||||
|
||||
gpiomoncxx_SOURCES = gpiomoncxx.cpp
|
||||
|
||||
gpiosetcxx_SOURCES = gpiosetcxx.cpp
|
||||
161
bindings/cxx/examples/gpio_cxx_tests.cpp
Normal file
161
bindings/cxx/examples/gpio_cxx_tests.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
/* Misc tests/examples of the C++ API. */
|
||||
|
||||
#include <gpiod.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
|
||||
using test_func = ::std::function<void (void)>;
|
||||
|
||||
::std::vector<::std::pair<::std::string, test_func>> test_funcs;
|
||||
|
||||
struct test_case
|
||||
{
|
||||
test_case(const ::std::string& name, test_func& func)
|
||||
{
|
||||
test_funcs.push_back(::std::make_pair(name, func));
|
||||
}
|
||||
};
|
||||
|
||||
#define TEST_CASE(_func) \
|
||||
test_func _test_func_##_func(_func); \
|
||||
test_case _test_case_##_func(#_func, _test_func_##_func)
|
||||
|
||||
void chip_info(void)
|
||||
{
|
||||
::gpiod::chip chip("gpiochip0");
|
||||
|
||||
::std::cout << "chip name: " << chip.name() << ::std::endl;
|
||||
::std::cout << "chip label: " << chip.label() << ::std::endl;
|
||||
::std::cout << "number of lines " << chip.num_lines() << ::std::endl;
|
||||
}
|
||||
TEST_CASE(chip_info);
|
||||
|
||||
void chip_open_different_modes(void)
|
||||
{
|
||||
::gpiod::chip by_name("gpiochip0", ::gpiod::chip::OPEN_BY_NAME);
|
||||
::gpiod::chip by_path("/dev/gpiochip0", ::gpiod::chip::OPEN_BY_PATH);
|
||||
::gpiod::chip by_label("gpio-mockup-A", ::gpiod::chip::OPEN_BY_LABEL);
|
||||
::gpiod::chip by_number("0", ::gpiod::chip::OPEN_BY_NUMBER);
|
||||
}
|
||||
TEST_CASE(chip_open_different_modes);
|
||||
|
||||
void chip_line_ops(void)
|
||||
{
|
||||
::gpiod::chip chip("gpiochip0");
|
||||
|
||||
::gpiod::line line = chip.get_line(3);
|
||||
::std::cout << "Got line by offset: " << line.offset() << ::std::endl;
|
||||
|
||||
line = chip.find_line("gpio-mockup-A-4");
|
||||
::std::cout << "Got line by name: " << line.name() << ::std::endl;
|
||||
|
||||
::gpiod::line_bulk lines = chip.get_lines({ 1, 2, 3, 6, 6 });
|
||||
::std::cout << "Got multiple lines by offset: ";
|
||||
for (auto& it: lines)
|
||||
::std::cout << it.offset() << " ";
|
||||
::std::cout << ::std::endl;
|
||||
|
||||
lines = chip.find_lines({ "gpio-mockup-A-1", "gpio-mockup-A-4", "gpio-mockup-A-7" });
|
||||
::std::cout << "Got multiple lines by name: ";
|
||||
for (auto& it: lines)
|
||||
::std::cout << it.name() << " ";
|
||||
::std::cout << ::std::endl;
|
||||
}
|
||||
TEST_CASE(chip_line_ops);
|
||||
|
||||
void line_info(void)
|
||||
{
|
||||
::gpiod::chip chip("gpiochip0");
|
||||
::gpiod::line line = chip.get_line(2);
|
||||
|
||||
::std::cout << "line offset: " << line.offset() << ::std::endl;
|
||||
::std::cout << "line name: " << line.name() << ::std::endl;
|
||||
::std::cout << "line direction: "
|
||||
<< (line.direction() == ::gpiod::line::DIRECTION_INPUT ?
|
||||
"input" : "output") << ::std::endl;
|
||||
}
|
||||
TEST_CASE(line_info);
|
||||
|
||||
void empty_objects(void)
|
||||
{
|
||||
::std::cout << "Are initialized line & chip objects 'false'?" << ::std::endl;
|
||||
|
||||
::gpiod::line line;
|
||||
if (line)
|
||||
throw ::std::logic_error("line built with a default constructor should be 'false'");
|
||||
|
||||
::gpiod::chip chip;
|
||||
if (chip)
|
||||
throw ::std::logic_error("chip built with a default constructor should be 'false'");
|
||||
|
||||
::std::cout << "YES" << ::std::endl;
|
||||
}
|
||||
TEST_CASE(empty_objects);
|
||||
|
||||
void line_bulk_iterator(void)
|
||||
{
|
||||
::std::cout << "Checking line_bulk iterators" << ::std::endl;
|
||||
|
||||
::gpiod::chip chip("gpiochip0");
|
||||
::gpiod::line_bulk bulk = chip.get_lines({ 0, 1, 2, 3, 4 });
|
||||
|
||||
for (auto& it: bulk)
|
||||
::std::cout << it.name() << ::std::endl;
|
||||
|
||||
::std::cout << "DONE" << ::std::endl;
|
||||
}
|
||||
TEST_CASE(line_bulk_iterator);
|
||||
|
||||
void single_line_test(void)
|
||||
{
|
||||
const ::std::string line_name("gpio-mockup-A-4");
|
||||
|
||||
::std::cout << "Looking up a GPIO line by name (" << line_name << ")" << ::std::endl;
|
||||
|
||||
::gpiod::line line = ::gpiod::find_line(line_name);
|
||||
if (!line)
|
||||
throw ::std::runtime_error(line_name + " line not found");
|
||||
|
||||
::std::cout << "Requesting a single line" << ::std::endl;
|
||||
|
||||
::gpiod::line_request conf;
|
||||
conf.consumer = "gpiod_cxx_tests";
|
||||
conf.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
|
||||
|
||||
line.request(conf, 1);
|
||||
::std::cout << "Reading value" << ::std::endl;
|
||||
::std::cout << line.get_value() << ::std::endl;
|
||||
::std::cout << "Changing value to 0" << ::std::endl;
|
||||
line.set_value(0);
|
||||
::std::cout << "Reading value again" << ::std::endl;
|
||||
::std::cout << line.get_value() << ::std::endl;
|
||||
}
|
||||
TEST_CASE(single_line_test);
|
||||
|
||||
} /* namespace */
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
for (auto& it: test_funcs) {
|
||||
::std::cout << "=================================================" << ::std::endl;
|
||||
::std::cout << it.first << ":\n" << ::std::endl;
|
||||
it.second();
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
33
bindings/cxx/examples/gpiodetectcxx.cpp
Normal file
33
bindings/cxx/examples/gpiodetectcxx.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
/* C++ reimplementation of the gpiodetect tool. */
|
||||
|
||||
#include <gpiod.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 1) {
|
||||
::std::cerr << "usage: " << argv[0] << ::std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (auto& it: ::gpiod::make_chip_iterator()) {
|
||||
::std::cout << it.name() << " ["
|
||||
<< it.label() << "] ("
|
||||
<< it.num_lines() << " lines)" << ::std::endl;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
33
bindings/cxx/examples/gpiofindcxx.cpp
Normal file
33
bindings/cxx/examples/gpiofindcxx.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
/* C++ reimplementation of the gpiofind tool. */
|
||||
|
||||
#include <gpiod.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
::std::cerr << "usage: " << argv[0] << " <line name>" << ::std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
::gpiod::line line = ::gpiod::find_line(argv[1]);
|
||||
if (!line)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
::std::cout << line.get_chip().name() << " " << line.offset() << ::std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
47
bindings/cxx/examples/gpiogetcxx.cpp
Normal file
47
bindings/cxx/examples/gpiogetcxx.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
/* Simplified C++ reimplementation of the gpioget tool. */
|
||||
|
||||
#include <gpiod.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
::std::cerr << "usage: " << argv[0] << " <chip> <line_offset0> ..." << ::std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
::std::vector<unsigned int> offsets;
|
||||
|
||||
for (int i = 2; i < argc; i++)
|
||||
offsets.push_back(::std::stoul(argv[i]));
|
||||
|
||||
::gpiod::chip chip(argv[1]);
|
||||
auto lines = chip.get_lines(offsets);
|
||||
|
||||
lines.request({
|
||||
argv[0],
|
||||
::gpiod::line_request::DIRECTION_INPUT,
|
||||
0
|
||||
});
|
||||
|
||||
auto vals = lines.get_values();
|
||||
|
||||
for (auto& it: vals)
|
||||
::std::cout << it << ' ';
|
||||
::std::cout << ::std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
55
bindings/cxx/examples/gpioinfocxx.cpp
Normal file
55
bindings/cxx/examples/gpioinfocxx.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
/* Simplified C++ reimplementation of the gpioinfo tool. */
|
||||
|
||||
#include <gpiod.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 1) {
|
||||
::std::cerr << "usage: " << argv[0] << ::std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (auto& cit: ::gpiod::make_chip_iterator()) {
|
||||
::std::cout << cit.name() << " - " << cit.num_lines() << " lines:" << ::std::endl;
|
||||
|
||||
for (auto& lit: ::gpiod::line_iterator(cit)) {
|
||||
::std::cout << "\tline ";
|
||||
::std::cout.width(3);
|
||||
::std::cout << lit.offset() << ": ";
|
||||
|
||||
::std::cout.width(12);
|
||||
::std::cout << (lit.name().empty() ? "unnamed" : lit.name());
|
||||
::std::cout << " ";
|
||||
|
||||
::std::cout.width(12);
|
||||
::std::cout << (lit.consumer().empty() ? "unused" : lit.consumer());
|
||||
::std::cout << " ";
|
||||
|
||||
::std::cout.width(8);
|
||||
::std::cout << (lit.direction() == ::gpiod::line::DIRECTION_INPUT ? "input" : "output");
|
||||
::std::cout << " ";
|
||||
|
||||
::std::cout.width(10);
|
||||
::std::cout << (lit.active_state() == ::gpiod::line::ACTIVE_LOW
|
||||
? "active-low" : "active-high");
|
||||
|
||||
::std::cout << ::std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
73
bindings/cxx/examples/gpiomoncxx.cpp
Normal file
73
bindings/cxx/examples/gpiomoncxx.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
/* Simplified C++ reimplementation of the gpiomon tool. */
|
||||
|
||||
#include <gpiod.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
|
||||
void print_event(const ::gpiod::line_event& event)
|
||||
{
|
||||
if (event.event_type == ::gpiod::line_event::RISING_EDGE)
|
||||
::std::cout << " RISING EDGE";
|
||||
else if (event.event_type == ::gpiod::line_event::FALLING_EDGE)
|
||||
::std::cout << "FALLING EDGE";
|
||||
else
|
||||
throw ::std::logic_error("invalid event type");
|
||||
|
||||
::std::cout << " ";
|
||||
|
||||
::std::cout << ::std::chrono::duration_cast<::std::chrono::seconds>(event.timestamp).count();
|
||||
::std::cout << ".";
|
||||
::std::cout << event.timestamp.count() % 1000000000;
|
||||
|
||||
::std::cout << " line: " << event.source.offset();
|
||||
|
||||
::std::cout << ::std::endl;
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
::std::cout << "usage: " << argv[0] << " <chip> <offset0> ..." << ::std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
::std::vector<unsigned int> offsets;
|
||||
offsets.reserve(argc);
|
||||
for (int i = 2; i < argc; i++)
|
||||
offsets.push_back(::std::stoul(argv[i]));
|
||||
|
||||
::gpiod::chip chip(argv[1]);
|
||||
auto lines = chip.get_lines(offsets);
|
||||
|
||||
lines.request({
|
||||
argv[0],
|
||||
::gpiod::line_request::EVENT_BOTH_EDGES,
|
||||
0,
|
||||
});
|
||||
|
||||
for (;;) {
|
||||
auto events = lines.event_wait(::std::chrono::nanoseconds(1000000000));
|
||||
if (events) {
|
||||
for (auto& it: events)
|
||||
print_event(it.event_read());
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
56
bindings/cxx/examples/gpiosetcxx.cpp
Normal file
56
bindings/cxx/examples/gpiosetcxx.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
/* Simplified C++ reimplementation of the gpioset tool. */
|
||||
|
||||
#include <gpiod.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
::std::cerr << "usage: " << argv[0] << " <chip> <line_offset0>=<value0> ..." << ::std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
::std::vector<unsigned int> offsets;
|
||||
::std::vector<int> values;
|
||||
|
||||
for (int i = 2; i < argc; i++) {
|
||||
::std::string arg(argv[i]);
|
||||
|
||||
size_t pos = arg.find('=');
|
||||
|
||||
::std::string offset(arg.substr(0, pos));
|
||||
::std::string value(arg.substr(pos + 1, ::std::string::npos));
|
||||
|
||||
if (offset.empty() || value.empty())
|
||||
throw ::std::invalid_argument("invalid argument: " + ::std::string(argv[i]));
|
||||
|
||||
offsets.push_back(::std::stoul(offset));
|
||||
values.push_back(::std::stoul(value));
|
||||
}
|
||||
|
||||
::gpiod::chip chip(argv[1]);
|
||||
auto lines = chip.get_lines(offsets);
|
||||
|
||||
lines.request({
|
||||
argv[0],
|
||||
::gpiod::line_request::DIRECTION_OUTPUT,
|
||||
0
|
||||
}, values);
|
||||
|
||||
::std::cin.get();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
959
bindings/cxx/gpiod.hpp
Normal file
959
bindings/cxx/gpiod.hpp
Normal file
@@ -0,0 +1,959 @@
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef __LIBGPIOD_GPIOD_CXX_HPP__
|
||||
#define __LIBGPIOD_GPIOD_CXX_HPP__
|
||||
|
||||
#include <gpiod.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <bitset>
|
||||
#include <chrono>
|
||||
|
||||
namespace gpiod {
|
||||
|
||||
class line;
|
||||
class line_bulk;
|
||||
class line_event;
|
||||
class line_iterator;
|
||||
class chip_iterator;
|
||||
|
||||
/**
|
||||
* @defgroup __gpiod_cxx__ C++ bindings
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Represents a GPIO chip.
|
||||
*
|
||||
* Internally this class holds a smart pointer to an open GPIO chip descriptor.
|
||||
* Multiple objects of this class can reference the same chip. The chip is
|
||||
* closed and all resources freed when the last reference is dropped.
|
||||
*/
|
||||
class chip
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Default constructor. Creates an empty GPIO chip object.
|
||||
*/
|
||||
GPIOD_API chip(void) = default;
|
||||
|
||||
/**
|
||||
* @brief Constructor. Opens the chip using chip::open.
|
||||
* @param device String describing the GPIO chip.
|
||||
* @param how Indicates how the chip should be opened.
|
||||
*/
|
||||
GPIOD_API chip(const ::std::string& device, int how = OPEN_LOOKUP);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor. References the object held by other.
|
||||
* @param other Other chip object.
|
||||
*/
|
||||
GPIOD_API chip(const chip& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move constructor. References the object held by other.
|
||||
* @param other Other chip object.
|
||||
*/
|
||||
GPIOD_API chip(chip&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Assignment operator. References the object held by other.
|
||||
* @param other Other chip object.
|
||||
* @return Reference to this object.
|
||||
*/
|
||||
GPIOD_API chip& operator=(const chip& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator. References the object held by other.
|
||||
* @param other Other chip object.
|
||||
* @return Reference to this object.
|
||||
*/
|
||||
GPIOD_API chip& operator=(chip&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor. Unreferences the internal chip object.
|
||||
*/
|
||||
GPIOD_API ~chip(void) = default;
|
||||
|
||||
/**
|
||||
* @brief Open a GPIO chip.
|
||||
* @param device String describing the GPIO chip.
|
||||
* @param how Indicates how the chip should be opened.
|
||||
*
|
||||
* If the object already holds a reference to an open chip, it will be
|
||||
* closed and the reference reset.
|
||||
*/
|
||||
GPIOD_API void open(const ::std::string &device, int how = OPEN_LOOKUP);
|
||||
|
||||
/**
|
||||
* @brief Reset the internal smart pointer owned by this object.
|
||||
*/
|
||||
GPIOD_API void reset(void) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Return the name of the chip held by this object.
|
||||
* @return Name of the GPIO chip.
|
||||
*/
|
||||
GPIOD_API ::std::string name(void) const;
|
||||
|
||||
/**
|
||||
* @brief Return the label of the chip held by this object.
|
||||
* @return Label of the GPIO chip.
|
||||
*/
|
||||
GPIOD_API ::std::string label(void) const;
|
||||
|
||||
/**
|
||||
* @brief Return the number of lines exposed by this chip.
|
||||
* @return Number of lines.
|
||||
*/
|
||||
GPIOD_API unsigned int num_lines(void) const;
|
||||
|
||||
/**
|
||||
* @brief Get the line exposed by this chip at given offset.
|
||||
* @param offset Offset of the line.
|
||||
* @return Line object.
|
||||
*/
|
||||
GPIOD_API line get_line(unsigned int offset) const;
|
||||
|
||||
/**
|
||||
* @brief Get the line exposed by this chip by name.
|
||||
* @param name Line name.
|
||||
* @return Line object.
|
||||
*/
|
||||
GPIOD_API line find_line(const ::std::string& name) const;
|
||||
|
||||
/**
|
||||
* @brief Get a set of lines exposed by this chip at given offsets.
|
||||
* @param offsets Vector of line offsets.
|
||||
* @return Set of lines held by a line_bulk object.
|
||||
*/
|
||||
GPIOD_API line_bulk get_lines(const ::std::vector<unsigned int>& offsets) const;
|
||||
|
||||
/**
|
||||
* @brief Get a set of lines exposed by this chip by their names.
|
||||
* @param names Vector of line names.
|
||||
* @return Set of lines held by a line_bulk object.
|
||||
*/
|
||||
GPIOD_API line_bulk find_lines(const ::std::vector<::std::string>& names) const;
|
||||
|
||||
/**
|
||||
* @brief Equality operator.
|
||||
* @param rhs Right-hand side of the equation.
|
||||
* @return True if rhs references the same chip. False otherwise.
|
||||
*/
|
||||
GPIOD_API bool operator==(const chip& rhs) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Inequality operator.
|
||||
* @param rhs Right-hand side of the equation.
|
||||
* @return False if rhs references the same chip. True otherwise.
|
||||
*/
|
||||
GPIOD_API bool operator!=(const chip& rhs) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Check if this object holds a reference to a GPIO chip.
|
||||
* @return True if this object references a GPIO chip, false otherwise.
|
||||
*/
|
||||
GPIOD_API operator bool(void) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Check if this object doesn't hold a reference to a GPIO chip.
|
||||
* @return False if this object references a GPIO chip, true otherwise.
|
||||
*/
|
||||
GPIOD_API bool operator!(void) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Affect the way in which chip::chip and chip::open will try
|
||||
* to open a GPIO chip character device.
|
||||
*/
|
||||
enum : int {
|
||||
OPEN_LOOKUP = 1,
|
||||
/**< Open based on the best guess what the supplied string is. */
|
||||
OPEN_BY_PATH,
|
||||
/**< Assume the string is a path to the GPIO chardev. */
|
||||
OPEN_BY_NAME,
|
||||
/**< Assume the string is the name of the chip */
|
||||
OPEN_BY_LABEL,
|
||||
/**< Assume the string is the label of the GPIO chip. */
|
||||
OPEN_BY_NUMBER,
|
||||
/**< Assume the string is the number of the GPIO chip. */
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
chip(::gpiod_chip* chip);
|
||||
|
||||
void throw_if_noref(void) const;
|
||||
|
||||
::std::shared_ptr<::gpiod_chip> _m_chip;
|
||||
|
||||
friend chip_iterator;
|
||||
friend line_iterator;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Stores the configuration for line requests.
|
||||
*/
|
||||
struct line_request
|
||||
{
|
||||
/**
|
||||
* @brief Request types.
|
||||
*/
|
||||
enum : int {
|
||||
DIRECTION_AS_IS = 1,
|
||||
/**< Request for values, don't change the direction. */
|
||||
DIRECTION_INPUT,
|
||||
/**< Request for reading line values. */
|
||||
DIRECTION_OUTPUT,
|
||||
/**< Request for driving the GPIO lines. */
|
||||
EVENT_FALLING_EDGE,
|
||||
/**< Listen for falling edge events. */
|
||||
EVENT_RISING_EDGE,
|
||||
/**< Listen for rising edge events. */
|
||||
EVENT_BOTH_EDGES,
|
||||
/**< Listen for all types of events. */
|
||||
};
|
||||
|
||||
static const ::std::bitset<32> FLAG_ACTIVE_LOW;
|
||||
/**< Set the active state to 'low' (high is the default). */
|
||||
static const ::std::bitset<32> FLAG_OPEN_SOURCE;
|
||||
/**< The line is an open-source port. */
|
||||
static const ::std::bitset<32> FLAG_OPEN_DRAIN;
|
||||
/**< The line is an open-drain port. */
|
||||
|
||||
::std::string consumer;
|
||||
/**< Consumer name to pass to the request. */
|
||||
int request_type;
|
||||
/**< Type of the request. */
|
||||
::std::bitset<32> flags;
|
||||
/**< Additional request flags. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents a single GPIO line.
|
||||
*
|
||||
* Internally this class holds a raw pointer to a GPIO line descriptor and a
|
||||
* reference to the parent chip. All line resources are freed when the last
|
||||
* reference to the parent chip is dropped.
|
||||
*/
|
||||
class line
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Default constructor. Creates an empty line object.
|
||||
*/
|
||||
GPIOD_API line(void);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other Other line object.
|
||||
*/
|
||||
GPIOD_API line(const line& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other Other line object.
|
||||
*/
|
||||
GPIOD_API line(line&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Assignment operator.
|
||||
* @param other Other line object.
|
||||
* @return Reference to this object.
|
||||
*/
|
||||
GPIOD_API line& operator=(const line& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other Other line object.
|
||||
* @return Reference to this object.
|
||||
*/
|
||||
GPIOD_API line& operator=(line&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
GPIOD_API ~line(void) = default;
|
||||
|
||||
/**
|
||||
* @brief Get the offset of this line.
|
||||
* @return Offet of this line.
|
||||
*/
|
||||
GPIOD_API unsigned int offset(void) const;
|
||||
|
||||
/**
|
||||
* @brief Get the name of this line (if any).
|
||||
* @return Name of this line or an empty string if it is unnamed.
|
||||
*/
|
||||
GPIOD_API ::std::string name(void) const;
|
||||
|
||||
/**
|
||||
* @brief Get the consumer of this line (if any).
|
||||
* @return Name of the consumer of this line or an empty string if it
|
||||
* is unused.
|
||||
*/
|
||||
GPIOD_API ::std::string consumer(void) const;
|
||||
|
||||
/**
|
||||
* @brief Get current direction of this line.
|
||||
* @return Current direction setting.
|
||||
*/
|
||||
GPIOD_API int direction(void) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get current active state of this line.
|
||||
* @return Current active state setting.
|
||||
*/
|
||||
GPIOD_API int active_state(void) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Check if this line is used by the kernel or other user space
|
||||
* process.
|
||||
* @return True if this line is in use, false otherwise.
|
||||
*/
|
||||
GPIOD_API bool is_used(void) const;
|
||||
|
||||
/**
|
||||
* @brief Check if this line represents an open-drain GPIO.
|
||||
* @return True if the line is an open-drain GPIO, false otherwise.
|
||||
*/
|
||||
GPIOD_API bool is_open_drain(void) const;
|
||||
|
||||
/**
|
||||
* @brief Check if this line represents an open-source GPIO.
|
||||
* @return True if the line is an open-source GPIO, false otherwise.
|
||||
*/
|
||||
GPIOD_API bool is_open_source(void) const;
|
||||
|
||||
/**
|
||||
* @brief Request this line.
|
||||
* @param config Request config (see gpiod::line_request).
|
||||
* @param default_val Default value - only matters for OUTPUT direction.
|
||||
*/
|
||||
GPIOD_API void request(const line_request& config, int default_val = 0) const;
|
||||
|
||||
/**
|
||||
* @brief Check if this user has ownership of this line.
|
||||
* @return True if the user has ownership of this line, false otherwise.
|
||||
*/
|
||||
GPIOD_API bool is_requested(void) const;
|
||||
|
||||
/**
|
||||
* @brief Read the line value.
|
||||
* @return Current value (0 or 1).
|
||||
*/
|
||||
GPIOD_API int get_value(void) const;
|
||||
|
||||
/**
|
||||
* @brief Set the value of this line.
|
||||
* @param val New value (0 or 1).
|
||||
*/
|
||||
GPIOD_API void set_value(int val) const;
|
||||
|
||||
/**
|
||||
* @brief Wait for an event on this line.
|
||||
* @param timeout Time to wait before returning if no event occurred.
|
||||
* @return True if an event occurred and can be read, false if the wait
|
||||
* timed out.
|
||||
*/
|
||||
GPIOD_API bool event_wait(const ::std::chrono::nanoseconds& timeout) const;
|
||||
|
||||
/**
|
||||
* @brief Read a line event.
|
||||
* @return Line event object.
|
||||
*/
|
||||
GPIOD_API line_event event_read(void) const;
|
||||
|
||||
/**
|
||||
* @brief Get the event file descriptor associated with this line.
|
||||
* @return File descriptor number.
|
||||
*/
|
||||
GPIOD_API int event_get_fd(void) const;
|
||||
|
||||
/**
|
||||
* @brief Get the reference to the parent chip.
|
||||
* @return Reference to the parent chip object.
|
||||
*/
|
||||
GPIOD_API const chip& get_chip(void) const;
|
||||
|
||||
/**
|
||||
* @brief Reset the state of this object.
|
||||
*
|
||||
* This is useful when the user needs to e.g. keep the line_event object
|
||||
* but wants to drop the reference to the GPIO chip indirectly held by
|
||||
* the line being the source of the event.
|
||||
*/
|
||||
GPIOD_API void reset(void);
|
||||
|
||||
/**
|
||||
* @brief Check if two line objects reference the same GPIO line.
|
||||
* @param rhs Right-hand side of the equation.
|
||||
* @return True if both objects reference the same line, fale otherwise.
|
||||
*/
|
||||
GPIOD_API bool operator==(const line& rhs) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Check if two line objects reference different GPIO lines.
|
||||
* @param rhs Right-hand side of the equation.
|
||||
* @return False if both objects reference the same line, true otherwise.
|
||||
*/
|
||||
GPIOD_API bool operator!=(const line& rhs) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Check if this object holds a reference to any GPIO line.
|
||||
* @return True if this object references a GPIO line, false otherwise.
|
||||
*/
|
||||
GPIOD_API operator bool(void) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Check if this object doesn't reference any GPIO line.
|
||||
* @return True if this object doesn't reference any GPIO line, true
|
||||
* otherwise.
|
||||
*/
|
||||
GPIOD_API bool operator!(void) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Possible direction settings.
|
||||
*/
|
||||
enum : int {
|
||||
DIRECTION_INPUT = 1,
|
||||
/**< Line's direction setting is input. */
|
||||
DIRECTION_OUTPUT,
|
||||
/**< Line's direction setting is output. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Possible active state settings.
|
||||
*/
|
||||
enum : int {
|
||||
ACTIVE_LOW = 1,
|
||||
/**< Line's active state is low. */
|
||||
ACTIVE_HIGH,
|
||||
/**< Line's active state is high. */
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
line(::gpiod_line* line, const chip& owner);
|
||||
|
||||
void throw_if_null(void) const;
|
||||
|
||||
::gpiod_line* _m_line;
|
||||
chip _m_chip;
|
||||
|
||||
friend chip;
|
||||
friend line_bulk;
|
||||
friend line_iterator;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Find a GPIO line by name. Search all GPIO chips present on the system.
|
||||
* @param name Name of the line.
|
||||
* @return Returns a line object - empty if the line was not found.
|
||||
*/
|
||||
GPIOD_API line find_line(const ::std::string& name);
|
||||
|
||||
/**
|
||||
* @brief Describes a single GPIO line event.
|
||||
*/
|
||||
struct line_event
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Possible event types.
|
||||
*/
|
||||
enum : int {
|
||||
RISING_EDGE = 1,
|
||||
/**< Rising edge event. */
|
||||
FALLING_EDGE,
|
||||
/**< Falling edge event. */
|
||||
};
|
||||
|
||||
::std::chrono::nanoseconds timestamp;
|
||||
/**< Best estimate of time of event occurrence in nanoseconds. */
|
||||
int event_type;
|
||||
/**< Type of the event that occurred. */
|
||||
line source;
|
||||
/**< Line object referencing the GPIO line on which the event occurred. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents a set of GPIO lines.
|
||||
*
|
||||
* Internally an object of this class stores an array of line objects
|
||||
* owned by a single chip.
|
||||
*/
|
||||
class line_bulk
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Default constructor. Creates an empty line_bulk object.
|
||||
*/
|
||||
GPIOD_API line_bulk(void) = default;
|
||||
|
||||
/**
|
||||
* @brief Construct a line_bulk from a vector of lines.
|
||||
* @param lines Vector of gpiod::line objects.
|
||||
* @note All lines must be owned by the same GPIO chip.
|
||||
*/
|
||||
GPIOD_API line_bulk(const ::std::vector<line>& lines);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other Other line_bulk object.
|
||||
*/
|
||||
GPIOD_API line_bulk(const line_bulk& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other Other line_bulk object.
|
||||
*/
|
||||
GPIOD_API line_bulk(line_bulk&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Assignment operator.
|
||||
* @param other Other line_bulk object.
|
||||
* @return Reference to this object.
|
||||
*/
|
||||
GPIOD_API line_bulk& operator=(const line_bulk& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other Other line_bulk object.
|
||||
* @return Reference to this object.
|
||||
*/
|
||||
GPIOD_API line_bulk& operator=(line_bulk&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
GPIOD_API ~line_bulk(void) = default;
|
||||
|
||||
/**
|
||||
* @brief Add a line to this line_bulk object.
|
||||
* @param new_line Line to add.
|
||||
* @note The new line must be owned by the same chip as all the other
|
||||
* lines already held by this line_bulk object.
|
||||
*/
|
||||
GPIOD_API void add(const line& new_line);
|
||||
|
||||
/**
|
||||
* @brief Get the line at given offset.
|
||||
* @param offset Offset of the line to get.
|
||||
* @return Reference to the line object.
|
||||
*/
|
||||
GPIOD_API line& get(unsigned int offset);
|
||||
|
||||
/**
|
||||
* @brief Get the line at given offset without bounds checking.
|
||||
* @param offset Offset of the line to get.
|
||||
* @return Reference to the line object.
|
||||
* @note No bounds checking is performed.
|
||||
*/
|
||||
GPIOD_API line& operator[](unsigned int offset);
|
||||
|
||||
/**
|
||||
* @brief Get the number of lines currently held by this object.
|
||||
* @return Number of elements in this line_bulk.
|
||||
*/
|
||||
GPIOD_API unsigned int size(void) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Check if this line_bulk doesn't hold any lines.
|
||||
* @return True if this object is empty, false otherwise.
|
||||
*/
|
||||
GPIOD_API bool empty(void) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Remove all lines from this object.
|
||||
*/
|
||||
GPIOD_API void clear(void);
|
||||
|
||||
/**
|
||||
* @brief Request all lines held by this object.
|
||||
* @param config Request config (see gpiod::line_request).
|
||||
* @param default_vals Vector of default values. Only relevant for
|
||||
* output direction requests.
|
||||
*/
|
||||
GPIOD_API void request(const line_request& config,
|
||||
std::vector<int> default_vals = std::vector<int>()) const;
|
||||
|
||||
/**
|
||||
* @brief Read values from all lines held by this object.
|
||||
* @return Vector containing line values the order of which corresponds
|
||||
* with the order of lines in the internal array.
|
||||
*/
|
||||
GPIOD_API ::std::vector<int> get_values(void) const;
|
||||
|
||||
/**
|
||||
* @brief Set values of all lines held by this object.
|
||||
* @param values Vector of values to set. Must be the same size as the
|
||||
* number of lines held by this line_bulk.
|
||||
*/
|
||||
GPIOD_API void set_values(const ::std::vector<int>& values) const;
|
||||
|
||||
/**
|
||||
* @brief Poll the set of lines for line events.
|
||||
* @param timeout Number of nanoseconds to wait before returning an
|
||||
* empty line_bulk.
|
||||
* @return Returns a line_bulk object containing lines on which events
|
||||
* occurred.
|
||||
*/
|
||||
GPIOD_API line_bulk event_wait(const ::std::chrono::nanoseconds& timeout) const;
|
||||
|
||||
/**
|
||||
* @brief Check if this object holds any lines.
|
||||
* @return True if this line_bulk holds at least one line, false otherwise.
|
||||
*/
|
||||
GPIOD_API operator bool(void) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Check if this object doesn't hold any lines.
|
||||
* @return True if this line_bulk is empty, false otherwise.
|
||||
*/
|
||||
GPIOD_API bool operator!(void) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Max number of lines that this object can hold.
|
||||
*/
|
||||
GPIOD_API static const unsigned int MAX_LINES;
|
||||
|
||||
/**
|
||||
* @brief Iterator for iterating over lines held by line_bulk.
|
||||
*/
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Default constructor. Builds an empty iterator object.
|
||||
*/
|
||||
GPIOD_API iterator(void) = default;
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other Other line_bulk iterator.
|
||||
*/
|
||||
GPIOD_API iterator(const iterator& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other Other line_bulk iterator.
|
||||
*/
|
||||
GPIOD_API iterator(iterator&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Assignment operator.
|
||||
* @param other Other line_bulk iterator.
|
||||
* @return Reference to this iterator.
|
||||
*/
|
||||
GPIOD_API iterator& operator=(const iterator& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other Other line_bulk iterator.
|
||||
* @return Reference to this iterator.
|
||||
*/
|
||||
GPIOD_API iterator& operator=(iterator&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
GPIOD_API ~iterator(void) = default;
|
||||
|
||||
/**
|
||||
* @brief Advance the iterator by one element.
|
||||
* @return Reference to this iterator.
|
||||
*/
|
||||
GPIOD_API iterator& operator++(void);
|
||||
|
||||
/**
|
||||
* @brief Dereference current element.
|
||||
* @return Current GPIO line by reference.
|
||||
*/
|
||||
GPIOD_API const line& operator*(void) const;
|
||||
|
||||
/**
|
||||
* @brief Member access operator.
|
||||
* @return Current GPIO line by pointer.
|
||||
*/
|
||||
GPIOD_API const line* operator->(void) const;
|
||||
|
||||
/**
|
||||
* @brief Check if this operator points to the same element.
|
||||
* @param rhs Right-hand side of the equation.
|
||||
* @return True if this iterator points to the same GPIO line,
|
||||
* false otherwise.
|
||||
*/
|
||||
GPIOD_API bool operator==(const iterator& rhs) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Check if this operator doesn't point to the same element.
|
||||
* @param rhs Right-hand side of the equation.
|
||||
* @return True if this iterator doesn't point to the same GPIO
|
||||
* line, false otherwise.
|
||||
*/
|
||||
GPIOD_API bool operator!=(const iterator& rhs) const noexcept;
|
||||
|
||||
private:
|
||||
|
||||
iterator(const ::std::vector<line>::iterator& it);
|
||||
|
||||
::std::vector<line>::iterator _m_iter;
|
||||
|
||||
friend line_bulk;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the first line.
|
||||
* @return A line_bulk iterator.
|
||||
*/
|
||||
GPIOD_API iterator begin(void) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the element following the last line.
|
||||
* @return A line_bulk iterator.
|
||||
*/
|
||||
GPIOD_API iterator end(void) noexcept;
|
||||
|
||||
private:
|
||||
|
||||
void throw_if_empty(void) const;
|
||||
void to_line_bulk(::gpiod_line_bulk* bulk) const;
|
||||
|
||||
::std::vector<line> _m_bulk;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new chip_iterator.
|
||||
* @return New chip iterator object pointing to the first GPIO chip on the system.
|
||||
* @note This function is needed as we already use the default constructor of
|
||||
* gpiod::chip_iterator as the return value of gpiod::end.
|
||||
*/
|
||||
GPIOD_API chip_iterator make_chip_iterator(void);
|
||||
|
||||
/**
|
||||
* @brief Support for range-based loops for chip iterators.
|
||||
* @param iter A chip iterator.
|
||||
* @return Iterator unchanged.
|
||||
*/
|
||||
GPIOD_API chip_iterator begin(chip_iterator iter) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Support for range-based loops for chip iterators.
|
||||
* @param iter A chip iterator.
|
||||
* @return New end iterator.
|
||||
*/
|
||||
GPIOD_API chip_iterator end(const chip_iterator& iter) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Allows to iterate over all GPIO chips present on the system.
|
||||
*/
|
||||
class chip_iterator
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Default constructor. Creates the end iterator.
|
||||
*/
|
||||
GPIOD_API chip_iterator(void) = default;
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other Other chip_iterator.
|
||||
*/
|
||||
GPIOD_API chip_iterator(const chip_iterator& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other Other chip_iterator.
|
||||
*/
|
||||
GPIOD_API chip_iterator(chip_iterator&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Assignment operator.
|
||||
* @param other Other chip_iterator.
|
||||
* @return Reference to this iterator.
|
||||
*/
|
||||
GPIOD_API chip_iterator& operator=(const chip_iterator& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other Other chip_iterator.
|
||||
* @return Reference to this iterator.
|
||||
*/
|
||||
GPIOD_API chip_iterator& operator=(chip_iterator&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
GPIOD_API ~chip_iterator(void) = default;
|
||||
|
||||
/**
|
||||
* @brief Advance the iterator by one element.
|
||||
* @return Reference to this iterator.
|
||||
*/
|
||||
GPIOD_API chip_iterator& operator++(void);
|
||||
|
||||
/**
|
||||
* @brief Dereference current element.
|
||||
* @return Current GPIO chip by reference.
|
||||
*/
|
||||
GPIOD_API const chip& operator*(void) const;
|
||||
|
||||
/**
|
||||
* @brief Member access operator.
|
||||
* @return Current GPIO chip by pointer.
|
||||
*/
|
||||
GPIOD_API const chip* operator->(void) const;
|
||||
|
||||
/**
|
||||
* @brief Check if this operator points to the same element.
|
||||
* @param rhs Right-hand side of the equation.
|
||||
* @return True if this iterator points to the same chip_iterator,
|
||||
* false otherwise.
|
||||
*/
|
||||
GPIOD_API bool operator==(const chip_iterator& rhs) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Check if this operator doesn't point to the same element.
|
||||
* @param rhs Right-hand side of the equation.
|
||||
* @return True if this iterator doesn't point to the same chip_iterator,
|
||||
* false otherwise.
|
||||
*/
|
||||
GPIOD_API bool operator!=(const chip_iterator& rhs) const noexcept;
|
||||
|
||||
private:
|
||||
|
||||
chip_iterator(::gpiod_chip_iter* iter);
|
||||
|
||||
::std::shared_ptr<::gpiod_chip_iter> _m_iter;
|
||||
chip _m_current;
|
||||
|
||||
friend chip_iterator make_chip_iterator(void);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Support for range-based loops for line iterators.
|
||||
* @param iter A line iterator.
|
||||
* @return Iterator unchanged.
|
||||
*/
|
||||
GPIOD_API line_iterator begin(line_iterator iter) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Support for range-based loops for line iterators.
|
||||
* @param iter A line iterator.
|
||||
* @return New end iterator.
|
||||
*/
|
||||
GPIOD_API line_iterator end(const line_iterator& iter) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Allows to iterate over all lines owned by a GPIO chip.
|
||||
*/
|
||||
class line_iterator
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Default constructor. Creates the end iterator.
|
||||
*/
|
||||
GPIOD_API line_iterator(void) = default;
|
||||
|
||||
/**
|
||||
* @brief Constructor. Creates the begin iterator.
|
||||
* @param owner Chip owning the GPIO lines over which we want to iterate.
|
||||
*/
|
||||
GPIOD_API line_iterator(const chip& owner);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other Other line iterator.
|
||||
*/
|
||||
GPIOD_API line_iterator(const line_iterator& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other Other line iterator.
|
||||
*/
|
||||
GPIOD_API line_iterator(line_iterator&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Assignment operator.
|
||||
* @param other Other line iterator.
|
||||
* @return Reference to this line_iterator.
|
||||
*/
|
||||
GPIOD_API line_iterator& operator=(const line_iterator& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other Other line iterator.
|
||||
* @return Reference to this line_iterator.
|
||||
*/
|
||||
GPIOD_API line_iterator& operator=(line_iterator&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
GPIOD_API ~line_iterator(void) = default;
|
||||
|
||||
/**
|
||||
* @brief Advance the iterator by one element.
|
||||
* @return Reference to this iterator.
|
||||
*/
|
||||
GPIOD_API line_iterator& operator++(void);
|
||||
|
||||
/**
|
||||
* @brief Dereference current element.
|
||||
* @return Current GPIO line by reference.
|
||||
*/
|
||||
GPIOD_API const line& operator*(void) const;
|
||||
|
||||
/**
|
||||
* @brief Member access operator.
|
||||
* @return Current GPIO line by pointer.
|
||||
*/
|
||||
GPIOD_API const line* operator->(void) const;
|
||||
|
||||
/**
|
||||
* @brief Check if this operator points to the same element.
|
||||
* @param rhs Right-hand side of the equation.
|
||||
* @return True if this iterator points to the same line_iterator,
|
||||
* false otherwise.
|
||||
*/
|
||||
GPIOD_API bool operator==(const line_iterator& rhs) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Check if this operator doesn't point to the same element.
|
||||
* @param rhs Right-hand side of the equation.
|
||||
* @return True if this iterator doesn't point to the same line_iterator,
|
||||
* false otherwise.
|
||||
*/
|
||||
GPIOD_API bool operator!=(const line_iterator& rhs) const noexcept;
|
||||
|
||||
private:
|
||||
|
||||
::std::shared_ptr<::gpiod_line_iter> _m_iter;
|
||||
line _m_current;
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
} /* namespace gpiod */
|
||||
|
||||
#endif /* __LIBGPIOD_GPIOD_CXX_HPP__ */
|
||||
146
bindings/cxx/iter.cpp
Normal file
146
bindings/cxx/iter.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
#include <gpiod.hpp>
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace gpiod {
|
||||
|
||||
namespace {
|
||||
|
||||
void chip_iter_deleter(::gpiod_chip_iter* iter)
|
||||
{
|
||||
::gpiod_chip_iter_free_noclose(iter);
|
||||
}
|
||||
|
||||
void line_iter_deleter(::gpiod_line_iter* iter)
|
||||
{
|
||||
::gpiod_line_iter_free(iter);
|
||||
}
|
||||
|
||||
::gpiod_line_iter* make_line_iterator(::gpiod_chip* chip)
|
||||
{
|
||||
::gpiod_line_iter* iter;
|
||||
|
||||
iter = ::gpiod_line_iter_new(chip);
|
||||
if (!iter)
|
||||
throw ::std::system_error(errno, ::std::system_category(),
|
||||
"error creating GPIO line iterator");
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
chip_iterator make_chip_iterator(void)
|
||||
{
|
||||
::gpiod_chip_iter* iter = ::gpiod_chip_iter_new();
|
||||
if (!iter)
|
||||
throw ::std::system_error(errno, ::std::system_category(),
|
||||
"error creating GPIO chip iterator");
|
||||
|
||||
return ::std::move(chip_iterator(iter));
|
||||
}
|
||||
|
||||
bool chip_iterator::operator==(const chip_iterator& rhs) const noexcept
|
||||
{
|
||||
return this->_m_current == rhs._m_current;
|
||||
}
|
||||
|
||||
bool chip_iterator::operator!=(const chip_iterator& rhs) const noexcept
|
||||
{
|
||||
return this->_m_current != rhs._m_current;
|
||||
}
|
||||
|
||||
chip_iterator::chip_iterator(::gpiod_chip_iter *iter)
|
||||
: _m_iter(iter, chip_iter_deleter),
|
||||
_m_current(chip(::gpiod_chip_iter_next_noclose(this->_m_iter.get())))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
chip_iterator& chip_iterator::operator++(void)
|
||||
{
|
||||
::gpiod_chip* next = ::gpiod_chip_iter_next_noclose(this->_m_iter.get());
|
||||
|
||||
this->_m_current = next ? chip(next) : chip();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const chip& chip_iterator::operator*(void) const
|
||||
{
|
||||
return this->_m_current;
|
||||
}
|
||||
|
||||
const chip* chip_iterator::operator->(void) const
|
||||
{
|
||||
return ::std::addressof(this->_m_current);
|
||||
}
|
||||
|
||||
chip_iterator begin(chip_iterator iter) noexcept
|
||||
{
|
||||
return iter;
|
||||
}
|
||||
|
||||
chip_iterator end(const chip_iterator&) noexcept
|
||||
{
|
||||
return ::std::move(chip_iterator());
|
||||
}
|
||||
|
||||
line_iterator begin(line_iterator iter) noexcept
|
||||
{
|
||||
return iter;
|
||||
}
|
||||
|
||||
line_iterator end(const line_iterator&) noexcept
|
||||
{
|
||||
return ::std::move(line_iterator());
|
||||
}
|
||||
|
||||
line_iterator::line_iterator(const chip& owner)
|
||||
: _m_iter(make_line_iterator(owner._m_chip.get()), line_iter_deleter),
|
||||
_m_current(line(::gpiod_line_iter_next(this->_m_iter.get()), owner))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
line_iterator& line_iterator::operator++(void)
|
||||
{
|
||||
::gpiod_line* next = ::gpiod_line_iter_next(this->_m_iter.get());
|
||||
|
||||
this->_m_current = next ? line(next, this->_m_current._m_chip) : line();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const line& line_iterator::operator*(void) const
|
||||
{
|
||||
return this->_m_current;
|
||||
}
|
||||
|
||||
const line* line_iterator::operator->(void) const
|
||||
{
|
||||
return ::std::addressof(this->_m_current);
|
||||
}
|
||||
|
||||
bool line_iterator::operator==(const line_iterator& rhs) const noexcept
|
||||
{
|
||||
return this->_m_current._m_line == rhs._m_current._m_line;
|
||||
}
|
||||
|
||||
bool line_iterator::operator!=(const line_iterator& rhs) const noexcept
|
||||
{
|
||||
return this->_m_current._m_line != rhs._m_current._m_line;
|
||||
}
|
||||
|
||||
} /* namespace gpiod */
|
||||
238
bindings/cxx/line.cpp
Normal file
238
bindings/cxx/line.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
#include <gpiod.hpp>
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace gpiod {
|
||||
|
||||
line::line(void)
|
||||
: _m_line(nullptr),
|
||||
_m_chip()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
line::line(::gpiod_line* line, const chip& owner)
|
||||
: _m_line(line),
|
||||
_m_chip(owner)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
unsigned int line::offset(void) const
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
return ::gpiod_line_offset(this->_m_line);
|
||||
}
|
||||
|
||||
::std::string line::name(void) const
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
const char* name = ::gpiod_line_name(this->_m_line);
|
||||
|
||||
return ::std::move(name ? ::std::string(name) : ::std::string());
|
||||
}
|
||||
|
||||
::std::string line::consumer(void) const
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
const char* consumer = ::gpiod_line_consumer(this->_m_line);
|
||||
|
||||
return ::std::move(consumer ? ::std::string(consumer) : ::std::string());
|
||||
}
|
||||
|
||||
int line::direction(void) const noexcept
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
int dir = ::gpiod_line_direction(this->_m_line);
|
||||
|
||||
return dir == GPIOD_LINE_DIRECTION_INPUT ? DIRECTION_INPUT : DIRECTION_OUTPUT;
|
||||
}
|
||||
|
||||
int line::active_state(void) const noexcept
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
int active = ::gpiod_line_active_state(this->_m_line);
|
||||
|
||||
return active == GPIOD_LINE_ACTIVE_STATE_HIGH ? ACTIVE_HIGH : ACTIVE_LOW;
|
||||
}
|
||||
|
||||
bool line::is_used(void) const
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
return ::gpiod_line_is_used(this->_m_line);
|
||||
}
|
||||
|
||||
bool line::is_open_drain(void) const
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
return ::gpiod_line_is_open_drain(this->_m_line);
|
||||
}
|
||||
|
||||
bool line::is_open_source(void) const
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
return ::gpiod_line_is_open_source(this->_m_line);
|
||||
}
|
||||
|
||||
void line::request(const line_request& config, int default_val) const
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
line_bulk bulk({ *this });
|
||||
|
||||
bulk.request(config, { default_val });
|
||||
}
|
||||
|
||||
bool line::is_requested(void) const
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
return ::gpiod_line_is_requested(this->_m_line);
|
||||
}
|
||||
|
||||
/*
|
||||
* REVISIT: Check the performance of get/set_value & event_wait compared to
|
||||
* the C API. Creating a line_bulk object involves a memory allocation every
|
||||
* time this method if called. If the performance is significantly lower,
|
||||
* switch to calling the C functions for setting/getting line values and
|
||||
* polling for events on single lines directly.
|
||||
*/
|
||||
|
||||
int line::get_value(void) const
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
line_bulk bulk({ *this });
|
||||
|
||||
return bulk.get_values()[0];
|
||||
}
|
||||
|
||||
void line::set_value(int val) const
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
line_bulk bulk({ *this });
|
||||
|
||||
bulk.set_values({ val });
|
||||
}
|
||||
|
||||
bool line::event_wait(const ::std::chrono::nanoseconds& timeout) const
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
line_bulk bulk({ *this });
|
||||
|
||||
line_bulk event_bulk = bulk.event_wait(timeout);
|
||||
|
||||
return ::std::move(event_bulk);
|
||||
}
|
||||
|
||||
line_event line::event_read(void) const
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
::gpiod_line_event event_buf;
|
||||
line_event event;
|
||||
int rv;
|
||||
|
||||
rv = ::gpiod_line_event_read(this->_m_line, ::std::addressof(event_buf));
|
||||
if (rv < 0)
|
||||
throw ::std::system_error(errno, ::std::system_category(),
|
||||
"error reading line event");
|
||||
|
||||
if (event_buf.event_type == GPIOD_LINE_EVENT_RISING_EDGE)
|
||||
event.event_type = line_event::RISING_EDGE;
|
||||
else if (event_buf.event_type == GPIOD_LINE_EVENT_FALLING_EDGE)
|
||||
event.event_type = line_event::FALLING_EDGE;
|
||||
|
||||
event.timestamp = ::std::chrono::nanoseconds(
|
||||
event_buf.ts.tv_nsec + (event_buf.ts.tv_sec * 1000000000));
|
||||
|
||||
event.source = *this;
|
||||
|
||||
return ::std::move(event);
|
||||
}
|
||||
|
||||
int line::event_get_fd(void) const
|
||||
{
|
||||
this->throw_if_null();
|
||||
|
||||
int ret = ::gpiod_line_event_get_fd(this->_m_line);
|
||||
|
||||
if (ret < 0)
|
||||
::std::system_error(errno, ::std::system_category(),
|
||||
"unable to get the line event file descriptor");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const chip& line::get_chip(void) const
|
||||
{
|
||||
return this->_m_chip;
|
||||
}
|
||||
|
||||
void line::reset(void)
|
||||
{
|
||||
this->_m_line = nullptr;
|
||||
this->_m_chip.reset();
|
||||
}
|
||||
|
||||
bool line::operator==(const line& rhs) const noexcept
|
||||
{
|
||||
return this->_m_line == rhs._m_line;
|
||||
}
|
||||
|
||||
bool line::operator!=(const line& rhs) const noexcept
|
||||
{
|
||||
return this->_m_line != rhs._m_line;
|
||||
}
|
||||
|
||||
line::operator bool(void) const noexcept
|
||||
{
|
||||
return this->_m_line != nullptr;
|
||||
}
|
||||
|
||||
bool line::operator!(void) const noexcept
|
||||
{
|
||||
return this->_m_line == nullptr;
|
||||
}
|
||||
|
||||
void line::throw_if_null(void) const
|
||||
{
|
||||
if (!this->_m_line)
|
||||
throw ::std::logic_error("object not holding a GPIO line handle");
|
||||
}
|
||||
|
||||
line find_line(const ::std::string& name)
|
||||
{
|
||||
line ret;
|
||||
|
||||
for (auto& it: make_chip_iterator()) {
|
||||
ret = it.find_line(name);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ::std::move(ret);
|
||||
}
|
||||
|
||||
} /* namespace gpiod */
|
||||
262
bindings/cxx/line_bulk.cpp
Normal file
262
bindings/cxx/line_bulk.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
#include <gpiod.hpp>
|
||||
|
||||
#include <system_error>
|
||||
#include <map>
|
||||
|
||||
namespace gpiod {
|
||||
|
||||
namespace {
|
||||
|
||||
const ::std::map<int, int> reqtype_mapping = {
|
||||
{ line_request::DIRECTION_AS_IS, GPIOD_LINE_REQUEST_DIRECTION_AS_IS, },
|
||||
{ line_request::DIRECTION_INPUT, GPIOD_LINE_REQUEST_DIRECTION_INPUT, },
|
||||
{ line_request::DIRECTION_OUTPUT, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT, },
|
||||
{ line_request::EVENT_FALLING_EDGE, GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE, },
|
||||
{ line_request::EVENT_RISING_EDGE, GPIOD_LINE_REQUEST_EVENT_RISING_EDGE, },
|
||||
{ line_request::EVENT_BOTH_EDGES, GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES, },
|
||||
};
|
||||
|
||||
struct bitset_cmp
|
||||
{
|
||||
bool operator()(const ::std::bitset<32>& lhs, const ::std::bitset<32>& rhs)
|
||||
{
|
||||
return lhs.to_ulong() < rhs.to_ulong();
|
||||
}
|
||||
};
|
||||
|
||||
const ::std::map<::std::bitset<32>, int, bitset_cmp> reqflag_mapping = {
|
||||
{ line_request::FLAG_ACTIVE_LOW, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW, },
|
||||
{ line_request::FLAG_OPEN_DRAIN, GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN, },
|
||||
{ line_request::FLAG_OPEN_SOURCE, GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE, },
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
||||
const ::std::bitset<32> line_request::FLAG_ACTIVE_LOW("001");
|
||||
const ::std::bitset<32> line_request::FLAG_OPEN_SOURCE("010");
|
||||
const ::std::bitset<32> line_request::FLAG_OPEN_DRAIN("100");
|
||||
|
||||
const unsigned int line_bulk::MAX_LINES = GPIOD_LINE_BULK_MAX_LINES;
|
||||
|
||||
line_bulk::line_bulk(const ::std::vector<line>& lines)
|
||||
: _m_bulk()
|
||||
{
|
||||
this->_m_bulk.reserve(lines.size());
|
||||
|
||||
for (auto& it: lines)
|
||||
this->add(it);
|
||||
}
|
||||
|
||||
void line_bulk::add(const line& new_line)
|
||||
{
|
||||
if (!new_line)
|
||||
throw ::std::logic_error("line_bulk cannot hold empty line objects");
|
||||
|
||||
if (this->_m_bulk.size() >= MAX_LINES)
|
||||
throw ::std::logic_error("maximum number of lines reached");
|
||||
|
||||
if (this->_m_bulk.size() >= 1 && this->_m_bulk.begin()->get_chip() != new_line.get_chip())
|
||||
throw std::logic_error("line_bulk cannot hold GPIO lines from different chips");
|
||||
|
||||
this->_m_bulk.push_back(new_line);
|
||||
}
|
||||
|
||||
line& line_bulk::get(unsigned int offset)
|
||||
{
|
||||
return this->_m_bulk.at(offset);
|
||||
}
|
||||
|
||||
line& line_bulk::operator[](unsigned int offset)
|
||||
{
|
||||
return this->_m_bulk[offset];
|
||||
}
|
||||
|
||||
unsigned int line_bulk::size(void) const noexcept
|
||||
{
|
||||
return this->_m_bulk.size();
|
||||
}
|
||||
|
||||
bool line_bulk::empty(void) const noexcept
|
||||
{
|
||||
return this->_m_bulk.empty();
|
||||
}
|
||||
|
||||
void line_bulk::clear(void)
|
||||
{
|
||||
this->_m_bulk.clear();
|
||||
}
|
||||
|
||||
void line_bulk::request(const line_request& config, std::vector<int> default_vals) const
|
||||
{
|
||||
this->throw_if_empty();
|
||||
|
||||
if (!default_vals.empty() && this->size() != default_vals.size())
|
||||
throw ::std::invalid_argument("the number of default values must correspond with the number of lines");
|
||||
|
||||
::gpiod_line_request_config conf;
|
||||
::gpiod_line_bulk bulk;
|
||||
int rv;
|
||||
|
||||
this->to_line_bulk(::std::addressof(bulk));
|
||||
|
||||
conf.consumer = config.consumer.c_str();
|
||||
conf.request_type = reqtype_mapping.at(config.request_type);
|
||||
conf.flags = 0;
|
||||
|
||||
for (auto& it: reqflag_mapping) {
|
||||
if ((it.first & config.flags).to_ulong())
|
||||
conf.flags |= it.second;
|
||||
}
|
||||
|
||||
rv = ::gpiod_line_request_bulk(::std::addressof(bulk),
|
||||
::std::addressof(conf), default_vals.data());
|
||||
if (rv)
|
||||
throw ::std::system_error(errno, ::std::system_category(),
|
||||
"error requesting GPIO lines");
|
||||
}
|
||||
|
||||
::std::vector<int> line_bulk::get_values(void) const
|
||||
{
|
||||
this->throw_if_empty();
|
||||
|
||||
::std::vector<int> values;
|
||||
::gpiod_line_bulk bulk;
|
||||
int rv;
|
||||
|
||||
this->to_line_bulk(::std::addressof(bulk));
|
||||
values.resize(this->_m_bulk.size());
|
||||
|
||||
rv = ::gpiod_line_get_value_bulk(::std::addressof(bulk), values.data());
|
||||
if (rv)
|
||||
throw ::std::system_error(errno, ::std::system_category(),
|
||||
"error reading GPIO line values");
|
||||
|
||||
return ::std::move(values);
|
||||
}
|
||||
|
||||
void line_bulk::set_values(const ::std::vector<int>& values) const
|
||||
{
|
||||
this->throw_if_empty();
|
||||
|
||||
if (values.size() != this->_m_bulk.size())
|
||||
throw ::std::invalid_argument("the size of values array must correspond with the number of lines");
|
||||
|
||||
::gpiod_line_bulk bulk;
|
||||
int rv;
|
||||
|
||||
this->to_line_bulk(::std::addressof(bulk));
|
||||
|
||||
rv = ::gpiod_line_set_value_bulk(::std::addressof(bulk), values.data());
|
||||
if (rv)
|
||||
throw ::std::system_error(errno, ::std::system_category(),
|
||||
"error setting GPIO line values");
|
||||
}
|
||||
|
||||
line_bulk line_bulk::event_wait(const ::std::chrono::nanoseconds& timeout) const
|
||||
{
|
||||
this->throw_if_empty();
|
||||
|
||||
::gpiod_line_bulk bulk, event_bulk;
|
||||
::timespec ts;
|
||||
line_bulk ret;
|
||||
int rv;
|
||||
|
||||
this->to_line_bulk(::std::addressof(bulk));
|
||||
|
||||
::gpiod_line_bulk_init(::std::addressof(event_bulk));
|
||||
|
||||
ts.tv_sec = timeout.count() / 1000000000ULL;
|
||||
ts.tv_nsec = timeout.count() % 1000000000ULL;
|
||||
|
||||
rv = ::gpiod_line_event_wait_bulk(::std::addressof(bulk),
|
||||
::std::addressof(ts),
|
||||
::std::addressof(event_bulk));
|
||||
if (rv < 0) {
|
||||
throw ::std::system_error(errno, ::std::system_category(),
|
||||
"error polling for events");
|
||||
} else if (rv > 0) {
|
||||
for (unsigned int i = 0; i < event_bulk.num_lines; i++)
|
||||
ret.add(line(event_bulk.lines[i], this->_m_bulk[i].get_chip()));
|
||||
}
|
||||
|
||||
return ::std::move(ret);
|
||||
}
|
||||
|
||||
line_bulk::operator bool(void) const noexcept
|
||||
{
|
||||
return !this->_m_bulk.empty();
|
||||
}
|
||||
|
||||
bool line_bulk::operator!(void) const noexcept
|
||||
{
|
||||
return this->_m_bulk.empty();
|
||||
}
|
||||
|
||||
line_bulk::iterator::iterator(const ::std::vector<line>::iterator& it)
|
||||
: _m_iter(it)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
line_bulk::iterator& line_bulk::iterator::operator++(void)
|
||||
{
|
||||
this->_m_iter++;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const line& line_bulk::iterator::operator*(void) const
|
||||
{
|
||||
return *this->_m_iter;
|
||||
}
|
||||
|
||||
const line* line_bulk::iterator::operator->(void) const
|
||||
{
|
||||
return this->_m_iter.operator->();
|
||||
}
|
||||
|
||||
bool line_bulk::iterator::operator==(const iterator& rhs) const noexcept
|
||||
{
|
||||
return this->_m_iter == rhs._m_iter;
|
||||
}
|
||||
|
||||
bool line_bulk::iterator::operator!=(const iterator& rhs) const noexcept
|
||||
{
|
||||
return this->_m_iter != rhs._m_iter;
|
||||
}
|
||||
|
||||
line_bulk::iterator line_bulk::begin(void) noexcept
|
||||
{
|
||||
return ::std::move(line_bulk::iterator(this->_m_bulk.begin()));
|
||||
}
|
||||
|
||||
line_bulk::iterator line_bulk::end(void) noexcept
|
||||
{
|
||||
return ::std::move(line_bulk::iterator(this->_m_bulk.end()));
|
||||
}
|
||||
|
||||
void line_bulk::throw_if_empty(void) const
|
||||
{
|
||||
if (this->_m_bulk.empty())
|
||||
throw std::logic_error("line_bulk not holding any GPIO lines");
|
||||
}
|
||||
|
||||
void line_bulk::to_line_bulk(::gpiod_line_bulk *bulk) const
|
||||
{
|
||||
::gpiod_line_bulk_init(bulk);
|
||||
for (auto& it: this->_m_bulk)
|
||||
::gpiod_line_bulk_add(bulk, it._m_line);
|
||||
}
|
||||
|
||||
} /* namespace gpiod */
|
||||
27
configure.ac
27
configure.ac
@@ -33,6 +33,7 @@ AC_SUBST(AR_FLAGS, [cr])
|
||||
|
||||
AM_PROG_AR
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_PROG_LIBTOOL
|
||||
AC_PROG_INSTALL
|
||||
|
||||
@@ -113,6 +114,27 @@ then
|
||||
PKG_CHECK_MODULES([UDEV], [libudev >= 215])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([bindings-cxx],
|
||||
[AC_HELP_STRING([--enable-bindings-cxx],
|
||||
[enable C++ bindings [default=no]])],
|
||||
[
|
||||
if test "x$enableval" = xyes
|
||||
then
|
||||
with_bindings_cxx=true
|
||||
else
|
||||
with_bindings_cxx=false
|
||||
fi
|
||||
],
|
||||
[with_bindings_cxx=false])
|
||||
AM_CONDITIONAL([WITH_BINDINGS_CXX], [test "x$with_bindings_cxx" = xtrue])
|
||||
|
||||
if test "x$with_bindings_cxx" = xtrue
|
||||
then
|
||||
AC_LIBTOOL_CXX
|
||||
# This needs autoconf-archive
|
||||
AX_CXX_COMPILE_STDCXX_11([ext], [mandatory])
|
||||
fi
|
||||
|
||||
AC_CHECK_PROG([has_doxygen], [doxygen], [true], [false])
|
||||
AM_CONDITIONAL([HAS_DOXYGEN], [test "x$has_doxygen" = xtrue])
|
||||
if test "x$has_doxygen" = xfalse
|
||||
@@ -126,6 +148,9 @@ AC_CONFIG_FILES([libgpiod.pc
|
||||
src/Makefile
|
||||
src/lib/Makefile
|
||||
src/tools/Makefile
|
||||
tests/Makefile])
|
||||
tests/Makefile
|
||||
bindings/Makefile
|
||||
bindings/cxx/Makefile
|
||||
bindings/cxx/examples/Makefile])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
Reference in New Issue
Block a user