For easier review, let's first remove the entire sub-tree containing the old C++ bindings. Signed-off-by: Bartosz Golaszewski <brgl@xxxxxxxx> --- bindings/cxx/Makefile.am | 28 - bindings/cxx/chip.cpp | 157 ---- bindings/cxx/examples/.gitignore | 9 - bindings/cxx/examples/Makefile.am | 26 - bindings/cxx/examples/gpiodetectcxx.cpp | 30 - bindings/cxx/examples/gpiofindcxx.cpp | 32 - bindings/cxx/examples/gpiogetcxx.cpp | 39 - bindings/cxx/examples/gpioinfocxx.cpp | 51 -- bindings/cxx/examples/gpiomoncxx.cpp | 65 -- bindings/cxx/examples/gpiosetcxx.cpp | 48 -- bindings/cxx/gpiod.hpp | 940 --------------------- bindings/cxx/internal.hpp | 9 - bindings/cxx/iter.cpp | 60 -- bindings/cxx/libgpiodcxx.pc.in | 14 - bindings/cxx/line.cpp | 321 ------- bindings/cxx/line_bulk.cpp | 366 -------- bindings/cxx/tests/.gitignore | 4 - bindings/cxx/tests/Makefile.am | 21 - bindings/cxx/tests/gpio-mockup.cpp | 153 ---- bindings/cxx/tests/gpio-mockup.hpp | 94 --- bindings/cxx/tests/gpiod-cxx-test-main.cpp | 5 - bindings/cxx/tests/gpiod-cxx-test.cpp | 55 -- bindings/cxx/tests/tests-chip.cpp | 173 ---- bindings/cxx/tests/tests-event.cpp | 280 ------ bindings/cxx/tests/tests-iter.cpp | 21 - bindings/cxx/tests/tests-line.cpp | 467 ---------- 26 files changed, 3468 deletions(-) delete mode 100644 bindings/cxx/Makefile.am delete mode 100644 bindings/cxx/chip.cpp delete mode 100644 bindings/cxx/examples/.gitignore delete mode 100644 bindings/cxx/examples/Makefile.am delete mode 100644 bindings/cxx/examples/gpiodetectcxx.cpp delete mode 100644 bindings/cxx/examples/gpiofindcxx.cpp delete mode 100644 bindings/cxx/examples/gpiogetcxx.cpp delete mode 100644 bindings/cxx/examples/gpioinfocxx.cpp delete mode 100644 bindings/cxx/examples/gpiomoncxx.cpp delete mode 100644 bindings/cxx/examples/gpiosetcxx.cpp delete mode 100644 bindings/cxx/gpiod.hpp delete mode 100644 bindings/cxx/internal.hpp delete mode 100644 bindings/cxx/iter.cpp delete mode 100644 bindings/cxx/libgpiodcxx.pc.in delete mode 100644 bindings/cxx/line.cpp delete mode 100644 bindings/cxx/line_bulk.cpp delete mode 100644 bindings/cxx/tests/.gitignore delete mode 100644 bindings/cxx/tests/Makefile.am delete mode 100644 bindings/cxx/tests/gpio-mockup.cpp delete mode 100644 bindings/cxx/tests/gpio-mockup.hpp delete mode 100644 bindings/cxx/tests/gpiod-cxx-test-main.cpp delete mode 100644 bindings/cxx/tests/gpiod-cxx-test.cpp delete mode 100644 bindings/cxx/tests/tests-chip.cpp delete mode 100644 bindings/cxx/tests/tests-event.cpp delete mode 100644 bindings/cxx/tests/tests-iter.cpp delete mode 100644 bindings/cxx/tests/tests-line.cpp diff --git a/bindings/cxx/Makefile.am b/bindings/cxx/Makefile.am deleted file mode 100644 index d9fa577..0000000 --- a/bindings/cxx/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -lib_LTLIBRARIES = libgpiodcxx.la -libgpiodcxx_la_SOURCES = chip.cpp internal.h 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-info $(subst .,:,$(ABI_CXX_VERSION)) -libgpiodcxx_la_LDFLAGS += -lgpiod -L$(top_builddir)/lib - -include_HEADERS = gpiod.hpp - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libgpiodcxx.pc - -SUBDIRS = . - -if WITH_TESTS - -SUBDIRS += tests - -endif - -if WITH_EXAMPLES - -SUBDIRS += examples - -endif diff --git a/bindings/cxx/chip.cpp b/bindings/cxx/chip.cpp deleted file mode 100644 index ee6ab6f..0000000 --- a/bindings/cxx/chip.cpp +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -#include <functional> -#include <gpiod.hpp> -#include <map> -#include <system_error> -#include <utility> - -#include "internal.hpp" - -namespace gpiod { - -namespace { - -GPIOD_CXX_API void chip_deleter(::gpiod_chip* chip) -{ - ::gpiod_chip_unref(chip); -} - -} /* namespace */ - -GPIOD_CXX_API bool is_gpiochip_device(const ::std::string& path) -{ - return ::gpiod_is_gpiochip_device(path.c_str()); -} - -GPIOD_CXX_API chip::chip(const ::std::string& path) - : _m_chip() -{ - this->open(path); -} - -GPIOD_CXX_API chip::chip(::gpiod_chip* chip) - : _m_chip(chip, chip_deleter) -{ - -} - -GPIOD_CXX_API chip::chip(const ::std::weak_ptr<::gpiod_chip>& chip_ptr) - : _m_chip(chip_ptr) -{ - -} - -GPIOD_CXX_API void chip::open(const ::std::string& path) -{ - ::gpiod_chip *chip = ::gpiod_chip_open(path.c_str()); - if (!chip) - throw ::std::system_error(errno, ::std::system_category(), - "cannot open GPIO device " + path); - - this->_m_chip.reset(chip, chip_deleter); -} - -GPIOD_CXX_API void chip::reset(void) noexcept -{ - this->_m_chip.reset(); -} - -GPIOD_CXX_API ::std::string chip::name(void) const -{ - this->throw_if_noref(); - - return ::std::string(::gpiod_chip_get_name(this->_m_chip.get())); -} - -GPIOD_CXX_API ::std::string chip::label(void) const -{ - this->throw_if_noref(); - - return ::std::string(::gpiod_chip_get_label(this->_m_chip.get())); -} - -GPIOD_CXX_API unsigned int chip::num_lines(void) const -{ - this->throw_if_noref(); - - return ::gpiod_chip_get_num_lines(this->_m_chip.get()); -} - -GPIOD_CXX_API 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 line(line_handle, *this); -} - -GPIOD_CXX_API int chip::find_line(const ::std::string& name) const -{ - this->throw_if_noref(); - - for (unsigned int offset = 0; offset < this->num_lines(); offset++) { - auto line = this->get_line(offset); - - if (line.name() == name) - return offset; - } - - return -1; -} - -GPIOD_CXX_API line_bulk chip::get_lines(const ::std::vector<unsigned int>& offsets) const -{ - line_bulk lines; - - for (auto& it: offsets) - lines.append(this->get_line(it)); - - return lines; -} - -GPIOD_CXX_API line_bulk chip::get_all_lines(void) const -{ - line_bulk lines; - - for (unsigned int i = 0; i < this->num_lines(); i++) - lines.append(this->get_line(i)); - - return lines; -} - -GPIOD_CXX_API bool chip::operator==(const chip& rhs) const noexcept -{ - return this->_m_chip.get() == rhs._m_chip.get(); -} - -GPIOD_CXX_API bool chip::operator!=(const chip& rhs) const noexcept -{ - return this->_m_chip.get() != rhs._m_chip.get(); -} - -GPIOD_CXX_API chip::operator bool(void) const noexcept -{ - return this->_m_chip.get() != nullptr; -} - -GPIOD_CXX_API bool chip::operator!(void) const noexcept -{ - return this->_m_chip.get() == nullptr; -} - -GPIOD_CXX_API 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 */ diff --git a/bindings/cxx/examples/.gitignore b/bindings/cxx/examples/.gitignore deleted file mode 100644 index 54bda46..0000000 --- a/bindings/cxx/examples/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -gpiodetectcxx -gpiofindcxx -gpiogetcxx -gpioinfocxx -gpiomoncxx -gpiosetcxx diff --git a/bindings/cxx/examples/Makefile.am b/bindings/cxx/examples/Makefile.am deleted file mode 100644 index 748b581..0000000 --- a/bindings/cxx/examples/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -AM_CPPFLAGS = -I$(top_srcdir)/bindings/cxx/ -I$(top_srcdir)/include -AM_CPPFLAGS += -Wall -Wextra -g -std=gnu++17 -AM_LDFLAGS = -lgpiodcxx -L$(top_builddir)/bindings/cxx/ -lstdc++fs - -noinst_PROGRAMS = \ - gpiodetectcxx \ - gpiofindcxx \ - gpiogetcxx \ - gpioinfocxx \ - gpiomoncxx \ - gpiosetcxx - -gpiodetectcxx_SOURCES = gpiodetectcxx.cpp - -gpiofindcxx_SOURCES = gpiofindcxx.cpp - -gpiogetcxx_SOURCES = gpiogetcxx.cpp - -gpioinfocxx_SOURCES = gpioinfocxx.cpp - -gpiomoncxx_SOURCES = gpiomoncxx.cpp - -gpiosetcxx_SOURCES = gpiosetcxx.cpp diff --git a/bindings/cxx/examples/gpiodetectcxx.cpp b/bindings/cxx/examples/gpiodetectcxx.cpp deleted file mode 100644 index 872cd96..0000000 --- a/bindings/cxx/examples/gpiodetectcxx.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -/* C++ reimplementation of the gpiodetect tool. */ - -#include <gpiod.hpp> - -#include <cstdlib> -#include <filesystem> -#include <iostream> - -int main(int argc, char **argv) -{ - if (argc != 1) { - ::std::cerr << "usage: " << argv[0] << ::std::endl; - return EXIT_FAILURE; - } - - for (const auto& entry: ::std::filesystem::directory_iterator("/dev/")) { - if (::gpiod::is_gpiochip_device(entry.path())) { - ::gpiod::chip chip(entry.path()); - - ::std::cout << chip.name() << " [" - << chip.label() << "] (" - << chip.num_lines() << " lines)" << ::std::endl; - } - } - - return EXIT_SUCCESS; -} diff --git a/bindings/cxx/examples/gpiofindcxx.cpp b/bindings/cxx/examples/gpiofindcxx.cpp deleted file mode 100644 index ec4d79b..0000000 --- a/bindings/cxx/examples/gpiofindcxx.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -/* C++ reimplementation of the gpiofind tool. */ - -#include <gpiod.hpp> - -#include <cstdlib> -#include <filesystem> -#include <iostream> - -int main(int argc, char **argv) -{ - if (argc != 2) { - ::std::cerr << "usage: " << argv[0] << " <line name>" << ::std::endl; - return EXIT_FAILURE; - } - - for (const auto& entry: ::std::filesystem::directory_iterator("/dev/")) { - if (::gpiod::is_gpiochip_device(entry.path())) { - ::gpiod::chip chip(entry.path()); - - auto offset = chip.find_line(argv[1]); - if (offset >= 0) { - ::std::cout << chip.name() << " " << offset << ::std::endl; - return EXIT_SUCCESS; - } - } - } - - return EXIT_FAILURE; -} diff --git a/bindings/cxx/examples/gpiogetcxx.cpp b/bindings/cxx/examples/gpiogetcxx.cpp deleted file mode 100644 index 94b3dac..0000000 --- a/bindings/cxx/examples/gpiogetcxx.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -/* 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; -} diff --git a/bindings/cxx/examples/gpioinfocxx.cpp b/bindings/cxx/examples/gpioinfocxx.cpp deleted file mode 100644 index 2175adc..0000000 --- a/bindings/cxx/examples/gpioinfocxx.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -/* Simplified C++ reimplementation of the gpioinfo tool. */ - -#include <gpiod.hpp> - -#include <cstdlib> -#include <filesystem> -#include <iostream> - -int main(int argc, char **argv) -{ - if (argc != 1) { - ::std::cerr << "usage: " << argv[0] << ::std::endl; - return EXIT_FAILURE; - } - - for (const auto& entry: ::std::filesystem::directory_iterator("/dev/")) { - if (::gpiod::is_gpiochip_device(entry.path())) { - ::gpiod::chip chip(entry.path()); - - ::std::cout << chip.name() << " - " << chip.num_lines() << " lines:" << ::std::endl; - - for (auto& lit: ::gpiod::line_iter(chip)) { - ::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.is_active_low() ? "active-low" : "active-high"); - - ::std::cout << ::std::endl; - } - } - } - - return EXIT_SUCCESS; -} diff --git a/bindings/cxx/examples/gpiomoncxx.cpp b/bindings/cxx/examples/gpiomoncxx.cpp deleted file mode 100644 index 4d6ac6e..0000000 --- a/bindings/cxx/examples/gpiomoncxx.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -/* 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::seconds(1)); - if (events) { - for (auto& it: events) - print_event(it.event_read()); - } - } - - return EXIT_SUCCESS; -} diff --git a/bindings/cxx/examples/gpiosetcxx.cpp b/bindings/cxx/examples/gpiosetcxx.cpp deleted file mode 100644 index 71b27a9..0000000 --- a/bindings/cxx/examples/gpiosetcxx.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -/* 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; -} diff --git a/bindings/cxx/gpiod.hpp b/bindings/cxx/gpiod.hpp deleted file mode 100644 index e3ce2fc..0000000 --- a/bindings/cxx/gpiod.hpp +++ /dev/null @@ -1,940 +0,0 @@ -/* SPDX-License-Identifier: LGPL-3.0-or-later */ -/* SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> */ - -#ifndef __LIBGPIOD_GPIOD_CXX_HPP__ -#define __LIBGPIOD_GPIOD_CXX_HPP__ - -#include <bitset> -#include <chrono> -#include <gpiod.h> -#include <memory> -#include <string> -#include <vector> - -namespace gpiod { - -class line; -class line_bulk; -class line_iter; -class chip_iter; -struct line_event; - -/** - * @file gpiod.hpp - */ - -/** - * @defgroup gpiod_cxx C++ bindings - * @{ - */ - -/** - * @brief Check if the file pointed to by path is a GPIO chip character device. - * @param path Path to check. - * @return True if the file exists and is a GPIO chip character device or a - * symbolic link to it. - */ -bool is_gpiochip_device(const ::std::string& path); - -/** - * @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. - */ - chip(void) = default; - - /** - * @brief Constructor. Opens the chip using chip::open. - * @param path Path to the GPIO chip device. - */ - chip(const ::std::string& path); - - /** - * @brief Copy constructor. References the object held by other. - * @param other Other chip object. - */ - chip(const chip& other) = default; - - /** - * @brief Move constructor. References the object held by other. - * @param other Other chip object. - */ - chip(chip&& other) = default; - - /** - * @brief Assignment operator. References the object held by other. - * @param other Other chip object. - * @return Reference to this object. - */ - 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. - */ - chip& operator=(chip&& other) = default; - - /** - * @brief Destructor. Unreferences the internal chip object. - */ - ~chip(void) = default; - - /** - * @brief Open a GPIO chip. - * @param path Path to the GPIO chip device. - * - * If the object already holds a reference to an open chip, it will be - * closed and the reference reset. - */ - void open(const ::std::string &path); - - /** - * @brief Reset the internal smart pointer owned by this object. - */ - void reset(void) noexcept; - - /** - * @brief Return the name of the chip held by this object. - * @return Name of the GPIO chip. - */ - ::std::string name(void) const; - - /** - * @brief Return the label of the chip held by this object. - * @return Label of the GPIO chip. - */ - ::std::string label(void) const; - - /** - * @brief Return the number of lines exposed by this chip. - * @return Number of lines. - */ - 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. - */ - line get_line(unsigned int offset) const; - - /** - * @brief Map a GPIO line's name to its offset within the chip. - * @param name Name of the GPIO line to map. - * @return Offset of the line within the chip or -1 if a line with - * given name is not exposed by the chip. - */ - int 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. - */ - line_bulk get_lines(const ::std::vector<unsigned int>& offsets) const; - - /** - * @brief Get all lines exposed by this chip. - * @return All lines exposed by this chip held by a line_bulk object. - */ - line_bulk get_all_lines(void) const; - - /** - * @brief Equality operator. - * @param rhs Right-hand side of the equation. - * @return True if rhs references the same chip. False otherwise. - */ - 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. - */ - 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. - */ - explicit 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. - */ - bool operator!(void) const noexcept; - -private: - - chip(::gpiod_chip* chip); - chip(const ::std::weak_ptr<::gpiod_chip>& chip_ptr); - - void throw_if_noref(void) const; - - ::std::shared_ptr<::gpiod_chip> _m_chip; - - friend line; - friend chip_iter; - friend line_iter; -}; - -/** - * @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. */ - static const ::std::bitset<32> FLAG_BIAS_DISABLED; - /**< The line has neither pull-up nor pull-down resistor enabled. */ - static const ::std::bitset<32> FLAG_BIAS_PULL_DOWN; - /**< The line has a configurable pull-down resistor enabled. */ - static const ::std::bitset<32> FLAG_BIAS_PULL_UP; - /**< The line has a configurable pull-up resistor enabled. */ - - ::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. - */ - line(void); - - /** - * @brief Copy constructor. - * @param other Other line object. - */ - line(const line& other) = default; - - /** - * @brief Move constructor. - * @param other Other line object. - */ - line(line&& other) = default; - - /** - * @brief Assignment operator. - * @param other Other line object. - * @return Reference to this object. - */ - line& operator=(const line& other) = default; - - /** - * @brief Move assignment operator. - * @param other Other line object. - * @return Reference to this object. - */ - line& operator=(line&& other) = default; - - /** - * @brief Destructor. - */ - ~line(void) = default; - - /** - * @brief Get the offset of this line. - * @return Offet of this line. - */ - 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. - */ - ::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. - */ - ::std::string consumer(void) const; - - /** - * @brief Get current direction of this line. - * @return Current direction setting. - */ - int direction(void) const; - - /** - * @brief Check if this line's signal is inverted. - * @return True if this line is "active-low", false otherwise. - */ - bool is_active_low(void) const; - - /** - * @brief Get current bias of this line. - * @return Current bias setting. - */ - int bias(void) const; - - /** - * @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. - */ - bool is_used(void) const; - - /** - * @brief Get current drive setting of this line. - * @return Current drive setting. - */ - int drive(void) const; - - /** - * @brief Request this line. - * @param config Request config (see gpiod::line_request). - * @param default_val Default value - only matters for OUTPUT direction. - */ - void request(const line_request& config, int default_val = 0) const; - - /** - * @brief Release the line if it was previously requested. - */ - void release(void) const; - - /** - * @brief Read the line value. - * @return Current value (0 or 1). - */ - int get_value(void) const; - - /** - * @brief Set the value of this line. - * @param val New value (0 or 1). - */ - void set_value(int val) const; - - /** - * @brief Set configuration of this line. - * @param direction New direction. - * @param flags Replacement flags. - * @param value New value (0 or 1) - only matters for OUTPUT direction. - */ - void set_config(int direction, ::std::bitset<32> flags, int value = 0) const; - - /** - * @brief Set configuration flags of this line. - * @param flags Replacement flags. - */ - void set_flags(::std::bitset<32> flags) const; - - /** - * @brief Change the direction this line to input. - */ - void set_direction_input() const; - - /** - * @brief Change the direction this lines to output. - * @param value New value (0 or 1). - */ - void set_direction_output(int value = 0) 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. - */ - bool event_wait(const ::std::chrono::nanoseconds& timeout) const; - - /** - * @brief Read a line event. - * @return Line event object. - */ - line_event event_read(void) const; - - /** - * @brief Read multiple line events. - * @return Vector of line event objects. - */ - ::std::vector<line_event> event_read_multiple(void) const; - - /** - * @brief Get the event file descriptor associated with this line. - * @return File descriptor number. - */ - int event_get_fd(void) const; - - /** - * @brief Get the parent chip. - * @return Parent chip of this line. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - explicit 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. - */ - 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 drive settings. - */ - enum : int { - DRIVE_PUSH_PULL = 1, - /**< Drive setting is unknown. */ - DRIVE_OPEN_DRAIN, - /**< Line output is open-drain. */ - DRIVE_OPEN_SOURCE, - /**< Line output is open-source. */ - }; - - /** - * @brief Possible bias settings. - */ - enum : int { - BIAS_UNKNOWN = 1, - /**< Line's bias state is unknown. */ - BIAS_DISABLED, - /**< Line's internal bias is disabled. */ - BIAS_PULL_UP, - /**< Line's internal pull-up bias is enabled. */ - BIAS_PULL_DOWN, - /**< Line's internal pull-down bias is enabled. */ - }; - -private: - - line(::gpiod_line* line, const chip& owner); - - void throw_if_null(void) const; - line_event make_line_event(const ::gpiod_line_event& event) const noexcept; - - ::gpiod_line* _m_line; - ::std::weak_ptr<::gpiod_chip> _m_owner; - - class chip_guard - { - public: - chip_guard(const line& line); - ~chip_guard(void) = default; - - chip_guard(const chip_guard& other) = delete; - chip_guard(chip_guard&& other) = delete; - chip_guard& operator=(const chip_guard&& other) = delete; - chip_guard& operator=(chip_guard&& other) = delete; - - private: - ::std::shared_ptr<::gpiod_chip> _m_chip; - }; - - friend chip; - friend line_bulk; - friend line_iter; -}; - -/** - * @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. - */ - 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. - */ - line_bulk(const ::std::vector<line>& lines); - - /** - * @brief Copy constructor. - * @param other Other line_bulk object. - */ - line_bulk(const line_bulk& other) = default; - - /** - * @brief Move constructor. - * @param other Other line_bulk object. - */ - line_bulk(line_bulk&& other) = default; - - /** - * @brief Assignment operator. - * @param other Other line_bulk object. - * @return Reference to this object. - */ - line_bulk& operator=(const line_bulk& other) = default; - - /** - * @brief Move assignment operator. - * @param other Other line_bulk object. - * @return Reference to this object. - */ - line_bulk& operator=(line_bulk&& other) = default; - - /** - * @brief Destructor. - */ - ~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. - */ - void append(const line& new_line); - - /** - * @brief Get the line at given offset. - * @param index Index of the line to get. - * @return Reference to the line object. - * @note This method will throw if index is equal or greater than the - * number of lines currently held by this bulk. - */ - line& get(unsigned int index); - - /** - * @brief Get the line at given offset without bounds checking. - * @param index Offset of the line to get. - * @return Reference to the line object. - * @note No bounds checking is performed. - */ - line& operator[](unsigned int index); - - /** - * @brief Get the number of lines currently held by this object. - * @return Number of elements in this line_bulk. - */ - 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. - */ - bool empty(void) const noexcept; - - /** - * @brief Remove all lines from this object. - */ - 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. - */ - void request(const line_request& config, - const ::std::vector<int> default_vals = ::std::vector<int>()) const; - - /** - * @brief Release all lines held by this object. - */ - void release(void) 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. - */ - ::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. - */ - void set_values(const ::std::vector<int>& values) const; - - /** - * @brief Set configuration of all lines held by this object. - * @param direction New direction. - * @param flags Replacement flags. - * @param values Vector of values to set. Must be the same size as the - * number of lines held by this line_bulk. - * Only relevant for output direction requests. - */ - void set_config(int direction, ::std::bitset<32> flags, - const ::std::vector<int> values = ::std::vector<int>()) const; - - /** - * @brief Set configuration flags of all lines held by this object. - * @param flags Replacement flags. - */ - void set_flags(::std::bitset<32> flags) const; - - /** - * @brief Change the direction all lines held by this object to input. - */ - void set_direction_input() const; - - /** - * @brief Change the direction all lines held by this object to output. - * @param values Vector of values to set. Must be the same size as the - * number of lines held by this line_bulk. - */ - void set_direction_output(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. - */ - 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. - */ - explicit 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. - */ - bool operator!(void) const noexcept; - - /** - * @brief Max number of lines that this object can hold. - */ - 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. - */ - iterator(void) = default; - - /** - * @brief Copy constructor. - * @param other Other line_bulk iterator. - */ - iterator(const iterator& other) = default; - - /** - * @brief Move constructor. - * @param other Other line_bulk iterator. - */ - iterator(iterator&& other) = default; - - /** - * @brief Assignment operator. - * @param other Other line_bulk iterator. - * @return Reference to this iterator. - */ - iterator& operator=(const iterator& other) = default; - - /** - * @brief Move assignment operator. - * @param other Other line_bulk iterator. - * @return Reference to this iterator. - */ - iterator& operator=(iterator&& other) = default; - - /** - * @brief Destructor. - */ - ~iterator(void) = default; - - /** - * @brief Advance the iterator by one element. - * @return Reference to this iterator. - */ - iterator& operator++(void); - - /** - * @brief Dereference current element. - * @return Current GPIO line by reference. - */ - const line& operator*(void) const; - - /** - * @brief Member access operator. - * @return Current GPIO line by pointer. - */ - 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. - */ - 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. - */ - 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. - */ - iterator begin(void) noexcept; - - /** - * @brief Returns an iterator to the element following the last line. - * @return A line_bulk iterator. - */ - iterator end(void) noexcept; - -private: - - struct line_bulk_deleter - { - void operator()(::gpiod_line_bulk *bulk); - }; - - void throw_if_empty(void) const; - - using line_bulk_ptr = ::std::unique_ptr<::gpiod_line_bulk, line_bulk_deleter>; - - line_bulk_ptr make_line_bulk_ptr(void) const; - line_bulk_ptr to_line_bulk(void) const; - - ::std::vector<line> _m_bulk; -}; - -/** - * @brief Support for range-based loops for line iterators. - * @param iter A line iterator. - * @return Iterator unchanged. - */ -line_iter begin(line_iter iter) noexcept; - -/** - * @brief Support for range-based loops for line iterators. - * @param iter A line iterator. - * @return New end iterator. - */ -line_iter end(const line_iter& iter) noexcept; - -/** - * @brief Allows to iterate over all lines owned by a GPIO chip. - */ -class line_iter -{ -public: - - /** - * @brief Default constructor. Creates the end iterator. - */ - line_iter(void) = default; - - /** - * @brief Constructor. Creates the begin iterator. - * @param owner Chip owning the GPIO lines over which we want to iterate. - */ - line_iter(const chip& owner); - - /** - * @brief Copy constructor. - * @param other Other line iterator. - */ - line_iter(const line_iter& other) = default; - - /** - * @brief Move constructor. - * @param other Other line iterator. - */ - line_iter(line_iter&& other) = default; - - /** - * @brief Assignment operator. - * @param other Other line iterator. - * @return Reference to this line_iter. - */ - line_iter& operator=(const line_iter& other) = default; - - /** - * @brief Move assignment operator. - * @param other Other line iterator. - * @return Reference to this line_iter. - */ - line_iter& operator=(line_iter&& other) = default; - - /** - * @brief Destructor. - */ - ~line_iter(void) = default; - - /** - * @brief Advance the iterator by one element. - * @return Reference to this iterator. - */ - line_iter& operator++(void); - - /** - * @brief Dereference current element. - * @return Current GPIO line by reference. - */ - const line& operator*(void) const; - - /** - * @brief Member access operator. - * @return Current GPIO line by pointer. - */ - 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_iter, - * false otherwise. - */ - bool operator==(const line_iter& 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_iter, - * false otherwise. - */ - bool operator!=(const line_iter& rhs) const noexcept; - -private: - - line _m_current; -}; - -/** - * @} - */ - -} /* namespace gpiod */ - -#endif /* __LIBGPIOD_GPIOD_CXX_HPP__ */ diff --git a/bindings/cxx/internal.hpp b/bindings/cxx/internal.hpp deleted file mode 100644 index 9406d30..0000000 --- a/bindings/cxx/internal.hpp +++ /dev/null @@ -1,9 +0,0 @@ -/* SPDX-License-Identifier: LGPL-3.0-or-later */ -/* SPDX-FileCopyrightText: 2021 Bartosz Golaszewski <bgolaszewski@xxxxxxxxxxxx> */ - -#ifndef __LIBGPIOD_GPIOD_CXX_INTERNAL_HPP__ -#define __LIBGPIOD_GPIOD_CXX_INTERNAL_HPP__ - -#define GPIOD_CXX_API __attribute__((visibility("default"))) - -#endif /* __LIBGPIOD_GPIOD_CXX_INTERNAL_HPP__ */ diff --git a/bindings/cxx/iter.cpp b/bindings/cxx/iter.cpp deleted file mode 100644 index 09d46f3..0000000 --- a/bindings/cxx/iter.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -#include <gpiod.hpp> -#include <system_error> - -#include "internal.hpp" - -namespace gpiod { - -GPIOD_CXX_API line_iter begin(line_iter iter) noexcept -{ - return iter; -} - -GPIOD_CXX_API line_iter end(const line_iter&) noexcept -{ - return line_iter(); -} - -GPIOD_CXX_API line_iter::line_iter(const chip& owner) - : _m_current(owner.get_line(0)) -{ - -} - -GPIOD_CXX_API line_iter& line_iter::operator++(void) -{ - unsigned int offset = this->_m_current.offset() + 1; - chip owner = this->_m_current.get_chip(); - - if (offset == owner.num_lines()) - this->_m_current = line(); /* Last element */ - else - this->_m_current = owner.get_line(offset); - - return *this; -} - -GPIOD_CXX_API const line& line_iter::operator*(void) const -{ - return this->_m_current; -} - -GPIOD_CXX_API const line* line_iter::operator->(void) const -{ - return ::std::addressof(this->_m_current); -} - -GPIOD_CXX_API bool line_iter::operator==(const line_iter& rhs) const noexcept -{ - return this->_m_current._m_line == rhs._m_current._m_line; -} - -GPIOD_CXX_API bool line_iter::operator!=(const line_iter& rhs) const noexcept -{ - return this->_m_current._m_line != rhs._m_current._m_line; -} - -} /* namespace gpiod */ diff --git a/bindings/cxx/libgpiodcxx.pc.in b/bindings/cxx/libgpiodcxx.pc.in deleted file mode 100644 index 731227c..0000000 --- a/bindings/cxx/libgpiodcxx.pc.in +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libgpiodcxx -Description: C++ bindings for libgpiod -URL: @PACKAGE_URL@ -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lgpiodcxx -Cflags: -I${includedir} diff --git a/bindings/cxx/line.cpp b/bindings/cxx/line.cpp deleted file mode 100644 index cfcf2fb..0000000 --- a/bindings/cxx/line.cpp +++ /dev/null @@ -1,321 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -#include <gpiod.hpp> -#include <array> -#include <map> -#include <system_error> - -#include "internal.hpp" - -namespace gpiod { - -namespace { - -const ::std::map<int, int> drive_mapping = { - { GPIOD_LINE_DRIVE_PUSH_PULL, line::DRIVE_PUSH_PULL, }, - { GPIOD_LINE_DRIVE_OPEN_DRAIN, line::DRIVE_OPEN_DRAIN, }, - { GPIOD_LINE_DRIVE_OPEN_SOURCE, line::DRIVE_OPEN_SOURCE, }, -}; - -const ::std::map<int, int> bias_mapping = { - { GPIOD_LINE_BIAS_UNKNOWN, line::BIAS_UNKNOWN, }, - { GPIOD_LINE_BIAS_DISABLED, line::BIAS_DISABLED, }, - { GPIOD_LINE_BIAS_PULL_UP, line::BIAS_PULL_UP, }, - { GPIOD_LINE_BIAS_PULL_DOWN, line::BIAS_PULL_DOWN, }, -}; - -} /* namespace */ - -GPIOD_CXX_API line::line(void) - : _m_line(nullptr), - _m_owner() -{ - -} - -GPIOD_CXX_API line::line(::gpiod_line* line, const chip& owner) - : _m_line(line), - _m_owner(owner._m_chip) -{ - -} - -GPIOD_CXX_API unsigned int line::offset(void) const -{ - this->throw_if_null(); - line::chip_guard lock_chip(*this); - - return ::gpiod_line_offset(this->_m_line); -} - -GPIOD_CXX_API ::std::string line::name(void) const -{ - this->throw_if_null(); - line::chip_guard lock_chip(*this); - - const char* name = ::gpiod_line_name(this->_m_line); - - return name ? ::std::string(name) : ::std::string(); -} - -GPIOD_CXX_API ::std::string line::consumer(void) const -{ - this->throw_if_null(); - line::chip_guard lock_chip(*this); - - const char* consumer = ::gpiod_line_consumer(this->_m_line); - - return consumer ? ::std::string(consumer) : ::std::string(); -} - -GPIOD_CXX_API int line::direction(void) const -{ - this->throw_if_null(); - line::chip_guard lock_chip(*this); - - int dir = ::gpiod_line_direction(this->_m_line); - - return dir == GPIOD_LINE_DIRECTION_INPUT ? DIRECTION_INPUT : DIRECTION_OUTPUT; -} - -GPIOD_CXX_API bool line::is_active_low(void) const -{ - this->throw_if_null(); - line::chip_guard lock_chip(*this); - - return ::gpiod_line_is_active_low(this->_m_line); -} - -GPIOD_CXX_API int line::bias(void) const -{ - this->throw_if_null(); - line::chip_guard lock_chip(*this); - - return bias_mapping.at(::gpiod_line_bias(this->_m_line)); -} - -GPIOD_CXX_API bool line::is_used(void) const -{ - this->throw_if_null(); - line::chip_guard lock_chip(*this); - - return ::gpiod_line_is_used(this->_m_line); -} - -GPIOD_CXX_API int line::drive(void) const -{ - this->throw_if_null(); - line::chip_guard lock_chip(*this); - - return drive_mapping.at(::gpiod_line_drive(this->_m_line)); -} - -GPIOD_CXX_API void line::request(const line_request& config, int default_val) const -{ - this->throw_if_null(); - - line_bulk bulk({ *this }); - - bulk.request(config, { default_val }); -} - -GPIOD_CXX_API void line::release(void) const -{ - this->throw_if_null(); - - line_bulk bulk({ *this }); - - bulk.release(); -} - -/* - * 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. - */ - -GPIOD_CXX_API int line::get_value(void) const -{ - this->throw_if_null(); - - line_bulk bulk({ *this }); - - return bulk.get_values()[0]; -} - -GPIOD_CXX_API void line::set_value(int val) const -{ - this->throw_if_null(); - - line_bulk bulk({ *this }); - - bulk.set_values({ val }); -} - -GPIOD_CXX_API void line::set_config(int direction, ::std::bitset<32> flags, - int value) const -{ - this->throw_if_null(); - - line_bulk bulk({ *this }); - - bulk.set_config(direction, flags, { value }); -} - -GPIOD_CXX_API void line::set_flags(::std::bitset<32> flags) const -{ - this->throw_if_null(); - - line_bulk bulk({ *this }); - - bulk.set_flags(flags); -} - -GPIOD_CXX_API void line::set_direction_input() const -{ - this->throw_if_null(); - - line_bulk bulk({ *this }); - - bulk.set_direction_input(); -} - -GPIOD_CXX_API void line::set_direction_output(int value) const -{ - this->throw_if_null(); - - line_bulk bulk({ *this }); - - bulk.set_direction_output({ value }); -} - -GPIOD_CXX_API 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 !!event_bulk; -} - -GPIOD_CXX_API line_event line::make_line_event(const ::gpiod_line_event& event) const noexcept -{ - line_event ret; - - if (event.event_type == GPIOD_LINE_EVENT_RISING_EDGE) - ret.event_type = line_event::RISING_EDGE; - else if (event.event_type == GPIOD_LINE_EVENT_FALLING_EDGE) - ret.event_type = line_event::FALLING_EDGE; - - ret.timestamp = ::std::chrono::duration_cast<::std::chrono::nanoseconds>( - ::std::chrono::seconds(event.ts.tv_sec)) + - ::std::chrono::nanoseconds(event.ts.tv_nsec); - - ret.source = *this; - - return ret; -} - -GPIOD_CXX_API line_event line::event_read(void) const -{ - this->throw_if_null(); - line::chip_guard lock_chip(*this); - - ::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"); - - return this->make_line_event(event_buf); -} - -GPIOD_CXX_API ::std::vector<line_event> line::event_read_multiple(void) const -{ - this->throw_if_null(); - line::chip_guard lock_chip(*this); - - /* 16 is the maximum number of events stored in the kernel FIFO. */ - ::std::array<::gpiod_line_event, 16> event_buf; - ::std::vector<line_event> events; - int rv; - - rv = ::gpiod_line_event_read_multiple(this->_m_line, - event_buf.data(), event_buf.size()); - if (rv < 0) - throw ::std::system_error(errno, ::std::system_category(), - "error reading multiple line events"); - - events.reserve(rv); - for (int i = 0; i < rv; i++) - events.push_back(this->make_line_event(event_buf[i])); - - return events; -} - -GPIOD_CXX_API int line::event_get_fd(void) const -{ - this->throw_if_null(); - line::chip_guard lock_chip(*this); - - int ret = ::gpiod_line_event_get_fd(this->_m_line); - - if (ret < 0) - throw ::std::system_error(errno, ::std::system_category(), - "unable to get the line event file descriptor"); - - return ret; -} - -GPIOD_CXX_API const chip line::get_chip(void) const -{ - return chip(this->_m_owner); -} - -GPIOD_CXX_API void line::reset(void) -{ - this->_m_line = nullptr; - this->_m_owner.reset(); -} - -GPIOD_CXX_API bool line::operator==(const line& rhs) const noexcept -{ - return this->_m_line == rhs._m_line; -} - -GPIOD_CXX_API bool line::operator!=(const line& rhs) const noexcept -{ - return this->_m_line != rhs._m_line; -} - -GPIOD_CXX_API line::operator bool(void) const noexcept -{ - return this->_m_line != nullptr; -} - -GPIOD_CXX_API bool line::operator!(void) const noexcept -{ - return this->_m_line == nullptr; -} - -GPIOD_CXX_API void line::throw_if_null(void) const -{ - if (!this->_m_line) - throw ::std::logic_error("object not holding a GPIO line handle"); -} - -GPIOD_CXX_API line::chip_guard::chip_guard(const line& line) - : _m_chip(line._m_owner) -{ - -} - -} /* namespace gpiod */ diff --git a/bindings/cxx/line_bulk.cpp b/bindings/cxx/line_bulk.cpp deleted file mode 100644 index a9261c0..0000000 --- a/bindings/cxx/line_bulk.cpp +++ /dev/null @@ -1,366 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -#include <gpiod.hpp> -#include <map> -#include <system_error> - -#include "internal.hpp" - -namespace gpiod { - -GPIOD_CXX_API const ::std::bitset<32> line_request::FLAG_ACTIVE_LOW(GPIOD_BIT(0)); -GPIOD_CXX_API const ::std::bitset<32> line_request::FLAG_OPEN_SOURCE(GPIOD_BIT(1)); -GPIOD_CXX_API const ::std::bitset<32> line_request::FLAG_OPEN_DRAIN(GPIOD_BIT(2)); -GPIOD_CXX_API const ::std::bitset<32> line_request::FLAG_BIAS_DISABLED(GPIOD_BIT(3)); -GPIOD_CXX_API const ::std::bitset<32> line_request::FLAG_BIAS_PULL_DOWN(GPIOD_BIT(4)); -GPIOD_CXX_API const ::std::bitset<32> line_request::FLAG_BIAS_PULL_UP(GPIOD_BIT(5)); - -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) const - { - 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, }, - { line_request::FLAG_BIAS_DISABLED, GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLED, }, - { line_request::FLAG_BIAS_PULL_DOWN, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN, }, - { line_request::FLAG_BIAS_PULL_UP, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP, }, -}; - -} /* namespace */ - -GPIOD_CXX_API const unsigned int line_bulk::MAX_LINES = 64; - -GPIOD_CXX_API line_bulk::line_bulk(const ::std::vector<line>& lines) - : _m_bulk() -{ - this->_m_bulk.reserve(lines.size()); - - for (auto& it: lines) - this->append(it); -} - -GPIOD_CXX_API void line_bulk::append(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); -} - -GPIOD_CXX_API line& line_bulk::get(unsigned int index) -{ - return this->_m_bulk.at(index); -} - -GPIOD_CXX_API line& line_bulk::operator[](unsigned int index) -{ - return this->_m_bulk[index]; -} - -GPIOD_CXX_API unsigned int line_bulk::size(void) const noexcept -{ - return this->_m_bulk.size(); -} - -GPIOD_CXX_API bool line_bulk::empty(void) const noexcept -{ - return this->_m_bulk.empty(); -} - -GPIOD_CXX_API void line_bulk::clear(void) -{ - this->_m_bulk.clear(); -} - -GPIOD_CXX_API void line_bulk::request(const line_request& config, const ::std::vector<int> default_vals) const -{ - this->throw_if_empty(); - line::chip_guard lock_chip(this->_m_bulk.front()); - - 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; - auto bulk = this->to_line_bulk(); - int rv; - - 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(bulk.get(), - ::std::addressof(conf), - default_vals.empty() ? NULL : default_vals.data()); - if (rv) - throw ::std::system_error(errno, ::std::system_category(), - "error requesting GPIO lines"); -} - -GPIOD_CXX_API void line_bulk::release(void) const -{ - this->throw_if_empty(); - line::chip_guard lock_chip(this->_m_bulk.front()); - - auto bulk = this->to_line_bulk(); - - ::gpiod_line_release_bulk(bulk.get()); -} - -GPIOD_CXX_API ::std::vector<int> line_bulk::get_values(void) const -{ - this->throw_if_empty(); - line::chip_guard lock_chip(this->_m_bulk.front()); - - auto bulk = this->to_line_bulk(); - ::std::vector<int> values; - int rv; - - values.resize(this->_m_bulk.size()); - - rv = ::gpiod_line_get_value_bulk(bulk.get(), values.data()); - if (rv) - throw ::std::system_error(errno, ::std::system_category(), - "error reading GPIO line values"); - - return values; -} - -GPIOD_CXX_API void line_bulk::set_values(const ::std::vector<int>& values) const -{ - this->throw_if_empty(); - line::chip_guard lock_chip(this->_m_bulk.front()); - - if (values.size() != this->_m_bulk.size()) - throw ::std::invalid_argument("the size of values array must correspond with the number of lines"); - - auto bulk = this->to_line_bulk(); - int rv; - - rv = ::gpiod_line_set_value_bulk(bulk.get(), values.data()); - if (rv) - throw ::std::system_error(errno, ::std::system_category(), - "error setting GPIO line values"); -} - -GPIOD_CXX_API void line_bulk::set_config(int direction, ::std::bitset<32> flags, - const ::std::vector<int> values) const -{ - this->throw_if_empty(); - line::chip_guard lock_chip(this->_m_bulk.front()); - - if (!values.empty() && this->_m_bulk.size() != values.size()) - throw ::std::invalid_argument("the number of default values must correspond with the number of lines"); - - auto bulk = this->to_line_bulk(); - int rv, gflags; - - gflags = 0; - - for (auto& it: reqflag_mapping) { - if ((it.first & flags).to_ulong()) - gflags |= it.second; - } - - rv = ::gpiod_line_set_config_bulk(bulk.get(), direction, - gflags, values.data()); - if (rv) - throw ::std::system_error(errno, ::std::system_category(), - "error setting GPIO line config"); -} - -GPIOD_CXX_API void line_bulk::set_flags(::std::bitset<32> flags) const -{ - this->throw_if_empty(); - line::chip_guard lock_chip(this->_m_bulk.front()); - - auto bulk = this->to_line_bulk(); - int rv, gflags; - - gflags = 0; - - for (auto& it: reqflag_mapping) { - if ((it.first & flags).to_ulong()) - gflags |= it.second; - } - - rv = ::gpiod_line_set_flags_bulk(bulk.get(), gflags); - if (rv) - throw ::std::system_error(errno, ::std::system_category(), - "error setting GPIO line flags"); -} - -GPIOD_CXX_API void line_bulk::set_direction_input() const -{ - this->throw_if_empty(); - line::chip_guard lock_chip(this->_m_bulk.front()); - - auto bulk = this->to_line_bulk(); - int rv; - - rv = ::gpiod_line_set_direction_input_bulk(bulk.get()); - if (rv) - throw ::std::system_error(errno, ::std::system_category(), - "error setting GPIO line direction to input"); -} - -GPIOD_CXX_API void line_bulk::set_direction_output(const ::std::vector<int>& values) const -{ - this->throw_if_empty(); - line::chip_guard lock_chip(this->_m_bulk.front()); - - if (values.size() != this->_m_bulk.size()) - throw ::std::invalid_argument("the size of values array must correspond with the number of lines"); - - auto bulk = this->to_line_bulk(); - int rv; - - rv = ::gpiod_line_set_direction_output_bulk(bulk.get(), values.data()); - if (rv) - throw ::std::system_error(errno, ::std::system_category(), - "error setting GPIO line direction to output"); -} - -GPIOD_CXX_API line_bulk line_bulk::event_wait(const ::std::chrono::nanoseconds& timeout) const -{ - this->throw_if_empty(); - line::chip_guard lock_chip(this->_m_bulk.front()); - - auto ev_bulk = this->make_line_bulk_ptr(); - auto bulk = this->to_line_bulk(); - ::timespec ts; - line_bulk ret; - int rv; - - ts.tv_sec = timeout.count() / 1000000000ULL; - ts.tv_nsec = timeout.count() % 1000000000ULL; - - rv = ::gpiod_line_event_wait_bulk(bulk.get(), ::std::addressof(ts), ev_bulk.get()); - if (rv < 0) { - throw ::std::system_error(errno, ::std::system_category(), - "error polling for events"); - } else if (rv > 0) { - auto chip = this->_m_bulk[0].get_chip(); - auto num_lines = ::gpiod_line_bulk_num_lines(ev_bulk.get()); - - for (unsigned int i = 0; i < num_lines; i++) - ret.append(line(::gpiod_line_bulk_get_line(ev_bulk.get(), i), chip)); - } - - return ret; -} - -GPIOD_CXX_API line_bulk::operator bool(void) const noexcept -{ - return !this->_m_bulk.empty(); -} - -GPIOD_CXX_API bool line_bulk::operator!(void) const noexcept -{ - return this->_m_bulk.empty(); -} - -GPIOD_CXX_API line_bulk::iterator::iterator(const ::std::vector<line>::iterator& it) - : _m_iter(it) -{ - -} - -GPIOD_CXX_API line_bulk::iterator& line_bulk::iterator::operator++(void) -{ - this->_m_iter++; - - return *this; -} - -GPIOD_CXX_API const line& line_bulk::iterator::operator*(void) const -{ - return *this->_m_iter; -} - -GPIOD_CXX_API const line* line_bulk::iterator::operator->(void) const -{ - return this->_m_iter.operator->(); -} - -GPIOD_CXX_API bool line_bulk::iterator::operator==(const iterator& rhs) const noexcept -{ - return this->_m_iter == rhs._m_iter; -} - -GPIOD_CXX_API bool line_bulk::iterator::operator!=(const iterator& rhs) const noexcept -{ - return this->_m_iter != rhs._m_iter; -} - -GPIOD_CXX_API line_bulk::iterator line_bulk::begin(void) noexcept -{ - return line_bulk::iterator(this->_m_bulk.begin()); -} - -GPIOD_CXX_API line_bulk::iterator line_bulk::end(void) noexcept -{ - return line_bulk::iterator(this->_m_bulk.end()); -} - -GPIOD_CXX_API void line_bulk::throw_if_empty(void) const -{ - if (this->_m_bulk.empty()) - throw ::std::logic_error("line_bulk not holding any GPIO lines"); -} - -GPIOD_CXX_API line_bulk::line_bulk_ptr line_bulk::make_line_bulk_ptr(void) const -{ - line_bulk_ptr bulk(::gpiod_line_bulk_new(this->size())); - - if (!bulk) - throw ::std::system_error(errno, ::std::system_category(), - "unable to allocate new bulk object"); - - return bulk; -} - -GPIOD_CXX_API line_bulk::line_bulk_ptr line_bulk::to_line_bulk(void) const -{ - line_bulk_ptr bulk = this->make_line_bulk_ptr(); - - for (auto& it: this->_m_bulk) - ::gpiod_line_bulk_add_line(bulk.get(), it._m_line); - - return bulk; -} - -GPIOD_CXX_API void line_bulk::line_bulk_deleter::operator()(::gpiod_line_bulk *bulk) -{ - ::gpiod_line_bulk_free(bulk); -} - -} /* namespace gpiod */ diff --git a/bindings/cxx/tests/.gitignore b/bindings/cxx/tests/.gitignore deleted file mode 100644 index 7990193..0000000 --- a/bindings/cxx/tests/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -gpiod-cxx-test diff --git a/bindings/cxx/tests/Makefile.am b/bindings/cxx/tests/Makefile.am deleted file mode 100644 index cbdecdc..0000000 --- a/bindings/cxx/tests/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -AM_CPPFLAGS = -I$(top_srcdir)/bindings/cxx/ -I$(top_srcdir)/include -AM_CPPFLAGS += -I$(top_srcdir)/tests/mockup/ -AM_CPPFLAGS += -Wall -Wextra -g -std=gnu++11 $(CATCH2_CFLAGS) -AM_LDFLAGS = -lgpiodcxx -L$(top_builddir)/bindings/cxx/ -AM_LDFLAGS += -lgpiomockup -L$(top_builddir)/tests/mockup/ -AM_LDFLAGS += -pthread - -bin_PROGRAMS = gpiod-cxx-test - -gpiod_cxx_test_SOURCES = \ - gpiod-cxx-test-main.cpp \ - gpiod-cxx-test.cpp \ - gpio-mockup.cpp \ - gpio-mockup.hpp \ - tests-chip.cpp \ - tests-event.cpp \ - tests-iter.cpp \ - tests-line.cpp diff --git a/bindings/cxx/tests/gpio-mockup.cpp b/bindings/cxx/tests/gpio-mockup.cpp deleted file mode 100644 index 2e99dd4..0000000 --- a/bindings/cxx/tests/gpio-mockup.cpp +++ /dev/null @@ -1,153 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -#include <system_error> - -#include "gpio-mockup.hpp" - -namespace gpiod { -namespace test { - -const ::std::bitset<32> mockup::FLAG_NAMED_LINES("1"); - -mockup& mockup::instance(void) -{ - static mockup mockup; - - return mockup; -} - -mockup::mockup(void) : _m_mockup(::gpio_mockup_new()) -{ - if (!this->_m_mockup) - throw ::std::system_error(errno, ::std::system_category(), - "unable to create the gpio-mockup context"); -} - -mockup::~mockup(void) -{ - ::gpio_mockup_unref(this->_m_mockup); -} - -void mockup::probe(const ::std::vector<unsigned int>& chip_sizes, - const ::std::bitset<32>& flags) -{ - int ret, probe_flags = 0; - - if (flags.to_ulong() & FLAG_NAMED_LINES.to_ulong()) - probe_flags |= GPIO_MOCKUP_FLAG_NAMED_LINES; - - ret = ::gpio_mockup_probe(this->_m_mockup, chip_sizes.size(), - chip_sizes.data(), probe_flags); - if (ret) - throw ::std::system_error(errno, ::std::system_category(), - "unable to probe gpio-mockup module"); -} - -void mockup::remove(void) -{ - int ret = ::gpio_mockup_remove(this->_m_mockup); - if (ret) - throw ::std::system_error(errno, ::std::system_category(), - "unable to remove gpio-mockup module"); -} - -::std::string mockup::chip_name(unsigned int idx) const -{ - const char *name = ::gpio_mockup_chip_name(this->_m_mockup, idx); - if (!name) - throw ::std::system_error(errno, ::std::system_category(), - "unable to retrieve the chip name"); - - return ::std::string(name); -} - -::std::string mockup::chip_path(unsigned int idx) const -{ - const char *path = ::gpio_mockup_chip_path(this->_m_mockup, idx); - if (!path) - throw ::std::system_error(errno, ::std::system_category(), - "unable to retrieve the chip path"); - - return ::std::string(path); -} - -unsigned int mockup::chip_num(unsigned int idx) const -{ - int num = ::gpio_mockup_chip_num(this->_m_mockup, idx); - if (num < 0) - throw ::std::system_error(errno, ::std::system_category(), - "unable to retrieve the chip number"); - - return num; -} - -int mockup::chip_get_value(unsigned int chip_idx, unsigned int line_offset) -{ - int val = ::gpio_mockup_get_value(this->_m_mockup, chip_idx, line_offset); - if (val < 0) - throw ::std::system_error(errno, ::std::system_category(), - "error reading the line value"); - - return val; -} - -void mockup::chip_set_pull(unsigned int chip_idx, unsigned int line_offset, int pull) -{ - int ret = ::gpio_mockup_set_pull(this->_m_mockup, chip_idx, line_offset, pull); - if (ret) - throw ::std::system_error(errno, ::std::system_category(), - "error setting line pull"); -} - -mockup::probe_guard::probe_guard(const ::std::vector<unsigned int>& chip_sizes, - const ::std::bitset<32>& flags) -{ - mockup::instance().probe(chip_sizes, flags); -} - -mockup::probe_guard::~probe_guard(void) -{ - mockup::instance().remove(); -} - -mockup::event_thread::event_thread(unsigned int chip_index, - unsigned int line_offset, unsigned int period_ms) - : _m_chip_index(chip_index), - _m_line_offset(line_offset), - _m_period_ms(period_ms), - _m_stop(false), - _m_mutex(), - _m_cond(), - _m_thread(&event_thread::event_worker, this) -{ - -} - -mockup::event_thread::~event_thread(void) -{ - ::std::unique_lock<::std::mutex> lock(this->_m_mutex); - this->_m_stop = true; - this->_m_cond.notify_all(); - lock.unlock(); - this->_m_thread.join(); -} - -void mockup::event_thread::event_worker(void) -{ - for (unsigned int i = 0;; i++) { - ::std::unique_lock<::std::mutex> lock(this->_m_mutex); - - if (this->_m_stop) - break; - - ::std::cv_status status = this->_m_cond.wait_for(lock, - std::chrono::milliseconds(this->_m_period_ms)); - if (status == ::std::cv_status::timeout) - mockup::instance().chip_set_pull(this->_m_chip_index, - this->_m_line_offset, i % 2); - } -} - -} /* namespace test */ -} /* namespace gpiod */ diff --git a/bindings/cxx/tests/gpio-mockup.hpp b/bindings/cxx/tests/gpio-mockup.hpp deleted file mode 100644 index 9ca27bd..0000000 --- a/bindings/cxx/tests/gpio-mockup.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/* SPDX-License-Identifier: LGPL-3.0-or-later */ -/* SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> */ - -#ifndef __GPIOD_CXX_TEST_HPP__ -#define __GPIOD_CXX_TEST_HPP__ - -#include <bitset> -#include <condition_variable> -#include <gpio-mockup.h> -#include <mutex> -#include <string> -#include <vector> -#include <thread> - -namespace gpiod { -namespace test { - -class mockup -{ -public: - - static mockup& instance(void); - - mockup(const mockup& other) = delete; - mockup(mockup&& other) = delete; - mockup& operator=(const mockup& other) = delete; - mockup& operator=(mockup&& other) = delete; - - void probe(const ::std::vector<unsigned int>& chip_sizes, - const ::std::bitset<32>& flags = 0); - void remove(void); - - std::string chip_name(unsigned int idx) const; - std::string chip_path(unsigned int idx) const; - unsigned int chip_num(unsigned int idx) const; - - int chip_get_value(unsigned int chip_idx, unsigned int line_offset); - void chip_set_pull(unsigned int chip_idx, unsigned int line_offset, int pull); - - static const ::std::bitset<32> FLAG_NAMED_LINES; - - class probe_guard - { - public: - - probe_guard(const ::std::vector<unsigned int>& chip_sizes, - const ::std::bitset<32>& flags = 0); - ~probe_guard(void); - - probe_guard(const probe_guard& other) = delete; - probe_guard(probe_guard&& other) = delete; - probe_guard& operator=(const probe_guard& other) = delete; - probe_guard& operator=(probe_guard&& other) = delete; - }; - - class event_thread - { - public: - - event_thread(unsigned int chip_index, unsigned int line_offset, unsigned int period_ms); - ~event_thread(void); - - event_thread(const event_thread& other) = delete; - event_thread(event_thread&& other) = delete; - event_thread& operator=(const event_thread& other) = delete; - event_thread& operator=(event_thread&& other) = delete; - - private: - - void event_worker(void); - - unsigned int _m_chip_index; - unsigned int _m_line_offset; - unsigned int _m_period_ms; - - bool _m_stop; - - ::std::mutex _m_mutex; - ::std::condition_variable _m_cond; - ::std::thread _m_thread; - }; - -private: - - mockup(void); - ~mockup(void); - - ::gpio_mockup *_m_mockup; -}; - -} /* namespace test */ -} /* namespace gpiod */ - -#endif /* __GPIOD_CXX_TEST_HPP__ */ diff --git a/bindings/cxx/tests/gpiod-cxx-test-main.cpp b/bindings/cxx/tests/gpiod-cxx-test-main.cpp deleted file mode 100644 index 11bf8e5..0000000 --- a/bindings/cxx/tests/gpiod-cxx-test-main.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -#define CATCH_CONFIG_MAIN -#include <catch2/catch.hpp> diff --git a/bindings/cxx/tests/gpiod-cxx-test.cpp b/bindings/cxx/tests/gpiod-cxx-test.cpp deleted file mode 100644 index 834f372..0000000 --- a/bindings/cxx/tests/gpiod-cxx-test.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -#include <linux/version.h> -#include <sys/utsname.h> -#include <system_error> -#include <sstream> - -namespace { - -class kernel_checker -{ -public: - - kernel_checker(unsigned int major, unsigned int minor, unsigned int release) - { - unsigned long curr_major, curr_minor, curr_release, curr_ver, req_ver; - ::std::string major_str, minor_str, release_str; - ::utsname un; - int ret; - - ret = ::uname(::std::addressof(un)); - if (ret) - throw ::std::system_error(errno, ::std::system_category(), - "unable to read the kernel version"); - - ::std::stringstream ver_stream(::std::string(un.release)); - ::std::getline(ver_stream, major_str, '.'); - ::std::getline(ver_stream, minor_str, '.'); - ::std::getline(ver_stream, release_str, '.'); - - curr_major = ::std::stoul(major_str, nullptr, 0); - curr_minor = ::std::stoul(minor_str, nullptr, 0); - curr_release = ::std::stoul(release_str, nullptr, 0); - - curr_ver = KERNEL_VERSION(curr_major, curr_minor, curr_release); - req_ver = KERNEL_VERSION(major, minor, release); - - if (curr_ver < req_ver) - throw ::std::system_error(EOPNOTSUPP, ::std::system_category(), - "kernel release must be at least: " + - ::std::to_string(major) + "." + - ::std::to_string(minor) + "." + - ::std::to_string(release)); - } - - kernel_checker(const kernel_checker& other) = delete; - kernel_checker(kernel_checker&& other) = delete; - kernel_checker& operator=(const kernel_checker& other) = delete; - kernel_checker& operator=(kernel_checker&& other) = delete; -}; - -kernel_checker require_kernel(5, 10, 0); - -} /* namespace */ diff --git a/bindings/cxx/tests/tests-chip.cpp b/bindings/cxx/tests/tests-chip.cpp deleted file mode 100644 index aea00fa..0000000 --- a/bindings/cxx/tests/tests-chip.cpp +++ /dev/null @@ -1,173 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -#include <catch2/catch.hpp> -#include <gpiod.hpp> - -#include "gpio-mockup.hpp" - -using ::gpiod::test::mockup; - -TEST_CASE("GPIO chip device can be verified with is_gpiochip_device()", "[chip]") -{ - mockup::probe_guard mockup_chips({ 8 }); - - SECTION("good chip") - { - REQUIRE(::gpiod::is_gpiochip_device(mockup::instance().chip_path(0))); - } - - SECTION("not a chip") - { - REQUIRE_FALSE(::gpiod::is_gpiochip_device("/dev/null")); - } - - SECTION("nonexistent file") - { - REQUIRE_FALSE(::gpiod::is_gpiochip_device("/dev/nonexistent_device")); - } -} - -TEST_CASE("GPIO chip device can be opened", "[chip]") -{ - mockup::probe_guard mockup_chips({ 8, 8, 8 }); - - SECTION("open from constructor") - { - REQUIRE_NOTHROW(::gpiod::chip(mockup::instance().chip_path(1))); - } - - SECTION("open from open() method") - { - ::gpiod::chip chip; - - REQUIRE_FALSE(!!chip); - - REQUIRE_NOTHROW(chip.open(mockup::instance().chip_path(1))); - } -} - -TEST_CASE("Uninitialized GPIO chip behaves correctly", "[chip]") -{ - ::gpiod::chip chip; - - SECTION("uninitialized chip is 'false'") - { - REQUIRE_FALSE(!!chip); - } - - SECTION("using uninitialized chip throws logic_error") - { - REQUIRE_THROWS_AS(chip.name(), ::std::logic_error); - } -} - -TEST_CASE("Trying to open a nonexistent chip throws system_error", "[chip]") -{ - REQUIRE_THROWS_AS(::gpiod::chip("nonexistent-chip"), ::std::system_error); -} - -TEST_CASE("Chip object can be reset", "[chip]") -{ - mockup::probe_guard mockup_chips({ 8 }); - - ::gpiod::chip chip(mockup::instance().chip_path(0)); - REQUIRE(chip); - chip.reset(); - REQUIRE_FALSE(!!chip); -} - -TEST_CASE("Chip info can be correctly retrieved", "[chip]") -{ - mockup::probe_guard mockup_chips({ 8, 16, 8 }); - - ::gpiod::chip chip(mockup::instance().chip_path(1)); - REQUIRE(chip.name() == mockup::instance().chip_name(1)); - REQUIRE(chip.label() == "gpio-mockup-B"); - REQUIRE(chip.num_lines() == 16); -} - -TEST_CASE("Chip object can be copied and compared", "[chip]") -{ - mockup::probe_guard mockup_chips({ 8, 8 }); - - ::gpiod::chip chip1(mockup::instance().chip_path(0)); - auto chip2 = chip1; - REQUIRE(chip1 == chip2); - REQUIRE_FALSE(chip1 != chip2); - ::gpiod::chip chip3(mockup::instance().chip_path(1)); - REQUIRE(chip1 != chip3); - REQUIRE_FALSE(chip2 == chip3); -} - -TEST_CASE("Lines can be retrieved from chip objects", "[chip]") -{ - mockup::probe_guard mockup_chips({ 8, 8, 8 }, mockup::FLAG_NAMED_LINES); - ::gpiod::chip chip(mockup::instance().chip_path(1)); - - SECTION("get single line by offset") - { - auto line = chip.get_line(3); - REQUIRE(line.name() == "gpio-mockup-B-3"); - } - - SECTION("find single line by name") - { - auto offset = chip.find_line("gpio-mockup-B-3"); - REQUIRE(offset == 3); - } - - SECTION("get multiple lines by offsets") - { - auto lines = chip.get_lines({ 1, 3, 4, 7}); - REQUIRE(lines.size() == 4); - REQUIRE(lines.get(0).name() == "gpio-mockup-B-1"); - REQUIRE(lines.get(1).name() == "gpio-mockup-B-3"); - REQUIRE(lines.get(2).name() == "gpio-mockup-B-4"); - REQUIRE(lines.get(3).name() == "gpio-mockup-B-7"); - } - - SECTION("get multiple lines by offsets in mixed order") - { - auto lines = chip.get_lines({ 5, 1, 3, 2}); - REQUIRE(lines.size() == 4); - REQUIRE(lines.get(0).name() == "gpio-mockup-B-5"); - REQUIRE(lines.get(1).name() == "gpio-mockup-B-1"); - REQUIRE(lines.get(2).name() == "gpio-mockup-B-3"); - REQUIRE(lines.get(3).name() == "gpio-mockup-B-2"); - } -} - -TEST_CASE("All lines can be retrieved from a chip at once", "[chip]") -{ - mockup::probe_guard mockup_chips({ 4 }); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - - auto lines = chip.get_all_lines(); - REQUIRE(lines.size() == 4); - REQUIRE(lines.get(0).offset() == 0); - REQUIRE(lines.get(1).offset() == 1); - REQUIRE(lines.get(2).offset() == 2); - REQUIRE(lines.get(3).offset() == 3); -} - -TEST_CASE("Errors occurring when retrieving lines are correctly reported", "[chip]") -{ - mockup::probe_guard mockup_chips({ 8 }, mockup::FLAG_NAMED_LINES); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - - SECTION("invalid offset (single line)") - { - REQUIRE_THROWS_AS(chip.get_line(9), ::std::out_of_range); - } - - SECTION("invalid offset (multiple lines)") - { - REQUIRE_THROWS_AS(chip.get_lines({ 1, 19, 4, 7 }), ::std::out_of_range); - } - - SECTION("line not found by name") - { - REQUIRE(chip.find_line("nonexistent-line") == -1); - } -} diff --git a/bindings/cxx/tests/tests-event.cpp b/bindings/cxx/tests/tests-event.cpp deleted file mode 100644 index aeb50dd..0000000 --- a/bindings/cxx/tests/tests-event.cpp +++ /dev/null @@ -1,280 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -#include <catch2/catch.hpp> -#include <gpiod.hpp> -#include <poll.h> -#include <thread> - -#include "gpio-mockup.hpp" - -using ::gpiod::test::mockup; - -namespace { - -const ::std::string consumer = "event-test"; - -} /* namespace */ - -TEST_CASE("Line events can be detected", "[event][line]") -{ - mockup::probe_guard mockup_chips({ 8 }); - mockup::event_thread events(0, 4, 200); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - auto line = chip.get_line(4); - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - - SECTION("rising edge") - { - config.request_type = ::gpiod::line_request::EVENT_RISING_EDGE; - line.request(config); - - auto got_event = line.event_wait(::std::chrono::seconds(1)); - REQUIRE(got_event); - - auto event = line.event_read(); - REQUIRE(event.source == line); - REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE); - } - - SECTION("falling edge") - { - config.request_type = ::gpiod::line_request::EVENT_FALLING_EDGE; - - line.request(config); - - auto got_event = line.event_wait(::std::chrono::seconds(1)); - REQUIRE(got_event); - - auto event = line.event_read(); - REQUIRE(event.source == line); - REQUIRE(event.event_type == ::gpiod::line_event::FALLING_EDGE); - } - - SECTION("both edges") - { - config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES; - - line.request(config); - - auto got_event = line.event_wait(::std::chrono::seconds(1)); - REQUIRE(got_event); - - auto event = line.event_read(); - REQUIRE(event.source == line); - REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE); - - got_event = line.event_wait(::std::chrono::seconds(1)); - REQUIRE(got_event); - - event = line.event_read(); - REQUIRE(event.source == line); - REQUIRE(event.event_type == ::gpiod::line_event::FALLING_EDGE); - } - - SECTION("active-low") - { - config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES; - config.flags = ::gpiod::line_request::FLAG_ACTIVE_LOW; - - line.request(config); - - auto got_event = line.event_wait(::std::chrono::seconds(1)); - REQUIRE(got_event); - - auto event = line.event_read(); - REQUIRE(event.source == line); - REQUIRE(event.event_type == ::gpiod::line_event::FALLING_EDGE); - - got_event = line.event_wait(::std::chrono::seconds(1)); - REQUIRE(got_event); - - event = line.event_read(); - REQUIRE(event.source == line); - REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE); - } -} - -TEST_CASE("Watching line_bulk objects for events works", "[event][bulk]") -{ - mockup::probe_guard mockup_chips({ 8 }); - mockup::event_thread events(0, 2, 200); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - auto lines = chip.get_lines({ 0, 1, 2, 3 }); - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES; - lines.request(config); - - auto event_lines = lines.event_wait(::std::chrono::seconds(1)); - REQUIRE(event_lines); - REQUIRE(event_lines.size() == 1); - - auto event = event_lines.get(0).event_read(); - REQUIRE(event.source == event_lines.get(0)); - REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE); - - event_lines = lines.event_wait(::std::chrono::seconds(1)); - REQUIRE(event_lines); - REQUIRE(event_lines.size() == 1); - - event = event_lines.get(0).event_read(); - REQUIRE(event.source == event_lines.get(0)); - REQUIRE(event.event_type == ::gpiod::line_event::FALLING_EDGE); -} - -TEST_CASE("It's possible to retrieve the event file descriptor", "[event][line]") -{ - mockup::probe_guard mockup_chips({ 8 }); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - auto line = chip.get_line(4); - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - - SECTION("get the fd") - { - config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES; - - line.request(config); - REQUIRE(line.event_get_fd() >= 0); - } - - SECTION("error if not requested") - { - REQUIRE_THROWS_AS(line.event_get_fd(), ::std::system_error); - } - - SECTION("error if requested for values") - { - config.request_type = ::gpiod::line_request::DIRECTION_INPUT; - - line.request(config); - REQUIRE_THROWS_AS(line.event_get_fd(), ::std::system_error); - } -} - -TEST_CASE("Event file descriptors can be used for polling", "[event]") -{ - mockup::probe_guard mockup_chips({ 8 }); - mockup::event_thread events(0, 3, 200); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - auto lines = chip.get_lines({ 0, 1, 2, 3, 4, 5 }); - - ::gpiod::line_request config; - config.consumer = consumer.c_str(); - config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES; - - lines.request(config); - - ::std::vector<::pollfd> fds(3); - fds[0].fd = lines[1].event_get_fd(); - fds[1].fd = lines[3].event_get_fd(); - fds[2].fd = lines[5].event_get_fd(); - - fds[0].events = fds[1].events = fds[2].events = POLLIN | POLLPRI; - - int ret = ::poll(fds.data(), 3, 1000); - REQUIRE(ret == 1); - - for (int i = 0; i < 3; i++) { - if (fds[i].revents) { - auto event = lines[3].event_read(); - REQUIRE(event.source == lines[3]); - REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE); - } - } -} - -TEST_CASE("It's possible to read a value from a line requested for events", "[event][line]") -{ - mockup::probe_guard mockup_chips({ 8 }); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - auto line = chip.get_line(4); - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES; - - mockup::instance().chip_set_pull(0, 4, 1); - - SECTION("active-high (default)") - { - line.request(config); - REQUIRE(line.get_value() == 1); - } - - SECTION("active-low") - { - config.flags = ::gpiod::line_request::FLAG_ACTIVE_LOW; - line.request(config); - REQUIRE(line.get_value() == 0); - } -} - -TEST_CASE("It's possible to read values from lines requested for events", "[event][bulk]") -{ - mockup::probe_guard mockup_chips({ 8 }); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - auto lines = chip.get_lines({ 0, 1, 2, 3, 4 }); - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES; - - mockup::instance().chip_set_pull(0, 5, 1); - - SECTION("active-high (default)") - { - lines.request(config); - REQUIRE(lines.get_values() == ::std::vector<int>({ 0, 0, 0, 0, 0 })); - mockup::instance().chip_set_pull(0, 1, 1); - mockup::instance().chip_set_pull(0, 3, 1); - mockup::instance().chip_set_pull(0, 4, 1); - REQUIRE(lines.get_values() == ::std::vector<int>({ 0, 1, 0, 1, 1 })); - } - - SECTION("active-low") - { - config.flags = ::gpiod::line_request::FLAG_ACTIVE_LOW; - lines.request(config); - REQUIRE(lines.get_values() == ::std::vector<int>({ 1, 1, 1, 1, 1 })); - mockup::instance().chip_set_pull(0, 1, 1); - mockup::instance().chip_set_pull(0, 3, 1); - mockup::instance().chip_set_pull(0, 4, 1); - REQUIRE(lines.get_values() == ::std::vector<int>({ 1, 0, 1, 0, 0 })); - } -} - -TEST_CASE("It's possible to read more than one line event", "[event][line]") -{ - mockup::probe_guard mockup_chips({ 8 }); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - auto line = chip.get_line(4); - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES; - - line.request(config); - - mockup::instance().chip_set_pull(0, 4, 1); - ::std::this_thread::sleep_for(::std::chrono::milliseconds(10)); - mockup::instance().chip_set_pull(0, 4, 0); - ::std::this_thread::sleep_for(::std::chrono::milliseconds(10)); - mockup::instance().chip_set_pull(0, 4, 1); - ::std::this_thread::sleep_for(::std::chrono::milliseconds(10)); - - auto events = line.event_read_multiple(); - - REQUIRE(events.size() == 3); - REQUIRE(events.at(0).event_type == ::gpiod::line_event::RISING_EDGE); - REQUIRE(events.at(1).event_type == ::gpiod::line_event::FALLING_EDGE); - REQUIRE(events.at(2).event_type == ::gpiod::line_event::RISING_EDGE); - REQUIRE(events.at(0).source == line); - REQUIRE(events.at(1).source == line); - REQUIRE(events.at(2).source == line); -} diff --git a/bindings/cxx/tests/tests-iter.cpp b/bindings/cxx/tests/tests-iter.cpp deleted file mode 100644 index 848889b..0000000 --- a/bindings/cxx/tests/tests-iter.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -#include <catch2/catch.hpp> -#include <gpiod.hpp> - -#include "gpio-mockup.hpp" - -using ::gpiod::test::mockup; - -TEST_CASE("Line iterator works", "[iter][line]") -{ - mockup::probe_guard mockup_chips({ 4 }); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - unsigned int count = 0; - - for (auto& it: ::gpiod::line_iter(chip)) - REQUIRE(it.offset() == count++); - - REQUIRE(count == chip.num_lines()); -} diff --git a/bindings/cxx/tests/tests-line.cpp b/bindings/cxx/tests/tests-line.cpp deleted file mode 100644 index ababf8b..0000000 --- a/bindings/cxx/tests/tests-line.cpp +++ /dev/null @@ -1,467 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@xxxxxxxxx> - -#include <catch2/catch.hpp> -#include <gpiod.hpp> - -#include "gpio-mockup.hpp" - -using ::gpiod::test::mockup; - -namespace { - -const ::std::string consumer = "line-test"; - -} /* namespace */ - -TEST_CASE("Line information can be correctly retrieved", "[line]") -{ - mockup::probe_guard mockup_chips({ 8 }, mockup::FLAG_NAMED_LINES); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - auto line = chip.get_line(4); - - SECTION("unexported line") - { - REQUIRE(line.offset() == 4); - REQUIRE(line.name() == "gpio-mockup-A-4"); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_INPUT); - REQUIRE_FALSE(line.is_active_low()); - REQUIRE(line.consumer().empty()); - REQUIRE_FALSE(line.is_used()); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_PUSH_PULL); - REQUIRE(line.bias() == ::gpiod::line::BIAS_UNKNOWN); - } - - SECTION("exported line") - { - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - line.request(config); - - REQUIRE(line.offset() == 4); - REQUIRE(line.name() == "gpio-mockup-A-4"); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE_FALSE(line.is_active_low()); - REQUIRE(line.is_used()); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_PUSH_PULL); - REQUIRE(line.bias() == ::gpiod::line::BIAS_UNKNOWN); - } - - SECTION("exported line with flags") - { - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - config.flags = ::gpiod::line_request::FLAG_ACTIVE_LOW | - ::gpiod::line_request::FLAG_OPEN_DRAIN; - line.request(config); - - REQUIRE(line.offset() == 4); - REQUIRE(line.name() == "gpio-mockup-A-4"); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE(line.is_active_low()); - REQUIRE(line.is_used()); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_OPEN_DRAIN); - REQUIRE(line.bias() == ::gpiod::line::BIAS_UNKNOWN); - } - - SECTION("exported open source line") - { - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - config.flags = ::gpiod::line_request::FLAG_OPEN_SOURCE; - line.request(config); - - REQUIRE(line.offset() == 4); - REQUIRE(line.name() == "gpio-mockup-A-4"); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE_FALSE(line.is_active_low()); - REQUIRE(line.is_used()); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_OPEN_SOURCE); - REQUIRE(line.bias() == ::gpiod::line::BIAS_UNKNOWN); - } - - SECTION("exported bias disable line") - { - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - config.flags = ::gpiod::line_request::FLAG_BIAS_DISABLED; - line.request(config); - - REQUIRE(line.offset() == 4); - REQUIRE(line.name() == "gpio-mockup-A-4"); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE_FALSE(line.is_active_low()); - REQUIRE(line.is_used()); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_PUSH_PULL); - REQUIRE(line.bias() == ::gpiod::line::BIAS_DISABLED); - } - - SECTION("exported pull-down line") - { - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - config.flags = ::gpiod::line_request::FLAG_BIAS_PULL_DOWN; - line.request(config); - - REQUIRE(line.offset() == 4); - REQUIRE(line.name() == "gpio-mockup-A-4"); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE_FALSE(line.is_active_low());; - REQUIRE(line.is_used()); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_PUSH_PULL); - REQUIRE(line.bias() == ::gpiod::line::BIAS_PULL_DOWN); - } - - SECTION("exported pull-up line") - { - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - config.flags = ::gpiod::line_request::FLAG_BIAS_PULL_UP; - line.request(config); - - REQUIRE(line.offset() == 4); - REQUIRE(line.name() == "gpio-mockup-A-4"); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE_FALSE(line.is_active_low()); - REQUIRE(line.is_used()); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_PUSH_PULL); - REQUIRE(line.bias() == ::gpiod::line::BIAS_PULL_UP); - } -} - -TEST_CASE("Line values can be set and read", "[line]") -{ - mockup::probe_guard mockup_chips({ 8 }); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - - SECTION("get value (single line)") - { - auto line = chip.get_line(3); - config.request_type = ::gpiod::line_request::DIRECTION_INPUT; - line.request(config); - REQUIRE(line.get_value() == 0); - mockup::instance().chip_set_pull(0, 3, 1); - REQUIRE(line.get_value() == 1); - } - - SECTION("set value (single line)") - { - auto line = chip.get_line(3); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - line.request(config); - line.set_value(1); - REQUIRE(mockup::instance().chip_get_value(0, 3) == 1); - line.set_value(0); - REQUIRE(mockup::instance().chip_get_value(0, 3) == 0); - } - - SECTION("set value with default value parameter") - { - auto line = chip.get_line(3); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - line.request(config, 1); - REQUIRE(mockup::instance().chip_get_value(0, 3) == 1); - } - - SECTION("get multiple values at once") - { - auto lines = chip.get_lines({ 0, 1, 2, 3, 4 }); - config.request_type = ::gpiod::line_request::DIRECTION_INPUT; - lines.request(config); - REQUIRE(lines.get_values() == ::std::vector<int>({ 0, 0, 0, 0, 0 })); - mockup::instance().chip_set_pull(0, 1, 1); - mockup::instance().chip_set_pull(0, 3, 1); - mockup::instance().chip_set_pull(0, 4, 1); - REQUIRE(lines.get_values() == ::std::vector<int>({ 0, 1, 0, 1, 1 })); - } - - SECTION("set multiple values at once") - { - auto lines = chip.get_lines({ 0, 1, 2, 6, 7 }); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - lines.request(config); - lines.set_values({ 1, 1, 0, 1, 0 }); - REQUIRE(mockup::instance().chip_get_value(0, 0) == 1); - REQUIRE(mockup::instance().chip_get_value(0, 1) == 1); - REQUIRE(mockup::instance().chip_get_value(0, 2) == 0); - REQUIRE(mockup::instance().chip_get_value(0, 6) == 1); - REQUIRE(mockup::instance().chip_get_value(0, 7) == 0); - } - - SECTION("set multiple values with default values parameter") - { - auto lines = chip.get_lines({ 1, 2, 4, 6, 7 }); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - lines.request(config, { 1, 1, 0, 1, 0 }); - REQUIRE(mockup::instance().chip_get_value(0, 1) == 1); - REQUIRE(mockup::instance().chip_get_value(0, 2) == 1); - REQUIRE(mockup::instance().chip_get_value(0, 4) == 0); - REQUIRE(mockup::instance().chip_get_value(0, 6) == 1); - REQUIRE(mockup::instance().chip_get_value(0, 7) == 0); - } - - SECTION("get value (single line, active-low") - { - auto line = chip.get_line(4); - config.request_type = ::gpiod::line_request::DIRECTION_INPUT; - config.flags = ::gpiod::line_request::FLAG_ACTIVE_LOW; - line.request(config); - REQUIRE(line.get_value() == 1); - mockup::instance().chip_set_pull(0, 4, 1); - REQUIRE(line.get_value() == 0); - } - - SECTION("set value (single line, active-low)") - { - auto line = chip.get_line(3); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - config.flags = ::gpiod::line_request::FLAG_ACTIVE_LOW; - line.request(config); - line.set_value(1); - REQUIRE(mockup::instance().chip_get_value(0, 3) == 0); - line.set_value(0); - REQUIRE(mockup::instance().chip_get_value(0, 3) == 1); - } -} - -TEST_CASE("Line can be reconfigured", "[line]") -{ - mockup::probe_guard mockup_chips({ 8 }); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - - SECTION("set config (single line, active-state)") - { - auto line = chip.get_line(3); - config.request_type = ::gpiod::line_request::DIRECTION_INPUT; - config.flags = 0; - line.request(config); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_INPUT); - REQUIRE_FALSE(line.is_active_low()); - - line.set_config(::gpiod::line_request::DIRECTION_OUTPUT, - ::gpiod::line_request::FLAG_ACTIVE_LOW,1); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE(line.is_active_low()); - REQUIRE(mockup::instance().chip_get_value(0, 3) == 0); - line.set_value(0); - REQUIRE(mockup::instance().chip_get_value(0, 3) == 1); - - line.set_config(::gpiod::line_request::DIRECTION_OUTPUT, 0); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE_FALSE(line.is_active_low()); - REQUIRE(mockup::instance().chip_get_value(0, 3) == 0); - line.set_value(1); - REQUIRE(mockup::instance().chip_get_value(0, 3) == 1); - } - - SECTION("set flags (single line, active-state)") - { - auto line = chip.get_line(3); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - config.flags = 0; - line.request(config,1); - REQUIRE(mockup::instance().chip_get_value(0, 3) == 1); - - line.set_flags(::gpiod::line_request::FLAG_ACTIVE_LOW); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE(line.is_active_low()); - REQUIRE(mockup::instance().chip_get_value(0, 3) == 0); - - line.set_flags(0); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE_FALSE(line.is_active_low()); - REQUIRE(mockup::instance().chip_get_value(0, 3) == 1); - } - - SECTION("set flags (single line, drive)") - { - auto line = chip.get_line(3); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - config.flags = 0; - line.request(config); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_PUSH_PULL); - - line.set_flags(::gpiod::line_request::FLAG_OPEN_DRAIN); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_OPEN_DRAIN); - - line.set_flags(::gpiod::line_request::FLAG_OPEN_SOURCE); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_OPEN_SOURCE); - - line.set_flags(0); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_PUSH_PULL); - } - - SECTION("set flags (single line, bias)") - { - auto line = chip.get_line(3); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - config.flags = 0; - line.request(config); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_PUSH_PULL); - - line.set_flags(::gpiod::line_request::FLAG_OPEN_DRAIN); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_OPEN_DRAIN); - - line.set_flags(::gpiod::line_request::FLAG_OPEN_SOURCE); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_OPEN_SOURCE); - - line.set_flags(0); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE(line.drive() == ::gpiod::line::DRIVE_PUSH_PULL); - } - - SECTION("set direction input (single line)") - { - auto line = chip.get_line(3); - config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT; - config.flags = 0; - line.request(config); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - line.set_direction_input(); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_INPUT); - } - - SECTION("set direction output (single line)") - { - auto line = chip.get_line(3); - config.request_type = ::gpiod::line_request::DIRECTION_INPUT; - config.flags = 0; - line.request(config); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_INPUT); - line.set_direction_output(1); - REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT); - REQUIRE(mockup::instance().chip_get_value(0, 3) == 1); - } -} - -TEST_CASE("Exported line can be released", "[line]") -{ - mockup::probe_guard mockup_chips({ 8 }); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - auto line = chip.get_line(4); - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - config.request_type = ::gpiod::line_request::DIRECTION_INPUT; - - line.request(config); - - REQUIRE(line.get_value() == 0); - - line.release(); - - REQUIRE_THROWS_AS(line.get_value(), ::std::system_error); -} - -TEST_CASE("Uninitialized GPIO line behaves correctly", "[line]") -{ - ::gpiod::line line; - - SECTION("uninitialized line is 'false'") - { - REQUIRE_FALSE(line); - } - - SECTION("using uninitialized line throws logic_error") - { - REQUIRE_THROWS_AS(line.name(), ::std::logic_error); - } -} - -TEST_CASE("Uninitialized GPIO line_bulk behaves correctly", "[line][bulk]") -{ - ::gpiod::line_bulk bulk; - - SECTION("uninitialized line_bulk is 'false'") - { - REQUIRE_FALSE(bulk); - } - - SECTION("using uninitialized line_bulk throws logic_error") - { - REQUIRE_THROWS_AS(bulk.get(0), ::std::logic_error); - } -} - -TEST_CASE("Cannot request the same line twice", "[line]") -{ - mockup::probe_guard mockup_chips({ 8 }); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - ::gpiod::line_request config; - - config.consumer = consumer.c_str(); - config.request_type = ::gpiod::line_request::DIRECTION_INPUT; - - SECTION("two separate calls to request()") - { - auto line = chip.get_line(3); - - REQUIRE_NOTHROW(line.request(config)); - REQUIRE_THROWS_AS(line.request(config), ::std::system_error); - } - - SECTION("request the same line twice in line_bulk") - { - /* - * While a line_bulk object can hold two or more line objects - * representing the same line - requesting it will fail. - */ - auto lines = chip.get_lines({ 2, 3, 4, 4 }); - - REQUIRE_THROWS_AS(lines.request(config), ::std::system_error); - } -} - -TEST_CASE("Cannot get/set values of unrequested lines", "[line]") -{ - mockup::probe_guard mockup_chips({ 8 }); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - auto line = chip.get_line(3); - - SECTION("get value") - { - REQUIRE_THROWS_AS(line.get_value(), ::std::system_error); - } - - SECTION("set value") - { - REQUIRE_THROWS_AS(line.set_value(1), ::std::system_error); - } -} - -TEST_CASE("Line objects can be compared") -{ - mockup::probe_guard mockup_chips({ 8 }); - ::gpiod::chip chip(mockup::instance().chip_path(0)); - auto line1 = chip.get_line(3); - auto line2 = chip.get_line(3); - auto line3 = chip.get_line(4); - - REQUIRE(line1 == line2); - REQUIRE(line2 != line3); -} -- 2.32.0