Extend the sigrok-cli manpage section which discusses the -P option.
Mention the assignment of logic channels to decoder inputs by index
or by name.
Automatic assignment by position in the absence of user specs seems
to not have been recent implementations' default behaviour. Remove
that outdated or incorrect comment.
Random notes
------------
- - Consistently use g_try_malloc() / g_try_malloc0(). Do not use standard
+ - Don't do variable declarations in compound statements, only at the
+ beginning of a function.
+
+ - Generally avoid assigning values to variables at declaration time,
+ especially so for complex and/or run-time dependent values.
+
+ - Consistently use g_*malloc() / g_*malloc0(). Do not use standard
malloc()/calloc() if it can be avoided (sometimes other libs such
as libftdi can return malloc()'d memory, for example).
- Always properly match allocations with the proper *free() functions. If
- glib's g_try_malloc()/g_try_malloc0() was used, use g_free() to free the
+ glib's g_*malloc()/g_*malloc0() was used, use g_free() to free the
memory. Otherwise use standard free(). Never use the wrong function!
- - Never use g_malloc() or g_malloc0(). These functions do not return NULL
- if not enough memory is available but rather lead to an exit() or segfault
- instead. This behaviour is not acceptable.
- Use g_try_malloc()/g_try_malloc0() instead and check the return value.
+ - We assume that "small" memory allocations (< 1MB) will always succeed.
+ Thus, it's fine to use g_malloc() or g_malloc0() for allocations of
+ simple/small structs and such (instead of using g_try_malloc()), and
+ there's no need to check the return value.
+
+ Do use g_try_malloc() or g_try_malloc0() for large (>= 1MB) allocations
+ and check the return value.
- You should never print any messages (neither to stdout nor stderr nor
elsewhere) "manually" via e.g. printf() or g_log() or similar functions.
- pkg-config >= 0.22
- libglib >= 2.32.0
- libsigrok >= 0.5.0
- - libsigrokdecode >= 0.6.0
+ - libsigrokdecode >= 0.5.0
Building and installing
IRC
---
-You can find the sigrok developers in the #sigrok IRC channel on Freenode.
+You can find the sigrok developers in the #sigrok IRC channel on Libera.Chat.
Website
PKG_CHECK_MODULES([SIGROK_CLI],
[glib-2.0 >= 2.32.0 libsigrok >= 0.5.0 $SC_PKGLIBS])
+# Check for version dependent availability of functions.
+srd_save_cflags=$CFLAGS
+srd_save_libs=$LIBS
+CFLAGS="$SIGROK_CLI_CFLAGS $CFLAGS"
+LIBS="$SIGROK_CLI_LIBS $LIBS"
+AC_CHECK_FUNCS([srd_session_send_eof])
+CFLAGS=$srd_save_cflags
+LIBS=$srd_save_libs
+
sc_glib_version=`$PKG_CONFIG --modversion glib-2.0 2>&AS_MESSAGE_LOG_FD`
sc_libsigrok_version=`$PKG_CONFIG --modversion libsigrok 2>&AS_MESSAGE_LOG_FD`
OutFile "@PACKAGE_NAME@-@SC_PACKAGE_VERSION@-installer.exe"
# Where to install the application.
-InstallDir "$PROGRAMFILES\sigrok\@PACKAGE_NAME@"
+!ifdef PE64
+ InstallDir "$PROGRAMFILES64\sigrok\@PACKAGE_NAME@"
+!else
+ InstallDir "$PROGRAMFILES\sigrok\@PACKAGE_NAME@"
+!endif
# Request admin privileges for Windows Vista and Windows 7.
# http://nsis.sourceforge.net/Docs/Chapter4.html
extern struct srd_session *srd_sess;
+static const char *keyword_assign = "assign_channels";
+static const char *assign_by_index = "auto_index";
+static const char *assign_by_name = "auto_names";
+
static int opts_to_gvar(struct srd_decoder *dec, GHashTable *hash,
GHashTable **options)
{
return ret;
}
-static int move_hash_element(GHashTable *src, GHashTable *dest, void *key)
+static int move_hash_element(GHashTable *src, GHashTable *dest, const void *key)
{
void *orig_key, *value;
channel_map = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, g_free);
+ move_hash_element(hash, channel_map, keyword_assign);
for (l = dec->channels; l; l = l->next) {
pdch = l->data;
move_hash_element(hash, channel_map, pdch->id);
GHashTable *channel_indices;
GSList *channel_list;
struct srd_decoder_inst *di;
+ struct srd_decoder *pd;
GVariant *var;
void *channel_id;
void *channel_target;
struct sr_channel *ch;
GHashTableIter iter;
+ enum assign_t {
+ ASSIGN_UNKNOWN,
+ ASSIGN_USER_SPEC,
+ ASSIGN_BY_INDEX,
+ ASSIGN_BY_NAMES,
+ } assign;
+ const char *keyword;
+ GSList *l_pd, *l_pdo, *l_ch;
+ struct srd_channel *pdch;
channel_map = value;
channel_list = user_data;
channel_indices = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
(GDestroyNotify)g_variant_unref);
+ /*
+ * The typical mode of operation is to apply a user specified
+ * mapping of sigrok channels to decoder inputs. Lack of mapping
+ * specs will assign no signals (compatible behaviour to earlier
+ * implementations).
+ *
+ * Alternatively we can assign sigrok logic channels to decoder
+ * inputs in the strict order of channel indices, or when their
+ * names match. Users need to request this automatic assignment
+ * though, because this behaviour differs from earlier versions.
+ *
+ * Even more sophisticated heuristics of mapping sigrok channels
+ * to decoder inputs are not implemented here. Later versions
+ * could translate the Pulseview approach to the C language, but
+ * it's better to stabilize that logic first before porting it.
+ */
+ assign = ASSIGN_USER_SPEC;
+ keyword = g_hash_table_lookup(channel_map, keyword_assign);
+ if (g_hash_table_size(channel_map) != 1) {
+ assign = ASSIGN_USER_SPEC;
+ } else if (!keyword) {
+ assign = ASSIGN_USER_SPEC;
+ } else if (strcmp(keyword, assign_by_index) == 0) {
+ assign = ASSIGN_BY_INDEX;
+ } else if (strcmp(keyword, assign_by_name) == 0) {
+ assign = ASSIGN_BY_NAMES;
+ } else {
+ g_critical("Unknown type of decoder channel assignment: %s.",
+ keyword);
+ return;
+ }
+
+ pd = di->decoder;
+ if (assign == ASSIGN_BY_INDEX) {
+ /*
+ * Iterate the protocol decoder's list of input signals
+ * (mandatory and optional, never more than the decoder's
+ * total channels count). Assign sigrok logic channels
+ * until either is exhausted. Use sigrok channels in the
+ * very order of their declaration in the input stream.
+ */
+ l_ch = channel_list;
+ l_pd = pd->channels;
+ while (l_ch && l_pd) {
+ ch = l_ch->data;
+ l_ch = l_ch->next;
+ if (ch->type != SR_CHANNEL_LOGIC)
+ break;
+ if (ch->index >= di->dec_num_channels)
+ break;
+ pdch = l_pd->data;
+ l_pd = l_pd->next;
+ if (!l_pd)
+ l_pd = pd->opt_channels;
+ /* TODO Emit an INFO message. */
+ g_hash_table_insert(channel_map,
+ g_strdup(pdch->id), g_strdup(ch->name));
+ }
+ } else if (assign == ASSIGN_BY_NAMES) {
+ /*
+ * Iterate the protocol decoder's list of input signals.
+ * Search for sigrok logic channels that have matching
+ * names (case insensitive comparison). Not finding a
+ * sigrok channel of a given name is non-fatal (could be
+ * an optional channel, the decoder will check later for
+ * all mandatory channels to be assigned).
+ */
+ l_pd = pd->channels;
+ l_pdo = pd->opt_channels;
+ while (l_pd) {
+ pdch = l_pd->data;
+ l_pd = l_pd->next;
+ if (!l_pd) {
+ l_pd = l_pdo;
+ l_pdo = NULL;
+ }
+ ch = find_channel(channel_list, pdch->id, FALSE);
+ if (!ch) {
+ /* TODO Emit a WARN message. */
+ /* if (l_pdo) ...; */
+ continue;
+ }
+ if (ch->type != SR_CHANNEL_LOGIC) {
+ /* TODO Emit a WARN message. */
+ continue;
+ }
+ /* TODO Emit an INFO message. */
+ g_hash_table_insert(channel_map,
+ g_strdup(pdch->id), g_strdup(ch->name));
+ }
+ }
+
g_hash_table_iter_init(&iter, channel_map);
while (g_hash_table_iter_next(&iter, &channel_id, &channel_target)) {
+ if (strcmp(channel_id, keyword_assign) == 0)
+ continue;
if (!channel_target) {
g_printerr("cli: Channel name for \"%s\" missing.\n",
(char *)channel_id);
continue;
}
- ch = find_channel(channel_list, channel_target);
+ ch = find_channel(channel_list, channel_target, TRUE);
if (!ch) {
g_printerr("cli: No channel with name \"%s\" found.\n",
(char *)channel_target);
show_class = TRUE;
show_abbrev = TRUE;
}
+ if (opt_pd_ann_class)
+ show_class = TRUE;
/*
* Display the annotation's fields after the layout was
-.TH SIGROK\-CLI 1 "March 28, 2019"
+.TH SIGROK\-CLI 1 "April 07, 2023"
.SH "NAME"
sigrok\-cli \- Command-line client for the sigrok software
.SH "SYNOPSIS"
.BR "\-c, \-\-config " <deviceoption>
A colon-separated list of device options, where each option takes the form
.BR key=value .
+Multiple occurances of the
+.B \-\-config
+option are supported.
+The first item in the list of options can take the form
+.B channel_group=<name>
+which would override the
+.B \-\-channel\-group
+specification for this list of options. Other option lists in other
+.B \-\-config
+occurances are not affected by this list's channel group name.
+.sp
For example, to set the samplerate to 1MHz on a device supported by the
fx2lafw driver, you might specify
.sp
.RB " $ " "sigrok\-cli \-d fx2lafw \-\-config samplerate=1m" " [...]"
.sp
.RB " $ " "sigrok\-cli \-d fx2lafw \-\-config \(dqsamplerate=1 MHz\(dq" " [...]"
+.sp
+These examples specify options within a channel group.
+The first two are equivalent.
+.sp
+.RB " $ " "sigrok\-cli \-d demo \-\-channel\-group Logic \-\-config pattern=random [...]"
+.sp
+.RB " $ " "sigrok\-cli \-d demo \-\-config channel_group=Logic:pattern=random [...]"
+.sp
+.RB " $ " "sigrok\-cli \-d demo \-\-config samplerate=1m \-\-config channel_group=Logic:pattern=random [...]"
.TP
.BR "\-i, \-\-input\-file " <filename>
Load input from a file instead of a hardware device. You can specify
.RB " $ " "sigrok\-cli \-g CH1" " [...]"
.sp
.RB " $ " "sigrok\-cli \-d demo \-g Logic \-c pattern=graycode" " [...]"
+.sp
+Channel group specifications in
+.B \-\-get
+or
+.B \-\-config
+options take precedence over channel group names in
+.B \-\-channel\-group
+so that a single
+.B sigrok\-cli
+invocation can support the query or manipulation of multiple device options
+which reside in different channel groups.
.TP
.BR "\-t, \-\-triggers " <triggerlist>
A comma-separated list of triggers to use, of the form
$
.B "sigrok\-cli \-i <file.sr> "
.br
-.B " \-P uart:baudrate=115200:parity_type=odd"
+.B " \-P uart:baudrate=115200:parity=odd"
.sp
The list of supported options depends entirely on the protocol decoder. Every
protocol decoder has different options it supports.
.B wordsize
is an option supported by the
.B spi
-protocol decoder. Additionally, the user tells sigrok to decode the SPI
+protocol decoder. Additionally, the user requests sigrok to decode the SPI
protocol using channel 1 as MISO signal for SPI, channel 5 as MOSI, channel 3
as CLK, and channel 0 as CS# signal.
.sp
-Notice that the
+The
.B sigrok\-cli
-application does not support "name matching". Instead it's assumed that the
-traces in the input stream match the order of the decoder's input signals,
-or that users explicitly specify the input channel to decoder signal mapping.
+application can automatically assign logic channels to decoder inputs
+in their strict channel index order (by means of the
+.B auto_index
+keyword), or can automatically assign logic channels to decoder inputs
+when their names match (case insensitive match,
+.B auto_names
+keyword). Users need to explicitly request this assignment, the default
+behaviour is to not automatically assign any signals.
+.sp
+Example:
+.sp
+ $
+.B "sigrok\-cli \-i <file.sr>"
+.br
+.B " \-P ieee488:assign_channels=auto_names"
.br
.sp
When multiple decoders are specified in the same
When given, decoder annotations will include sample numbers, too.
This allows consumers to receive machine readable timing information.
.TP
+.BR "\-\-protocol\-decoder\-ann\-class
+When given, decoder annotations will include annotation class names.
+.TP
+.BR "\-\-protocol\-decoder\-jsontrace
+When given, decoder output uses the Google Trace Event format (JSON).
+Which can be inspected in web browsers or other viewers.
+.TP
.BR "\-l, \-\-loglevel " <level>
Set the libsigrok and libsigrokdecode loglevel. At the moment \fBsigrok\-cli\fP
doesn't support setting the two loglevels independently. The higher the
Get the value of
.B <variable>
from the specified device and print it.
+Multiple variable names can be specified and get separated by colon.
+The list of variable names optionally can be preceeded by
+.B "channel_group=<name>"
+which would override the
+.B \-\-channel\-group
+specification.
+Multiple
+.B \-\-get
+occurances are supported in a single
+.B sigrok\-cli
+invocation.
+.sp
+ $
+.B sigrok\-cli \-d demo \-\-get samplerate:averaging \-\-get channel_group=Logic:pattern
.TP
.BR "\-\-set"
Set one or more variables specified with the \fB\-\-config\fP option, without
.SH "EXIT STATUS"
.B sigrok\-cli
exits with 0 on success, 1 on most failures.
+.SH "ENVIRONMENT"
+.TP
+.B SIGROK_FIRMWARE_DIR
+A single path where to search for firmware images, in addition to a
+builtin list of locations.
+.TP
+.B SIGROK_FIRMWARE_PATH
+Multiple path entries where to search for firmware images, in addition
+to builtin locations.
+.TP
+When decoder support was enabled in the application's configuration:
+.TP
+.B SIGROKDECODE_DIR
+A single path where to search for protocol decoders, in addition to
+a builtin list of locations.
+.TP
+.B SIGROKDECODE_PATH
+Multiple path entries where to search for protocol decoders, in addition
+to builtin locations.
.SH "SEE ALSO"
\fBpulseview\fP(1)
.SH "BUGS"
ssize_t len;
char *mod_id;
gboolean is_stdin;
+ gboolean push_scan_data;
if (!sr_input_list())
g_critical("No supported input formats available.");
}
is_stdin = strcmp(opt_input_file, "-") == 0;
+ push_scan_data = FALSE;
fd = 0;
buf = g_string_sized_new(CHUNK_SIZE);
if (mod_id) {
if ((options = sr_input_options_get(imod))) {
mod_opts = generic_arg_to_opt(options, mod_args);
(void)warn_unknown_keys(options, mod_args, NULL);
- sr_output_options_free(options);
+ sr_input_options_free(options);
} else {
mod_opts = NULL;
}
g_critical("Failed to load %s: %s.", opt_input_file,
g_strerror(errno));
}
- if ((len = read(fd, buf->str, CHUNK_SIZE)) < 1)
+ if ((len = read(fd, buf->str, buf->allocated_len)) < 1)
g_critical("Failed to read %s: %s.", opt_input_file,
g_strerror(errno));
buf->len = len;
sr_input_scan_buffer(buf, &in);
+ push_scan_data = TRUE;
}
if (!in)
g_critical("Error: no input module found for this file.");
df_arg->session = session;
sr_session_datafeed_callback_add(session, datafeed_in, df_arg);
+ /*
+ * Implementation detail: The combination of reading from stdin
+ * and automatic file format detection may have pushed the first
+ * chunk of input data into the input module's data accumulator,
+ * _bypassing_ the .receive() callback. It is essential to call
+ * .receive() before calling .end() for files of size smaller than
+ * CHUNK_SIZE (which is a typical case). So that sdi becomes ready.
+ * Fortunately all input modules accept .receive() calls with
+ * a zero length, and inspect whatever was accumulated so far.
+ *
+ * After that optional initial push of data which was queued
+ * above during format detection, continue reading remaining
+ * chunks from the input file until EOF is seen.
+ */
got_sdi = FALSE;
while (TRUE) {
g_string_truncate(buf, 0);
- len = read(fd, buf->str, CHUNK_SIZE);
+ if (push_scan_data)
+ len = 0;
+ else
+ len = read(fd, buf->str, buf->allocated_len);
if (len < 0)
g_critical("Read failed: %s", g_strerror(errno));
- if (len == 0)
+ if (len == 0 && !push_scan_data)
/* End of file or stream. */
break;
+ push_scan_data = FALSE;
buf->len = len;
- if (sr_input_send(in, buf) != SR_OK)
+ if (sr_input_send(in, buf) != SR_OK) {
+ g_critical("File import failed (read)");
break;
+ }
sdi = sr_input_dev_inst_get(in);
if (!got_sdi && sdi) {
/* First time we got a valid sdi. */
- if (select_channels(sdi) != SR_OK)
+ if (select_channels(sdi) != SR_OK) {
+ g_critical("File import failed (channels)");
return;
+ }
if (sr_session_dev_add(session, sdi) != SR_OK) {
g_critical("Failed to use device.");
sr_session_destroy(session);
sr_input_end(in);
sr_input_free(in);
g_string_free(buf, TRUE);
+ close(fd);
df_arg->session = NULL;
sr_session_destroy(session);
-
}
void load_input_file(gboolean do_props)
gchar *opt_pd_annotations = NULL;
gchar *opt_pd_meta = NULL;
gchar *opt_pd_binary = NULL;
+gboolean opt_pd_ann_class = FALSE;
gboolean opt_pd_samplenum = FALSE;
gboolean opt_pd_jsontrace = FALSE;
#endif
"Protocol decoder meta output to show", NULL},
{"protocol-decoder-binary", 'B', 0, G_OPTION_ARG_CALLBACK, &check_opt_pd_binary,
"Protocol decoder binary output to show", NULL},
+ {"protocol-decoder-ann-class", 0, 0, G_OPTION_ARG_NONE, &opt_pd_ann_class,
+ "Show annotation class in decoder output", NULL},
{"protocol-decoder-samplenum", 0, 0, G_OPTION_ARG_NONE, &opt_pd_samplenum,
"Show sample numbers in decoder output", NULL},
{"protocol-decoder-jsontrace", 0, 0, G_OPTION_ARG_NONE, &opt_pd_jsontrace,
#include <glib.h>
#include "sigrok-cli.h"
-struct sr_channel *find_channel(GSList *channellist, const char *channelname)
+struct sr_channel *find_channel(GSList *channellist, const char *channelname,
+ gboolean exact_case)
{
struct sr_channel *ch;
GSList *l;
ch = NULL;
for (l = channellist; l; l = l->next) {
ch = l->data;
- if (!strcmp(ch->name, channelname))
- break;
+ if (exact_case) {
+ if (strcmp(ch->name, channelname) == 0)
+ break;
+ } else {
+ if (g_ascii_strcasecmp(ch->name, channelname) == 0)
+ break;
+ }
}
ch = l ? l->data : NULL;
ret = SR_ERR;
break;
}
- ch = find_channel(channels, str);
+ ch = find_channel(channels, str, TRUE);
if (!ch) {
g_critical("unknown channel '%d'.", b);
ret = SR_ERR;
break;
}
- ch = find_channel(channels, names[0]);
+ ch = find_channel(channels, names[0], TRUE);
if (!ch) {
g_critical("unknown channel '%s'.", names[0]);
g_strfreev(names);
}
if (names[1]) {
/* Rename channel. */
- g_free(ch->name);
- ch->name = g_strdup(names[1]);
+ sr_dev_channel_name_set(ch, names[1]);
}
channellist = g_slist_append(channellist, ch);
i++;
}
for (; elements[i]; i++) {
+ if (!elements[i][0])
+ continue;
split_key_value(elements[i], &k, &v);
k = g_strdup(k);
v = v ? g_strdup(v) : NULL;
g_hash_table_insert(hash, g_strdup(opts[i]->id),
g_variant_ref_sink(gvar));
} else if (g_variant_is_of_type(opts[i]->def, G_VARIANT_TYPE_INT32)) {
- gvar = g_variant_new_int32(strtoul(s, NULL, 10));
+ gvar = g_variant_new_int32(strtol(s, NULL, 10));
g_hash_table_insert(hash, g_strdup(opts[i]->id),
g_variant_ref_sink(gvar));
} else if (g_variant_is_of_type(opts[i]->def, G_VARIANT_TYPE_UINT64)) {
- gvar = g_variant_new_uint64(strtoul(s, NULL, 10));
+ gvar = g_variant_new_uint64(strtoull(s, NULL, 10));
g_hash_table_insert(hash, g_strdup(opts[i]->id),
g_variant_ref_sink(gvar));
} else if (g_variant_is_of_type(opts[i]->def, G_VARIANT_TYPE_DOUBLE)) {
if (packet->type == SR_DF_END) {
g_debug("cli: Received SR_DF_END.");
+#if defined HAVE_SRD_SESSION_SEND_EOF && HAVE_SRD_SESSION_SEND_EOF
+ (void)srd_session_send_eof(srd_sess);
+#endif
+
if (do_props) {
props_dump_details(df_arg);
props_cleanup(df_arg);
#include <string.h>
#include "sigrok-cli.h"
+#define DECODERS_HAVE_TAGS \
+ ((SRD_PACKAGE_VERSION_MAJOR > 0) || \
+ (SRD_PACKAGE_VERSION_MAJOR == 0) && (SRD_PACKAGE_VERSION_MINOR > 5))
+
static gint sort_inputs(gconstpointer a, gconstpointer b)
{
return strcmp(sr_input_id_get((struct sr_input_module *)a),
for (l = sl; l; l = l->next) {
dec = l->data;
+#if DECODERS_HAVE_TAGS
GString *tags = g_string_new(NULL);
for (GSList *t = dec->tags; t; t = t->next)
g_string_append_printf(tags, "%s, ", (char *)t->data);
if (tags->len != 0)
g_string_truncate(tags, tags->len - 2);
+#endif
GString *in = g_string_new(NULL);
for (GSList *t = dec->inputs; t; t = t->next)
else
g_string_truncate(out, out->len - 2);
+#if DECODERS_HAVE_TAGS
printf("{{pd|%s|%s|%s|%s|%s|%s|%s|supported}}\n",
dec->id, dec->name, dec->longname, dec->desc,
tags->str, in->str, out->str);
+#else
+ printf("{{pd|%s|%s|%s|%s|%s|%s|supported}}\n",
+ dec->id, dec->name, dec->longname, dec->desc,
+ in->str, out->str);
+#endif
+#if DECODERS_HAVE_TAGS
g_string_free(tags, TRUE);
+#endif
g_string_free(in, TRUE);
g_string_free(out, TRUE);
}
char *tmp_str, *s, c;
const char **stropts;
double tmp_flt;
- gboolean have_tmp_flt;
+ gboolean have_tmp_flt, have_curr;
const double *fltopts;
if (parse_driver(opt_drv, &driver_from_opt, NULL)) {
printf("Channel groups:\n");
for (cgl = channel_groups; cgl; cgl = cgl->next) {
cg = cgl->data;
- printf(" %s: channel%s", cg->name,
- g_slist_length(cg->channels) > 1 ? "s" : "");
+ printf(" %s: ", cg->name);
+ if (g_slist_length(cg->channels) == 0)
+ printf("No channels");
+ else
+ printf("channel%s", g_slist_length(cg->channels) > 1 ? "s" : "");
for (chl = cg->channels; chl; chl = chl->next) {
ch = chl->data;
printf(" %s", ch->name);
continue;
}
+ have_curr = FALSE;
if (maybe_config_get(driver, sdi, channel_group, key, &gvar) == SR_OK) {
g_variant_get(gvar, "(dd)", &dcur_low, &dcur_high);
g_variant_unref(gvar);
- } else {
- dcur_low = 0;
- dcur_high = 0;
+ have_curr = TRUE;
}
num_elements = g_variant_n_children(gvar_list);
if (i)
printf(", ");
printf("%.1f-%.1f", dlow, dhigh);
+ if (!have_curr)
+ continue;
if (dlow == dcur_low && dhigh == dcur_high)
printf(" (current)");
}
printf("None.\n");
}
printf("Decoder tags:\n");
+#if DECODERS_HAVE_TAGS
if (dec->tags) {
for (l = dec->tags; l; l = l->next) {
str = l->data;
} else {
printf("None.\n");
}
+#endif
printf("Annotation classes:\n");
if (dec->annotations) {
for (l = dec->annotations; l; l = l->next) {
#endif
/* parsers.c */
-struct sr_channel *find_channel(GSList *channellist, const char *channelname);
+struct sr_channel *find_channel(GSList *channellist, const char *channelname,
+ gboolean exact_case);
GSList *parse_channelstring(struct sr_dev_inst *sdi, const char *channelstring);
int parse_triggerstring(const struct sr_dev_inst *sdi, const char *s,
struct sr_trigger **trigger);
extern gchar *opt_pd_annotations;
extern gchar *opt_pd_meta;
extern gchar *opt_pd_binary;
+extern gboolean opt_pd_ann_class;
extern gboolean opt_pd_samplenum;
extern gboolean opt_pd_jsontrace;
#endif