]> sigrok.org Git - sigrok-cli.git/blobdiff - decode.c
Sort probes by index.
[sigrok-cli.git] / decode.c
index 19112a922575b04edfbb5ec8e6e5aae6bc6709a7..0346d7d7d9afad31e2df2436eeab2c282f4a52af 100644 (file)
--- a/decode.c
+++ b/decode.c
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "sigrok-cli.h"
 #include "config.h"
 #include <glib.h>
-#include <libsigrok/libsigrok.h>
-#ifdef HAVE_SRD
-#include <libsigrokdecode/libsigrokdecode.h> /* First, so we avoid a _POSIX_C_SOURCE warning. */
-#endif
-#include "sigrok-cli.h"
 
 #ifdef HAVE_SRD
 static GHashTable *pd_ann_visible = NULL;
 static GHashTable *pd_meta_visible = NULL;
 static GHashTable *pd_binary_visible = NULL;
+static GHashTable *pd_probe_maps = NULL;
 
 extern struct srd_session *srd_sess;
 extern gint opt_loglevel;
-extern gchar *opt_pds;
-extern gchar *opt_pd_stack;
-extern gchar *opt_pd_annotations;
-extern gchar *opt_pd_meta;
-extern gchar *opt_pd_binary;
 
 
 static int opts_to_gvar(struct srd_decoder *dec, GHashTable *hash,
@@ -83,42 +75,38 @@ static int opts_to_gvar(struct srd_decoder *dec, GHashTable *hash,
        return ret;
 }
 
-static int probes_to_gvar(struct srd_decoder *dec, GHashTable *hash,
-               GHashTable **probes)
+static int move_hash_element(GHashTable *src, GHashTable *dest, void *key)
 {
+       void *orig_key, *value;
+
+       if (!g_hash_table_lookup_extended(src, key, &orig_key, &value))
+               /* Not specified. */
+               return FALSE;
+       g_hash_table_steal(src, orig_key);
+       g_hash_table_insert(dest, orig_key, value);
+
+       return TRUE;
+}
+
+static GHashTable *extract_probe_map(struct srd_decoder *dec, GHashTable *hash)
+{
+       GHashTable *probe_map;
        struct srd_probe *p;
-       GSList *all_probes, *l;
-       GVariant *gvar;
-       gint32 val_int;
-       int ret;
-       char *val_str, *conv;
+       GSList *l;
 
-       ret = TRUE;
-       *probes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
-                       (GDestroyNotify)g_variant_unref);
+       probe_map = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                         g_free, g_free);
 
-       all_probes = g_slist_copy(dec->probes);
-       all_probes = g_slist_concat(all_probes, g_slist_copy(dec->opt_probes));
-       for (l = all_probes; l; l = l->next) {
+       for (l = dec->probes; l; l = l->next) {
                p = l->data;
-               if (!(val_str = g_hash_table_lookup(hash, p->id)))
-                       /* Not specified. */
-                       continue;
-               val_int = strtoll(val_str, &conv, 10);
-               if (!conv || conv == val_str) {
-                       g_critical("Protocol decoder '%s' probes '%s' "
-                                       "is not a number.", dec->name, p->id);
-                       ret = FALSE;
-                       break;
-               }
-               gvar = g_variant_new_int32(val_int);
-               g_variant_ref_sink(gvar);
-               g_hash_table_insert(*probes, g_strdup(p->id), gvar);
-               g_hash_table_remove(hash, p->id);
+               move_hash_element(hash, probe_map, p->id);
+       }
+       for (l = dec->opt_probes; l; l = l->next) {
+               p = l->data;
+               move_hash_element(hash, probe_map, p->id);
        }
-       g_slist_free(all_probes);
 
-       return ret;
+       return probe_map;
 }
 
 /* Register the given PDs for this session.
@@ -126,7 +114,7 @@ static int probes_to_gvar(struct srd_decoder *dec, GHashTable *hash,
  * That will instantiate two SPI decoders on the clock but different data
  * lines.
  */
-int register_pds(const char *pdstring)
+int register_pds(const char *opt_pds, char *opt_pd_annotations)
 {
        struct srd_decoder *dec;
        GHashTable *pd_opthash, *options, *probes;
@@ -135,12 +123,12 @@ int register_pds(const char *pdstring)
        int ret;
        char **pdtokens, **pdtok, *pd_name;
 
-       pd_ann_visible = g_hash_table_new_full(g_str_hash, g_int_equal,
-                       g_free, NULL);
+       pd_ann_visible = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                              g_free, NULL);
        ret = 0;
        pd_name = NULL;
