libsigrok
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines
gnuplot.c
Go to the documentation of this file.
00001 /*
00002  * This file is part of the sigrok project.
00003  *
00004  * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00019  */
00020 
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <glib.h>
00024 #include "config.h"
00025 #include "sigrok.h"
00026 #include "sigrok-internal.h"
00027 
00028 struct context {
00029         unsigned int num_enabled_probes;
00030         unsigned int unitsize;
00031         char *probelist[SR_MAX_NUM_PROBES + 1];
00032         char *header;
00033 };
00034 
00035 #define MAX_HEADER_LEN \
00036         (1024 + (SR_MAX_NUM_PROBES * (SR_MAX_PROBENAME_LEN + 10)))
00037 
00038 static const char *gnuplot_header = "\
00039 # Sample data in space-separated columns format usable by gnuplot\n\
00040 #\n\
00041 # Generated by: %s on %s%s\
00042 # Period: %s\n\
00043 #\n\
00044 # Column\tProbe\n\
00045 # -------------------------------------\
00046 ----------------------------------------\n\
00047 # 0\t\tSample counter (for internal gnuplot purposes)\n%s\n";
00048 
00049 static const char *gnuplot_header_comment = "\
00050 # Comment: Acquisition with %d/%d probes at %s\n";
00051 
00052 static int init(struct sr_output *o)
00053 {
00054         struct context *ctx;
00055         struct sr_probe *probe;
00056         GSList *l;
00057         uint64_t samplerate;
00058         unsigned int i;
00059         int b, num_probes;
00060         char *c, *frequency_s;
00061         char wbuf[1000], comment[128];
00062         time_t t;
00063 
00064         if (!o) {
00065                 sr_err("gnuplot out: %s: o was NULL", __func__);
00066                 return SR_ERR_ARG;
00067         }
00068 
00069         if (!o->dev) {
00070                 sr_err("gnuplot out: %s: o->dev was NULL", __func__);
00071                 return SR_ERR_ARG;
00072         }
00073 
00074         if (!o->dev->driver) {
00075                 sr_err("gnuplot out: %s: o->dev->driver was NULL", __func__);
00076                 return SR_ERR_ARG;
00077         }
00078 
00079         if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
00080                 sr_err("gnuplot out: %s: ctx malloc failed", __func__);
00081                 return SR_ERR_MALLOC;
00082         }
00083 
00084         if (!(ctx->header = g_try_malloc0(MAX_HEADER_LEN + 1))) {
00085                 sr_err("gnuplot out: %s: ctx->header malloc failed", __func__);
00086                 g_free(ctx);
00087                 return SR_ERR_MALLOC;
00088         }
00089 
00090         o->internal = ctx;
00091         ctx->num_enabled_probes = 0;
00092         for (l = o->dev->probes; l; l = l->next) {
00093                 probe = l->data; /* TODO: Error checks. */
00094                 if (!probe->enabled)
00095                         continue;
00096                 ctx->probelist[ctx->num_enabled_probes++] = probe->name;
00097         }
00098         ctx->probelist[ctx->num_enabled_probes] = 0;
00099         ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
00100 
00101         num_probes = g_slist_length(o->dev->probes);
00102         comment[0] = '\0';
00103         if (sr_dev_has_hwcap(o->dev, SR_HWCAP_SAMPLERATE)) {
00104                 samplerate = *((uint64_t *) o->dev->driver->dev_info_get(
00105                                 o->dev->driver_index, SR_DI_CUR_SAMPLERATE));
00106                 if (!(frequency_s = sr_samplerate_string(samplerate))) {
00107                         sr_err("gnuplot out: %s: sr_samplerate_string failed",
00108                                __func__);
00109                         g_free(ctx->header);
00110                         g_free(ctx);
00111                         return SR_ERR;
00112                 }
00113                 snprintf(comment, 127, gnuplot_header_comment,
00114                         ctx->num_enabled_probes, num_probes, frequency_s);
00115                 g_free(frequency_s);
00116         }
00117 
00118         /* Columns / channels */
00119         wbuf[0] = '\0';
00120         for (i = 0; i < ctx->num_enabled_probes; i++) {
00121                 c = (char *)&wbuf + strlen((const char *)&wbuf);
00122                 sprintf(c, "# %d\t\t%s\n", i + 1, ctx->probelist[i]);
00123         }
00124 
00125         if (!(frequency_s = sr_period_string(samplerate))) {
00126                 sr_err("gnuplot out: %s: sr_period_string failed", __func__);
00127                 g_free(ctx->header);
00128                 g_free(ctx);
00129                 return SR_ERR;
00130         }
00131 
00132         t = time(NULL);
00133         b = snprintf(ctx->header, MAX_HEADER_LEN, gnuplot_header,
00134                      PACKAGE_STRING, ctime(&t), comment, frequency_s,
00135                      (char *)&wbuf);
00136         g_free(frequency_s);
00137 
00138         if (b < 0) {
00139                 sr_err("gnuplot out: %s: sprintf failed", __func__);
00140                 g_free(ctx->header);
00141                 g_free(ctx);
00142                 return SR_ERR;
00143         }
00144 
00145         return 0;
00146 }
00147 
00148 static int event(struct sr_output *o, int event_type, uint8_t **data_out,
00149                  uint64_t *length_out)
00150 {
00151         if (!o) {
00152                 sr_err("gnuplot out: %s: o was NULL", __func__);
00153                 return SR_ERR_ARG;
00154         }
00155 
00156         if (!data_out) {
00157                 sr_err("gnuplot out: %s: data_out was NULL", __func__);
00158                 return SR_ERR_ARG;
00159         }
00160 
00161         if (!length_out) {
00162                 sr_err("gnuplot out: %s: length_out was NULL", __func__);
00163                 return SR_ERR_ARG;
00164         }
00165 
00166         switch (event_type) {
00167         case SR_DF_TRIGGER:
00168                 /* TODO: Can a trigger mark be in a gnuplot data file? */
00169                 break;
00170         case SR_DF_END:
00171                 g_free(o->internal);
00172                 o->internal = NULL;
00173                 break;
00174         default:
00175                 sr_err("gnuplot out: %s: unsupported event type: %d",
00176                        __func__, event_type);
00177                 break;
00178         }
00179 
00180         *data_out = NULL;
00181         *length_out = 0;
00182 
00183         return SR_OK;
00184 }
00185 
00186 static int data(struct sr_output *o, const uint8_t *data_in,
00187                 uint64_t length_in, uint8_t **data_out, uint64_t *length_out)
00188 {
00189         struct context *ctx;
00190         unsigned int max_linelen, outsize, p, curbit, i;
00191         uint64_t sample;
00192         static uint64_t samplecount = 0, old_sample = 0;
00193         uint8_t *outbuf, *c;
00194 
00195         if (!o) {
00196                 sr_err("gnuplot out: %s: o was NULL", __func__);
00197                 return SR_ERR_ARG;
00198         }
00199 
00200         if (!o->internal) {
00201                 sr_err("gnuplot out: %s: o->internal was NULL", __func__);
00202                 return SR_ERR_ARG;
00203         }
00204 
00205         if (!data_in) {
00206                 sr_err("gnuplot out: %s: data_in was NULL", __func__);
00207                 return SR_ERR_ARG;
00208         }
00209 
00210         if (!data_out) {
00211                 sr_err("gnuplot out: %s: data_out was NULL", __func__);
00212                 return SR_ERR_ARG;
00213         }
00214 
00215         if (!length_out) {
00216                 sr_err("gnuplot out: %s: length_out was NULL", __func__);
00217                 return SR_ERR_ARG;
00218         }
00219 
00220         ctx = o->internal;
00221         max_linelen = 16 + ctx->num_enabled_probes * 2;
00222         outsize = length_in / ctx->unitsize * max_linelen;
00223         if (ctx->header)
00224                 outsize += strlen(ctx->header);
00225 
00226         if (!(outbuf = g_try_malloc0(outsize))) {
00227                 sr_err("gnuplot out: %s: outbuf malloc failed", __func__);
00228                 return SR_ERR_MALLOC;
00229         }
00230 
00231         outbuf[0] = '\0';
00232         if (ctx->header) {
00233                 /* The header is still here, this must be the first packet. */
00234                 strncpy((char *)outbuf, ctx->header, outsize);
00235                 g_free(ctx->header);
00236                 ctx->header = NULL;
00237         }
00238 
00239         for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) {
00240 
00241                 memcpy(&sample, data_in + i, ctx->unitsize);
00242 
00243                 /*
00244                  * Don't output the same samples multiple times. However, make
00245                  * sure to output at least the first and last sample.
00246                  */
00247                 if (samplecount++ != 0 && sample == old_sample) {
00248                         if (i != (length_in - ctx->unitsize))
00249                                 continue;
00250                 }
00251                 old_sample = sample;
00252 
00253                 /* The first column is a counter (needed for gnuplot). */
00254                 c = outbuf + strlen((const char *)outbuf);
00255                 sprintf((char *)c, "%" PRIu64 "\t", samplecount++);
00256 
00257                 /* The next columns are the values of all channels. */
00258                 for (p = 0; p < ctx->num_enabled_probes; p++) {
00259                         curbit = (sample & ((uint64_t) (1 << p))) >> p;
00260                         c = outbuf + strlen((const char *)outbuf);
00261                         sprintf((char *)c, "%d ", curbit);
00262                 }
00263 
00264                 c = outbuf + strlen((const char *)outbuf);
00265                 sprintf((char *)c, "\n");
00266         }
00267 
00268         *data_out = outbuf;
00269         *length_out = strlen((const char *)outbuf);
00270 
00271         return SR_OK;
00272 }
00273 
00274 SR_PRIV struct sr_output_format output_gnuplot = {
00275         .id = "gnuplot",
00276         .description = "Gnuplot",
00277         .df_type = SR_DF_LOGIC,
00278         .init = init,
00279         .data = data,
00280         .event = event,
00281 };
00282 
00283 /* Temporarily disabled. */
00284 #if 0
00285 static int analog_init(struct sr_output *o)
00286 {
00287         struct context *ctx;
00288         struct sr_probe *probe;
00289         GSList *l;
00290         uint64_t samplerate;
00291         unsigned int i;
00292         int b, num_probes;
00293         char *c, *frequency_s;
00294         char wbuf[1000], comment[128];
00295         time_t t;
00296 
00297         if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
00298                 sr_err("gnuplot out: %s: ctx malloc failed", __func__);
00299                 return SR_ERR_MALLOC;
00300         }
00301 
00302         if (!(ctx->header = g_try_malloc0(MAX_HEADER_LEN + 1))) {
00303                 g_free(ctx);
00304                 sr_err("gnuplot out: %s: ctx->header malloc failed", __func__);
00305                 return SR_ERR_MALLOC;
00306         }
00307 
00308         o->internal = ctx;
00309         ctx->num_enabled_probes = 0;
00310         for (l = o->dev->probes; l; l = l->next) {
00311                 probe = l->data;
00312                 if (!probe->enabled)
00313                         continue;
00314                 ctx->probelist[ctx->num_enabled_probes++] = probe->name;
00315         }
00316         ctx->probelist[ctx->num_enabled_probes] = 0;
00317 //      ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
00318         ctx->unitsize = sizeof(struct sr_analog_sample) +
00319                         (ctx->num_enabled_probes * sizeof(struct sr_analog_probe));
00320 
00321         num_probes = g_slist_length(o->dev->probes);
00322         comment[0] = '\0';
00323         if (o->dev->driver && sr_dev_has_hwcap(o->dev, SR_HWCAP_SAMPLERATE)) {
00324                 samplerate = *((uint64_t *) o->dev->driver->dev_info_get(
00325                                 o->dev->driver_index, SR_DI_CUR_SAMPLERATE));
00326                 if (!(frequency_s = sr_samplerate_string(samplerate))) {
00327                         g_free(ctx->header);
00328                         g_free(ctx);
00329                         return SR_ERR;
00330                 }
00331                 snprintf(comment, 127, gnuplot_header_comment,
00332                         ctx->num_enabled_probes, num_probes, frequency_s);
00333                 g_free(frequency_s);
00334         }
00335 
00336         /* Columns / channels */
00337         wbuf[0] = '\0';
00338         for (i = 0; i < ctx->num_enabled_probes; i++) {
00339                 c = (char *)&wbuf + strlen((char *)&wbuf);
00340                 sprintf(c, "# %d\t\t%s\n", i + 1, ctx->probelist[i]);
00341         }
00342 
00343         if (!(frequency_s = sr_period_string(samplerate))) {
00344                 g_free(ctx->header);
00345                 g_free(ctx);
00346                 return SR_ERR;
00347         }
00348         t = time(NULL);
00349         b = snprintf(ctx->header, MAX_HEADER_LEN, gnuplot_header,
00350                      PACKAGE_STRING, ctime(&t), comment, frequency_s,
00351                      (char *)&wbuf);
00352         g_free(frequency_s);
00353 
00354         if (b < 0) {
00355                 g_free(ctx->header);
00356                 g_free(ctx);
00357                 return SR_ERR;
00358         }
00359 
00360         return 0;
00361 }
00362 
00363 static int analog_data(struct sr_output *o, uint8_t *data_in,
00364                        uint64_t length_in, uint8_t **data_out,
00365                        uint64_t *length_out)
00366 {
00367         struct context *ctx;
00368         unsigned int max_linelen, outsize, p, /* curbit, */ i;
00369 //      uint64_t sample;
00370         static uint64_t samplecount = 0;
00371         uint8_t *outbuf, *c;
00372         struct sr_analog_sample *sample;
00373 
00374         ctx = o->internal;
00375 //      max_linelen = 16 + ctx->num_enabled_probes * 2;
00376         max_linelen = 16 + ctx->num_enabled_probes * 30;
00377         outsize = length_in / ctx->unitsize * max_linelen;
00378         if (ctx->header)
00379                 outsize += strlen(ctx->header);
00380 
00381         if (!(outbuf = g_try_malloc0(outsize))) {
00382                 sr_err("gnuplot out: %s: outbuf malloc failed", __func__);
00383                 return SR_ERR_MALLOC;
00384         }
00385 
00386         outbuf[0] = '\0';
00387         if (ctx->header) {
00388                 /* The header is still here, this must be the first packet. */
00389                 strncpy(outbuf, ctx->header, outsize);
00390                 g_free(ctx->header);
00391                 ctx->header = NULL;
00392         }
00393 
00394         for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) {
00395 //              memcpy(&sample, data_in + i, ctx->unitsize);
00396                 sample = (struct sr_analog_sample *) (data_in + i);
00397 
00398                 /* The first column is a counter (needed for gnuplot). */
00399                 c = outbuf + strlen(outbuf);
00400                 sprintf(c, "%" PRIu64 "\t", samplecount++);
00401 
00402                 /* The next columns are the values of all channels. */
00403                 for (p = 0; p < ctx->num_enabled_probes; p++) {
00404 //                      curbit = (sample & ((uint64_t) (1 << p))) >> p;
00405                         c = outbuf + strlen(outbuf);
00406 //                      sprintf(c, "%d ", curbit);
00407                         /*
00408                          * FIXME: Should be doing proper raw->voltage conversion
00409                          * here, casting to int16_t isn't it. Remember that if
00410                          * res = 1 conversion isn't necessary.
00411                          */
00412                         sprintf(c, "%f ", (double) ((int16_t) (sample->probes[p].val &
00413                                         ((1 << sample->probes[p].res) - 1))));
00414                 }
00415 
00416                 c = outbuf + strlen(outbuf);
00417                 sprintf(c, "\n");
00418         }
00419 
00420         *data_out = outbuf;
00421         *length_out = strlen(outbuf);
00422 
00423         return SR_OK;
00424 }
00425 
00426 struct sr_output_format output_analog_gnuplot = {
00427         .id = "analog_gnuplot",
00428         .description = "Gnuplot analog",
00429         .df_type = SR_DF_ANALOG,
00430         .init = analog_init,
00431         .data = analog_data,
00432         .event = event,
00433 };
00434 #endif
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines