Add a parameter to csv output module, which allows to specify the type of data fed to it. By default the module assumes it receives logic data for backwards compatibility.
Signed-off-by: Bartosz Golaszewski <bgolaszew...@baylibre.com> --- Initially I thought it would be possible to work with both data types simultaneously, but since logic and analog packets can arrive at different times and contain different number of samples it's not very feasible. NOTE: In order to output proper csv lines while not having to store data in memory at the same time, this module assumes that each sample comes from a subsequent channel. This means - it will not work properly with the demo driver in its current form. src/output/csv.c | 128 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 102 insertions(+), 26 deletions(-) diff --git a/src/output/csv.c b/src/output/csv.c index 77b6228..5aebd9f 100644 --- a/src/output/csv.c +++ b/src/output/csv.c @@ -2,6 +2,7 @@ * This file is part of the libsigrok project. * * Copyright (C) 2011 Uwe Hermann <u...@hermann-uwe.de> + * Copyright (C) 2015 Bartosz Golaszewski <bgolaszew...@baylibre.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 @@ -29,10 +30,17 @@ struct context { unsigned int num_enabled_channels; + unsigned int channel_counter; uint64_t samplerate; char separator; gboolean header_done; int *channel_index; + int mode; +}; + +enum { + MODE_LOGIC, + MODE_ANALOG, }; /* @@ -51,6 +59,7 @@ static int init(struct sr_output *o, GHashTable *options) { struct context *ctx; struct sr_channel *ch; + const char *s; GSList *l; int i; @@ -63,25 +72,31 @@ static int init(struct sr_output *o, GHashTable *options) o->priv = ctx; ctx->separator = ','; + s = g_variant_get_string(g_hash_table_lookup(options, "mode"), NULL); + if (!strcmp(s, "analog")) + ctx->mode = MODE_ANALOG; + else /* default: "logic" */ + ctx->mode = MODE_LOGIC; + /* Get the number of channels, and the unitsize. */ for (l = o->sdi->channels; l; l = l->next) { ch = l->data; - if (ch->type != SR_CHANNEL_LOGIC) - continue; if (!ch->enabled) continue; - ctx->num_enabled_channels++; + if ((ch->type == SR_CHANNEL_LOGIC && ctx->mode == MODE_LOGIC) || + (ch->type == SR_CHANNEL_ANALOG && ctx->mode == MODE_ANALOG)) + ctx->num_enabled_channels++; } ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels); /* Once more to map the enabled channels. */ for (i = 0, l = o->sdi->channels; l; l = l->next) { ch = l->data; - if (ch->type != SR_CHANNEL_LOGIC) - continue; if (!ch->enabled) continue; - ctx->channel_index[i++] = ch->index; + if ((ch->type == SR_CHANNEL_LOGIC && ctx->mode == MODE_LOGIC) || + (ch->type == SR_CHANNEL_ANALOG && ctx->mode == MODE_ANALOG)) + ctx->channel_index[i++] = ch->index; } return SR_OK; @@ -112,11 +127,11 @@ static GString *gen_header(const struct sr_output *o) ctx->num_enabled_channels, num_channels); for (i = 0, l = o->sdi->channels; l; l = l->next, i++) { ch = l->data; - if (ch->type != SR_CHANNEL_LOGIC) - continue; if (!ch->enabled) continue; - g_string_append_printf(header, " %s,", ch->name); + if ((ch->type == SR_CHANNEL_LOGIC && ctx->mode == MODE_LOGIC) || + (ch->type == SR_CHANNEL_ANALOG && ctx->mode == MODE_ANALOG)) + g_string_append_printf(header, " %s,", ch->name); } if (o->sdi->channels) /* Drop last separator. */ @@ -139,16 +154,41 @@ static GString *gen_header(const struct sr_output *o) return header; } +static GString *make_header(const struct sr_output *o, struct context *ctx) +{ + if (!ctx->header_done) { + ctx->header_done = TRUE; + return gen_header(o); + } else { + return g_string_sized_new(512); + } +} + +/* Returns TRUE when all channels are done. */ +static gboolean fin_line(struct context *ctx, GString *out) +{ + if ((ctx->channel_counter+1) >= ctx->num_enabled_channels) { + ctx->channel_counter = 0; + /* Drop last separator. */ + g_string_truncate(out, (out)->len - 1); + g_string_append_c(out, '\n'); + return TRUE; + } + + return FALSE; +} + static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet, GString **out) { const struct sr_datafeed_meta *meta; const struct sr_datafeed_logic *logic; + const struct sr_datafeed_analog *analog; const struct sr_config *src; GSList *l; struct context *ctx; - int idx; - uint64_t i, j; + int idx, ret = SR_OK; + uint64_t i, j, ns; gchar *p, c; *out = NULL; @@ -168,32 +208,50 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p } break; case SR_DF_LOGIC: + if (ctx->mode != MODE_LOGIC) + break; + logic = packet->payload; - if (!ctx->header_done) { - *out = gen_header(o); - ctx->header_done = TRUE; - } else { - *out = g_string_sized_new(512); - } + *out = make_header(o, ctx); for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) { - for (j = 0; j < ctx->num_enabled_channels; j++) { - idx = ctx->channel_index[j]; + for (j = 0; j < logic->unitsize * 8; j++, ctx->channel_counter++) { + idx = ctx->channel_index[ctx->channel_counter]; p = logic->data + i + idx / 8; c = *p & (1 << (idx % 8)); g_string_append_c(*out, c ? '1' : '0'); g_string_append_c(*out, ctx->separator); + + if (fin_line(ctx, *out)) + break; } - if (j) { - /* Drop last separator. */ - g_string_truncate(*out, (*out)->len - 1); - } - g_string_append_printf(*out, "\n"); } break; + case SR_DF_ANALOG: + if (ctx->mode != MODE_ANALOG) + break; + + analog = packet->payload; + *out = make_header(o, ctx); + + ns = analog->num_samples; + for (i = 0; i < ns; i++, ctx->channel_counter++) { + idx = ctx->channel_index[ctx->channel_counter]; + g_string_append_printf(*out, "%f", analog->data[i]); + g_string_append_c(*out, ctx->separator); + + if (fin_line(ctx, *out)) + break; + } + break; + /* TODO case SR_DF_ANALOG2: */ + case SR_DF_FRAME_BEGIN: + case SR_DF_FRAME_END: + ret = SR_OK_CONTINUE; + break; } - return SR_OK; + return ret; } static int cleanup(struct sr_output *o) @@ -213,12 +271,30 @@ static int cleanup(struct sr_output *o) return SR_OK; } +static struct sr_option options[] = { + { "mode", "Mode", "Analog output mode", 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("logic")); + options[0].values = g_slist_append(options[0].values, + g_variant_ref_sink(g_variant_new_string("logic"))); + options[0].values = g_slist_append(options[0].values, + g_variant_ref_sink(g_variant_new_string("analog"))); + } + + return options; +} + SR_PRIV struct sr_output_module output_csv = { .id = "csv", .name = "CSV", .desc = "Comma-separated values", .exts = (const char*[]){"csv", NULL}, - .options = NULL, + .options = get_options, .init = init, .receive = receive, .cleanup = cleanup, -- 2.1.4 ------------------------------------------------------------------------------ Dive into the World of Parallel Programming. The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net/ _______________________________________________ sigrok-devel mailing list sigrok-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/sigrok-devel