Support multiple protocol decoder stacks
authorKarl Palsson <karlp@etactica.com>
Fri, 25 Nov 2016 16:28:17 +0000 (16:28 +0000)
committerUwe Hermann <uwe@hermann-uwe.de>
Mon, 20 Feb 2017 15:30:50 +0000 (16:30 +0100)
Requires libsigrokdecode changes to actually work.
This allows multiple -P options to be specified, each of which is
registered as a full stack with libsigrokdecode.

At this point, there's no way to specify annotations per instance, the
annotations are simply global per decoder (as before) rather than per
instance.

This fixes parts of bug #868.

Signed-off-by: Karl Palsson <karlp@etactica.com>
decode.c
main.c
options.c
show.c
sigrok-cli.h

index f71ead0..6b3490a 100644 (file)
--- a/decode.c
+++ b/decode.c
@@ -109,26 +109,20 @@ static GHashTable *extract_channel_map(struct srd_decoder *dec, GHashTable *hash
        return channel_map;
 }
 
-/*
- * Register the given PDs for this session.
- * Accepts a string of the form: "spi:sck=3:sdata=4,spi:sck=3:sdata=5"
- * That will instantiate two SPI decoders on the clock but different data
- * lines.
- */
-int register_pds(const char *opt_pds, char *opt_pd_annotations)
+static int register_pd(char *opt_pds, char *opt_pd_annotations)
 {
+       int ret;
        struct srd_decoder *dec;
+       struct srd_decoder_inst *di, *di_prior;
+       char **pdtokens, **pdtok, *pd_name;
        GHashTable *pd_opthash, *options, *channels;
        GList *leftover, *l;
-       struct srd_decoder_inst *di;
-       int ret;
-       char **pdtokens, **pdtok, *pd_name;
 
-       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 = channels = pd_channel_maps = NULL;
+       di_prior = NULL;
+       pd_opthash = options = channels = NULL;
+
        pdtokens = g_strsplit(opt_pds, ",", 0);
        for (pdtok = pdtokens; *pdtok; pdtok++) {
                if (!(pd_opthash = parse_generic_arg(*pdtok, TRUE))) {
@@ -175,8 +169,6 @@ int register_pds(const char *opt_pds, char *opt_pd_annotations)
                         * Save the channel setup for later, but only on the
                         * first decoder (stacked decoders don't get channels).
                         */
-                       pd_channel_maps = g_hash_table_new_full(g_str_hash,
-                                       g_str_equal, g_free, (GDestroyNotify)g_hash_table_destroy);
                        g_hash_table_insert(pd_channel_maps, g_strdup(di->inst_id), channels);
                        channels = NULL;
                }
@@ -186,23 +178,58 @@ int register_pds(const char *opt_pds, char *opt_pd_annotations)
                 * This will be pared down later to leave only the last PD
                 * in the stack.
                 */
-               if (!opt_pd_annotations)
+               if (!opt_pd_annotations) {
                        g_hash_table_insert(pd_ann_visible, g_strdup(di->inst_id),
                                        g_slist_append(NULL, GINT_TO_POINTER(-1)));
+               }
+               if (di_prior) {
+                       if (srd_inst_stack(srd_sess, di_prior, di) != SRD_OK) {
+                               g_critical("Failed to stack %s -> %s.",
+                                       di_prior->inst_id, di->inst_id);
+                               ret = 1;
+                               break;
+                       }
+                       /* Remove annotations from prior levels. */
+                       if (!opt_pd_annotations)
+                               g_hash_table_remove(pd_ann_visible, di_prior->inst_id);
+               }
+               di_prior = di;
        }
 
-       g_strfreev(pdtokens);
        if (pd_opthash)
                g_hash_table_destroy(pd_opthash);
        if (options)
                g_hash_table_destroy(options);
        if (channels)
                g_hash_table_destroy(channels);
+
+       g_strfreev(pdtokens);
        g_free(pd_name);
 
        return ret;
 }
 
+/*
+ * Register all the PDs from all stacks.
+ *
+ * Each PD string is a single stack such as "uart:baudrate=19200,modbus".
+ */
+int register_pds(gchar **all_pds, char *opt_pd_annotations)
+{
+       int ret;
+
+       ret = 0;
+       pd_ann_visible = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                              g_free, NULL);
+       pd_channel_maps = g_hash_table_new_full(g_str_hash,
+               g_str_equal, g_free, (GDestroyNotify)g_hash_table_destroy);
+
+       for (int i = 0; all_pds[i]; i++)
+               ret += register_pd(all_pds[i], opt_pd_annotations);
+
+       return ret;
+}
+
 static void map_pd_inst_channels(void *key, void *value, void *user_data)
 {
        GHashTable *channel_map;
@@ -261,54 +288,6 @@ void map_pd_channels(struct sr_dev_inst *sdi)
        }
 }
 
