]> sigrok.org Git - libsigrok.git/blob - output/output_vcd.c
input/output formats: s/extension/id/.
[libsigrok.git] / output / output_vcd.c
1 /*
2  * This file is part of the sigrok project.
3  *
4  * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
5  * Copyright (C) 2011 Bert Vermeulen <bert@biot.com>
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 2 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, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
20  */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <glib.h>
25 #include <sigrok.h>
26 #include "config.h"
27
28 struct context {
29         int num_enabled_probes;
30         int unitsize;
31         char *probelist[65];
32         int *prevbits;
33         GString *header;
34         uint64_t prevsample;
35         int period;
36         uint64_t samplerate;
37 };
38
39 static const char *vcd_header_comment = "\
40 $comment\n  Acquisition with %d/%d probes at %s\n$end\n";
41
42 static int init(struct sr_output *o)
43 {
44         struct context *ctx;
45         struct sr_probe *probe;
46         GSList *l;
47         int num_probes, i;
48         char *samplerate_s, *frequency_s, *timestamp;
49         time_t t;
50
51         if (!(ctx = calloc(1, sizeof(struct context))))
52                 return SR_ERR_MALLOC;
53
54         o->internal = ctx;
55         ctx->num_enabled_probes = 0;
56
57         for (l = o->device->probes; l; l = l->next) {
58                 probe = l->data;
59                 if (!probe->enabled)
60                         continue;
61                 ctx->probelist[ctx->num_enabled_probes++] = probe->name;
62         }
63         if (ctx->num_enabled_probes > 94) {
64                 g_warning("VCD only supports 94 probes.");
65                 return SR_ERR;
66         }
67
68         ctx->probelist[ctx->num_enabled_probes] = 0;
69         ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
70         ctx->header = g_string_sized_new(512);
71         num_probes = g_slist_length(o->device->probes);
72
73         /* timestamp */
74         t = time(NULL);
75         timestamp = strdup(ctime(&t));
76         timestamp[strlen(timestamp)-1] = 0;
77         g_string_printf(ctx->header, "$date %s $end\n", timestamp);
78         free(timestamp);
79
80         /* generator */
81         g_string_append_printf(ctx->header, "$version %s %s $end\n",
82                         PACKAGE, PACKAGE_VERSION);
83
84         if (o->device->plugin && sr_device_has_hwcap(o->device, SR_HWCAP_SAMPLERATE)) {
85                 ctx->samplerate = *((uint64_t *) o->device->plugin->get_device_info(
86                                 o->device->plugin_index, SR_DI_CUR_SAMPLERATE));
87                 if (!((samplerate_s = sr_samplerate_string(ctx->samplerate)))) {
88                         g_string_free(ctx->header, TRUE);
89                         free(ctx);
90                         return SR_ERR;
91                 }
92                 g_string_append_printf(ctx->header, vcd_header_comment,
93                                  ctx->num_enabled_probes, num_probes, samplerate_s);
94                 free(samplerate_s);
95         }
96
97         /* timescale */
98         /* VCD can only handle 1/10/100 (s - fs), so scale up first */
99         if (ctx->samplerate > SR_MHZ(1))
100                 ctx->period = SR_GHZ(1);
101         else if (ctx->samplerate > SR_KHZ(1))
102                 ctx->period = SR_MHZ(1);
103         else
104                 ctx->period = SR_KHZ(1);
105         if (!(frequency_s = sr_period_string(ctx->period))) {
106                 g_string_free(ctx->header, TRUE);
107                 free(ctx);
108                 return SR_ERR;
109         }
110         g_string_append_printf(ctx->header, "$timescale %s $end\n", frequency_s);
111         free(frequency_s);
112
113         /* scope */
114         g_string_append_printf(ctx->header, "$scope module %s $end\n", PACKAGE);
115
116         /* Wires / channels */
117         for (i = 0; i < ctx->num_enabled_probes; i++) {
118                 g_string_append_printf(ctx->header, "$var wire 1 %c %s $end\n",
119                                 (char)('!' + i), ctx->probelist[i]);
120         }
121
122         g_string_append(ctx->header, "$upscope $end\n"
123                         "$enddefinitions $end\n$dumpvars\n");
124
125         if (!(ctx->prevbits = calloc(sizeof(int), num_probes))) {
126                 g_string_free(ctx->header, TRUE);
127                 free(ctx);
128                 return SR_ERR_MALLOC;
129         }
130
131         return SR_OK;
132 }
133
134 static int event(struct sr_output *o, int event_type, char **data_out,
135                  uint64_t *length_out)
136 {
137         struct context *ctx;
138         char *outbuf;
139
140         ctx = o->internal;
141         switch (event_type) {
142         case SR_DF_END:
143                 outbuf = strdup("$dumpoff\n$end\n");
144                 *data_out = outbuf;
145                 *length_out = strlen(outbuf);
146                 free(o->internal);
147                 o->internal = NULL;
148                 break;
149         default:
150                 *data_out = NULL;
151                 *length_out = 0;
152                 break;
153         }
154
155         return SR_OK;
156 }
157
158 static int data(struct sr_output *o, const char *data_in, uint64_t length_in,
159                 char **data_out, uint64_t *length_out)
160 {
161         struct context *ctx;
162         unsigned int i;
163         int p, curbit, prevbit;
164         uint64_t sample;
165         static uint64_t samplecount = 0;
166         GString *out;
167         int first_sample = 0;
168
169         ctx = o->internal;
170         out = g_string_sized_new(512);
171
172         if (ctx->header) {
173                 /* The header is still here, this must be the first packet. */
174                 g_string_append(out, ctx->header->str);
175                 g_string_free(ctx->header, TRUE);
176                 ctx->header = NULL;
177                 first_sample = 1;
178         }
179
180         for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) {
181                 samplecount++;
182
183                 memcpy(&sample, data_in + i, ctx->unitsize);
184
185                 if (first_sample) {
186                         /* First packet. We neg to make sure sample is stored. */
187                         ctx->prevsample = ~sample;
188                         first_sample = 0;
189                 }
190
191                 for (p = 0; p < ctx->num_enabled_probes; p++) {
192                         curbit = (sample & ((uint64_t) (1 << p))) >> p;
193                         prevbit = (ctx->prevsample & ((uint64_t) (1 << p))) >> p;
194
195                         /* VCD only contains deltas/changes of signals. */
196                         if (prevbit == curbit)
197                                 continue;
198
199                         /* Output which signal changed to which value. */
200                         g_string_append_printf(out, "#%" PRIu64 "\n%i%c\n",
201                                         (uint64_t)(((float)samplecount / ctx->samplerate)
202                                         * ctx->period), curbit, (char)('!' + p));
203                 }
204
205                 ctx->prevsample = sample;
206         }
207
208         *data_out = out->str;
209         *length_out = out->len;
210         g_string_free(out, FALSE);
211
212         return SR_OK;
213 }
214
215 struct sr_output_format output_vcd = {
216         .id = "vcd",
217         .description = "Value Change Dump (VCD)",
218         .df_type = SR_DF_LOGIC,
219         .init = init,
220         .data = data,
221         .event = event,
222 };