From: Uwe Hermann Date: Tue, 3 Jan 2012 19:01:02 +0000 (+0100) Subject: sr: Remove useless filename prefixes. X-Git-Tag: libsigrok-0.1.0~196 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=0da5b6a9f5a119ab485ed3dba08aeb4a3ad2c8f4;p=libsigrok.git sr: Remove useless filename prefixes. --- diff --git a/input/Makefile.am b/input/Makefile.am index 68fb129c..16740347 100644 --- a/input/Makefile.am +++ b/input/Makefile.am @@ -21,8 +21,8 @@ noinst_LTLIBRARIES = libsigrokinput.la libsigrokinput_la_SOURCES = \ - input_binary.c \ - input_chronovu_la8.c \ + binary.c \ + chronovu_la8.c \ input.c libsigrokinput_la_CFLAGS = \ diff --git a/input/binary.c b/input/binary.c new file mode 100644 index 00000000..9d7e1560 --- /dev/null +++ b/input/binary.c @@ -0,0 +1,112 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2010 Bert Vermeulen + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include "sigrok.h" + +#define CHUNKSIZE 4096 +#define DEFAULT_NUM_PROBES 8 + +static int format_match(const char *filename) +{ + /* suppress compiler warning */ + (void)filename; + + /* this module will handle anything you throw at it */ + return TRUE; +} + +static int init(struct sr_input *in) +{ + int num_probes, i; + char name[SR_MAX_PROBENAME_LEN + 1]; + + if (in->param && in->param[0]) { + num_probes = strtoul(in->param, NULL, 10); + if (num_probes < 1) + return SR_ERR; + } else { + num_probes = DEFAULT_NUM_PROBES; + } + + /* Create a virtual device. */ + in->vdevice = sr_device_new(NULL, 0); + + for (i = 0; i < num_probes; i++) { + snprintf(name, SR_MAX_PROBENAME_LEN, "%d", i); + /* TODO: Check return value. */ + sr_device_probe_add(in->vdevice, name); + } + + return SR_OK; +} + +static int loadfile(struct sr_input *in, const char *filename) +{ + struct sr_datafeed_header header; + struct sr_datafeed_packet packet; + struct sr_datafeed_logic logic; + unsigned char buffer[CHUNKSIZE]; + int fd, size, num_probes; + + if ((fd = open(filename, O_RDONLY)) == -1) + return SR_ERR; + + num_probes = g_slist_length(in->vdevice->probes); + + /* send header */ + header.feed_version = 1; + header.num_logic_probes = num_probes; + header.num_analog_probes = 0; + header.samplerate = 0; + gettimeofday(&header.starttime, NULL); + packet.type = SR_DF_HEADER; + packet.payload = &header; + sr_session_bus(in->vdevice, &packet); + + /* chop up the input file into chunks and feed it into the session bus */ + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + logic.unitsize = (num_probes + 7) / 8; + logic.data = buffer; + while ((size = read(fd, buffer, CHUNKSIZE)) > 0) { + logic.length = size; + sr_session_bus(in->vdevice, &packet); + } + close(fd); + + /* end of stream */ + packet.type = SR_DF_END; + sr_session_bus(in->vdevice, &packet); + + return SR_OK; +} + +struct sr_input_format input_binary = { + .id = "binary", + .description = "Raw binary", + .format_match = format_match, + .init = init, + .loadfile = loadfile, +}; diff --git a/input/chronovu_la8.c b/input/chronovu_la8.c new file mode 100644 index 00000000..c39f0169 --- /dev/null +++ b/input/chronovu_la8.c @@ -0,0 +1,177 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2011 Uwe Hermann + * + * 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 +#include +#include +#include "sigrok.h" +#include "sigrok-internal.h" + +#define NUM_PACKETS 2048 +#define PACKET_SIZE 4096 +#define DEFAULT_NUM_PROBES 8 + +/** + * Convert the LA8 'divcount' value to the respective samplerate (in Hz). + * + * LA8 hardware: sample period = (divcount + 1) * 10ns. + * Min. value for divcount: 0x00 (10ns sample period, 100MHz samplerate). + * Max. value for divcount: 0xfe (2550ns sample period, 392.15kHz samplerate). + * + * @param divcount The divcount value as needed by the hardware. + * @return The samplerate in Hz, or 0xffffffffffffffff upon errors. + */ +static uint64_t divcount_to_samplerate(uint8_t divcount) +{ + if (divcount == 0xff) + return 0xffffffffffffffffULL; + + return SR_MHZ(100) / (divcount + 1); +} + +static int format_match(const char *filename) +{ + if (!filename) { + sr_warn("la8input: %s: filename was NULL", __func__); + // return SR_ERR; /* FIXME */ + return FALSE; + } + + if (!g_file_test(filename, G_FILE_TEST_EXISTS)) { + sr_warn("la8input: %s: input file '%s' does not exist", + __func__, filename); + // return SR_ERR; /* FIXME */ + return FALSE; + } + + if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { + sr_warn("la8input: %s: input file '%s' not a regular file", + __func__, filename); + // return SR_ERR; /* FIXME */ + return FALSE; + } + + /* TODO: Only accept files of length 8MB + 5 bytes. */ + + /* TODO: Check for divcount != 0xff. */ + + return TRUE; +} + +static int init(struct sr_input *in) +{ + int num_probes, i; + char name[SR_MAX_PROBENAME_LEN + 1]; + + if (in->param && in->param[0]) { + num_probes = strtoul(in->param, NULL, 10); + if (num_probes < 1) { + sr_warn("la8input: %s: strtoul failed", __func__); + return SR_ERR; + } + } else { + num_probes = DEFAULT_NUM_PROBES; + } + + /* Create a virtual device. */ + in->vdevice = sr_device_new(NULL, 0); + + for (i = 0; i < num_probes; i++) { + snprintf(name, SR_MAX_PROBENAME_LEN, "%d", i); + /* TODO: Check return value. */ + sr_device_probe_add(in->vdevice, name); + } + + return SR_OK; +} + +static int loadfile(struct sr_input *in, const char *filename) +{ + struct sr_datafeed_header header; + struct sr_datafeed_packet packet; + struct sr_datafeed_logic logic; + uint8_t buf[PACKET_SIZE], divcount; + int i, fd, size, num_probes; + uint64_t samplerate; + + /* TODO: Use glib functions! GIOChannel, g_fopen, etc. */ + if ((fd = open(filename, O_RDONLY)) == -1) { + sr_warn("la8input: %s: file open failed", __func__); + return SR_ERR; + } + + num_probes = g_slist_length(in->vdevice->probes); + + /* Seek to the end of the file, and read the divcount byte. */ + divcount = 0x00; /* TODO: Don't hardcode! */ + + /* Convert the divcount value to a samplerate. */ + samplerate = divcount_to_samplerate(divcount); + if (samplerate == 0xffffffffffffffffULL) { + close(fd); /* FIXME */ + return SR_ERR; + } + sr_dbg("la8input: %s: samplerate is %" PRIu64, __func__, samplerate); + + /* Send header packet to the session bus. */ + sr_dbg("la8input: %s: sending SR_DF_HEADER packet", __func__); + packet.type = SR_DF_HEADER; + packet.payload = &header; + header.feed_version = 1; + gettimeofday(&header.starttime, NULL); + header.num_logic_probes = num_probes; + header.num_analog_probes = 0; + header.samplerate = samplerate; + sr_session_bus(in->vdevice, &packet); + + /* TODO: Handle trigger point. */ + + /* Send data packets to the session bus. */ + sr_dbg("la8input: %s: sending SR_DF_LOGIC data packets", __func__); + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + logic.unitsize = (num_probes + 7) / 8; + logic.data = buf; + + /* Send 8MB of total data to the session bus in small chunks. */ + for (i = 0; i < NUM_PACKETS; i++) { + /* TODO: Handle errors, handle incomplete reads. */ + size = read(fd, buf, PACKET_SIZE); + logic.length = PACKET_SIZE; + sr_session_bus(in->vdevice, &packet); + } + close(fd); /* FIXME */ + + /* Send end packet to the session bus. */ + sr_dbg("la8input: %s: sending SR_DF_END", __func__); + packet.type = SR_DF_END; + packet.payload = NULL; + sr_session_bus(in->vdevice, &packet); + + return SR_OK; +} + +struct sr_input_format input_chronovu_la8 = { + .id = "chronovu-la8", + .description = "ChronoVu LA8", + .format_match = format_match, + .init = init, + .loadfile = loadfile, +}; diff --git a/input/input_binary.c b/input/input_binary.c deleted file mode 100644 index 9d7e1560..00000000 --- a/input/input_binary.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * This file is part of the sigrok project. - * - * Copyright (C) 2010 Bert Vermeulen - * - * 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 . - */ - -#include -#include -#include -#include -#include -#include -#include "sigrok.h" - -#define CHUNKSIZE 4096 -#define DEFAULT_NUM_PROBES 8 - -static int format_match(const char *filename) -{ - /* suppress compiler warning */ - (void)filename; - - /* this module will handle anything you throw at it */ - return TRUE; -} - -static int init(struct sr_input *in) -{ - int num_probes, i; - char name[SR_MAX_PROBENAME_LEN + 1]; - - if (in->param && in->param[0]) { - num_probes = strtoul(in->param, NULL, 10); - if (num_probes < 1) - return SR_ERR; - } else { - num_probes = DEFAULT_NUM_PROBES; - } - - /* Create a virtual device. */ - in->vdevice = sr_device_new(NULL, 0); - - for (i = 0; i < num_probes; i++) { - snprintf(name, SR_MAX_PROBENAME_LEN, "%d", i); - /* TODO: Check return value. */ - sr_device_probe_add(in->vdevice, name); - } - - return SR_OK; -} - -static int loadfile(struct sr_input *in, const char *filename) -{ - struct sr_datafeed_header header; - struct sr_datafeed_packet packet; - struct sr_datafeed_logic logic; - unsigned char buffer[CHUNKSIZE]; - int fd, size, num_probes; - - if ((fd = open(filename, O_RDONLY)) == -1) - return SR_ERR; - - num_probes = g_slist_length(in->vdevice->probes); - - /* send header */ - header.feed_version = 1; - header.num_logic_probes = num_probes; - header.num_analog_probes = 0; - header.samplerate = 0; - gettimeofday(&header.starttime, NULL); - packet.type = SR_DF_HEADER; - packet.payload = &header; - sr_session_bus(in->vdevice, &packet); - - /* chop up the input file into chunks and feed it into the session bus */ - packet.type = SR_DF_LOGIC; - packet.payload = &logic; - logic.unitsize = (num_probes + 7) / 8; - logic.data = buffer; - while ((size = read(fd, buffer, CHUNKSIZE)) > 0) { - logic.length = size; - sr_session_bus(in->vdevice, &packet); - } - close(fd); - - /* end of stream */ - packet.type = SR_DF_END; - sr_session_bus(in->vdevice, &packet); - - return SR_OK; -} - -struct sr_input_format input_binary = { - .id = "binary", - .description = "Raw binary", - .format_match = format_match, - .init = init, - .loadfile = loadfile, -}; diff --git a/input/input_chronovu_la8.c b/input/input_chronovu_la8.c deleted file mode 100644 index c39f0169..00000000 --- a/input/input_chronovu_la8.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * This file is part of the sigrok project. - * - * Copyright (C) 2011 Uwe Hermann - * - * 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 -#include -#include -#include "sigrok.h" -#include "sigrok-internal.h" - -#define NUM_PACKETS 2048 -#define PACKET_SIZE 4096 -#define DEFAULT_NUM_PROBES 8 - -/** - * Convert the LA8 'divcount' value to the respective samplerate (in Hz). - * - * LA8 hardware: sample period = (divcount + 1) * 10ns. - * Min. value for divcount: 0x00 (10ns sample period, 100MHz samplerate). - * Max. value for divcount: 0xfe (2550ns sample period, 392.15kHz samplerate). - * - * @param divcount The divcount value as needed by the hardware. - * @return The samplerate in Hz, or 0xffffffffffffffff upon errors. - */ -static uint64_t divcount_to_samplerate(uint8_t divcount) -{ - if (divcount == 0xff) - return 0xffffffffffffffffULL; - - return SR_MHZ(100) / (divcount + 1); -} - -static int format_match(const char *filename) -{ - if (!filename) { - sr_warn("la8input: %s: filename was NULL", __func__); - // return SR_ERR; /* FIXME */ - return FALSE; - } - - if (!g_file_test(filename, G_FILE_TEST_EXISTS)) { - sr_warn("la8input: %s: input file '%s' does not exist", - __func__, filename); - // return SR_ERR; /* FIXME */ - return FALSE; - } - - if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { - sr_warn("la8input: %s: input file '%s' not a regular file", - __func__, filename); - // return SR_ERR; /* FIXME */ - return FALSE; - } - - /* TODO: Only accept files of length 8MB + 5 bytes. */ - - /* TODO: Check for divcount != 0xff. */ - - return TRUE; -} - -static int init(struct sr_input *in) -{ - int num_probes, i; - char name[SR_MAX_PROBENAME_LEN + 1]; - - if (in->param && in->param[0]) { - num_probes = strtoul(in->param, NULL, 10); - if (num_probes < 1) { - sr_warn("la8input: %s: strtoul failed", __func__); - return SR_ERR; - } - } else { - num_probes = DEFAULT_NUM_PROBES; - } - - /* Create a virtual device. */ - in->vdevice = sr_device_new(NULL, 0); - - for (i = 0; i < num_probes; i++) { - snprintf(name, SR_MAX_PROBENAME_LEN, "%d", i); - /* TODO: Check return value. */ - sr_device_probe_add(in->vdevice, name); - } - - return SR_OK; -} - -static int loadfile(struct sr_input *in, const char *filename) -{ - struct sr_datafeed_header header; - struct sr_datafeed_packet packet; - struct sr_datafeed_logic logic; - uint8_t buf[PACKET_SIZE], divcount; - int i, fd, size, num_probes; - uint64_t samplerate; - - /* TODO: Use glib functions! GIOChannel, g_fopen, etc. */ - if ((fd = open(filename, O_RDONLY)) == -1) { - sr_warn("la8input: %s: file open failed", __func__); - return SR_ERR; - } - - num_probes = g_slist_length(in->vdevice->probes); - - /* Seek to the end of the file, and read the divcount byte. */ - divcount = 0x00; /* TODO: Don't hardcode! */ - - /* Convert the divcount value to a samplerate. */ - samplerate = divcount_to_samplerate(divcount); - if (samplerate == 0xffffffffffffffffULL) { - close(fd); /* FIXME */ - return SR_ERR; - } - sr_dbg("la8input: %s: samplerate is %" PRIu64, __func__, samplerate); - - /* Send header packet to the session bus. */ - sr_dbg("la8input: %s: sending SR_DF_HEADER packet", __func__); - packet.type = SR_DF_HEADER; - packet.payload = &header; - header.feed_version = 1; - gettimeofday(&header.starttime, NULL); - header.num_logic_probes = num_probes; - header.num_analog_probes = 0; - header.samplerate = samplerate; - sr_session_bus(in->vdevice, &packet); - - /* TODO: Handle trigger point. */ - - /* Send data packets to the session bus. */ - sr_dbg("la8input: %s: sending SR_DF_LOGIC data packets", __func__); - packet.type = SR_DF_LOGIC; - packet.payload = &logic; - logic.unitsize = (num_probes + 7) / 8; - logic.data = buf; - - /* Send 8MB of total data to the session bus in small chunks. */ - for (i = 0; i < NUM_PACKETS; i++) { - /* TODO: Handle errors, handle incomplete reads. */ - size = read(fd, buf, PACKET_SIZE); - logic.length = PACKET_SIZE; - sr_session_bus(in->vdevice, &packet); - } - close(fd); /* FIXME */ - - /* Send end packet to the session bus. */ - sr_dbg("la8input: %s: sending SR_DF_END", __func__); - packet.type = SR_DF_END; - packet.payload = NULL; - sr_session_bus(in->vdevice, &packet); - - return SR_OK; -} - -struct sr_input_format input_chronovu_la8 = { - .id = "chronovu-la8", - .description = "ChronoVu LA8", - .format_match = format_match, - .init = init, - .loadfile = loadfile, -}; diff --git a/output/Makefile.am b/output/Makefile.am index 77650966..87114005 100644 --- a/output/Makefile.am +++ b/output/Makefile.am @@ -23,12 +23,12 @@ SUBDIRS = text noinst_LTLIBRARIES = libsigrokoutput.la libsigrokoutput_la_SOURCES = \ - output_binary.c \ - output_vcd.c \ - output_ols.c \ - output_gnuplot.c \ - output_chronovu_la8.c \ - output_csv.c \ + binary.c \ + vcd.c \ + ols.c \ + gnuplot.c \ + chronovu_la8.c \ + csv.c \ output.c # Temporarily disabled: output_analog.c diff --git a/output/analog.c b/output/analog.c new file mode 100644 index 00000000..5f9fcd55 --- /dev/null +++ b/output/analog.c @@ -0,0 +1,467 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2010 Bert Vermeulen + * Copyright (C) 2011 HÃ¥vard Espeland + * Copyright (C) 2011 Daniel Ribeiro + * + * 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 . + */ + +#include +#include +#include +#include +#include "sigrok.h" +#include "config.h" + +#define DEFAULT_BPL_BITS 64 +#define DEFAULT_BPL_HEX 192 +#define DEFAULT_BPL_ASCII 74 + +enum outputmode { + MODE_BITS = 1, + MODE_HEX, + MODE_ASCII, +}; + +struct context { + unsigned int num_enabled_probes; + int samples_per_line; + unsigned int unitsize; + int line_offset; + int linebuf_len; + char *probelist[65]; + char *linebuf; + int spl_cnt; + uint8_t *linevalues; + char *header; + int mark_trigger; +// struct sr_analog_sample *prevsample; + enum outputmode mode; +}; + +static void flush_linebufs(struct context *ctx, char *outbuf) +{ + static int max_probename_len = 0; + int len, i; + + if (ctx->linebuf[0] == 0) + return; + + if (max_probename_len == 0) { + /* First time through... */ + for (i = 0; ctx->probelist[i]; i++) { + len = strlen(ctx->probelist[i]); + if (len > max_probename_len) + max_probename_len = len; + } + } + + for (i = 0; ctx->probelist[i]; i++) { + sprintf(outbuf + strlen(outbuf), "%*s:%s\n", max_probename_len, + ctx->probelist[i], ctx->linebuf + i * ctx->linebuf_len); + } + + /* Mark trigger with a ^ character. */ + if (ctx->mark_trigger != -1) + { + int space_offset = ctx->mark_trigger / 8; + + if (ctx->mode == MODE_ASCII) + space_offset = 0; + + sprintf(outbuf + strlen(outbuf), "T:%*s^\n", + ctx->mark_trigger + space_offset, ""); + } + + memset(ctx->linebuf, 0, i * ctx->linebuf_len); +} + +static int init(struct sr_output *o, int default_spl, enum outputmode mode) +{ + struct context *ctx; + struct sr_probe *probe; + GSList *l; + uint64_t samplerate; + int num_probes; + char *samplerate_s; + + if (!(ctx = calloc(1, sizeof(struct context)))) + return SR_ERR_MALLOC; + + o->internal = ctx; + ctx->num_enabled_probes = 0; + + for (l = o->device->probes; l; l = l->next) { + probe = l->data; + if (!probe->enabled) + continue; + ctx->probelist[ctx->num_enabled_probes++] = probe->name; + } + + ctx->probelist[ctx->num_enabled_probes] = 0; + ctx->unitsize = sizeof(struct sr_analog_sample) + + (ctx->num_enabled_probes * sizeof(struct sr_analog_probe)); + ctx->line_offset = 0; + ctx->spl_cnt = 0; + ctx->mark_trigger = -1; + ctx->mode = mode; + + if (o->param && o->param[0]) { + ctx->samples_per_line = strtoul(o->param, NULL, 10); + if (ctx->samples_per_line < 1) + return SR_ERR; + } else + ctx->samples_per_line = default_spl; + + if (!(ctx->header = malloc(512))) { + free(ctx); + return SR_ERR_MALLOC; + } + + snprintf(ctx->header, 511, "%s\n", PACKAGE_STRING); + num_probes = g_slist_length(o->device->probes); + if (o->device->plugin && sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) { + samplerate = *((uint64_t *) o->device->plugin->get_device_info( + o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); + if (!(samplerate_s = sr_samplerate_string(samplerate))) { + free(ctx->header); + free(ctx); + return SR_ERR; + } + snprintf(ctx->header + strlen(ctx->header), + 511 - strlen(ctx->header), + "Acquisition with %d/%d probes at %s\n", + ctx->num_enabled_probes, num_probes, samplerate_s); + free(samplerate_s); + } + + ctx->linebuf_len = ctx->samples_per_line * 2 + 4; + if (!(ctx->linebuf = calloc(1, num_probes * ctx->linebuf_len))) { + free(ctx->header); + free(ctx); + return SR_ERR_MALLOC; + } + if (!(ctx->linevalues = calloc(1, num_probes))) { + free(ctx->header); + free(ctx); + return SR_ERR_MALLOC; + } + + return SR_OK; +} + +static int event(struct sr_output *o, int event_type, char **data_out, + uint64_t *length_out) +{ + struct context *ctx; + int outsize; + char *outbuf; + + ctx = o->internal; + switch (event_type) { + case SR_DF_TRIGGER: + ctx->mark_trigger = ctx->spl_cnt; + *data_out = NULL; + *length_out = 0; + break; + case SR_DF_END: + outsize = ctx->num_enabled_probes + * (ctx->samples_per_line + 20) + 512; + if (!(outbuf = calloc(1, outsize))) + return SR_ERR_MALLOC; + flush_linebufs(ctx, outbuf); + *data_out = outbuf; + *length_out = strlen(outbuf); + free(o->internal); + o->internal = NULL; + break; + default: + *data_out = NULL; + *length_out = 0; + break; + } + + return SR_OK; +} + +static int init_bits(struct sr_output *o) +{ + return init(o, DEFAULT_BPL_BITS, MODE_BITS); +} + +static int data_bits(struct sr_output *o, const char *data_in, + uint64_t length_in, char **data_out, uint64_t *length_out) +{ + struct context *ctx; + unsigned int outsize, offset, p; + int max_linelen; + struct sr_analog_sample *sample; + char *outbuf, c; + + ctx = o->internal; + max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line + + ctx->samples_per_line / 8; + /* + * Calculate space needed for probes. Set aside 512 bytes for + * extra output, e.g. trigger. + */ + outsize = 512 + (1 + (length_in / ctx->unitsize) / ctx->samples_per_line) + * (ctx->num_enabled_probes * max_linelen); + + if (!(outbuf = calloc(1, outsize + 1))) + return SR_ERR_MALLOC; + + outbuf[0] = '\0'; + if (ctx->header) { + /* The header is still here, this must be the first packet. */ + strncpy(outbuf, ctx->header, outsize); + free(ctx->header); + ctx->header = NULL; + + /* Ensure first transition. */ +// memcpy(&ctx->prevsample, data_in, ctx->unitsize); +// ctx->prevsample = ~ctx->prevsample; + } + + if (length_in >= ctx->unitsize) { + for (offset = 0; offset <= length_in - ctx->unitsize; + offset += ctx->unitsize) { + sample = (struct sr_analog_sample *) (data_in + offset); + for (p = 0; p < ctx->num_enabled_probes; p++) { + int val = sample->probes[p].val; + int res = sample->probes[p].res; + if (res == 1) + c = '0' + (val & ((1 << res) - 1)); + else + /* + * Scale analog resolution down so it + * fits 25 letters + */ + c = 'A' + (((val & ((1 << res) - 1)) / + (res * res)) / 10); + ctx->linebuf[p * ctx->linebuf_len + + ctx->line_offset] = c; + } + ctx->line_offset++; + ctx->spl_cnt++; + + /* Add a space every 8th bit. */ + if ((ctx->spl_cnt & 7) == 0) { + for (p = 0; p < ctx->num_enabled_probes; p++) + ctx->linebuf[p * ctx->linebuf_len + + ctx->line_offset] = ' '; + ctx->line_offset++; + } + + /* End of line. */ + if (ctx->spl_cnt >= ctx->samples_per_line) { + flush_linebufs(ctx, outbuf); + ctx->line_offset = ctx->spl_cnt = 0; + ctx->mark_trigger = -1; + } + } + } else { + sr_info("short buffer (length_in=%" PRIu64 ")", length_in); + } + + *data_out = outbuf; + *length_out = strlen(outbuf); + + return SR_OK; +} +#if 0 +static int init_hex(struct sr_output *o) +{ + return init(o, DEFAULT_BPL_HEX, MODE_HEX); +} + +static int data_hex(struct sr_output *o, const char *data_in, + uint64_t length_in, char **data_out, uint64_t *length_out) +{ + struct context *ctx; + unsigned int outsize, offset, p; + int max_linelen; + uint64_t sample; + char *outbuf; + + ctx = o->internal; + max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line + + ctx->samples_per_line / 2; + outsize = length_in / ctx->unitsize * ctx->num_enabled_probes + / ctx->samples_per_line * max_linelen + 512; + + if (!(outbuf = calloc(1, outsize + 1))) + return SR_ERR_MALLOC; + + outbuf[0] = '\0'; + if (ctx->header) { + /* The header is still here, this must be the first packet. */ + strncpy(outbuf, ctx->header, outsize); + free(ctx->header); + ctx->header = NULL; + } + + ctx->line_offset = 0; + for (offset = 0; offset <= length_in - ctx->unitsize; + offset += ctx->unitsize) { + memcpy(&sample, data_in + offset, ctx->unitsize); + for (p = 0; p < ctx->num_enabled_probes; p++) { + ctx->linevalues[p] <<= 1; + if (sample & ((uint64_t) 1 << p)) + ctx->linevalues[p] |= 1; + sprintf(ctx->linebuf + (p * ctx->linebuf_len) + + ctx->line_offset, "%.2x", ctx->linevalues[p]); + } + ctx->spl_cnt++; + + /* Add a space after every complete hex byte. */ + if ((ctx->spl_cnt & 7) == 0) { + for (p = 0; p < ctx->num_enabled_probes; p++) + ctx->linebuf[p * ctx->linebuf_len + + ctx->line_offset + 2] = ' '; + ctx->line_offset += 3; + } + + /* End of line. */ + if (ctx->spl_cnt >= ctx->samples_per_line) { + flush_linebufs(ctx, outbuf); + ctx->line_offset = ctx->spl_cnt = 0; + } + } + + *data_out = outbuf; + *length_out = strlen(outbuf); + + return SR_OK; +} + +static int init_ascii(struct sr_output *o) +{ + return init(o, DEFAULT_BPL_ASCII, MODE_ASCII); +} + +static int data_ascii(struct sr_output *o, const char *data_in, + uint64_t length_in, char **data_out, uint64_t *length_out) +{ + struct context *ctx; + unsigned int outsize, offset, p; + int max_linelen; + uint64_t sample; + char *outbuf; + + ctx = o->internal; + max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line + + ctx->samples_per_line / 8; + /* + * Calculate space needed for probes. Set aside 512 bytes for + * extra output, e.g. trigger. + */ + outsize = 512 + (1 + (length_in / ctx->unitsize) / ctx->samples_per_line) + * (ctx->num_enabled_probes * max_linelen); + + if (!(outbuf = calloc(1, outsize + 1))) + return SR_ERR_MALLOC; + + outbuf[0] = '\0'; + if (ctx->header) { + /* The header is still here, this must be the first packet. */ + strncpy(outbuf, ctx->header, outsize); + free(ctx->header); + ctx->header = NULL; + } + + if (length_in >= ctx->unitsize) { + for (offset = 0; offset <= length_in - ctx->unitsize; + offset += ctx->unitsize) { + memcpy(&sample, data_in + offset, ctx->unitsize); + + char tmpval[ctx->num_enabled_probes]; + + for (p = 0; p < ctx->num_enabled_probes; p++) { + uint64_t curbit = (sample & ((uint64_t) 1 << p)); + uint64_t prevbit = (ctx->prevsample & + ((uint64_t) 1 << p)); + + if (curbit < prevbit && ctx->line_offset > 0) { + ctx->linebuf[p * ctx->linebuf_len + + ctx->line_offset-1] = '\\'; + } + + if (curbit > prevbit) { + tmpval[p] = '/'; + } else { + if (curbit) + tmpval[p] = '"'; + else + tmpval[p] = '.'; + } + } + + /* End of line. */ + if (ctx->spl_cnt >= ctx->samples_per_line) { + flush_linebufs(ctx, outbuf); + ctx->line_offset = ctx->spl_cnt = 0; + ctx->mark_trigger = -1; + } + + for (p = 0; p < ctx->num_enabled_probes; p++) { + ctx->linebuf[p * ctx->linebuf_len + + ctx->line_offset] = tmpval[p]; + } + + ctx->line_offset++; + ctx->spl_cnt++; + + ctx->prevsample = sample; + } + } else { + sr_info("short buffer (length_in=%" PRIu64 ")", length_in); + } + + *data_out = outbuf; + *length_out = strlen(outbuf); + + return SR_OK; +} +#endif + +struct sr_output_format output_analog_bits = { + .id = "analog_bits", + .description = "Bits (takes argument, default 64)", + .df_type = SR_DF_ANALOG, + .init = init_bits, + .data = data_bits, + .event = event, +}; +#if 0 +struct sr_output_format output_analog_hex = { + .id = "analog_hex", + .description = "Hexadecimal (takes argument, default 192)", + .df_type = SR_DF_ANALOG, + .init = init_hex, + .data = data_hex, + .event = event, +}; + +struct sr_output_format output_analog_ascii = { + .id = "analog_ascii", + .description = "ASCII (takes argument, default 74)", + .df_type = SR_DF_ANALOG, + .init = init_ascii, + .data = data_ascii, + .event = event, +}; +#endif diff --git a/output/binary.c b/output/binary.c new file mode 100644 index 00000000..039d10bc --- /dev/null +++ b/output/binary.c @@ -0,0 +1,70 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2010 Uwe Hermann + * + * 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 +#include +#include +#include "sigrok.h" +#include "sigrok-internal.h" +#include "config.h" + +static int data(struct sr_output *o, const char *data_in, uint64_t length_in, + char **data_out, uint64_t *length_out) +{ + char *outbuf; + + /* Prevent compiler warnings. */ + (void)o; + + if (!data_in) { + sr_warn("binary output: %s: data_in was NULL", __func__); + return SR_ERR; + } + + if (!length_out) { + sr_warn("binary output: %s: length_out was NULL", __func__); + return SR_ERR; + } + + if (length_in == 0) { + sr_warn("binary output: %s: length_in was 0", __func__); + return SR_ERR; + } + + if (!(outbuf = calloc(1, length_in))) { + sr_warn("binary output: %s: outbuf calloc failed", __func__); + return SR_ERR_MALLOC; + } + + memcpy(outbuf, data_in, length_in); + *data_out = outbuf; + *length_out = length_in; + + return SR_OK; +} + +struct sr_output_format output_binary = { + .id = "binary", + .description = "Raw binary", + .df_type = SR_DF_LOGIC, + .init = NULL, + .data = data, + .event = NULL, +}; diff --git a/output/chronovu_la8.c b/output/chronovu_la8.c new file mode 100644 index 00000000..f6127352 --- /dev/null +++ b/output/chronovu_la8.c @@ -0,0 +1,241 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2011 Uwe Hermann + * + * 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 +#include +#include +#include "sigrok.h" +#include "sigrok-internal.h" + +struct context { + unsigned int num_enabled_probes; + unsigned int unitsize; + char *probelist[SR_MAX_NUM_PROBES + 1]; + uint64_t trigger_point; + uint64_t samplerate; +}; + +/** + * Check if the given samplerate is supported by the LA8 hardware. + * + * @param samplerate The samplerate (in Hz) to check. + * @return 1 if the samplerate is supported/valid, 0 otherwise. + */ +static int is_valid_samplerate(uint64_t samplerate) +{ + unsigned int i; + + for (i = 0; i < 255; i++) { + if (samplerate == (SR_MHZ(100) / (i + 1))) + return 1; + } + + sr_warn("la8 out: %s: invalid samplerate (%" PRIu64 "Hz)", + __func__, samplerate); + + return 0; +} + +/** + * Convert a samplerate (in Hz) to the 'divcount' value the LA8 wants. + * + * LA8 hardware: sample period = (divcount + 1) * 10ns. + * Min. value for divcount: 0x00 (10ns sample period, 100MHz samplerate). + * Max. value for divcount: 0xfe (2550ns sample period, 392.15kHz samplerate). + * + * @param samplerate The samplerate in Hz. + * @return The divcount value as needed by the hardware, or 0xff upon errors. + */ +static uint8_t samplerate_to_divcount(uint64_t samplerate) +{ + if (samplerate == 0) { + sr_warn("la8 out: %s: samplerate was 0", __func__); + return 0xff; + } + + if (!is_valid_samplerate(samplerate)) { + sr_warn("la8 out: %s: can't get divcount, samplerate invalid", + __func__); + return 0xff; + } + + return (SR_MHZ(100) / samplerate) - 1; +} + +static int init(struct sr_output *o) +{ + struct context *ctx; + struct sr_probe *probe; + GSList *l; + int num_probes; + uint64_t samplerate; + + if (!o) { + sr_warn("la8 out: %s: o was NULL", __func__); + return SR_ERR_ARG; + } + + if (!o->device) { + sr_warn("la8 out: %s: o->device was NULL", __func__); + return SR_ERR_ARG; + } + + if (!o->device->plugin) { + sr_warn("la8 out: %s: o->device->plugin was NULL", __func__); + return SR_ERR_ARG; + } + + if (!(ctx = calloc(1, sizeof(struct context)))) { + sr_warn("la8 out: %s: ctx calloc failed", __func__); + return SR_ERR_MALLOC; + } + + o->internal = ctx; + + /* Get the number of probes, their names, and the unitsize. */ + /* TODO: Error handling. */ + for (l = o->device->probes; l; l = l->next) { + probe = l->data; + if (!probe->enabled) + continue; + ctx->probelist[ctx->num_enabled_probes++] = probe->name; + } + ctx->probelist[ctx->num_enabled_probes] = 0; + ctx->unitsize = (ctx->num_enabled_probes + 7) / 8; + + num_probes = g_slist_length(o->device->probes); + + if (sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) { + samplerate = *((uint64_t *) o->device->plugin->get_device_info( + o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); + /* TODO: Error checks. */ + } else { + samplerate = 0; /* TODO: Error or set some value? */ + } + ctx->samplerate = samplerate; + + return 0; /* TODO: SR_OK? */ +} + +static int event(struct sr_output *o, int event_type, char **data_out, + uint64_t *length_out) +{ + struct context *ctx; + char *outbuf; + + if (!o) { + sr_warn("la8 out: %s: o was NULL", __func__); + return SR_ERR_ARG; + } + + if (!(ctx = o->internal)) { + sr_warn("la8 out: %s: o->internal was NULL", __func__); + return SR_ERR_ARG; + } + + if (!data_out) { + sr_warn("la8 out: %s: data_out was NULL", __func__); + return SR_ERR_ARG; + } + + switch (event_type) { + case SR_DF_TRIGGER: + sr_dbg("la8 out: %s: SR_DF_TRIGGER event", __func__); + /* Save the trigger point for later (SR_DF_END). */ + ctx->trigger_point = 0; /* TODO: Store _actual_ value. */ + break; + case SR_DF_END: + sr_dbg("la8 out: %s: SR_DF_END event", __func__); + if (!(outbuf = malloc(4 + 1))) { + sr_warn("la8 out: %s: outbuf malloc failed", __func__); + return SR_ERR_MALLOC; + } + + /* One byte for the 'divcount' value. */ + outbuf[0] = samplerate_to_divcount(ctx->samplerate); + // if (outbuf[0] == 0xff) { + // sr_warn("la8 out: %s: invalid divcount", __func__); + // return SR_ERR; + // } + + /* Four bytes (little endian) for the trigger point. */ + outbuf[1] = (ctx->trigger_point >> 0) & 0xff; + outbuf[2] = (ctx->trigger_point >> 8) & 0xff; + outbuf[3] = (ctx->trigger_point >> 16) & 0xff; + outbuf[4] = (ctx->trigger_point >> 24) & 0xff; + + *data_out = outbuf; + *length_out = 4 + 1; + free(o->internal); + o->internal = NULL; + break; + default: + sr_warn("la8 out: %s: unsupported event type: %d", __func__, + event_type); + *data_out = NULL; + *length_out = 0; + break; + } + + return SR_OK; +} + +static int data(struct sr_output *o, const char *data_in, uint64_t length_in, + char **data_out, uint64_t *length_out) +{ + struct context *ctx; + char *outbuf; + + if (!o) { + sr_warn("la8 out: %s: o was NULL", __func__); + return SR_ERR_ARG; + } + + if (!(ctx = o->internal)) { + sr_warn("la8 out: %s: o->internal was NULL", __func__); + return SR_ERR_ARG; + } + + if (!data_in) { + sr_warn("la8 out: %s: data_in was NULL", __func__); + return SR_ERR_ARG; + } + + if (!(outbuf = calloc(1, length_in))) { + sr_warn("la8 out: %s: outbuf calloc failed", __func__); + return SR_ERR_MALLOC; + } + + memcpy(outbuf, data_in, length_in); + + *data_out = outbuf; + *length_out = length_in; + + return SR_OK; +} + +struct sr_output_format output_chronovu_la8 = { + .id = "chronovu-la8", + .description = "ChronoVu LA8", + .df_type = SR_DF_LOGIC, + .init = init, + .data = data, + .event = event, +}; diff --git a/output/csv.c b/output/csv.c new file mode 100644 index 00000000..d56a023d --- /dev/null +++ b/output/csv.c @@ -0,0 +1,226 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2011 Uwe Hermann + * + * 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 +#include +#include +#include "sigrok.h" +#include "sigrok-internal.h" +#include "config.h" + +struct context { + unsigned int num_enabled_probes; + unsigned int unitsize; + char *probelist[SR_MAX_NUM_PROBES + 1]; + 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; + int num_probes; + uint64_t samplerate; + time_t t; + unsigned int i; + + if (!o) { + sr_err("csv out: %s: o was NULL", __func__); + return SR_ERR_ARG; + } + + if (!o->device) { + sr_err("csv out: %s: o->device was NULL", __func__); + return SR_ERR_ARG; + } + + if (!o->device->plugin) { + sr_err("csv out: %s: o->device->plugin was NULL", __func__); + return SR_ERR_ARG; + } + + if (!(ctx = g_try_malloc0(sizeof(struct context)))) { + sr_err("csv out: %s: ctx malloc failed", __func__); + return SR_ERR_MALLOC; + } + + o->internal = ctx; + + /* Get the number of probes, their names, and the unitsize. */ + /* TODO: Error handling. */ + for (l = o->device->probes; l; l = l->next) { + probe = l->data; + if (!probe->enabled) + continue; + ctx->probelist[ctx->num_enabled_probes++] = probe->name; + } + ctx->probelist[ctx->num_enabled_probes] = 0; + ctx->unitsize = (ctx->num_enabled_probes + 7) / 8; + + num_probes = g_slist_length(o->device->probes); + + if (sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) { + samplerate = *((uint64_t *) o->device->plugin->get_device_info( + o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); + /* TODO: Error checks. */ + } else { + samplerate = 0; /* TODO: Error or set some value? */ + } + ctx->samplerate = samplerate; + + 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); + for (i = 0; i < ctx->num_enabled_probes; i++) + g_string_append_printf(ctx->header, "%s, ", ctx->probelist[i]); + g_string_append_printf(ctx->header, "\n"); + + return 0; /* TODO: SR_OK? */ +} + +static int event(struct sr_output *o, int event_type, char **data_out, + uint64_t *length_out) +{ + struct context *ctx; + + if (!o) { + sr_err("csv out: %s: o was NULL", __func__); + return SR_ERR_ARG; + } + + if (!(ctx = o->internal)) { + sr_err("csv out: %s: o->internal was NULL", __func__); + return SR_ERR_ARG; + } + + if (!data_out) { + sr_err("csv out: %s: data_out was NULL", __func__); + return SR_ERR_ARG; + } + + switch (event_type) { + case SR_DF_TRIGGER: + sr_dbg("csv out: %s: SR_DF_TRIGGER event", __func__); + /* TODO */ + *data_out = NULL; + *length_out = 0; + break; + case SR_DF_END: + sr_dbg("csv out: %s: SR_DF_END event", __func__); + /* TODO */ + *data_out = NULL; + *length_out = 0; + g_free(o->internal); + o->internal = NULL; + break; + default: + sr_err("csv out: %s: unsupported event type: %d", __func__, + event_type); + *data_out = NULL; + *length_out = 0; + break; + } + + return SR_OK; +} + +static int data(struct sr_output *o, const char *data_in, uint64_t length_in, + char **data_out, uint64_t *length_out) +{ + struct context *ctx; + GString *outstr; + uint64_t sample, i; + int j; + + if (!o) { + sr_err("csv out: %s: o was NULL", __func__); + return SR_ERR_ARG; + } + + if (!(ctx = o->internal)) { + sr_err("csv out: %s: o->internal was NULL", __func__); + return SR_ERR_ARG; + } + + if (!data_in) { + sr_err("csv out: %s: data_in was NULL", __func__); + 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); + for (j = ctx->num_enabled_probes - 1; j >= 0; j--) { + g_string_append_printf(outstr, "%d%c", + (int)((sample & (1 << j)) >> j), + ctx->separator); + } + g_string_append_printf(outstr, "\n"); + } + + *data_out = outstr->str; + *length_out = outstr->len; + g_string_free(outstr, FALSE); + + return SR_OK; +} + +struct sr_output_format output_csv = { + .id = "csv", + .description = "Comma-separated values (CSV)", + .df_type = SR_DF_LOGIC, + .init = init, + .data = data, + .event = event, +}; diff --git a/output/gnuplot.c b/output/gnuplot.c new file mode 100644 index 00000000..39b2d2ee --- /dev/null +++ b/output/gnuplot.c @@ -0,0 +1,434 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2010 Uwe Hermann + * + * 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 +#include +#include +#include "sigrok.h" +#include "sigrok-internal.h" +#include "config.h" + +struct context { + unsigned int num_enabled_probes; + unsigned int unitsize; + char *probelist[SR_MAX_NUM_PROBES + 1]; + char *header; +}; + +#define MAX_HEADER_LEN \ + (1024 + (SR_MAX_NUM_PROBES * (SR_MAX_PROBENAME_LEN + 10))) + +static const char *gnuplot_header = "\ +# Sample data in space-separated columns format usable by gnuplot\n\ +#\n\ +# Generated by: %s on %s%s\ +# Period: %s\n\ +#\n\ +# Column\tProbe\n\ +# -------------------------------------\ +----------------------------------------\n\ +# 0\t\tSample counter (for internal gnuplot purposes)\n%s\n"; + +static const char *gnuplot_header_comment = "\ +# Comment: Acquisition with %d/%d probes at %s\n"; + +static int init(struct sr_output *o) +{ + struct context *ctx; + struct sr_probe *probe; + GSList *l; + uint64_t samplerate; + unsigned int i; + int b, num_probes; + char *c, *frequency_s; + char wbuf[1000], comment[128]; + time_t t; + + if (!o) { + sr_warn("gnuplot out: %s: o was NULL", __func__); + return SR_ERR_ARG; + } + + if (!o->device) { + sr_warn("gnuplot out: %s: o->device was NULL", __func__); + return SR_ERR_ARG; + } + + if (!o->device->plugin) { + sr_warn("gnuplot out: %s: o->device->plugin was NULL", + __func__); + return SR_ERR_ARG; + } + + if (!(ctx = calloc(1, sizeof(struct context)))) { + sr_warn("gnuplot out: %s: ctx calloc failed", __func__); + return SR_ERR_MALLOC; + } + + if (!(ctx->header = calloc(1, MAX_HEADER_LEN + 1))) { + sr_warn("gnuplot out: %s: ctx->header calloc failed", + __func__); + free(ctx); + return SR_ERR_MALLOC; + } + + o->internal = ctx; + ctx->num_enabled_probes = 0; + for (l = o->device->probes; l; l = l->next) { + probe = l->data; /* TODO: Error checks. */ + if (!probe->enabled) + continue; + ctx->probelist[ctx->num_enabled_probes++] = probe->name; + } + ctx->probelist[ctx->num_enabled_probes] = 0; + ctx->unitsize = (ctx->num_enabled_probes + 7) / 8; + + num_probes = g_slist_length(o->device->probes); + comment[0] = '\0'; + if (sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) { + samplerate = *((uint64_t *) o->device->plugin->get_device_info( + o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); + if (!(frequency_s = sr_samplerate_string(samplerate))) { + sr_warn("gnuplot out: %s: sr_samplerate_string failed", + __func__); + free(ctx->header); + free(ctx); + return SR_ERR; + } + snprintf(comment, 127, gnuplot_header_comment, + ctx->num_enabled_probes, num_probes, frequency_s); + free(frequency_s); + } + + /* Columns / channels */ + wbuf[0] = '\0'; + for (i = 0; i < ctx->num_enabled_probes; i++) { + c = (char *)&wbuf + strlen((char *)&wbuf); + sprintf(c, "# %d\t\t%s\n", i + 1, ctx->probelist[i]); + } + + if (!(frequency_s = sr_period_string(samplerate))) { + sr_warn("gnuplot out: %s: sr_period_string failed", __func__); + free(ctx->header); + free(ctx); + return SR_ERR; + } + + t = time(NULL); + b = snprintf(ctx->header, MAX_HEADER_LEN, gnuplot_header, + PACKAGE_STRING, ctime(&t), comment, frequency_s, + (char *)&wbuf); + free(frequency_s); + + if (b < 0) { + sr_warn("gnuplot out: %s: sprintf failed", __func__); + free(ctx->header); + free(ctx); + return SR_ERR; + } + + return 0; +} + +static int event(struct sr_output *o, int event_type, char **data_out, + uint64_t *length_out) +{ + struct context *ctx; + + if (!o) { + sr_warn("gnuplot out: %s: o was NULL", __func__); + return SR_ERR_ARG; + } + + if (!data_out) { + sr_warn("gnuplot out: %s: data_out was NULL", __func__); + return SR_ERR_ARG; + } + + if (!length_out) { + sr_warn("gnuplot out: %s: length_out was NULL", __func__); + return SR_ERR_ARG; + } + + ctx = o->internal; + + switch (event_type) { + case SR_DF_TRIGGER: + /* TODO: Can a trigger mark be in a gnuplot data file? */ + break; + case SR_DF_END: + free(o->internal); + o->internal = NULL; + break; + default: + sr_warn("gnuplot out: %s: unsupported event type: %d", + __func__, event_type); + break; + } + + *data_out = NULL; + *length_out = 0; + + return SR_OK; +} + +static int data(struct sr_output *o, const char *data_in, uint64_t length_in, + char **data_out, uint64_t *length_out) +{ + struct context *ctx; + unsigned int max_linelen, outsize, p, curbit, i; + uint64_t sample; + static uint64_t samplecount = 0, old_sample = 0; + char *outbuf, *c; + + if (!o) { + sr_warn("gnuplot out: %s: o was NULL", __func__); + return SR_ERR_ARG; + } + + if (!o->internal) { + sr_warn("gnuplot out: %s: o->internal was NULL", __func__); + return SR_ERR_ARG; + } + + if (!data_in) { + sr_warn("gnuplot out: %s: data_in was NULL", __func__); + return SR_ERR_ARG; + } + + if (!data_out) { + sr_warn("gnuplot out: %s: data_out was NULL", __func__); + return SR_ERR_ARG; + } + + if (!length_out) { + sr_warn("gnuplot out: %s: length_out was NULL", __func__); + return SR_ERR_ARG; + } + + ctx = o->internal; + max_linelen = 16 + ctx->num_enabled_probes * 2; + outsize = length_in / ctx->unitsize * max_linelen; + if (ctx->header) + outsize += strlen(ctx->header); + + if (!(outbuf = calloc(1, outsize))) { + sr_warn("gnuplot out: %s: outbuf calloc failed", __func__); + return SR_ERR_MALLOC; + } + + outbuf[0] = '\0'; + if (ctx->header) { + /* The header is still here, this must be the first packet. */ + strncpy(outbuf, ctx->header, outsize); + free(ctx->header); + ctx->header = NULL; + } + + for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) { + + memcpy(&sample, data_in + i, ctx->unitsize); + + /* + * Don't output the same samples multiple times. However, make + * sure to output at least the first and last sample. + */ + if (samplecount++ != 0 && sample == old_sample) { + if (i != (length_in - ctx->unitsize)) + continue; + } + old_sample = sample; + + /* The first column is a counter (needed for gnuplot). */ + c = outbuf + strlen(outbuf); + sprintf(c, "%" PRIu64 "\t", samplecount++); + + /* The next columns are the values of all channels. */ + for (p = 0; p < ctx->num_enabled_probes; p++) { + curbit = (sample & ((uint64_t) (1 << p))) >> p; + c = outbuf + strlen(outbuf); + sprintf(c, "%d ", curbit); + } + + c = outbuf + strlen(outbuf); + sprintf(c, "\n"); + } + + *data_out = outbuf; + *length_out = strlen(outbuf); + + return SR_OK; +} + +struct sr_output_format output_gnuplot = { + .id = "gnuplot", + .description = "Gnuplot", + .df_type = SR_DF_LOGIC, + .init = init, + .data = data, + .event = event, +}; + +/* Temporarily disabled. */ +#if 0 +static int analog_init(struct sr_output *o) +{ + struct context *ctx; + struct sr_probe *probe; + GSList *l; + uint64_t samplerate; + unsigned int i; + int b, num_probes; + char *c, *frequency_s; + char wbuf[1000], comment[128]; + time_t t; + + if (!(ctx = calloc(1, sizeof(struct context)))) + return SR_ERR_MALLOC; + + if (!(ctx->header = calloc(1, MAX_HEADER_LEN + 1))) { + free(ctx); + return SR_ERR_MALLOC; + } + + o->internal = ctx; + ctx->num_enabled_probes = 0; + for (l = o->device->probes; l; l = l->next) { + probe = l->data; + if (!probe->enabled) + continue; + ctx->probelist[ctx->num_enabled_probes++] = probe->name; + } + ctx->probelist[ctx->num_enabled_probes] = 0; +// ctx->unitsize = (ctx->num_enabled_probes + 7) / 8; + ctx->unitsize = sizeof(struct sr_analog_sample) + + (ctx->num_enabled_probes * sizeof(struct sr_analog_probe)); + + num_probes = g_slist_length(o->device->probes); + comment[0] = '\0'; + if (o->device->plugin && sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) { + samplerate = *((uint64_t *) o->device->plugin->get_device_info( + o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); + if (!(frequency_s = sr_samplerate_string(samplerate))) { + free(ctx->header); + free(ctx); + return SR_ERR; + } + snprintf(comment, 127, gnuplot_header_comment, + ctx->num_enabled_probes, num_probes, frequency_s); + free(frequency_s); + } + + /* Columns / channels */ + wbuf[0] = '\0'; + for (i = 0; i < ctx->num_enabled_probes; i++) { + c = (char *)&wbuf + strlen((char *)&wbuf); + sprintf(c, "# %d\t\t%s\n", i + 1, ctx->probelist[i]); + } + + if (!(frequency_s = sr_period_string(samplerate))) { + free(ctx->header); + free(ctx); + return SR_ERR; + } + t = time(NULL); + b = snprintf(ctx->header, MAX_HEADER_LEN, gnuplot_header, + PACKAGE_STRING, ctime(&t), comment, frequency_s, + (char *)&wbuf); + free(frequency_s); + + if (b < 0) { + free(ctx->header); + free(ctx); + return SR_ERR; + } + + return 0; +} + +static int analog_data(struct sr_output *o, char *data_in, uint64_t length_in, + char **data_out, uint64_t *length_out) +{ + struct context *ctx; + unsigned int max_linelen, outsize, p, /* curbit, */ i; +// uint64_t sample; + static uint64_t samplecount = 0; + char *outbuf, *c; + struct sr_analog_sample *sample; + + ctx = o->internal; +// max_linelen = 16 + ctx->num_enabled_probes * 2; + max_linelen = 16 + ctx->num_enabled_probes * 30; + outsize = length_in / ctx->unitsize * max_linelen; + if (ctx->header) + outsize += strlen(ctx->header); + + if (!(outbuf = calloc(1, outsize))) + return SR_ERR_MALLOC; + + outbuf[0] = '\0'; + if (ctx->header) { + /* The header is still here, this must be the first packet. */ + strncpy(outbuf, ctx->header, outsize); + free(ctx->header); + ctx->header = NULL; + } + + for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) { +// memcpy(&sample, data_in + i, ctx->unitsize); + sample = (struct sr_analog_sample *) (data_in + i); + + /* The first column is a counter (needed for gnuplot). */ + c = outbuf + strlen(outbuf); + sprintf(c, "%" PRIu64 "\t", samplecount++); + + /* The next columns are the values of all channels. */ + for (p = 0; p < ctx->num_enabled_probes; p++) { +// curbit = (sample & ((uint64_t) (1 << p))) >> p; + c = outbuf + strlen(outbuf); +// sprintf(c, "%d ", curbit); + /* + * FIXME: Should be doing proper raw->voltage conversion + * here, casting to int16_t isn't it. Remember that if + * res = 1 conversion isn't necessary. + */ + sprintf(c, "%f ", (double) ((int16_t) (sample->probes[p].val & + ((1 << sample->probes[p].res) - 1)))); + } + + c = outbuf + strlen(outbuf); + sprintf(c, "\n"); + } + + *data_out = outbuf; + *length_out = strlen(outbuf); + + return SR_OK; +} + +struct sr_output_format output_analog_gnuplot = { + .id = "analog_gnuplot", + .description = "Gnuplot analog", + .df_type = SR_DF_ANALOG, + .init = analog_init, + .data = analog_data, + .event = event, +}; +#endif diff --git a/output/ols.c b/output/ols.c new file mode 100644 index 00000000..16b288ac --- /dev/null +++ b/output/ols.c @@ -0,0 +1,136 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2011 Uwe Hermann + * Copyright (C) 2011 Bert Vermeulen + * + * 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 + */ + +/* + * This implements version 1.3 of the output format for the OpenBench Logic + * Sniffer "Alternative" Java client. Details: + * https://github.com/jawi/ols/wiki/OLS-data-file-format + */ + +#include +#include +#include +#include "sigrok.h" +#include "sigrok-internal.h" +#include "config.h" + +struct context { + GString *header; + uint64_t num_samples; + unsigned int unitsize; +}; + +static int init(struct sr_output *o) +{ + struct context *ctx; + struct sr_probe *probe; + GSList *l; + uint64_t samplerate; + int num_enabled_probes; + + if (!(ctx = g_try_malloc(sizeof(struct context)))) { + sr_err("ols out: %s: ctx malloc failed", __func__); + return SR_ERR_MALLOC; + } + o->internal = ctx; + + ctx->num_samples = 0; + num_enabled_probes = 0; + for (l = o->device->probes; l; l = l->next) { + probe = l->data; + if (probe->enabled) + num_enabled_probes++; + } + ctx->unitsize = (num_enabled_probes + 7) / 8; + + if (o->device->plugin && sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) + samplerate = *((uint64_t *) o->device->plugin->get_device_info( + o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); + else + samplerate = 0; + + ctx->header = g_string_sized_new(512); + g_string_append_printf(ctx->header, ";Rate: %"PRIu64"\n", samplerate); + g_string_append_printf(ctx->header, ";Channels: %d\n", num_enabled_probes); + g_string_append_printf(ctx->header, ";EnabledChannels: -1\n"); + g_string_append_printf(ctx->header, ";Compressed: true\n"); + g_string_append_printf(ctx->header, ";CursorEnabled: false\n"); + + return SR_OK; +} + +static int event(struct sr_output *o, int event_type, char **data_out, + uint64_t *length_out) +{ + struct context *ctx; + + ctx = o->internal; + + if (ctx && event_type == SR_DF_END) { + if (ctx->header) + g_string_free(ctx->header, TRUE); + free(o->internal); + o->internal = NULL; + } + + *data_out = NULL; + *length_out = 0; + + return SR_OK; +} + +static int data(struct sr_output *o, const char *data_in, uint64_t length_in, + char **data_out, uint64_t *length_out) +{ + GString *out; + struct context *ctx; + uint64_t sample; + unsigned int i; + + ctx = o->internal; + if (ctx->header) { + /* first data packet */ + out = ctx->header; + ctx->header = NULL; + } else + out = g_string_sized_new(512); + + for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) { + sample = 0; + memcpy(&sample, data_in + i, ctx->unitsize); + g_string_append_printf(out, "%08x@%"PRIu64"\n", + (uint32_t) sample, ctx->num_samples++); + } + *data_out = out->str; + *length_out = out->len; + g_string_free(out, FALSE); + + return SR_OK; +} + +struct sr_output_format output_ols = { + .id = "ols", + .description = "OpenBench Logic Sniffer", + .df_type = SR_DF_LOGIC, + .init = init, + .data = data, + .event = event, +}; diff --git a/output/output_analog.c b/output/output_analog.c deleted file mode 100644 index 5f9fcd55..00000000 --- a/output/output_analog.c +++ /dev/null @@ -1,467 +0,0 @@ -/* - * This file is part of the sigrok project. - * - * Copyright (C) 2010 Bert Vermeulen - * Copyright (C) 2011 HÃ¥vard Espeland - * Copyright (C) 2011 Daniel Ribeiro - * - * 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 . - */ - -#include -#include -#include -#include -#include "sigrok.h" -#include "config.h" - -#define DEFAULT_BPL_BITS 64 -#define DEFAULT_BPL_HEX 192 -#define DEFAULT_BPL_ASCII 74 - -enum outputmode { - MODE_BITS = 1, - MODE_HEX, - MODE_ASCII, -}; - -struct context { - unsigned int num_enabled_probes; - int samples_per_line; - unsigned int unitsize; - int line_offset; - int linebuf_len; - char *probelist[65]; - char *linebuf; - int spl_cnt; - uint8_t *linevalues; - char *header; - int mark_trigger; -// struct sr_analog_sample *prevsample; - enum outputmode mode; -}; - -static void flush_linebufs(struct context *ctx, char *outbuf) -{ - static int max_probename_len = 0; - int len, i; - - if (ctx->linebuf[0] == 0) - return; - - if (max_probename_len == 0) { - /* First time through... */ - for (i = 0; ctx->probelist[i]; i++) { - len = strlen(ctx->probelist[i]); - if (len > max_probename_len) - max_probename_len = len; - } - } - - for (i = 0; ctx->probelist[i]; i++) { - sprintf(outbuf + strlen(outbuf), "%*s:%s\n", max_probename_len, - ctx->probelist[i], ctx->linebuf + i * ctx->linebuf_len); - } - - /* Mark trigger with a ^ character. */ - if (ctx->mark_trigger != -1) - { - int space_offset = ctx->mark_trigger / 8; - - if (ctx->mode == MODE_ASCII) - space_offset = 0; - - sprintf(outbuf + strlen(outbuf), "T:%*s^\n", - ctx->mark_trigger + space_offset, ""); - } - - memset(ctx->linebuf, 0, i * ctx->linebuf_len); -} - -static int init(struct sr_output *o, int default_spl, enum outputmode mode) -{ - struct context *ctx; - struct sr_probe *probe; - GSList *l; - uint64_t samplerate; - int num_probes; - char *samplerate_s; - - if (!(ctx = calloc(1, sizeof(struct context)))) - return SR_ERR_MALLOC; - - o->internal = ctx; - ctx->num_enabled_probes = 0; - - for (l = o->device->probes; l; l = l->next) { - probe = l->data; - if (!probe->enabled) - continue; - ctx->probelist[ctx->num_enabled_probes++] = probe->name; - } - - ctx->probelist[ctx->num_enabled_probes] = 0; - ctx->unitsize = sizeof(struct sr_analog_sample) + - (ctx->num_enabled_probes * sizeof(struct sr_analog_probe)); - ctx->line_offset = 0; - ctx->spl_cnt = 0; - ctx->mark_trigger = -1; - ctx->mode = mode; - - if (o->param && o->param[0]) { - ctx->samples_per_line = strtoul(o->param, NULL, 10); - if (ctx->samples_per_line < 1) - return SR_ERR; - } else - ctx->samples_per_line = default_spl; - - if (!(ctx->header = malloc(512))) { - free(ctx); - return SR_ERR_MALLOC; - } - - snprintf(ctx->header, 511, "%s\n", PACKAGE_STRING); - num_probes = g_slist_length(o->device->probes); - if (o->device->plugin && sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) { - samplerate = *((uint64_t *) o->device->plugin->get_device_info( - o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); - if (!(samplerate_s = sr_samplerate_string(samplerate))) { - free(ctx->header); - free(ctx); - return SR_ERR; - } - snprintf(ctx->header + strlen(ctx->header), - 511 - strlen(ctx->header), - "Acquisition with %d/%d probes at %s\n", - ctx->num_enabled_probes, num_probes, samplerate_s); - free(samplerate_s); - } - - ctx->linebuf_len = ctx->samples_per_line * 2 + 4; - if (!(ctx->linebuf = calloc(1, num_probes * ctx->linebuf_len))) { - free(ctx->header); - free(ctx); - return SR_ERR_MALLOC; - } - if (!(ctx->linevalues = calloc(1, num_probes))) { - free(ctx->header); - free(ctx); - return SR_ERR_MALLOC; - } - - return SR_OK; -} - -static int event(struct sr_output *o, int event_type, char **data_out, - uint64_t *length_out) -{ - struct context *ctx; - int outsize; - char *outbuf; - - ctx = o->internal; - switch (event_type) { - case SR_DF_TRIGGER: - ctx->mark_trigger = ctx->spl_cnt; - *data_out = NULL; - *length_out = 0; - break; - case SR_DF_END: - outsize = ctx->num_enabled_probes - * (ctx->samples_per_line + 20) + 512; - if (!(outbuf = calloc(1, outsize))) - return SR_ERR_MALLOC; - flush_linebufs(ctx, outbuf); - *data_out = outbuf; - *length_out = strlen(outbuf); - free(o->internal); - o->internal = NULL; - break; - default: - *data_out = NULL; - *length_out = 0; - break; - } - - return SR_OK; -} - -static int init_bits(struct sr_output *o) -{ - return init(o, DEFAULT_BPL_BITS, MODE_BITS); -} - -static int data_bits(struct sr_output *o, const char *data_in, - uint64_t length_in, char **data_out, uint64_t *length_out) -{ - struct context *ctx; - unsigned int outsize, offset, p; - int max_linelen; - struct sr_analog_sample *sample; - char *outbuf, c; - - ctx = o->internal; - max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line - + ctx->samples_per_line / 8; - /* - * Calculate space needed for probes. Set aside 512 bytes for - * extra output, e.g. trigger. - */ - outsize = 512 + (1 + (length_in / ctx->unitsize) / ctx->samples_per_line) - * (ctx->num_enabled_probes * max_linelen); - - if (!(outbuf = calloc(1, outsize + 1))) - return SR_ERR_MALLOC; - - outbuf[0] = '\0'; - if (ctx->header) { - /* The header is still here, this must be the first packet. */ - strncpy(outbuf, ctx->header, outsize); - free(ctx->header); - ctx->header = NULL; - - /* Ensure first transition. */ -// memcpy(&ctx->prevsample, data_in, ctx->unitsize); -// ctx->prevsample = ~ctx->prevsample; - } - - if (length_in >= ctx->unitsize) { - for (offset = 0; offset <= length_in - ctx->unitsize; - offset += ctx->unitsize) { - sample = (struct sr_analog_sample *) (data_in + offset); - for (p = 0; p < ctx->num_enabled_probes; p++) { - int val = sample->probes[p].val; - int res = sample->probes[p].res; - if (res == 1) - c = '0' + (val & ((1 << res) - 1)); - else - /* - * Scale analog resolution down so it - * fits 25 letters - */ - c = 'A' + (((val & ((1 << res) - 1)) / - (res * res)) / 10); - ctx->linebuf[p * ctx->linebuf_len + - ctx->line_offset] = c; - } - ctx->line_offset++; - ctx->spl_cnt++; - - /* Add a space every 8th bit. */ - if ((ctx->spl_cnt & 7) == 0) { - for (p = 0; p < ctx->num_enabled_probes; p++) - ctx->linebuf[p * ctx->linebuf_len + - ctx->line_offset] = ' '; - ctx->line_offset++; - } - - /* End of line. */ - if (ctx->spl_cnt >= ctx->samples_per_line) { - flush_linebufs(ctx, outbuf); - ctx->line_offset = ctx->spl_cnt = 0; - ctx->mark_trigger = -1; - } - } - } else { - sr_info("short buffer (length_in=%" PRIu64 ")", length_in); - } - - *data_out = outbuf; - *length_out = strlen(outbuf); - - return SR_OK; -} -#if 0 -static int init_hex(struct sr_output *o) -{ - return init(o, DEFAULT_BPL_HEX, MODE_HEX); -} - -static int data_hex(struct sr_output *o, const char *data_in, - uint64_t length_in, char **data_out, uint64_t *length_out) -{ - struct context *ctx; - unsigned int outsize, offset, p; - int max_linelen; - uint64_t sample; - char *outbuf; - - ctx = o->internal; - max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line - + ctx->samples_per_line / 2; - outsize = length_in / ctx->unitsize * ctx->num_enabled_probes - / ctx->samples_per_line * max_linelen + 512; - - if (!(outbuf = calloc(1, outsize + 1))) - return SR_ERR_MALLOC; - - outbuf[0] = '\0'; - if (ctx->header) { - /* The header is still here, this must be the first packet. */ - strncpy(outbuf, ctx->header, outsize); - free(ctx->header); - ctx->header = NULL; - } - - ctx->line_offset = 0; - for (offset = 0; offset <= length_in - ctx->unitsize; - offset += ctx->unitsize) { - memcpy(&sample, data_in + offset, ctx->unitsize); - for (p = 0; p < ctx->num_enabled_probes; p++) { - ctx->linevalues[p] <<= 1; - if (sample & ((uint64_t) 1 << p)) - ctx->linevalues[p] |= 1; - sprintf(ctx->linebuf + (p * ctx->linebuf_len) + - ctx->line_offset, "%.2x", ctx->linevalues[p]); - } - ctx->spl_cnt++; - - /* Add a space after every complete hex byte. */ - if ((ctx->spl_cnt & 7) == 0) { - for (p = 0; p < ctx->num_enabled_probes; p++) - ctx->linebuf[p * ctx->linebuf_len + - ctx->line_offset + 2] = ' '; - ctx->line_offset += 3; - } - - /* End of line. */ - if (ctx->spl_cnt >= ctx->samples_per_line) { - flush_linebufs(ctx, outbuf); - ctx->line_offset = ctx->spl_cnt = 0; - } - } - - *data_out = outbuf; - *length_out = strlen(outbuf); - - return SR_OK; -} - -static int init_ascii(struct sr_output *o) -{ - return init(o, DEFAULT_BPL_ASCII, MODE_ASCII); -} - -static int data_ascii(struct sr_output *o, const char *data_in, - uint64_t length_in, char **data_out, uint64_t *length_out) -{ - struct context *ctx; - unsigned int outsize, offset, p; - int max_linelen; - uint64_t sample; - char *outbuf; - - ctx = o->internal; - max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line - + ctx->samples_per_line / 8; - /* - * Calculate space needed for probes. Set aside 512 bytes for - * extra output, e.g. trigger. - */ - outsize = 512 + (1 + (length_in / ctx->unitsize) / ctx->samples_per_line) - * (ctx->num_enabled_probes * max_linelen); - - if (!(outbuf = calloc(1, outsize + 1))) - return SR_ERR_MALLOC; - - outbuf[0] = '\0'; - if (ctx->header) { - /* The header is still here, this must be the first packet. */ - strncpy(outbuf, ctx->header, outsize); - free(ctx->header); - ctx->header = NULL; - } - - if (length_in >= ctx->unitsize) { - for (offset = 0; offset <= length_in - ctx->unitsize; - offset += ctx->unitsize) { - memcpy(&sample, data_in + offset, ctx->unitsize); - - char tmpval[ctx->num_enabled_probes]; - - for (p = 0; p < ctx->num_enabled_probes; p++) { - uint64_t curbit = (sample & ((uint64_t) 1 << p)); - uint64_t prevbit = (ctx->prevsample & - ((uint64_t) 1 << p)); - - if (curbit < prevbit && ctx->line_offset > 0) { - ctx->linebuf[p * ctx->linebuf_len + - ctx->line_offset-1] = '\\'; - } - - if (curbit > prevbit) { - tmpval[p] = '/'; - } else { - if (curbit) - tmpval[p] = '"'; - else - tmpval[p] = '.'; - } - } - - /* End of line. */ - if (ctx->spl_cnt >= ctx->samples_per_line) { - flush_linebufs(ctx, outbuf); - ctx->line_offset = ctx->spl_cnt = 0; - ctx->mark_trigger = -1; - } - - for (p = 0; p < ctx->num_enabled_probes; p++) { - ctx->linebuf[p * ctx->linebuf_len + - ctx->line_offset] = tmpval[p]; - } - - ctx->line_offset++; - ctx->spl_cnt++; - - ctx->prevsample = sample; - } - } else { - sr_info("short buffer (length_in=%" PRIu64 ")", length_in); - } - - *data_out = outbuf; - *length_out = strlen(outbuf); - - return SR_OK; -} -#endif - -struct sr_output_format output_analog_bits = { - .id = "analog_bits", - .description = "Bits (takes argument, default 64)", - .df_type = SR_DF_ANALOG, - .init = init_bits, - .data = data_bits, - .event = event, -}; -#if 0 -struct sr_output_format output_analog_hex = { - .id = "analog_hex", - .description = "Hexadecimal (takes argument, default 192)", - .df_type = SR_DF_ANALOG, - .init = init_hex, - .data = data_hex, - .event = event, -}; - -struct sr_output_format output_analog_ascii = { - .id = "analog_ascii", - .description = "ASCII (takes argument, default 74)", - .df_type = SR_DF_ANALOG, - .init = init_ascii, - .data = data_ascii, - .event = event, -}; -#endif diff --git a/output/output_binary.c b/output/output_binary.c deleted file mode 100644 index 039d10bc..00000000 --- a/output/output_binary.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of the sigrok project. - * - * Copyright (C) 2010 Uwe Hermann - * - * 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 -#include -#include -#include "sigrok.h" -#include "sigrok-internal.h" -#include "config.h" - -static int data(struct sr_output *o, const char *data_in, uint64_t length_in, - char **data_out, uint64_t *length_out) -{ - char *outbuf; - - /* Prevent compiler warnings. */ - (void)o; - - if (!data_in) { - sr_warn("binary output: %s: data_in was NULL", __func__); - return SR_ERR; - } - - if (!length_out) { - sr_warn("binary output: %s: length_out was NULL", __func__); - return SR_ERR; - } - - if (length_in == 0) { - sr_warn("binary output: %s: length_in was 0", __func__); - return SR_ERR; - } - - if (!(outbuf = calloc(1, length_in))) { - sr_warn("binary output: %s: outbuf calloc failed", __func__); - return SR_ERR_MALLOC; - } - - memcpy(outbuf, data_in, length_in); - *data_out = outbuf; - *length_out = length_in; - - return SR_OK; -} - -struct sr_output_format output_binary = { - .id = "binary", - .description = "Raw binary", - .df_type = SR_DF_LOGIC, - .init = NULL, - .data = data, - .event = NULL, -}; diff --git a/output/output_chronovu_la8.c b/output/output_chronovu_la8.c deleted file mode 100644 index f6127352..00000000 --- a/output/output_chronovu_la8.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * This file is part of the sigrok project. - * - * Copyright (C) 2011 Uwe Hermann - * - * 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 -#include -#include -#include "sigrok.h" -#include "sigrok-internal.h" - -struct context { - unsigned int num_enabled_probes; - unsigned int unitsize; - char *probelist[SR_MAX_NUM_PROBES + 1]; - uint64_t trigger_point; - uint64_t samplerate; -}; - -/** - * Check if the given samplerate is supported by the LA8 hardware. - * - * @param samplerate The samplerate (in Hz) to check. - * @return 1 if the samplerate is supported/valid, 0 otherwise. - */ -static int is_valid_samplerate(uint64_t samplerate) -{ - unsigned int i; - - for (i = 0; i < 255; i++) { - if (samplerate == (SR_MHZ(100) / (i + 1))) - return 1; - } - - sr_warn("la8 out: %s: invalid samplerate (%" PRIu64 "Hz)", - __func__, samplerate); - - return 0; -} - -/** - * Convert a samplerate (in Hz) to the 'divcount' value the LA8 wants. - * - * LA8 hardware: sample period = (divcount + 1) * 10ns. - * Min. value for divcount: 0x00 (10ns sample period, 100MHz samplerate). - * Max. value for divcount: 0xfe (2550ns sample period, 392.15kHz samplerate). - * - * @param samplerate The samplerate in Hz. - * @return The divcount value as needed by the hardware, or 0xff upon errors. - */ -static uint8_t samplerate_to_divcount(uint64_t samplerate) -{ - if (samplerate == 0) { - sr_warn("la8 out: %s: samplerate was 0", __func__); - return 0xff; - } - - if (!is_valid_samplerate(samplerate)) { - sr_warn("la8 out: %s: can't get divcount, samplerate invalid", - __func__); - return 0xff; - } - - return (SR_MHZ(100) / samplerate) - 1; -} - -static int init(struct sr_output *o) -{ - struct context *ctx; - struct sr_probe *probe; - GSList *l; - int num_probes; - uint64_t samplerate; - - if (!o) { - sr_warn("la8 out: %s: o was NULL", __func__); - return SR_ERR_ARG; - } - - if (!o->device) { - sr_warn("la8 out: %s: o->device was NULL", __func__); - return SR_ERR_ARG; - } - - if (!o->device->plugin) { - sr_warn("la8 out: %s: o->device->plugin was NULL", __func__); - return SR_ERR_ARG; - } - - if (!(ctx = calloc(1, sizeof(struct context)))) { - sr_warn("la8 out: %s: ctx calloc failed", __func__); - return SR_ERR_MALLOC; - } - - o->internal = ctx; - - /* Get the number of probes, their names, and the unitsize. */ - /* TODO: Error handling. */ - for (l = o->device->probes; l; l = l->next) { - probe = l->data; - if (!probe->enabled) - continue; - ctx->probelist[ctx->num_enabled_probes++] = probe->name; - } - ctx->probelist[ctx->num_enabled_probes] = 0; - ctx->unitsize = (ctx->num_enabled_probes + 7) / 8; - - num_probes = g_slist_length(o->device->probes); - - if (sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) { - samplerate = *((uint64_t *) o->device->plugin->get_device_info( - o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); - /* TODO: Error checks. */ - } else { - samplerate = 0; /* TODO: Error or set some value? */ - } - ctx->samplerate = samplerate; - - return 0; /* TODO: SR_OK? */ -} - -static int event(struct sr_output *o, int event_type, char **data_out, - uint64_t *length_out) -{ - struct context *ctx; - char *outbuf; - - if (!o) { - sr_warn("la8 out: %s: o was NULL", __func__); - return SR_ERR_ARG; - } - - if (!(ctx = o->internal)) { - sr_warn("la8 out: %s: o->internal was NULL", __func__); - return SR_ERR_ARG; - } - - if (!data_out) { - sr_warn("la8 out: %s: data_out was NULL", __func__); - return SR_ERR_ARG; - } - - switch (event_type) { - case SR_DF_TRIGGER: - sr_dbg("la8 out: %s: SR_DF_TRIGGER event", __func__); - /* Save the trigger point for later (SR_DF_END). */ - ctx->trigger_point = 0; /* TODO: Store _actual_ value. */ - break; - case SR_DF_END: - sr_dbg("la8 out: %s: SR_DF_END event", __func__); - if (!(outbuf = malloc(4 + 1))) { - sr_warn("la8 out: %s: outbuf malloc failed", __func__); - return SR_ERR_MALLOC; - } - - /* One byte for the 'divcount' value. */ - outbuf[0] = samplerate_to_divcount(ctx->samplerate); - // if (outbuf[0] == 0xff) { - // sr_warn("la8 out: %s: invalid divcount", __func__); - // return SR_ERR; - // } - - /* Four bytes (little endian) for the trigger point. */ - outbuf[1] = (ctx->trigger_point >> 0) & 0xff; - outbuf[2] = (ctx->trigger_point >> 8) & 0xff; - outbuf[3] = (ctx->trigger_point >> 16) & 0xff; - outbuf[4] = (ctx->trigger_point >> 24) & 0xff; - - *data_out = outbuf; - *length_out = 4 + 1; - free(o->internal); - o->internal = NULL; - break; - default: - sr_warn("la8 out: %s: unsupported event type: %d", __func__, - event_type); - *data_out = NULL; - *length_out = 0; - break; - } - - return SR_OK; -} - -static int data(struct sr_output *o, const char *data_in, uint64_t length_in, - char **data_out, uint64_t *length_out) -{ - struct context *ctx; - char *outbuf; - - if (!o) { - sr_warn("la8 out: %s: o was NULL", __func__); - return SR_ERR_ARG; - } - - if (!(ctx = o->internal)) { - sr_warn("la8 out: %s: o->internal was NULL", __func__); - return SR_ERR_ARG; - } - - if (!data_in) { - sr_warn("la8 out: %s: data_in was NULL", __func__); - return SR_ERR_ARG; - } - - if (!(outbuf = calloc(1, length_in))) { - sr_warn("la8 out: %s: outbuf calloc failed", __func__); - return SR_ERR_MALLOC; - } - - memcpy(outbuf, data_in, length_in); - - *data_out = outbuf; - *length_out = length_in; - - return SR_OK; -} - -struct sr_output_format output_chronovu_la8 = { - .id = "chronovu-la8", - .description = "ChronoVu LA8", - .df_type = SR_DF_LOGIC, - .init = init, - .data = data, - .event = event, -}; diff --git a/output/output_csv.c b/output/output_csv.c deleted file mode 100644 index d56a023d..00000000 --- a/output/output_csv.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * This file is part of the sigrok project. - * - * Copyright (C) 2011 Uwe Hermann - * - * 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 -#include -#include -#include "sigrok.h" -#include "sigrok-internal.h" -#include "config.h" - -struct context { - unsigned int num_enabled_probes; - unsigned int unitsize; - char *probelist[SR_MAX_NUM_PROBES + 1]; - 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; - int num_probes; - uint64_t samplerate; - time_t t; - unsigned int i; - - if (!o) { - sr_err("csv out: %s: o was NULL", __func__); - return SR_ERR_ARG; - } - - if (!o->device) { - sr_err("csv out: %s: o->device was NULL", __func__); - return SR_ERR_ARG; - } - - if (!o->device->plugin) { - sr_err("csv out: %s: o->device->plugin was NULL", __func__); - return SR_ERR_ARG; - } - - if (!(ctx = g_try_malloc0(sizeof(struct context)))) { - sr_err("csv out: %s: ctx malloc failed", __func__); - return SR_ERR_MALLOC; - } - - o->internal = ctx; - - /* Get the number of probes, their names, and the unitsize. */ - /* TODO: Error handling. */ - for (l = o->device->probes; l; l = l->next) { - probe = l->data; - if (!probe->enabled) - continue; - ctx->probelist[ctx->num_enabled_probes++] = probe->name; - } - ctx->probelist[ctx->num_enabled_probes] = 0; - ctx->unitsize = (ctx->num_enabled_probes + 7) / 8; - - num_probes = g_slist_length(o->device->probes); - - if (sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) { - samplerate = *((uint64_t *) o->device->plugin->get_device_info( - o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); - /* TODO: Error checks. */ - } else { - samplerate = 0; /* TODO: Error or set some value? */ - } - ctx->samplerate = samplerate; - - 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); - for (i = 0; i < ctx->num_enabled_probes; i++) - g_string_append_printf(ctx->header, "%s, ", ctx->probelist[i]); - g_string_append_printf(ctx->header, "\n"); - - return 0; /* TODO: SR_OK? */ -} - -static int event(struct sr_output *o, int event_type, char **data_out, - uint64_t *length_out) -{ - struct context *ctx; - - if (!o) { - sr_err("csv out: %s: o was NULL", __func__); - return SR_ERR_ARG; - } - - if (!(ctx = o->internal)) { - sr_err("csv out: %s: o->internal was NULL", __func__); - return SR_ERR_ARG; - } - - if (!data_out) { - sr_err("csv out: %s: data_out was NULL", __func__); - return SR_ERR_ARG; - } - - switch (event_type) { - case SR_DF_TRIGGER: - sr_dbg("csv out: %s: SR_DF_TRIGGER event", __func__); - /* TODO */ - *data_out = NULL; - *length_out = 0; - break; - case SR_DF_END: - sr_dbg("csv out: %s: SR_DF_END event", __func__); - /* TODO */ - *data_out = NULL; - *length_out = 0; - g_free(o->internal); - o->internal = NULL; - break; - default: - sr_err("csv out: %s: unsupported event type: %d", __func__, - event_type); - *data_out = NULL; - *length_out = 0; - break; - } - - return SR_OK; -} - -static int data(struct sr_output *o, const char *data_in, uint64_t length_in, - char **data_out, uint64_t *length_out) -{ - struct context *ctx; - GString *outstr; - uint64_t sample, i; - int j; - - if (!o) { - sr_err("csv out: %s: o was NULL", __func__); - return SR_ERR_ARG; - } - - if (!(ctx = o->internal)) { - sr_err("csv out: %s: o->internal was NULL", __func__); - return SR_ERR_ARG; - } - - if (!data_in) { - sr_err("csv out: %s: data_in was NULL", __func__); - 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); - for (j = ctx->num_enabled_probes - 1; j >= 0; j--) { - g_string_append_printf(outstr, "%d%c", - (int)((sample & (1 << j)) >> j), - ctx->separator); - } - g_string_append_printf(outstr, "\n"); - } - - *data_out = outstr->str; - *length_out = outstr->len; - g_string_free(outstr, FALSE); - - return SR_OK; -} - -struct sr_output_format output_csv = { - .id = "csv", - .description = "Comma-separated values (CSV)", - .df_type = SR_DF_LOGIC, - .init = init, - .data = data, - .event = event, -}; diff --git a/output/output_gnuplot.c b/output/output_gnuplot.c deleted file mode 100644 index 39b2d2ee..00000000 --- a/output/output_gnuplot.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - * This file is part of the sigrok project. - * - * Copyright (C) 2010 Uwe Hermann - * - * 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 -#include -#include -#include "sigrok.h" -#include "sigrok-internal.h" -#include "config.h" - -struct context { - unsigned int num_enabled_probes; - unsigned int unitsize; - char *probelist[SR_MAX_NUM_PROBES + 1]; - char *header; -}; - -#define MAX_HEADER_LEN \ - (1024 + (SR_MAX_NUM_PROBES * (SR_MAX_PROBENAME_LEN + 10))) - -static const char *gnuplot_header = "\ -# Sample data in space-separated columns format usable by gnuplot\n\ -#\n\ -# Generated by: %s on %s%s\ -# Period: %s\n\ -#\n\ -# Column\tProbe\n\ -# -------------------------------------\ -----------------------------------------\n\ -# 0\t\tSample counter (for internal gnuplot purposes)\n%s\n"; - -static const char *gnuplot_header_comment = "\ -# Comment: Acquisition with %d/%d probes at %s\n"; - -static int init(struct sr_output *o) -{ - struct context *ctx; - struct sr_probe *probe; - GSList *l; - uint64_t samplerate; - unsigned int i; - int b, num_probes; - char *c, *frequency_s; - char wbuf[1000], comment[128]; - time_t t; - - if (!o) { - sr_warn("gnuplot out: %s: o was NULL", __func__); - return SR_ERR_ARG; - } - - if (!o->device) { - sr_warn("gnuplot out: %s: o->device was NULL", __func__); - return SR_ERR_ARG; - } - - if (!o->device->plugin) { - sr_warn("gnuplot out: %s: o->device->plugin was NULL", - __func__); - return SR_ERR_ARG; - } - - if (!(ctx = calloc(1, sizeof(struct context)))) { - sr_warn("gnuplot out: %s: ctx calloc failed", __func__); - return SR_ERR_MALLOC; - } - - if (!(ctx->header = calloc(1, MAX_HEADER_LEN + 1))) { - sr_warn("gnuplot out: %s: ctx->header calloc failed", - __func__); - free(ctx); - return SR_ERR_MALLOC; - } - - o->internal = ctx; - ctx->num_enabled_probes = 0; - for (l = o->device->probes; l; l = l->next) { - probe = l->data; /* TODO: Error checks. */ - if (!probe->enabled) - continue; - ctx->probelist[ctx->num_enabled_probes++] = probe->name; - } - ctx->probelist[ctx->num_enabled_probes] = 0; - ctx->unitsize = (ctx->num_enabled_probes + 7) / 8; - - num_probes = g_slist_length(o->device->probes); - comment[0] = '\0'; - if (sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) { - samplerate = *((uint64_t *) o->device->plugin->get_device_info( - o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); - if (!(frequency_s = sr_samplerate_string(samplerate))) { - sr_warn("gnuplot out: %s: sr_samplerate_string failed", - __func__); - free(ctx->header); - free(ctx); - return SR_ERR; - } - snprintf(comment, 127, gnuplot_header_comment, - ctx->num_enabled_probes, num_probes, frequency_s); - free(frequency_s); - } - - /* Columns / channels */ - wbuf[0] = '\0'; - for (i = 0; i < ctx->num_enabled_probes; i++) { - c = (char *)&wbuf + strlen((char *)&wbuf); - sprintf(c, "# %d\t\t%s\n", i + 1, ctx->probelist[i]); - } - - if (!(frequency_s = sr_period_string(samplerate))) { - sr_warn("gnuplot out: %s: sr_period_string failed", __func__); - free(ctx->header); - free(ctx); - return SR_ERR; - } - - t = time(NULL); - b = snprintf(ctx->header, MAX_HEADER_LEN, gnuplot_header, - PACKAGE_STRING, ctime(&t), comment, frequency_s, - (char *)&wbuf); - free(frequency_s); - - if (b < 0) { - sr_warn("gnuplot out: %s: sprintf failed", __func__); - free(ctx->header); - free(ctx); - return SR_ERR; - } - - return 0; -} - -static int event(struct sr_output *o, int event_type, char **data_out, - uint64_t *length_out) -{ - struct context *ctx; - - if (!o) { - sr_warn("gnuplot out: %s: o was NULL", __func__); - return SR_ERR_ARG; - } - - if (!data_out) { - sr_warn("gnuplot out: %s: data_out was NULL", __func__); - return SR_ERR_ARG; - } - - if (!length_out) { - sr_warn("gnuplot out: %s: length_out was NULL", __func__); - return SR_ERR_ARG; - } - - ctx = o->internal; - - switch (event_type) { - case SR_DF_TRIGGER: - /* TODO: Can a trigger mark be in a gnuplot data file? */ - break; - case SR_DF_END: - free(o->internal); - o->internal = NULL; - break; - default: - sr_warn("gnuplot out: %s: unsupported event type: %d", - __func__, event_type); - break; - } - - *data_out = NULL; - *length_out = 0; - - return SR_OK; -} - -static int data(struct sr_output *o, const char *data_in, uint64_t length_in, - char **data_out, uint64_t *length_out) -{ - struct context *ctx; - unsigned int max_linelen, outsize, p, curbit, i; - uint64_t sample; - static uint64_t samplecount = 0, old_sample = 0; - char *outbuf, *c; - - if (!o) { - sr_warn("gnuplot out: %s: o was NULL", __func__); - return SR_ERR_ARG; - } - - if (!o->internal) { - sr_warn("gnuplot out: %s: o->internal was NULL", __func__); - return SR_ERR_ARG; - } - - if (!data_in) { - sr_warn("gnuplot out: %s: data_in was NULL", __func__); - return SR_ERR_ARG; - } - - if (!data_out) { - sr_warn("gnuplot out: %s: data_out was NULL", __func__); - return SR_ERR_ARG; - } - - if (!length_out) { - sr_warn("gnuplot out: %s: length_out was NULL", __func__); - return SR_ERR_ARG; - } - - ctx = o->internal; - max_linelen = 16 + ctx->num_enabled_probes * 2; - outsize = length_in / ctx->unitsize * max_linelen; - if (ctx->header) - outsize += strlen(ctx->header); - - if (!(outbuf = calloc(1, outsize))) { - sr_warn("gnuplot out: %s: outbuf calloc failed", __func__); - return SR_ERR_MALLOC; - } - - outbuf[0] = '\0'; - if (ctx->header) { - /* The header is still here, this must be the first packet. */ - strncpy(outbuf, ctx->header, outsize); - free(ctx->header); - ctx->header = NULL; - } - - for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) { - - memcpy(&sample, data_in + i, ctx->unitsize); - - /* - * Don't output the same samples multiple times. However, make - * sure to output at least the first and last sample. - */ - if (samplecount++ != 0 && sample == old_sample) { - if (i != (length_in - ctx->unitsize)) - continue; - } - old_sample = sample; - - /* The first column is a counter (needed for gnuplot). */ - c = outbuf + strlen(outbuf); - sprintf(c, "%" PRIu64 "\t", samplecount++); - - /* The next columns are the values of all channels. */ - for (p = 0; p < ctx->num_enabled_probes; p++) { - curbit = (sample & ((uint64_t) (1 << p))) >> p; - c = outbuf + strlen(outbuf); - sprintf(c, "%d ", curbit); - } - - c = outbuf + strlen(outbuf); - sprintf(c, "\n"); - } - - *data_out = outbuf; - *length_out = strlen(outbuf); - - return SR_OK; -} - -struct sr_output_format output_gnuplot = { - .id = "gnuplot", - .description = "Gnuplot", - .df_type = SR_DF_LOGIC, - .init = init, - .data = data, - .event = event, -}; - -/* Temporarily disabled. */ -#if 0 -static int analog_init(struct sr_output *o) -{ - struct context *ctx; - struct sr_probe *probe; - GSList *l; - uint64_t samplerate; - unsigned int i; - int b, num_probes; - char *c, *frequency_s; - char wbuf[1000], comment[128]; - time_t t; - - if (!(ctx = calloc(1, sizeof(struct context)))) - return SR_ERR_MALLOC; - - if (!(ctx->header = calloc(1, MAX_HEADER_LEN + 1))) { - free(ctx); - return SR_ERR_MALLOC; - } - - o->internal = ctx; - ctx->num_enabled_probes = 0; - for (l = o->device->probes; l; l = l->next) { - probe = l->data; - if (!probe->enabled) - continue; - ctx->probelist[ctx->num_enabled_probes++] = probe->name; - } - ctx->probelist[ctx->num_enabled_probes] = 0; -// ctx->unitsize = (ctx->num_enabled_probes + 7) / 8; - ctx->unitsize = sizeof(struct sr_analog_sample) + - (ctx->num_enabled_probes * sizeof(struct sr_analog_probe)); - - num_probes = g_slist_length(o->device->probes); - comment[0] = '\0'; - if (o->device->plugin && sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) { - samplerate = *((uint64_t *) o->device->plugin->get_device_info( - o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); - if (!(frequency_s = sr_samplerate_string(samplerate))) { - free(ctx->header); - free(ctx); - return SR_ERR; - } - snprintf(comment, 127, gnuplot_header_comment, - ctx->num_enabled_probes, num_probes, frequency_s); - free(frequency_s); - } - - /* Columns / channels */ - wbuf[0] = '\0'; - for (i = 0; i < ctx->num_enabled_probes; i++) { - c = (char *)&wbuf + strlen((char *)&wbuf); - sprintf(c, "# %d\t\t%s\n", i + 1, ctx->probelist[i]); - } - - if (!(frequency_s = sr_period_string(samplerate))) { - free(ctx->header); - free(ctx); - return SR_ERR; - } - t = time(NULL); - b = snprintf(ctx->header, MAX_HEADER_LEN, gnuplot_header, - PACKAGE_STRING, ctime(&t), comment, frequency_s, - (char *)&wbuf); - free(frequency_s); - - if (b < 0) { - free(ctx->header); - free(ctx); - return SR_ERR; - } - - return 0; -} - -static int analog_data(struct sr_output *o, char *data_in, uint64_t length_in, - char **data_out, uint64_t *length_out) -{ - struct context *ctx; - unsigned int max_linelen, outsize, p, /* curbit, */ i; -// uint64_t sample; - static uint64_t samplecount = 0; - char *outbuf, *c; - struct sr_analog_sample *sample; - - ctx = o->internal; -// max_linelen = 16 + ctx->num_enabled_probes * 2; - max_linelen = 16 + ctx->num_enabled_probes * 30; - outsize = length_in / ctx->unitsize * max_linelen; - if (ctx->header) - outsize += strlen(ctx->header); - - if (!(outbuf = calloc(1, outsize))) - return SR_ERR_MALLOC; - - outbuf[0] = '\0'; - if (ctx->header) { - /* The header is still here, this must be the first packet. */ - strncpy(outbuf, ctx->header, outsize); - free(ctx->header); - ctx->header = NULL; - } - - for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) { -// memcpy(&sample, data_in + i, ctx->unitsize); - sample = (struct sr_analog_sample *) (data_in + i); - - /* The first column is a counter (needed for gnuplot). */ - c = outbuf + strlen(outbuf); - sprintf(c, "%" PRIu64 "\t", samplecount++); - - /* The next columns are the values of all channels. */ - for (p = 0; p < ctx->num_enabled_probes; p++) { -// curbit = (sample & ((uint64_t) (1 << p))) >> p; - c = outbuf + strlen(outbuf); -// sprintf(c, "%d ", curbit); - /* - * FIXME: Should be doing proper raw->voltage conversion - * here, casting to int16_t isn't it. Remember that if - * res = 1 conversion isn't necessary. - */ - sprintf(c, "%f ", (double) ((int16_t) (sample->probes[p].val & - ((1 << sample->probes[p].res) - 1)))); - } - - c = outbuf + strlen(outbuf); - sprintf(c, "\n"); - } - - *data_out = outbuf; - *length_out = strlen(outbuf); - - return SR_OK; -} - -struct sr_output_format output_analog_gnuplot = { - .id = "analog_gnuplot", - .description = "Gnuplot analog", - .df_type = SR_DF_ANALOG, - .init = analog_init, - .data = analog_data, - .event = event, -}; -#endif diff --git a/output/output_ols.c b/output/output_ols.c deleted file mode 100644 index 16b288ac..00000000 --- a/output/output_ols.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * This file is part of the sigrok project. - * - * Copyright (C) 2011 Uwe Hermann - * Copyright (C) 2011 Bert Vermeulen - * - * 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 - */ - -/* - * This implements version 1.3 of the output format for the OpenBench Logic - * Sniffer "Alternative" Java client. Details: - * https://github.com/jawi/ols/wiki/OLS-data-file-format - */ - -#include -#include -#include -#include "sigrok.h" -#include "sigrok-internal.h" -#include "config.h" - -struct context { - GString *header; - uint64_t num_samples; - unsigned int unitsize; -}; - -static int init(struct sr_output *o) -{ - struct context *ctx; - struct sr_probe *probe; - GSList *l; - uint64_t samplerate; - int num_enabled_probes; - - if (!(ctx = g_try_malloc(sizeof(struct context)))) { - sr_err("ols out: %s: ctx malloc failed", __func__); - return SR_ERR_MALLOC; - } - o->internal = ctx; - - ctx->num_samples = 0; - num_enabled_probes = 0; - for (l = o->device->probes; l; l = l->next) { - probe = l->data; - if (probe->enabled) - num_enabled_probes++; - } - ctx->unitsize = (num_enabled_probes + 7) / 8; - - if (o->device->plugin && sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) - samplerate = *((uint64_t *) o->device->plugin->get_device_info( - o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); - else - samplerate = 0; - - ctx->header = g_string_sized_new(512); - g_string_append_printf(ctx->header, ";Rate: %"PRIu64"\n", samplerate); - g_string_append_printf(ctx->header, ";Channels: %d\n", num_enabled_probes); - g_string_append_printf(ctx->header, ";EnabledChannels: -1\n"); - g_string_append_printf(ctx->header, ";Compressed: true\n"); - g_string_append_printf(ctx->header, ";CursorEnabled: false\n"); - - return SR_OK; -} - -static int event(struct sr_output *o, int event_type, char **data_out, - uint64_t *length_out) -{ - struct context *ctx; - - ctx = o->internal; - - if (ctx && event_type == SR_DF_END) { - if (ctx->header) - g_string_free(ctx->header, TRUE); - free(o->internal); - o->internal = NULL; - } - - *data_out = NULL; - *length_out = 0; - - return SR_OK; -} - -static int data(struct sr_output *o, const char *data_in, uint64_t length_in, - char **data_out, uint64_t *length_out) -{ - GString *out; - struct context *ctx; - uint64_t sample; - unsigned int i; - - ctx = o->internal; - if (ctx->header) { - /* first data packet */ - out = ctx->header; - ctx->header = NULL; - } else - out = g_string_sized_new(512); - - for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) { - sample = 0; - memcpy(&sample, data_in + i, ctx->unitsize); - g_string_append_printf(out, "%08x@%"PRIu64"\n", - (uint32_t) sample, ctx->num_samples++); - } - *data_out = out->str; - *length_out = out->len; - g_string_free(out, FALSE); - - return SR_OK; -} - -struct sr_output_format output_ols = { - .id = "ols", - .description = "OpenBench Logic Sniffer", - .df_type = SR_DF_LOGIC, - .init = init, - .data = data, - .event = event, -}; diff --git a/output/output_vcd.c b/output/output_vcd.c deleted file mode 100644 index c15e9f07..00000000 --- a/output/output_vcd.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * This file is part of the sigrok project. - * - * Copyright (C) 2010 Uwe Hermann - * Copyright (C) 2011 Bert Vermeulen - * - * 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 -#include -#include -#include "sigrok.h" -#include "sigrok-internal.h" -#include "config.h" - -struct context { - int num_enabled_probes; - int unitsize; - char *probelist[65]; - int *prevbits; - GString *header; - uint64_t prevsample; - int period; - uint64_t samplerate; -}; - -static const char *vcd_header_comment = "\ -$comment\n Acquisition with %d/%d probes at %s\n$end\n"; - -static int init(struct sr_output *o) -{ - struct context *ctx; - struct sr_probe *probe; - GSList *l; - int num_probes, i; - char *samplerate_s, *frequency_s, *timestamp; - time_t t; - - if (!(ctx = calloc(1, sizeof(struct context)))) - return SR_ERR_MALLOC; - - o->internal = ctx; - ctx->num_enabled_probes = 0; - - for (l = o->device->probes; l; l = l->next) { - probe = l->data; - if (!probe->enabled) - continue; - ctx->probelist[ctx->num_enabled_probes++] = probe->name; - } - if (ctx->num_enabled_probes > 94) { - sr_warn("VCD only supports 94 probes."); - return SR_ERR; - } - - ctx->probelist[ctx->num_enabled_probes] = 0; - ctx->unitsize = (ctx->num_enabled_probes + 7) / 8; - ctx->header = g_string_sized_new(512); - num_probes = g_slist_length(o->device->probes); - - /* timestamp */ - t = time(NULL); - timestamp = strdup(ctime(&t)); - timestamp[strlen(timestamp)-1] = 0; - g_string_printf(ctx->header, "$date %s $end\n", timestamp); - free(timestamp); - - /* generator */ - g_string_append_printf(ctx->header, "$version %s %s $end\n", - PACKAGE, PACKAGE_VERSION); - - if (o->device->plugin && sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) { - ctx->samplerate = *((uint64_t *) o->device->plugin->get_device_info( - o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); - if (!((samplerate_s = sr_samplerate_string(ctx->samplerate)))) { - g_string_free(ctx->header, TRUE); - free(ctx); - return SR_ERR; - } - g_string_append_printf(ctx->header, vcd_header_comment, - ctx->num_enabled_probes, num_probes, samplerate_s); - free(samplerate_s); - } - - /* timescale */ - /* VCD can only handle 1/10/100 (s - fs), so scale up first */ - if (ctx->samplerate > SR_MHZ(1)) - ctx->period = SR_GHZ(1); - else if (ctx->samplerate > SR_KHZ(1)) - ctx->period = SR_MHZ(1); - else - ctx->period = SR_KHZ(1); - if (!(frequency_s = sr_period_string(ctx->period))) { - g_string_free(ctx->header, TRUE); - free(ctx); - return SR_ERR; - } - g_string_append_printf(ctx->header, "$timescale %s $end\n", frequency_s); - free(frequency_s); - - /* scope */ - g_string_append_printf(ctx->header, "$scope module %s $end\n", PACKAGE); - - /* Wires / channels */ - for (i = 0; i < ctx->num_enabled_probes; i++) { - g_string_append_printf(ctx->header, "$var wire 1 %c %s $end\n", - (char)('!' + i), ctx->probelist[i]); - } - - g_string_append(ctx->header, "$upscope $end\n" - "$enddefinitions $end\n$dumpvars\n"); - - if (!(ctx->prevbits = calloc(sizeof(int), num_probes))) { - g_string_free(ctx->header, TRUE); - free(ctx); - return SR_ERR_MALLOC; - } - - return SR_OK; -} - -static int event(struct sr_output *o, int event_type, char **data_out, - uint64_t *length_out) -{ - struct context *ctx; - char *outbuf; - - ctx = o->internal; - switch (event_type) { - case SR_DF_END: - outbuf = strdup("$dumpoff\n$end\n"); - *data_out = outbuf; - *length_out = strlen(outbuf); - free(o->internal); - o->internal = NULL; - break; - default: - *data_out = NULL; - *length_out = 0; - break; - } - - return SR_OK; -} - -static int data(struct sr_output *o, const char *data_in, uint64_t length_in, - char **data_out, uint64_t *length_out) -{ - struct context *ctx; - unsigned int i; - int p, curbit, prevbit; - uint64_t sample; - static uint64_t samplecount = 0; - GString *out; - int first_sample = 0; - - ctx = o->internal; - out = g_string_sized_new(512); - - if (ctx->header) { - /* The header is still here, this must be the first packet. */ - g_string_append(out, ctx->header->str); - g_string_free(ctx->header, TRUE); - ctx->header = NULL; - first_sample = 1; - } - - for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) { - samplecount++; - - memcpy(&sample, data_in + i, ctx->unitsize); - - if (first_sample) { - /* First packet. We neg to make sure sample is stored. */ - ctx->prevsample = ~sample; - first_sample = 0; - } - - for (p = 0; p < ctx->num_enabled_probes; p++) { - curbit = (sample & ((uint64_t) (1 << p))) >> p; - prevbit = (ctx->prevsample & ((uint64_t) (1 << p))) >> p; - - /* VCD only contains deltas/changes of signals. */ - if (prevbit == curbit) - continue; - - /* Output which signal changed to which value. */ - g_string_append_printf(out, "#%" PRIu64 "\n%i%c\n", - (uint64_t)(((float)samplecount / ctx->samplerate) - * ctx->period), curbit, (char)('!' + p)); - } - - ctx->prevsample = sample; - } - - *data_out = out->str; - *length_out = out->len; - g_string_free(out, FALSE); - - return SR_OK; -} - -struct sr_output_format output_vcd = { - .id = "vcd", - .description = "Value Change Dump (VCD)", - .df_type = SR_DF_LOGIC, - .init = init, - .data = data, - .event = event, -}; diff --git a/output/vcd.c b/output/vcd.c new file mode 100644 index 00000000..c15e9f07 --- /dev/null +++ b/output/vcd.c @@ -0,0 +1,223 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2010 Uwe Hermann + * Copyright (C) 2011 Bert Vermeulen + * + * 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 +#include +#include +#include "sigrok.h" +#include "sigrok-internal.h" +#include "config.h" + +struct context { + int num_enabled_probes; + int unitsize; + char *probelist[65]; + int *prevbits; + GString *header; + uint64_t prevsample; + int period; + uint64_t samplerate; +}; + +static const char *vcd_header_comment = "\ +$comment\n Acquisition with %d/%d probes at %s\n$end\n"; + +static int init(struct sr_output *o) +{ + struct context *ctx; + struct sr_probe *probe; + GSList *l; + int num_probes, i; + char *samplerate_s, *frequency_s, *timestamp; + time_t t; + + if (!(ctx = calloc(1, sizeof(struct context)))) + return SR_ERR_MALLOC; + + o->internal = ctx; + ctx->num_enabled_probes = 0; + + for (l = o->device->probes; l; l = l->next) { + probe = l->data; + if (!probe->enabled) + continue; + ctx->probelist[ctx->num_enabled_probes++] = probe->name; + } + if (ctx->num_enabled_probes > 94) { + sr_warn("VCD only supports 94 probes."); + return SR_ERR; + } + + ctx->probelist[ctx->num_enabled_probes] = 0; + ctx->unitsize = (ctx->num_enabled_probes + 7) / 8; + ctx->header = g_string_sized_new(512); + num_probes = g_slist_length(o->device->probes); + + /* timestamp */ + t = time(NULL); + timestamp = strdup(ctime(&t)); + timestamp[strlen(timestamp)-1] = 0; + g_string_printf(ctx->header, "$date %s $end\n", timestamp); + free(timestamp); + + /* generator */ + g_string_append_printf(ctx->header, "$version %s %s $end\n", + PACKAGE, PACKAGE_VERSION); + + if (o->device->plugin && sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) { + ctx->samplerate = *((uint64_t *) o->device->plugin->get_device_info( + o->device->plugin_index, SR_DI_CUR_SAMPLERATE)); + if (!((samplerate_s = sr_samplerate_string(ctx->samplerate)))) { + g_string_free(ctx->header, TRUE); + free(ctx); + return SR_ERR; + } + g_string_append_printf(ctx->header, vcd_header_comment, + ctx->num_enabled_probes, num_probes, samplerate_s); + free(samplerate_s); + } + + /* timescale */ + /* VCD can only handle 1/10/100 (s - fs), so scale up first */ + if (ctx->samplerate > SR_MHZ(1)) + ctx->period = SR_GHZ(1); + else if (ctx->samplerate > SR_KHZ(1)) + ctx->period = SR_MHZ(1); + else + ctx->period = SR_KHZ(1); + if (!(frequency_s = sr_period_string(ctx->period))) { + g_string_free(ctx->header, TRUE); + free(ctx); + return SR_ERR; + } + g_string_append_printf(ctx->header, "$timescale %s $end\n", frequency_s); + free(frequency_s); + + /* scope */ + g_string_append_printf(ctx->header, "$scope module %s $end\n", PACKAGE); + + /* Wires / channels */ + for (i = 0; i < ctx->num_enabled_probes; i++) { + g_string_append_printf(ctx->header, "$var wire 1 %c %s $end\n", + (char)('!' + i), ctx->probelist[i]); + } + + g_string_append(ctx->header, "$upscope $end\n" + "$enddefinitions $end\n$dumpvars\n"); + + if (!(ctx->prevbits = calloc(sizeof(int), num_probes))) { + g_string_free(ctx->header, TRUE); + free(ctx); + return SR_ERR_MALLOC; + } + + return SR_OK; +} + +static int event(struct sr_output *o, int event_type, char **data_out, + uint64_t *length_out) +{ + struct context *ctx; + char *outbuf; + + ctx = o->internal; + switch (event_type) { + case SR_DF_END: + outbuf = strdup("$dumpoff\n$end\n"); + *data_out = outbuf; + *length_out = strlen(outbuf); + free(o->internal); + o->internal = NULL; + break; + default: + *data_out = NULL; + *length_out = 0; + break; + } + + return SR_OK; +} + +static int data(struct sr_output *o, const char *data_in, uint64_t length_in, + char **data_out, uint64_t *length_out) +{ + struct context *ctx; + unsigned int i; + int p, curbit, prevbit; + uint64_t sample; + static uint64_t samplecount = 0; + GString *out; + int first_sample = 0; + + ctx = o->internal; + out = g_string_sized_new(512); + + if (ctx->header) { + /* The header is still here, this must be the first packet. */ + g_string_append(out, ctx->header->str); + g_string_free(ctx->header, TRUE); + ctx->header = NULL; + first_sample = 1; + } + + for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) { + samplecount++; + + memcpy(&sample, data_in + i, ctx->unitsize); + + if (first_sample) { + /* First packet. We neg to make sure sample is stored. */ + ctx->prevsample = ~sample; + first_sample = 0; + } + + for (p = 0; p < ctx->num_enabled_probes; p++) { + curbit = (sample & ((uint64_t) (1 << p))) >> p; + prevbit = (ctx->prevsample & ((uint64_t) (1 << p))) >> p; + + /* VCD only contains deltas/changes of signals. */ + if (prevbit == curbit) + continue; + + /* Output which signal changed to which value. */ + g_string_append_printf(out, "#%" PRIu64 "\n%i%c\n", + (uint64_t)(((float)samplecount / ctx->samplerate) + * ctx->period), curbit, (char)('!' + p)); + } + + ctx->prevsample = sample; + } + + *data_out = out->str; + *length_out = out->len; + g_string_free(out, FALSE); + + return SR_OK; +} + +struct sr_output_format output_vcd = { + .id = "vcd", + .description = "Value Change Dump (VCD)", + .df_type = SR_DF_LOGIC, + .init = init, + .data = data, + .event = event, +};