X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Foutput%2Fcsv.c;h=296d9a06b0ab541037b588b63a42f7d62b13a619;hb=4feb6ec9a2c818cb7cad508ee4284ce2386ccd41;hp=f6502fb8a9b6e6588f669e893e7f686307641e43;hpb=b078dddb849829be05093bbce5a7056fa2fc0eb7;p=libsigrok.git diff --git a/src/output/csv.c b/src/output/csv.c index f6502fb8..296d9a06 100644 --- a/src/output/csv.c +++ b/src/output/csv.c @@ -44,12 +44,12 @@ * Values are "channel", "units", "off". Defaults to "units". * * time: Whether or not the first column should include the time the sample - * was taken. Defaults to TRUE. + * was taken. Defaults to FALSE. * * trigger: Whether or not to add a "trigger" column as the last column. * Defaults to FALSE. * - * dedup: Don't output duplicate rows. Defaults to TRUE. If time is off, then + * dedup: Don't output duplicate rows. Defaults to FALSE. If time is off, then * this is forced to be off. */ @@ -93,8 +93,9 @@ struct context { uint32_t num_samples; uint32_t channel_count, logic_channel_count; uint32_t channels_seen; - uint64_t period; - uint64_t sample_time; + uint64_t sample_rate; + uint64_t sample_scale; + uint64_t out_sample_count; uint8_t *previous_sample; float *analog_samples; uint8_t *logic_samples; @@ -218,31 +219,28 @@ static GString *gen_header(const struct sr_output *o, GString *header; GSList *channels, *l; unsigned int num_channels, i; - uint64_t samplerate = 0, sr; char *samplerate_s; ctx = o->priv; header = g_string_sized_new(512); - if (ctx->period == 0) { + if (ctx->sample_rate == 0) { if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE, &gvar) == SR_OK) { - samplerate = g_variant_get_uint64(gvar); + ctx->sample_rate = g_variant_get_uint64(gvar); g_variant_unref(gvar); } i = 0; - sr = 1; - while (sr < samplerate) { + ctx->sample_scale = 1; + while (ctx->sample_scale < ctx->sample_rate) { i++; - sr *= 1000; + ctx->sample_scale *= 1000; } - if (samplerate) - ctx->period = sr / samplerate; if (i < ARRAY_SIZE(xlabels)) ctx->xlabel = xlabels[i]; - sr_info("Set sample period to %" PRIu64 " %s", - ctx->period, ctx->xlabel); + sr_info("Set sample rate, scale to %" PRIu64 ", %" PRIu64 " %s", + ctx->sample_rate, ctx->sample_scale, ctx->xlabel); } ctx->title = (o->sdi && o->sdi->driver) ? o->sdi->driver->longname : "unknown"; @@ -252,7 +250,7 @@ static GString *gen_header(const struct sr_output *o, g_string_append_printf(header, "%s CSV generated by %s %s\n%s from %s on %s", ctx->comment, PACKAGE_NAME, - SR_PACKAGE_VERSION_STRING, ctx->comment, + sr_package_version_string_get(), ctx->comment, ctx->title, ctime(&hdr->starttime.tv_sec)); /* Columns / channels */ @@ -271,8 +269,8 @@ static GString *gen_header(const struct sr_output *o, g_string_truncate(header, header->len - 1); } g_string_append_printf(header, "\n"); - if (samplerate != 0) { - samplerate_s = sr_samplerate_string(samplerate); + if (ctx->sample_rate != 0) { + samplerate_s = sr_samplerate_string(ctx->sample_rate); g_string_append_printf(header, "%s Samplerate: %s\n", ctx->comment, samplerate_s); g_free(samplerate_s); @@ -280,6 +278,10 @@ static GString *gen_header(const struct sr_output *o, ctx->did_header = TRUE; } + /* Time column requested but samplerate unknown. Emit a warning. */ + if (ctx->time && !ctx->sample_rate) + sr_warn("Samplerate unknown, cannot provide timestamps."); + return header; } @@ -310,7 +312,9 @@ static void process_analog(struct context *ctx, const struct sr_datafeed_analog *analog) { int ret; - unsigned int i, j, c, num_channels; + size_t num_rcvd_ch, num_have_ch; + size_t idx_have, idx_smpl, idx_rcvd; + size_t idx_send; struct sr_analog_meaning *meaning; GSList *l; float *fdata = NULL; @@ -327,31 +331,34 @@ static void process_analog(struct context *ctx, ctx->num_samples, analog->num_samples); meaning = analog->meaning; - num_channels = g_slist_length(meaning->channels); - ctx->channels_seen += num_channels; - sr_dbg("Processing packet of %u analog channels", num_channels); - fdata = g_malloc(analog->num_samples * num_channels * sizeof(float)); + num_rcvd_ch = g_slist_length(meaning->channels); + ctx->channels_seen += num_rcvd_ch; + sr_dbg("Processing packet of %zu analog channels", num_rcvd_ch); + fdata = g_malloc(analog->num_samples * num_rcvd_ch * sizeof(float)); if ((ret = sr_analog_to_float(analog, fdata)) != SR_OK) sr_warn("Problems converting data to floating point values."); - for (i = 0; i < ctx->num_analog_channels + ctx->num_logic_channels; i++) { - if (ctx->channels[i].ch->type != SR_CHANNEL_ANALOG) + num_have_ch = ctx->num_analog_channels + ctx->num_logic_channels; + idx_send = 0; + for (idx_have = 0; idx_have < num_have_ch; idx_have++) { + if (ctx->channels[idx_have].ch->type != SR_CHANNEL_ANALOG) continue; sr_dbg("Looking for channel %s", - ctx->channels[i].ch->name); - for (l = meaning->channels, c = 0; l; l = l->next, c++) { + ctx->channels[idx_have].ch->name); + for (l = meaning->channels, idx_rcvd = 0; l; l = l->next, idx_rcvd++) { ch = l->data; sr_dbg("Checking %s", ch->name); - if (ctx->channels[i].ch != l->data) + if (ctx->channels[idx_have].ch != ch) continue; if (ctx->label_do && !ctx->label_names) { sr_analog_unit_to_string(analog, - &ctx->channels[i].label); + &ctx->channels[idx_have].label); } - for (j = 0; j < analog->num_samples; j++) - ctx->analog_samples[j * ctx->num_analog_channels + i] = fdata[j * num_channels + c]; + for (idx_smpl = 0; idx_smpl < analog->num_samples; idx_smpl++) + ctx->analog_samples[idx_smpl * ctx->num_analog_channels + idx_send] = fdata[idx_smpl * num_rcvd_ch + idx_rcvd]; break; } + idx_send++; } g_free(fdata); } @@ -396,6 +403,8 @@ static void process_logic(struct context *ctx, static void dump_saved_values(struct context *ctx, GString **out) { unsigned int i, j, analog_size, num_channels; + double sample_time_dbl; + uint64_t sample_time_u64; float *analog_sample, value; uint8_t *logic_sample; @@ -413,8 +422,8 @@ static void dump_saved_values(struct context *ctx, GString **out) if (ctx->label_do) { if (ctx->time) g_string_append_printf(*out, "%s%s", - ctx->label_names ? "Time" : - ctx->xlabel, ctx->value); + ctx->label_names ? "Time" : ctx->xlabel, + ctx->value); for (i = 0; i < num_channels; i++) { g_string_append_printf(*out, "%s%s", ctx->channels[i].label, ctx->value); @@ -437,7 +446,6 @@ static void dump_saved_values(struct context *ctx, GString **out) ctx->previous_sample = g_malloc0(analog_size + ctx->num_logic_channels); for (i = 0; i < ctx->num_samples; i++) { - ctx->sample_time += ctx->period; analog_sample = &ctx->analog_samples[i * ctx->num_analog_channels]; logic_sample = @@ -459,9 +467,16 @@ static void dump_saved_values(struct context *ctx, GString **out) analog_sample, analog_size); } - if (ctx->time) + if (ctx->time && !ctx->sample_rate) { + g_string_append_printf(*out, "0%s", ctx->value); + } else if (ctx->time) { + sample_time_dbl = ctx->out_sample_count++; + sample_time_dbl /= ctx->sample_rate; + sample_time_dbl *= ctx->sample_scale; + sample_time_u64 = sample_time_dbl; g_string_append_printf(*out, "%" PRIu64 "%s", - ctx->sample_time, ctx->value); + sample_time_u64, ctx->value); + } for (j = 0; j < num_channels; j++) { if (ctx->channels[j].ch->type == SR_CHANNEL_ANALOG) { @@ -638,6 +653,8 @@ static struct sr_option options[] = { static const struct sr_option *get_options(void) { + GSList *l = NULL; + if (!options[0].def) { options[0].def = g_variant_ref_sink(g_variant_new_string("")); options[1].def = g_variant_ref_sink(g_variant_new_boolean(TRUE)); @@ -647,9 +664,13 @@ static const struct sr_option *get_options(void) options[5].def = g_variant_ref_sink(g_variant_new_string(";")); options[6].def = g_variant_ref_sink(g_variant_new_boolean(TRUE)); options[7].def = g_variant_ref_sink(g_variant_new_string("units")); - options[8].def = g_variant_ref_sink(g_variant_new_boolean(TRUE)); + l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("units"))); + l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("channel"))); + l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("off"))); + options[7].values = l; + options[8].def = g_variant_ref_sink(g_variant_new_boolean(FALSE)); options[9].def = g_variant_ref_sink(g_variant_new_boolean(FALSE)); - options[10].def = g_variant_ref_sink(g_variant_new_boolean(TRUE)); + options[10].def = g_variant_ref_sink(g_variant_new_boolean(FALSE)); } return options;