show: add support for -i <fn> --show, provide details on input stream
authorGerhard Sittig <gerhard.sittig@gmx.net>
Fri, 12 Apr 2019 16:50:49 +0000 (18:50 +0200)
committerUwe Hermann <uwe@hermann-uwe.de>
Tue, 14 May 2019 18:06:07 +0000 (20:06 +0200)
The combination of an input file spec and --show was not handled before,
and fell through to the case of showing device driver details. Do gather
input stream properties when --show was specified in combination with an
input file, and print those details to stdout.

This implementation does not assume a specific file format, instead the
datafeed callback got modified to watch the packets but not process them
(neither decode nor send data to an output module).

This approach, and the order of option combination checks in main(),
make this implementation work with input files as well as pipes, as well
as with any supported input module or session file, including automatic
format detection.

input.c
main.c
session.c
sigrok-cli.h

diff --git a/input.c b/input.c
index 8eeb94c869b57679eb75ca4494248740c52633a3..7d3396fc744503cdad7e348d2eb319a98e584556 100644 (file)
--- a/input.c
+++ b/input.c
@@ -30,7 +30,7 @@
 
 #define CHUNK_SIZE (4 * 1024 * 1024)
 
-static void load_input_file_module(void)
+static void load_input_file_module(struct df_arg_desc *df_arg)
 {
        struct sr_session *session;
        const struct sr_input *in;
@@ -111,7 +111,8 @@ static void load_input_file_module(void)
                        g_critical("Error: no input module found for this file.");
        }
        sr_session_new(sr_ctx, &session);
-       sr_session_datafeed_callback_add(session, &datafeed_in, session);
+       df_arg->session = session;
+       sr_session_datafeed_callback_add(session, datafeed_in, df_arg);
 
        got_sdi = FALSE;
        while (TRUE) {
@@ -143,21 +144,26 @@ static void load_input_file_module(void)
        sr_input_free(in);
        g_string_free(buf, TRUE);
 
+       df_arg->session = NULL;
        sr_session_destroy(session);
 
 }
 
-void load_input_file(void)
+void load_input_file(gboolean do_props)
 {
+       struct df_arg_desc df_arg;
        struct sr_session *session;
        struct sr_dev_inst *sdi;
        GSList *devices;
        GMainLoop *main_loop;
        int ret;
 
+       memset(&df_arg, 0, sizeof(df_arg));
+       df_arg.do_props = do_props;
+
        if (!strcmp(opt_input_file, "-")) {
                /* Input from stdin is never a session file. */
-               load_input_file_module();
+               load_input_file_module(&df_arg);
        } else {
                if ((ret = sr_session_load(sr_ctx, opt_input_file,
                                &session)) == SR_OK) {
@@ -177,7 +183,9 @@ void load_input_file(void)
                        }
                        main_loop = g_main_loop_new(NULL, FALSE);
 
-                       sr_session_datafeed_callback_add(session, datafeed_in, session);
+                       df_arg.session = session;
+                       sr_session_datafeed_callback_add(session,
+                               datafeed_in, &df_arg);
                        sr_session_stopped_callback_set(session,
                                (sr_session_stopped_callback)g_main_loop_quit,
                                main_loop);
@@ -185,13 +193,14 @@ void load_input_file(void)
                                g_main_loop_run(main_loop);
 
                        g_main_loop_unref(main_loop);
+                       df_arg.session = NULL;
                        sr_session_destroy(session);
                } else if (ret != SR_ERR) {
                        /* It's a session file, but it didn't work out somehow. */
                        g_critical("Failed to load session file.");
                } else {
                        /* Fall back on input modules. */
-                       load_input_file_module();
+                       load_input_file_module(&df_arg);
                }
        }
 }
diff --git a/main.c b/main.c
index 701da8e1992a66d69fac8f2e8316a0196c1e6c4d..8e4ac3a6a5891879c8aec9c946c82b5121b60753 100644 (file)
--- a/main.c
+++ b/main.c
@@ -268,6 +268,8 @@ int main(int argc, char **argv)
                show_supported();
        else if (opt_list_supported_wiki)
                show_supported_wiki();
