X-Git-Url: https://sigrok.org/gitweb/?p=sigrok-cli.git;a=blobdiff_plain;f=sigrok-cli.c;h=aaf0c3633530777cdd0a62178c7fa0f2297838f8;hp=87b421c91b3e3637dfbf24e14d9731516078e0c3;hb=478a782d1c7aa2da82e144671dc9feb89729b333;hpb=3a999920eb5fa7edd95b9a67b58cdbd653f52f5a diff --git a/sigrok-cli.c b/sigrok-cli.c index 87b421c..aaf0c36 100644 --- a/sigrok-cli.c +++ b/sigrok-cli.c @@ -43,7 +43,7 @@ static struct sr_output_format *output_format = NULL; static int default_output_format = FALSE; static char *output_format_param = NULL; static char *input_format_param = NULL; -static GData *pd_ann_visible = NULL; +static GHashTable *pd_ann_visible = NULL; static gboolean opt_version = FALSE; static gint opt_loglevel = SR_LOG_WARN; /* Show errors+warnings per default. */ @@ -56,6 +56,7 @@ static gchar *opt_probes = NULL; static gchar *opt_triggers = NULL; static gchar *opt_pds = NULL; static gchar *opt_pd_stack = NULL; +static gchar *opt_pd_annotations = NULL; static gchar *opt_input_format = NULL; static gchar *opt_output_format = NULL; static gchar *opt_time = NULL; @@ -63,22 +64,40 @@ static gchar *opt_samples = NULL; static gchar *opt_continuous = NULL; static GOptionEntry optargs[] = { - {"version", 'V', 0, G_OPTION_ARG_NONE, &opt_version, "Show version and support list", NULL}, - {"loglevel", 'l', 0, G_OPTION_ARG_INT, &opt_loglevel, "Select libsigrok/libsigrokdecode loglevel", NULL}, - {"list-devices", 'D', 0, G_OPTION_ARG_NONE, &opt_list_devs, "Scan for devices", NULL}, - {"device", 'd', 0, G_OPTION_ARG_STRING, &opt_dev, "Use specified device", NULL}, - {"input-file", 'i', 0, G_OPTION_ARG_FILENAME, &opt_input_file, "Load input from file", NULL}, - {"input-format", 'I', 0, G_OPTION_ARG_STRING, &opt_input_format, "Input format", NULL}, - {"output-file", 'o', 0, G_OPTION_ARG_FILENAME, &opt_output_file, "Save output to file", NULL}, - {"output-format", 'O', 0, G_OPTION_ARG_STRING, &opt_output_format, "Output format", NULL}, - {"probes", 'p', 0, G_OPTION_ARG_STRING, &opt_probes, "Probes to use", NULL}, - {"triggers", 't', 0, G_OPTION_ARG_STRING, &opt_triggers, "Trigger configuration", NULL}, - {"wait-trigger", 'w', 0, G_OPTION_ARG_NONE, &opt_wait_trigger, "Wait for trigger", NULL}, - {"protocol-decoders", 'a', 0, G_OPTION_ARG_STRING, &opt_pds, "Protocol decoders to run", NULL}, - {"protocol-decoder-stack", 's', 0, G_OPTION_ARG_STRING, &opt_pd_stack, "Protocol decoder stack", NULL}, - {"time", 0, 0, G_OPTION_ARG_STRING, &opt_time, "How long to sample (ms)", NULL}, - {"samples", 0, 0, G_OPTION_ARG_STRING, &opt_samples, "Number of samples to acquire", NULL}, - {"continuous", 0, 0, G_OPTION_ARG_NONE, &opt_continuous, "Sample continuously", NULL}, + {"version", 'V', 0, G_OPTION_ARG_NONE, &opt_version, + "Show version and support list", NULL}, + {"loglevel", 'l', 0, G_OPTION_ARG_INT, &opt_loglevel, + "Select libsigrok/libsigrokdecode loglevel", NULL}, + {"list-devices", 'D', 0, G_OPTION_ARG_NONE, &opt_list_devs, + "Scan for devices", NULL}, + {"device", 'd', 0, G_OPTION_ARG_STRING, &opt_dev, + "Use specified device", NULL}, + {"input-file", 'i', 0, G_OPTION_ARG_FILENAME, &opt_input_file, + "Load input from file", NULL}, + {"input-format", 'I', 0, G_OPTION_ARG_STRING, &opt_input_format, + "Input format", NULL}, + {"output-file", 'o', 0, G_OPTION_ARG_FILENAME, &opt_output_file, + "Save output to file", NULL}, + {"output-format", 'O', 0, G_OPTION_ARG_STRING, &opt_output_format, + "Output format", NULL}, + {"probes", 'p', 0, G_OPTION_ARG_STRING, &opt_probes, + "Probes to use", NULL}, + {"triggers", 't', 0, G_OPTION_ARG_STRING, &opt_triggers, + "Trigger configuration", NULL}, + {"wait-trigger", 'w', 0, G_OPTION_ARG_NONE, &opt_wait_trigger, + "Wait for trigger", NULL}, + {"protocol-decoders", 'a', 0, G_OPTION_ARG_STRING, &opt_pds, + "Protocol decoders to run", NULL}, + {"protocol-decoder-stack", 's', 0, G_OPTION_ARG_STRING, &opt_pd_stack, + "Protocol decoder stack", NULL}, + {"protocol-decoder-annotations", 'A', 0, G_OPTION_ARG_STRING, &opt_pd_annotations, + "Protocol decoder annotation(s) to show", NULL}, + {"time", 0, 0, G_OPTION_ARG_STRING, &opt_time, + "How long to sample (ms)", NULL}, + {"samples", 0, 0, G_OPTION_ARG_STRING, &opt_samples, + "Number of samples to acquire", NULL}, + {"continuous", 0, 0, G_OPTION_ARG_NONE, &opt_continuous, + "Sample continuously", NULL}, {NULL, 0, 0, 0, NULL, NULL, NULL} }; @@ -273,7 +292,7 @@ static void show_pd_detail(void) pdtokens = g_strsplit(opt_pds, ",", -1); for (pdtok = pdtokens; *pdtok; pdtok++) { if (!(dec = srd_decoder_get_by_id(*pdtok))) { - printf("Protocol decoder %s not found.", *pdtok); + printf("Protocol decoder %s not found.\n", *pdtok); return; } printf("ID: %s\nName: %s\nLong name: %s\nDescription: %s\n", @@ -497,16 +516,18 @@ static int register_pds(struct sr_dev *dev, const char *pdstring) { GHashTable *pd_opthash; struct srd_decoder_inst *di; + int ret; char **pdtokens, **pdtok, *pd_name; /* Avoid compiler warnings. */ (void)dev; - g_datalist_init(&pd_ann_visible); - pdtokens = g_strsplit(pdstring, ",", -1); - pd_opthash = NULL; + ret = 0; + pd_ann_visible = g_hash_table_new_full(g_str_hash, g_int_equal, + g_free, NULL); pd_name = NULL; - + pd_opthash = NULL; + pdtokens = g_strsplit(pdstring, ",", 0); for (pdtok = pdtokens; *pdtok; pdtok++) { if (!(pd_opthash = parse_generic_arg(*pdtok))) { g_critical("Invalid protocol decoder option '%s'.", *pdtok); @@ -517,20 +538,31 @@ static int register_pds(struct sr_dev *dev, const char *pdstring) g_hash_table_remove(pd_opthash, "sigrok_key"); if (srd_decoder_load(pd_name) != SRD_OK) { g_critical("Failed to load protocol decoder %s.", pd_name); + ret = 1; goto err_out; } if (!(di = srd_inst_new(pd_name, pd_opthash))) { g_critical("Failed to instantiate protocol decoder %s.", pd_name); + ret = 1; goto err_out; } - g_datalist_set_data(&pd_ann_visible, di->inst_id, pd_name); + + /* If no annotation list was specified, add them all in now. + * This will be pared down later to leave only the last PD + * in the stack. + */ + if (!opt_pd_annotations) + g_hash_table_insert(pd_ann_visible, + g_strdup(di->inst_id), NULL); /* Any keys left in the options hash are probes, where the key * is the probe name as specified in the decoder class, and the * value is the probe number i.e. the order in which the PD's * incoming samples are arranged. */ - if (srd_inst_probe_set_all(di, pd_opthash) != SRD_OK) + if (srd_inst_probe_set_all(di, pd_opthash) != SRD_OK) { + ret = 1; goto err_out; + } g_hash_table_destroy(pd_opthash); pd_opthash = NULL; } @@ -542,26 +574,169 @@ err_out: if (pd_name) g_free(pd_name); + return ret; +} + +int setup_pd_stack(void) +{ + struct srd_decoder_inst *di_from, *di_to; + int ret, i; + char **pds; + + /* Set up the protocol decoder stack. */ + pds = g_strsplit(opt_pds, ",", 0); + if (g_strv_length(pds) > 1) { + if (opt_pd_stack) { + /* A stack setup was specified, use that. */ + g_strfreev(pds); + pds = g_strsplit(opt_pd_stack, ",", 0); + if (g_strv_length(pds) < 2) { + g_strfreev(pds); + g_critical("Specify at least two protocol decoders to stack."); + return 1; + } + } + + if (!(di_from = srd_inst_find_by_id(pds[0]))) { + g_critical("Cannot stack protocol decoder '%s': " + "instance not found.", pds[0]); + return 1; + } + for (i = 1; pds[i]; i++) { + if (!(di_to = srd_inst_find_by_id(pds[i]))) { + g_critical("Cannot stack protocol decoder '%s': " + "instance not found.", pds[i]); + return 1; + } + if ((ret = srd_inst_stack(di_from, di_to)) != SRD_OK) + return 1; + + /* Don't show annotation from this PD. Only the last PD in + * the stack will be left on the annotation list (unless + * the annotation list was specifically provided). + */ + if (!opt_pd_annotations) + g_hash_table_remove(pd_ann_visible, + di_from->inst_id); + + di_from = di_to; + } + } + g_strfreev(pds); + + return 0; +} + +int setup_pd_annotations(void) +{ + GSList *l; + struct srd_decoder *dec; + int ann; + char **pds, **pdtok, **keyval, **ann_descr; + + /* Set up custom list of PDs and annotations to show. */ + if (opt_pd_annotations) { + pds = g_strsplit(opt_pd_annotations, ",", 0); + for (pdtok = pds; *pdtok && **pdtok; pdtok++) { + ann = 0; + keyval = g_strsplit(*pdtok, "=", 0); + if (!(dec = srd_decoder_get_by_id(keyval[0]))) { + g_critical("Protocol decoder '%s' not found.", keyval[0]); + return 1; + } + if (!dec->annotations) { + g_critical("Protocol decoder '%s' has no annotations.", keyval[0]); + return 1; + } + if (g_strv_length(keyval) == 2) { + for (l = dec->annotations; l; l = l->next, ann++) { + ann_descr = l->data; + if (!canon_cmp(ann_descr[0], keyval[1])) + /* Found it. */ + break; + } + if (!l) { + g_critical("Annotation '%s' not found " + "for protocol decoder '%s'.", keyval[1], keyval[0]); + return 1; + } + } + g_debug("cli: showing protocol decoder annotation %d from '%s'", ann, keyval[0]); + g_hash_table_insert(pd_ann_visible, g_strdup(keyval[0]), GINT_TO_POINTER(ann)); + g_strfreev(keyval); + } + g_strfreev(pds); + } + return 0; } -void show_pd_annotation(struct srd_proto_data *pdata, void *cb_data) +int setup_output_format(void) +{ + GHashTable *fmtargs; + GHashTableIter iter; + gpointer key, value; + struct sr_output_format **outputs; + int i; + char *fmtspec; + + if (!opt_output_format) { + opt_output_format = DEFAULT_OUTPUT_FORMAT; + /* we'll need to remember this so when saving to a file + * later, sigrok session format will be used. + */ + default_output_format = TRUE; + } + fmtargs = parse_generic_arg(opt_output_format); + fmtspec = g_hash_table_lookup(fmtargs, "sigrok_key"); + if (!fmtspec) { + g_critical("Invalid output format."); + return 1; + } + outputs = sr_output_list(); + for (i = 0; outputs[i]; i++) { + if (strcmp(outputs[i]->id, fmtspec)) + continue; + g_hash_table_remove(fmtargs, "sigrok_key"); + output_format = outputs[i]; + g_hash_table_iter_init(&iter, fmtargs); + while (g_hash_table_iter_next(&iter, &key, &value)) { + /* only supporting one parameter per output module + * for now, and only its value */ + output_format_param = g_strdup(value); + break; + } + break; + } + if (!output_format) { + g_critical("Invalid output format %s.", opt_output_format); + return 1; + } + g_hash_table_destroy(fmtargs); + + return 0; +} + +void show_pd_annotations(struct srd_proto_data *pdata, void *cb_data) { int i; char **annotations; + gpointer ann_format; /* 'cb_data' is not used in this specific callback. */ (void)cb_data; - if (pdata->ann_format != 0) { - /* CLI only shows the default annotation format. */ + if (!pd_ann_visible) return; - } - if (!g_datalist_get_data(&pd_ann_visible, pdata->pdo->di->inst_id)) { + if (!g_hash_table_lookup_extended(pd_ann_visible, pdata->pdo->di->inst_id, + NULL, &ann_format)) /* Not in the list of PDs whose annotations we're showing. */ return; - } + + if (pdata->ann_format != GPOINTER_TO_INT(ann_format)) + /* We don't want this particular format from the PD. */ + return; annotations = pdata->data; if (opt_loglevel > SR_LOG_WARN) @@ -657,6 +832,9 @@ static struct sr_input_format *determine_input_file_format( g_critical("Error: no matching input module found."); return NULL; } + + g_debug("cli: Autodetected '%s' input format for file '%s'.", + inputs[i]->id, filename); return inputs[i]; } @@ -976,7 +1154,7 @@ static void logger(const gchar *log_domain, GLogLevelFlags log_level, * All messages, warnings, errors etc. go to stderr (not stdout) in * order to not mess up the CLI tool data output, e.g. VCD output. */ - if (log_level & (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING) + if (log_level & (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING) || opt_loglevel > SR_LOG_WARN) { fprintf(stderr, "%s\n", message); fflush(stderr); @@ -987,13 +1165,6 @@ int main(int argc, char **argv) { GOptionContext *context; GError *error; - GHashTable *fmtargs; - GHashTableIter iter; - gpointer key, value; - struct sr_output_format **outputs; - struct srd_decoder_inst *di_from, *di_to; - int i, ret; - char *fmtspec, **pds; g_log_set_default_handler(logger, NULL); @@ -1007,105 +1178,32 @@ int main(int argc, char **argv) } /* Set the loglevel (amount of messages to output) for libsigrok. */ - if (sr_log_loglevel_set(opt_loglevel) != SR_OK) { - g_critical("sr_log_loglevel_set(%d) failed.", opt_loglevel); + if (sr_log_loglevel_set(opt_loglevel) != SR_OK) return 1; - } /* Set the loglevel (amount of messages to output) for libsigrokdecode. */ - if (srd_log_loglevel_set(opt_loglevel) != SRD_OK) { - g_critical("srd_log_loglevel_set(%d) failed.", opt_loglevel); + if (srd_log_loglevel_set(opt_loglevel) != SRD_OK) return 1; - } if (sr_init() != SR_OK) return 1; if (opt_pds) { - if (srd_init(NULL) != SRD_OK) { - g_critical("Failed to initialize sigrokdecode."); + if (srd_init(NULL) != SRD_OK) return 1; - } - if (register_pds(NULL, opt_pds) != 0) { - g_critical("Failed to register protocol decoders."); + if (register_pds(NULL, opt_pds) != 0) return 1; - } if (srd_pd_output_callback_add(SRD_OUTPUT_ANN, - show_pd_annotation, NULL) != SRD_OK) { - g_critical("Failed to register protocol decoder callback."); + show_pd_annotations, NULL) != SRD_OK) + return 1; + if (setup_pd_stack() != 0) + return 1; + if (setup_pd_annotations() != 0) return 1; - } - - pds = g_strsplit(opt_pds, ",", 0); - if (g_strv_length(pds) > 1) { - if (opt_pd_stack) { - /* A stack setup was specified, use that. */ - g_strfreev(pds); - pds = g_strsplit(opt_pd_stack, ",", 0); - if (g_strv_length(pds) < 2) { - g_strfreev(pds); - g_critical("Specify at least two protocol decoders to stack."); - return 1; - } - } - - if (!(di_from = srd_inst_find_by_id(pds[0]))) { - g_critical("Cannot stack protocol decoder '%s': " - "instance not found.", pds[0]); - return 1; - } - for (i = 1; pds[i]; i++) { - if (!(di_to = srd_inst_find_by_id(pds[i]))) { - g_critical("Cannot stack protocol decoder '%s': " - "instance not found.", pds[i]); - return 1; - } - if ((ret = srd_inst_stack(di_from, di_to)) != SRD_OK) - return ret; - - /* Don't show annotation from this PD. Only the last PD in - * the stack will be left on the annotation list. - */ - g_datalist_remove_data(&pd_ann_visible, di_from->inst_id); - - di_from = di_to; - } - } - g_strfreev(pds); } - if (!opt_output_format) { - opt_output_format = DEFAULT_OUTPUT_FORMAT; - /* we'll need to remember this so when saving to a file - * later, sigrok session format will be used. - */ - default_output_format = TRUE; - } - fmtargs = parse_generic_arg(opt_output_format); - fmtspec = g_hash_table_lookup(fmtargs, "sigrok_key"); - if (!fmtspec) { - g_critical("Invalid output format."); - return 1; - } - outputs = sr_output_list(); - for (i = 0; outputs[i]; i++) { - if (strcmp(outputs[i]->id, fmtspec)) - continue; - g_hash_table_remove(fmtargs, "sigrok_key"); - output_format = outputs[i]; - g_hash_table_iter_init(&iter, fmtargs); - while (g_hash_table_iter_next(&iter, &key, &value)) { - /* only supporting one parameter per output module - * for now, and only its value */ - output_format_param = g_strdup(value); - break; - } - break; - } - if (!output_format) { - g_critical("Invalid output format %s.", opt_output_format); + if (setup_output_format() != 0) return 1; - } if (opt_version) show_version(); @@ -1126,7 +1224,6 @@ int main(int argc, char **argv) srd_exit(); g_option_context_free(context); - g_hash_table_destroy(fmtargs); sr_exit(); return 0;