new file mode 100644
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/* Minimal example of finding a line with the given name. */
+
+#include <glib.h>
+#include <gpiod-glib.h>
+#include <stdlib.h>
+
+int main(void)
+{
+ /* Example configuration - customize to suit your situation. */
+ static const gchar *const line_name = "GPIO0";
+
+ g_autoptr(GPIODChipInfo) info = NULL;
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GDir) dir = NULL;
+ const gchar *filename;
+ gboolean ret;
+ guint offset;
+
+ dir = g_dir_open("/dev", 0, &err);
+ if (err) {
+ g_printerr("Unable to open /dev: %s\n", err->message);
+ return EXIT_FAILURE;
+ }
+
+ /*
+ * Names are not guaranteed unique, so this finds the first line with
+ * the given name.
+ */
+ while ((filename = g_dir_read_name(dir))) {
+ g_autoptr(GPIODChip) chip = NULL;
+ g_autofree gchar *path = NULL;
+
+ path = g_strdup_printf("/dev/%s", filename);
+ if (!g_gpiod_is_gpiochip_device(path))
+ continue;
+
+ chip = g_gpiod_chip_new(path, &err);
+ if (err) {
+ g_printerr("Failed to open the GPIO chip at '%s': %s\n",
+ path, err->message);
+ return EXIT_FAILURE;
+ }
+
+ ret = g_gpiod_chip_get_line_offset_from_name(chip, line_name,
+ &offset, &err);
+ if (!ret) {
+ g_printerr("Failed to map the line name '%s' to offset: %s\n",
+ line_name, err->message);
+ return EXIT_FAILURE;
+ }
+
+ info = g_gpiod_chip_get_info(chip, &err);
+ if (!info) {
+ g_printerr("Failed to get chip info: %s\n",
+ err->message);
+ return EXIT_FAILURE;
+ }
+
+ g_print("%s %u\n", g_gpiod_chip_info_get_name(info), offset);
+ }
+
+ g_print("line '%s' not found\n", line_name);
+
+ return EXIT_SUCCESS;
+}
new file mode 100644
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/* Minimal example of reading the info for a chip. */
+
+#include <glib.h>
+#include <gpiod-glib.h>
+#include <stdlib.h>
+
+int main(void)
+{
+ /* Example configuration - customize to suit your situation. */
+ static const gchar *const chip_path = "/dev/gpiochip0";
+
+ g_autoptr(GPIODChipInfo) info = NULL;
+ g_autoptr(GPIODChip) chip = NULL;
+ g_autoptr(GError) err = NULL;
+
+ chip = g_gpiod_chip_new(chip_path, &err);
+ if (err) {
+ g_printerr("Failed to open the GPIO chip at '%s': %s\n",
+ chip_path, err->message);
+ return EXIT_FAILURE;
+ }
+
+ info = g_gpiod_chip_get_info(chip, &err);
+ if (err) {
+ g_printerr("Failed to retrieve GPIO chip info: %s\n",
+ err->message);
+ return EXIT_FAILURE;
+ }
+
+ g_print("%s [%s] (%u lines)\n",
+ g_gpiod_chip_info_get_name(info),
+ g_gpiod_chip_info_get_label(info),
+ g_gpiod_chip_info_get_num_lines(info));
+
+ return EXIT_SUCCESS;
+}
new file mode 100644
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2022-2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/* Minimal example of reading the info for a line. */
+
+#include <glib.h>
+#include <gpiod-glib.h>
+#include <stdlib.h>
+
+static GString *make_flags(GPIODLineInfo *info)
+{
+ g_autofree gchar *drive_str = NULL;
+ g_autofree gchar *edge_str = NULL;
+ g_autofree gchar *bias_str = NULL;
+ GPIODLineDrive drive;
+ GPIODLineEdge edge;
+ GPIODLineBias bias;
+ GString *ret;
+
+ edge = g_gpiod_line_info_get_edge_detection(info);
+ bias = g_gpiod_line_info_get_bias(info);
+ drive = g_gpiod_line_info_get_drive(info);
+
+ edge_str = g_enum_to_string(G_GPIOD_LINE_EDGE_TYPE, edge);
+ bias_str = g_enum_to_string(G_GPIOD_LINE_BIAS_TYPE, bias);
+ drive_str = g_enum_to_string(G_GPIOD_LINE_DRIVE_TYPE, drive);
+
+ ret = g_string_new(NULL);
+ g_string_printf(ret, "%s, %s, %s", edge_str, bias_str, drive_str);
+ g_string_replace(ret, "G_GPIOD_LINE_", "", 0);
+
+ return ret;
+}
+
+int main(void)
+{
+ /* Example configuration - customize to suit your situation. */
+ static const gchar *const chip_path = "/dev/gpiochip0";
+ static const guint line_offset = 4;
+
+ g_autoptr(GPIODLineInfo) info = NULL;
+ g_autoptr(GPIODChip) chip = NULL;
+ g_autoptr(GString) flags = NULL;
+ const gchar *name, *consumer;
+ GPIODLineDirection direction;
+ g_autoptr(GError) err = NULL;
+ gboolean active_low;
+
+ chip = g_gpiod_chip_new(chip_path, &err);
+ if (err) {
+ g_printerr("Failed to open the GPIO chip at '%s': %s\n",
+ chip_path, err->message);
+ return EXIT_FAILURE;
+ }
+
+ info = g_gpiod_chip_get_line_info(chip, line_offset, &err);
+ if (err) {
+ g_printerr("Failed to retrieve GPIO line info: %s\n",
+ err->message);
+ return EXIT_FAILURE;
+ }
+
+ name = g_gpiod_line_info_get_name(info);
+ consumer = g_gpiod_line_info_get_consumer(info);
+ direction = g_gpiod_line_info_get_direction(info);
+ active_low = g_gpiod_line_info_is_active_low(info);
+ flags = make_flags(info);
+
+ g_print("\tline: %u %s %s %s %s [%s]\n",
+ line_offset,
+ name ?: "unnamed",
+ consumer ?: "unused",
+ direction == G_GPIOD_LINE_DIRECTION_INPUT ?
+ "input" : "output",
+ active_low ? "active-low" : "active-high",
+ flags->str);
+
+ return EXIT_SUCCESS;
+}
new file mode 100644
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/* Minimal example of reading a single line. */
+
+#include <glib.h>
+#include <gpiod-glib.h>
+#include <stdlib.h>
+
+int main(void)
+{
+ /* Example configuration - customize to suit your situation. */
+ static const gchar *const chip_path = "/dev/gpiochip1";
+ static const guint line_offset = 5;
+
+ g_autoptr(GPIODRequestConfig) req_cfg = NULL;
+ g_autoptr(GPIODLineSettings) settings = NULL;
+ g_autoptr(GPIODLineRequest) request = NULL;
+ g_autoptr(GPIODLineConfig) line_cfg = NULL;
+ g_autoptr(GArray) offsets = NULL;
+ g_autoptr(GPIODChip) chip = NULL;
+ g_autoptr(GError) err = NULL;
+ guint offset;
+ gboolean ret;
+
+ chip = g_gpiod_chip_new(chip_path, &err);
+ if (!chip) {
+ g_printerr("unable to open %s: %s\n", chip_path, err->message);
+ return EXIT_FAILURE;
+ }
+
+ offsets = g_array_new(FALSE, TRUE, sizeof(guint));
+ g_array_append_val(offsets, line_offset);
+
+ settings = g_gpiod_line_settings_new(
+ "direction", G_GPIOD_LINE_DIRECTION_INPUT,
+ NULL);
+
+ line_cfg = g_gpiod_line_config_new();
+ ret = g_gpiod_line_config_add_line_settings(line_cfg, offsets,
+ settings, &err);
+ if (!ret) {
+ g_printerr("failed to add line settings to line config: %s\n",
+ err->message);
+ return EXIT_FAILURE;
+ }
+
+ req_cfg = g_gpiod_request_config_new("consumer", "get-line-value-glib",
+ NULL);
+
+ request = g_gpiod_chip_request_lines(chip, req_cfg, line_cfg, &err);
+ if (!request) {
+ g_printerr("failed to request lines: %s\n", err->message);
+ return EXIT_FAILURE;
+ }
+
+ ret = g_gpiod_line_request_get_value(request, line_offset,
+ &offset, &err);
+ if (!ret) {
+ g_printerr("failed to read line values: %s\n", err->message);
+ return EXIT_FAILURE;
+ }
+
+ g_print("%u\n", offset);
+
+ return EXIT_SUCCESS;
+}
new file mode 100644
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/* Minimal example of reading multiple lines. */
+
+#include <glib.h>
+#include <gpiod-glib.h>
+#include <stdlib.h>
+
+int main(void)
+{
+ /* Example configuration - customize to suit your situation. */
+ static const gchar *const chip_path = "/dev/gpiochip1";
+ static const guint line_offsets[] = { 5, 3, 7 };
+ static const gsize num_lines = 3;
+
+ g_autoptr(GPIODRequestConfig) req_cfg = NULL;
+ g_autoptr(GPIODLineSettings) settings = NULL;
+ g_autoptr(GPIODLineRequest) request = NULL;
+ g_autoptr(GPIODLineConfig) line_cfg = NULL;
+ g_autoptr(GArray) offsets = NULL;
+ g_autoptr(GPIODChip) chip = NULL;
+ g_autoptr(GArray) values = NULL;
+ g_autoptr(GError) err = NULL;
+ gboolean ret;
+ guint i, j;
+
+ offsets = g_array_new(FALSE, TRUE, sizeof(guint));
+ for (i = 0; i < num_lines; i++)
+ g_array_append_val(offsets, line_offsets[i]);
+
+ chip = g_gpiod_chip_new(chip_path, &err);
+ if (!chip) {
+ g_printerr("unable to open %s: %s\n", chip_path, err->message);
+ return EXIT_FAILURE;
+ }
+
+ settings = g_gpiod_line_settings_new(
+ "direction", G_GPIOD_LINE_DIRECTION_INPUT,
+ NULL);
+
+ line_cfg = g_gpiod_line_config_new();
+ ret = g_gpiod_line_config_add_line_settings(line_cfg, offsets,
+ settings, &err);
+ if (!ret) {
+ g_printerr("failed to add line settings to line config: %s\n",
+ err->message);
+ return EXIT_FAILURE;
+ }
+
+ req_cfg = g_gpiod_request_config_new(
+ "consumer", "get-multiple-line-values", NULL);
+
+ request = g_gpiod_chip_request_lines(chip, req_cfg, line_cfg, &err);
+ if (!request) {
+ g_printerr("failed to request lines: %s\n", err->message);
+ return EXIT_FAILURE;
+ }
+
+ ret = g_gpiod_line_request_get_values_subset(request, offsets,
+ &values, &err);
+ if (!ret) {
+ g_printerr("failed to read line values: %s\n", err->message);
+ return EXIT_FAILURE;
+ }
+
+ for (j = 0; j < values->len; j++)
+ g_print("%d ", g_array_index(values, GPIODLineValue, j));
+ g_print("\n");
+
+ return EXIT_SUCCESS;
+}
new file mode 100644
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/*
+ * Example of a bi-directional line requested as input and then switched
+ * to output.
+ */
+
+#include <glib.h>
+#include <gpiod-glib.h>
+#include <stdlib.h>
+
+int main(void)
+{
+ /* Example configuration - customize to suit your situation */
+ static const gchar *const chip_path = "/dev/gpiochip1";
+ static const guint line_offset = 5;
+
+ g_autoptr(GPIODRequestConfig) req_cfg = NULL;
+ g_autoptr(GPIODLineSettings) settings = NULL;
+ g_autoptr(GPIODLineRequest) request = NULL;
+ g_autoptr(GPIODLineConfig) line_cfg = NULL;
+ g_autoptr(GArray) offsets = NULL;
+ g_autoptr(GPIODChip) chip = NULL;
+ g_autoptr(GError) err = NULL;
+ GPIODLineValue value;
+ gboolean ret;
+
+ offsets = g_array_new(FALSE, TRUE, sizeof(guint));
+ g_array_append_val(offsets, line_offset);
+
+ chip = g_gpiod_chip_new(chip_path, &err);
+ if (!chip) {
+ g_printerr("unable to open %s: %s\n", chip_path, err->message);
+ return EXIT_FAILURE;
+ }
+
+ settings = g_gpiod_line_settings_new(
+ "direction", G_GPIOD_LINE_DIRECTION_INPUT,
+ NULL);
+
+ line_cfg = g_gpiod_line_config_new();
+ ret = g_gpiod_line_config_add_line_settings(line_cfg, offsets,
+ settings, &err);
+ if (!ret) {
+ g_printerr("failed to add line settings to line config: %s\n",
+ err->message);
+ return EXIT_FAILURE;
+ }
+
+ req_cfg = g_gpiod_request_config_new(
+ "consumer", "reconfigure-input-to-output", NULL);
+
+ request = g_gpiod_chip_request_lines(chip, req_cfg, line_cfg, &err);
+ if (!request) {
+ g_printerr("failed to request lines: %s\n", err->message);
+ return EXIT_FAILURE;
+ }
+
+ /* Read the current line value. */
+ ret = g_gpiod_line_request_get_value(request, line_offset,
+ &value, &err);
+ if (!ret) {
+ g_printerr("failed to read line value: %s\n", err->message);
+ return EXIT_FAILURE;
+ }
+
+ g_print("%s (input)\n",
+ value == G_GPIOD_LINE_VALUE_ACTIVE ? "Active" : "Inactive");
+
+ /* Switch the line to an output and drive it high. */
+ g_gpiod_line_settings_set_direction(settings,
+ G_GPIOD_LINE_DIRECTION_OUTPUT);
+ g_gpiod_line_settings_set_output_value(settings,
+ G_GPIOD_LINE_VALUE_ACTIVE);
+ ret = g_gpiod_line_config_add_line_settings(line_cfg, offsets,
+ settings, &err);
+ if (!ret) {
+ g_printerr("failed to add line settings to line config: %s\n",
+ err->message);
+ return EXIT_FAILURE;
+ }
+
+ /* Reconfigure lines. */
+ ret = g_gpiod_line_request_reconfigure_lines(request, line_cfg, &err);
+ if (!ret) {
+ g_printerr("failed to reconfigure lines: %s\n", err->message);
+ return EXIT_FAILURE;
+ }
+
+ /* Report the current driven value. */
+ ret = g_gpiod_line_request_get_value(request, line_offset,
+ &value, &err);
+ if (!ret) {
+ g_printerr("failed to read line value: %s\n", err->message);
+ return EXIT_FAILURE;
+ }
+
+ g_print("%s (output)\n",
+ value == G_GPIOD_LINE_VALUE_ACTIVE ? "Active" : "Inactive");
+
+ return EXIT_SUCCESS;
+}
new file mode 100644
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/* Minimal example of periodically toggling a single line. */
+
+#include <glib.h>
+#include <gpiod-glib.h>
+#include <stdlib.h>
+
+typedef struct {
+ GPIODLineRequest *request;
+ guint line_offset;
+ GPIODLineValue value;
+} ToggleData;
+
+static gboolean toggle_line(gpointer user_data)
+{
+ ToggleData *data = user_data;
+ g_autoptr(GError) err = NULL;
+ gboolean ret;
+
+ data->value = data->value == G_GPIOD_LINE_VALUE_ACTIVE ?
+ G_GPIOD_LINE_VALUE_INACTIVE :
+ G_GPIOD_LINE_VALUE_ACTIVE;
+
+ ret = g_gpiod_line_request_set_value(data->request, data->line_offset,
+ data->value, &err);
+ if (!ret) {
+ g_printerr("failed to set line value: %s\n", err->message);
+ exit(EXIT_FAILURE);
+ }
+
+ g_print("%u=%s\n",
+ data->line_offset,
+ data->value == G_GPIOD_LINE_VALUE_ACTIVE ?
+ "active" : "inactive");
+
+ return G_SOURCE_CONTINUE;
+}
+
+int main(void)
+{
+ /* Example configuration - customize to suit your situation. */
+ static const gchar *const chip_path = "/dev/gpiochip1";
+ static const guint line_offset = 5;
+
+ g_autoptr(GPIODRequestConfig) req_cfg = NULL;
+ g_autoptr(GPIODLineSettings) settings = NULL;
+ g_autoptr(GPIODLineRequest) request = NULL;
+ g_autoptr(GPIODLineConfig) line_cfg = NULL;
+ g_autoptr(GArray) offsets = NULL;
+ g_autoptr(GPIODChip) chip = NULL;
+ g_autoptr(GMainLoop) loop = NULL;
+ g_autoptr(GError) err = NULL;
+ ToggleData data;
+ gboolean ret;
+
+ offsets = g_array_new(FALSE, TRUE, sizeof(guint));
+ g_array_append_val(offsets, line_offset);
+
+ chip = g_gpiod_chip_new(chip_path, &err);
+ if (!chip) {
+ g_printerr("unable to open %s: %s\n", chip_path, err->message);
+ return EXIT_FAILURE;
+ }
+
+ settings = g_gpiod_line_settings_new(
+ "direction", G_GPIOD_LINE_DIRECTION_OUTPUT,
+ NULL);
+ line_cfg = g_gpiod_line_config_new();
+ ret = g_gpiod_line_config_add_line_settings(line_cfg, offsets,
+ settings, &err);
+ if (!ret) {
+ g_printerr("failed to add line settings to line config: %s\n",
+ err->message);
+ return EXIT_FAILURE;
+ }
+
+ req_cfg = g_gpiod_request_config_new("consumer", "toggle-line-value",
+ NULL);
+
+ request = g_gpiod_chip_request_lines(chip, req_cfg, line_cfg, &err);
+ if (!request) {
+ g_printerr("failed to request lines: %s\n", err->message);
+ return EXIT_FAILURE;
+ }
+
+ data.request = request;
+ data.line_offset = line_offset;
+ data.value = G_GPIOD_LINE_VALUE_INACTIVE;
+
+ loop = g_main_loop_new(NULL, FALSE);
+ /* Do the GLib way: add a callback to be invoked from the main loop. */
+ g_timeout_add_seconds(1, toggle_line, &data);
+
+ g_main_loop_run(loop);
+
+ return EXIT_SUCCESS;
+}
new file mode 100644
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/* Minimal example of periodically toggling multiple lines. */
+
+#include <glib.h>
+#include <gpiod-glib.h>
+#include <stdlib.h>
+
+typedef struct {
+ GPIODLineRequest *request;
+ GArray *offsets;
+ GArray *values;
+} ToggleData;
+
+static void toggle_values(GArray *values)
+{
+ GPIODLineValue *value;
+ guint i;
+
+ for (i = 0; i < values->len; i++) {
+ value = &g_array_index(values, GPIODLineValue, i);
+ *value = *value == G_GPIOD_LINE_VALUE_ACTIVE ?
+ G_GPIOD_LINE_VALUE_INACTIVE :
+ G_GPIOD_LINE_VALUE_ACTIVE;
+ }
+}
+
+static gboolean toggle_lines(gpointer user_data)
+{
+ ToggleData *data = user_data;
+ g_autoptr(GError) err = NULL;
+ gboolean ret;
+ guint i;
+
+ toggle_values(data->values);
+
+ ret = g_gpiod_line_request_set_values_subset(data->request,
+ data->offsets,
+ data->values, &err);
+ if (!ret) {
+ g_printerr("failed to set line values: %s\n", err->message);
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < data->offsets->len; i++)
+ g_print("%u=%s ",
+ g_array_index(data->offsets, guint, i),
+ g_array_index(data->values,
+ GPIODLineValue,
+ i) == G_GPIOD_LINE_VALUE_ACTIVE ?
+ "active" : "inactive");
+ g_print("\n");
+
+ return G_SOURCE_CONTINUE;
+}
+
+int main(void)
+{
+ /* Example configuration - customize to suit your situation. */
+ static const gchar *const chip_path = "/dev/gpiochip1";
+ static const guint line_offsets[] = { 5, 3, 7 };
+ static const GPIODLineValue line_values[] = {
+ G_GPIOD_LINE_VALUE_ACTIVE,
+ G_GPIOD_LINE_VALUE_ACTIVE,
+ G_GPIOD_LINE_VALUE_INACTIVE
+ };
+ static const gsize num_lines = 3;
+
+ g_autoptr(GPIODRequestConfig) req_cfg = NULL;
+ g_autoptr(GPIODLineSettings) settings = NULL;
+ g_autoptr(GPIODLineRequest) request = NULL;
+ g_autoptr(GPIODLineConfig) line_cfg = NULL;
+ g_autoptr(GArray) offsets = NULL;
+ g_autoptr(GPIODChip) chip = NULL;
+ g_autoptr(GMainLoop) loop = NULL;
+ g_autoptr(GArray) values = NULL;
+ g_autoptr(GError) err = NULL;
+ ToggleData data;
+ gboolean ret;
+
+ offsets = g_array_new(FALSE, TRUE, sizeof(guint));
+ g_array_append_vals(offsets, line_offsets, num_lines);
+
+ values = g_array_new(FALSE, TRUE, sizeof(GPIODLineValue));
+ g_array_append_vals(values, line_values, num_lines);
+
+ chip = g_gpiod_chip_new(chip_path, &err);
+ if (!chip) {
+ g_printerr("unable to open %s: %s\n", chip_path, err->message);
+ return EXIT_FAILURE;
+ }
+
+ settings = g_gpiod_line_settings_new(
+ "direction", G_GPIOD_LINE_DIRECTION_OUTPUT,
+ NULL);
+ line_cfg = g_gpiod_line_config_new();
+ ret = g_gpiod_line_config_add_line_settings(line_cfg, offsets,
+ settings, &err);
+ if (!ret) {
+ g_printerr("failed to add line settings to line config: %s\n",
+ err->message);
+ return EXIT_FAILURE;
+ }
+
+ ret = g_gpiod_line_config_set_output_values(line_cfg, values, &err);
+ if (!ret) {
+ g_printerr("failed to set output values: %s\n", err->message);
+ return EXIT_FAILURE;
+ }
+
+ req_cfg = g_gpiod_request_config_new("consumer", "toggle-line-value",
+ NULL);
+
+ request = g_gpiod_chip_request_lines(chip, req_cfg, line_cfg, &err);
+ if (!request) {
+ g_printerr("failed to request lines: %s\n", err->message);
+ return EXIT_FAILURE;
+ }
+
+ data.request = request;
+ data.offsets = offsets;
+ data.values = values;
+
+ loop = g_main_loop_new(NULL, FALSE);
+ /* Do the GLib way: add a callback to be invoked from the main loop. */
+ g_timeout_add_seconds(1, toggle_lines, &data);
+
+ g_main_loop_run(loop);
+
+ return EXIT_SUCCESS;
+}
new file mode 100644
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/* Minimal example of watching for requests on particular lines. */
+
+#include <glib.h>
+#include <gpiod-glib.h>
+#include <stdlib.h>
+
+static void on_info_event(GPIODChip *chip G_GNUC_UNUSED,
+ GPIODInfoEvent *event,
+ gpointer data G_GNUC_UNUSED)
+{
+ g_autoptr(GPIODLineInfo) info = NULL;
+ g_autoptr(GString) event_name = NULL;
+ guint offset;
+
+ event_name = g_string_new(
+ g_enum_to_string(G_GPIOD_INFO_EVENT_TYPE_TYPE,
+ g_gpiod_info_event_get_event_type(event)));
+ g_string_replace(event_name, "G_GPIOD_INFO_EVENT_LINE_", "", 0);
+ info = g_gpiod_info_event_get_line_info(event);
+ offset = g_gpiod_line_info_get_offset(info);
+
+ g_print("%s %u\n", event_name->str, offset);
+}
+
+int main(void)
+{
+ static const gchar *const chip_path = "/dev/gpiochip1";
+ static const guint line_offsets[] = { 5, 3, 7 };
+ static const gsize num_lines = 3;
+
+ g_autoptr(GMainLoop) loop = NULL;
+ g_autoptr(GPIODChip) chip = NULL;
+ g_autoptr(GError) err = NULL;
+ guint i;
+
+ chip = g_gpiod_chip_new(chip_path, &err);
+ if (!chip) {
+ g_printerr("unable to open %s: %s\n", chip_path, err->message);
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < num_lines; i++) {
+ g_autoptr(GPIODLineInfo) info =
+ g_gpiod_chip_watch_line_info(chip, line_offsets[i],
+ &err);
+ if (!info) {
+ g_printerr("unable to watch line info for offset %u: %s",
+ line_offsets[1], err->message);
+ return EXIT_FAILURE;
+ }
+ }
+
+ loop = g_main_loop_new(NULL, FALSE);
+
+ g_signal_connect(chip, "info-event", G_CALLBACK(on_info_event), NULL);
+
+ g_main_loop_run(loop);
+
+ return EXIT_SUCCESS;
+}
new file mode 100644
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/* Minimal example of asynchronously watching for edges on a single line. */
+
+#include <glib.h>
+#include <gpiod-glib.h>
+#include <stdlib.h>
+
+static void on_edge_event(GPIODLineRequest *request G_GNUC_UNUSED,
+ GPIODEdgeEvent *event,
+ gpointer data G_GNUC_UNUSED)
+{
+ g_autoptr(GString) event_name = NULL;
+ guint64 timestamp;
+ guint offset;
+
+ event_name = g_string_new(
+ g_enum_to_string(G_GPIOD_EDGE_EVENT_TYPE_TYPE,
+ g_gpiod_edge_event_get_event_type(event)));
+ g_string_replace(event_name, "G_GPIOD_EDGE_EVENT_", "", 0);
+ timestamp = g_gpiod_edge_event_get_timestamp_ns(event);
+ offset = g_gpiod_edge_event_get_line_offset(event);
+
+ g_print("%s %lu %u\n", event_name->str, timestamp, offset);
+}
+
+int main(void)
+{
+ /* Example configuration - customize to suit your situation. */
+ static const gchar *const chip_path = "/dev/gpiochip1";
+ static const guint line_offset = 5;
+
+ g_autoptr(GPIODRequestConfig) req_cfg = NULL;
+ g_autoptr(GPIODLineSettings) settings = NULL;
+ g_autoptr(GPIODLineRequest) request = NULL;
+ g_autoptr(GPIODLineConfig) line_cfg = NULL;
+ g_autoptr(GArray) offsets = NULL;
+ g_autoptr(GMainLoop) loop = NULL;
+ g_autoptr(GPIODChip) chip = NULL;
+ g_autoptr(GError) err = NULL;
+ gboolean ret;
+
+ offsets = g_array_new(FALSE, TRUE, sizeof(guint));
+ g_array_append_val(offsets, line_offset);
+
+ chip = g_gpiod_chip_new(chip_path, &err);
+ if (!chip) {
+ g_printerr("unable to open %s: %s\n", chip_path, err->message);
+ return EXIT_FAILURE;
+ }
+
+ /*
+ * Assume a button connecting the pin to ground, so pull it up and
+ * provide some debounce.
+ */
+ settings = g_gpiod_line_settings_new(
+ "direction", G_GPIOD_LINE_DIRECTION_INPUT,
+ "edge-detection", G_GPIOD_LINE_EDGE_BOTH,
+ "bias", G_GPIOD_LINE_BIAS_PULL_UP,
+ "debounce-period-us", 1000,
+ NULL);
+
+ line_cfg = g_gpiod_line_config_new();
+ ret = g_gpiod_line_config_add_line_settings(line_cfg, offsets,
+ settings, &err);
+ if (!ret) {
+ g_printerr("failed to add line settings to line config: %s",
+ err->message);
+ return EXIT_FAILURE;
+ }
+
+ req_cfg = g_gpiod_request_config_new("consumer", "watch-line-value",
+ NULL);
+
+ request = g_gpiod_chip_request_lines(chip, req_cfg, line_cfg, &err);
+ if (!request) {
+ g_printerr("failed to request lines: %s", err->message);
+ return EXIT_FAILURE;
+ }
+
+ loop = g_main_loop_new(NULL, FALSE);
+
+ /* Connect to the edge-event signal on the line-request. */
+ g_signal_connect(request, "edge-event",
+ G_CALLBACK(on_edge_event), NULL);
+
+ g_main_loop_run(loop);
+
+ return EXIT_SUCCESS;
+}
new file mode 100644
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/*
+ * Minimal example of asynchronously watching for rising edges on multiple
+ * lines.
+ */
+
+#include <glib.h>
+#include <gpiod-glib.h>
+#include <stdlib.h>
+
+static void on_edge_event(GPIODLineRequest *request G_GNUC_UNUSED,
+ GPIODEdgeEvent *event,
+ gpointer data G_GNUC_UNUSED)
+{
+ g_autoptr(GString) event_name = NULL;
+ guint64 timestamp;
+ guint offset;
+
+ event_name = g_string_new(
+ g_enum_to_string(G_GPIOD_EDGE_EVENT_TYPE_TYPE,
+ g_gpiod_edge_event_get_event_type(event)));
+ g_string_replace(event_name, "G_GPIOD_EDGE_EVENT_", "", 0);
+ timestamp = g_gpiod_edge_event_get_timestamp_ns(event);
+ offset = g_gpiod_edge_event_get_line_offset(event);
+
+ g_print("%s %lu %u\n", event_name->str, timestamp, offset);
+}
+
+int main(void)
+{
+ /* Example configuration - customize to suit your situation. */
+ static const gchar *const chip_path = "/dev/gpiochip1";
+ static const guint line_offsets[] = { 5, 3, 7 };
+ static const gsize num_lines = 3;
+
+ g_autoptr(GPIODRequestConfig) req_cfg = NULL;
+ g_autoptr(GPIODLineSettings) settings = NULL;
+ g_autoptr(GPIODLineRequest) request = NULL;
+ g_autoptr(GPIODLineConfig) line_cfg = NULL;
+ g_autoptr(GArray) offsets = NULL;
+ g_autoptr(GMainLoop) loop = NULL;
+ g_autoptr(GPIODChip) chip = NULL;
+ g_autoptr(GError) err = NULL;
+ gboolean ret;
+
+ offsets = g_array_new(FALSE, TRUE, sizeof(guint));
+ g_array_append_vals(offsets, line_offsets, num_lines);
+
+ chip = g_gpiod_chip_new(chip_path, &err);
+ if (!chip) {
+ g_printerr("unable to open %s: %s\n", chip_path, err->message);
+ return EXIT_FAILURE;
+ }
+
+ /*
+ * Assume a button connecting the pin to ground, so pull it up and
+ * provide some debounce.
+ */
+ settings = g_gpiod_line_settings_new(
+ "direction", G_GPIOD_LINE_DIRECTION_INPUT,
+ "edge-detection", G_GPIOD_LINE_EDGE_RISING,
+ "bias", G_GPIOD_LINE_BIAS_PULL_UP,
+ "debounce-period-us", 1000,
+ NULL);
+
+ line_cfg = g_gpiod_line_config_new();
+ ret = g_gpiod_line_config_add_line_settings(line_cfg, offsets,
+ settings, &err);
+ if (!ret) {
+ g_printerr("failed to add line settings to line config: %s",
+ err->message);
+ return EXIT_FAILURE;
+ }
+
+ req_cfg = g_gpiod_request_config_new(NULL);
+ g_gpiod_request_config_set_consumer(req_cfg, "watch-multiline-value");
+
+ request = g_gpiod_chip_request_lines(chip, req_cfg, line_cfg, &err);
+ if (!request) {
+ g_printerr("failed to request lines: %s", err->message);
+ return EXIT_FAILURE;
+ }
+
+ loop = g_main_loop_new(NULL, FALSE);
+
+ /* Connect to the edge-event signal on the line-request. */
+ g_signal_connect(request, "edge-event",
+ G_CALLBACK(on_edge_event), NULL);
+
+ g_main_loop_run(loop);
+
+ return EXIT_SUCCESS;
+}