X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Foutput%2Fcsv.c;h=db023a476050c59ffdb88ef144c8a84377413442;hb=6525d819eef098a43b1f438ae4af50e67c9c4335;hp=86df2613565af110e9391aa7dc2526b50d8850da;hpb=d686c5ec462a4044e049931e57d60e9d08df8cde;p=libsigrok.git diff --git a/src/output/csv.c b/src/output/csv.c index 86df2613..db023a47 100644 --- a/src/output/csv.c +++ b/src/output/csv.c @@ -18,11 +18,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include #include -#include "config.h" /* Needed for PACKAGE_STRING and others. */ -#include "libsigrok.h" +#include #include "libsigrok-internal.h" #define LOG_PREFIX "output/csv" @@ -32,7 +32,13 @@ struct context { uint64_t samplerate; char separator; gboolean header_done; - int *channel_index; + struct sr_channel **channels; + + /* For analog measurements split into frames, not packets. */ + struct sr_channel **analog_channels; + float *analog_vals; /* Analog values stored until the end of the frame. */ + unsigned int num_analog_channels; + gboolean inframe; }; /* @@ -52,7 +58,7 @@ static int init(struct sr_output *o, GHashTable *options) struct context *ctx; struct sr_channel *ch; GSList *l; - int i; + int i, j; (void)options; @@ -66,22 +72,31 @@ static int init(struct sr_output *o, GHashTable *options) /* 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->enabled) { + if (ch->type == SR_CHANNEL_LOGIC || + ch->type == SR_CHANNEL_ANALOG) + ctx->num_enabled_channels++; + if (ch->type == SR_CHANNEL_ANALOG) + ctx->num_analog_channels++; + } } - ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels); + ctx->channels = g_malloc(sizeof(struct sr_channel *) + * ctx->num_enabled_channels); + ctx->analog_channels = g_malloc(sizeof(struct sr_channel *) + * ctx->num_analog_channels); + ctx->analog_vals = g_malloc(sizeof(float) * ctx->num_analog_channels); /* Once more to map the enabled channels. */ - for (i = 0, l = o->sdi->channels; l; l = l->next) { + for (i = 0, l = o->sdi->channels, j = 0; 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->enabled) { + if (ch->type == SR_CHANNEL_LOGIC || + ch->type == SR_CHANNEL_ANALOG) + ctx->channels[i++] = ch; + if (ch->type == SR_CHANNEL_ANALOG) + ctx->analog_channels[j++] = ch; + } + } return SR_OK; @@ -103,8 +118,8 @@ static GString *gen_header(const struct sr_output *o) /* Some metadata */ t = time(NULL); - g_string_append_printf(header, "; CSV, generated by %s on %s", - PACKAGE_STRING, ctime(&t)); + g_string_append_printf(header, "; CSV, generated by %s %s on %s", + PACKAGE_NAME, SR_PACKAGE_VERSION_STRING, ctime(&t)); /* Columns / channels */ num_channels = g_slist_length(o->sdi->channels); @@ -112,11 +127,10 @@ 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->enabled && + (ch->type == SR_CHANNEL_LOGIC || + ch->type == SR_CHANNEL_ANALOG)) + g_string_append_printf(header, " %s,", ch->name); } if (o->sdi->channels) /* Drop last separator. */ @@ -139,17 +153,56 @@ static GString *gen_header(const struct sr_output *o) return header; } +static void init_output(GString **out, struct context *ctx, + const struct sr_output *o) +{ + if (!ctx->header_done) { + *out = gen_header(o); + ctx->header_done = TRUE; + } else { + *out = g_string_sized_new(512); + } +} + +static void handle_analog_frame(struct context *ctx, GSList *channels, + unsigned int num_samples, float *data) +{ + unsigned int numch, nums, i, j, s; + GSList *l; + + numch = g_slist_length(channels); + if (num_samples > numch) + nums = num_samples / numch; + else + nums = 1; + + s = 0; + l = channels; + for (i = 0; i < nums; i++) { + for (j = 0; j < ctx->num_analog_channels; j++) { + if (ctx->analog_channels[j] == l->data) + ctx->analog_vals[j] = data[s++]; + } + l = l->next; + } +} + 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_old *analog_old; + const struct sr_datafeed_analog *analog; const struct sr_config *src; - GSList *l; + unsigned int num_samples; + float *data; + GSList *l, *channels; struct context *ctx; int idx; - uint64_t i, j; + uint64_t i, j, k, nums, numch; gchar *p, c; + int ret = SR_OK; *out = NULL; if (!o || !o->sdi) @@ -167,21 +220,45 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p ctx->samplerate = g_variant_get_uint64(src->data); } break; + case SR_DF_FRAME_BEGIN: + /* + * Special case - we start gathering data from analog channels + * and wait for SR_DF_FRAME_END to dump it. + */ + memset(ctx->analog_vals, 0, sizeof(float) * ctx->num_analog_channels); + ctx->inframe = TRUE; + ret = SR_OK; + break; + case SR_DF_FRAME_END: + /* + * Dump gathered data. + */ + init_output(out, ctx, o); + + for (i = 0, j = 0; i < ctx->num_enabled_channels; i++) { + if (ctx->channels[i]->type == SR_CHANNEL_ANALOG) { + g_string_append_printf(*out, "%f", + ctx->analog_vals[j++]); + } + g_string_append_c(*out, ctx->separator); + } + g_string_truncate(*out, (*out)->len - 1); + g_string_append_printf(*out, "\n"); + + ctx->inframe = FALSE; + break; case SR_DF_LOGIC: logic = packet->payload; - if (!ctx->header_done) { - *out = gen_header(o); - ctx->header_done = TRUE; - } else { - *out = g_string_sized_new(512); - } + init_output(out, ctx, o); 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]; - p = logic->data + i + idx / 8; - c = *p & (1 << (idx % 8)); - g_string_append_c(*out, c ? '1' : '0'); + if (ctx->channels[j]->type == SR_CHANNEL_LOGIC) { + idx = ctx->channels[j]->index; + 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 (j) { @@ -191,9 +268,62 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p g_string_append_printf(*out, "\n"); } break; + case SR_DF_ANALOG_OLD: + case SR_DF_ANALOG: + analog_old = packet->payload; + analog = packet->payload; + + if (packet->type == SR_DF_ANALOG_OLD) { + channels = analog_old->channels; + numch = g_slist_length(channels); + num_samples = analog_old->num_samples; + data = analog_old->data; + } else { + channels = analog->meaning->channels; + numch = g_slist_length(channels); + num_samples = analog->num_samples; + data = g_malloc(sizeof(float) * num_samples * numch); + ret = sr_analog_to_float(analog, data); + if (ret != SR_OK) + return ret; + } + + if (ctx->inframe) { + handle_analog_frame(ctx, channels, num_samples, data); + break; + } + + init_output(out, ctx, o); + k = 0; + l = NULL; + + if (num_samples > numch) + nums = num_samples / numch; + else + nums = 1; + + for (i = 0; i < nums; i++) { + for (j = 0; j < ctx->num_enabled_channels; j++) { + if (ctx->channels[j]->type == SR_CHANNEL_ANALOG) { + if (!l) + l = channels; + + if (ctx->channels[j] == l->data) { + g_string_append_printf(*out, + "%f", data[k++]); + } + + l = l->next; + } + g_string_append_c(*out, ctx->separator); + } + g_string_truncate(*out, (*out)->len - 1); + g_string_append_printf(*out, "\n"); + } + break; } - return SR_OK; + return ret; } static int cleanup(struct sr_output *o) @@ -205,7 +335,9 @@ static int cleanup(struct sr_output *o) if (o->priv) { ctx = o->priv; - g_free(ctx->channel_index); + g_free(ctx->channels); + g_free(ctx->analog_channels); + g_free(ctx->analog_vals); g_free(o->priv); o->priv = NULL; } @@ -217,6 +349,8 @@ SR_PRIV struct sr_output_module output_csv = { .id = "csv", .name = "CSV", .desc = "Comma-separated values", + .exts = (const char*[]){"csv", NULL}, + .flags = 0, .options = NULL, .init = init, .receive = receive,