X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;f=output%2Fanalog.c;h=9873a8f5f8e92d461bbe0b44f4dbfc38368d531c;hb=3544f848e0d7f67af8e11ce7ec344b34cd797df3;hp=65bdc71d3beaff7736871d7ec7f02989d4f0dd83;hpb=5097b0d0912165429aceddb5febbf68467b623f5;p=libsigrok.git diff --git a/output/analog.c b/output/analog.c index 65bdc71d..9873a8f5 100644 --- a/output/analog.c +++ b/output/analog.c @@ -1,9 +1,7 @@ /* - * This file is part of the sigrok project. + * This file is part of the libsigrok project. * - * Copyright (C) 2010-2012 Bert Vermeulen - * Copyright (C) 2011 HÃ¥vard Espeland - * Copyright (C) 2011 Daniel Ribeiro + * Copyright (C) 2012 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 @@ -20,465 +18,254 @@ */ #include -#include #include +#include #include -#include "sigrok.h" +#include "libsigrok.h" +#include "libsigrok-internal.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, -}; +#define LOG_PREFIX "output/analog" 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; + int num_enabled_probes; + GPtrArray *probelist; }; -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) +static int init(struct sr_output *o) { struct context *ctx; struct sr_probe *probe; GSList *l; - uint64_t samplerate; - int num_probes; - char *samplerate_s; + + sr_spew("Initializing output module."); + + if (!o || !o->sdi) + return SR_ERR_ARG; if (!(ctx = g_try_malloc0(sizeof(struct context)))) { - sr_err("analog out: %s: ctx malloc failed", __func__); + sr_err("Output module context malloc failed."); return SR_ERR_MALLOC; } - o->internal = ctx; - ctx->num_enabled_probes = 0; - for (l = o->dev->probes; l; l = l->next) { + /* Get the number of probes and their names. */ + ctx->probelist = g_ptr_array_new(); + for (l = o->sdi->probes; l; l = l->next) { probe = l->data; - if (!probe->enabled) + if (!probe || !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 = g_try_malloc(512))) { - g_free(ctx); - sr_err("analog out: %s: ctx->header malloc failed", __func__); - return SR_ERR_MALLOC; - } - - snprintf(ctx->header, 511, "%s\n", PACKAGE_STRING); - num_probes = g_slist_length(o->dev->probes); - if (o->dev->plugin && sr_dev_has_hwcap(o->dev, SR_HWCAP_SAMPLERATE)) { - samplerate = *((uint64_t *) o->dev->plugin->dev_info_get( - o->dev->plugin_index, SR_DI_CUR_SAMPLERATE)); - if (!(samplerate_s = sr_samplerate_string(samplerate))) { - g_free(ctx->header); - g_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); - g_free(samplerate_s); - } - - ctx->linebuf_len = ctx->samples_per_line * 2 + 4; - if (!(ctx->linebuf = g_try_malloc0(num_probes * ctx->linebuf_len))) { - g_free(ctx->header); - g_free(ctx); - sr_err("analog out: %s: ctx->linebuf malloc failed", __func__); - return SR_ERR_MALLOC; - } - if (!(ctx->linevalues = g_try_malloc0(num_probes))) { - g_free(ctx->header); - g_free(ctx); - sr_err("analog out: %s: ctx->linevalues malloc failed", - __func__); - return SR_ERR_MALLOC; + g_ptr_array_add(ctx->probelist, probe->name); + ctx->num_enabled_probes++; } return SR_OK; } -static int event(struct sr_output *o, int event_type, char **data_out, - uint64_t *length_out) +static void si_printf(float value, GString *out, char *unitstr) { - struct context *ctx; - int outsize; - char *outbuf; + float v; + + if (signbit(value)) + v = -(value); + else + v = value; + + if (v < 1e-12 || v > 1e+12) + g_string_append_printf(out, "%f %s", value, unitstr); + else if (v > 1e+9) + g_string_append_printf(out, "%f G%s", value / 1e+9, unitstr); + else if (v > 1e+6) + g_string_append_printf(out, "%f M%s", value / 1e+6, unitstr); + else if (v > 1e+3) + g_string_append_printf(out, "%f k%s", value / 1e+3, unitstr); + else if (v < 1e-9) + g_string_append_printf(out, "%f n%s", value * 1e+9, unitstr); + else if (v < 1e-6) + g_string_append_printf(out, "%f u%s", value * 1e+6, unitstr); + else if (v < 1e-3) + g_string_append_printf(out, "%f m%s", value * 1e+3, unitstr); + else + g_string_append_printf(out, "%f %s", value, unitstr); - ctx = o->internal; - switch (event_type) { - case SR_DF_TRIGGER: - ctx->mark_trigger = ctx->spl_cnt; - *data_out = NULL; - *length_out = 0; +} + +static void fancyprint(int unit, int mqflags, float value, GString *out) +{ + switch (unit) { + case SR_UNIT_VOLT: + si_printf(value, out, "V"); break; - case SR_DF_END: - outsize = ctx->num_enabled_probes - * (ctx->samples_per_line + 20) + 512; - if (!(outbuf = g_try_malloc0(outsize))) { - sr_err("analog out: %s: outbuf malloc failed", - __func__); - return SR_ERR_MALLOC; - } - flush_linebufs(ctx, outbuf); - *data_out = outbuf; - *length_out = strlen(outbuf); - g_free(o->internal); - o->internal = NULL; + case SR_UNIT_AMPERE: + si_printf(value, out, "A"); + break; + case SR_UNIT_OHM: + si_printf(value, out, ""); + g_string_append_unichar(out, 0x2126); + break; + case SR_UNIT_FARAD: + si_printf(value, out, "F"); + break; + case SR_UNIT_KELVIN: + si_printf(value, out, "K"); + break; + case SR_UNIT_CELSIUS: + si_printf(value, out, ""); + g_string_append_unichar(out, 0x00b0); + g_string_append_c(out, 'C'); + break; + case SR_UNIT_FAHRENHEIT: + si_printf(value, out, ""); + g_string_append_unichar(out, 0x00b0); + g_string_append_c(out, 'F'); + break; + case SR_UNIT_HERTZ: + si_printf(value, out, "Hz"); + break; + case SR_UNIT_PERCENTAGE: + g_string_append_printf(out, "%f%%", value); + break; + case SR_UNIT_BOOLEAN: + if (value > 0) + g_string_append_printf(out, "TRUE"); + else + g_string_append_printf(out, "FALSE"); + break; + case SR_UNIT_SECOND: + si_printf(value, out, "s"); + break; + case SR_UNIT_SIEMENS: + si_printf(value, out, "S"); + break; + case SR_UNIT_DECIBEL_MW: + si_printf(value, out, "dBu"); + break; + case SR_UNIT_DECIBEL_VOLT: + si_printf(value, out, "dBV"); + break; + case SR_UNIT_DECIBEL_SPL: + if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_A) + si_printf(value, out, "dB(A)"); + else if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_C) + si_printf(value, out, "dB(C)"); + else if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_Z) + si_printf(value, out, "dB(Z)"); + else + /* No frequency weighting, or non-standard "flat" */ + si_printf(value, out, "dB(SPL)"); + if (mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_S) + g_string_append(out, " S"); + else if (mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_F) + g_string_append(out, " F"); + if (mqflags & SR_MQFLAG_SPL_LAT) + g_string_append(out, " LAT"); + else if (mqflags & SR_MQFLAG_SPL_PCT_OVER_ALARM) + /* Not a standard function for SLMs, so this is + * a made-up notation. */ + g_string_append(out, " %oA"); + break; + case SR_UNIT_CONCENTRATION: + g_string_append_printf(out, "%f ppm", value * 1000000); + break; + case SR_UNIT_REVOLUTIONS_PER_MINUTE: + si_printf(value, out, "RPM"); + break; + case SR_UNIT_VOLT_AMPERE: + si_printf(value, out, "VA"); + break; + case SR_UNIT_WATT: + si_printf(value, out, "W"); + break; + case SR_UNIT_WATT_HOUR: + si_printf(value, out, "Wh"); break; default: - *data_out = NULL; - *length_out = 0; + si_printf(value, out, ""); break; } - return SR_OK; -} - -static int init_bits(struct sr_output *o) -{ - return init(o, DEFAULT_BPL_BITS, MODE_BITS); + if (mqflags & SR_MQFLAG_AC) + g_string_append_printf(out, " AC"); + if (mqflags & SR_MQFLAG_DC) + g_string_append_printf(out, " DC"); + if (mqflags & SR_MQFLAG_RMS) + g_string_append_printf(out, " RMS"); + if (mqflags & SR_MQFLAG_DIODE) + g_string_append_printf(out, " DIODE"); + if (mqflags & SR_MQFLAG_HOLD) + g_string_append_printf(out, " HOLD"); + if (mqflags & SR_MQFLAG_MAX) + g_string_append_printf(out, " MAX"); + if (mqflags & SR_MQFLAG_MIN) + g_string_append_printf(out, " MIN"); + if (mqflags & SR_MQFLAG_AUTORANGE) + g_string_append_printf(out, " AUTO"); + if (mqflags & SR_MQFLAG_RELATIVE) + g_string_append_printf(out, " REL"); + if (mqflags & SR_MQFLAG_AVG) + g_string_append_printf(out, " AVG"); + g_string_append_c(out, '\n'); } -static int data_bits(struct sr_output *o, const char *data_in, - uint64_t length_in, char **data_out, uint64_t *length_out) +static int receive(struct sr_output *o, const struct sr_dev_inst *sdi, + const struct sr_datafeed_packet *packet, GString **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 = g_try_malloc0(outsize + 1))) { - sr_err("analog out: %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(outbuf, ctx->header, outsize); - g_free(ctx->header); - ctx->header = NULL; - - /* Ensure first transition. */ -// memcpy(&ctx->prevsample, data_in, ctx->unitsize); -// ctx->prevsample = ~ctx->prevsample; - } + const struct sr_datafeed_analog *analog; + struct sr_probe *probe; + GSList *l; + const float *fdata; + int i, p; - 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++; + (void)sdi; - /* 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++; - } + *out = NULL; + if (!o || !o->sdi) + return SR_ERR_ARG; - /* 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; + switch (packet->type) { + case SR_DF_FRAME_BEGIN: + *out = g_string_new("FRAME-BEGIN\n"); + break; + case SR_DF_FRAME_END: + *out = g_string_new("FRAME-END\n"); + break; + case SR_DF_ANALOG: + analog = packet->payload; + fdata = (const float *)analog->data; + *out = g_string_sized_new(512); + for (i = 0; i < analog->num_samples; i++) { + for (l = analog->probes, p = 0; l; l = l->next, p++) { + probe = l->data; + g_string_append_printf(*out, "%s: ", probe->name); + fancyprint(analog->unit, analog->mqflags, + fdata[i + p], *out); } } - } else { - sr_info("analog out: 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 = g_try_malloc0(outsize + 1))) { - sr_err("analog out: %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(outbuf, ctx->header, outsize); - g_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; - } + break; } - *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) +static int cleanup(struct sr_output *o) { struct context *ctx; - unsigned int outsize, offset, p; - int max_linelen; - uint64_t sample; - char *outbuf; + if (!o || !o->sdi) + return SR_ERR_ARG; 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 = g_try_malloc0(outsize + 1))) { - sr_err("analog out: %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(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) { - 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("analog out: short buffer (length_in=%" PRIu64 ")", - length_in); - } - - *data_out = outbuf; - *length_out = strlen(outbuf); + g_ptr_array_free(ctx->probelist, 1); + g_free(ctx); + o->internal = NULL; return SR_OK; } -#endif - -SR_PRIV 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)", +SR_PRIV struct sr_output_format output_analog = { + .id = "analog", + .description = "Analog data", .df_type = SR_DF_ANALOG, - .init = init_ascii, - .data = data_ascii, - .event = event, + .init = init, + .receive = receive, + .cleanup = cleanup }; -#endif