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 f71ead00b3284c58c87d0695ff52ac8e7cefe6d4..6b3490a1d4ce1b0b206e8dc0a073fbc9d7ab4ba4 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 e699d2f0e6d905b5ab06775c9c65f30bb54c7267..94f1c0f6491c25159573b73259fb59a4c7b2734f 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 49a12433618a0b868abfe706d77a0da47fc8a13b..4d398471ee86f22012a1a65994239f3ae79fe836 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 7d02326e86bad5860b698c38a9d4106fcd88d61f..eca05b8b92216145dc998213b32e8b6b75efc1ee 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 f5260b18bcc83df4c64bf17c287bb5b27e54385e..d0b5872ae88984f4b4ced8faa99b0a55ccd985b6 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;