decode: Optionally print annotation class with PD annotations master
authorSergey Spivak <sespivak@yandex.ru>
Fri, 12 Aug 2022 11:53:43 +0000 (15:53 +0400)
committerSoeren Apel <soeren@apelpie.net>
Sat, 8 Oct 2022 20:00:40 +0000 (22:00 +0200)
Introduce the "--protocol-decoder-ann-class" command line option
(no short form available), which emits annotation class names
with textual output from protocol decoder annotations, regardless
of a log level value.

Based on commit 08e9378bf68a by Gerhard Sittig <gerhard.sittig@gmx.net>

configure.ac
decode.c
doc/sigrok-cli.1
input.c
options.c
parsers.c
session.c
show.c
sigrok-cli.h

index ef0ea0b2ce34dff2379c742785d9d0b95f2e5654..f7e689be976b5516c9b15f73e207e5f5d3b7d721 100644 (file)
@@ -91,6 +91,15 @@ AC_SYS_LARGEFILE
 PKG_CHECK_MODULES([SIGROK_CLI],
        [glib-2.0 >= 2.32.0 libsigrok >= 0.5.0 $SC_PKGLIBS])
 
+# Check for version dependent availability of functions.
+srd_save_cflags=$CFLAGS
+srd_save_libs=$LIBS
+CFLAGS="$SIGROK_CLI_CFLAGS $CFLAGS"
+LIBS="$SIGROK_CLI_LIBS $LIBS"
+AC_CHECK_FUNCS([srd_session_send_eof])
+CFLAGS=$srd_save_cflags
+LIBS=$srd_save_libs
+
 sc_glib_version=`$PKG_CONFIG --modversion glib-2.0 2>&AS_MESSAGE_LOG_FD`
 sc_libsigrok_version=`$PKG_CONFIG --modversion libsigrok 2>&AS_MESSAGE_LOG_FD`
 
index 4ddf34afbbaf00db414a041f4ef2e61ddc27bc0f..ac0e3e17cc283e51d16a0aa8e7c21be846faf657 100644 (file)
--- a/decode.c
+++ b/decode.c
@@ -684,6 +684,8 @@ void show_pd_annotations(struct srd_proto_data *pdata, void *cb_data)
                show_class = TRUE;
                show_abbrev = TRUE;
        }