-int setup_pd_stack(char *opt_pds, char *opt_pd_annotations)
-{
-       struct srd_decoder_inst *di_from, *di_to;
-       int ret, i;
-       char **pds, **ids;
-
-       /* Set up the protocol decoder stack. */
-       pds = g_strsplit(opt_pds, ",", 0);
-       if (g_strv_length(pds) > 1) {
-               /* First PD goes at the bottom of the stack. */
-               ids = g_strsplit(pds[0], ":", 0);
-               if (!(di_from = srd_inst_find_by_id(srd_sess, ids[0]))) {
-                       g_strfreev(ids);
-                       g_critical("Cannot stack protocol decoder '%s': "
-                                       "instance not found.", pds[0]);
-                       return 1;
-               }
-               g_strfreev(ids);
-
-               /* Every subsequent PD goes on top. */
-               for (i = 1; pds[i]; i++) {
-                       ids = g_strsplit(pds[i], ":", 0);
-                       if (!(di_to = srd_inst_find_by_id(srd_sess, ids[0]))) {
-                               g_strfreev(ids);
-                               g_critical("Cannot stack protocol decoder '%s': "
-                                               "instance not found.", pds[i]);
-                               return 1;
-                       }
-                       g_strfreev(ids);
-                       if ((ret = srd_inst_stack(srd_sess, 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(char *opt_pd_annotations)
 {
        GSList *l, *l_ann;
diff --git a/main.c b/main.c
index e699d2f..94f1c0f 100644 (file)
--- a/main.c
+++ b/main.c
@@ -214,8 +214,6 @@ int main(int argc, char **argv)
                }
                if (register_pds(opt_pds, opt_pd_annotations) != 0)
                        goto done;
-               if (setup_pd_stack(opt_pds, opt_pd_annotations) != 0)
-                       goto done;
 
                /* Only one output type is ever shown. */
                if (opt_pd_binary) {
index 49a1243..4d39847 100644 (file)
--- a/options.c
+++ b/options.c
@@ -32,7 +32,7 @@ gchar *opt_config = NULL;
 gchar *opt_channels = NULL;
 gchar *opt_channel_group = NULL;
 gchar *opt_triggers = NULL;
-gchar *opt_pds = NULL;
+gchar **opt_pds = NULL;
 #ifdef HAVE_SRD
 gchar *opt_pd_annotations = NULL;
 gchar *opt_pd_meta = NULL;
@@ -81,7 +81,6 @@ CHECK_ONCE(opt_channels)
 CHECK_ONCE(opt_channel_group)
 CHECK_ONCE(opt_triggers)
 #ifdef HAVE_SRD
-CHECK_ONCE(opt_pds)
 CHECK_ONCE(opt_pd_annotations)
 CHECK_ONCE(opt_pd_meta)
 CHECK_ONCE(opt_pd_binary)
@@ -124,7 +123,7 @@ static const GOptionEntry optargs[] = {
        {"wait-trigger", 'w', 0, G_OPTION_ARG_NONE, &opt_wait_trigger,
                        "Wait for trigger", NULL},
 #ifdef HAVE_SRD
-       {"protocol-decoders", 'P', 0, G_OPTION_ARG_CALLBACK, &check_opt_pds,
+       {"protocol-decoders", 'P', 0, G_OPTION_ARG_STRING_ARRAY, &opt_pds,
                        "Protocol decoders to run", NULL},
        {"protocol-decoder-annotations", 'A', 0, G_OPTION_ARG_CALLBACK, &check_opt_pd_annotations,
                        "Protocol decoder annotation(s) to show", NULL},
diff --git a/show.c b/show.c
index 7d02326..eca05b8 100644 (file)
--- a/show.c
+++ b/show.c
@@ -674,7 +674,7 @@ void show_dev_detail(void)
 }
 
 #ifdef HAVE_SRD
-void show_pd_detail(void)
+static void show_pd_detail_single(const char *pd)
 {
        struct srd_decoder *dec;
        struct srd_decoder_option *o;
@@ -684,7 +684,7 @@ void show_pd_detail(void)
        int idx;
        char **pdtokens, **pdtok, *optsep, **ann, **bin, *val, *doc;
 
-       pdtokens = g_strsplit(opt_pds, ",", -1);
+       pdtokens = g_strsplit(pd, ",", -1);
        for (pdtok = pdtokens; *pdtok; pdtok++) {
                /* Strip options. */
                if ((optsep = strchr(*pdtok, ':')))
@@ -777,6 +777,12 @@ void show_pd_detail(void)
 
        g_strfreev(pdtokens);
 }
+
+void show_pd_detail(void)
+{
+       for (int i = 0; opt_pds[i]; i++)
+               show_pd_detail_single(opt_pds[i]);
+}
 #endif
 
 void show_input(void)
index f5260b1..d0b5872 100644 (file)
@@ -73,8 +73,7 @@ void load_input_file(void);
 
 /* decode.c */
 #ifdef HAVE_SRD
-int register_pds(const char *opt_pds, char *opt_pd_annotations);
-int setup_pd_stack(char *opt_pds, char *opt_pd_annotations);
+int register_pds(gchar **all_pds, char *opt_pd_annotations);
 int setup_pd_annotations(char *opt_pd_annotations);
 int setup_pd_meta(char *opt_pd_meta);
 int setup_pd_binary(char *opt_pd_binary);
@@ -110,7 +109,7 @@ extern gchar *opt_config;
 extern gchar *opt_channels;
 extern gchar *opt_channel_group;
 extern gchar *opt_triggers;
-extern gchar *opt_pds;
+extern gchar **opt_pds;
 #ifdef HAVE_SRD
 extern gchar *opt_pd_annotations;
 extern gchar *opt_pd_meta;