-       pd_opthash = options = probes = NULL;
-       pdtokens = g_strsplit(pdstring, ",", 0);
+       pd_opthash = options = probes = pd_probe_maps = NULL;
+       pdtokens = g_strsplit(opt_pds, ",", 0);
        for (pdtok = pdtokens; *pdtok; pdtok++) {
                if (!(pd_opthash = parse_generic_arg(*pdtok, TRUE))) {
                        g_critical("Invalid protocol decoder option '%s'.", *pdtok);
@@ -161,10 +149,8 @@ int register_pds(const char *pdstring)
                        ret = 1;
                        break;
                }
-               if (!probes_to_gvar(dec, pd_opthash, &probes)) {
-                       ret = 1;
-                       break;
-               }
+               probes = extract_probe_map(dec, pd_opthash);
+
                if (g_hash_table_size(pd_opthash) > 0) {
                        leftover = g_hash_table_get_keys(pd_opthash);
                        for (l = leftover; l; l = l->next)
@@ -179,6 +165,15 @@ int register_pds(const char *pdstring)
                        break;
                }
 
+               if (pdtok == pdtokens) {
+                       /* Save the probe setup for later, but only on the first
+                        * decoder -- stacked decoders don't get probes. */
+                       pd_probe_maps = g_hash_table_new_full(g_str_hash,
+                                       g_str_equal, g_free, (GDestroyNotify)g_hash_table_destroy);
+                       g_hash_table_insert(pd_probe_maps, g_strdup(di->inst_id), probes);
+                       probes = NULL;
+               }
+
                /* 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.
@@ -186,12 +181,6 @@ int register_pds(const char *pdstring)
                if (!opt_pd_annotations)
                        g_hash_table_insert(pd_ann_visible,
                                            g_strdup(di->inst_id), GINT_TO_POINTER(-1));
-
-               /* Remap the probes if needed. */
-               if (srd_inst_probe_set_all(di, probes) != SRD_OK) {
-                       ret = 1;
-                       break;
-               }
        }
 
        g_strfreev(pdtokens);
@@ -207,7 +196,63 @@ int register_pds(const char *pdstring)
        return ret;
 }
 
-int setup_pd_stack(void)
+static void map_pd_inst_probes(void *key, void *value, void *user_data)
+{
+       GHashTable *probe_map;
+       GHashTable *probe_indices;
+       GSList *probe_list;
+       struct srd_decoder_inst *di;
+       GVariant *var;
+       void *probe_id;
+       void *probe_target;
+       struct sr_probe *probe;
+       GHashTableIter iter;
+       int num_probes;
+
+       probe_map = value;
+       probe_list = user_data;
+
+       di = srd_inst_find_by_id(srd_sess, key);
+       if (!di) {
+               g_critical("Protocol decoder instance \"%s\" not found.",
+                          (char *)key);
+               return;
+       }
+       probe_indices = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+                                             (GDestroyNotify)g_variant_unref);
+
+       g_hash_table_iter_init(&iter, probe_map);
+       while (g_hash_table_iter_next(&iter, &probe_id, &probe_target)) {
+               probe = find_probe(probe_list, probe_target);
+               if (!probe) {
+                       g_printerr("cli: No probe with name \"%s\" found.\n",
+                                  (char *)probe_target);
+                       continue;
+               }
+               if (!probe->enabled)
+                       g_printerr("cli: Target probe \"%s\" not enabled.\n",
+                                  (char *)probe_target);
+
+               var = g_variant_new_int32(probe->index);
+               g_variant_ref_sink(var);
+               g_hash_table_insert(probe_indices, g_strdup(probe_id), var);
+       }
+
+       num_probes = g_slist_length(probe_list);
+       srd_inst_probe_set_all(di, probe_indices, (num_probes + 7) / 8);
+}
+
+void map_pd_probes(struct sr_dev_inst *sdi)
+{
+       if (pd_probe_maps) {
+               g_hash_table_foreach(pd_probe_maps, &map_pd_inst_probes,
+                                    sdi->probes);
+               g_hash_table_destroy(pd_probe_maps);
+               pd_probe_maps = NULL;
+       }
+}
+
+int setup_pd_stack(char *opt_pds, char *opt_pd_stack, char *opt_pd_annotations)
 {
        struct srd_decoder_inst *di_from, *di_to;
        int ret, i;
@@ -266,7 +311,7 @@ int setup_pd_stack(void)
        return 0;
 }
 
