From dbd0aeff352c93d6091f141550683966504a72d5 Mon Sep 17 00:00:00 2001 From: Bert Vermeulen Date: Sat, 19 Apr 2014 12:25:02 +0200 Subject: [PATCH] output/bits: Rewrite for new output API. This also fixes the performance problems in the old module. --- Makefile.am | 2 +- output/bits.c | 211 +++++++++++++++++++++++++++++++++++++++++++++ output/output.c | 4 +- output/text/bits.c | 113 ------------------------ 4 files changed, 214 insertions(+), 116 deletions(-) create mode 100644 output/bits.c delete mode 100644 output/text/bits.c diff --git a/Makefile.am b/Makefile.am index 81a8176d..149f7177 100644 --- a/Makefile.am +++ b/Makefile.am @@ -51,6 +51,7 @@ libsigrok_la_SOURCES += \ # Output formats libsigrok_la_SOURCES += \ output/binary.c \ + output/bits.c \ output/vcd.c \ output/ols.c \ output/gnuplot.c \ @@ -60,7 +61,6 @@ libsigrok_la_SOURCES += \ output/output.c \ output/text/text.c \ output/text/text.h \ - output/text/bits.c \ output/text/hex.c \ output/text/ascii.c diff --git a/output/bits.c b/output/bits.c new file mode 100644 index 00000000..9b4d3487 --- /dev/null +++ b/output/bits.c @@ -0,0 +1,211 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2014 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 "libsigrok.h" +#include "libsigrok-internal.h" + +#define LOG_PREFIX "output/bits" + +#define DEFAULT_SAMPLES_PER_LINE 64 + +struct context { + unsigned int num_enabled_channels; + int samples_per_line; + int spl_cnt; + int trigger; + int *channel_index; + char **channel_names; + GString **lines; + GString *header; +}; + +static int init(struct sr_output *o) +{ + struct context *ctx; + struct sr_channel *ch; + GSList *l; + GVariant *gvar; + uint64_t samplerate; + unsigned int i, j; + int spl, num_channels; + char *samplerate_s; + + if (!o || !o->sdi) + return SR_ERR_ARG; + ctx = g_malloc0(sizeof(struct context)); + o->internal = ctx; + ctx->trigger = -1; + + if (o->param && o->param[0]) { + if ((spl = strtoul(o->param, NULL, 10)) < 1) + return SR_ERR_ARG; + } else + spl = DEFAULT_SAMPLES_PER_LINE; + ctx->samples_per_line = spl; + + for (l = o->sdi->channels; l; l = l->next) { + ch = l->data; + if (ch->type != SR_CHANNEL_LOGIC) + continue; + if (!ch->enabled) + continue; + ctx->num_enabled_channels++; + } + ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels); + ctx->channel_names = g_malloc(sizeof(char *) * ctx->num_enabled_channels); + ctx->lines = g_malloc(sizeof(GString *) * ctx->num_enabled_channels); + + j = 0; + for (i = 0, l = o->sdi->channels; l; l = l->next, i++) { + ch = l->data; + if (ch->type != SR_CHANNEL_LOGIC) + continue; + if (!ch->enabled) + continue; + ctx->channel_index[j] = ch->index; + ctx->channel_names[j] = ch->name; + ctx->lines[j] = g_string_sized_new(80); + g_string_printf(ctx->lines[j], "%s:", ch->name); + j++; + } + + ctx->header = g_string_sized_new(512); + g_string_printf(ctx->header, "%s\n", PACKAGE_STRING); + num_channels = g_slist_length(o->sdi->channels); + if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE, + &gvar) == SR_OK) { + samplerate = g_variant_get_uint64(gvar); + samplerate_s = sr_samplerate_string(samplerate); + g_string_append_printf(ctx->header, "Acquisition with %d/%d channels at %s\n", + ctx->num_enabled_channels, num_channels, samplerate_s); + g_free(samplerate_s); + g_variant_unref(gvar); + } + + return SR_OK; +} + +static int receive(struct sr_output *o, const struct sr_dev_inst *sdi, + const struct sr_datafeed_packet *packet, GString **out) +{ + const struct sr_datafeed_logic *logic; + struct context *ctx; + int idx, offset; + uint64_t i, j; + gchar *p, c; + + (void)sdi; + + *out = NULL; + if (!o || !o->sdi) + return SR_ERR_ARG; + if (!(ctx = o->internal)) + return SR_ERR_ARG; + + switch (packet->type) { + case SR_DF_TRIGGER: + ctx->trigger = ctx->spl_cnt; + break; + case SR_DF_LOGIC: + if (ctx->header) { + /* The header is still here, this must be the first packet. */ + *out = ctx->header; + ctx->header = NULL; + } else + *out = g_string_sized_new(512); + + logic = packet->payload; + for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) { + ctx->spl_cnt++; + for (j = 0; j < ctx->num_enabled_channels; j++) { + idx = ctx->channel_index[j]; + p = logic->data + i + idx / 8; + c = (*p & (1 << (idx % 8))) ? '1' : '0'; + g_string_append_c(ctx->lines[j], c); + + if (ctx->spl_cnt == ctx->samples_per_line) { + /* Flush line buffers. */ + g_string_append_len(*out, ctx->lines[j]->str, ctx->lines[j]->len); + g_string_append_c(*out, '\n'); + if (j == ctx->num_enabled_channels - 1 && ctx->trigger > -1) { + offset = ctx->trigger + ctx->trigger / 8; + g_string_append_printf(*out, "T:%*s^ %d\n", offset, "", ctx->trigger); + ctx->trigger = -1; + } + g_string_printf(ctx->lines[j], "%s:", ctx->channel_names[j]); + } else if ((ctx->spl_cnt & 7) == 0) { + /* Add a space every 8th bit. */ + g_string_append_c(ctx->lines[j], ' '); + } + } + if (ctx->spl_cnt == ctx->samples_per_line) + /* Line buffers were already flushed. */ + ctx->spl_cnt = 0; + } + break; + case SR_DF_END: + if (ctx->spl_cnt) { + /* Line buffers need flushing. */ + *out = g_string_sized_new(512); + for (i = 0; i < ctx->num_enabled_channels; i++) { + g_string_append_len(*out, ctx->lines[i]->str, ctx->lines[i]->len); + g_string_append_c(*out, '\n'); + } + } + break; + } + + return SR_OK; +} + +static int cleanup(struct sr_output *o) +{ + struct context *ctx; + unsigned int i; + + if (!o) + return SR_ERR_ARG; + + if (!(ctx = o->internal)) + return SR_OK; + + g_free(ctx->header); + g_free(ctx->channel_index); + g_free(ctx->channel_names); + for (i = 0; i < ctx->num_enabled_channels; i++) + g_string_free(ctx->lines[i], TRUE); + g_free(ctx->lines); + if (ctx->header) + g_string_free(ctx->header, TRUE); + g_free(ctx); + o->internal = NULL; + + return SR_OK; +} + +SR_PRIV struct sr_output_format output_bits = { + .id = "bits", + .description = "Bits", + .init = init, + .receive = receive, + .cleanup = cleanup, +}; diff --git a/output/output.c b/output/output.c index a3e5dc79..80552f6d 100644 --- a/output/output.c +++ b/output/output.c @@ -49,7 +49,7 @@ */ /** @cond PRIVATE */ -extern SR_PRIV struct sr_output_format output_text_bits; +extern SR_PRIV struct sr_output_format output_bits; extern SR_PRIV struct sr_output_format output_text_hex; extern SR_PRIV struct sr_output_format output_text_ascii; extern SR_PRIV struct sr_output_format output_binary; @@ -63,7 +63,7 @@ extern SR_PRIV struct sr_output_format output_analog; /* @endcond */ static struct sr_output_format *output_module_list[] = { - &output_text_bits, + &output_bits, &output_text_hex, &output_text_ascii, &output_binary, diff --git a/output/text/bits.c b/output/text/bits.c deleted file mode 100644 index 4ab59253..00000000 --- a/output/text/bits.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * This file is part of the libsigrok project. - * - * Copyright (C) 2010-2012 Bert Vermeulen - * Copyright (C) 2011 HÃ¥vard Espeland - * - * 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 "libsigrok.h" -#include "libsigrok-internal.h" -#include "text.h" - -#define LOG_PREFIX "output/bits" - -SR_PRIV int init_bits(struct sr_output *o) -{ - return init(o, DEFAULT_BPL_BITS, MODE_BITS); -} - -SR_PRIV int data_bits(struct sr_output *o, const uint8_t *data_in, - uint64_t length_in, uint8_t **data_out, - uint64_t *length_out) -{ - struct context *ctx; - unsigned int outsize, offset, p; - int max_linelen; - const uint8_t *sample; - uint8_t *outbuf, c; - - ctx = o->internal; - max_linelen = SR_MAX_CHANNELNAME_LEN + 3 + ctx->samples_per_line - + ctx->samples_per_line / 8; - /* - * Calculate space needed for channels. Set aside 512 bytes for - * extra output, e.g. trigger. - */ - outsize = 512 + (1 + (length_in / ctx->unitsize) / ctx->samples_per_line) - * (ctx->num_enabled_channels * max_linelen); - - if (!(outbuf = g_try_malloc0(outsize + 1))) { - sr_err("%s: outbuf malloc failed", __func__); - return SR_ERR_MALLOC; - } - - outbuf[0] = '\0'; - if (ctx->header) { - /* The header is still here, this must be the first packet. */ - strncpy((char *)outbuf, ctx->header, outsize); - g_free(ctx->header); - ctx->header = NULL; - } - - if (length_in >= ctx->unitsize) { - for (offset = 0; offset <= length_in - ctx->unitsize; - offset += ctx->unitsize) { - sample = data_in + offset; - for (p = 0; p < ctx->num_enabled_channels; p++) { - c = (sample[p / 8] & ((uint8_t) 1 << (p % 8))) ? '1' : '0'; - 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_channels; 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((const char *)outbuf); - - return SR_OK; -} - -SR_PRIV struct sr_output_format output_text_bits = { - .id = "bits", - .description = "Bits", - .df_type = SR_DF_LOGIC, - .init = init_bits, - .data = data_bits, - .event = event, - .cleanup = text_cleanup, -};