]> sigrok.org Git - libsigrok.git/blobdiff - src/output/analog.c
analog: avoid double free in '-O analog' shutdown path
[libsigrok.git] / src / output / analog.c
index 5e2b7cd527b6ce0c60c7b1f3bafbb44e60d862ed..d665b8ec2edaa81182adc50387b0538d6dc70dfe 100644 (file)
@@ -27,6 +27,8 @@
 
 #define LOG_PREFIX "output/analog"
 
+#define BIN_TO_DEC_DIGITS (log(2) / log(10))
+
 struct context {
        int num_enabled_channels;
        GPtrArray *channellist;
@@ -75,11 +77,14 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p
 {
        struct context *ctx;
        const struct sr_datafeed_analog *analog;
+       const struct sr_datafeed_meta *meta;
+       const struct sr_config *src;
+       const struct sr_key_info *srci;
        struct sr_channel *ch;
        GSList *l;
        float *fdata;
        unsigned int i;
-       int num_channels, c, ret, digits;
+       int num_channels, c, ret, digits, actual_digits;
        char *number, *suffix;
 
        *out = NULL;
@@ -94,6 +99,32 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p
        case SR_DF_FRAME_END:
                *out = g_string_new("FRAME-END\n");
                break;
+       case SR_DF_META:
+               meta = packet->payload;
+               for (l = meta->config; l; l = l->next) {
+                       src = l->data;
+                       if (!(srci = sr_key_info_get(SR_KEY_CONFIG, src->key)))
+                               return SR_ERR;
+                       *out = g_string_sized_new(512);
+                       g_string_append(*out, "META ");
+                       g_string_append_printf(*out, "%s: ", srci->id);
+                       if (srci->datatype == SR_T_BOOL) {
+                               g_string_append_printf(*out, "%u",
+                                       g_variant_get_boolean(src->data));
+                       } else if (srci->datatype == SR_T_FLOAT) {
+                               g_string_append_printf(*out, "%f",
+                                       g_variant_get_double(src->data));
+                       } else if (srci->datatype == SR_T_UINT64) {
+                               g_string_append_printf(*out, "%"
+                                       G_GUINT64_FORMAT,
+                                       g_variant_get_uint64(src->data));
+                       } else if (srci->datatype == SR_T_STRING) {
+                               g_string_append_printf(*out, "%s",
+                                       g_variant_get_string(src->data, NULL));
+                       }
+                       g_string_append(*out, "\n");
+               }
+               break;
        case SR_DF_ANALOG:
                analog = packet->payload;
                num_channels = g_slist_length(analog->meaning->channels);
@@ -104,23 +135,24 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p
                if ((ret = sr_analog_to_float(analog, fdata)) != SR_OK)
                        return ret;
                *out = g_string_sized_new(512);
-               if (analog->encoding->is_digits_decimal) {
-                       if (ctx->digits == DIGITS_ALL)
-                               digits = analog->encoding->digits;
-                       else
-                               digits = analog->spec->spec_digits;
-               } else {
-                       /* TODO we don't know how to print by number of bits yet. */
-                       digits = 6;
-               }
+               if (ctx->digits == DIGITS_ALL)
+                       digits = analog->encoding->digits;
+               else
+                       digits = analog->spec->spec_digits;
+               if (!analog->encoding->is_digits_decimal)
+                       digits = copysign(ceil(abs(digits) * BIN_TO_DEC_DIGITS), digits);
+               gboolean si_friendly = sr_analog_si_prefix_friendly(analog->meaning->unit);
                sr_analog_unit_to_string(analog, &suffix);
                for (i = 0; i < analog->num_samples; i++) {
                        for (l = analog->meaning->channels, c = 0; l; l = l->next, c++) {
                                float value = fdata[i * num_channels + c];
-                               const char *prefix = sr_analog_si_prefix(&value, &digits);
+                               const char *prefix = "";
+                               actual_digits = digits;
+                               if (si_friendly)
+                                       prefix = sr_analog_si_prefix(&value, &actual_digits);
                                ch = l->data;
                                g_string_append_printf(*out, "%s: ", ch->name);
-                               number = g_strdup_printf("%.*f", MAX(digits, 0), value);
+                               number = g_strdup_printf("%.*f", MAX(actual_digits, 0), value);
                                g_string_append(*out, number);
                                g_free(number);
                                g_string_append(*out, " ");
@@ -163,8 +195,14 @@ static int cleanup(struct sr_output *o)
        ctx = o->priv;
 
        g_ptr_array_free(ctx->channellist, 1);
-       g_variant_unref(options[0].def);
-       g_slist_free_full(options[0].values, (GDestroyNotify)g_variant_unref);
+       if (options[0].def) {
+               g_variant_unref(options[0].def);
+               options[0].def = NULL;
+       }
+       if (options[0].values) {
+               g_slist_free_full(options[0].values, (GDestroyNotify)g_variant_unref);
+               options[0].values = NULL;
+       }
        g_free(ctx->fdata);
        g_free(ctx);
        o->priv = NULL;
@@ -175,7 +213,7 @@ static int cleanup(struct sr_output *o)
 SR_PRIV struct sr_output_module output_analog = {
        .id = "analog",
        .name = "Analog",
-       .desc = "Analog data and types",
+       .desc = "ASCII analog data values and units",
        .exts = NULL,
        .flags = 0,
        .options = get_options,