From: Bert Vermeulen Date: Sat, 19 Apr 2014 10:34:30 +0000 (+0200) Subject: output/ascii: Rewrite for new output API. X-Git-Tag: libsigrok-0.3.0~76 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=6f64ebb22306d1436becd9da4fb3761c99462810;p=libsigrok.git output/ascii: Rewrite for new output API. --- diff --git a/Makefile.am b/Makefile.am index 1cc6b35f..a19123b6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -62,7 +62,7 @@ libsigrok_la_SOURCES += \ output/text/text.c \ output/text/text.h \ output/hex.c \ - output/text/ascii.c + output/ascii.c # Hardware (common files) libsigrok_la_SOURCES += \ diff --git a/output/ascii.c b/output/ascii.c new file mode 100644 index 00000000..884769c8 --- /dev/null +++ b/output/ascii.c @@ -0,0 +1,226 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2011 HÃ¥vard Espeland + * 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/hex" + +#define DEFAULT_SAMPLES_PER_LINE 74 + +struct context { + unsigned int num_enabled_channels; + int samples_per_line; + int bit_cnt; + int spl_cnt; + int trigger; + int *channel_index; + char **channel_names; + char **line_values; + uint8_t *prev_sample; + 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); + ctx->prev_sample = g_malloc(g_slist_length(o->sdi->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, curbit, prevbit; + 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; + curbit = *p & (1 << (idx % 8)); + prevbit = (ctx->prev_sample[idx / 8] & ((uint8_t) 1 << (idx % 8))); + + c = curbit ? '"' : '.'; + if (ctx->spl_cnt > 1) { + if (curbit < prevbit) + c = '\\'; + else if (curbit > prevbit) + c = '/'; + } + 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]); + } + } + if (ctx->spl_cnt == ctx->samples_per_line) + /* Line buffers were already flushed. */ + ctx->spl_cnt = 0; + memcpy(ctx->prev_sample, logic->data + i, logic->unitsize); + } + 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->prev_sample); + 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_ascii = { + .id = "ascii", + .description = "ASCII", + .init = init, + .receive = receive, + .cleanup = cleanup, +}; + + diff --git a/output/output.c b/output/output.c index 76ff758b..a0c81e82 100644 --- a/output/output.c +++ b/output/output.c @@ -51,7 +51,7 @@ /** @cond PRIVATE */ extern SR_PRIV struct sr_output_format output_bits; extern SR_PRIV struct sr_output_format output_hex; -extern SR_PRIV struct sr_output_format output_text_ascii; +extern SR_PRIV struct sr_output_format output_ascii; extern SR_PRIV struct sr_output_format output_binary; extern SR_PRIV struct sr_output_format output_vcd; extern SR_PRIV struct sr_output_format output_ols; @@ -59,13 +59,12 @@ extern SR_PRIV struct sr_output_format output_gnuplot; extern SR_PRIV struct sr_output_format output_chronovu_la8; extern SR_PRIV struct sr_output_format output_csv; extern SR_PRIV struct sr_output_format output_analog; -/* extern SR_PRIV struct sr_output_format output_analog_gnuplot; */ /* @endcond */ static struct sr_output_format *output_module_list[] = { &output_bits, &output_hex, - &output_text_ascii, + &output_ascii, &output_binary, &output_vcd, &output_ols, @@ -73,7 +72,6 @@ static struct sr_output_format *output_module_list[] = { &output_chronovu_la8, &output_csv, &output_analog, - /* &output_analog_gnuplot, */ NULL, }; diff --git a/output/text/ascii.c b/output/text/ascii.c deleted file mode 100644 index 3b3bcc72..00000000 --- a/output/text/ascii.c +++ /dev/null @@ -1,130 +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/ascii" - -SR_PRIV int init_ascii(struct sr_output *o) -{ - return init(o, DEFAULT_BPL_ASCII, MODE_ASCII); -} - -SR_PRIV int data_ascii(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; - - 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; - - char tmpval[ctx->num_enabled_channels]; - - for (p = 0; p < ctx->num_enabled_channels; p++) { - uint8_t curbit = (sample[p / 8] & ((uint8_t) 1 << (p % 8))); - uint8_t prevbit = (ctx->prevsample[p / 8] & - ((uint8_t) 1 << (p % 8))); - - 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_channels; p++) { - ctx->linebuf[p * ctx->linebuf_len + - ctx->line_offset] = tmpval[p]; - } - - ctx->line_offset++; - ctx->spl_cnt++; - - memcpy(ctx->prevsample, sample, ctx->unitsize); - } - } 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_ascii = { - .id = "ascii", - .description = "ASCII", - .df_type = SR_DF_LOGIC, - .init = init_ascii, - .data = data_ascii, - .event = event, - .cleanup = text_cleanup, -};