analog.c 5.55 KB
Newer Older
1
/*
2
 * This file is part of the libsigrok project.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

20
#include <config.h>
21 22
#include <stdlib.h>
#include <string.h>
23
#include <math.h>
24
#include <glib.h>
25
#include <libsigrok/libsigrok.h>
26
#include "libsigrok-internal.h"
27

28
#define LOG_PREFIX "output/analog"
29 30

struct context {
31 32
	int num_enabled_channels;
	GPtrArray *channellist;
33
	int digits;
34
	float *fdata;
35 36 37 38 39
};

enum {
	DIGITS_ALL,
	DIGITS_SPEC,
40 41
};

42
static int init(struct sr_output *o, GHashTable *options)
43 44
{
	struct context *ctx;
45
	struct sr_channel *ch;
46
	GSList *l;
47
	const char *s;
48

49 50 51
	if (!o || !o->sdi)
		return SR_ERR_ARG;

52
	o->priv = ctx = g_malloc0(sizeof(struct context));
53 54 55 56 57
	s = g_variant_get_string(g_hash_table_lookup(options, "digits"), NULL);
	if (!strcmp(s, "all"))
		ctx->digits = DIGITS_ALL;
	else
		ctx->digits = DIGITS_SPEC;
58

59 60 61 62 63
	/* Get the number of channels and their names. */
	ctx->channellist = g_ptr_array_new();
	for (l = o->sdi->channels; l; l = l->next) {
		ch = l->data;
		if (!ch || !ch->enabled)
64
			continue;
65 66
		g_ptr_array_add(ctx->channellist, ch->name);
		ctx->num_enabled_channels++;
67
	}
68
	ctx->fdata = NULL;
69 70 71 72

	return SR_OK;
}

73
static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
74
		GString **out)
75
{
76
	struct context *ctx;
77
	const struct sr_datafeed_analog *analog;
78 79 80
	const struct sr_datafeed_meta *meta;
	const struct sr_config *src;
	const struct sr_key_info *srci;
81
	struct sr_channel *ch;
82
	GSList *l;
83 84
	float *fdata;
	unsigned int i;
85
	int num_channels, c, ret, digits, actual_digits;
86
	char *number, *suffix;
87

88
	*out = NULL;
89
	if (!o || !o->sdi)
90
		return SR_ERR_ARG;
91
	ctx = o->priv;
92 93 94

	switch (packet->type) {
	case SR_DF_FRAME_BEGIN:
95
		*out = g_string_new("FRAME-BEGIN\n");
96 97
		break;
	case SR_DF_FRAME_END:
98
		*out = g_string_new("FRAME-END\n");
99
		break;
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
	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, "%" PRIu64,
					g_variant_get_uint64(src->data));
			}
			g_string_append(*out, "\n");
		}
		break;
122 123 124
	case SR_DF_ANALOG:
		analog = packet->payload;
		num_channels = g_slist_length(analog->meaning->channels);
125
		if (!(fdata = g_try_realloc(ctx->fdata,
126
						analog->num_samples * num_channels * sizeof(float))))
127
			return SR_ERR_MALLOC;
128
		ctx->fdata = fdata;
129
		if ((ret = sr_analog_to_float(analog, fdata)) != SR_OK)
130 131
			return ret;
		*out = g_string_sized_new(512);
132
		if (analog->encoding->is_digits_decimal) {
133
			if (ctx->digits == DIGITS_ALL)
134
				digits = analog->encoding->digits;
135
			else
136
				digits = analog->spec->spec_digits;
137 138 139 140
		} else {
			/* TODO we don't know how to print by number of bits yet. */
			digits = 6;
		}
141
		gboolean si_friendly = sr_analog_si_prefix_friendly(analog->meaning->unit);
142 143 144
		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++) {
145
				float value = fdata[i * num_channels + c];
146
				const char *prefix = "";
147
				actual_digits = digits;
148
				if (si_friendly)
149
					prefix = sr_analog_si_prefix(&value, &actual_digits);
150 151
				ch = l->data;
				g_string_append_printf(*out, "%s: ", ch->name);
152
				number = g_strdup_printf("%.*f", MAX(actual_digits, 0), value);
153
				g_string_append(*out, number);
154
				g_free(number);
155
				g_string_append(*out, " ");
156
				g_string_append(*out, prefix);
157 158
				g_string_append(*out, suffix);
				g_string_append(*out, "\n");
159 160
			}
		}
161
		g_free(suffix);
162 163 164
		break;
	}

165
	return SR_OK;
166 167
}

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
static struct sr_option options[] = {
	{ "digits", "Digits", "Digits to show", NULL, NULL },
	ALL_ZERO
};

static const struct sr_option *get_options(void)
{
	if (!options[0].def) {
		options[0].def = g_variant_ref_sink(g_variant_new_string("all"));
		options[0].values = g_slist_append(options[0].values,
				g_variant_ref_sink(g_variant_new_string("all")));
		options[0].values = g_slist_append(options[0].values,
				g_variant_ref_sink(g_variant_new_string("spec")));
	}

	return options;
}

186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
static int cleanup(struct sr_output *o)
{
	struct context *ctx;

	if (!o || !o->sdi)
		return SR_ERR_ARG;
	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);
	g_free(ctx->fdata);
	g_free(ctx);
	o->priv = NULL;

	return SR_OK;
}

204
SR_PRIV struct sr_output_module output_analog = {
205
	.id = "analog",
206 207
	.name = "Analog",
	.desc = "Analog data and types",
208
	.exts = NULL,
Soeren Apel's avatar
Soeren Apel committed
209
	.flags = 0,
210
	.options = get_options,
211
	.init = init,
212
	.receive = receive,
213 214
	.cleanup = cleanup
};