+       else if (opt_input_file && opt_show)
+               load_input_file(TRUE);
        else if (opt_input_format && opt_show)
                show_input();
        else if (opt_output_format && opt_show)
@@ -283,7 +285,7 @@ int main(int argc, char **argv)
        else if (opt_show)
                show_dev_detail();
        else if (opt_input_file)
-               load_input_file();
+               load_input_file(FALSE);
        else if (opt_get)
                get_option();
        else if (opt_set)
index c5eb7aad3988e2ad67f8aae3725c5024f8f419c1..65352bbd841481b31219c0d20111f65d3fb9d3b6 100644 (file)
--- a/session.c
+++ b/session.c
@@ -150,6 +150,96 @@ const struct sr_transform *setup_transform_module(const struct sr_dev_inst *sdi)
        return t;
 }
 
+/* Get the input stream's list of channels and their types, once. */
+static void props_get_channels(struct df_arg_desc *args,
+       const struct sr_dev_inst *sdi)
+{
+       struct input_stream_props *props;
+       GSList *l;
+       const struct sr_channel *ch;
+
+       if (!args)
+               return;
+       props = &args->props;
+       if (props->channels)
+               return;
+
+       props->channels = g_slist_copy(sr_dev_inst_channels_get(sdi));
+       if (!props->channels)
+               return;
+       for (l = props->channels; l; l = l->next) {
+               ch = l->data;
+               if (!ch->enabled)
+                       continue;
+               if (ch->type != SR_CHANNEL_ANALOG)
+                       continue;
+               props->first_analog_channel = ch;
+               break;
+       }
+}
+
+static gboolean props_chk_1st_channel(struct df_arg_desc *args,
+       const struct sr_datafeed_analog *analog)
+{
+       struct sr_channel *ch;
+
+       if (!args || !analog || !analog->meaning)
+               return FALSE;
+       ch = g_slist_nth_data(analog->meaning->channels, 0);
+       if (!ch)
+               return FALSE;
+       return ch == args->props.first_analog_channel;
+}
+
+static void props_dump_details(struct df_arg_desc *args)
+{
+       struct input_stream_props *props;
+       size_t ch_count;
+       GSList *l;
+       const struct sr_channel *ch;
+       const char *type;
+
+       if (!args)
+               return;
+       props = &args->props;
+       if (props->samplerate)
+               printf("Samplerate: %" PRIu64 "\n", props->samplerate);
+       if (props->channels) {
+               ch_count = g_slist_length(props->channels);
+               printf("Channels: %zu\n", ch_count);
+               for (l = props->channels; l; l = l->next) {
+                       ch = l->data;
+                       if (ch->type == SR_CHANNEL_ANALOG)
+                               type = "analog";
+                       else
+                               type = "logic";
+                       printf("- %s: %s\n", ch->name, type);
+               }
+       }
+       if (props->unitsize)
+               printf("Logic unitsize: %zu\n", props->unitsize);
+       if (props->sample_count_logic)
+               printf("Logic sample count: %" PRIu64 "\n", props->sample_count_logic);
+       if (props->sample_count_analog)
+               printf("Analog sample count: %" PRIu64 "\n", props->sample_count_analog);
+       if (props->frame_count)
+               printf("Frame count: %" PRIu64 "\n", props->frame_count);
+       if (props->triggered)
+               printf("Trigger count: %" PRIu64 "\n", props->triggered);
+}
+
+static void props_cleanup(struct df_arg_desc *args)
+{
+       struct input_stream_props *props;
+
+       if (!args)
+               return;
+       props = &args->props;
+       g_slist_free(props->channels);
+       props->channels = NULL;
+       props->first_analog_channel = NULL;
+}
+
 void datafeed_in(const struct sr_dev_inst *sdi,
                const struct sr_datafeed_packet *packet, void *cb_data)
 {
@@ -164,6 +254,9 @@ void datafeed_in(const struct sr_dev_inst *sdi,
        const struct sr_datafeed_meta *meta;
        const struct sr_datafeed_logic *logic;
        const struct sr_datafeed_analog *analog;
+       struct df_arg_desc *df_arg;
+       int do_props;
+       struct input_stream_props *props;
        struct sr_session *session;
        struct sr_config *src;
        GSList *l;
@@ -183,10 +276,30 @@ void datafeed_in(const struct sr_dev_inst *sdi,
        if (packet->type != SR_DF_HEADER && !o)
                return;
 
-       session = cb_data;
+       /* Prepare to either process data, or "just" gather properties. */
+       df_arg = cb_data;
+       session = df_arg->session;
+       do_props = df_arg->do_props;
+       props = &df_arg->props;
+
        switch (packet->type) {
        case SR_DF_HEADER:
                g_debug("cli: Received SR_DF_HEADER.");
+               if (maybe_config_get(driver, sdi, NULL, SR_CONF_SAMPLERATE,
+                               &gvar) == SR_OK) {
+                       samplerate = g_variant_get_uint64(gvar);
+                       g_variant_unref(gvar);
+               }
+               if (do_props) {
+                       /* Setup variables for maximum code path re-use. */
+                       o = (void *)-1;
+                       limit_samples = 0;
+                       /* Start collecting input stream properties. */
+                       memset(props, 0, sizeof(*props));
+                       props->samplerate = samplerate;
+                       props_get_channels(df_arg, sdi);
+                       break;
+               }
                if (!(o = setup_output_format(sdi, &outfile)))
                        g_critical("Failed to initialize output module.");
 
@@ -197,12 +310,6 @@ void datafeed_in(const struct sr_dev_inst *sdi,
 
                rcvd_samples_logic = rcvd_samples_analog = 0;
 
-               if (maybe_config_get(driver, sdi, NULL, SR_CONF_SAMPLERATE,
-                               &gvar) == SR_OK) {
-                       samplerate = g_variant_get_uint64(gvar);
-                       g_variant_unref(gvar);
-               }
-
 #ifdef HAVE_SRD
                if (opt_pds) {
                        if (samplerate) {
@@ -229,6 +336,10 @@ void datafeed_in(const struct sr_dev_inst *sdi,
                        case SR_CONF_SAMPLERATE:
                                samplerate = g_variant_get_uint64(src->data);
                                g_debug("cli: Got samplerate %"PRIu64" Hz.", samplerate);
+                               if (do_props) {
+                                       props->samplerate = samplerate;
+                                       break;
+                               }
 #ifdef HAVE_SRD
                                if (opt_pds) {
                                        if (srd_session_metadata_set(srd_sess, SRD_CONF_SAMPLERATE,
@@ -241,6 +352,10 @@ void datafeed_in(const struct sr_dev_inst *sdi,
                        case SR_CONF_SAMPLE_INTERVAL:
                                samplerate = g_variant_get_uint64(src->data);
                                g_debug("cli: Got sample interval %"PRIu64" ms.", samplerate);
+                               if (do_props) {
+                                       props->samplerate = samplerate;
+                                       break;
+                               }
                                break;
                        default:
                                /* Unknown metadata is not an error. */
@@ -251,6 +366,10 @@ void datafeed_in(const struct sr_dev_inst *sdi,
 
        case SR_DF_TRIGGER:
                g_debug("cli: Received SR_DF_TRIGGER.");
+               if (do_props) {
+                       props->triggered++;
+                       break;
+               }
                triggered = 1;
                break;
 
@@ -261,6 +380,13 @@ void datafeed_in(const struct sr_dev_inst *sdi,
                if (logic->length == 0)
                        break;
 
+               if (do_props) {
+                       props_get_channels(df_arg, sdi);
+                       props->unitsize = logic->unitsize;
+                       props->sample_count_logic += logic->length / logic->unitsize;
+                       break;
+               }
+
                /* Don't store any samples until triggered. */
                if (opt_wait_trigger && !triggered)
                        break;
@@ -291,6 +417,15 @@ void datafeed_in(const struct sr_dev_inst *sdi,
                if (analog->num_samples == 0)
                        break;
 
+               if (do_props) {
+                       /* Only count the first analog channel. */
+                       props_get_channels(df_arg, sdi);
+                       if (!props_chk_1st_channel(df_arg, analog))
+                               break;
+                       props->sample_count_analog += analog->num_samples;
+                       break;
+               }
+
                if (limit_samples && rcvd_samples_analog >= limit_samples)
                        break;
 
@@ -303,13 +438,17 @@ void datafeed_in(const struct sr_dev_inst *sdi,
 
        case SR_DF_FRAME_END:
                g_debug("cli: Received SR_DF_FRAME_END.");
+               if (do_props) {
+                       props->frame_count++;
+                       break;
+               }
                break;
 
        default:
                break;
        }
 
-       if (o && !opt_pds) {
+       if (!do_props && o && !opt_pds) {
                if (sr_output_send(o, packet, &out) == SR_OK) {
                        if (oa && !out) {
                                /*
@@ -334,6 +473,12 @@ void datafeed_in(const struct sr_dev_inst *sdi,
        if (packet->type == SR_DF_END) {
                g_debug("cli: Received SR_DF_END.");
 
+               if (do_props) {
+                       props_dump_details(df_arg);
+                       props_cleanup(df_arg);
+                       o = NULL;
+               }
+
                if (o)
                        sr_output_free(o);
                o = NULL;
@@ -523,6 +668,7 @@ int set_dev_options(struct sr_dev_inst *sdi, GHashTable *args)
 
 void run_session(void)
 {
+       struct df_arg_desc df_arg;
        GSList *devices, *real_devices, *sd;
        GHashTable *devargs;
        GVariant *gvar;
@@ -537,6 +683,9 @@ void run_session(void)
        const struct sr_transform *t;
        GMainLoop *main_loop;
 
+       memset(&df_arg, 0, sizeof(df_arg));
+       df_arg.do_props = FALSE;
+
        devices = device_scan();
        if (!devices) {
                g_critical("No devices found.");
@@ -589,7 +738,9 @@ void run_session(void)
        g_slist_free(real_devices);
 
        sr_session_new(sr_ctx, &session);
-       sr_session_datafeed_callback_add(session, datafeed_in, session);
+       df_arg.session = session;
+       sr_session_datafeed_callback_add(session, datafeed_in, &df_arg);
+       df_arg.session = NULL;
 
        if (sr_dev_open(sdi) != SR_OK) {
                g_critical("Failed to open device.");
index 12a1462fe2a43de2b9504b00f33c26b6ff84def4..37746e3b8b25c3a38d09ecbe0b2e5fa22c7a0cfc 100644 (file)
@@ -58,6 +58,20 @@ GSList *device_scan(void);
 struct sr_channel_group *select_channel_group(struct sr_dev_inst *sdi);
 
 /* session.c */
+struct df_arg_desc {
+       struct sr_session *session;
+       int do_props;
+       struct input_stream_props {
+               uint64_t samplerate;
+               GSList *channels;
+               const struct sr_channel *first_analog_channel;
+               size_t unitsize;
+               uint64_t sample_count_logic;
+               uint64_t sample_count_analog;
+               uint64_t frame_count;
+               uint64_t triggered;
+       } props;
+};
 void datafeed_in(const struct sr_dev_inst *sdi,
                const struct sr_datafeed_packet *packet, void *cb_data);
 int opt_to_gvar(char *key, char *value, struct sr_config *src);
@@ -65,7 +79,7 @@ int set_dev_options(struct sr_dev_inst *sdi, GHashTable *args);
 void run_session(void);
 
 /* input.c */
-void load_input_file(void);
+void load_input_file(gboolean do_props);
 
 /* decode.c */
 #ifdef HAVE_SRD