@@ -51,6 +51,11 @@ void chip_deleter(::gpiod_chip* chip)
} /* namespace */
+bool is_gpiochip_device(const ::std::string& path)
+{
+ return ::gpiod_is_gpiochip_device(path.c_str());
+}
+
chip::chip(const ::std::string& device, int how)
: _m_chip()
{
@@ -7,8 +7,8 @@
#
AM_CPPFLAGS = -I$(top_srcdir)/bindings/cxx/ -I$(top_srcdir)/include
-AM_CPPFLAGS += -Wall -Wextra -g -std=gnu++11
-AM_LDFLAGS = -lgpiodcxx -L$(top_builddir)/bindings/cxx/
+AM_CPPFLAGS += -Wall -Wextra -g -std=gnu++17
+AM_LDFLAGS = -lgpiodcxx -L$(top_builddir)/bindings/cxx/ -lstdc++fs
noinst_PROGRAMS = \
gpiodetectcxx \
@@ -10,6 +10,7 @@
#include <gpiod.hpp>
#include <cstdlib>
+#include <filesystem>
#include <iostream>
int main(int argc, char **argv)
@@ -19,10 +20,14 @@ int main(int argc, char **argv)
return EXIT_FAILURE;
}
- for (auto& it: ::gpiod::make_chip_iter()) {
- ::std::cout << it.name() << " ["
- << it.label() << "] ("
- << it.num_lines() << " lines)" << ::std::endl;
+ 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;
@@ -10,6 +10,7 @@
#include <gpiod.hpp>
#include <cstdlib>
+#include <filesystem>
#include <iostream>
int main(int argc, char **argv)
@@ -19,11 +20,16 @@ int main(int argc, char **argv)
return EXIT_FAILURE;
}
- for (auto& chip: ::gpiod::make_chip_iter()) {
- auto lines = chip.find_line(argv[1], true);
- if (!lines.empty()) {
- ::std::cout << lines.front().name() << " " << lines.front().offset() << ::std::endl;
- return EXIT_SUCCESS;
+ for (const auto& entry: ::std::filesystem::directory_iterator("/dev/")) {
+ if (::gpiod::is_gpiochip_device(entry.path())) {
+ ::gpiod::chip chip(entry.path());
+
+ auto lines = chip.find_line(argv[1], true);
+ if (!lines.empty()) {
+ ::std::cout << lines.front().name() << " " <<
+ lines.front().offset() << ::std::endl;
+ return EXIT_SUCCESS;
+ }
}
}
@@ -10,6 +10,7 @@
#include <gpiod.hpp>
#include <cstdlib>
+#include <filesystem>
#include <iostream>
int main(int argc, char **argv)
@@ -19,31 +20,35 @@ int main(int argc, char **argv)
return EXIT_FAILURE;
}
- for (auto& cit: ::gpiod::make_chip_iter()) {
- ::std::cout << cit.name() << " - " << cit.num_lines() << " lines:" << ::std::endl;
+ for (const auto& entry: ::std::filesystem::directory_iterator("/dev/")) {
+ if (::gpiod::is_gpiochip_device(entry.path())) {
+ ::gpiod::chip chip(entry.path());
- for (auto& lit: ::gpiod::line_iter(cit)) {
- ::std::cout << "\tline ";
- ::std::cout.width(3);
- ::std::cout << lit.offset() << ": ";
+ ::std::cout << chip.name() << " - " << chip.num_lines() << " lines:" << ::std::endl;
- ::std::cout.width(12);
- ::std::cout << (lit.name().empty() ? "unnamed" : lit.name());
- ::std::cout << " ";
+ 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.consumer().empty() ? "unused" : lit.consumer());
- ::std::cout << " ";
+ ::std::cout.width(12);
+ ::std::cout << (lit.name().empty() ? "unnamed" : lit.name());
+ ::std::cout << " ";
- ::std::cout.width(8);
- ::std::cout << (lit.direction() == ::gpiod::line::DIRECTION_INPUT ? "input" : "output");
- ::std::cout << " ";
+ ::std::cout.width(12);
+ ::std::cout << (lit.consumer().empty() ? "unused" : lit.consumer());
+ ::std::cout << " ";
- ::std::cout.width(10);
- ::std::cout << (lit.active_state() == ::gpiod::line::ACTIVE_LOW
- ? "active-low" : "active-high");
+ ::std::cout.width(8);
+ ::std::cout << (lit.direction() == ::gpiod::line::DIRECTION_INPUT ? "input" : "output");
+ ::std::cout << " ";
- ::std::cout << ::std::endl;
+ ::std::cout.width(10);
+ ::std::cout << (lit.active_state() == ::gpiod::line::ACTIVE_LOW
+ ? "active-low" : "active-high");
+
+ ::std::cout << ::std::endl;
+ }
}
}
@@ -32,6 +32,14 @@ struct line_event;
* @{
*/
+/**
+ * @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) GPIOD_API;
+
/**
* @brief Represents a GPIO chip.
*
@@ -861,115 +869,6 @@ private:
::std::vector<line> _m_bulk;
};
-/**
- * @brief Create a new chip_iter.
- * @return New chip iterator object pointing to the first GPIO chip on the system.
- * @note This function is needed as we already use the default constructor of
- * gpiod::chip_iter as the return value of gpiod::end.
- */
-GPIOD_API chip_iter make_chip_iter(void);
-
-/**
- * @brief Support for range-based loops for chip iterators.
- * @param iter A chip iterator.
- * @return Iterator unchanged.
- */
-GPIOD_API chip_iter begin(chip_iter iter) noexcept;
-
-/**
- * @brief Support for range-based loops for chip iterators.
- * @param iter A chip iterator.
- * @return New end iterator.
- */
-GPIOD_API chip_iter end(const chip_iter& iter) noexcept;
-
-/**
- * @brief Allows to iterate over all GPIO chips present on the system.
- */
-class chip_iter
-{
-public:
-
- /**
- * @brief Default constructor. Creates the end iterator.
- */
- GPIOD_API chip_iter(void) = default;
-
- /**
- * @brief Copy constructor.
- * @param other Other chip_iter.
- */
- GPIOD_API chip_iter(const chip_iter& other) = default;
-
- /**
- * @brief Move constructor.
- * @param other Other chip_iter.
- */
- GPIOD_API chip_iter(chip_iter&& other) = default;
-
- /**
- * @brief Assignment operator.
- * @param other Other chip_iter.
- * @return Reference to this iterator.
- */
- GPIOD_API chip_iter& operator=(const chip_iter& other) = default;
-
- /**
- * @brief Move assignment operator.
- * @param other Other chip_iter.
- * @return Reference to this iterator.
- */
- GPIOD_API chip_iter& operator=(chip_iter&& other) = default;
-
- /**
- * @brief Destructor.
- */
- GPIOD_API ~chip_iter(void) = default;
-
- /**
- * @brief Advance the iterator by one element.
- * @return Reference to this iterator.
- */
- GPIOD_API chip_iter& operator++(void);
-
- /**
- * @brief Dereference current element.
- * @return Current GPIO chip by reference.
- */
- GPIOD_API const chip& operator*(void) const;
-
- /**
- * @brief Member access operator.
- * @return Current GPIO chip by pointer.
- */
- GPIOD_API const chip* operator->(void) const;
-
- /**
- * @brief Check if this operator points to the same element.
- * @param rhs Right-hand side of the equation.
- * @return True if this iterator points to the same chip_iter,
- * false otherwise.
- */
- GPIOD_API bool operator==(const chip_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 chip_iter,
- * false otherwise.
- */
- GPIOD_API bool operator!=(const chip_iter& rhs) const noexcept;
-
-private:
-
- chip_iter(::gpiod_chip_iter* iter);
-
- ::std::shared_ptr<::gpiod_chip_iter> _m_iter;
- chip _m_current;
-
- friend chip_iter make_chip_iter(void);
-};
-
/**
* @brief Support for range-based loops for line iterators.
* @param iter A line iterator.
@@ -10,73 +10,6 @@
namespace gpiod {
-namespace {
-
-void chip_iter_deleter(::gpiod_chip_iter* iter)
-{
- ::gpiod_chip_iter_free_noclose(iter);
-}
-
-} /* namespace */
-
-chip_iter make_chip_iter(void)
-{
- ::gpiod_chip_iter* iter = ::gpiod_chip_iter_new();
- if (!iter)
- throw ::std::system_error(errno, ::std::system_category(),
- "error creating GPIO chip iterator");
-
- return chip_iter(iter);
-}
-
-bool chip_iter::operator==(const chip_iter& rhs) const noexcept
-{
- return this->_m_current == rhs._m_current;
-}
-
-bool chip_iter::operator!=(const chip_iter& rhs) const noexcept
-{
- return this->_m_current != rhs._m_current;
-}
-
-chip_iter::chip_iter(::gpiod_chip_iter *iter)
- : _m_iter(iter, chip_iter_deleter)
-{
- ::gpiod_chip* first = ::gpiod_chip_iter_next_noclose(this->_m_iter.get());
-
- if (first != nullptr)
- this->_m_current = chip(first);
-}
-
-chip_iter& chip_iter::operator++(void)
-{
- ::gpiod_chip* next = ::gpiod_chip_iter_next_noclose(this->_m_iter.get());
-
- this->_m_current = next ? chip(next) : chip();
-
- return *this;
-}
-
-const chip& chip_iter::operator*(void) const
-{
- return this->_m_current;
-}
-
-const chip* chip_iter::operator->(void) const
-{
- return ::std::addressof(this->_m_current);
-}
-
-chip_iter begin(chip_iter iter) noexcept
-{
- return iter;
-}
-
-chip_iter end(const chip_iter&) noexcept
-{
- return chip_iter();
-}
-
line_iter begin(line_iter iter) noexcept
{
return iter;
@@ -12,6 +12,26 @@
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 in different modes", "[chip]")
{
mockup::probe_guard mockup_chips({ 8, 8, 8 });
@@ -12,43 +12,6 @@
using ::gpiod::test::mockup;
-TEST_CASE("Chip iterator works", "[iter][chip]")
-{
- mockup::probe_guard mockup_chips({ 8, 8, 8 });
- bool gotA = false, gotB = false, gotC = false;
-
- for (auto& it: ::gpiod::make_chip_iter()) {
- if (it.label() == "gpio-mockup-A")
- gotA = true;
- if (it.label() == "gpio-mockup-B")
- gotB = true;
- if (it.label() == "gpio-mockup-C")
- gotC = true;
- }
-
- REQUIRE(gotA);
- REQUIRE(gotB);
- REQUIRE(gotC);
-}
-
-TEST_CASE("Chip iterator loop can be broken out of", "[iter][chip]")
-{
- mockup::probe_guard mockup_chips({ 8, 8, 8, 8, 8, 8 });
- int count_chips = 0;
-
- for (auto& it: ::gpiod::make_chip_iter()) {
- if (it.label() == "gpio-mockup-A" ||
- it.label() == "gpio-mockup-B" ||
- it.label() == "gpio-mockup-C")
- count_chips++;
-
- if (count_chips == 3)
- break;
- }
-
- REQUIRE(count_chips == 3);
-}
-
TEST_CASE("Line iterator works", "[iter][line]")
{
mockup::probe_guard mockup_chips({ 4 });
@@ -10,10 +10,12 @@
'''Reimplementation of the gpiodetect tool in Python.'''
import gpiod
+import os
if __name__ == '__main__':
- for chip in gpiod.ChipIter():
- print('{} [{}] ({} lines)'.format(chip.name(),
- chip.label(),
- chip.num_lines()))
- chip.close()
+ for entry in os.scandir('/dev/'):
+ if gpiod.is_gpiochip_device(entry.path):
+ with gpiod.Chip(entry.path) as chip:
+ print('{} [{}] ({} lines)'.format(chip.name(),
+ chip.label(),
+ chip.num_lines()))
@@ -10,12 +10,17 @@
'''Reimplementation of the gpiofind tool in Python.'''
import gpiod
+import os
import sys
if __name__ == '__main__':
- line = gpiod.find_line(sys.argv[1])
- if line is None:
- sys.exit(1)
+ for entry in os.scandir('/dev/'):
+ if gpiod.is_gpiochip_device(entry.path):
+ with gpiod.Chip(entry.path) as chip:
+ lines = chip.find_line(sys.argv[1], unique=True)
+ if lines is not None:
+ line = lines.to_list()[0]
+ print('{} {}'.format(line.owner().name(), line.offset()))
+ sys.exit(0)
- print('{} {}'.format(line.owner().name(), line.offset()))
- line.owner().close()
+ sys.exit(1)
@@ -10,23 +10,24 @@
'''Simplified reimplementation of the gpioinfo tool in Python.'''
import gpiod
+import os
if __name__ == '__main__':
- for chip in gpiod.ChipIter():
- print('{} - {} lines:'.format(chip.name(), chip.num_lines()))
+ for entry in os.scandir('/dev/'):
+ if gpiod.is_gpiochip_device(entry.path):
+ with gpiod.Chip(entry.path) as chip:
+ print('{} - {} lines:'.format(chip.name(), chip.num_lines()))
- for line in gpiod.LineIter(chip):
- offset = line.offset()
- name = line.name()
- consumer = line.consumer()
- direction = line.direction()
- active_state = line.active_state()
+ for line in gpiod.LineIter(chip):
+ offset = line.offset()
+ name = line.name()
+ consumer = line.consumer()
+ direction = line.direction()
+ active_state = line.active_state()
- print('\tline {:>3}: {:>18} {:>12} {:>8} {:>10}'.format(
- offset,
- 'unnamed' if name is None else name,
- 'unused' if consumer is None else consumer,
- 'input' if direction == gpiod.Line.DIRECTION_INPUT else 'output',
- 'active-low' if active_state == gpiod.Line.ACTIVE_LOW else 'active-high'))
-
- chip.close()
+ print('\tline {:>3}: {:>18} {:>12} {:>8} {:>10}'.format(
+ offset,
+ 'unnamed' if name is None else name,
+ 'unused' if consumer is None else consumer,
+ 'input' if direction == gpiod.Line.DIRECTION_INPUT else 'output',
+ 'active-low' if active_state == gpiod.Line.ACTIVE_LOW else 'active-high'))
@@ -34,11 +34,6 @@ typedef struct {
Py_ssize_t iter_idx;
} gpiod_LineBulkObject;
-typedef struct {
- PyObject_HEAD
- struct gpiod_chip_iter *iter;
-} gpiod_ChipIterObject;
-
typedef struct {
PyObject_HEAD
unsigned int offset;
@@ -2220,7 +2215,7 @@ PyDoc_STRVAR(gpiod_Chip_find_line_doc,
static gpiod_LineBulkObject *
gpiod_Chip_find_line(gpiod_ChipObject *self, PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = { "unique", NULL };
+ static char *kwlist[] = { "", "unique", NULL };
gpiod_LineBulkObject *bulk_obj;
struct gpiod_line_bulk *bulk;
@@ -2469,76 +2464,6 @@ static PyTypeObject gpiod_ChipType = {
.tp_methods = gpiod_Chip_methods,
};
-static int gpiod_ChipIter_init(gpiod_ChipIterObject *self,
- PyObject *Py_UNUSED(ignored0),
- PyObject *Py_UNUSED(ignored1))
-{
- self->iter = gpiod_chip_iter_new();
- if (!self->iter) {
- PyErr_SetFromErrno(PyExc_OSError);
- return -1;
- }
-
- return 0;
-}
-
-static void gpiod_ChipIter_dealloc(gpiod_ChipIterObject *self)
-{
- if (self->iter)
- gpiod_chip_iter_free_noclose(self->iter);
-
- PyObject_Del(self);
-}
-
-static gpiod_ChipObject *gpiod_ChipIter_next(gpiod_ChipIterObject *self)
-{
- gpiod_ChipObject *chip_obj;
- struct gpiod_chip *chip;
-
- Py_BEGIN_ALLOW_THREADS;
- chip = gpiod_chip_iter_next_noclose(self->iter);
- Py_END_ALLOW_THREADS;
- if (!chip)
- return NULL; /* Last element. */
-
- chip_obj = PyObject_New(gpiod_ChipObject, &gpiod_ChipType);
- if (!chip_obj) {
- gpiod_chip_close(chip);
- return NULL;
- }
-
- chip_obj->chip = chip;
-
- return chip_obj;
-}
-
-PyDoc_STRVAR(gpiod_ChipIterType_doc,
-"Allows to iterate over all GPIO chips in the system.\n"
-"\n"
-"The ChipIter's constructor takes no arguments.\n"
-"\n"
-"Each iteration yields the next open GPIO chip handle. The caller is\n"
-"responsible for closing each chip\n"
-"\n"
-"Example:\n"
-"\n"
-" for chip in gpiod.ChipIter():\n"
-" do_something_with_chip(chip)\n"
-" chip.close()");
-
-static PyTypeObject gpiod_ChipIterType = {
- PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "gpiod.ChipIter",
- .tp_basicsize = sizeof(gpiod_ChipIterObject),
- .tp_flags = Py_TPFLAGS_DEFAULT,
- .tp_doc = gpiod_ChipIterType_doc,
- .tp_new = PyType_GenericNew,
- .tp_init = (initproc)gpiod_ChipIter_init,
- .tp_dealloc = (destructor)gpiod_ChipIter_dealloc,
- .tp_iter = PyObject_SelfIter,
- .tp_iternext = (iternextfunc)gpiod_ChipIter_next,
-};
-
static int gpiod_LineIter_init(gpiod_LineIterObject *self,
PyObject *args, PyObject *Py_UNUSED(ignored))
{
@@ -2618,7 +2543,6 @@ static gpiod_PyType gpiod_PyType_list[] = {
{ .name = "LineEvent", .typeobj = &gpiod_LineEventType, },
{ .name = "LineBulk", .typeobj = &gpiod_LineBulkType, },
{ .name = "LineIter", .typeobj = &gpiod_LineIterType, },
- { .name = "ChipIter", .typeobj = &gpiod_ChipIterType },
{ }
};
@@ -2702,6 +2626,41 @@ static gpiod_ConstDescr gpiod_ConstList[] = {
{ }
};
+PyDoc_STRVAR(gpiod_Module_is_gpiochip_device_doc,
+"is_gpiochip_device(path) -> boolean\n"
+"\n"
+"Check if the file pointed to by path is a GPIO chip character device.\n"
+"Returns true if so, False otherwise.\n"
+"\n"
+" path\n"
+" Path to the file that should be checked.\n");
+
+static PyObject *
+gpiod_Module_is_gpiochip_device(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ const char *path;
+ int ret;
+
+ ret = PyArg_ParseTuple(args, "s", &path);
+ if (!ret)
+ return NULL;
+
+ if (gpiod_is_gpiochip_device(path))
+ Py_RETURN_TRUE;
+
+ Py_RETURN_FALSE;
+}
+
+static PyMethodDef gpiod_module_methods[] = {
+ {
+ .ml_name = "is_gpiochip_device",
+ .ml_meth = (PyCFunction)gpiod_Module_is_gpiochip_device,
+ .ml_flags = METH_VARARGS,
+ .ml_doc = gpiod_Module_is_gpiochip_device_doc,
+ },
+ { }
+};
+
PyDoc_STRVAR(gpiod_Module_doc,
"Python bindings for libgpiod.\n\
\n\
@@ -2712,6 +2671,7 @@ static PyModuleDef gpiod_Module = {
.m_name = "gpiod",
.m_doc = gpiod_Module_doc,
.m_size = -1,
+ .m_methods = gpiod_module_methods,
};
typedef struct {
@@ -79,6 +79,19 @@ def check_kernel(major, minor, release):
# Chip test cases
#
+class IsGpioDevice(MockupTestCase):
+
+ chip_sizes = ( 8, )
+
+ def test_is_gpiochip_device_good(self):
+ self.assertTrue(gpiod.is_gpiochip_device(mockup.chip_path(0)))
+
+ def test_is_gpiochip_device_bad(self):
+ self.assertFalse(gpiod.is_gpiochip_device('/dev/null'))
+
+ def test_is_gpiochip_device_nonexistent(self):
+ self.assertFalse(gpiod.is_gpiochip_device('/dev/nonexistent_device'))
+
class ChipOpen(MockupTestCase):
chip_sizes = ( 8, 8, 8 )
@@ -149,8 +162,7 @@ class ChipGetLines(MockupTestCase):
def test_find_single_line_by_name(self):
with gpiod.Chip(mockup.chip_name(1)) as chip:
- lines = chip.find_line('gpio-mockup-B-4').to_list()
- self.assertEqual(len(lines), 1)
+ lines = chip.find_line('gpio-mockup-B-4', unique=True).to_list()
self.assertEqual(lines[0].offset(), 4)
def test_get_single_line_invalid_offset(self):
@@ -162,7 +174,7 @@ class ChipGetLines(MockupTestCase):
def test_find_single_line_nonexistent(self):
with gpiod.Chip(mockup.chip_name(1)) as chip:
- lines = chip.find_line('nonexistent-line')
+ lines = chip.find_line('nonexistent-line', unique=True)
self.assertEqual(lines, None)
def test_get_multiple_lines_by_offsets_in_tuple(self):
@@ -675,27 +687,6 @@ class LineRequestBehavior(MockupTestCase):
# Iterator test cases
#
-class ChipIterator(MockupTestCase):
-
- chip_sizes = ( 4, 8, 16 )
-
- def test_iterate_over_chips(self):
- gotA = False
- gotB = False
- gotC = False
-
- for chip in gpiod.ChipIter():
- if chip.label() == 'gpio-mockup-A':
- gotA = True
- elif chip.label() == 'gpio-mockup-B':
- gotB = True
- elif chip.label() == 'gpio-mockup-C':
- gotC = True
-
- self.assertTrue(gotA)
- self.assertTrue(gotB)
- self.assertTrue(gotC)
-
class LineIterator(MockupTestCase):
chip_sizes = ( 4, )
@@ -181,6 +181,12 @@ then
AC_LANG_POP([C++])
])
fi
+
+ if test "x$with_examples" = xtrue
+ then
+ # Examples use C++17 features
+ AX_CXX_COMPILE_STDCXX([17], [ext], [mandatory])
+ fi
fi
AC_ARG_ENABLE([bindings-python],
@@ -8,6 +8,7 @@
#ifndef __LIBGPIOD_GPIOD_H__
#define __LIBGPIOD_GPIOD_H__
+#include <dirent.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
@@ -27,7 +28,7 @@ extern "C" {
* users of libgpiod.
*
* <p>The API is logically split into several parts such as: GPIO chip & line
- * operators, iterators, GPIO events handling etc.
+ * operators, GPIO events handling etc.
*
* <p>General note on error handling: all routines exported by libgpiod set
* errno to one of the error values defined in errno.h upon failure. The way
@@ -39,7 +40,6 @@ extern "C" {
struct gpiod_chip;
struct gpiod_line;
-struct gpiod_chip_iter;
struct gpiod_line_bulk;
/**
@@ -1053,95 +1053,6 @@ int gpiod_line_event_read_fd_multiple(int fd, struct gpiod_line_event *events,
/**
* @}
*
- * @}
- *
- * @defgroup iterators Iterators for GPIO chips and lines
- * @{
- *
- * These functions and data structures allow easy iterating over GPIO
- * chips and lines.
- */
-
-/**
- * @brief Create a new gpiochip iterator.
- * @return Pointer to a new chip iterator object or NULL if an error occurred.
- *
- * Internally this routine scans the /dev/ directory for GPIO chip device
- * files, opens them and stores their the handles until ::gpiod_chip_iter_free
- * or ::gpiod_chip_iter_free_noclose is called.
- */
-struct gpiod_chip_iter *gpiod_chip_iter_new(void) GPIOD_API;
-
-/**
- * @brief Release all resources allocated for the gpiochip iterator and close
- * the most recently opened gpiochip (if any).
- * @param iter The gpiochip iterator object.
- */
-void gpiod_chip_iter_free(struct gpiod_chip_iter *iter) GPIOD_API;
-
-/**
- * @brief Release all resources allocated for the gpiochip iterator but
- * don't close the most recently opened gpiochip (if any).
- * @param iter The gpiochip iterator object.
- *
- * Users may want to break the loop when iterating over gpiochips and keep
- * the most recently opened chip active while freeing the iterator data.
- * This routine enables that.
- */
-void gpiod_chip_iter_free_noclose(struct gpiod_chip_iter *iter) GPIOD_API;
-
-/**
- * @brief Get the next gpiochip handle.
- * @param iter The gpiochip iterator object.
- * @return Pointer to the next open gpiochip handle or NULL if no more chips
- * are present in the system.
- * @note The previous chip handle will be closed using ::gpiod_chip_iter_free.
- */
-struct gpiod_chip *
-gpiod_chip_iter_next(struct gpiod_chip_iter *iter) GPIOD_API;
-
-/**
- * @brief Get the next gpiochip handle without closing the previous one.
- * @param iter The gpiochip iterator object.
- * @return Pointer to the next open gpiochip handle or NULL if no more chips
- * are present in the system.
- * @note This function works just like ::gpiod_chip_iter_next but doesn't
- * close the most recently opened chip handle.
- */
-struct gpiod_chip *
-gpiod_chip_iter_next_noclose(struct gpiod_chip_iter *iter) GPIOD_API;
-
-/**
- * @brief Iterate over all GPIO chips present in the system.
- * @param iter An initialized GPIO chip iterator.
- * @param chip Pointer to a GPIO chip handle. On each iteration the newly
- * opened chip handle is assigned to this argument.
- *
- * The user must not close the GPIO chip manually - instead the previous chip
- * handle is closed automatically on the next iteration. The last chip to be
- * opened is closed internally by ::gpiod_chip_iter_free.
- */
-#define gpiod_foreach_chip(iter, chip) \
- for ((chip) = gpiod_chip_iter_next(iter); \
- (chip); \
- (chip) = gpiod_chip_iter_next(iter))
-
-/**
- * @brief Iterate over all chips present in the system without closing them.
- * @param iter An initialized GPIO chip iterator.
- * @param chip Pointer to a GPIO chip handle. On each iteration the newly
- * opened chip handle is assigned to this argument.
- *
- * The user must close all the GPIO chips manually after use, until then, the
- * chips remain open. Free the iterator by calling
- * ::gpiod_chip_iter_free_noclose to avoid closing the last chip automatically.
- */
-#define gpiod_foreach_chip_noclose(iter, chip) \
- for ((chip) = gpiod_chip_iter_next_noclose(iter); \
- (chip); \
- (chip) = gpiod_chip_iter_next_noclose(iter))
-
-/**
* @}
*
* @defgroup misc Stuff that didn't fit anywhere else
@@ -7,7 +7,7 @@
#
lib_LTLIBRARIES = libgpiod.la
-libgpiod_la_SOURCES = core.c helpers.c iter.c misc.c
+libgpiod_la_SOURCES = core.c helpers.c misc.c
libgpiod_la_CFLAGS = -Wall -Wextra -g -std=gnu89
libgpiod_la_CFLAGS += -fvisibility=hidden -I$(top_srcdir)/include/
libgpiod_la_CFLAGS += -include $(top_builddir)/config.h
deleted file mode 100644
@@ -1,123 +0,0 @@
-// SPDX-License-Identifier: LGPL-2.1-or-later
-/*
- * This file is part of libgpiod.
- *
- * Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
- */
-
-/* GPIO chip and line iterators. */
-
-#include <dirent.h>
-#include <gpiod.h>
-#include <string.h>
-
-struct gpiod_chip_iter {
- struct gpiod_chip **chips;
- unsigned int num_chips;
- unsigned int offset;
-};
-
-static int dir_filter(const struct dirent *dir)
-{
- return !strncmp(dir->d_name, "gpiochip", 8);
-}
-
-static void free_dirs(struct dirent **dirs, unsigned int num_dirs)
-{
- unsigned int i;
-
- for (i = 0; i < num_dirs; i++)
- free(dirs[i]);
- free(dirs);
-}
-
-struct gpiod_chip_iter *gpiod_chip_iter_new(void)
-{
- struct gpiod_chip_iter *iter;
- struct dirent **dirs;
- int i, num_chips;
-
- num_chips = scandir("/dev", &dirs, dir_filter, alphasort);
- if (num_chips < 0)
- return NULL;
-
- iter = malloc(sizeof(*iter));
- if (!iter)
- goto err_free_dirs;
-
- iter->num_chips = num_chips;
- iter->offset = 0;
-
- if (num_chips == 0) {
- iter->chips = NULL;
- return iter;
- }
-
- iter->chips = calloc(num_chips, sizeof(*iter->chips));
- if (!iter->chips)
- goto err_free_iter;
-
- for (i = 0; i < num_chips; i++) {
- iter->chips[i] = gpiod_chip_open_by_name(dirs[i]->d_name);
- if (!iter->chips[i])
- goto err_close_chips;
- }
-
- free_dirs(dirs, num_chips);
-
- return iter;
-
-err_close_chips:
- for (i = 0; i < num_chips; i++) {
- if (iter->chips[i])
- gpiod_chip_close(iter->chips[i]);
- }
-
- free(iter->chips);
-
-err_free_iter:
- free(iter);
-
-err_free_dirs:
- free_dirs(dirs, num_chips);
-
- return NULL;
-}
-
-void gpiod_chip_iter_free(struct gpiod_chip_iter *iter)
-{
- if (iter->offset > 0 && iter->offset < iter->num_chips)
- gpiod_chip_close(iter->chips[iter->offset - 1]);
- gpiod_chip_iter_free_noclose(iter);
-}
-
-void gpiod_chip_iter_free_noclose(struct gpiod_chip_iter *iter)
-{
- unsigned int i;
-
- for (i = iter->offset; i < iter->num_chips; i++) {
- if (iter->chips[i])
- gpiod_chip_close(iter->chips[i]);
- }
-
- if (iter->chips)
- free(iter->chips);
-
- free(iter);
-}
-
-struct gpiod_chip *gpiod_chip_iter_next(struct gpiod_chip_iter *iter)
-{
- if (iter->offset > 0) {
- gpiod_chip_close(iter->chips[iter->offset - 1]);
- iter->chips[iter->offset - 1] = NULL;
- }
-
- return gpiod_chip_iter_next_noclose(iter);
-}
-
-struct gpiod_chip *gpiod_chip_iter_next_noclose(struct gpiod_chip_iter *iter)
-{
- return iter->offset < (iter->num_chips)
- ? iter->chips[iter->offset++] : NULL;
-}
@@ -25,6 +25,5 @@ gpiod_test_SOURCES = \
tests-bulk.c \
tests-chip.c \
tests-event.c \
- tests-iter.c \
tests-line.c \
tests-misc.c
@@ -25,11 +25,9 @@
*/
typedef struct gpiod_chip gpiod_chip_struct;
typedef struct gpiod_line_bulk gpiod_line_bulk_struct;
-typedef struct gpiod_chip_iter gpiod_chip_iter_struct;
G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_chip_struct, gpiod_chip_close);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_line_bulk_struct, gpiod_line_bulk_free);
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_chip_iter_struct, gpiod_chip_iter_free);
/* These are private definitions and should not be used directly. */
typedef void (*_gpiod_test_func)(void);
deleted file mode 100644
@@ -1,100 +0,0 @@
-// SPDX-License-Identifier: LGPL-2.1-or-later
-/*
- * This file is part of libgpiod.
- *
- * Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
- */
-
-#include <string.h>
-
-#include "gpiod-test.h"
-
-#define GPIOD_TEST_GROUP "iter"
-
-GPIOD_TEST_CASE(chip_iter, 0, { 8, 8, 8 })
-{
- g_autoptr(gpiod_chip_iter_struct) iter = NULL;
- struct gpiod_chip *chip;
- gboolean A, B, C;
-
- A = B = C = FALSE;
-
- iter = gpiod_chip_iter_new();
- g_assert_nonnull(iter);
- gpiod_test_return_if_failed();
-
- gpiod_foreach_chip(iter, chip) {
- if (strcmp(gpiod_chip_label(chip), "gpio-mockup-A") == 0)
- A = TRUE;
- else if (strcmp(gpiod_chip_label(chip), "gpio-mockup-B") == 0)
- B = TRUE;
- else if (strcmp(gpiod_chip_label(chip), "gpio-mockup-C") == 0)
- C = TRUE;
- }
-
- g_assert_true(A);
- g_assert_true(B);
- g_assert_true(C);
-}
-
-GPIOD_TEST_CASE(chip_iter_no_close, 0, { 8, 8, 8 })
-{
- g_autoptr(gpiod_chip_iter_struct) iter = NULL;
- g_autoptr(gpiod_chip_struct) chipA = NULL;
- g_autoptr(gpiod_chip_struct) chipB = NULL;
- g_autoptr(gpiod_chip_struct) chipC = NULL;
- struct gpiod_chip *chip;
-
- iter = gpiod_chip_iter_new();
- g_assert_nonnull(iter);
- gpiod_test_return_if_failed();
-
- gpiod_foreach_chip_noclose(iter, chip) {
- if (strcmp(gpiod_chip_label(chip), "gpio-mockup-A") == 0)
- chipA = chip;
- else if (strcmp(gpiod_chip_label(chip), "gpio-mockup-B") == 0)
- chipB = chip;
- else if (strcmp(gpiod_chip_label(chip), "gpio-mockup-C") == 0)
- chipC = chip;
- else
- gpiod_chip_close(chip);
- }
-
- g_assert_nonnull(chipA);
- g_assert_nonnull(chipB);
- g_assert_nonnull(chipC);
-
- gpiod_chip_iter_free_noclose(iter);
- iter = NULL;
-
- /* See if the chips are still open and usable. */
- g_assert_cmpstr(gpiod_chip_label(chipA), ==, "gpio-mockup-A");
- g_assert_cmpstr(gpiod_chip_label(chipB), ==, "gpio-mockup-B");
- g_assert_cmpstr(gpiod_chip_label(chipC), ==, "gpio-mockup-C");
-}
-
-GPIOD_TEST_CASE(chip_iter_break, 0, { 8, 8, 8, 8, 8 })
-{
- g_autoptr(gpiod_chip_iter_struct) iter = NULL;
- struct gpiod_chip *chip;
- guint i = 0;
-
- iter = gpiod_chip_iter_new();
- g_assert_nonnull(iter);
- gpiod_test_return_if_failed();
-
- gpiod_foreach_chip(iter, chip) {
- if ((strcmp(gpiod_chip_label(chip), "gpio-mockup-A") == 0) ||
- (strcmp(gpiod_chip_label(chip), "gpio-mockup-B") == 0) ||
- (strcmp(gpiod_chip_label(chip), "gpio-mockup-C") == 0))
- i++;
-
- if (i == 3)
- break;
- }
-
- gpiod_chip_iter_free(iter);
- iter = NULL;
-
- g_assert_cmpuint(i, ==, 3);
-}
@@ -5,6 +5,8 @@
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
*/
+#include <dirent.h>
+#include <errno.h>
#include <getopt.h>
#include <gpiod.h>
#include <stdio.h>
@@ -33,9 +35,9 @@ static void print_help(void)
int main(int argc, char **argv)
{
- struct gpiod_chip_iter *iter;
+ int optc, opti, num_chips, i;
struct gpiod_chip *chip;
- int optc, opti;
+ struct dirent **entries;
for (;;) {
optc = getopt_long(argc, argv, shortopts, longopts, &opti);
@@ -62,18 +64,31 @@ int main(int argc, char **argv)
if (argc > 0)
die("unrecognized argument: %s", argv[0]);
- iter = gpiod_chip_iter_new();
- if (!iter)
- die_perror("unable to access GPIO chips");
+ num_chips = scandir("/dev/", &entries, chip_dir_filter, alphasort);
+ if (num_chips < 0)
+ die_perror("unable to scan /dev");
+
+ for (i = 0; i < num_chips; i++) {
+ chip = gpiod_chip_open_by_name(entries[i]->d_name);
+ if (!chip) {
+ if (errno == EACCES)
+ printf("%s Permission denied\n",
+ entries[i]->d_name);
+ else
+ die_perror("unable to open %s",
+ entries[i]->d_name);
+ }
- gpiod_foreach_chip(iter, chip) {
printf("%s [%s] (%u lines)\n",
gpiod_chip_name(chip),
gpiod_chip_label(chip),
gpiod_chip_num_lines(chip));
+
+ gpiod_chip_close(chip);
+ free(entries[i]);
}
- gpiod_chip_iter_free(iter);
+ free(entries);
return EXIT_SUCCESS;
}
@@ -5,6 +5,7 @@
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
*/
+#include <dirent.h>
#include <errno.h>
#include <getopt.h>
#include <gpiod.h>
@@ -34,10 +35,10 @@ static void print_help(void)
int main(int argc, char **argv)
{
- struct gpiod_chip_iter *iter;
+ int i, num_chips, optc, opti;
struct gpiod_chip *chip;
struct gpiod_line *line;
- int optc, opti;
+ struct dirent **entries;
for (;;) {
optc = getopt_long(argc, argv, shortopts, longopts, &opti);
@@ -64,23 +65,27 @@ int main(int argc, char **argv)
if (argc != 1)
die("exactly one GPIO line name must be specified");
- iter = gpiod_chip_iter_new();
- if (!iter)
- die_perror("unable to access GPIO chips");
+ num_chips = scandir("/dev/", &entries, chip_dir_filter, alphasort);
+ if (num_chips < 0)
+ die_perror("unable to scan /dev");
+
+ for (i = 0; i < num_chips; i++) {
+ chip = gpiod_chip_open_by_name(entries[i]->d_name);
+ if (!chip) {
+ if (errno == EACCES)
+ continue;
+
+ die_perror("unable to open %s", entries[i]->d_name);
+ }
- gpiod_foreach_chip(iter, chip) {
line = gpiod_chip_find_line_unique(chip, argv[0]);
if (line) {
printf("%s %u\n",
gpiod_chip_name(chip), gpiod_line_offset(line));
- gpiod_chip_iter_free(iter);
+ gpiod_chip_close(chip);
return EXIT_SUCCESS;
}
-
- if (errno != ENOENT)
- die_perror("error performing the line lookup");
}
- gpiod_chip_iter_free(iter);
return EXIT_FAILURE;
}
@@ -5,6 +5,7 @@
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
*/
+#include <dirent.h>
#include <errno.h>
#include <getopt.h>
#include <gpiod.h>
@@ -180,9 +181,9 @@ static void list_lines(struct gpiod_chip *chip)
int main(int argc, char **argv)
{
- struct gpiod_chip_iter *chip_iter;
+ int num_chips, i, optc, opti;
struct gpiod_chip *chip;
- int i, optc, opti;
+ struct dirent **entries;
for (;;) {
optc = getopt_long(argc, argv, shortopts, longopts, &opti);
@@ -207,14 +208,26 @@ int main(int argc, char **argv)
argv += optind;
if (argc == 0) {
- chip_iter = gpiod_chip_iter_new();
- if (!chip_iter)
- die_perror("error accessing GPIO chips");
+ num_chips = scandir("/dev/", &entries,
+ chip_dir_filter, alphasort);
+ if (num_chips < 0)
+ die_perror("unable to scan /dev");
+
+ for (i = 0; i < num_chips; i++) {
+ chip = gpiod_chip_open_by_name(entries[i]->d_name);
+ if (!chip) {
+ if (errno == EACCES)
+ printf("%s Permission denied\n",
+ entries[i]->d_name);
+ else
+ die_perror("unable to open %s",
+ entries[i]->d_name);
+ }
- gpiod_foreach_chip(chip_iter, chip)
list_lines(chip);
- gpiod_chip_iter_free(chip_iter);
+ gpiod_chip_close(chip);
+ }
} else {
for (i = 0; i < argc; i++) {
chip = gpiod_chip_open_lookup(argv[i]);
@@ -101,3 +101,18 @@ int make_signalfd(void)
return sigfd;
}
+
+int chip_dir_filter(const struct dirent *entry)
+{
+ bool is_chip;
+ char *path;
+ int ret;
+
+ ret = asprintf(&path, "/dev/%s", entry->d_name);
+ if (ret < 0)
+ return 0;
+
+ is_chip = gpiod_is_gpiochip_device(path);
+ free(path);
+ return !!is_chip;
+}
@@ -8,6 +8,8 @@
#ifndef __GPIOD_TOOLS_COMMON_H__
#define __GPIOD_TOOLS_COMMON_H__
+#include <dirent.h>
+
/*
* Various helpers for the GPIO tools.
*
@@ -29,5 +31,6 @@ void print_version(void);
int bias_flags(const char *option);
void print_bias_help(void);
int make_signalfd(void);
+int chip_dir_filter(const struct dirent *entry);
#endif /* __GPIOD_TOOLS_COMMON_H__ */