X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Finput%2Fvcd.c;h=e3c2347ac0875ff6f44f99f000077a691ce3a455;hb=aac306330012568bbf31026b335f54a893310633;hp=5051f0e37d8bb97b20c67dc8a50f88bb381050a3;hpb=9a4fd01af84ac4739074c0e27b5ef3cb43637215;p=libsigrok.git diff --git a/src/input/vcd.c b/src/input/vcd.c index 5051f0e3..e3c2347a 100644 --- a/src/input/vcd.c +++ b/src/input/vcd.c @@ -85,6 +85,7 @@ struct context { size_t samples_in_buffer; uint8_t *buffer; uint8_t *current_levels; + GSList *prev_sr_channels; }; struct vcd_channel { @@ -151,7 +152,11 @@ static gboolean parse_section(GString *buf, gchar **name, gchar **contents) static void free_channel(void *data) { - struct vcd_channel *vcd_ch = data; + struct vcd_channel *vcd_ch; + + vcd_ch = data; + if (!vcd_ch) + return; g_free(vcd_ch->name); g_free(vcd_ch->identifier); g_free(vcd_ch); @@ -171,6 +176,56 @@ static void remove_empty_parts(gchar **parts) *dest = NULL; } +/* + * Keep track of a previously created channel list, in preparation of + * re-reading the input file. Gets called from reset()/cleanup() paths. + */ +static void keep_header_for_reread(const struct sr_input *in) +{ + struct context *inc; + + inc = in->priv; + g_slist_free_full(inc->prev_sr_channels, sr_channel_free_cb); + inc->prev_sr_channels = in->sdi->channels; + in->sdi->channels = NULL; +} + +/* + * Check whether the input file is being re-read, and refuse operation + * when essential parameters of the acquisition have changed in ways + * that are unexpected to calling applications. Gets called after the + * file header got parsed (again). + * + * Changing the channel list across re-imports of the same file is not + * supported, by design and for valid reasons, see bug #1215 for details. + * Users are expected to start new sessions when they change these + * essential parameters in the acquisition's setup. When we accept the + * re-read file, then make sure to keep using the previous channel list, + * applications may still reference them. + */ +static int check_header_in_reread(const struct sr_input *in) +{ + struct context *inc; + + if (!in) + return FALSE; + inc = in->priv; + if (!inc) + return FALSE; + if (!inc->prev_sr_channels) + return TRUE; + + if (sr_channel_lists_differ(inc->prev_sr_channels, in->sdi->channels)) { + sr_err("Channel list change not supported for file re-read."); + return FALSE; + } + g_slist_free_full(in->sdi->channels, sr_channel_free_cb); + in->sdi->channels = inc->prev_sr_channels; + inc->prev_sr_channels = NULL; + + return TRUE; +} + /* * Parse VCD header to get values for context structure. * The context structure should be zeroed before calling this. @@ -261,11 +316,13 @@ static gboolean parse_header(const struct sr_input *in, GString *buf) inc->current_levels = g_malloc0(inc->bytes_per_sample); inc->got_header = status; + if (status) + status = check_header_in_reread(in); return status; } -static int format_match(GHashTable *metadata) +static int format_match(GHashTable *metadata, unsigned int *confidence) { GString *buf, *tmpbuf; gboolean status; @@ -283,7 +340,11 @@ static int format_match(GHashTable *metadata) g_free(name); g_free(contents); - return status ? SR_OK : SR_ERR; + if (!status) + return SR_ERR; + *confidence = 1; + + return SR_OK; } /* Send all accumulated bytes from inc->buffer. */ @@ -404,6 +465,10 @@ static void parse_contents(const struct sr_input *in, char *data) inc->prev_timestamp = inc->skip; } else if (timestamp == inc->prev_timestamp) { /* Ignore repeated timestamps (e.g. sigrok outputs these) */ + } else if (timestamp < inc->prev_timestamp) { + sr_err("Invalid timestamp: %" PRIu64 " (smaller than previous timestamp).", timestamp); + inc->skip_until_end = TRUE; + break; } else { if (inc->compress != 0 && timestamp - inc->prev_timestamp > inc->compress) { /* Compress long idle periods */ @@ -606,7 +671,10 @@ static void cleanup(struct sr_input *in) struct context *inc; inc = in->priv; + keep_header_for_reread(in); g_slist_free_full(inc->channels, free_channel); + inc->channels = NULL; + g_free(inc->buffer); inc->buffer = NULL; g_free(inc->current_levels); @@ -618,9 +686,16 @@ static int reset(struct sr_input *in) struct context *inc = in->priv; cleanup(in); - inc->started = FALSE; g_string_truncate(in->buf, 0); + inc->started = FALSE; + inc->got_header = FALSE; + inc->prev_timestamp = 0; + inc->skip_until_end = FALSE; + inc->channelcount = 0; + /* The inc->channels list was released in cleanup() above. */ + inc->buffer = g_malloc(CHUNK_SIZE); + return SR_OK; } @@ -648,7 +723,7 @@ static const struct sr_option *get_options(void) SR_PRIV struct sr_input_module input_vcd = { .id = "vcd", .name = "VCD", - .desc = "Value Change Dump", + .desc = "Value Change Dump data", .exts = (const char*[]){"vcd", NULL}, .metadata = { SR_INPUT_META_HEADER | SR_INPUT_META_REQUIRED }, .options = get_options,