// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-FileCopyrightText: 2024 Bartosz Golaszewski #include #include "common.h" static void free_str(gpointer data) { GString *str = data; g_string_free(str, TRUE); } int gpiocli_set_main(int argc, char **argv) { static const gchar *const summary = "Set values of one or more GPIO lines."; static const gchar *const description = "If -r/--request is specified then all the lines must belong to the same\n" "request (and - by extension - the same chip)."; const gchar *request_name = NULL, *chip_path, *req_path; g_autoptr(GpiodbusObject) chip_obj = NULL; g_autoptr(GpiodbusObject) req_obj = NULL; g_autoptr(GPtrArray) line_names = NULL; g_autoptr(GArray) values = NULL; g_autoptr(GError) err = NULL; g_auto(GStrv) lines = NULL; GpiodbusRequest *request; GVariantBuilder builder; GpiodbusLine *line; gsize num_lines, i; GString *line_name; gboolean ret; guint offset; gint val; const GOptionEntry opts[] = { { .long_name = "request", .short_name = 'r', .flags = G_OPTION_FLAG_NONE, .arg = G_OPTION_ARG_STRING, .arg_data = &request_name, .description = "restrict scope to a particular request", .arg_description = "", }, { .long_name = G_OPTION_REMAINING, .flags = G_OPTION_FLAG_NONE, .arg = G_OPTION_ARG_STRING_ARRAY, .arg_data = &lines, .arg_description = " [line2=value2] ...", }, { } }; parse_options(opts, summary, description, &argc, &argv); if (!lines) die_parsing_opts("at least one line value must be specified"); num_lines = g_strv_length(lines); line_names = g_ptr_array_new_full(num_lines, free_str); values = g_array_sized_new(FALSE, TRUE, sizeof(gint), num_lines); for (i = 0; i < num_lines; i++) { g_auto(GStrv) tokens = NULL; tokens = g_strsplit(lines[i], "=", 2); if (g_strv_length(tokens) != 2) die_parsing_opts("line must have a single value assigned"); g_ptr_array_add(line_names, g_string_new(tokens[0])); val = output_value_from_str(tokens[1]); g_array_append_val(values, val); } check_manager(); if (request_name) { g_autoptr(GVariant) arg_values = NULL; g_autoptr(GArray) offsets = NULL; req_obj = get_request_obj(request_name); request = gpiodbus_object_peek_request(req_obj); chip_path = gpiodbus_request_get_chip_path(request); chip_obj = get_chip_obj_by_path(chip_path); offsets = g_array_sized_new(FALSE, TRUE, sizeof(guint), num_lines); for (i = 0; i < num_lines; i++) { g_autoptr(GpiodbusObject) line_obj = NULL; line_name = g_ptr_array_index(line_names, i); line_obj = get_line_obj_by_name_for_chip(chip_obj, line_name->str); if (!line_obj) die("Line not found: %s\n", line_name->str); line = gpiodbus_object_peek_line(line_obj); offset = gpiodbus_line_get_offset(line); g_array_append_val(offsets, offset); } g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); for (i = 0; i < num_lines; i++) { g_variant_builder_add(&builder, "{ui}", g_array_index(offsets, guint, i), g_array_index(values, gint, i)); } arg_values = g_variant_ref_sink( g_variant_builder_end(&builder)); ret = gpiodbus_request_call_set_values_sync( request, arg_values, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err); if (!ret) die_gerror(err, "Failed to set line values"); return EXIT_SUCCESS; } for (i = 0; i < num_lines; i++) { g_autoptr(GpiodbusRequest) req_proxy = NULL; g_autoptr(GpiodbusObject) line_obj = NULL; g_autoptr(GVariant) arg_values = NULL; line_name = g_ptr_array_index(line_names, i); ret = get_line_obj_by_name(line_name->str, &line_obj, NULL); if (!ret) die("Line not found: %s\n", line_name->str); line = gpiodbus_object_peek_line(line_obj); req_path = gpiodbus_line_get_request_path(line); if (!gpiodbus_line_get_managed(line)) die("Line '%s' not managed by gpio-manager, must be requested first", line_name->str); req_proxy = gpiodbus_request_proxy_new_for_bus_sync( G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, "io.gpiod1", req_path, NULL, &err); if (err) die_gerror(err, "Failed to get D-Bus proxy for '%s'", req_path); offset = gpiodbus_line_get_offset(line); g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); g_variant_builder_add(&builder, "{ui}", offset, g_array_index(values, gint, i)); arg_values = g_variant_ref_sink( g_variant_builder_end(&builder)); ret = gpiodbus_request_call_set_values_sync( req_proxy, arg_values, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err); if (!ret) die_gerror(err, "Failed to set line values"); } return EXIT_SUCCESS; }