2011-04-26 21:56:00 +00:00
|
|
|
/*
|
2013-04-23 20:24:30 +00:00
|
|
|
* This file is part of the libsigrok project.
|
2011-04-26 21:56:00 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 2011 Uwe Hermann <uwe@hermann-uwe.de>
|
|
|
|
*
|
|
|
|
* 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 2 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <glib.h>
|
2012-10-23 22:41:21 +00:00
|
|
|
#include "config.h" /* Needed for PACKAGE_STRING and others. */
|
2012-07-04 22:55:07 +00:00
|
|
|
#include "libsigrok.h"
|
|
|
|
#include "libsigrok-internal.h"
|
2011-04-26 21:56:00 +00:00
|
|
|
|
2013-05-03 19:59:32 +00:00
|
|
|
/* Message logging helpers with subsystem-specific prefix string. */
|
|
|
|
#define LOG_PREFIX "output/csv: "
|
|
|
|
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
|
|
|
|
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
|
|
|
|
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
|
|
|
|
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
|
|
|
|
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
|
|
|
|
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
|
2012-11-11 08:36:21 +00:00
|
|
|
|
2011-04-26 21:56:00 +00:00
|
|
|
struct context {
|
|
|
|
unsigned int num_enabled_probes;
|
|
|
|
unsigned int unitsize;
|
|
|
|
uint64_t samplerate;
|
|
|
|
GString *header;
|
|
|
|
char separator;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO:
|
|
|
|
* - Option to specify delimiter character and/or string.
|
|
|
|
* - Option to (not) print metadata as comments.
|
|
|
|
* - Option to specify the comment character(s), e.g. # or ; or C/C++-style.
|
|
|
|
* - Option to (not) print samplenumber / time as extra column.
|
|
|
|
* - Option to "compress" output (only print changed samples, VCD-like).
|
|
|
|
* - Option to print comma-separated bits, or whole bytes/words (for 8/16
|
|
|
|
* probe LAs) as ASCII/hex etc. etc.
|
|
|
|
* - Trigger support.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int init(struct sr_output *o)
|
|
|
|
{
|
|
|
|
struct context *ctx;
|
|
|
|
struct sr_probe *probe;
|
|
|
|
GSList *l;
|
2013-03-25 19:27:26 +00:00
|
|
|
GVariant *gvar;
|
2011-04-26 21:56:00 +00:00
|
|
|
int num_probes;
|
|
|
|
time_t t;
|
|
|
|
|
|
|
|
if (!o) {
|
2012-11-11 08:36:21 +00:00
|
|
|
sr_err("%s: o was NULL", __func__);
|
2011-04-26 21:56:00 +00:00
|
|
|
return SR_ERR_ARG;
|
|
|
|
}
|
|
|
|
|
2012-07-20 19:37:36 +00:00
|
|
|
if (!o->sdi) {
|
2012-11-11 08:36:21 +00:00
|
|
|
sr_err("%s: o->sdi was NULL", __func__);
|
2011-04-26 21:56:00 +00:00
|
|
|
return SR_ERR_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
|
2012-11-11 08:36:21 +00:00
|
|
|
sr_err("%s: ctx malloc failed", __func__);
|
2011-04-26 21:56:00 +00:00
|
|
|
return SR_ERR_MALLOC;
|
|
|
|
}
|
|
|
|
|
|
|
|
o->internal = ctx;
|
|
|
|
|
2013-04-26 21:26:14 +00:00
|
|
|
/* Get the number of probes, and the unitsize. */
|
2012-07-20 19:37:36 +00:00
|
|
|
for (l = o->sdi->probes; l; l = l->next) {
|
2011-04-26 21:56:00 +00:00
|
|
|
probe = l->data;
|
2013-04-26 21:26:14 +00:00
|
|
|
if (probe->enabled)
|
|
|
|
ctx->num_enabled_probes++;
|
2011-04-26 21:56:00 +00:00
|
|
|
}
|
2013-04-26 21:26:14 +00:00
|
|
|
|
2011-04-26 21:56:00 +00:00
|
|
|
ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
|
|
|
|
|
2012-07-20 19:37:36 +00:00
|
|
|
num_probes = g_slist_length(o->sdi->probes);
|
2011-04-26 21:56:00 +00:00
|
|
|
|
2013-04-30 14:03:37 +00:00
|
|
|
if (sr_config_get(o->sdi->driver, SR_CONF_SAMPLERATE, &gvar,
|
|
|
|
o->sdi) == SR_OK) {
|
2013-03-25 19:27:26 +00:00
|
|
|
ctx->samplerate = g_variant_get_uint64(gvar);
|
|
|
|
g_variant_unref(gvar);
|
2012-07-20 19:37:36 +00:00
|
|
|
} else
|
|
|
|
ctx->samplerate = 0;
|
2011-04-26 21:56:00 +00:00
|
|
|
|
|
|
|
ctx->separator = ',';
|
|
|
|
ctx->header = g_string_sized_new(512);
|
|
|
|
|
|
|
|
t = time(NULL);
|
|
|
|
|
|
|
|
/* Some metadata */
|
|
|
|
g_string_append_printf(ctx->header, "; CSV, generated by %s on %s",
|
|
|
|
PACKAGE_STRING, ctime(&t));
|
|
|
|
g_string_append_printf(ctx->header, "; Samplerate: %"PRIu64"\n",
|
|
|
|
ctx->samplerate);
|
|
|
|
|
|
|
|
/* Columns / channels */
|
|
|
|
g_string_append_printf(ctx->header, "; Channels (%d/%d): ",
|
|
|
|
ctx->num_enabled_probes, num_probes);
|
2013-04-26 21:26:14 +00:00
|
|
|
for (l = o->sdi->probes; l; l = l->next) {
|
|
|
|
probe = l->data;
|
|
|
|
if (probe->enabled)
|
|
|
|
g_string_append_printf(ctx->header, "%s, ", probe->name);
|
|
|
|
}
|
2011-04-26 21:56:00 +00:00
|
|
|
g_string_append_printf(ctx->header, "\n");
|
|
|
|
|
2012-07-20 19:37:36 +00:00
|
|
|
return SR_OK;
|
2011-04-26 21:56:00 +00:00
|
|
|
}
|
|
|
|
|
2012-03-28 18:00:13 +00:00
|
|
|
static int event(struct sr_output *o, int event_type, uint8_t **data_out,
|
2011-04-26 21:56:00 +00:00
|
|
|
uint64_t *length_out)
|
|
|
|
{
|
|
|
|
struct context *ctx;
|
|
|
|
|
|
|
|
if (!o) {
|
2012-11-11 08:36:21 +00:00
|
|
|
sr_err("%s: o was NULL", __func__);
|
2011-04-26 21:56:00 +00:00
|
|
|
return SR_ERR_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ctx = o->internal)) {
|
2012-11-11 08:36:21 +00:00
|
|
|
sr_err("%s: o->internal was NULL", __func__);
|
2011-04-26 21:56:00 +00:00
|
|
|
return SR_ERR_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!data_out) {
|
2012-11-11 08:36:21 +00:00
|
|
|
sr_err("%s: data_out was NULL", __func__);
|
2011-04-26 21:56:00 +00:00
|
|
|
return SR_ERR_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (event_type) {
|
|
|
|
case SR_DF_TRIGGER:
|
2012-11-11 08:36:21 +00:00
|
|
|
sr_dbg("%s: SR_DF_TRIGGER event", __func__);
|
2011-04-26 21:56:00 +00:00
|
|
|
/* TODO */
|
|
|
|
*data_out = NULL;
|
|
|
|
*length_out = 0;
|
|
|
|
break;
|
|
|
|
case SR_DF_END:
|
2012-11-11 08:36:21 +00:00
|
|
|
sr_dbg("%s: SR_DF_END event", __func__);
|
2011-04-26 21:56:00 +00:00
|
|
|
/* TODO */
|
|
|
|
*data_out = NULL;
|
|
|
|
*length_out = 0;
|
|
|
|
g_free(o->internal);
|
|
|
|
o->internal = NULL;
|
|
|
|
break;
|
|
|
|
default:
|
2012-11-11 08:36:21 +00:00
|
|
|
sr_err("%s: unsupported event type: %d", __func__, event_type);
|
2011-04-26 21:56:00 +00:00
|
|
|
*data_out = NULL;
|
|
|
|
*length_out = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SR_OK;
|
|
|
|
}
|
|
|
|
|
2012-03-28 18:00:13 +00:00
|
|
|
static int data(struct sr_output *o, const uint8_t *data_in,
|
|
|
|
uint64_t length_in, uint8_t **data_out, uint64_t *length_out)
|
2011-04-26 21:56:00 +00:00
|
|
|
{
|
|
|
|
struct context *ctx;
|
|
|
|
GString *outstr;
|
csv output: Fix incorrect ordering of the probes.
The comment for the CSV output module says probes are ordered e.g.
0,1,2,3, but the actual values were in the 3,2,1,0 order.
We're fixing this by making the order of the probe values 0,1,2,3 too
for now, but this will become a configurable option later on.
Thanks Patrick Servello <patrick.servello@gmail.com> for the patch.
2013-05-21 18:54:42 +00:00
|
|
|
uint64_t sample, i, j;
|
2011-04-26 21:56:00 +00:00
|
|
|
|
|
|
|
if (!o) {
|
2012-11-11 08:36:21 +00:00
|
|
|
sr_err("%s: o was NULL", __func__);
|
2011-04-26 21:56:00 +00:00
|
|
|
return SR_ERR_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ctx = o->internal)) {
|
2012-11-11 08:36:21 +00:00
|
|
|
sr_err("%s: o->internal was NULL", __func__);
|
2011-04-26 21:56:00 +00:00
|
|
|
return SR_ERR_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!data_in) {
|
2012-11-11 08:36:21 +00:00
|
|
|
sr_err("%s: data_in was NULL", __func__);
|
2011-04-26 21:56:00 +00:00
|
|
|
return SR_ERR_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->header) {
|
|
|
|
/* First data packet. */
|
|
|
|
outstr = ctx->header;
|
|
|
|
ctx->header = NULL;
|
|
|
|
} else {
|
|
|
|
outstr = g_string_sized_new(512);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) {
|
|
|
|
memcpy(&sample, data_in + i, ctx->unitsize);
|
csv output: Fix incorrect ordering of the probes.
The comment for the CSV output module says probes are ordered e.g.
0,1,2,3, but the actual values were in the 3,2,1,0 order.
We're fixing this by making the order of the probe values 0,1,2,3 too
for now, but this will become a configurable option later on.
Thanks Patrick Servello <patrick.servello@gmail.com> for the patch.
2013-05-21 18:54:42 +00:00
|
|
|
for (j = 0; j < ctx->num_enabled_probes; j++) {
|
2011-04-26 21:56:00 +00:00
|
|
|
g_string_append_printf(outstr, "%d%c",
|
|
|
|
(int)((sample & (1 << j)) >> j),
|
|
|
|
ctx->separator);
|
|
|
|
}
|
|
|
|
g_string_append_printf(outstr, "\n");
|
|
|
|
}
|
|
|
|
|
2012-03-28 18:00:13 +00:00
|
|
|
*data_out = (uint8_t *)outstr->str;
|
2011-04-26 21:56:00 +00:00
|
|
|
*length_out = outstr->len;
|
|
|
|
g_string_free(outstr, FALSE);
|
|
|
|
|
|
|
|
return SR_OK;
|
|
|
|
}
|
|
|
|
|
2012-02-04 09:56:51 +00:00
|
|
|
SR_PRIV struct sr_output_format output_csv = {
|
2011-04-26 21:56:00 +00:00
|
|
|
.id = "csv",
|
|
|
|
.description = "Comma-separated values (CSV)",
|
|
|
|
.df_type = SR_DF_LOGIC,
|
|
|
|
.init = init,
|
|
|
|
.data = data,
|
|
|
|
.event = event,
|
|
|
|
};
|