-int setup_pd_annotations(void)
+int setup_pd_annotations(char *opt_pd_annotations)
 {
        GSList *l;
        struct srd_decoder *dec;
@@ -314,7 +359,7 @@ int setup_pd_annotations(void)
        return 0;
 }
 
-int setup_pd_meta(void)
+int setup_pd_meta(char *opt_pd_meta)
 {
        struct srd_decoder *dec;
        char **pds, **pdtok;
@@ -335,12 +380,12 @@ int setup_pd_meta(void)
        return 0;
 }
 
-int setup_pd_binary(void)
+int setup_pd_binary(char *opt_pd_binary)
 {
        GSList *l;
        struct srd_decoder *dec;
        int bin_class;
-       char **pds, **pdtok, **keyval, *bin_name;
+       char **pds, **pdtok, **keyval, **bin_name;
 
        pd_binary_visible = g_hash_table_new_full(g_str_hash, g_int_equal,
                        g_free, NULL);
@@ -359,7 +404,7 @@ int setup_pd_binary(void)
                if (g_strv_length(keyval) == 2) {
                        for (l = dec->binary; l; l = l->next, bin_class++) {
                                bin_name = l->data;
-                               if (!canon_cmp(bin_name, keyval[1]))
+                               if (!strcmp(bin_name[0], keyval[1]))
                                        /* Found it. */
                                        break;
                        }
@@ -369,7 +414,7 @@ int setup_pd_binary(void)
                                return 1;
                        }
                        g_debug("cli: Showing protocol decoder %s binary class "
-                                       "%d (%s).", keyval[0], bin_class, bin_name);
+                                       "%d (%s).", keyval[0], bin_class, bin_name[0]);
                } else {
                        /* No class specified: output all of them. */
                        bin_class = -1;
@@ -386,9 +431,11 @@ int setup_pd_binary(void)
 
 void show_pd_annotations(struct srd_proto_data *pdata, void *cb_data)
 {
+       struct srd_decoder *dec;
        struct srd_proto_data_annotation *pda;
        gpointer ann_format;
-       int format;
+       int format, i;
+       char **ann_descr;
 
        /* 'cb_data' is not used in this specific callback. */
        (void)cb_data;
@@ -402,16 +449,29 @@ void show_pd_annotations(struct srd_proto_data *pdata, void *cb_data)
                return;
 
        format = GPOINTER_TO_INT(ann_format);
+       dec = pdata->pdo->di->decoder;
        pda = pdata->data;
        if (format != -1 && pda->ann_format != format)
                /* We don't want this particular format from the PD. */
                return;
 
-       if (opt_loglevel > SR_LOG_WARN)
-               printf("%"PRIu64"-%"PRIu64" ", pdata->start_sample, pdata->end_sample);
-       printf("%s: ", pdata->pdo->proto_id);
-       /* Show only the longest annotation. */
-       printf("\"%s\" ", pda->ann_text[0]);
+       if (opt_loglevel <= SR_LOG_WARN) {
+               /* Show only the longest annotation. */
+               printf("%s", pda->ann_text[0]);
+       } else if (opt_loglevel >= SR_LOG_INFO) {
+               /* Sample numbers and quotes around the longest annotation. */
+               printf("%"PRIu64"-%"PRIu64"", pdata->start_sample, pdata->end_sample);
+               if (opt_loglevel == SR_LOG_INFO) {
+                       printf(" \"%s\"", pda->ann_text[0]);
+               } else {
+                       /* Protocol decoder id, annotation class,
+                        * all annotation strings. */
+                       ann_descr = g_slist_nth_data(dec->annotations, pda->ann_format);
+                       printf(" %s: %s:", pdata->pdo->proto_id, ann_descr[0]);
+                       for (i = 0; pda->ann_text[i]; i++)
+                               printf(" \"%s\"", pda->ann_text[i]);
+               }
+       }
        printf("\n");
        fflush(stdout);
 }