+
+ case SR_DF_FRAME_END:
+ g_debug("cli: received SR_DF_FRAME_END");
+ if (o->format->event) {
+ o->format->event(o, SR_DF_FRAME_END, &output_buf,
+ &output_len);
+ if (output_buf) {
+ fwrite(output_buf, 1, output_len, outfile);
+ fflush(outfile);
+ g_free(output_buf);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (o && o->format->receive) {
+ if (o->format->receive(o, sdi, packet, &out) == SR_OK && out) {
+ fwrite(out->str, 1, out->len, outfile);
+ fflush(outfile);
+ g_string_free(out, TRUE);
+ }
+ }
+
+ /* SR_DF_END needs to be handled after the output module's receive()
+ * is called, so it can properly clean up that module etc. */
+ if (packet->type == SR_DF_END) {
+ g_debug("cli: Received SR_DF_END");
+
+ if (o->format->event) {
+ o->format->event(o, SR_DF_END, &output_buf, &output_len);
+ if (output_buf) {
+ if (outfile)
+ fwrite(output_buf, 1, output_len, outfile);
+ g_free(output_buf);
+ output_len = 0;
+ }
+ }
+
+ if (limit_samples && received_samples < limit_samples)
+ g_warning("Device only sent %" PRIu64 " samples.",
+ received_samples);
+
+ if (opt_continuous)
+ g_warning("Device stopped after %" PRIu64 " samples.",
+ received_samples);
+
+ g_array_free(logic_probelist, TRUE);
+
+ if (o->format->cleanup)
+ o->format->cleanup(o);
+ g_free(o);
+ o = NULL;
+
+ if (outfile && outfile != stdout)
+ fclose(outfile);
+
+ if (opt_output_file && default_output_format && savebuf->len) {
+ if (sr_session_save(opt_output_file, sdi, savebuf->data,
+ unitsize, savebuf->len / unitsize) != SR_OK)
+ g_critical("Failed to save session.");
+ g_byte_array_free(savebuf, FALSE);
+ }
+ }
+
+}
+
+#ifdef HAVE_SRD
+static int opts_to_gvar(struct srd_decoder *dec, GHashTable *hash,
+ GHashTable **options)
+{
+ struct srd_decoder_option *o;
+ GSList *optl;
+ GVariant *gvar;
+ gint64 val_int;
+ int ret;
+ char *val_str, *conv;
+
+ ret = TRUE;
+ *options = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify)g_variant_unref);
+
+ for (optl = dec->options; optl; optl = optl->next) {
+ o = optl->data;
+ if (!(val_str = g_hash_table_lookup(hash, o->id)))
+ /* Not specified. */
+ continue;
+ if (g_variant_is_of_type(o->def, G_VARIANT_TYPE_STRING)) {
+ gvar = g_variant_new_string(val_str);
+ } else if (g_variant_is_of_type(o->def, G_VARIANT_TYPE_INT64)) {
+ val_int = strtoll(val_str, &conv, 0);
+ if (!conv || conv == val_str) {
+ g_critical("Protocol decoder '%s' option '%s' "
+ "requires a number.", dec->name, o->id);
+ ret = FALSE;
+ break;
+ }
+ gvar = g_variant_new_int64(val_int);
+ } else {
+ g_critical("Unsupported type for option '%s' (%s)",
+ o->id, g_variant_get_type_string(o->def));
+ ret = FALSE;
+ break;
+ }
+ g_variant_ref_sink(gvar);
+ g_hash_table_insert(*options, g_strdup(o->id), gvar);
+ g_hash_table_remove(hash, o->id);
+ }
+
+ return ret;
+}
+
+static int probes_to_gvar(struct srd_decoder *dec, GHashTable *hash,
+ GHashTable **probes)
+{
+ struct srd_probe *p;
+ GSList *all_probes, *l;
+ GVariant *gvar;
+ gint32 val_int;
+ int ret;
+ char *val_str, *conv;
+
+ ret = TRUE;
+ *probes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify)g_variant_unref);
+
+ 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) {
+ 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);
+ }
+ g_slist_free(all_probes);
+
+ return ret;
+}
+
+/* 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.
+ */
+static int register_pds(struct sr_dev *dev, const char *pdstring)
+{
+ struct srd_decoder *dec;
+ GHashTable *pd_opthash, *options, *probes;
+ GList *leftover, *l;
+ struct srd_decoder_inst *di;
+ int ret;
+ char **pdtokens, **pdtok, *pd_name;
+
+ (void)dev;
+
+ pd_ann_visible = g_hash_table_new_full(g_str_hash, g_int_equal,
+ g_free, NULL);
+ ret = 0;
+ pd_name = NULL;
+ pd_opthash = options = probes = NULL;
+ pdtokens = g_strsplit(pdstring, ",", 0);
+ for (pdtok = pdtokens; *pdtok; pdtok++) {
+ if (!(pd_opthash = parse_generic_arg(*pdtok, TRUE))) {
+ g_critical("Invalid protocol decoder option '%s'.", *pdtok);
+ break;
+ }
+
+ pd_name = g_strdup(g_hash_table_lookup(pd_opthash, "sigrok_key"));
+ g_hash_table_remove(pd_opthash, "sigrok_key");
+ if (srd_decoder_load(pd_name) != SRD_OK) {
+ g_critical("Failed to load protocol decoder %s.", pd_name);
+ ret = 1;
+ break;
+ }
+ dec = srd_decoder_get_by_id(pd_name);
+
+ /* Convert decoder option and probe values to GVariant. */
+ if (!opts_to_gvar(dec, pd_opthash, &options)) {
+ ret = 1;
+ break;
+ }
+ if (!probes_to_gvar(dec, pd_opthash, &probes)) {
+ ret = 1;
+ break;
+ }
+ if (g_hash_table_size(pd_opthash) > 0) {
+ leftover = g_hash_table_get_keys(pd_opthash);
+ for (l = leftover; l; l = l->next)
+ g_critical("Unknown option or probe '%s'", (char *)l->data);
+ g_list_free(leftover);
+ break;
+ }
+
+ if (!(di = srd_inst_new(srd_sess, pd_name, options))) {
+ g_critical("Failed to instantiate protocol decoder %s.", pd_name);
+ ret = 1;
+ break;
+ }
+
+ /* 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.
+ */
+ 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);
+ if (pd_opthash)
+ g_hash_table_destroy(pd_opthash);
+ if (options)
+ g_hash_table_destroy(options);
+ if (probes)
+ g_hash_table_destroy(probes);
+ if (pd_name)
+ g_free(pd_name);
+
+ return ret;
+}
+
+int setup_pd_stack(void)
+{
+ 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) {
+ if (opt_pd_stack) {
+ /* A stack setup was specified, use that. */
+ g_strfreev(pds);
+ pds = g_strsplit(opt_pd_stack, ",", 0);
+ if (g_strv_length(pds) < 2) {
+ g_strfreev(pds);
+ g_critical("Specify at least two protocol decoders to stack.");
+ return 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(void)
+{
+ GSList *l;
+ struct srd_decoder *dec;
+ int ann_class;
+ char **pds, **pdtok, **keyval, **ann_descr;
+
+ /* Set up custom list of PDs and annotations to show. */
+ pds = g_strsplit(opt_pd_annotations, ",", 0);
+ for (pdtok = pds; *pdtok && **pdtok; pdtok++) {
+ keyval = g_strsplit(*pdtok, "=", 0);
+ if (!(dec = srd_decoder_get_by_id(keyval[0]))) {
+ g_critical("Protocol decoder '%s' not found.", keyval[0]);
+ return 1;
+ }
+ if (!dec->annotations) {
+ g_critical("Protocol decoder '%s' has no annotations.", keyval[0]);
+ return 1;
+ }
+ ann_class = 0;
+ if (g_strv_length(keyval) == 2) {
+ for (l = dec->annotations; l; l = l->next, ann_class++) {
+ ann_descr = l->data;
+ if (!canon_cmp(ann_descr[0], keyval[1]))
+ /* Found it. */
+ break;
+ }
+ if (!l) {
+ g_critical("Annotation '%s' not found "
+ "for protocol decoder '%s'.", keyval[1], keyval[0]);
+ return 1;
+ }
+ g_debug("cli: Showing protocol decoder %s annotation "
+ "class %d (%s).", keyval[0], ann_class, ann_descr[0]);
+ } else {
+ /* No class specified: show all of them. */
+ ann_class = -1;
+ g_debug("cli: Showing all annotation classes for protocol "
+ "decoder %s.", keyval[0]);
+ }
+ g_hash_table_insert(pd_ann_visible, g_strdup(keyval[0]), GINT_TO_POINTER(ann_class));
+ g_strfreev(keyval);
+ }
+ g_strfreev(pds);
+
+ return 0;
+}
+
+int setup_pd_meta(void)
+{
+ struct srd_decoder *dec;
+ char **pds, **pdtok;
+
+ pd_meta_visible = g_hash_table_new_full(g_str_hash, g_int_equal,
+ g_free, NULL);
+ pds = g_strsplit(opt_pd_meta, ",", 0);
+ for (pdtok = pds; *pdtok && **pdtok; pdtok++) {
+ if (!(dec = srd_decoder_get_by_id(*pdtok))) {
+ g_critical("Protocol decoder '%s' not found.", *pdtok);
+ return 1;
+ }
+ g_debug("cli: Showing protocol decoder meta output from '%s'.", *pdtok);
+ g_hash_table_insert(pd_meta_visible, g_strdup(*pdtok), NULL);
+ }
+ g_strfreev(pds);
+
+ return 0;
+}
+
+int setup_pd_binary(void)
+{
+ GSList *l;
+ struct srd_decoder *dec;
+ int bin_class;
+ char **pds, **pdtok, **keyval, *bin_name;
+
+ pd_binary_visible = g_hash_table_new_full(g_str_hash, g_int_equal,
+ g_free, NULL);
+ pds = g_strsplit(opt_pd_binary, ",", 0);
+ for (pdtok = pds; *pdtok && **pdtok; pdtok++) {
+ keyval = g_strsplit(*pdtok, "=", 0);
+ if (!(dec = srd_decoder_get_by_id(keyval[0]))) {
+ g_critical("Protocol decoder '%s' not found.", keyval[0]);
+ return 1;
+ }
+ if (!dec->binary) {
+ g_critical("Protocol decoder '%s' has no binary output.", keyval[0]);
+ return 1;
+ }
+ bin_class = 0;
+ 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]))
+ /* Found it. */
+ break;
+ }
+ if (!l) {
+ g_critical("binary output '%s' not found "
+ "for protocol decoder '%s'.", keyval[1], keyval[0]);
+ return 1;
+ }
+ g_debug("cli: Showing protocol decoder %s binary class "
+ "%d (%s).", keyval[0], bin_class, bin_name);
+ } else {
+ /* No class specified: output all of them. */
+ bin_class = -1;
+ g_debug("cli: Showing all binary classes for protocol "
+ "decoder %s.", keyval[0]);
+ }
+ g_hash_table_insert(pd_binary_visible, g_strdup(keyval[0]), GINT_TO_POINTER(bin_class));
+ g_strfreev(keyval);