]> sigrok.org Git - libsigrok.git/blob - src/output/vcd.c
ec326b7eeae99d1184b9cd18f8e12607bd2923a2
[libsigrok.git] / src / output / vcd.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
5  * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
6  * Copyright (C) 2017-2020 Gerhard Sittig <gerhard.sittig@gmx.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 /*
23  * TODO
24  * - Check the mixed signal queue for completeness and correctness.
25  * - Tune the analog "immediate write" code path for throughput.
26  * - Remove excess diagnostics when the implementation is considered
27  *   feature complete and reliable.
28  */
29
30 #include <config.h>
31
32 #include <ctype.h>
33 #include <glib.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include <libsigrok/libsigrok.h>
38 #include "libsigrok-internal.h"
39
40 #define LOG_PREFIX "output/vcd"
41
42 static const int with_queue_stats = 0;
43 static const int with_pool_stats = 0;
44
45 struct vcd_channel_desc {
46         size_t index;
47         GString *name;
48         enum sr_channeltype type;
49         struct {
50                 uint8_t logic;
51                 double real;
52         } last;
53         uint64_t last_rcvd_snum;
54 };
55
56 /** Queued values for a given sample number. */
57 struct vcd_queue_item {
58         uint64_t samplenum;     /**!< sample number, _not_ timestamp */
59         GString *values;        /**!< text of value changes */
60 };
61
62 struct context {
63         size_t enabled_count;
64         size_t logic_count;
65         size_t analog_count;
66         gboolean header_done;
67         uint64_t period;
68         struct vcd_channel_desc *channels;
69         uint64_t samplerate;
70         GSList *free_list, *used_list;
71         size_t alloced, freed, reused, pooled;
72         GList *vcd_queue_list;
73         GList *vcd_queue_last;
74         gboolean immediate_write;
75         uint8_t *last_logic;
76 };
77
78 /*
79  * Construct VCD signal identifiers from a sigrok channel index. The
80  * routine returns a GString which the caller is supposed to release.
81  *
82  * There are 94 printable ASCII characters. For larger channel index
83  * numbers multiple letters get concatenated (sticking with letters).
84  *
85  * The current implementation covers these ranges:
86  * - 94 single letter identifiers
87  * - 26 ^ 2 = 676, 94 + 676 = 770 for two letter identifiers
88  * - 26 ^ 3 = 17576, 770 + 17576 = 18346 for three letter identifiers
89  *
90  * This approach can get extended as needed when support for larger
91  * channel counts is desired. Any such extension remains transparent
92  * to call sites.
93  *
94  * TODO This implementation assumes that the software will run on a
95  * machine which uses the ASCII character set. Platforms that use other
96  * representations or non-contiguous character ranges for their alphabet
97  * cannot use a simple addition, instead need to execute table lookups.
98  */
99
100 #define VCD_IDENT_CHAR_MIN      '!'
101 #define VCD_IDENT_CHAR_MAX      '~'
102 #define VCD_IDENT_COUNT_1CHAR   (VCD_IDENT_CHAR_MAX + 1 - VCD_IDENT_CHAR_MIN)
103 #define VCD_IDENT_ALPHA_MIN     'a'
104 #define VCD_IDENT_ALPHA_MAX     'z'
105 #define VCD_IDENT_COUNT_ALPHA   (VCD_IDENT_ALPHA_MAX + 1 - VCD_IDENT_ALPHA_MIN)
106 #define VCD_IDENT_COUNT_2CHAR   (VCD_IDENT_COUNT_ALPHA * VCD_IDENT_COUNT_ALPHA)
107 #define VCD_IDENT_COUNT_3CHAR   (VCD_IDENT_COUNT_2CHAR * VCD_IDENT_COUNT_ALPHA)
108 #define VCD_IDENT_COUNT         (VCD_IDENT_COUNT_1CHAR + VCD_IDENT_COUNT_2CHAR + VCD_IDENT_COUNT_3CHAR)
109
110 static GString *vcd_identifier(size_t idx)
111 {
112         GString *symbol;
113         char c1, c2, c3;
114
115         symbol = g_string_sized_new(4);
116
117         /* First 94 channels, one printable character. */
118         if (idx < VCD_IDENT_COUNT_1CHAR) {
119                 c1 = VCD_IDENT_CHAR_MIN + idx;
120                 g_string_printf(symbol, "%c", c1);
121                 return symbol;
122         }
123         idx -= VCD_IDENT_COUNT_1CHAR;
124
125         /* Next 676 channels, two lower case characters. */
126         if (idx < VCD_IDENT_COUNT_2CHAR) {
127                 c2 = VCD_IDENT_ALPHA_MIN + (idx % VCD_IDENT_COUNT_ALPHA);
128                 idx /= VCD_IDENT_COUNT_ALPHA;
129                 c1 = VCD_IDENT_ALPHA_MIN + (idx % VCD_IDENT_COUNT_ALPHA);
130                 idx /= VCD_IDENT_COUNT_ALPHA;
131                 if (idx)
132                         sr_dbg("VCD identifier creation BUG (two char).");
133                 g_string_printf(symbol, "%c%c", c1, c2);
134                 return symbol;
135         }
136         idx -= VCD_IDENT_COUNT_2CHAR;
137
138         /* Next 17576 channels, three lower case characters. */
139         if (idx < VCD_IDENT_COUNT_3CHAR) {
140                 c3 = VCD_IDENT_ALPHA_MIN + (idx % VCD_IDENT_COUNT_ALPHA);
141                 idx /= VCD_IDENT_COUNT_ALPHA;
142                 c2 = VCD_IDENT_ALPHA_MIN + (idx % VCD_IDENT_COUNT_ALPHA);
143                 idx /= VCD_IDENT_COUNT_ALPHA;
144                 c1 = VCD_IDENT_ALPHA_MIN + (idx % VCD_IDENT_COUNT_ALPHA);
145                 idx /= VCD_IDENT_COUNT_ALPHA;
146                 if (idx)
147                         sr_dbg("VCD identifier creation BUG (three char).");
148                 g_string_printf(symbol, "%c%c%c", c1, c2, c3);
149                 return symbol;
150         }
151         idx -= VCD_IDENT_COUNT_3CHAR;
152
153         /*
154          * TODO
155          * Add combinations with more positions or larger character sets
156          * when support for more channels is required.
157          */
158         sr_dbg("VCD identifier creation ENOTSUPP (need %zu more).", idx);
159         g_string_free(symbol, TRUE);
160
161         return NULL;
162 }
163
164 /*
165  * Notes on the VCD text output formatting routines:
166  * - Always start new text lines when timestamps get emitted.
167  * - Optionally terminate timestamp lines when the caller asked us to.
168  * - Prepend all values with whitespace, assume they follow a timestamp
169  *   or a previously printed value. This works fine from the data point
170  *   of view for the start of new lines, as well.
171  * - Put the mandatory whitespace between real (or vector) values and
172  *   the following identifier. No whitespace for single bit values.
173  * - For real values callers need not specify "precision" nor the number
174  *   of significant digits. The Verilog VCD spec specifically picked the
175  *   "%.16g" format such that all bits of the internal presentation of
176  *   the IEEE754 floating point value get communicated between the
177  *   writer and the reader.
178  */
179
180 static void append_vcd_timestamp(GString *s, double ts, gboolean lf)
181 {
182
183         g_string_append_c(s, '\n');
184         g_string_append_c(s, '#');
185         g_string_append_printf(s, "%.0f", ts);
186         g_string_append_c(s, lf ? '\n' : ' ');
187 }
188
189 static void format_vcd_value_bit(GString *s, uint8_t bit_value, GString *id)
190 {
191
192         g_string_append_c(s, bit_value ? '1' : '0');
193         g_string_append(s, id->str);
194 }
195
196 static void format_vcd_value_real(GString *s, double real_value, GString *id)
197 {
198
199         g_string_append_c(s, 'r');
200         g_string_append_printf(s, "%.16g", real_value);
201         g_string_append_c(s, ' ');
202         g_string_append(s, id->str);
203 }
204
205 static int init(struct sr_output *o, GHashTable *options)
206 {
207         struct context *ctx;
208         size_t alloc_size;
209         struct sr_channel *ch;
210         GSList *l;
211         size_t num_enabled, num_logic, num_analog, desc_idx;
212         struct vcd_channel_desc *desc;
213
214         (void)options;
215
216         /* Determine the number of involved channels. */
217         num_enabled = 0;
218         num_logic = 0;
219         num_analog = 0;
220         for (l = o->sdi->channels; l; l = l->next) {
221                 ch = l->data;
222                 if (!ch->enabled)
223                         continue;
224                 if (ch->type == SR_CHANNEL_LOGIC) {
225                         num_logic++;
226                 } else if (ch->type == SR_CHANNEL_ANALOG) {
227                         num_analog++;
228                 } else {
229                         continue;
230                 }
231                 num_enabled++;
232         }
233         if (num_enabled > VCD_IDENT_COUNT) {
234                 sr_err("Only up to %d VCD signals supported.", VCD_IDENT_COUNT);
235                 return SR_ERR;
236         }
237
238         /* Allocate space for channel descriptions. */
239         ctx = g_malloc0(sizeof(*ctx));
240         o->priv = ctx;
241         ctx->enabled_count = num_enabled;
242         ctx->logic_count = num_logic;
243         ctx->analog_count = num_analog;
244         alloc_size = sizeof(ctx->channels[0]) * ctx->enabled_count;
245         ctx->channels = g_malloc0(alloc_size);
246
247         /*
248          * Reiterate input descriptions, to fill in output descriptions.
249          * Map channel indices, and assign symbols to VCD channels.
250          */
251         desc_idx = 0;
252         for (l = o->sdi->channels; l; l = l->next) {
253                 ch = l->data;
254                 if (!ch->enabled)
255                         continue;
256                 desc = &ctx->channels[desc_idx];
257                 desc->index = ch->index;
258                 desc->name = vcd_identifier(desc_idx);
259                 desc->type = ch->type;
260                 /*
261                  * Make sure to _not_ match next time, to have initial
262                  * values dumped when the first sample gets received.
263                  */
264                 if (desc->type == SR_CHANNEL_LOGIC && num_logic) {
265                         num_logic--;
266                         desc->last.logic = ~0;
267                 } else if (desc->type == SR_CHANNEL_ANALOG && num_analog) {
268                         num_analog--;
269                         /* "Construct" NaN, avoid a compile time error. */
270                         desc->last.real = 0.0;
271                         desc->last.real = 0.0 / desc->last.real;
272                 } else {
273                         g_string_free(desc->name, TRUE);
274                         memset(desc, 0, sizeof(*desc));
275                         continue;
276                 }
277                 desc_idx++;
278         }
279
280         /*
281          * Keep channel counts at hand, and a flag which allows to tune
282          * for special cases' speedup in .receive().
283          */
284         ctx->immediate_write = FALSE;
285         if (ctx->analog_count == 0)
286                 ctx->immediate_write = TRUE;
287         if (ctx->logic_count == 0 && ctx->analog_count == 1)
288                 ctx->immediate_write = TRUE;
289
290         /*
291          * Keep a copy of the last logic data bitmap around. To avoid
292          * iterating over individual bits when nothing in the set has
293          * changed. The overhead of two byte array compares should
294          * outweight the tenfold bit count compared to byte counts.
295          */
296         alloc_size = (ctx->logic_count + 7) / 8;
297         ctx->last_logic = g_malloc0(alloc_size);
298         if (ctx->logic_count && !ctx->last_logic)
299                 return SR_ERR_MALLOC;
300
301         return SR_OK;
302 }
303
304 /*
305  * VCD can only handle 1/10/100 factors in the s to fs range. Find a
306  * suitable timescale which satisfies this resolution constraint, yet
307  * won't result in excessive overhead.
308  */
309 static uint64_t get_timescale_freq(uint64_t samplerate)
310 {
311         uint64_t timescale;
312         size_t max_up_scale;
313
314         /* Go to the next full decade. */
315         timescale = 1;
316         while (timescale < samplerate) {
317                 timescale *= 10;
318         }
319
320         /*
321          * Avoid loss of precision, go up a few more decades when needed.
322          * For example switch to 10GHz timescale when samplerate is 400MHz.
323          * Stop after at most factor 100 to not loop endlessly for odd
324          * samplerates, yet provide good enough accuracy.
325          */
326         max_up_scale = 2;
327         while (max_up_scale--) {
328                 if (timescale / samplerate * samplerate == timescale)
329                         break;
330                 timescale *= 10;
331         }
332
333         return timescale;
334 }
335
336 /* Emit a VCD file header. */
337 static GString *gen_header(const struct sr_output *o)
338 {
339         struct context *ctx;
340         struct sr_channel *ch;
341         GVariant *gvar;
342         GString *header;
343         GSList *l;
344         time_t t;
345         size_t num_channels, i;
346         char *samplerate_s, *frequency_s, *timestamp;
347         struct vcd_channel_desc *desc;
348         char *type_text, *size_text;
349         int ret;
350
351         ctx = o->priv;
352
353         /* Get channel count, and samplerate if not done yet. */
354         num_channels = g_slist_length(o->sdi->channels);
355         if (!ctx->samplerate) {
356                 ret = sr_config_get(o->sdi->driver, o->sdi, NULL,
357                         SR_CONF_SAMPLERATE, &gvar);
358                 if (ret == SR_OK) {
359                         ctx->samplerate = g_variant_get_uint64(gvar);
360                         g_variant_unref(gvar);
361                 }
362         }
363         ctx->period = get_timescale_freq(ctx->samplerate);
364         t = time(NULL);
365         timestamp = g_strdup(ctime(&t));
366         timestamp[strlen(timestamp) - 1] = '\0';
367         samplerate_s = NULL;
368         if (ctx->samplerate)
369                 samplerate_s = sr_samplerate_string(ctx->samplerate);
370         frequency_s = sr_period_string(1, ctx->period);
371
372         /* Construct the VCD output file header. */
373         header = g_string_sized_new(512);
374         g_string_printf(header, "$date %s $end\n", timestamp);
375         g_string_append_printf(header, "$version %s %s $end\n",
376                 PACKAGE_NAME, sr_package_version_string_get());
377         g_string_append_printf(header, "$comment\n");
378         g_string_append_printf(header,
379                 "  Acquisition with %zu/%zu channels%s%s\n",
380                 ctx->enabled_count, num_channels,
381                 samplerate_s ? " at " : "", samplerate_s ? : "");
382         g_string_append_printf(header, "$end\n");
383         g_string_append_printf(header, "$timescale %s $end\n", frequency_s);
384
385         /* List generated VCD signals within a scope. */
386         g_string_append_printf(header, "$scope module %s $end\n", PACKAGE_NAME);
387         i = 0;
388         for (l = o->sdi->channels; l; l = l->next) {
389                 ch = l->data;
390                 if (!ch->enabled)
391                         continue;
392                 desc = &ctx->channels[i++];
393                 if (desc->type == SR_CHANNEL_LOGIC) {
394                         type_text = "wire";
395                         size_text = "1";
396                 } else if (desc->type == SR_CHANNEL_ANALOG) {
397                         type_text = "real";
398                         size_text = "64";
399                 } else {
400                         i--;
401                         continue;
402                 }
403                 g_string_append_printf(header, "$var %s %s %s %s $end\n",
404                         type_text, size_text, desc->name->str, ch->name);
405         }
406         g_string_append(header, "$upscope $end\n");
407
408         g_string_append(header, "$enddefinitions $end\n");
409
410         g_free(timestamp);
411         g_free(samplerate_s);
412         g_free(frequency_s);
413
414         return header;
415 }
416
417 /*
418  * Gets called when a session feed packet was received. Either creates
419  * a VCD file header (once in the output module's lifetime), or an empty
420  * GString. Callers will append the text representation of sample data
421  * to that string as needed.
422  */
423 static GString *chk_header(const struct sr_output *o)
424 {
425         struct context *ctx;
426         GString *s;
427
428         ctx = o->priv;
429
430         if (!ctx->header_done) {
431                 ctx->header_done = TRUE;
432                 s = gen_header(o);
433         } else {
434                 s = g_string_sized_new(512);
435         }
436
437         return s;
438 }
439
440 /*
441  * Helpers to "merge sort" sample data that we have received in chunks
442  * at different times in different code paths. Queue the data until we
443  * have seen samples from all involved channels for a given samplenumber.
444  * Data for a given sample number can only get emitted when we are sure
445  * no other channel's data can arrive any more.
446  */
447
448 static struct vcd_queue_item *queue_alloc_item(struct context *ctx, uint64_t snum)
449 {
450         GSList *node;
451         struct vcd_queue_item *item;
452
453         /* Get an item from the free list if available. */
454         node = ctx->free_list;
455         if (node) {
456                 ctx->reused++;
457
458                 /* Unlink GSList node from the free list. */
459                 ctx->free_list = node->next;
460                 node->next = NULL;
461                 item = node->data;
462                 node->data = NULL;
463
464                 /* Setup content of the item. */
465                 item->samplenum = snum;
466                 if (!item->values)
467                         item->values = g_string_sized_new(32);
468                 else
469                         g_string_truncate(item->values, 0);
470
471                 /* Keep GSList node in the used list (avoid free/alloc). */
472                 node->next = ctx->used_list;
473                 ctx->used_list = node;
474
475                 return item;
476         }
477
478         /* Dynamic allocation of an item. */
479         ctx->alloced++;
480         item = g_malloc0(sizeof(*item));
481         if (!item)
482                 return NULL;
483         item->samplenum = snum;
484         item->values = g_string_sized_new(32);
485
486         /* Create a used list item, to later move to the free list. */
487         ctx->used_list = g_slist_prepend(ctx->used_list, item);
488
489         return item;
490 }
491
492 static void queue_free_item(struct context *ctx, struct vcd_queue_item *item)
493 {
494         GSList *node;
495
496         /*
497          * Put item back into the free list. We can assume to find a
498          * used list node, it got allocated when the item was acquired.
499          */
500         node = ctx->used_list;
501         if (node) {
502                 ctx->pooled++;
503
504                 ctx->used_list = node->next;
505                 node->next = NULL;
506                 node->data = item;
507
508                 item->samplenum = 0;
509                 g_string_truncate(item->values, 0);
510
511                 node->next = ctx->free_list;
512                 ctx->free_list = node;
513
514                 return;
515         }
516
517         /*
518          * Release dynamically allocated resources. Could also be used
519          * to release free list items when the use list is empty.
520          */
521         ctx->freed++;
522         if (item->values)
523                 g_string_free(item->values, TRUE);
524         g_free(item);
525 }
526
527 static void queue_drain_pool_cb(gpointer data, gpointer cb_data)
528 {
529         struct context *ctx;
530         struct vcd_queue_item *item;
531
532         item = data;
533         ctx = cb_data;
534         queue_free_item(ctx, item);
535 }
536
537 static void queue_drain_pool(struct context *ctx)
538 {
539         GSList *list;
540
541         /*
542          * Grab the list and "empty" the context member. Then
543          * iterate over the items, have dymamic memory released.
544          * Then free the GSList nodes (but not their data parts).
545          * Do this for the used and the free lists.
546          */
547         list = ctx->used_list;
548         ctx->used_list = NULL;
549         g_slist_foreach(list, queue_drain_pool_cb, ctx);
550         g_slist_free(list);
551
552         list = ctx->free_list;
553         ctx->free_list = NULL;
554         g_slist_foreach(list, queue_drain_pool_cb, ctx);
555         g_slist_free(list);
556 }
557
558 static int cmp_snum(gconstpointer l, gconstpointer d)
559 {
560         const struct vcd_queue_item *list_item;
561         const uint64_t *snum_ptr;
562
563         list_item = l;
564         snum_ptr = d;
565         if (list_item->samplenum > *snum_ptr)
566                 return +1;
567         if (list_item->samplenum < *snum_ptr)
568                 return -1;
569         return 0;
570 }
571
572 static int cmp_items(gconstpointer a, gconstpointer b)
573 {
574         const struct vcd_queue_item *item_a, *item_b;
575
576         item_a = a;
577         item_b = b;
578         if (item_a->samplenum > item_b->samplenum)
579                 return +1;
580         if (item_a->samplenum < item_b->samplenum)
581                 return -1;
582         return 0;
583 }
584
585 /*
586  * Position the current pointer of the VCD value queue to a specific
587  * sample number. Create a new queue item when needed. The logic assumes
588  * a specific use pattern: Reception of striped sample data for channels
589  * and processing in strict order of sample numbers within a channel.
590  * Lower sample numbers near the start of the queue when channels change
591  * between session feed packets, before another linear sequence follows.
592  *
593  * Naive use of convenience glib routines would severely lose performance.
594  * That's why custom code is used, which is as complex as it needs to be,
595  * yet shall execute faster than a simpler implementation. For trivial
596  * cases (logic only, one analog channel only) this queue is bypassed.
597  */
598 static int queue_samplenum(struct context *ctx, uint64_t snum)
599 {
600         struct vcd_queue_item *item, *add_item;
601         GList *walk_list, *after_snum, *before_snum, *add_list;
602         GList *last;
603         gboolean add_after_last, do_search;
604
605         /* Already at that position? */
606         item = ctx->vcd_queue_last ? ctx->vcd_queue_last->data : NULL;
607         if (item && item->samplenum == snum)
608                 return SR_OK;
609
610         /*
611          * Search after the current position in the remaining queue. The
612          * custom code uses the queue's being sorted by sample number.
613          * Narrow down a later insert position as much as possible. This
614          * avoids linear search in huge spaces later on.
615          */
616         last = NULL;
617         add_after_last = FALSE;
618         after_snum = NULL;
619         before_snum = NULL;
620         walk_list = ctx->vcd_queue_last;
621         while (walk_list) {
622                 item = walk_list->data;
623                 if (!item)
624                         break;
625                 if (item->samplenum == snum) {
626                         ctx->vcd_queue_last = walk_list;
627                         return SR_OK;
628                 }
629                 last = walk_list;
630                 if (item->samplenum < snum)
631                         before_snum = walk_list;
632                 if (item->samplenum > snum) {
633                         after_snum = walk_list;
634                         break;
635                 }
636                 if (!walk_list->next)
637                         add_after_last = TRUE;
638                 walk_list = walk_list->next;
639         }
640
641         /*
642          * No exact match at or beyond the current position. Run another
643          * search from the start of the queue, again restrict the space
644          * which is searched, and narrow down the insert position when
645          * no match is found.
646          *
647          * If the searched sample number is larger than any we have seen
648          * before, or was in the above covered range but was not found,
649          * then we know that another queue item needs to get added, and
650          * where to put it. In that case we need not iterate the earlier
651          * list items.
652          */
653         walk_list = ctx->vcd_queue_list;
654         do_search = TRUE;
655         if (add_after_last)
656                 do_search = FALSE;
657         if (before_snum)
658                 do_search = FALSE;
659         while (do_search && walk_list && walk_list != ctx->vcd_queue_last) {
660                 item = walk_list->data;
661                 if (!item)
662                         break;
663                 if (item->samplenum == snum) {
664                         ctx->vcd_queue_last = walk_list;
665                         return SR_OK;
666                 }
667                 if (item->samplenum < snum)
668                         before_snum = walk_list;
669                 if (item->samplenum > snum) {
670                         after_snum = walk_list;
671                         break;
672                 }
673                 walk_list = walk_list->next;
674         }
675
676         /*
677          * The complete existing queue was exhausted, no exact match was
678          * found. A new queue item must get inserted. Identify a good
679          * position where to start searching for the exact position to
680          * link the new item to the list. Assume that the combination of
681          * the glib routine's list traversal and the sample number check
682          * in the callback is expensive, reduce the amount of work done.
683          *
684          * If we have seen an item with a larger sample number than the
685          * wanted, check its immediate predecessor. If this has a smaller
686          * sample number, then we found a perfect location to insert the
687          * new item. If we know that the new item must be inserted after
688          * the last traversed queue item, start there.
689          */
690         if (!before_snum) do {
691                 if (add_after_last)
692                         break;
693                 if (!after_snum)
694                         break;
695                 walk_list = after_snum->prev;
696                 if (!walk_list)
697                         break;
698                 item = walk_list->data;
699                 if (!item)
700                         break;
701                 if (item->samplenum == snum) {
702                         ctx->vcd_queue_last = walk_list;
703                         return SR_OK;
704                 }
705                 if (item->samplenum < snum)
706                         before_snum = walk_list;
707         } while (0);
708         add_list = add_after_last ? last : before_snum;
709         if (!add_list) {
710                 walk_list = ctx->vcd_queue_list;
711                 while (walk_list) {
712                         item = walk_list->data;
713                         if (!item)
714                                 break;
715                         if (item->samplenum == snum) {
716                                 ctx->vcd_queue_last = walk_list;
717                                 return SR_OK;
718                         }
719                         if (item->samplenum > snum) {
720                                 after_snum = walk_list;
721                                 break;
722                         }
723                         add_list = walk_list;
724                         walk_list = walk_list->next;
725                 }
726         }
727         if (add_list && (item = add_list->data) && item->samplenum == snum) {
728                 ctx->vcd_queue_last = add_list;
729                 return SR_OK;
730         }
731
732         /*
733          * Create a new queue item for the so far untracked sample
734          * number. Immediately search for the inserted position (is
735          * unfortunately not returned from the insert call), and
736          * cache that position for subsequent lookups.
737          */
738         if (with_queue_stats)
739                 sr_dbg("%s(), queue nr %" PRIu64, __func__, snum);
740         add_item = queue_alloc_item(ctx, snum);
741         if (!add_item)
742                 return SR_ERR_MALLOC;
743         if (!add_list)
744                 add_list = ctx->vcd_queue_list;
745         if (add_list && add_list->prev)
746                 add_list = add_list->prev;
747         walk_list = g_list_insert_sorted(add_list, add_item, cmp_items);
748         if (!walk_list->prev)
749                 ctx->vcd_queue_list = walk_list;
750         walk_list = g_list_find_custom(walk_list, &snum, cmp_snum);
751         item = walk_list ? walk_list->data : NULL;
752         if (item && item->samplenum == snum) {
753                 ctx->vcd_queue_last = walk_list;
754         }
755         return SR_OK;
756 }
757
758 /*
759  * Prepare to append another text fragment for a value change to the
760  * queue item which corresponds to the current sample number. Return
761  * the GString which the caller then will append to.
762  */
763 static GString *queue_value_text_prep(struct context *ctx)
764 {
765         struct vcd_queue_item *item;
766         GString *buff;
767
768         /* Cope with not-yet-positioned write pointers. */
769         item = ctx->vcd_queue_last ? ctx->vcd_queue_last->data : NULL;
770         if (!item)
771                 return NULL;
772
773         /* Create a GString if not done already. */
774         buff = item->values;
775         if (!buff) {
776                 buff = g_string_sized_new(20);
777                 item->values = buff;
778         }
779
780         /* Separate items with spaces (if previous content is present). */
781         if (buff->len)
782                 g_string_append_c(buff, ' ');
783
784         return buff;
785 }
786
787 static double snum_to_ts(struct context *ctx, uint64_t snum)
788 {
789         double ts;
790
791         ts = (double)snum;
792         ts /= ctx->samplerate;
793         ts *= ctx->period;
794
795         return ts;
796 }
797
798 /*
799  * Unqueue one item of the VCD values queue which corresponds to one
800  * sample number. Append all of the text to the passed in GString.
801  */
802 static int unqueue_item(struct context *ctx,
803         struct vcd_queue_item *item, GString *s)
804 {
805         double ts;
806         GString *buff;
807         gboolean is_empty;
808
809         /*
810          * Start the sample number's string with the timestamp. Append
811          * all value changes. Terminate lines for items which have a
812          * timestamp but no value changes, assuming this is the last
813          * entry which corresponds to SR_DF_END.
814          */
815         ts = snum_to_ts(ctx, item->samplenum);
816         buff = item->values;
817         is_empty = !buff || !buff->len || !buff->str || !*buff->str;
818         append_vcd_timestamp(s, ts, is_empty);
819         if (!is_empty)
820                 g_string_append(s, buff->str);
821
822         return SR_OK;
823 }
824
825 /*
826  * Get the last sample number which logic data was received for. This
827  * implementation assumes that all logic channels get received within
828  * exactly one packet of corresponding unitsize.
829  */
830 static uint64_t get_last_snum_logic(struct context *ctx)
831 {
832         size_t i;
833         struct vcd_channel_desc *desc;
834
835         for (i = 0; i < ctx->enabled_count; i++) {
836                 desc = &ctx->channels[i];
837                 if (desc->type != SR_CHANNEL_LOGIC)
838                         continue;
839                 return desc->last_rcvd_snum;
840         }
841
842         return 0;
843 }
844
845 /*
846  * Update the last sample number which logic data was received for.
847  */
848 static void upd_last_snum_logic(struct context *ctx, uint64_t inc)
849 {
850         size_t i;
851         struct vcd_channel_desc *desc;
852
853         for (i = 0; i < ctx->enabled_count; i++) {
854                 desc = &ctx->channels[i];
855                 if (desc->type != SR_CHANNEL_LOGIC)
856                         continue;
857                 desc->last_rcvd_snum += inc;
858         }
859 }
860
861 /*
862  * Get and update the last sample number which analog data was received
863  * for on a specific channel (which the caller already has identified).
864  */
865
866 static uint64_t get_last_snum_analog(struct vcd_channel_desc *desc)
867 {
868
869         return desc->last_rcvd_snum;
870 }
871
872 static void upd_last_snum_analog(struct vcd_channel_desc *desc, uint64_t inc)
873 {
874
875         if (!desc)
876                 return;
877         desc->last_rcvd_snum += inc;
878 }
879
880 /*
881  * Determine the maximum sample number which data from all involved
882  * channels was received for.
883  */
884 static uint64_t get_max_snum_export(struct context *ctx)
885 {
886         uint64_t snum;
887         size_t i;
888         struct vcd_channel_desc *desc;
889
890         snum = ~UINT64_C(0);
891         for (i = 0; i < ctx->enabled_count; i++) {
892                 desc = &ctx->channels[i];
893                 if (snum > desc->last_rcvd_snum)
894                         snum = desc->last_rcvd_snum;
895         }
896
897         return snum;
898 }
899
900 /*
901  * Determine the maximum sample number of any channel we may have
902  * received data for. Then pretend we had seen that number of samples
903  * on all channels. Such that the next export can flush all previously
904  * queued data up to and including the final number, which serves as
905  * some kind of termination of the VCD output data.
906  */
907 static uint64_t get_max_snum_flush(struct context *ctx)
908 {
909         uint64_t snum;
910         size_t i;
911         struct vcd_channel_desc *desc;
912
913         /* Determine the maximum sample number. */
914         snum = 0;
915         for (i = 0; i < ctx->enabled_count; i++) {
916                 desc = &ctx->channels[i];
917                 if (snum < desc->last_rcvd_snum)
918                         snum = desc->last_rcvd_snum;
919         }
920
921         /* Record that number as "seen" with all channels. */
922         for (i = 0; i < ctx->enabled_count; i++) {
923                 desc = &ctx->channels[i];
924                 desc->last_rcvd_snum = snum + 1;
925         }
926
927         return snum;
928 }
929
930 /*
931  * Pass all queued value changes when we are certain we have received
932  * data from all channels.
933  */
934 static int write_completed_changes(struct context *ctx, GString *out)
935 {
936         uint64_t upto_snum;
937         GList **listref, *node;
938         struct vcd_queue_item *item;
939         int rc;
940         size_t dumped;
941
942         /* Determine the number which all data was received for so far. */
943         upto_snum = get_max_snum_export(ctx);
944         if (with_queue_stats)
945                 sr_spew("%s(), check up to %" PRIu64, __func__, upto_snum);
946
947         /*
948          * Forward and consume those items from the head of the list
949          * which we completely have accumulated and are certain about.
950          */
951         dumped = 0;
952         listref = &ctx->vcd_queue_list;
953         while (*listref) {
954                 /* Find items before the targetted sample number. */
955                 node = *listref;
956                 item = node->data;
957                 if (!item)
958                         break;
959                 if (item->samplenum >= upto_snum)
960                         break;
961
962                 /*
963                  * Unlink the item from the list. Void cached positions.
964                  * Append its timestamp and values to the caller's text.
965                  */
966                 dumped++;
967                 if (with_queue_stats)
968                         sr_dbg("%s(), dump nr %" PRIu64,
969                                 __func__, item->samplenum);
970                 if (ctx->vcd_queue_last == node)
971                         ctx->vcd_queue_last = NULL;
972                 *listref = g_list_remove_link(*listref, node);
973                 rc = unqueue_item(ctx, item, out);
974                 queue_free_item(ctx, item);
975                 if (rc != SR_OK)
976                         return rc;
977         }
978
979         return SR_OK;
980 }
981
982 /* Get packets from the session feed, generate output text. */
983 static int receive(const struct sr_output *o,
984         const struct sr_datafeed_packet *packet, GString **out)
985 {
986         struct context *ctx;
987         const struct sr_datafeed_meta *meta;
988         const struct sr_datafeed_logic *logic;
989         const struct sr_datafeed_analog *analog;
990         const struct sr_config *src;
991         GSList *l;
992         struct vcd_channel_desc *desc;
993         uint64_t snum_curr;
994         size_t count, index, p, unit_size;
995         gboolean changed;
996         GString *s_val;
997         uint8_t *sample, *last_logic, prevbit, curbit;
998         GSList *channels;
999         struct sr_channel *channel;
1000         int rc;
1001         float *floats, value;
1002         double ts;
1003
1004         *out = NULL;
1005         if (!o || !o->priv)
1006                 return SR_ERR_BUG;
1007         ctx = o->priv;
1008
1009         switch (packet->type) {
1010         case SR_DF_META:
1011                 meta = packet->payload;
1012                 for (l = meta->config; l; l = l->next) {
1013                         src = l->data;
1014                         if (src->key != SR_CONF_SAMPLERATE)
1015                                 continue;
1016                         ctx->samplerate = g_variant_get_uint64(src->data);
1017                 }
1018                 break;
1019         case SR_DF_LOGIC:
1020                 *out = chk_header(o);
1021
1022                 logic = packet->payload;
1023                 sample = logic->data;
1024                 unit_size = logic->unitsize;
1025                 count = logic->length / unit_size;
1026                 snum_curr = get_last_snum_logic(ctx);
1027                 upd_last_snum_logic(ctx, count);
1028
1029                 last_logic = ctx->last_logic;
1030                 while (count--) {
1031                         /* Check whether any logic value has changed. */
1032                         changed = memcmp(last_logic, sample, unit_size) != 0;
1033                         changed |= snum_curr == 0;
1034                         if (changed)
1035                                 memcpy(last_logic, sample, unit_size);
1036
1037                         /*
1038                          * Start or continue tracking that sample number.
1039                          * Avoid string copies for logic-only setups.
1040                          */
1041                         if (changed) {
1042                                 if (ctx->immediate_write) {
1043                                         ts = snum_to_ts(ctx, snum_curr);
1044                                         append_vcd_timestamp(*out, ts, FALSE);
1045                                 } else {
1046                                         queue_samplenum(ctx, snum_curr);
1047                                 }
1048                         }
1049
1050                         /* Iterate over individual logic channels. */
1051                         for (p = 0; changed && p < ctx->enabled_count; p++) {
1052                                 /*
1053                                  * TODO Check whether the mapping from
1054                                  * data image positions to channel numbers
1055                                  * is required. Experiments suggest that
1056                                  * the data image "is dense", and packs
1057                                  * bits of enabled channels, and leaves no
1058                                  * room for positions of disabled channels.
1059                                  */
1060                                 desc = &ctx->channels[p];
1061                                 if (desc->type != SR_CHANNEL_LOGIC)
1062                                         continue;
1063                                 index = desc->index;
1064                                 prevbit = desc->last.logic;
1065
1066                                 /* Skip over unchanged values. */
1067                                 curbit = sample[index / 8];
1068                                 curbit = (curbit & (1 << (index % 8))) ? 1 : 0;
1069                                 if (snum_curr != 0 && prevbit == curbit)
1070                                         continue;
1071                                 desc->last.logic = curbit;
1072
1073                                 /*
1074                                  * Queue, or immediately emit the text for
1075                                  * the observed value change.
1076                                  */
1077                                 if (ctx->immediate_write) {
1078                                         g_string_append_c(*out, ' ');
1079                                         s_val = *out;
1080                                 } else {
1081                                         s_val = queue_value_text_prep(ctx);
1082                                         if (!s_val)
1083                                                 break;
1084                                 }
1085                                 format_vcd_value_bit(s_val, curbit, desc->name);
1086                         }
1087
1088                         /* Advance to next set of logic samples. */
1089                         snum_curr++;
1090                         sample += unit_size;
1091                 }
1092                 write_completed_changes(ctx, *out);
1093                 break;
1094         case SR_DF_ANALOG:
1095                 *out = chk_header(o);
1096
1097                 /*
1098                  * This implementation expects one analog packet per
1099                  * individual channel, with a number of samples each.
1100                  * Lookup the VCD output channel description.
1101                  */
1102                 analog = packet->payload;
1103                 count = analog->num_samples;
1104                 channels = analog->meaning->channels;
1105                 if (g_slist_length(channels) != 1) {
1106                         sr_err("Analog packets must be single-channel.");
1107                         return SR_ERR_ARG;
1108                 }
1109                 channel = g_slist_nth_data(channels, 0);
1110                 desc = NULL;
1111                 for (index = 0; index < ctx->enabled_count; index++) {
1112                         desc = &ctx->channels[index];
1113                         if ((int)desc->index == channel->index)
1114                                 break;
1115                 }
1116                 if (!desc)
1117                         return SR_OK;
1118                 if (desc->type != SR_CHANNEL_ANALOG)
1119                         return SR_ERR;
1120                 snum_curr = get_last_snum_analog(desc);
1121                 upd_last_snum_analog(desc, count);
1122
1123                 /*
1124                  * Convert incoming data to an array of single precision
1125                  * floating point values.
1126                  */
1127                 floats = g_try_malloc(sizeof(*floats) * analog->num_samples);
1128                 if (!floats)
1129                         return SR_ERR_MALLOC;
1130                 rc = sr_analog_to_float(analog, floats);
1131                 if (rc != SR_OK) {
1132                         g_free(floats);
1133                         return rc;
1134                 }
1135
1136                 /*
1137                  * Check for changes in the channel's values. Have the
1138                  * sample number's timestamp and new value printed when
1139                  * the value has changed.
1140                  */
1141                 for (index = 0; index < count; index++) {
1142                         /* Check for changes in the channel's values. */
1143                         value = floats[index];
1144                         changed = value != desc->last.real;
1145                         changed |= snum_curr + index == 0;
1146                         if (!changed)
1147                                 continue;
1148                         desc->last.real = value;
1149
1150                         /* Queue, or emit the timestamp and the new value. */
1151                         if (ctx->immediate_write) {
1152                                 ts = snum_to_ts(ctx, snum_curr + index);
1153                                 append_vcd_timestamp(*out, ts, FALSE);
1154                                 s_val = *out;
1155                         } else {
1156                                 queue_samplenum(ctx, snum_curr + index);
1157                                 s_val = queue_value_text_prep(ctx);
1158                         }
1159                         format_vcd_value_real(s_val, value, desc->name);
1160                 }
1161
1162                 g_free(floats);
1163                 write_completed_changes(ctx, *out);
1164                 break;
1165         case SR_DF_END:
1166                 *out = chk_header(o);
1167                 /* Push the final timestamp as length indicator. */
1168                 snum_curr = get_max_snum_flush(ctx);
1169                 queue_samplenum(ctx, snum_curr);
1170                 /* Flush previously queued value changes. */
1171                 write_completed_changes(ctx, *out);
1172                 break;
1173         }
1174
1175         return SR_OK;
1176 }
1177
1178 static int cleanup(struct sr_output *o)
1179 {
1180         struct context *ctx;
1181         struct vcd_channel_desc *desc;
1182
1183         if (!o || !o->priv)
1184                 return SR_ERR_ARG;
1185
1186         ctx = o->priv;
1187
1188         if (with_pool_stats)
1189                 sr_info("STATS: alloc/reuse %zu/%zu, pool/free %zu/%zu",
1190                         ctx->alloced, ctx->reused, ctx->pooled, ctx->freed);
1191         queue_drain_pool(ctx);
1192         if (with_pool_stats)
1193                 sr_info("STATS: alloc/reuse %zu/%zu, pool/free %zu/%zu",
1194                         ctx->alloced, ctx->reused, ctx->pooled, ctx->freed);
1195
1196         while (ctx->enabled_count--) {
1197                 desc = &ctx->channels[ctx->enabled_count];
1198                 g_string_free(desc->name, TRUE);
1199         }
1200         g_free(ctx->channels);
1201         g_free(ctx);
1202
1203         return SR_OK;
1204 }
1205
1206 struct sr_output_module output_vcd = {
1207         .id = "vcd",
1208         .name = "VCD",
1209         .desc = "Value Change Dump data",
1210         .exts = (const char*[]){"vcd", NULL},
1211         .flags = 0,
1212         .options = NULL,
1213         .init = init,
1214         .receive = receive,
1215         .cleanup = cleanup,
1216 };