]> sigrok.org Git - libsigrok.git/blob - output/output_text.c
output_text: Fix ASCII edge case.
[libsigrok.git] / output / output_text.c
1 /*
2  * This file is part of the sigrok project.
3  *
4  * Copyright (C) 2010 Bert Vermeulen <bert@biot.com>
5  * Copyright (C) 2011 HÃ¥vard Espeland <gus@ping.uio.no>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <glib.h>
25 #include <sigrok.h>
26 #include "config.h"
27
28 #define DEFAULT_BPL_BITS 64
29 #define DEFAULT_BPL_HEX  192
30 #define DEFAULT_BPL_ASCII 74
31
32 struct context {
33         unsigned int num_enabled_probes;
34         int samples_per_line;
35         unsigned int unitsize;
36         int line_offset;
37         int linebuf_len;
38         char *probelist[65];
39         char *linebuf;
40         int spl_cnt;
41         uint8_t *linevalues;
42         char *header;
43         int mark_trigger;
44         uint64_t prevsample;
45 };
46
47 static void flush_linebufs(struct context *ctx, char *outbuf)
48 {
49         static int max_probename_len = 0;
50         int len, i;
51
52         if (ctx->linebuf[0] == 0)
53                 return;
54
55         if (max_probename_len == 0) {
56                 /* First time through... */
57                 for (i = 0; ctx->probelist[i]; i++) {
58                         len = strlen(ctx->probelist[i]);
59                         if (len > max_probename_len)
60                                 max_probename_len = len;
61                 }
62         }
63
64         for (i = 0; ctx->probelist[i]; i++) {
65                 sprintf(outbuf + strlen(outbuf), "%*s:%s\n", max_probename_len,
66                         ctx->probelist[i], ctx->linebuf + i * ctx->linebuf_len);
67         }
68
69         /* Mark trigger with a ^ character. */
70         if (ctx->mark_trigger != -1)
71                 sprintf(outbuf + strlen(outbuf), "T:%*s^\n",
72                         ctx->mark_trigger + (ctx->mark_trigger / 8), "");
73
74         memset(ctx->linebuf, 0, i * ctx->linebuf_len);
75 }
76
77 static int init(struct output *o, int default_spl)
78 {
79         struct context *ctx;
80         struct probe *probe;
81         GSList *l;
82         uint64_t samplerate;
83         int num_probes;
84         char *samplerate_s;
85
86         if (!(ctx = calloc(1, sizeof(struct context))))
87                 return SIGROK_ERR_MALLOC;
88
89         o->internal = ctx;
90         ctx->num_enabled_probes = 0;
91
92         for (l = o->device->probes; l; l = l->next) {
93                 probe = l->data;
94                 if (!probe->enabled)
95                         continue;
96                 ctx->probelist[ctx->num_enabled_probes++] = probe->name;
97         }
98
99         ctx->probelist[ctx->num_enabled_probes] = 0;
100         ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
101         ctx->line_offset = 0;
102         ctx->spl_cnt = 0;
103         ctx->mark_trigger = -1;
104
105         if (o->param && o->param[0]) {
106                 ctx->samples_per_line = strtoul(o->param, NULL, 10);
107                 if (ctx->samples_per_line < 1)
108                         return SIGROK_ERR;
109         } else
110                 ctx->samples_per_line = default_spl;
111
112         if (!(ctx->header = malloc(512))) {
113                 free(ctx);
114                 return SIGROK_ERR_MALLOC;
115         }
116
117         snprintf(ctx->header, 511, "%s\n", PACKAGE_STRING);
118         num_probes = g_slist_length(o->device->probes);
119         if (o->device->plugin) {
120                 samplerate = *((uint64_t *) o->device->plugin->get_device_info(
121                                 o->device->plugin_index, DI_CUR_SAMPLERATE));
122                 if (!(samplerate_s = sigrok_samplerate_string(samplerate))) {
123                         free(ctx->header);
124                         free(ctx);
125                         return SIGROK_ERR;
126                 }
127                 snprintf(ctx->header + strlen(ctx->header),
128                          511 - strlen(ctx->header),
129                          "Acquisition with %d/%d probes at %s\n",
130                          ctx->num_enabled_probes, num_probes, samplerate_s);
131                 free(samplerate_s);
132         }
133
134         ctx->linebuf_len = ctx->samples_per_line * 2 + 4;
135         if (!(ctx->linebuf = calloc(1, num_probes * ctx->linebuf_len))) {
136                 free(ctx->header);
137                 free(ctx);
138                 return SIGROK_ERR_MALLOC;
139         }
140         if (!(ctx->linevalues = calloc(1, num_probes))) {
141                 free(ctx->header);
142                 free(ctx);
143                 return SIGROK_ERR_MALLOC;
144         }
145
146         return SIGROK_OK;
147 }
148
149 static int event(struct output *o, int event_type, char **data_out,
150                  uint64_t *length_out)
151 {
152         struct context *ctx;
153         int outsize;
154         char *outbuf;
155
156         ctx = o->internal;
157         switch (event_type) {
158         case DF_TRIGGER:
159                 ctx->mark_trigger = ctx->spl_cnt;
160                 *data_out = NULL;
161                 *length_out = 0;
162                 break;
163         case DF_END:
164                 outsize = ctx->num_enabled_probes
165                                 * (ctx->samples_per_line + 20) + 512;
166                 if (!(outbuf = calloc(1, outsize)))
167                         return SIGROK_ERR_MALLOC;
168                 flush_linebufs(ctx, outbuf);
169                 *data_out = outbuf;
170                 *length_out = strlen(outbuf);
171                 free(o->internal);
172                 o->internal = NULL;
173                 break;
174         default:
175                 *data_out = NULL;
176                 *length_out = 0;
177                 break;
178         }
179
180         return SIGROK_OK;
181 }
182
183 static int init_bits(struct output *o)
184 {
185         return init(o, DEFAULT_BPL_BITS);
186 }
187
188 static int data_bits(struct output *o, char *data_in, uint64_t length_in,
189                      char **data_out, uint64_t *length_out)
190 {
191         struct context *ctx;
192         unsigned int outsize, offset, p;
193         int max_linelen;
194         uint64_t sample;
195         char *outbuf, c;
196
197         ctx = o->internal;
198         max_linelen = MAX_PROBENAME_LEN + 3 + ctx->samples_per_line
199                         + ctx->samples_per_line / 8;
200         /*
201          * Calculate space needed for probes. Set aside 512 bytes for
202          * extra output, e.g. trigger.
203          */
204         outsize = 512 + (1 + (length_in / ctx->unitsize) / ctx->samples_per_line)
205             * (ctx->num_enabled_probes * max_linelen);
206
207         if (!(outbuf = calloc(1, outsize + 1)))
208                 return SIGROK_ERR_MALLOC;
209
210         outbuf[0] = '\0';
211         if (ctx->header) {
212                 /* The header is still here, this must be the first packet. */
213                 strncpy(outbuf, ctx->header, outsize);
214                 free(ctx->header);
215                 ctx->header = NULL;
216
217                 /* Ensure first transition. */
218                 memcpy(&ctx->prevsample, data_in, ctx->unitsize);
219                 ctx->prevsample = ~ctx->prevsample;
220         }
221
222         if (length_in >= ctx->unitsize) {
223                 for (offset = 0; offset <= length_in - ctx->unitsize;
224                      offset += ctx->unitsize) {
225                         memcpy(&sample, data_in + offset, ctx->unitsize);
226                         for (p = 0; p < ctx->num_enabled_probes; p++) {
227                                 c = (sample & ((uint64_t) 1 << p)) ? '1' : '0';
228                                 ctx->linebuf[p * ctx->linebuf_len +
229                                              ctx->line_offset] = c;
230                         }
231                         ctx->line_offset++;
232                         ctx->spl_cnt++;
233
234                         /* Add a space every 8th bit. */
235                         if ((ctx->spl_cnt & 7) == 0) {
236                                 for (p = 0; p < ctx->num_enabled_probes; p++)
237                                         ctx->linebuf[p * ctx->linebuf_len +
238                                                      ctx->line_offset] = ' ';
239                                 ctx->line_offset++;
240                         }
241
242                         /* End of line. */
243                         if (ctx->spl_cnt >= ctx->samples_per_line) {
244                                 flush_linebufs(ctx, outbuf);
245                                 ctx->line_offset = ctx->spl_cnt = 0;
246                                 ctx->mark_trigger = -1;
247                         }
248                 }
249         } else {
250                 g_message("short buffer (length_in=%" PRIu64 ")", length_in);
251         }
252
253         *data_out = outbuf;
254         *length_out = strlen(outbuf);
255
256         return SIGROK_OK;
257 }
258
259 static int init_hex(struct output *o)
260 {
261         return init(o, DEFAULT_BPL_HEX);
262 }
263
264 static int data_hex(struct output *o, char *data_in, uint64_t length_in,
265                     char **data_out, uint64_t *length_out)
266 {
267         struct context *ctx;
268         unsigned int outsize, offset, p;
269         int max_linelen;
270         uint64_t sample;
271         char *outbuf;
272
273         ctx = o->internal;
274         max_linelen = MAX_PROBENAME_LEN + 3 + ctx->samples_per_line
275                         + ctx->samples_per_line / 2;
276         outsize = length_in / ctx->unitsize * ctx->num_enabled_probes
277                         / ctx->samples_per_line * max_linelen + 512;
278
279         if (!(outbuf = calloc(1, outsize + 1)))
280                 return SIGROK_ERR_MALLOC;
281
282         outbuf[0] = '\0';
283         if (ctx->header) {
284                 /* The header is still here, this must be the first packet. */
285                 strncpy(outbuf, ctx->header, outsize);
286                 free(ctx->header);
287                 ctx->header = NULL;
288         }
289
290         ctx->line_offset = 0;
291         for (offset = 0; offset <= length_in - ctx->unitsize;
292              offset += ctx->unitsize) {
293                 memcpy(&sample, data_in + offset, ctx->unitsize);
294                 for (p = 0; p < ctx->num_enabled_probes; p++) {
295                         ctx->linevalues[p] <<= 1;
296                         if (sample & ((uint64_t) 1 << p))
297                                 ctx->linevalues[p] |= 1;
298                         sprintf(ctx->linebuf + (p * ctx->linebuf_len) +
299                                 ctx->line_offset, "%.2x", ctx->linevalues[p]);
300                 }
301                 ctx->spl_cnt++;
302
303                 /* Add a space after every complete hex byte. */
304                 if ((ctx->spl_cnt & 7) == 0) {
305                         for (p = 0; p < ctx->num_enabled_probes; p++)
306                                 ctx->linebuf[p * ctx->linebuf_len +
307                                              ctx->line_offset + 2] = ' ';
308                         ctx->line_offset += 3;
309                 }
310
311                 /* End of line. */
312                 if (ctx->spl_cnt >= ctx->samples_per_line) {
313                         flush_linebufs(ctx, outbuf);
314                         ctx->line_offset = ctx->spl_cnt = 0;
315                 }
316         }
317
318         *data_out = outbuf;
319         *length_out = strlen(outbuf);
320
321         return SIGROK_OK;
322 }
323
324 static int init_ascii(struct output *o)
325 {
326         return init(o, DEFAULT_BPL_ASCII);
327 }
328
329 static int data_ascii(struct output *o, char *data_in, uint64_t length_in,
330                      char **data_out, uint64_t *length_out)
331 {
332         struct context *ctx;
333         unsigned int outsize, offset, p;
334         int max_linelen;
335         uint64_t sample;
336         char *outbuf;
337
338         ctx = o->internal;
339         max_linelen = MAX_PROBENAME_LEN + 3 + ctx->samples_per_line
340                         + ctx->samples_per_line / 8;
341         /*
342          * Calculate space needed for probes. Set aside 512 bytes for
343          * extra output, e.g. trigger.
344          */
345         outsize = 512 + (1 + (length_in / ctx->unitsize) / ctx->samples_per_line)
346             * (ctx->num_enabled_probes * max_linelen);
347
348         if (!(outbuf = calloc(1, outsize + 1)))
349                 return SIGROK_ERR_MALLOC;
350
351         outbuf[0] = '\0';
352         if (ctx->header) {
353                 /* The header is still here, this must be the first packet. */
354                 strncpy(outbuf, ctx->header, outsize);
355                 free(ctx->header);
356                 ctx->header = NULL;
357         }
358
359         if (length_in >= ctx->unitsize) {
360                 for (offset = 0; offset <= length_in - ctx->unitsize;
361                      offset += ctx->unitsize) {
362                         memcpy(&sample, data_in + offset, ctx->unitsize);
363
364                         char tmpval[ctx->num_enabled_probes];
365
366                         for (p = 0; p < ctx->num_enabled_probes; p++) {
367                                 uint64_t curbit = (sample & ((uint64_t) 1 << p));
368                                 uint64_t prevbit = (ctx->prevsample &
369                                                 ((uint64_t) 1 << p));
370
371                                 if (curbit < prevbit && ctx->line_offset > 0) {
372                                         ctx->linebuf[p * ctx->linebuf_len +
373                                                 ctx->line_offset-1] = '\\';
374                                 }
375
376                                 if (curbit > prevbit) {
377                                         tmpval[p] = '/';
378                                 } else {
379                                         if (curbit)
380                                                 tmpval[p] = '"';
381                                         else
382                                                 tmpval[p] = '.';
383                                 }
384                         }
385
386                         /* End of line. */
387                         if (ctx->spl_cnt >= ctx->samples_per_line) {
388                                 flush_linebufs(ctx, outbuf);
389                                 ctx->line_offset = ctx->spl_cnt = 0;
390                                 ctx->mark_trigger = -1;
391                         }
392
393                         for (p = 0; p < ctx->num_enabled_probes; p++) {
394                                 ctx->linebuf[p * ctx->linebuf_len +
395                                              ctx->line_offset] = tmpval[p];
396                         }
397
398                         ctx->line_offset++;
399                         ctx->spl_cnt++;
400
401                         ctx->prevsample = sample;
402                 }
403         } else {
404                 g_message("short buffer (length_in=%" PRIu64 ")", length_in);
405         }
406
407         *data_out = outbuf;
408         *length_out = strlen(outbuf);
409
410         return SIGROK_OK;
411 }
412
413
414 struct output_format output_text_bits = {
415         "bits",
416         "Bits (takes argument, default 64)",
417         DF_LOGIC,
418         init_bits,
419         data_bits,
420         event,
421 };
422
423 struct output_format output_text_hex = {
424         "hex",
425         "Hexadecimal (takes argument, default 192)",
426         DF_LOGIC,
427         init_hex,
428         data_hex,
429         event,
430 };
431
432 struct output_format output_text_ascii = {
433         "ascii",
434         "ASCII (takes argument, default 74)",
435         DF_LOGIC,
436         init_ascii,
437         data_ascii,
438         event,
439 };