diff mbox series

[libgpiod,2/8] core: examples: add more use case examples

Message ID 20230623043901.16764-3-warthog618@gmail.com
State New
Headers show
Series replace tool examples with use case examples | expand

Commit Message

Kent Gibson June 23, 2023, 4:38 a.m. UTC
Add examples for use cases drawn from the tools.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 examples/.gitignore                    |   9 ++
 examples/Makefile.am                   |  29 ++++-
 examples/find_line_by_name.c           | 111 ++++++++++++++++++
 examples/get_chip_info.c               |  40 +++++++
 examples/get_line_info.c               |  56 +++++++++
 examples/get_multiple_line_values.c    | 119 +++++++++++++++++++
 examples/reconfigure_input_to_output.c | 152 +++++++++++++++++++++++++
 examples/toggle_multiple_line_values.c | 136 ++++++++++++++++++++++
 examples/watch_line_info.c             |  72 ++++++++++++
 examples/watch_line_rising.c           | 129 +++++++++++++++++++++
 examples/watch_multiple_line_values.c  | 140 +++++++++++++++++++++++
 11 files changed, 992 insertions(+), 1 deletion(-)
 create mode 100644 examples/find_line_by_name.c
 create mode 100644 examples/get_chip_info.c
 create mode 100644 examples/get_line_info.c
 create mode 100644 examples/get_multiple_line_values.c
 create mode 100644 examples/reconfigure_input_to_output.c
 create mode 100644 examples/toggle_multiple_line_values.c
 create mode 100644 examples/watch_line_info.c
 create mode 100644 examples/watch_line_rising.c
 create mode 100644 examples/watch_multiple_line_values.c
diff mbox series

Patch

diff --git a/examples/.gitignore b/examples/.gitignore
index bdfde9a..8fd3ff3 100644
--- a/examples/.gitignore
+++ b/examples/.gitignore
@@ -2,6 +2,15 @@ 
 # SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
 
 async_watch_line_value
+find_line_by_name
+get_chip_info
+get_line_info
 get_line_value
+get_multiple_line_values
+reconfigure_input_to_output
 toggle_line_value
+toggle_multiple_line_values
+watch_line_info
+watch_line_rising
 watch_line_value
+watch_multiple_line_values
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 55dfe39..daf902b 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -8,14 +8,41 @@  LDADD = $(top_builddir)/lib/libgpiod.la
 
 noinst_PROGRAMS = \
 	async_watch_line_value \
+	find_line_by_name \
+	get_chip_info \
+	get_line_info \
 	get_line_value \
+	get_multiple_line_values \
+	reconfigure_input_to_output \
 	toggle_line_value \
-	watch_line_value
+	toggle_multiple_line_values \
+	watch_line_info \
+	watch_line_rising \
+	watch_line_value \
+	watch_multiple_line_values
 
 async_watch_line_value_SOURCES = async_watch_line_value.c
 
+find_line_by_name_SOURCES = find_line_by_name.c
+
+get_chip_info_SOURCES = get_chip_info.c
+
+get_line_info_SOURCES = get_line_info.c
+
 get_line_value_SOURCES = get_line_value.c
 
+get_multiple_line_values_SOURCES = get_multiple_line_values.c
+
+reconfigure_input_to_output_SOURCES = reconfigure_input_to_output.c
+
 toggle_line_value_SOURCES = toggle_line_value.c
 
+toggle_multiple_line_value_SOURCES = toggle_multiple_line_value.c
+
+watch_line_info_SOURCES = watch_line_info.c
+
+watch_line_rising_SOURCES = watch_line_rising.c
+
 watch_line_value_SOURCES = watch_line_value.c
