@@ -16,6 +16,12 @@ EXTRA_DIST = \
LICENSES/LGPL-3.0-or-later.txt \
LICENSES/BSD-3-Clause.txt
+if WITH_EXAMPLES
+
+SUBDIRS += examples
+
+endif
+
if WITH_TOOLS
SUBDIRS += tools man
@@ -268,6 +268,7 @@ AC_CONFIG_FILES([Makefile
lib/Makefile
lib/libgpiod.pc
contrib/Makefile
+ examples/Makefile
tools/Makefile
tests/Makefile
tests/gpiosim/Makefile
new file mode 100644
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
+
+async_watch_line_value
+get_line_value
+toggle_line_value
+watch_line_value
new file mode 100644
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
+
+AM_CFLAGS = -I$(top_srcdir)/include/ -include $(top_builddir)/config.h
+AM_CFLAGS += -Wall -Wextra -g -std=gnu89
+
+LDADD = $(top_builddir)/lib/libgpiod.la
+
+bin_PROGRAMS = async_watch_line_value get_line_value toggle_line_value watch_line_value
+
+async_watch_line_value_SOURCES = async_watch_line_value.c
+
+get_line_value_SOURCES = get_line_value.c
+
+toggle_line_valuer_SOURCES = toggle_line_value.c
+
+watch_line_value_SOURCES = watch_line_value.c
new file mode 100644
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
+
+/* Minimal example of asynchronously watching for edges on a single line */
+
+#include <errno.h>
+#include <gpiod.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* request a line as input with edge detection */
+struct gpiod_line_request *request_input_line(const char *chip_path,
+ unsigned int offset,
+ const char *consumer)
+{
+ struct gpiod_line_settings *settings;
+ struct gpiod_line_request *request = NULL;
+ struct gpiod_request_config *req_cfg = NULL;
+ struct gpiod_line_config *line_cfg;
+ struct gpiod_chip *chip;
+ int ret;
+
+ chip = gpiod_chip_open(chip_path);
+ if (!chip)
+ return NULL;
+
+ settings = gpiod_line_settings_new();
+ if (!settings)
+ goto close_chip;
+
+ gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_INPUT);
+ gpiod_line_settings_set_edge_detection(settings, GPIOD_LINE_EDGE_BOTH);
+ /* assume a button connecting the pin to ground, so pull it up... */
+ gpiod_line_settings_set_bias(settings, GPIOD_LINE_BIAS_PULL_UP);
+ /* ... and provide some debounce. */
+ gpiod_line_settings_set_debounce_period_us(settings, 10000);
+
+ line_cfg = gpiod_line_config_new();
+ if (!line_cfg)
+ goto free_settings;
+
+ ret = gpiod_line_config_add_line_settings(line_cfg, &offset, 1,
+ settings);
+ if (ret)
+ goto free_line_config;
+
+ if (consumer) {
+ req_cfg = gpiod_request_config_new();
+ if (!req_cfg)
+ goto free_line_config;
+
+ gpiod_request_config_set_consumer(req_cfg, consumer);
+ }
+
+ request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
+
+ gpiod_request_config_free(req_cfg);
+free_line_config:
+ gpiod_line_config_free(line_cfg);
+free_settings:
+ gpiod_line_settings_free(settings);
+close_chip:
+ gpiod_chip_close(chip);
+
+ return request;
+}
+
+const char *edge_event_type_str(struct gpiod_edge_event *event)
+{
+ enum gpiod_edge_event_type eet = gpiod_edge_event_get_event_type(event);
+
+ if (eet == GPIOD_EDGE_EVENT_RISING_EDGE)
+ return "Rising ";
+ if (eet == GPIOD_EDGE_EVENT_FALLING_EDGE)
+ return "Falling";
+ return "Unknown";
+}
+
+int main(void)
+{
+ struct gpiod_line_request *request;
+ struct gpiod_edge_event_buffer *event_buffer;
+ struct gpiod_edge_event *event;
+ struct pollfd pollfd;
+ int i, ret, event_buf_size;
+ /* example configuration - customize to suit your situation */
+ const char *chip_path = "/dev/gpiochip0";
+ int line_offset = 5;
+
+ request = request_input_line(chip_path, line_offset,
+ "async-watch-line-value");
+ if (!request) {
+ fprintf(stderr, "failed to request line: %s\n",
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ /* a larger buffer is an optimisation for reading bursts of events from
+ * the kernel, but that is not necessary in this case, so 1 is fine.
+ */
+ event_buf_size = 1;
+ event_buffer = gpiod_edge_event_buffer_new(event_buf_size);
+ if (!event_buffer) {
+ fprintf(stderr, "failed to create event buffer: %s\n",
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ pollfd.fd = gpiod_line_request_get_fd(request);
+ pollfd.events = POLLIN;
+ while (1) {
+ ret = poll(&pollfd, 1, -1);
+ if (ret == -1) {
+ fprintf(stderr, "error waiting for edge events: %s\n",
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+ ret = gpiod_line_request_read_edge_events(request, event_buffer,
+ event_buf_size);
+ if (ret == -1) {
+ fprintf(stderr, "error reading edge events: %s\n",
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+ for (i = 0; i < ret; i++) {
+ event = gpiod_edge_event_buffer_get_event(event_buffer,
+ i);
+ printf("offset: %d, type: %s, event #%ld\n",
+ gpiod_edge_event_get_line_offset(event),
+ edge_event_type_str(event),
+ gpiod_edge_event_get_line_seqno(event));
+ }
+ }
+}
new file mode 100644
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
+
+/* Minimal example of reading a single line. */
+
+#include <errno.h>
+#include <gpiod.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* request a line as input */
+struct gpiod_line_request *request_input_line(const char *chip_path,
+ unsigned int offset,
+ const char *consumer)
+{
+ struct gpiod_line_settings *settings;
+ struct gpiod_line_request *request = NULL;
+ struct gpiod_request_config *req_cfg = NULL;
+ struct gpiod_line_config *line_cfg;
+ struct gpiod_chip *chip;
+ int ret;
+
+ chip = gpiod_chip_open(chip_path);
+ if (!chip)
+ return NULL;
+
+ settings = gpiod_line_settings_new();
+ if (!settings)
+ goto close_chip;
+
+ gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_INPUT);
+
+ line_cfg = gpiod_line_config_new();
+ if (!line_cfg)
+ goto free_settings;
+
+ ret = gpiod_line_config_add_line_settings(line_cfg, &offset, 1,
+ settings);
+ if (ret)
+ goto free_line_config;
+
+ if (consumer) {
+ req_cfg = gpiod_request_config_new();
+ if (!req_cfg)
+ goto free_line_config;
+
+ gpiod_request_config_set_consumer(req_cfg, consumer);
+ }
+
+ request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
+
+ gpiod_request_config_free(req_cfg);
+free_line_config:
+ gpiod_line_config_free(line_cfg);
+free_settings:
+ gpiod_line_settings_free(settings);
+close_chip:
+ gpiod_chip_close(chip);
+
+ return request;
+}
+
+int print_value(enum gpiod_line_value value)
+{
+ if (value == GPIOD_LINE_VALUE_ACTIVE)
+ printf("Active\n");
+ else if (value == GPIOD_LINE_VALUE_INACTIVE) {
+ printf("Inactive\n");
+ } else {
+ fprintf(stderr, "error reading value: %s\n",
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+}
+
+int main(void)
+{
+ struct gpiod_line_request *request;
+ enum gpiod_line_value value;
+ int ret;
+ /* example configuration - customize to suit your situation */
+ const char *chip_path = "/dev/gpiochip0";
+ int line_offset = 5;
+
+ request = request_input_line(chip_path, line_offset, "get-line-value");
+ if (!request) {
+ fprintf(stderr, "failed to request line: %s\n",
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ value = gpiod_line_request_get_value(request, line_offset);
+ ret = print_value(value);
+ return ret;
+}
new file mode 100644
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
+
+/* Minimal example of toggling a single line. */
+
+#include <errno.h>
+#include <gpiod.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct gpiod_line_request *request_output_line(const char *chip_path,
+ unsigned int offset,
+ enum gpiod_line_value value,
+ const char *consumer)
+{
+ struct gpiod_line_settings *settings;
+ struct gpiod_line_request *request = NULL;
+ struct gpiod_request_config *req_cfg = NULL;
+ struct gpiod_line_config *line_cfg;
+ struct gpiod_chip *chip;
+ int ret;
+
+ chip = gpiod_chip_open(chip_path);
+ if (!chip)
+ return NULL;
+
+ settings = gpiod_line_settings_new();
+ if (!settings)
+ goto close_chip;
+
+ gpiod_line_settings_set_direction(settings,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ gpiod_line_settings_set_output_value(settings, value);
+
+ line_cfg = gpiod_line_config_new();
+ if (!line_cfg)
+ goto free_settings;
+
+ ret = gpiod_line_config_add_line_settings(line_cfg, &offset, 1,
+ settings);
+ if (ret)
+ goto free_settings;
+
+ if (consumer) {
+ req_cfg = gpiod_request_config_new();
+ if (!req_cfg)
+ goto free_line_config;
+
+ gpiod_request_config_set_consumer(req_cfg, consumer);
+ }
+
+ request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
+
+ gpiod_request_config_free(req_cfg);
+free_line_config:
+ gpiod_line_config_free(line_cfg);
+free_settings:
+ gpiod_line_settings_free(settings);
+close_chip:
+ gpiod_chip_close(chip);
+
+ return request;
+}
+
+enum gpiod_line_value toggle_line_value(enum gpiod_line_value value)
+{
+ return (value == GPIOD_LINE_VALUE_ACTIVE) ? GPIOD_LINE_VALUE_INACTIVE :
+ GPIOD_LINE_VALUE_ACTIVE;
+}
+
+void print_value(enum gpiod_line_value value)
+{
+ if (value == GPIOD_LINE_VALUE_ACTIVE)
+ printf("Active\n");
+ else
+ printf("Inactive\n");
+}
+
+int main(void)
+{
+ struct gpiod_line_request *request;
+ enum gpiod_line_value value = GPIOD_LINE_VALUE_ACTIVE;
+ /* example configuration - customize to suit your situation */
+ const char *chip_path = "/dev/gpiochip0";
+ int line_offset = 5;
+
+ request = request_output_line(chip_path, line_offset, value,
+ "toggle-line-value");
+ if (!request) {
+ fprintf(stderr, "failed to request line: %s\n",
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ while (1) {
+ print_value(value);
+ sleep(1);
+ value = toggle_line_value(value);
+ gpiod_line_request_set_value(request, line_offset, value);
+ }
+
+ gpiod_line_request_release(request);
+ return EXIT_SUCCESS;
+}
new file mode 100644
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
+
+/* Minimal example of watching for edges on a single line. */
+
+#include <errno.h>
+#include <gpiod.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* request a line as input with edge detection */
+struct gpiod_line_request *request_input_line(const char *chip_path,
+ unsigned int offset,
+ const char *consumer)
+{
+ struct gpiod_line_settings *settings;
+ struct gpiod_line_request *request = NULL;
+ struct gpiod_request_config *req_cfg = NULL;
+ struct gpiod_line_config *line_cfg;
+ struct gpiod_chip *chip;
+ int ret;
+
+ chip = gpiod_chip_open(chip_path);
+ if (!chip)
+ return NULL;
+
+ settings = gpiod_line_settings_new();
+ if (!settings)
+ goto close_chip;
+
+ gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_INPUT);
+ gpiod_line_settings_set_edge_detection(settings, GPIOD_LINE_EDGE_BOTH);
+ /* assume a button connecting the pin to ground, so pull it up... */
+ gpiod_line_settings_set_bias(settings, GPIOD_LINE_BIAS_PULL_UP);
+ /* ... and provide some debounce. */
+ gpiod_line_settings_set_debounce_period_us(settings, 10000);
+
+ line_cfg = gpiod_line_config_new();
+ if (!line_cfg)
+ goto free_settings;
+
+ ret = gpiod_line_config_add_line_settings(line_cfg, &offset, 1,
+ settings);
+ if (ret)
+ goto free_line_config;
+
+ if (consumer) {
+ req_cfg = gpiod_request_config_new();
+ if (!req_cfg)
+ goto free_line_config;
+
+ gpiod_request_config_set_consumer(req_cfg, consumer);
+ }
+
+ request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
+
+ gpiod_request_config_free(req_cfg);
+free_line_config:
+ gpiod_line_config_free(line_cfg);
+free_settings:
+ gpiod_line_settings_free(settings);
+close_chip:
+ gpiod_chip_close(chip);
+
+ return request;
+}
+
+const char *edge_event_type_str(struct gpiod_edge_event *event)
+{
+ enum gpiod_edge_event_type eet = gpiod_edge_event_get_event_type(event);
+
+ if (eet == GPIOD_EDGE_EVENT_RISING_EDGE)
+ return "Rising ";
+ if (eet == GPIOD_EDGE_EVENT_FALLING_EDGE)
+ return "Falling";
+ return "Unknown";
+}
+
+int main(void)
+{
+ struct gpiod_line_request *request;
+ struct gpiod_edge_event_buffer *event_buffer;
+ struct gpiod_edge_event *event;
+ int i, ret, event_buf_size;
+ /* example configuration - customize to suit your situation */
+ const char *chip_path = "/dev/gpiochip0";
+ int line_offset = 5;
+
+ request = request_input_line(chip_path, line_offset,
+ "watch-line-value");
+ if (!request) {
+ fprintf(stderr, "failed to request line: %s\n",
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ /* a larger buffer is an optimisation for reading bursts of events from
+ * the kernel, but that is not necessary in this case, so 1 is fine.
+ */
+ event_buf_size = 1;
+ event_buffer = gpiod_edge_event_buffer_new(event_buf_size);
+ if (!event_buffer) {
+ fprintf(stderr, "failed to create event buffer: %s\n",
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ while (1) {
+ /* blocks until at least one event is available */
+ ret = gpiod_line_request_read_edge_events(request, event_buffer,
+ event_buf_size);
+ if (ret == -1) {
+ fprintf(stderr, "error reading edge events: %s\n",
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+ for (i = 0; i < ret; i++) {
+ event = gpiod_edge_event_buffer_get_event(event_buffer,
+ i);
+ printf("offset: %d, type: %s, event #%ld\n",
+ gpiod_edge_event_get_line_offset(event),
+ edge_event_type_str(event),
+ gpiod_edge_event_get_line_seqno(event));
+ }
+ }
+}
The tools have served as example code, but have become too complicated to serve that purpose. Add a set of examples that have no purpose other than providing minimal examples of common use cases. Signed-off-by: Kent Gibson <warthog618@gmail.com> --- Makefile.am | 6 ++ configure.ac | 1 + examples/.gitignore | 7 ++ examples/Makefile.am | 17 ++++ examples/async_watch_line_value.c | 136 ++++++++++++++++++++++++++++++ examples/get_line_value.c | 97 +++++++++++++++++++++ examples/toggle_line_value.c | 106 +++++++++++++++++++++++ examples/watch_line_value.c | 127 ++++++++++++++++++++++++++++ 8 files changed, 497 insertions(+) create mode 100644 examples/.gitignore create mode 100644 examples/Makefile.am create mode 100644 examples/async_watch_line_value.c create mode 100644 examples/get_line_value.c create mode 100644 examples/toggle_line_value.c create mode 100644 examples/watch_line_value.c