]> sigrok.org Git - libsigrok.git/blobdiff - src/input/vcd.c
input/vcd: abort VCD import when timestamp counts backwards
[libsigrok.git] / src / input / vcd.c
index 253e76f67d25a78a5b381a08e2cd841ca8bdc723..b9e9497dc8baf07b65370329179a615d2c175531 100644 (file)
@@ -26,7 +26,7 @@
  *
  * skip:        Allows skipping until given timestamp in the file.
  *              This can speed up analyzing of long captures.
- *            
+ *
  *              Value < 0: Skip until first timestamp listed in
  *              the file. (default)
  *
 
 #define LOG_PREFIX "input/vcd"
 
-#define CHUNKSIZE (1024 * 1024)
+#define CHUNK_SIZE (4 * 1024 * 1024)
 
 struct context {
        gboolean started;
        gboolean got_header;
+       uint64_t prev_timestamp;
        uint64_t samplerate;
        unsigned int maxchannels;
        unsigned int channelcount;
@@ -93,7 +94,7 @@ struct vcd_channel {
 
 /*
  * Reads a single VCD section from input file and parses it to name/contents.
- * e.g. $timescale 1ps $end  => "timescale" "1ps"
+ * e.g. $timescale 1ps $end => "timescale" "1ps"
  */
 static gboolean parse_section(GString *buf, gchar **name, gchar **contents)
 {
@@ -264,7 +265,7 @@ static gboolean parse_header(const struct sr_input *in, GString *buf)
        return status;
 }
 
-static int format_match(GHashTable *metadata)
+static int format_match(GHashTable *metadata, unsigned int *confidence)
 {
        GString *buf, *tmpbuf;
        gboolean status;
@@ -282,7 +283,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. */
@@ -318,7 +323,7 @@ static void add_samples(const struct sr_input *in, size_t count)
        uint8_t *p;
 
        inc = in->priv;
-       samples_per_chunk = CHUNKSIZE / inc->bytes_per_sample;
+       samples_per_chunk = CHUNK_SIZE / inc->bytes_per_sample;
 
        while (count) {
                space_left = samples_per_chunk - inc->samples_in_buffer;
@@ -367,12 +372,11 @@ static void process_bit(struct context *inc, char *identifier, unsigned int bit)
 static void parse_contents(const struct sr_input *in, char *data)
 {
        struct context *inc;
-       uint64_t timestamp, prev_timestamp;
+       uint64_t timestamp;
        unsigned int bit, i;
        char **tokens;
 
        inc = in->priv;
-       prev_timestamp = 0;
 
        /* Read one space-delimited token at a time. */
        tokens = g_strsplit_set(data, " \t\r\n", 0);
@@ -399,22 +403,26 @@ static void parse_contents(const struct sr_input *in, char *data)
                         */
                        if (inc->skip < 0) {
                                inc->skip = timestamp;
-                               prev_timestamp = timestamp;
+                               inc->prev_timestamp = timestamp;
                        } else if (inc->skip > 0 && timestamp < (uint64_t)inc->skip) {
-                               prev_timestamp = inc->skip;
-                       } else if (timestamp == prev_timestamp) {
+                               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 - prev_timestamp > inc->compress) {
+                               if (inc->compress != 0 && timestamp - inc->prev_timestamp > inc->compress) {
                                        /* Compress long idle periods */
-                                       prev_timestamp = timestamp - inc->compress;
+                                       inc->prev_timestamp = timestamp - inc->compress;
                                }
 
                                sr_dbg("New timestamp: %" PRIu64, timestamp);
 
                                /* Generate samples from prev_timestamp up to timestamp - 1. */
-                               add_samples(in, timestamp - prev_timestamp);
-                               prev_timestamp = timestamp;
+                               add_samples(in, timestamp - inc->prev_timestamp);
+                               inc->prev_timestamp = timestamp;
                        }
                } else if (tokens[i][0] == '$' && tokens[i][1] != '\0') {
                        /*
@@ -498,7 +506,7 @@ static int init(struct sr_input *in, GHashTable *options)
        in->sdi = g_malloc0(sizeof(struct sr_dev_inst));
        in->priv = inc;
 
-       inc->buffer = g_malloc(CHUNKSIZE);
+       inc->buffer = g_malloc(CHUNK_SIZE);
 
        return SR_OK;
 }
@@ -530,7 +538,7 @@ static int process_buffer(struct sr_input *in)
 
        inc = in->priv;
        if (!inc->started) {
-               std_session_send_df_header(in->sdi, LOG_PREFIX);
+               std_session_send_df_header(in->sdi);
 
                packet.type = SR_DF_META;
                packet.payload = &meta;
@@ -596,7 +604,7 @@ static int end(struct sr_input *in)
        send_buffer(in);
 
        if (inc->started)
-               std_session_send_df_end(in->sdi, LOG_PREFIX);
+               std_session_send_df_end(in->sdi);
 
        return ret;
 }
@@ -613,11 +621,23 @@ static void cleanup(struct sr_input *in)
        inc->current_levels = NULL;
 }
 
+static int reset(struct sr_input *in)
+{
+       struct context *inc = in->priv;
+
+       cleanup(in);
+       inc->started = FALSE;
+       g_string_truncate(in->buf, 0);
+
+       return SR_OK;
+}
+
 static struct sr_option options[] = {
-       { "numchannels", "Number of channels", "Number of channels", NULL, NULL },
-       { "skip", "Skip", "Skip until timestamp", NULL, NULL },
-       { "downsample", "Downsample", "Divide samplerate by factor", NULL, NULL },
-       { "compress", "Compress", "Compress idle periods longer than this value", NULL, NULL },
+       { "numchannels", "Number of logic channels", "The number of (logic) channels in the data", NULL, NULL },
+       { "skip", "Skip samples until timestamp", "Skip samples until the specified timestamp; "
+               "< 0: Skip until first timestamp listed; 0: Don't skip", NULL, NULL },
+       { "downsample", "Downsampling factor", "Downsample, i.e. divide the samplerate by the specified factor", NULL, NULL },
+       { "compress", "Compress idle periods", "Compress idle periods longer than the specified value", NULL, NULL },
        ALL_ZERO
 };
 
@@ -636,7 +656,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,
@@ -645,4 +665,5 @@ SR_PRIV struct sr_input_module input_vcd = {
        .receive = receive,
        .end = end,
        .cleanup = cleanup,
+       .reset = reset,
 };