+
+watch_multiple_line_values_SOURCES = watch_multiple_line_values.c
diff --git a/examples/find_line_by_name.c b/examples/find_line_by_name.c
new file mode 100644
index 0000000..ea1d938
--- /dev/null
+++ b/examples/find_line_by_name.c
@@ -0,0 +1,111 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
+
+/* Minimal example of finding a line with the given name. */
+
+#include <dirent.h>
+#include <errno.h>
+#include <gpiod.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+static int chip_dir_filter(const struct dirent *entry)
+{
+	struct stat sb;
+	int ret = 0;
+	char *path;
+
+	if (asprintf(&path, "/dev/%s", entry->d_name) < 0)
+		return 0;
+
+	if ((lstat(path, &sb) == 0) && (!S_ISLNK(sb.st_mode)) &&
+	    gpiod_is_gpiochip_device(path))
+		ret = 1;
+
+	free(path);
+
+	return ret;
+}
+
+static int all_chip_paths(char ***paths_ptr)
+{
+	int i, j, num_chips, ret = 0;
+	struct dirent **entries;
+	char **paths;
+
+	num_chips = scandir("/dev/", &entries, chip_dir_filter, versionsort);
+	if (num_chips < 0)
+		return 0;
+
+	paths = calloc(num_chips, sizeof(*paths));
+	if (!paths)
+		return 0;
+
+	for (i = 0; i < num_chips; i++) {
+		if (asprintf(&paths[i], "/dev/%s", entries[i]->d_name) < 0) {
+			for (j = 0; j < i; j++)
+				free(paths[j]);
+
+			free(paths);
+			return 0;
+		}
+	}
+
+	*paths_ptr = paths;
+	ret = num_chips;
+
+	for (i = 0; i < num_chips; i++)
+		free(entries[i]);
+
+	free(entries);
+	return ret;
+}
+
+int main(void)
+{
+	/* Example configuration - customize to suit your situation. */
+	static const char *const line_name = "GPIO19";
+
+	struct gpiod_chip *chip;
+	struct gpiod_chip_info *cinfo;
+	struct gpiod_line_info *linfo;
+	char **chip_paths;
+	const char *name;
+	unsigned int j, num_lines;
+	int i, num_chips;
+
+	/*
+	 * Names are not guaranteed unique, so this finds the first line with
+	 * the given name.
+	 */
+	num_chips = all_chip_paths(&chip_paths);
+	for (i = 0; i < num_chips; i++) {
+		chip = gpiod_chip_open(chip_paths[i]);
+		if (!chip)
+			continue;
+		cinfo = gpiod_chip_get_info(chip);
+		if (!cinfo)
+			continue;
+
+		num_lines = gpiod_chip_info_get_num_lines(cinfo);
+		for (j = 0; j < num_lines; j++) {
+			linfo = gpiod_chip_get_line_info(chip, j);
+			if (!linfo)
+				continue;
+			name = gpiod_line_info_get_name(linfo);
+			if (name && (strcmp(line_name, name) == 0)) {
+				printf("%s: %s %d\n", line_name,
+				       gpiod_chip_info_get_name(cinfo), j);
+				return EXIT_SUCCESS;
+			}
+			gpiod_line_info_free(linfo);
+		}
+		gpiod_chip_info_free(cinfo);
+		gpiod_chip_close(chip);
+	}
+
+	printf("line '%s' not found\n", line_name);
+	return EXIT_FAILURE;
+}
diff --git a/examples/get_chip_info.c b/examples/get_chip_info.c
new file mode 100644
index 0000000..5c181c8
--- /dev/null
+++ b/examples/get_chip_info.c
@@ -0,0 +1,40 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
+
+/* Minimal example of reading the info for a chip. */
+
+#include <errno.h>
+#include <gpiod.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(void)
+{
+	/* Example configuration - customize to suit your situation. */
+	static const char *const chip_path = "/dev/gpiochip0";
+
+	struct gpiod_chip_info *info;
+	struct gpiod_chip *chip;
+
+	chip = gpiod_chip_open(chip_path);
+	if (!chip) {
+		fprintf(stderr, "failed to open chip: %s\n", strerror(errno));
+		return EXIT_FAILURE;
+	}
+
+	info = gpiod_chip_get_info(chip);
+	if (!info) {
+		fprintf(stderr, "failed to read info: %s\n", strerror(errno));
+		return EXIT_FAILURE;
+	}
+
+	printf("%s [%s] (%zu lines)\n", gpiod_chip_info_get_name(info),
+	       gpiod_chip_info_get_label(info),
+	       gpiod_chip_info_get_num_lines(info));
+
+	gpiod_chip_info_free(info);
+	gpiod_chip_close(chip);
+
+	return EXIT_SUCCESS;
+}
diff --git a/examples/get_line_info.c b/examples/get_line_info.c
new file mode 100644
index 0000000..743c98f
--- /dev/null
+++ b/examples/get_line_info.c
@@ -0,0 +1,56 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
+
+/* Minimal example of reading the info for a line. */
+
+#include <errno.h>
+#include <gpiod.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(void)
+{
+	/* Example configuration - customize to suit your situation. */
+	static const char *const chip_path = "/dev/gpiochip0";
+	static const unsigned int line_offset = 3;
+
+	struct gpiod_line_info *info;
+	struct gpiod_chip *chip;
+	const char *name, *consumer, *dir;
+
+	chip = gpiod_chip_open(chip_path);
+	if (!chip) {
+		fprintf(stderr, "failed to open chip: %s\n", strerror(errno));
+		return EXIT_FAILURE;
+	}
+
+	info = gpiod_chip_get_line_info(chip, line_offset);
+	if (!info) {
+		fprintf(stderr, "failed to read info: %s\n", strerror(errno));
+		return EXIT_FAILURE;
+	}
+
+	name = gpiod_line_info_get_name(info);
+	if (!name)
+		name = "unnamed";
+
+	consumer = gpiod_line_info_get_consumer(info);
+	if (!consumer)
+		consumer = "unused";
+
+	dir = (gpiod_line_info_get_direction(info) ==
+	       GPIOD_LINE_DIRECTION_INPUT) ?
+		      "input" :
+		      "output";
+
+	printf("line %3d: %12s %12s %8s %10s\n",
+	       gpiod_line_info_get_offset(info), name, consumer, dir,
+	       gpiod_line_info_is_active_low(info) ? "active-low" :
+						     "active-high");
+
+	gpiod_line_info_free(info);
+	gpiod_chip_close(chip);
+
+	return EXIT_SUCCESS;
+}
diff --git a/examples/get_multiple_line_values.c b/examples/get_multiple_line_values.c
new file mode 100644
index 0000000..fc26636
--- /dev/null
+++ b/examples/get_multiple_line_values.c
@@ -0,0 +1,119 @@ 
+// 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. */
+static struct gpiod_line_request *
+request_input_lines(const char *chip_path, const unsigned int *offsets,
+		    unsigned int num_lines, const char *consumer)
+{
+	struct gpiod_request_config *req_cfg = NULL;
+	struct gpiod_line_request *request = NULL;
+	struct gpiod_line_settings *settings;
+	struct gpiod_line_config *line_cfg;
+	struct gpiod_chip *chip;
+	unsigned int i;
+	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;
+
+	for (i = 0; i < num_lines; i++) {
+		ret = gpiod_line_config_add_line_settings(line_cfg, &offsets[i],
+							  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;
+}
+
+static int print_values(const unsigned int *offsets, unsigned int num_lines,
+			enum gpiod_line_value *values)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_lines; i++) {
+		if (values[i] == GPIOD_LINE_VALUE_ACTIVE)
+			printf("%d=Active ", offsets[i]);
+		else if (values[i] == GPIOD_LINE_VALUE_INACTIVE) {
+			printf("%d=Inactive ", offsets[i]);
+		} else {
+			fprintf(stderr, "error reading value: %s\n",
+				strerror(errno));
+			return EXIT_FAILURE;
+		}
+	}
+	printf("\n");
+
+	return EXIT_SUCCESS;
+}
+
+#define NUM_LINES 3
+
+int main(void)
+{
+	/* Example configuration - customize to suit your situation. */
+	static const char *const chip_path = "/dev/gpiochip0";
+	static const unsigned int line_offsets[NUM_LINES] = { 5, 3, 7 };
+
+	struct gpiod_line_request *request;
+	enum gpiod_line_value values[NUM_LINES];
+	int ret;
+
+	request = request_input_lines(chip_path, line_offsets, NUM_LINES,
+				      "get-multiple-line-values");
+	if (!request) {
+		fprintf(stderr, "failed to request lines: %s\n",
+			strerror(errno));
+		return EXIT_FAILURE;
+	}
+
+	ret = gpiod_line_request_get_values(request, values);
+	if (ret == -1) {
+		fprintf(stderr, "failed to get values: %s\n", strerror(errno));
+		return EXIT_FAILURE;
+	}
+	ret = print_values(line_offsets, NUM_LINES, values);
+
+	return ret;
+}
diff --git a/examples/reconfigure_input_to_output.c b/examples/reconfigure_input_to_output.c
new file mode 100644
index 0000000..e8fbb1c
--- /dev/null
+++ b/examples/reconfigure_input_to_output.c
@@ -0,0 +1,152 @@ 
+// 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. */
+static struct gpiod_line_request *request_input_line(const char *chip_path,
+						     unsigned int offset,
+						     const char *consumer)
+{
+	struct gpiod_request_config *req_cfg = NULL;
+	struct gpiod_line_request *request = NULL;
+	struct gpiod_line_settings *settings;
+	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;
+}
+
+static int reconfigure_as_output_line(struct gpiod_line_request *request,
+				      unsigned int offset,
+				      enum gpiod_line_value value)
+{
+	struct gpiod_request_config *req_cfg = NULL;
+	struct gpiod_line_settings *settings;
+	struct gpiod_line_config *line_cfg;
+	int ret = -1;
+
+	settings = gpiod_line_settings_new();
+	if (!settings)
+		return -1;
+
+	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_line_config;
+
+	ret = gpiod_line_request_reconfigure_lines(request, line_cfg);
+
+	gpiod_request_config_free(req_cfg);
+
+free_line_config:
+	gpiod_line_config_free(line_cfg);
+
+free_settings:
+	gpiod_line_settings_free(settings);
+
+	return ret;
+}
+
+static const char * value_str(enum gpiod_line_value value)
+{
+	if (value == GPIOD_LINE_VALUE_ACTIVE)
+		return "Active";
+	else if (value == GPIOD_LINE_VALUE_INACTIVE) {
+		return "Inactive";
+	} else {
+		return "Unknown";
+	}
+}
+
+int main(void)
+{
+	/* Example configuration - customize to suit your situation. */
+	static const char *const chip_path = "/dev/gpiochip0";
+	static const unsigned int line_offset = 5;
+
+	struct gpiod_line_request *request;
+	enum gpiod_line_value value;
+	int ret;
+
+	/* request the line initially as an input */
+	request = request_input_line(chip_path, line_offset,
+				     "reconfigure-input-to-output");
+	if (!request) {
+		fprintf(stderr, "failed to request line: %s\n",
+			strerror(errno));
+		return EXIT_FAILURE;
+	}
+
+	/* read the current line value */
+	value = gpiod_line_request_get_value(request, line_offset);
+	printf("%d=%s (input)\n", line_offset, value_str(value));
+
+	/* switch the line to an output and drive it low */
+	ret = reconfigure_as_output_line(request, line_offset,
+					 GPIOD_LINE_VALUE_INACTIVE);
+
+	/* report the current driven value */
+	value = gpiod_line_request_get_value(request, line_offset);
+	printf("%d=%s (output)\n", line_offset, value_str(value));
+
+	/* not strictly required here, but if the app wasn't exiting... */
+	gpiod_line_request_release(request);
+
+	return ret;
+}
diff --git a/examples/toggle_multiple_line_values.c b/examples/toggle_multiple_line_values.c
new file mode 100644
index 0000000..059a79f
--- /dev/null
+++ b/examples/toggle_multiple_line_values.c
@@ -0,0 +1,136 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
+
+/* Minimal example of toggling multiple lines. */
+
+#include <errno.h>
+#include <gpiod.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static struct gpiod_line_request *
+request_output_lines(const char *chip_path, const unsigned int *offsets,
+		     enum gpiod_line_value *values, unsigned int num_lines,
+		     const char *consumer)
+{
+	struct gpiod_request_config *rconfig = NULL;
+	struct gpiod_line_request *request = NULL;
+	struct gpiod_line_settings *settings;
+	struct gpiod_line_config *lconfig;
+	struct gpiod_chip *chip;
+	unsigned int i;
+	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);
+
+	lconfig = gpiod_line_config_new();
+	if (!lconfig)
+		goto free_settings;
+
+	for (i = 0; i < num_lines; i++) {
+		ret = gpiod_line_config_add_line_settings(lconfig, &offsets[i],
+							  1, settings);
+		if (ret)
+			goto free_line_config;
+	}
+	gpiod_line_config_set_output_values(lconfig, values, num_lines);
+
+	if (consumer) {
+		rconfig = gpiod_request_config_new();
+		if (!rconfig)
+			goto free_line_config;
+
+		gpiod_request_config_set_consumer(rconfig, consumer);
+	}
+
+	request = gpiod_chip_request_lines(chip, rconfig, lconfig);
+
+	gpiod_request_config_free(rconfig);
+
+free_line_config:
+	gpiod_line_config_free(lconfig);
+
+free_settings:
+	gpiod_line_settings_free(settings);
+
+close_chip:
+	gpiod_chip_close(chip);
+
+	return request;
+}
+
+static 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;
+}
+
+static void toggle_line_values(enum gpiod_line_value *values,
+			       unsigned int num_lines)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_lines; i++) {
+		values[i] = toggle_line_value(values[i]);
+	}
+}
+
+static void print_values(const unsigned int *offsets,
+			 const enum gpiod_line_value *values,
+			 unsigned int num_lines)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_lines; i++) {
+		if (values[i] == GPIOD_LINE_VALUE_ACTIVE)
+			printf("%d=Active ", offsets[i]);
+		else
+			printf("%d=Inactive ", offsets[i]);
+	}
+	printf("\n");
+}
+
+#define NUM_LINES 3
+
+int main(void)
+{
+	/* Example configuration - customize to suit your situation. */
+	static const char *const chip_path = "/dev/gpiochip0";
+	static const unsigned int line_offsets[NUM_LINES] = { 5, 3, 7 };
+
+	enum gpiod_line_value values[NUM_LINES] = { GPIOD_LINE_VALUE_ACTIVE,
+						    GPIOD_LINE_VALUE_ACTIVE,
+						    GPIOD_LINE_VALUE_INACTIVE };
+	struct gpiod_line_request *request;
+
+	request = request_output_lines(chip_path, line_offsets, values,
+				       NUM_LINES,
+				       "toggle-multiple-line-values");
+	if (!request) {
+		fprintf(stderr, "failed to request line: %s\n",
+			strerror(errno));
+		return EXIT_FAILURE;
+	}
+
+	for (;;) {
+		print_values(line_offsets, values, NUM_LINES);
+		sleep(1);
+		toggle_line_values(values, NUM_LINES);
+		gpiod_line_request_set_values(request, values);
+	}
+
+	gpiod_line_request_release(request);
+
+	return EXIT_SUCCESS;
+}
diff --git a/examples/watch_line_info.c b/examples/watch_line_info.c
new file mode 100644
index 0000000..51fb5c7
--- /dev/null
+++ b/examples/watch_line_info.c
@@ -0,0 +1,72 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
+
+/* Minimal example of watching for info changes on particular lines. */
+
+#include <errno.h>
+#include <gpiod.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+const char *event_type(struct gpiod_info_event *event)
+{
+	switch (gpiod_info_event_get_event_type(event)) {
+	case GPIOD_INFO_EVENT_LINE_REQUESTED:
+		return "Requested";
+	case GPIOD_INFO_EVENT_LINE_RELEASED:
+		return "Released";
+	case GPIOD_INFO_EVENT_LINE_CONFIG_CHANGED:
+		return "Reconfig";
+	default:
+		return "Unknown";
+	}
+}
+
+#define NUM_LINES 3
+
+int main(void)
+{
+	/* Example configuration - customize to suit your situation. */
+	static const char *const chip_path = "/dev/gpiochip0";
+	static const unsigned int line_offsets[NUM_LINES] = { 5, 3, 7 };
+
+	struct gpiod_line_info *info;
+	struct gpiod_info_event *event;
+	struct gpiod_chip *chip;
+	unsigned int i;
+	uint64_t timestamp_ns;
+
+	chip = gpiod_chip_open(chip_path);
+	if (!chip) {
+		fprintf(stderr, "failed to open chip: %s\n", strerror(errno));
+		return EXIT_FAILURE;
+	}
+
+	for (i = 0; i < NUM_LINES; i++) {
+		info = gpiod_chip_watch_line_info(chip, line_offsets[i]);
+		if (!info) {
+			fprintf(stderr, "failed to read info: %s\n",
+				strerror(errno));
+			return EXIT_FAILURE;
+		}
+	}
+
+	for (;;) {
+		/* Blocks until an event is available. */
+		event = gpiod_chip_read_info_event(chip);
+		if (!event) {
+			fprintf(stderr, "failed to read event: %s\n",
+				strerror(errno));
+			return EXIT_FAILURE;
+		}
+
+		info = gpiod_info_event_get_line_info(event);
+		timestamp_ns = gpiod_info_event_get_timestamp_ns(event);
+		printf("line %3d: %-9s %ld.%ld\n",
+		       gpiod_line_info_get_offset(info), event_type(event),
+		       timestamp_ns / 1000000000, timestamp_ns % 1000000000);
+
+		gpiod_info_event_free(event);
+	}
+}
diff --git a/examples/watch_line_rising.c b/examples/watch_line_rising.c
new file mode 100644
index 0000000..062a46a
--- /dev/null
+++ b/examples/watch_line_rising.c
@@ -0,0 +1,129 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
+
+/* Minimal example of watching for rising 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. */
+static struct gpiod_line_request *request_input_line(const char *chip_path,
+						     unsigned int offset,
+						     const char *consumer)
+{
+	struct gpiod_request_config *req_cfg = NULL;
+	struct gpiod_line_request *request = NULL;
+	struct gpiod_line_settings *settings;
+	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_RISING);
+
+	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;
+}
+
+static const char *edge_event_type_str(struct gpiod_edge_event *event)
+{
+	switch (gpiod_edge_event_get_event_type(event)) {
+	case GPIOD_EDGE_EVENT_RISING_EDGE:
+		return "Rising";
+	case GPIOD_EDGE_EVENT_FALLING_EDGE:
+		return "Falling";
+	default:
+		return "Unknown";
+	}
+}
+
+int main(void)
+{
+	/* Example configuration - customize to suit your situation. */
+	static const char *const chip_path = "/dev/gpiochip0";
+	static const unsigned int line_offset = 5;
+
+	struct gpiod_edge_event_buffer *event_buffer;
+	struct gpiod_line_request *request;
+	struct gpiod_edge_event *event;
+	int i, ret, event_buf_size;
+
+	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;
+	}
+
+	for (;;) {
+		/* 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: %-7s  event #%ld\n",
+			       gpiod_edge_event_get_line_offset(event),
+			       edge_event_type_str(event),
+			       gpiod_edge_event_get_line_seqno(event));
+		}
+	}
+}
diff --git a/examples/watch_multiple_line_values.c b/examples/watch_multiple_line_values.c
new file mode 100644
index 0000000..6918aa6
--- /dev/null
+++ b/examples/watch_multiple_line_values.c
@@ -0,0 +1,140 @@ 
+// 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. */
+static struct gpiod_line_request *
+request_input_lines(const char *chip_path, const unsigned int *offsets,
+		    unsigned int num_lines, const char *consumer)
+{
+	struct gpiod_request_config *req_cfg = NULL;
+	struct gpiod_line_request *request = NULL;
+	struct gpiod_line_settings *settings;
+	struct gpiod_line_config *line_cfg;
+	struct gpiod_chip *chip;
+	unsigned int i;
+	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;
+
+	for (i = 0; i < num_lines; i++) {
+		ret = gpiod_line_config_add_line_settings(line_cfg, &offsets[i],
+							  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;
+}
+
+static const char *edge_event_type_str(struct gpiod_edge_event *event)
+{
+	switch (gpiod_edge_event_get_event_type(event)) {
+	case GPIOD_EDGE_EVENT_RISING_EDGE:
+		return "Rising";
+	case GPIOD_EDGE_EVENT_FALLING_EDGE:
+		return "Falling";
+	default:
+		return "Unknown";
+	}
+}
+
+#define NUM_LINES 3
+
+int main(void)
+{
+	/* Example configuration - customize to suit your situation. */
+	static const char *const chip_path = "/dev/gpiochip0";
+	static const unsigned int line_offsets[NUM_LINES] = { 5, 3, 7 };
+
+	struct gpiod_edge_event_buffer *event_buffer;
+	struct gpiod_line_request *request;
+	struct gpiod_edge_event *event;
+	int i, ret, event_buf_size;
+
+	request = request_input_lines(chip_path, line_offsets, NUM_LINES,
+				      "watch-multiple-line-values");
+	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, so even a value of 1 would be fine.
+	 * The size here allows for a simultaneous event on each of the lines
+	 * to be copied in one read.
+	 */
+	event_buf_size = NUM_LINES;
+	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;
+	}
+
+	for (;;) {
+		/* 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: %-7s  event #%ld\n",
+			       gpiod_edge_event_get_line_offset(event),
+			       edge_event_type_str(event),
+			       gpiod_edge_event_get_line_seqno(event));
+		}
+	}
+}