VCD data parsing

This commit is contained in:
Petteri Aimonen 2012-11-20 22:24:17 +02:00
parent 99eaa20695
commit 61a429c963
1 changed files with 145 additions and 14 deletions

View File

@ -22,6 +22,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <glib.h> #include <glib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "libsigrok.h" #include "libsigrok.h"
#include "libsigrok-internal.h" #include "libsigrok-internal.h"
@ -52,6 +53,7 @@ static gboolean read_until(FILE *file, GString *dest, char mode)
if (c == EOF) if (c == EOF)
{ {
if (mode != 'N')
sr_err("Unexpected EOF."); sr_err("Unexpected EOF.");
return FALSE; return FALSE;
} }
@ -132,6 +134,18 @@ struct context
struct probe probes[SR_MAX_NUM_PROBES]; struct probe probes[SR_MAX_NUM_PROBES];
}; };
static void release_context(struct context *ctx)
{
int i;
for (i = 0; i < ctx->probecount; i++)
{
g_free(ctx->probes[i].name); ctx->probes[i].name = NULL;
g_free(ctx->probes[i].identifier); ctx->probes[i].identifier = NULL;
}
g_free(ctx);
}
/* Remove empty parts from an array returned by g_strsplit. */ /* Remove empty parts from an array returned by g_strsplit. */
static void remove_empty_parts(gchar **parts) static void remove_empty_parts(gchar **parts)
{ {
@ -276,9 +290,12 @@ static int init(struct sr_input *in)
if (param) { if (param) {
num_probes = strtoul(param, NULL, 10); num_probes = strtoul(param, NULL, 10);
if (num_probes < 1) if (num_probes < 1)
{
release_context(ctx);
return SR_ERR; return SR_ERR;
} }
} }
}
/* Maximum number of probes to parse from the VCD */ /* Maximum number of probes to parse from the VCD */
ctx->maxprobes = num_probes; ctx->maxprobes = num_probes;
@ -291,19 +308,140 @@ static int init(struct sr_input *in)
snprintf(name, SR_MAX_PROBENAME_LEN, "%d", i); snprintf(name, SR_MAX_PROBENAME_LEN, "%d", i);
if (!(probe = sr_probe_new(i, SR_PROBE_LOGIC, TRUE, name))) if (!(probe = sr_probe_new(i, SR_PROBE_LOGIC, TRUE, name)))
{
release_context(ctx);
return SR_ERR; return SR_ERR;
}
in->sdi->probes = g_slist_append(in->sdi->probes, probe); in->sdi->probes = g_slist_append(in->sdi->probes, probe);
} }
return SR_OK; return SR_OK;
} }
#define CHUNKSIZE 1024
/* Send N samples of the given value. */
static void send_samples(const struct sr_dev_inst *sdi, uint64_t sample, uint64_t count)
{
struct sr_datafeed_packet packet;
struct sr_datafeed_logic logic;
uint64_t buffer[CHUNKSIZE];
uint64_t i;
unsigned chunksize = CHUNKSIZE;
if (count < chunksize)
chunksize = count;
for (i = 0; i < chunksize; i++)
{
buffer[i] = sample;
}
packet.type = SR_DF_LOGIC;
packet.payload = &logic;
logic.unitsize = sizeof(uint64_t);
logic.data = buffer;
while (count)
{
if (count < chunksize)
chunksize = count;
logic.length = sizeof(uint64_t) * chunksize;
sr_session_send(sdi, &packet);
count -= chunksize;
}
}
/* Parse the data section of VCD */
static void parse_contents(FILE *file, const struct sr_dev_inst *sdi, struct context *ctx)
{
GString *token = g_string_sized_new(32);
gboolean first = TRUE;
uint64_t prev_timestamp = 0;
uint64_t prev_values = 0;
/* Read one space-delimited token at a time. */
while (read_until(file, NULL, 'N') && read_until(file, token, 'W'))
{
if (token->str[0] == '#' && g_ascii_isdigit(token->str[1]))
{
/* Numeric value beginning with # is a new timestamp value */
uint64_t timestamp;
timestamp = strtoull(token->str + 1, NULL, 10);
if (first)
{
first = FALSE;
}
else
{
sr_dbg("New timestamp: %" PRIu64, timestamp);
/* Generate samples from prev_timestamp up to timestamp - 1. */
send_samples(sdi, prev_values, timestamp - prev_timestamp);
}
prev_timestamp = timestamp;
}
else if (token->str[0] == '$')
{
/* This is probably a $dumpvars, $comment or similar.
* For now, just skip it until $end. */
read_until(file, NULL, '$');
}
else if (strchr("01xXzZ", token->str[0]) != NULL)
{
/* A new 1-bit sample value */
int i, bit;
bit = (token->str[0] == '1');
g_string_erase(token, 0, 1);
if (token->len == 0)
{
/* There was a space between value and identifier.
* Read in the rest.
*/
read_until(file, NULL, 'N');
read_until(file, token, 'W');
}
for (i = 0; i < ctx->probecount; i++)
{
if (g_strcmp0(token->str, ctx->probes[i].identifier) == 0)
{
sr_dbg("Probe %d new value %d.", i, bit);
/* Found our probe */
if (bit)
prev_values |= (1 << i);
else
prev_values &= ~(1 << i);
break;
}
}
if (i == ctx->probecount)
{
sr_info("Did not find probe for identifier '%s'.", token->str);
}
}
g_string_truncate(token, 0);
}
g_string_free(token, TRUE);
}
static int loadfile(struct sr_input *in, const char *filename) static int loadfile(struct sr_input *in, const char *filename)
{ {
struct sr_datafeed_header header; struct sr_datafeed_header header;
struct sr_datafeed_packet packet; struct sr_datafeed_packet packet;
struct sr_datafeed_meta_logic meta; struct sr_datafeed_meta_logic meta;
struct sr_datafeed_logic logic;
FILE *file; FILE *file;
struct context *ctx; struct context *ctx;
@ -333,22 +471,15 @@ static int loadfile(struct sr_input *in, const char *filename)
meta.num_probes = ctx->probecount; meta.num_probes = ctx->probecount;
sr_session_send(in->sdi, &packet); sr_session_send(in->sdi, &packet);
/* Chop up the input file into chunks & send it to the session bus. */ /* Parse the contents of the VCD file */
/* packet.type = SR_DF_LOGIC; parse_contents(file, in->sdi, ctx);
packet.payload = &logic;
logic.unitsize = (num_probes + 7) / 8;
logic.data = buffer;
while ((size = read(fd, buffer, CHUNKSIZE)) > 0) {
logic.length = size;
sr_session_send(in->sdi, &packet);
}
close(fd);
*/
/* Send end packet to the session bus. */ /* Send end packet to the session bus. */
packet.type = SR_DF_END; packet.type = SR_DF_END;
sr_session_send(in->sdi, &packet); sr_session_send(in->sdi, &packet);
g_free(ctx); fclose(file);
release_context(ctx);
in->internal = NULL; in->internal = NULL;
return SR_OK; return SR_OK;