]> sigrok.org Git - libsigrok.git/blob - output/output_gnuplot.c
ec50b9d2bfa8a6c3bc794986f5bb98351eb9134d
[libsigrok.git] / output / output_gnuplot.c
1 /*
2  * This file is part of the sigrok project.
3  *
4  * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <glib.h>
24 #include <sigrok.h>
25 #include "config.h"
26
27 struct context {
28         unsigned int num_enabled_probes;
29         unsigned int unitsize;
30         char *probelist[SR_MAX_NUM_PROBES + 1];
31         char *header;
32 };
33
34 #define MAX_HEADER_LEN \
35         (1024 + (SR_MAX_NUM_PROBES * (SR_MAX_PROBENAME_LEN + 10)))
36
37 static const char *gnuplot_header = "\
38 # Sample data in space-separated columns format usable by gnuplot\n\
39 #\n\
40 # Generated by: %s on %s%s\
41 # Period: %s\n\
42 #\n\
43 # Column\tProbe\n\
44 # -------------------------------------\
45 ----------------------------------------\n\
46 # 0\t\tSample counter (for internal gnuplot purposes)\n%s\n";
47
48 static const char *gnuplot_header_comment = "\
49 # Comment: Acquisition with %d/%d probes at %s\n";
50
51 static int init(struct sr_output *o)
52 {
53         struct context *ctx;
54         struct sr_probe *probe;
55         GSList *l;
56         uint64_t samplerate;
57         unsigned int i;
58         int b, num_probes;
59         char *c, *frequency_s;
60         char wbuf[1000], comment[128];
61         time_t t;
62
63         if (!o) {
64                 g_warning("gnuplot out: %s: o was NULL", __func__);
65                 return SR_ERR_ARG;
66         }
67
68         if (!o->device) {
69                 g_warning("gnuplot out: %s: o->device was NULL", __func__);
70                 return SR_ERR_ARG;
71         }
72
73         if (!o->device->plugin) {
74                 g_warning("gnuplot out: %s: o->device->plugin was NULL",
75                           __func__);
76                 return SR_ERR_ARG;
77         }
78
79         if (!(ctx = calloc(1, sizeof(struct context)))) {
80                 g_warning("gnuplot out: %s: ctx calloc failed", __func__);
81                 return SR_ERR_MALLOC;
82         }
83
84         if (!(ctx->header = calloc(1, MAX_HEADER_LEN + 1))) {
85                 g_warning("gnuplot out: %s: ctx->header calloc failed",
86                           __func__);
87                 free(ctx);
88                 return SR_ERR_MALLOC;
89         }
90
91         o->internal = ctx;
92         ctx->num_enabled_probes = 0;
93         for (l = o->device->probes; l; l = l->next) {
94                 probe = l->data; /* TODO: Error checks. */
95                 if (!probe->enabled)
96                         continue;
97                 ctx->probelist[ctx->num_enabled_probes++] = probe->name;
98         }
99         ctx->probelist[ctx->num_enabled_probes] = 0;
100         ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
101
102         num_probes = g_slist_length(o->device->probes);
103         comment[0] = '\0';
104         if (sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) {
105                 samplerate = *((uint64_t *) o->device->plugin->get_device_info(
106                                 o->device->plugin_index, SR_DI_CUR_SAMPLERATE));
107                 if (!(frequency_s = sr_samplerate_string(samplerate))) {
108                         g_warning("gnuplot out: %s: sr_samplerate_string "
109                                   "failed", __func__);
110                         free(ctx->header);
111                         free(ctx);
112                         return SR_ERR;
113                 }
114                 snprintf(comment, 127, gnuplot_header_comment,
115                         ctx->num_enabled_probes, num_probes, frequency_s);
116                 free(frequency_s);
117         }
118
119         /* Columns / channels */
120         wbuf[0] = '\0';
121         for (i = 0; i < ctx->num_enabled_probes; i++) {
122                 c = (char *)&wbuf + strlen((char *)&wbuf);
123                 sprintf(c, "# %d\t\t%s\n", i + 1, ctx->probelist[i]);
124         }
125
126         if (!(frequency_s = sr_period_string(samplerate))) {
127                 g_warning("gnuplot out: %s: sr_period_string failed", __func__);
128                 free(ctx->header);
129                 free(ctx);
130                 return SR_ERR;
131         }
132
133         t = time(NULL);
134         b = snprintf(ctx->header, MAX_HEADER_LEN, gnuplot_header,
135                      PACKAGE_STRING, ctime(&t), comment, frequency_s,
136                      (char *)&wbuf);
137         free(frequency_s);
138
139         if (b < 0) {
140                 g_warning("gnuplot out: %s: sprintf failed", __func__);
141                 free(ctx->header);
142                 free(ctx);
143                 return SR_ERR;
144         }
145
146         return 0;
147 }
148
149 static int event(struct sr_output *o, int event_type, char **data_out,
150                  uint64_t *length_out)
151 {
152         struct context *ctx;
153
154         if (!o) {
155                 g_warning("gnuplot out: %s: o was NULL", __func__);
156                 return SR_ERR_ARG;
157         }
158
159         if (!data_out) {
160                 g_warning("gnuplot out: %s: data_out was NULL", __func__);
161                 return SR_ERR_ARG;
162         }
163
164         if (!length_out) {
165                 g_warning("gnuplot out: %s: length_out was NULL", __func__);
166                 return SR_ERR_ARG;
167         }
168
169         ctx = o->internal;
170
171         switch (event_type) {
172         case SR_DF_TRIGGER:
173                 /* TODO: Can a trigger mark be in a gnuplot data file? */
174                 break;
175         case SR_DF_END:
176                 free(o->internal);
177                 o->internal = NULL;
178                 break;
179         default:
180                 g_warning("gnuplot out: %s: unsupported event type: %d",
181                           __func__, event_type);
182                 break;
183         }
184
185         *data_out = NULL;
186         *length_out = 0;
187
188         return SR_OK;
189 }
190
191 static int data(struct sr_output *o, const char *data_in, uint64_t length_in,
192                 char **data_out, uint64_t *length_out)
193 {
194         struct context *ctx;
195         unsigned int max_linelen, outsize, p, curbit, i;
196         uint64_t sample;
197         static uint64_t samplecount = 0;
198         char *outbuf, *c;
199
200         if (!o) {
201                 g_warning("gnuplot out: %s: o was NULL", __func__);
202                 return SR_ERR_ARG;
203         }
204
205         if (!o->internal) {
206                 g_warning("gnuplot out: %s: o->internal was NULL", __func__);
207                 return SR_ERR_ARG;
208         }
209
210         if (!data_in) {
211                 g_warning("gnuplot out: %s: data_in was NULL", __func__);
212                 return SR_ERR_ARG;
213         }
214
215         if (!data_out) {
216                 g_warning("gnuplot out: %s: data_out was NULL", __func__);
217                 return SR_ERR_ARG;
218         }
219
220         if (!length_out) {
221                 g_warning("gnuplot out: %s: length_out was NULL", __func__);
222                 return SR_ERR_ARG;
223         }
224
225         ctx = o->internal;
226         max_linelen = 16 + ctx->num_enabled_probes * 2;
227         outsize = length_in / ctx->unitsize * max_linelen;
228         if (ctx->header)
229                 outsize += strlen(ctx->header);
230
231         if (!(outbuf = calloc(1, outsize))) {
232                 g_warning("gnuplot out: %s: outbuf calloc failed", __func__);
233                 return SR_ERR_MALLOC;
234         }
235
236         outbuf[0] = '\0';
237         if (ctx->header) {
238                 /* The header is still here, this must be the first packet. */
239                 strncpy(outbuf, ctx->header, outsize);
240                 free(ctx->header);
241                 ctx->header = NULL;
242         }
243
244         for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) {
245                 memcpy(&sample, data_in + i, ctx->unitsize);
246
247                 /* The first column is a counter (needed for gnuplot). */
248                 c = outbuf + strlen(outbuf);
249                 sprintf(c, "%" PRIu64 "\t", samplecount++);
250
251                 /* The next columns are the values of all channels. */
252                 for (p = 0; p < ctx->num_enabled_probes; p++) {
253                         curbit = (sample & ((uint64_t) (1 << p))) >> p;
254                         c = outbuf + strlen(outbuf);
255                         sprintf(c, "%d ", curbit);
256                 }
257
258                 c = outbuf + strlen(outbuf);
259                 sprintf(c, "\n");
260         }
261
262         *data_out = outbuf;
263         *length_out = strlen(outbuf);
264
265         return SR_OK;
266 }
267
268 struct sr_output_format output_gnuplot = {
269         .id = "gnuplot",
270         .description = "Gnuplot",
271         .df_type = SR_DF_LOGIC,
272         .init = init,
273         .data = data,
274         .event = event,
275 };
276
277 /* Temporarily disabled. */
278 #if 0
279 static int analog_init(struct sr_output *o)
280 {
281         struct context *ctx;
282         struct sr_probe *probe;
283         GSList *l;
284         uint64_t samplerate;
285         unsigned int i;
286         int b, num_probes;
287         char *c, *frequency_s;
288         char wbuf[1000], comment[128];
289         time_t t;
290
291         if (!(ctx = calloc(1, sizeof(struct context))))
292                 return SR_ERR_MALLOC;
293
294         if (!(ctx->header = calloc(1, MAX_HEADER_LEN + 1))) {
295                 free(ctx);
296                 return SR_ERR_MALLOC;
297         }
298
299         o->internal = ctx;
300         ctx->num_enabled_probes = 0;
301         for (l = o->device->probes; l; l = l->next) {
302                 probe = l->data;
303                 if (!probe->enabled)
304                         continue;
305                 ctx->probelist[ctx->num_enabled_probes++] = probe->name;
306         }
307         ctx->probelist[ctx->num_enabled_probes] = 0;
308 //      ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
309         ctx->unitsize = sizeof(struct sr_analog_sample) +
310                         (ctx->num_enabled_probes * sizeof(struct sr_analog_probe));
311
312         num_probes = g_slist_length(o->device->probes);
313         comment[0] = '\0';
314         if (o->device->plugin && sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) {
315                 samplerate = *((uint64_t *) o->device->plugin->get_device_info(
316                                 o->device->plugin_index, SR_DI_CUR_SAMPLERATE));
317                 if (!(frequency_s = sr_samplerate_string(samplerate))) {
318                         free(ctx->header);
319                         free(ctx);
320                         return SR_ERR;
321                 }
322                 snprintf(comment, 127, gnuplot_header_comment,
323                         ctx->num_enabled_probes, num_probes, frequency_s);
324                 free(frequency_s);
325         }
326
327         /* Columns / channels */
328         wbuf[0] = '\0';
329         for (i = 0; i < ctx->num_enabled_probes; i++) {
330                 c = (char *)&wbuf + strlen((char *)&wbuf);
331                 sprintf(c, "# %d\t\t%s\n", i + 1, ctx->probelist[i]);
332         }
333
334         if (!(frequency_s = sr_period_string(samplerate))) {
335                 free(ctx->header);
336                 free(ctx);
337                 return SR_ERR;
338         }
339         t = time(NULL);
340         b = snprintf(ctx->header, MAX_HEADER_LEN, gnuplot_header,
341                      PACKAGE_STRING, ctime(&t), comment, frequency_s,
342                      (char *)&wbuf);
343         free(frequency_s);
344
345         if (b < 0) {
346                 free(ctx->header);
347                 free(ctx);
348                 return SR_ERR;
349         }
350
351         return 0;
352 }
353
354 static int analog_data(struct sr_output *o, char *data_in, uint64_t length_in,
355                 char **data_out, uint64_t *length_out)
356 {
357         struct context *ctx;
358         unsigned int max_linelen, outsize, p, /* curbit, */ i;
359 //      uint64_t sample;
360         static uint64_t samplecount = 0;
361         char *outbuf, *c;
362         struct sr_analog_sample *sample;
363
364         ctx = o->internal;
365 //      max_linelen = 16 + ctx->num_enabled_probes * 2;
366         max_linelen = 16 + ctx->num_enabled_probes * 30;
367         outsize = length_in / ctx->unitsize * max_linelen;
368         if (ctx->header)
369                 outsize += strlen(ctx->header);
370
371         if (!(outbuf = calloc(1, outsize)))
372                 return SR_ERR_MALLOC;
373
374         outbuf[0] = '\0';
375         if (ctx->header) {
376                 /* The header is still here, this must be the first packet. */
377                 strncpy(outbuf, ctx->header, outsize);
378                 free(ctx->header);
379                 ctx->header = NULL;
380         }
381
382         for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) {
383 //              memcpy(&sample, data_in + i, ctx->unitsize);
384                 sample = (struct sr_analog_sample *) (data_in + i);
385
386                 /* The first column is a counter (needed for gnuplot). */
387                 c = outbuf + strlen(outbuf);
388                 sprintf(c, "%" PRIu64 "\t", samplecount++);
389
390                 /* The next columns are the values of all channels. */
391                 for (p = 0; p < ctx->num_enabled_probes; p++) {
392 //                      curbit = (sample & ((uint64_t) (1 << p))) >> p;
393                         c = outbuf + strlen(outbuf);
394 //                      sprintf(c, "%d ", curbit);
395                         /*
396                          * FIXME: Should be doing proper raw->voltage conversion
397                          * here, casting to int16_t isn't it. Remember that if
398                          * res = 1 conversion isn't necessary.
399                          */
400                         sprintf(c, "%f ", (double) ((int16_t) (sample->probes[p].val &
401                                         ((1 << sample->probes[p].res) - 1))));
402                 }
403
404                 c = outbuf + strlen(outbuf);
405                 sprintf(c, "\n");
406         }
407
408         *data_out = outbuf;
409         *length_out = strlen(outbuf);
410
411         return SR_OK;
412 }
413
414 struct sr_output_format output_analog_gnuplot = {
415         .id = "analog_gnuplot",
416         .description = "Gnuplot analog",
417         .df_type = SR_DF_ANALOG,
418         .init = analog_init,
419         .data = analog_data,
420         .event = event,
421 };
422 #endif