X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Finput%2Fvcd.c;h=253e76f67d25a78a5b381a08e2cd841ca8bdc723;hb=88a0265ebcb265ba839c02cc5bcd39e359c9f60f;hp=88e17f8b8ba4fb23c622edd81574d18fea64d8d5;hpb=a66175c2b1e11c961329aa2634fa9de7f3a45d5a;p=libsigrok.git diff --git a/src/input/vcd.c b/src/input/vcd.c index 88e17f8b..253e76f6 100644 --- a/src/input/vcd.c +++ b/src/input/vcd.c @@ -67,7 +67,6 @@ #define LOG_PREFIX "input/vcd" -#define DEFAULT_NUM_CHANNELS 8 #define CHUNKSIZE (1024 * 1024) struct context { @@ -106,6 +105,10 @@ static gboolean parse_section(GString *buf, gchar **name, gchar **contents) status = FALSE; pos = 0; + /* Skip UTF8 BOM */ + if (buf->len >= 3 && !strncmp(buf->str, "\xef\xbb\xbf", 3)) + pos = 3; + /* Skip any initial white-space. */ while (pos < buf->len && g_ascii_isspace(buf->str[pos])) pos++; @@ -219,7 +222,7 @@ static gboolean parse_header(const struct sr_input *in, GString *buf) sr_info("Unsupported signal type: '%s'", parts[0]); else if (strtol(parts[1], NULL, 10) != 1) sr_info("Unsupported signal size: '%s'", parts[1]); - else if (inc->channelcount >= inc->maxchannels) + else if (inc->maxchannels && inc->channelcount >= inc->maxchannels) sr_warn("Skipping '%s%s' because only %d channels requested.", parts[3], parts[4] ? : "", inc->maxchannels); else { @@ -233,8 +236,8 @@ static gboolean parse_header(const struct sr_input *in, GString *buf) sr_info("Channel %d is '%s' identified by '%s'.", inc->channelcount, vcd_ch->name, vcd_ch->identifier); + sr_channel_new(in->sdi, inc->channelcount++, SR_CHANNEL_LOGIC, TRUE, vcd_ch->name); inc->channels = g_slist_append(inc->channels, vcd_ch); - inc->channelcount++; } g_strfreev(parts); @@ -336,14 +339,36 @@ static void add_samples(const struct sr_input *in, size_t count) } } +/* Set the channel level depending on the identifier and parsed value. */ +static void process_bit(struct context *inc, char *identifier, unsigned int bit) +{ + GSList *l; + struct vcd_channel *vcd_ch; + unsigned int j; + + for (j = 0, l = inc->channels; j < inc->channelcount && l; j++, l = l->next) { + vcd_ch = l->data; + if (g_strcmp0(identifier, vcd_ch->identifier) == 0) { + /* Found our channel. */ + size_t byte_idx = (j / 8); + size_t bit_idx = j - 8 * byte_idx; + if (bit) + inc->current_levels[byte_idx] |= (uint8_t)1 << bit_idx; + else + inc->current_levels[byte_idx] &= ~((uint8_t)1 << bit_idx); + break; + } + } + if (j == inc->channelcount) + sr_dbg("Did not find channel for identifier '%s'.", identifier); +} + /* Parse a set of lines from the data section. */ static void parse_contents(const struct sr_input *in, char *data) { struct context *inc; - struct vcd_channel *vcd_ch; - GSList *l; uint64_t timestamp, prev_timestamp; - unsigned int bit, i, j; + unsigned int bit, i; char **tokens; inc = in->priv; @@ -406,14 +431,28 @@ static void parse_contents(const struct sr_input *in, char *data) inc->skip_until_end = TRUE; break; } - } else if (strchr("bBrR", tokens[i][0]) != NULL) { - sr_dbg("Vector values not supported yet"); + } else if (strchr("rR", tokens[i][0]) != NULL) { + sr_dbg("Real type vector values not supported yet!"); if (!tokens[++i]) /* No tokens left, bail out */ break; else /* Process next token */ continue; + } else if (strchr("bB", tokens[i][0]) != NULL) { + bit = (tokens[i][1] == '1'); + + /* + * Bail out if a) char after 'b' is NUL, or b) there is + * a second character after 'b', or c) there is no + * identifier. + */ + if (!tokens[i][1] || tokens[i][2] || !tokens[++i]) { + sr_dbg("Unexpected vector format!"); + break; + } + + process_bit(inc, tokens[i], bit); } else if (strchr("01xXzZ", tokens[i][0]) != NULL) { char *identifier; @@ -433,22 +472,7 @@ static void parse_contents(const struct sr_input *in, char *data) } else { identifier = tokens[i] + 1; } - - for (j = 0, l = inc->channels; j < inc->channelcount && l; j++, l = l->next) { - vcd_ch = l->data; - if (g_strcmp0(identifier, vcd_ch->identifier) == 0) { - /* Found our channel */ - size_t byte_idx = (j / 8); - size_t bit_idx = j - 8 * byte_idx; - if (bit) - inc->current_levels[byte_idx] |= (uint8_t)1 << bit_idx; - else - inc->current_levels[byte_idx] &= ~((uint8_t)1 << bit_idx); - break; - } - } - if (j == inc->channelcount) - sr_dbg("Did not find channel for identifier '%s'.", identifier); + process_bit(inc, identifier, bit); } else { sr_warn("Skipping unknown token '%s'.", tokens[i]); } @@ -458,18 +482,11 @@ static void parse_contents(const struct sr_input *in, char *data) static int init(struct sr_input *in, GHashTable *options) { - int num_channels, i; - char name[16]; struct context *inc; - num_channels = g_variant_get_int32(g_hash_table_lookup(options, "numchannels")); - if (num_channels < 1) { - sr_err("Invalid value for numchannels: must be at least 1."); - return SR_ERR_ARG; - } inc = in->priv = g_malloc0(sizeof(struct context)); - inc->maxchannels = num_channels; + inc->maxchannels = g_variant_get_int32(g_hash_table_lookup(options, "numchannels")); inc->downsample = g_variant_get_int32(g_hash_table_lookup(options, "downsample")); if (inc->downsample < 1) inc->downsample = 1; @@ -483,11 +500,6 @@ static int init(struct sr_input *in, GHashTable *options) inc->buffer = g_malloc(CHUNKSIZE); - for (i = 0; i < num_channels; i++) { - snprintf(name, 16, "%d", i); - sr_channel_new(in->sdi, i, SR_CHANNEL_LOGIC, TRUE, name); - } - return SR_OK; } @@ -570,7 +582,6 @@ static int receive(struct sr_input *in, GString *buf) static int end(struct sr_input *in) { - struct sr_datafeed_packet packet; struct context *inc; int ret; @@ -584,10 +595,8 @@ static int end(struct sr_input *in) /* Send any samples that haven't been sent yet. */ send_buffer(in); - if (inc->started) { - packet.type = SR_DF_END; - sr_session_send(in->sdi, &packet); - } + if (inc->started) + std_session_send_df_end(in->sdi, LOG_PREFIX); return ret; } @@ -615,7 +624,7 @@ static struct sr_option options[] = { static const struct sr_option *get_options(void) { if (!options[0].def) { - options[0].def = g_variant_ref_sink(g_variant_new_int32(DEFAULT_NUM_CHANNELS)); + options[0].def = g_variant_ref_sink(g_variant_new_int32(0)); options[1].def = g_variant_ref_sink(g_variant_new_int32(-1)); options[2].def = g_variant_ref_sink(g_variant_new_int32(1)); options[3].def = g_variant_ref_sink(g_variant_new_int32(0));