+       if (opt_pd_ann_class)
+               show_class = TRUE;
 
        /*
         * Display the annotation's fields after the layout was
index 4258009bd7a507b282911d78a2bdf6d2e50a82c5..b48992847e65ffc29c47b6709bc3d8293866cf9f 100644 (file)
@@ -292,7 +292,7 @@ Example:
  $
 .B "sigrok\-cli \-i <file.sr> "
 .br
-.B "              \-P uart:baudrate=115200:parity_type=odd"
+.B "              \-P uart:baudrate=115200:parity=odd"
 .sp
 The list of supported options depends entirely on the protocol decoder. Every
 protocol decoder has different options it supports.
@@ -426,6 +426,9 @@ Not every decoder generates binary output.
 When given, decoder annotations will include sample numbers, too.
 This allows consumers to receive machine readable timing information.
 .TP
+.BR "\-\-protocol\-decoder\-ann\-class
+When given, decoder annotations will include annotation class names.
+.TP
 .BR "\-l, \-\-loglevel " <level>
 Set the libsigrok and libsigrokdecode loglevel. At the moment \fBsigrok\-cli\fP
 doesn't support setting the two loglevels independently. The higher the
diff --git a/input.c b/input.c
index 6c149722588db3a88ff0f7ca3618a4f213f77426..cce0d9ff916b9a159f0f3400d80bd5d96df263eb 100644 (file)
--- a/input.c
+++ b/input.c
@@ -44,6 +44,7 @@ static void load_input_file_module(struct df_arg_desc *df_arg)
        ssize_t len;
        char *mod_id;
        gboolean is_stdin;
+       gboolean push_scan_data;
 
        if (!sr_input_list())
                g_critical("No supported input formats available.");
@@ -56,6 +57,7 @@ static void load_input_file_module(struct df_arg_desc *df_arg)
        }
 
        is_stdin = strcmp(opt_input_file, "-") == 0;
+       push_scan_data = FALSE;
        fd = 0;
        buf = g_string_sized_new(CHUNK_SIZE);
        if (mod_id) {
@@ -66,7 +68,7 @@ static void load_input_file_module(struct df_arg_desc *df_arg)
                if ((options = sr_input_options_get(imod))) {
                        mod_opts = generic_arg_to_opt(options, mod_args);
                        (void)warn_unknown_keys(options, mod_args, NULL);
-                       sr_output_options_free(options);
+                       sr_input_options_free(options);
                } else {
                        mod_opts = NULL;
                }
@@ -103,11 +105,12 @@ static void load_input_file_module(struct df_arg_desc *df_arg)
                                        g_critical("Failed to load %s: %s.", opt_input_file,
                                                        g_strerror(errno));
                        }
-                       if ((len = read(fd, buf->str, CHUNK_SIZE)) < 1)
+                       if ((len = read(fd, buf->str, buf->allocated_len)) < 1)
                                g_critical("Failed to read %s: %s.", opt_input_file,
                                                g_strerror(errno));
                        buf->len = len;
                        sr_input_scan_buffer(buf, &in);
+                       push_scan_data = TRUE;
                }
                if (!in)
                        g_critical("Error: no input module found for this file.");
@@ -116,24 +119,46 @@ static void load_input_file_module(struct df_arg_desc *df_arg)
        df_arg->session = session;
        sr_session_datafeed_callback_add(session, datafeed_in, df_arg);
 
+       /*
+        * Implementation detail: The combination of reading from stdin
+        * and automatic file format detection may have pushed the first
+        * chunk of input data into the input module's data accumulator,
+        * _bypassing_ the .receive() callback. It is essential to call
+        * .receive() before calling .end() for files of size smaller than
+        * CHUNK_SIZE (which is a typical case). So that sdi becomes ready.
+        * Fortunately all input modules accept .receive() calls with
+        * a zero length, and inspect whatever was accumulated so far.
+        *
+        * After that optional initial push of data which was queued
+        * above during format detection, continue reading remaining
+        * chunks from the input file until EOF is seen.
+        */
        got_sdi = FALSE;
        while (TRUE) {
                g_string_truncate(buf, 0);
-               len = read(fd, buf->str, CHUNK_SIZE);
+               if (push_scan_data)
+                       len = 0;
+               else
+                       len = read(fd, buf->str, buf->allocated_len);
                if (len < 0)
                        g_critical("Read failed: %s", g_strerror(errno));
-               if (len == 0)
+               if (len == 0 && !push_scan_data)
                        /* End of file or stream. */
                        break;
+               push_scan_data = FALSE;
                buf->len = len;
-               if (sr_input_send(in, buf) != SR_OK)
+               if (sr_input_send(in, buf) != SR_OK) {
+                       g_critical("File import failed (read)");
                        break;
+               }
 
                sdi = sr_input_dev_inst_get(in);
                if (!got_sdi && sdi) {
                        /* First time we got a valid sdi. */
-                       if (select_channels(sdi) != SR_OK)
+                       if (select_channels(sdi) != SR_OK) {
+                               g_critical("File import failed (channels)");
                                return;
+                       }
                        if (sr_session_dev_add(session, sdi) != SR_OK) {
                                g_critical("Failed to use device.");
                                sr_session_destroy(session);
@@ -145,10 +170,10 @@ static void load_input_file_module(struct df_arg_desc *df_arg)
        sr_input_end(in);
        sr_input_free(in);
        g_string_free(buf, TRUE);
+       close(fd);
 
        df_arg->session = NULL;
        sr_session_destroy(session);
-
 }
 
 void load_input_file(gboolean do_props)
index 2573bd4c17b6cb861be37239070ff6e7bc8e07ef..e47b6804e96eb7635f9874b3090cb02110526dae 100644 (file)
--- a/options.c
+++ b/options.c
@@ -40,6 +40,7 @@ gchar **opt_pds = NULL;
 gchar *opt_pd_annotations = NULL;
 gchar *opt_pd_meta = NULL;
 gchar *opt_pd_binary = NULL;
+gboolean opt_pd_ann_class = FALSE;
 gboolean opt_pd_samplenum = FALSE;
 gboolean opt_pd_jsontrace = FALSE;
 #endif
@@ -139,6 +140,8 @@ static const GOptionEntry optargs[] = {
                        "Protocol decoder meta output to show", NULL},
        {"protocol-decoder-binary", 'B', 0, G_OPTION_ARG_CALLBACK, &check_opt_pd_binary,
                        "Protocol decoder binary output to show", NULL},
+       {"protocol-decoder-ann-class", 0, 0, G_OPTION_ARG_NONE, &opt_pd_ann_class,
+                       "Show annotation class in decoder output", NULL},
        {"protocol-decoder-samplenum", 0, 0, G_OPTION_ARG_NONE, &opt_pd_samplenum,
                        "Show sample numbers in decoder output", NULL},
        {"protocol-decoder-jsontrace", 0, 0, G_OPTION_ARG_NONE, &opt_pd_jsontrace,
index d92218f8664ed5a8858e32a6b631b8d4c68633aa..59a7a91830220f573d7dd9abb85789fc0b038884 100644 (file)
--- a/parsers.c
+++ b/parsers.c
@@ -139,8 +139,7 @@ range_fail:
                        }
                        if (names[1]) {
                                /* Rename channel. */
-                               g_free(ch->name);
-                               ch->name = g_strdup(names[1]);
+                               sr_dev_channel_name_set(ch, names[1]);
                        }
                        channellist = g_slist_append(channellist, ch);
 
@@ -365,6 +364,8 @@ GHashTable *parse_generic_arg(const char *arg,
                i++;
        }
        for (; elements[i]; i++) {
+               if (!elements[i][0])
+                       continue;
                split_key_value(elements[i], &k, &v);
                k = g_strdup(k);
                v = v ? g_strdup(v) : NULL;
@@ -444,11 +445,11 @@ GHashTable *generic_arg_to_opt(const struct sr_option **opts, GHashTable *genarg
                        g_hash_table_insert(hash, g_strdup(opts[i]->id),
                                        g_variant_ref_sink(gvar));
                } else if (g_variant_is_of_type(opts[i]->def, G_VARIANT_TYPE_INT32)) {
-                       gvar = g_variant_new_int32(strtoul(s, NULL, 10));
+                       gvar = g_variant_new_int32(strtol(s, NULL, 10));
                        g_hash_table_insert(hash, g_strdup(opts[i]->id),
                                        g_variant_ref_sink(gvar));
                } else if (g_variant_is_of_type(opts[i]->def, G_VARIANT_TYPE_UINT64)) {
-                       gvar = g_variant_new_uint64(strtoul(s, NULL, 10));
+                       gvar = g_variant_new_uint64(strtoull(s, NULL, 10));
                        g_hash_table_insert(hash, g_strdup(opts[i]->id),
                                        g_variant_ref_sink(gvar));
                } else if (g_variant_is_of_type(opts[i]->def, G_VARIANT_TYPE_DOUBLE)) {
index 0e426cdd1957268102797f37f0c95a5d981de7fb..5f5ca8f01f7030cef93874d04047f0ee9692f75b 100644 (file)
--- a/session.c
+++ b/session.c
@@ -485,6 +485,10 @@ void datafeed_in(const struct sr_dev_inst *sdi,
        if (packet->type == SR_DF_END) {
                g_debug("cli: Received SR_DF_END.");
 
+#if defined HAVE_SRD_SESSION_SEND_EOF && HAVE_SRD_SESSION_SEND_EOF
+               (void)srd_session_send_eof(srd_sess);
+#endif
+
                if (do_props) {
                        props_dump_details(df_arg);
                        props_cleanup(df_arg);
diff --git a/show.c b/show.c
index 9ce35b4a61b4360e39dcc03cbc6c985371a580bb..85b440989212f04d2480f68bb242c155117c5b0f 100644 (file)
--- a/show.c
+++ b/show.c
@@ -418,7 +418,7 @@ void show_dev_detail(void)
        char *tmp_str, *s, c;
        const char **stropts;
        double tmp_flt;
-       gboolean have_tmp_flt;
+       gboolean have_tmp_flt, have_curr;
        const double *fltopts;
 
        if (parse_driver(opt_drv, &driver_from_opt, NULL)) {
@@ -465,8 +465,11 @@ void show_dev_detail(void)
                printf("Channel groups:\n");
                for (cgl = channel_groups; cgl; cgl = cgl->next) {
                        cg = cgl->data;
-                       printf("    %s: channel%s", cg->name,
-                                       g_slist_length(cg->channels) > 1 ? "s" : "");
+                       printf("    %s: ", cg->name);
+                       if (g_slist_length(cg->channels) == 0)
+                               printf("No channels");
+                       else
+                               printf("channel%s", g_slist_length(cg->channels) > 1 ? "s" : "");
                        for (chl = cg->channels; chl; chl = chl->next) {
                                ch = chl->data;
                                printf(" %s", ch->name);
@@ -715,12 +718,11 @@ void show_dev_detail(void)
                                continue;
                        }
 
+                       have_curr = FALSE;
                        if (maybe_config_get(driver, sdi, channel_group, key, &gvar) == SR_OK) {
                                g_variant_get(gvar, "(dd)", &dcur_low, &dcur_high);
                                g_variant_unref(gvar);
-                       } else {
-                               dcur_low = 0;
-                               dcur_high = 0;
+                               have_curr = TRUE;
                        }
 
                        num_elements = g_variant_n_children(gvar_list);
@@ -731,6 +733,8 @@ void show_dev_detail(void)
                                if (i)
                                        printf(", ");
                                printf("%.1f-%.1f", dlow, dhigh);
+                               if (!have_curr)
+                                       continue;
                                if (dlow == dcur_low && dhigh == dcur_high)
                                        printf(" (current)");
                        }
index 2c0fbdcf57d2358b9864cce8676b39e1e7bba1f0..684aed99a8bd302da3ae8d88f6ff9e9be94ee867 100644 (file)
@@ -140,6 +140,7 @@ extern gchar **opt_pds;
 extern gchar *opt_pd_annotations;
 extern gchar *opt_pd_meta;
 extern gchar *opt_pd_binary;
+extern gboolean opt_pd_ann_class;
 extern gboolean opt_pd_samplenum;
 extern gboolean opt_pd_jsontrace;
 #endif