From: Gerhard Sittig Date: Sat, 23 May 2020 11:10:14 +0000 (+0200) Subject: accept multiple --config requests for multiple channel groups X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=6c94f0c1cd6cf6c146851e4e87b9e31b1b17d41d;p=sigrok-cli.git accept multiple --config requests for multiple channel groups The previous UI implementation supported the selection of a channel group, and defaulted to the device's global options. This let users either manipulate global or a single channel group's parmeters. Extend the user interface. Accept multiple -c specs. Apply the remaining key-value pairs to the channel group which optionally can get specified in the first item of a -c spec. This lets users modify several channel groups' parameters in a single program invocation, including arbitrary combinations including the device's global parameters. This extension is completely backwards compatible. When a -c spec lacks a 'channel_group=' item, then the -g spec is used, which defaults to the global parameters. Either an empty string or the 'global' literal can be used to select the global parameters. Several -c specs can select the same channel group. This can be useful when command lines get generated by other programs. --- diff --git a/device.c b/device.c index 141e3cf..7da7444 100644 --- a/device.c +++ b/device.c @@ -66,22 +66,31 @@ GSList *device_scan(void) /** * Lookup a channel group from its name. * - * Uses the previously stored option value to lookup a channel group. - * Returns a reference to the channel group when the lookup succeeded, - * or #NULL after lookup failure, or #NULL for the global channel group - * (the device's global parameters). Emits an error message when the - * lookup failed while a channel group's name was specified. + * Uses the caller specified channel group name, or a previously stored + * option value as a fallback. Returns a reference to the channel group + * when the lookup succeeded, or #NULL after lookup failure, as well as + * #NULL for the global channel group (the device). + * + * Accepts either #NULL pointer, or an empty string, or the "global" + * literal to address the global channel group (the device). Emits an + * error message when the lookup failed while a name was specified. * * @param[in] sdi Device instance. + * @param[in] cg_name Caller provided channel group name. * * @returns The channel group, or #NULL for failed lookup. */ -struct sr_channel_group *lookup_channel_group(struct sr_dev_inst *sdi) +struct sr_channel_group *lookup_channel_group(struct sr_dev_inst *sdi, + const char *cg_name) { struct sr_channel_group *cg; GSList *l, *channel_groups; - if (!opt_channel_group) + if (!cg_name) + cg_name = opt_channel_group; + if (cg_name && g_ascii_strcasecmp(cg_name, "global") == 0) + cg_name = NULL; + if (!cg_name || !*cg_name) return NULL; channel_groups = sr_dev_inst_channel_groups_get(sdi); @@ -92,11 +101,11 @@ struct sr_channel_group *lookup_channel_group(struct sr_dev_inst *sdi) for (l = channel_groups; l; l = l->next) { cg = l->data; - if (g_ascii_strcasecmp(opt_channel_group, cg->name) != 0) + if (g_ascii_strcasecmp(cg_name, cg->name) != 0) continue; return cg; } - g_critical("Invalid channel group '%s'", opt_channel_group); + g_critical("Invalid channel group '%s'", cg_name); return NULL; } diff --git a/main.c b/main.c index db2bdc0..1de4b16 100644 --- a/main.c +++ b/main.c @@ -113,7 +113,6 @@ static void get_option(void) const struct sr_key_info *ci; GSList *devices; GVariant *gvar; - GHashTable *devargs; int ret; char *s; struct sr_dev_driver *driver; @@ -136,14 +135,11 @@ static void get_option(void) return; } - cg = lookup_channel_group(sdi); + cg = lookup_channel_group(sdi, NULL); if (!(ci = sr_key_info_name_get(SR_KEY_CONFIG, opt_get))) g_critical("Unknown option '%s'", opt_get); - if ((devargs = parse_generic_arg(opt_config, FALSE, NULL))) - set_dev_options(sdi, devargs); - else - devargs = NULL; + set_dev_options_array(sdi, opt_configs); if ((ret = maybe_config_get(driver, sdi, cg, ci->key, &gvar)) != SR_OK) g_critical("Failed to get '%s': %s", opt_get, sr_strerror(ret)); @@ -171,24 +167,18 @@ static void get_option(void) g_variant_unref(gvar); sr_dev_close(sdi); - if (devargs) - g_hash_table_destroy(devargs); } static void set_options(void) { struct sr_dev_inst *sdi; GSList *devices; - GHashTable *devargs; - if (!opt_config) { + if (!opt_configs) { g_critical("No setting specified."); return; } - if (!(devargs = parse_generic_arg(opt_config, FALSE, NULL))) - return; - if (!(devices = device_scan())) { g_critical("No devices found."); return; @@ -201,11 +191,9 @@ static void set_options(void) return; } - set_dev_options(sdi, devargs); + set_dev_options_array(sdi, opt_configs); sr_dev_close(sdi); - g_hash_table_destroy(devargs); - } int main(int argc, char **argv) diff --git a/options.c b/options.c index ebd620d..8d17e33 100644 --- a/options.c +++ b/options.c @@ -31,7 +31,7 @@ gboolean opt_wait_trigger = FALSE; gchar *opt_input_file = NULL; gchar *opt_output_file = NULL; gchar *opt_drv = NULL; -gchar *opt_config = NULL; +gchar **opt_configs = NULL; gchar *opt_channels = NULL; gchar *opt_channel_group = NULL; gchar *opt_triggers = NULL; @@ -79,7 +79,6 @@ static gboolean check_ ## option \ } CHECK_ONCE(opt_drv) -CHECK_ONCE(opt_config) CHECK_ONCE(opt_input_format) CHECK_ONCE(opt_output_format) CHECK_ONCE(opt_transform_module) @@ -112,7 +111,7 @@ static const GOptionEntry optargs[] = { "Set loglevel (5 is most verbose)", NULL}, {"driver", 'd', 0, G_OPTION_ARG_CALLBACK, &check_opt_drv, "The driver to use", NULL}, - {"config", 'c', 0, G_OPTION_ARG_CALLBACK, &check_opt_config, + {"config", 'c', 0, G_OPTION_ARG_STRING_ARRAY, &opt_configs, "Specify device configuration options", NULL}, {"input-file", 'i', 0, G_OPTION_ARG_FILENAME_ARRAY, &input_file_array, "Load input from file", NULL}, diff --git a/session.c b/session.c index 56a4d25..0e426cd 100644 --- a/session.c +++ b/session.c @@ -654,19 +654,51 @@ int opt_to_gvar(char *key, char *value, struct sr_config *src) return ret; } +int set_dev_options_array(struct sr_dev_inst *sdi, char **opts) +{ + size_t opt_idx; + const char *opt_text; + GHashTable *args; + int ret; + + for (opt_idx = 0; opts && opts[opt_idx]; opt_idx++) { + opt_text = opts[opt_idx]; + args = parse_generic_arg(opt_text, FALSE, "channel_group"); + if (!args) + continue; + ret = set_dev_options(sdi, args); + g_hash_table_destroy(args); + if (ret != SR_OK) + return ret; + } + + return SR_OK; +} + int set_dev_options(struct sr_dev_inst *sdi, GHashTable *args) { struct sr_config src; + const char *cg_name; struct sr_channel_group *cg; GHashTableIter iter; gpointer key, value; int ret; + /* + * Not finding the 'sigrok_key' key (optional user specified + * channel group name) in the current options group's hash table + * is perfectly fine. In that case the -g selection is used, + * which defaults to "the device" (global parameters). + */ + cg_name = g_hash_table_lookup(args, "sigrok_key"); + cg = lookup_channel_group(sdi, cg_name); + g_hash_table_iter_init(&iter, args); while (g_hash_table_iter_next(&iter, &key, &value)) { + if (g_ascii_strcasecmp(key, "sigrok_key") == 0) + continue; if ((ret = opt_to_gvar(key, value, &src)) != 0) return ret; - cg = lookup_channel_group(sdi); if ((ret = maybe_config_set(sr_dev_inst_driver_get(sdi), sdi, cg, src.key, src.data)) != SR_OK) { g_critical("Failed to set device option '%s': %s.", @@ -682,7 +714,6 @@ void run_session(void) { struct df_arg_desc df_arg; GSList *devices, *real_devices, *sd; - GHashTable *devargs; GVariant *gvar; struct sr_session *session; struct sr_trigger *trigger; @@ -765,12 +796,9 @@ void run_session(void) return; } - if (opt_config) { - if ((devargs = parse_generic_arg(opt_config, FALSE, NULL))) { - if (set_dev_options(sdi, devargs) != SR_OK) - return; - g_hash_table_destroy(devargs); - } + if (opt_configs) { + if (set_dev_options_array(sdi, opt_configs) != SR_OK) + return; } if (select_channels(sdi) != SR_OK) { diff --git a/show.c b/show.c index a6573e5..5c35bb3 100644 --- a/show.c +++ b/show.c @@ -441,7 +441,7 @@ void show_dev_detail(void) * returned, or which values for them. */ select_channels(sdi); - channel_group = lookup_channel_group(sdi); + channel_group = lookup_channel_group(sdi, NULL); if (!(opts = sr_dev_options(driver, sdi, channel_group))) /* Driver supports no device instance options. */ diff --git a/sigrok-cli.h b/sigrok-cli.h index b5603c3..51ce454 100644 --- a/sigrok-cli.h +++ b/sigrok-cli.h @@ -56,7 +56,8 @@ void show_serial_ports(void); /* device.c */ GSList *device_scan(void); -struct sr_channel_group *lookup_channel_group(struct sr_dev_inst *sdi); +struct sr_channel_group *lookup_channel_group(struct sr_dev_inst *sdi, + const char *cg_name); /* session.c */ struct df_arg_desc { @@ -76,6 +77,7 @@ struct df_arg_desc { void datafeed_in(const struct sr_dev_inst *sdi, const struct sr_datafeed_packet *packet, void *cb_data); int opt_to_gvar(char *key, char *value, struct sr_config *src); +int set_dev_options_array(struct sr_dev_inst *sdi, char **opts); int set_dev_options(struct sr_dev_inst *sdi, GHashTable *args); void run_session(void); @@ -129,7 +131,7 @@ extern gboolean opt_wait_trigger; extern gchar *opt_input_file; extern gchar *opt_output_file; extern gchar *opt_drv; -extern gchar *opt_config; +extern gchar **opt_configs; extern gchar *opt_channels; extern gchar *opt_channel_group; extern gchar *opt_triggers;