float *data;
};
+/** Generic option struct used by various subsystems. */
+struct sr_option {
+ /* Short name suitable for commandline usage, [a-z0-9-]. */
+ char *id;
+ /* Short name suitable for GUI usage, can contain UTF-8. */
+ char *name;
+ /* Description of the option, in a sentence. */
+ char *desc;
+ /* Default value for this option. */
+ GVariant *def;
+ /* List of possible values, if this is an option with few values. */
+ GSList *values;
+};
+
/** Input (file) format struct. */
struct sr_input {
/**
int (*loadfile) (struct sr_input *in, const char *filename);
};
-/** Output (file) format struct. */
-struct sr_output {
- /** A pointer to this output's format. */
- struct sr_output_format *format;
-
- /**
- * The device for which this output module is creating output. This
- * can be used by the module to find out channel names and numbers.
- */
- const struct sr_dev_inst *sdi;
-
- /**
- * An optional parameter which the frontend can pass in to the
- * output module. How the string is interpreted is entirely up to
- * the module.
- */
- GHashTable *params;
-
- /**
- * A generic pointer which can be used by the module to keep internal
- * state between calls into its callback functions.
- *
- * For example, the module might store a pointer to a chunk of output
- * there, and only flush it when it reaches a certain size.
- */
- void *internal;
-};
-
-/** Output (file) format driver. */
-struct sr_output_format {
- /**
- * A unique ID for this output format. Must not be NULL.
- *
- * It can be used by frontends to select this output format for use.
- *
- * For example, calling sigrok-cli with <code>-O hex</code> will
- * select the hexadecimal text output format.
- */
- char *id;
-
- /**
- * A short description of the output format. Must not be NULL.
- *
- * This can be displayed by frontends, e.g. when selecting the output
- * format for saving a file.
- */
- char *description;
-
- /**
- * This function is called once, at the beginning of an output stream.
- *
- * The device struct will be available in the output struct passed in,
- * as well as the param field -- which may be NULL or an empty string,
- * if no parameter was passed.
- *
- * The module can use this to initialize itself, create a struct for
- * keeping state and storing it in the <code>internal</code> field.
- *
- * @param o Pointer to the respective 'struct sr_output'.
- *
- * @retval SR_OK Success
- * @retval other Negative error code.
- */
- int (*init) (struct sr_output *o);
-
- /**
- * This function is passed a copy of every packed in the data feed.
- * Any output generated by the output module in response to the
- * packet should be returned in a newly allocated GString
- * <code>out</code>, which will be freed by the caller.
- *
- * Packets not of interest to the output module can just be ignored,
- * and the <code>out</code> parameter set to NULL.
- *
- * @param o Pointer to the respective 'struct sr_output'.
- * @param sdi The device instance that generated the packet.
- * @param packet The complete packet.
- * @param out A pointer where a GString * should be stored if
- * the module generates output, or NULL if not.
- *
- * @retval SR_OK Success
- * @retval other Negative error code.
- */
- int (*receive) (struct sr_output *o,
- const struct sr_datafeed_packet *packet, GString **out);
-
- /**
- * This function is called after the caller is finished using
- * the output module, and can be used to free any internal
- * resources the module may keep.
- *
- * @retval SR_OK Success
- * @retval other Negative error code.
- */
- int (*cleanup) (struct sr_output *o);
-};
+struct sr_output;
+struct sr_output_module;
/** Constants for channel type. */
enum sr_channeltype {
/*--- output/output.c -------------------------------------------------------*/
-SR_API struct sr_output_format **sr_output_list(void);
-SR_API struct sr_output *sr_output_new(struct sr_output_format *of,
+SR_API const struct sr_output_module **sr_output_list(void);
+SR_API const char *sr_output_id_get(const struct sr_output_module *o);
+SR_API const char *sr_output_name_get(const struct sr_output_module *o);
+SR_API const char *sr_output_description_get(const struct sr_output_module *o);
+SR_API const struct sr_output_module *sr_output_find(char *id);
+SR_API const struct sr_option *sr_output_options_get(const struct sr_output_module *o);
+SR_API void sr_output_options_free(const struct sr_output_module *o);
+SR_API const struct sr_output *sr_output_new(const struct sr_output_module *o,
GHashTable *params, const struct sr_dev_inst *sdi);
-SR_API int sr_output_send(struct sr_output *o,
+SR_API int sr_output_send(const struct sr_output *o,
const struct sr_datafeed_packet *packet, GString **out);
-SR_API int sr_output_free(struct sr_output *o);
+SR_API int sr_output_free(const struct sr_output *o);
/*--- trigger.c -------------------------------------------------------------*/
static int sanity_check_all_output_modules(void)
{
int i, errors, ret = SR_OK;
- struct sr_output_format **outputs;
+ const struct sr_output_module **outputs;
const char *d;
sr_spew("Sanity-checking all output modules.");
sr_err("No ID in module %d ('%s').", i, d);
errors++;
}
- if (!outputs[i]->description) {
+ if (!outputs[i]->name) {
+ sr_err("No name in module %d ('%s').", i, d);
+ errors++;
+ }
+ if (!outputs[i]->desc) {
sr_err("No description in module '%s'.", d);
errors++;
}
#endif
};
+/** Output module instance. */
+struct sr_output {
+ /** A pointer to this output's module. */
+ const struct sr_output_module *module;
+
+ /**
+ * The device for which this output module is creating output. This
+ * can be used by the module to find out channel names and numbers.
+ */
+ const struct sr_dev_inst *sdi;
+
+ /**
+ * A generic pointer which can be used by the module to keep internal
+ * state between calls into its callback functions.
+ *
+ * For example, the module might store a pointer to a chunk of output
+ * there, and only flush it when it reaches a certain size.
+ */
+ void *internal;
+};
+
+/** Output module driver. */
+struct sr_output_module {
+ /**
+ * A unique ID for this output module, suitable for use in command-line
+ * clients, [a-z0-9-]. Must not be NULL.
+ */
+ char *id;
+
+ /**
+ * A unique name for this output module, suitable for use in GUI
+ * clients, can contain UTF-8. Must not be NULL.
+ */
+ const char *name;
+
+ /**
+ * A short description of the output module. Must not be NULL.
+ *
+ * This can be displayed by frontends, e.g. when selecting the output
+ * module for saving a file.
+ */
+ char *desc;
+
+ /**
+ * Returns a NULL-terminated list of options this module can take.
+ * Can be NULL, if the module has no options.
+ *
+ * If cached is TRUE, no new GVariants are created for the def and
+ * values fields; instead, the current values are returned.
+ */
+ struct sr_option *(*options) (gboolean cached);
+
+ /**
+ * This function is called once, at the beginning of an output stream.
+ *
+ * The device struct will be available in the output struct passed in,
+ * as well as the param field -- which may be NULL or an empty string,
+ * if no parameter was passed.
+ *
+ * The module can use this to initialize itself, create a struct for
+ * keeping state and storing it in the <code>internal</code> field.
+ *
+ * @param o Pointer to the respective 'struct sr_output'.
+ *
+ * @retval SR_OK Success
+ * @retval other Negative error code.
+ */
+ int (*init) (struct sr_output *o, GHashTable *options);
+
+ /**
+ * This function is passed a copy of every packed in the data feed.
+ * Any output generated by the output module in response to the
+ * packet should be returned in a newly allocated GString
+ * <code>out</code>, which will be freed by the caller.
+ *
+ * Packets not of interest to the output module can just be ignored,
+ * and the <code>out</code> parameter set to NULL.
+ *
+ * @param o Pointer to the respective 'struct sr_output'.
+ * @param sdi The device instance that generated the packet.
+ * @param packet The complete packet.
+ * @param out A pointer where a GString * should be stored if
+ * the module generates output, or NULL if not.
+ *
+ * @retval SR_OK Success
+ * @retval other Negative error code.
+ */
+ int (*receive) (const struct sr_output *o,
+ const struct sr_datafeed_packet *packet, GString **out);
+
+ /**
+ * This function is called after the caller is finished using
+ * the output module, and can be used to free any internal
+ * resources the module may keep.
+ *
+ * @retval SR_OK Success
+ * @retval other Negative error code.
+ */
+ int (*cleanup) (struct sr_output *o);
+};
+
#ifdef HAVE_LIBUSB_1_0
/** USB device instance */
struct sr_usb_dev_inst {
GPtrArray *channellist;
};
-static int init(struct sr_output *o)
+static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
struct sr_channel *ch;
GSList *l;
- sr_spew("Initializing output module.");
+ (void)options;
if (!o || !o->sdi)
return SR_ERR_ARG;
g_string_append_c(out, '\n');
}
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_analog *analog;
return SR_OK;
}
-SR_PRIV struct sr_output_format output_analog = {
+SR_PRIV struct sr_output_module output_analog = {
.id = "analog",
- .description = "Analog data",
+ .name = "Analog",
+ .desc = "Analog data and types",
+ .options = NULL,
.init = init,
.receive = receive,
.cleanup = cleanup
GString *header;
};
-static int init(struct sr_output *o)
+static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
struct sr_channel *ch;
GHashTableIter iter;
gpointer key, value;
unsigned int i, j;
- int spl;
+ uint32_t spl;
if (!o || !o->sdi)
return SR_ERR_ARG;
spl = DEFAULT_SAMPLES_PER_LINE;
- g_hash_table_iter_init(&iter, o->params);
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- if (!strcmp(key, "width")) {
- if ((spl = strtoul(value, NULL, 10)) < 1) {
- sr_err("Invalid width.");
- return SR_ERR_ARG;
+ if (options) {
+ g_hash_table_iter_init(&iter, options);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ if (!strcmp(key, "width")) {
+ if (!g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32)) {
+ sr_err("Invalid type for 'width' option.");
+ return SR_ERR_ARG;
+ }
+ if (!(spl = g_variant_get_uint32(value))) {
+ sr_err("Invalid width.");
+ return SR_ERR_ARG;
+ }
+ } else {
+ sr_err("Unknown option '%s'.", key);
}
- } else {
- sr_err("Unknown parameter '%s'.", key);
- return SR_ERR_ARG;
}
}
return SR_OK;
}
-static GString *gen_header(struct sr_output *o)
+static GString *gen_header(const struct sr_output *o)
{
struct context *ctx;
GVariant *gvar;
return header;
}
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_meta *meta;
return SR_OK;
}
-SR_PRIV struct sr_output_format output_ascii = {
+static struct sr_option options[] = {
+ { "width", "Width", "Number of samples per line", NULL, NULL },
+ { 0 }
+};
+
+static struct sr_option *get_options(gboolean cached)
+{
+ if (cached)
+ return options;
+
+ options[0].def = g_variant_new_uint32(DEFAULT_SAMPLES_PER_LINE);
+ g_variant_ref_sink(options[0].def);
+
+ return options;
+}
+
+SR_PRIV struct sr_output_module output_ascii = {
.id = "ascii",
- .description = "ASCII",
+ .name = "ASCII",
+ .desc = "ASCII art",
+ .options = get_options,
.init = init,
.receive = receive,
.cleanup = cleanup,
#define LOG_PREFIX "output/binary"
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_logic *logic;
return SR_OK;
}
-SR_PRIV struct sr_output_format output_binary = {
+SR_PRIV struct sr_output_module output_binary = {
.id = "binary",
- .description = "Raw binary",
+ .name = "Binary",
+ .desc = "Raw binary",
+ .options = NULL,
.receive = receive,
};
GString **lines;
};
-static int init(struct sr_output *o)
+static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
struct sr_channel *ch;
GHashTableIter iter;
gpointer key, value;
unsigned int i, j;
- int spl;
+ uint32_t spl;
if (!o || !o->sdi)
return SR_ERR_ARG;
spl = DEFAULT_SAMPLES_PER_LINE;
- g_hash_table_iter_init(&iter, o->params);
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- if (!strcmp(key, "width")) {
- if ((spl = strtoul(value, NULL, 10)) < 1) {
- sr_err("Invalid width.");
- return SR_ERR_ARG;
+ if (options) {
+ g_hash_table_iter_init(&iter, options);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ if (!strcmp(key, "width")) {
+ if (!g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32)) {
+ sr_err("Invalid type for 'width' option.");
+ return SR_ERR_ARG;
+ }
+ if (!(spl = g_variant_get_uint32(value))) {
+ sr_err("Invalid width.");
+ return SR_ERR_ARG;
+ }
+ } else {
+ sr_err("Unknown option '%s'.", key);
}
- } else {
- sr_err("Unknown parameter '%s'.", key);
- return SR_ERR_ARG;
}
}
return SR_OK;
}
-static GString *gen_header(struct sr_output *o)
+static GString *gen_header(const struct sr_output *o)
{
struct context *ctx;
GVariant *gvar;
return header;
}
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_meta *meta;
return SR_OK;
}
-SR_PRIV struct sr_output_format output_bits = {
+static struct sr_option options[] = {
+ { "width", "Width", "Number of samples per line", NULL, NULL },
+ { 0 }
+};
+
+static struct sr_option *get_options(gboolean cached)
+{
+ if (cached)
+ return options;
+
+ options[0].def = g_variant_new_uint32(DEFAULT_SAMPLES_PER_LINE);
+ g_variant_ref_sink(options[0].def);
+
+ return options;
+}
+
+SR_PRIV struct sr_output_module output_bits = {
.id = "bits",
- .description = "Bits",
+ .name = "Bits",
+ .desc = "0/1 digits",
+ .options = get_options,
.init = init,
.receive = receive,
.cleanup = cleanup,
return (SR_MHZ(100) / samplerate) - 1;
}
-static int init(struct sr_output *o)
+static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
struct sr_channel *ch;
GSList *l;
+ (void)options;
+
if (!o || !o->sdi)
return SR_ERR_ARG;
return SR_OK;
}
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_logic *logic;
return SR_OK;
}
-SR_PRIV struct sr_output_format output_chronovu_la8 = {
+SR_PRIV struct sr_output_module output_chronovu_la8 = {
.id = "chronovu-la8",
- .description = "ChronoVu LA8",
+ .name = "ChronoVu LA8",
+ .desc = "ChronoVu LA8 native file format",
+ .options = NULL,
.init = init,
.receive = receive,
.cleanup = cleanup,
* - Trigger support.
*/
-static int init(struct sr_output *o)
+static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
struct sr_channel *ch;
GSList *l;
int i;
+ (void)options;
+
if (!o || !o->sdi)
return SR_ERR_ARG;
return SR_OK;
}
-static GString *gen_header(struct sr_output *o)
+static GString *gen_header(const struct sr_output *o)
{
struct context *ctx;
struct sr_channel *ch;
return header;
}
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_meta *meta;
return SR_OK;
}
-SR_PRIV struct sr_output_format output_csv = {
+SR_PRIV struct sr_output_module output_csv = {
.id = "csv",
- .description = "Comma-separated values (CSV)",
+ .name = "CSV",
+ .desc = "Comma-separated values",
+ .options = NULL,
.init = init,
.receive = receive,
.cleanup = cleanup,
# 0\t\tSample counter (for internal gnuplot purposes)\n";
-static int init(struct sr_output *o)
+static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
struct sr_channel *ch;
GSList *l;
unsigned int i;
+ (void)options;
+
if (!o || !o->sdi)
return SR_ERR_ARG;
return SR_OK;
}
-static GString *gen_header(struct sr_output *o)
+static GString *gen_header(const struct sr_output *o)
{
struct context *ctx;
struct sr_channel *ch;
return header;
}
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_meta *meta;
return SR_OK;
}
-SR_PRIV struct sr_output_format output_gnuplot = {
+SR_PRIV struct sr_output_module output_gnuplot = {
.id = "gnuplot",
- .description = "Gnuplot",
+ .name = "Gnuplot",
+ .desc = "Gnuplot file format",
+ .options = NULL,
.init = init,
.receive = receive,
.cleanup = cleanup,
GString **lines;
};
-static int init(struct sr_output *o)
+static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
struct sr_channel *ch;
GHashTableIter iter;
gpointer key, value;
unsigned int i, j;
- int spl;
+ uint32_t spl;
if (!o || !o->sdi)
return SR_ERR_ARG;
spl = DEFAULT_SAMPLES_PER_LINE;
- g_hash_table_iter_init(&iter, o->params);
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- if (!strcmp(key, "width")) {
- if ((spl = strtoul(value, NULL, 10)) < 1) {
- sr_err("Invalid width.");
+ if (options) {
+ g_hash_table_iter_init(&iter, options);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ if (!strcmp(key, "width")) {
+ if (!g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32)) {
+ sr_err("Invalid type for 'width' option.");
+ return SR_ERR_ARG;
+ }
+ if (!(spl = g_variant_get_uint32(value))) {
+ sr_err("Invalid width.");
+ return SR_ERR_ARG;
+ }
+ } else {
+ sr_err("Unknown option '%s'.", key);
return SR_ERR_ARG;
}
- } else {
- sr_err("Unknown parameter '%s'.", key);
- return SR_ERR_ARG;
}
}
return SR_OK;
}
-static GString *gen_header(struct sr_output *o)
+static GString *gen_header(const struct sr_output *o)
{
struct context *ctx;
GVariant *gvar;
return header;
}
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_meta *meta;
return SR_OK;
}
-SR_PRIV struct sr_output_format output_hex = {
+static struct sr_option options[] = {
+ { "width", "Width", "Number of samples per line", NULL, NULL },
+ { 0 }
+};
+
+static struct sr_option *get_options(gboolean cached)
+{
+ if (cached)
+ return options;
+
+ options[0].def = g_variant_new_uint32(DEFAULT_SAMPLES_PER_LINE);
+ g_variant_ref_sink(options[0].def);
+
+ return options;
+}
+
+SR_PRIV struct sr_output_module output_hex = {
.id = "hex",
- .description = "Hexadecimal",
+ .name = "Hexadecimal",
+ .desc = "Hexadecimal digits",
+ .options = get_options,
.init = init,
.receive = receive,
.cleanup = cleanup,
uint64_t num_samples;
};
-static int init(struct sr_output *o)
+static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
+ (void)options;
+
if (!(ctx = g_try_malloc(sizeof(struct context)))) {
sr_err("%s: ctx malloc failed", __func__);
return SR_ERR_MALLOC;
return s;
}
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
struct context *ctx;
return SR_OK;
}
-SR_PRIV struct sr_output_format output_ols = {
+SR_PRIV struct sr_output_module output_ols = {
.id = "ols",
- .description = "OpenBench Logic Sniffer",
+ .name = "OLS",
+ .desc = "OpenBench Logic Sniffer",
+ .options = NULL,
.init = init,
.receive = receive,
.cleanup = cleanup
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <string.h>
#include "libsigrok.h"
#include "libsigrok-internal.h"
+#define LOG_PREFIX "output"
+
/**
* @file
*
- * Output file/data format handling.
+ * Output module handling.
*/
/**
- * @defgroup grp_output Output formats
+ * @defgroup grp_output Output modules
*
- * Output file/data format handling.
+ * Output module handling.
*
- * libsigrok supports several output (file) formats, e.g. binary, VCD,
- * gnuplot, and so on. It provides an output API that frontends can use.
- * New output formats can be added/implemented in libsigrok without having
+ * libsigrok supports several output modules for file formats such as binary,
+ * VCD, gnuplot, and so on. It provides an output API that frontends can use.
+ * New output modules can be added/implemented in libsigrok without having
* to change the frontends at all.
*
* All output modules are fed data in a stream. Devices that can stream data
*/
/** @cond PRIVATE */
-extern SR_PRIV struct sr_output_format output_bits;
-extern SR_PRIV struct sr_output_format output_hex;
-extern SR_PRIV struct sr_output_format output_ascii;
-extern SR_PRIV struct sr_output_format output_binary;
-extern SR_PRIV struct sr_output_format output_vcd;
-extern SR_PRIV struct sr_output_format output_ols;
-extern SR_PRIV struct sr_output_format output_gnuplot;
-extern SR_PRIV struct sr_output_format output_chronovu_la8;
-extern SR_PRIV struct sr_output_format output_csv;
-extern SR_PRIV struct sr_output_format output_analog;
+extern SR_PRIV struct sr_output_module output_bits;
+extern SR_PRIV struct sr_output_module output_hex;
+extern SR_PRIV struct sr_output_module output_ascii;
+extern SR_PRIV struct sr_output_module output_binary;
+extern SR_PRIV struct sr_output_module output_vcd;
+extern SR_PRIV struct sr_output_module output_ols;
+extern SR_PRIV struct sr_output_module output_gnuplot;
+extern SR_PRIV struct sr_output_module output_chronovu_la8;
+extern SR_PRIV struct sr_output_module output_csv;
+extern SR_PRIV struct sr_output_module output_analog;
/* @endcond */
-static struct sr_output_format *output_module_list[] = {
+static const struct sr_output_module *output_module_list[] = {
&output_ascii,
&output_binary,
&output_bits,
NULL,
};
-/** @since 0.1.0 */
-SR_API struct sr_output_format **sr_output_list(void)
+/**
+ * Returns a NULL-terminated list of all the available output modules.
+ *
+ * @since 0.4.0
+ */
+SR_API const struct sr_output_module **sr_output_list(void)
{
return output_module_list;
}
-/** @since 0.3.0 */
-SR_API struct sr_output *sr_output_new(struct sr_output_format *of,
- GHashTable *params, const struct sr_dev_inst *sdi)
+/**
+ * Returns the specified output module's ID.
+ *
+ * @since 0.4.0
+ */
+SR_API const char *sr_output_id_get(const struct sr_output_module *o)
+{
+ if (!o) {
+ sr_err("Invalid output module NULL!");
+ return NULL;
+ }
+
+ return o->id;
+}
+
+/**
+ * Returns the specified output module's name.
+ *
+ * @since 0.4.0
+ */
+SR_API const char *sr_output_name_get(const struct sr_output_module *o)
+{
+ if (!o) {
+ sr_err("Invalid output module NULL!");
+ return NULL;
+ }
+
+ return o->name;
+}
+
+/**
+ * Returns the specified output module's description.
+ *
+ * @since 0.4.0
+ */
+SR_API const char *sr_output_description_get(const struct sr_output_module *o)
+{
+ if (!o) {
+ sr_err("Invalid output module NULL!");
+ return NULL;
+ }
+
+ return o->desc;
+}
+
+/**
+ * Return the output module with the specified ID, or NULL if no module
+ * with that id is found.
+ *
+ * @since 0.4.0
+ */
+SR_API const struct sr_output_module *sr_output_find(char *id)
+{
+ int i;
+
+ for (i = 0; output_module_list[i]; i++) {
+ if (!strcmp(output_module_list[i]->id, id))
+ return output_module_list[i];
+ }
+
+ return NULL;
+}
+
+/**
+ * Returns a NULL-terminated array of struct sr_option, or NULL if the
+ * module takes no options.
+ *
+ * Each call to this function must be followed by a call to
+ * sr_output_options_free().
+ *
+ * @since 0.4.0
+ */
+SR_API const struct sr_option *sr_output_options_get(const struct sr_output_module *o)
+{
+
+ if (!o || !o->options)
+ return NULL;
+
+ return o->options(FALSE);
+}
+
+/**
+ * After a call to sr_output_options_get(), this function cleans up all
+ * the resources allocated by that call.
+ *
+ * @since 0.4.0
+ */
+SR_API void sr_output_options_free(const struct sr_output_module *o)
{
- struct sr_output *o;
-
- o = g_malloc(sizeof(struct sr_output));
- o->format = of;
- o->sdi = sdi;
- o->params = params;
- if (o->format->init && o->format->init(o) != SR_OK) {
- g_free(o);
- o = NULL;
+ struct sr_option *opt;
+
+ if (!o || !o->options)
+ return;
+
+ for (opt = o->options(TRUE); opt->id; opt++) {
+ if (opt->def) {
+ g_variant_unref(opt->def);
+ opt->def = NULL;
+ }
+
+ if (opt->values) {
+ g_slist_free_full(opt->values, (GDestroyNotify)g_variant_unref);
+ opt->values = NULL;
+ }
}
+}
- return o;
+/**
+ * Create a new output instance using the specified output module.
+ *
+ * <code>options</code> is a *HashTable with the keys corresponding with
+ * the module options' <code>id</code> field. The values should be GVariant
+ * pointers with sunk * references, of the same GVariantType as the option's
+ * default value.
+ *
+ * The sr_dev_inst passed in can be used by the instance to determine
+ * channel names, samplerate, and so on.
+ *
+ * @since 0.4.0
+ */
+SR_API const struct sr_output *sr_output_new(const struct sr_output_module *o,
+ GHashTable *options, const struct sr_dev_inst *sdi)
+{
+ struct sr_output *op;
+
+ op = g_malloc(sizeof(struct sr_output));
+ op->module = o;
+ op->sdi = sdi;
+ if (op->module->init && op->module->init(op, options) != SR_OK) {
+ g_free(op);
+ op = NULL;
+ }
+
+ return op;
}
-/** @since 0.3.0 */
-SR_API int sr_output_send(struct sr_output *o,
+/**
+ * Send a packet to the specified output instance.
+ *
+ * The instance's output is returned as a newly allocated GString,
+ * which must be freed by the caller.
+ *
+ * @since 0.4.0
+ */
+SR_API int sr_output_send(const struct sr_output *o,
const struct sr_datafeed_packet *packet, GString **out)
{
- return o->format->receive(o, packet, out);
+ return o->module->receive(o, packet, out);
}
-/** @since 0.3.0 */
-SR_API int sr_output_free(struct sr_output *o)
+/**
+ * Free the specified output instance and all associated resources.
+ *
+ * @since 0.4.0
+ */
+SR_API int sr_output_free(const struct sr_output *o)
{
int ret;
+ if (!o)
+ return SR_ERR_ARG;
+
ret = SR_OK;
- if (o->format->cleanup)
- ret = o->format->cleanup(o);
- g_free(o);
+ if (o->module->cleanup)
+ ret = o->module->cleanup((struct sr_output *)o);
+ g_free((gpointer)o);
return ret;
}
static const char *const vcd_header_comment =
"$comment\n Acquisition with %d/%d channels at %s\n$end\n";
-static int init(struct sr_output *o)
+static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
struct sr_channel *ch;
GSList *l;
int num_enabled_channels, i;
+ (void)options;
+
num_enabled_channels = 0;
for (l = o->sdi->channels; l; l = l->next) {
ch = l->data;
return SR_OK;
}
-static GString *gen_header(struct sr_output *o)
+static GString *gen_header(const struct sr_output *o)
{
struct context *ctx;
struct sr_channel *ch;
return header;
}
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_meta *meta;
return SR_OK;
}
-struct sr_output_format output_vcd = {
+struct sr_output_module output_vcd = {
.id = "vcd",
- .description = "Value Change Dump (VCD)",
+ .name = "VCD",
+ .desc = "Value Change Dump",
+ .options = NULL,
.init = init,
.receive = receive,
.cleanup = cleanup,
/* Check whether at least one output module is available. */
START_TEST(test_output_available)
{
- struct sr_output_format **outputs;
+ const struct sr_output_module **outputs;
outputs = sr_output_list();
fail_unless(outputs != NULL, "No output modules found.");
}
END_TEST
+/* Check whether sr_output_id_get() works. */
+START_TEST(test_output_id)
+{
+ const struct sr_output_module **outputs;
+ const char *id;
+
+ outputs = sr_output_list();
+
+ id = sr_output_id_get(outputs[0]);
+ fail_unless(id != NULL, "No id found in output module.");
+}
+END_TEST
+
+/* Check whether sr_output_name_get() works. */
+START_TEST(test_output_name)
+{
+ const struct sr_output_module **outputs;
+ const char *name;
+
+ outputs = sr_output_list();
+
+ name = sr_output_name_get(outputs[0]);
+ fail_unless(name != NULL, "No name found in output module.");
+}
+END_TEST
+
+/* Check whether sr_output_description_get() works. */
+START_TEST(test_output_desc)
+{
+ const struct sr_output_module **outputs;
+ const char *desc;
+
+ outputs = sr_output_list();
+
+ desc = sr_output_description_get(outputs[0]);
+ fail_unless(desc != NULL, "No description found in output module.");
+}
+END_TEST
+
+/* Check whether sr_output_find() works. */
+START_TEST(test_output_find)
+{
+ const struct sr_output_module *omod;
+ const char *id;
+
+ omod = sr_output_find("bits");
+ fail_unless(omod != NULL, "Couldn't find the 'bits' output module.");
+ id = sr_output_id_get(omod);
+ fail_unless(!strcmp(id, "bits"), "That is not the 'bits' module!");
+}
+END_TEST
+
+/* Check whether sr_output_options_get() works. */
+START_TEST(test_output_options)
+{
+ const struct sr_option *opt;
+
+ opt = sr_output_options_get(sr_output_find("bits"));
+ fail_unless(opt != NULL, "Couldn't find 'bits' options.");
+ fail_unless(!strcmp(opt->id, "width"), "Wrong 'bits' option found!");
+}
+END_TEST
+
Suite *suite_output_all(void)
{
Suite *s;
tc = tcase_create("basic");
tcase_add_test(tc, test_output_available);
+ tcase_add_test(tc, test_output_id);
+ tcase_add_test(tc, test_output_name);
+ tcase_add_test(tc, test_output_desc);
+ tcase_add_test(tc, test_output_find);
+ tcase_add_test(tc, test_output_options);
suite_add_tcase(s, tc);
return s;
return input;
}
-/* Get a libsigrok output format by ID. */
-struct sr_output_format *srtest_output_get(const char *id)
-{
- struct sr_output_format **outputs, *output = NULL;
- int i;
-
- outputs = sr_output_list();
- fail_unless(outputs != NULL, "No output modules found.");
-
- for (i = 0; outputs[i]; i++) {
- if (strcmp(outputs[i]->id, id))
- continue;
- output = outputs[i];
- }
- fail_unless(output != NULL, "Output module '%s' not found.", id);
-
- return output;
-}
-
/* Initialize a libsigrok driver. */
void srtest_driver_init(struct sr_context *sr_ctx, struct sr_dev_driver *driver)
{
struct sr_dev_driver *srtest_driver_get(const char *drivername);
struct sr_input_format *srtest_input_get(const char *id);
-struct sr_output_format *srtest_output_get(const char *id);
void srtest_driver_init(struct sr_context *sr_ctx, struct sr_dev_driver *driver);
void srtest_driver_init_all(struct sr_context *sr_ctx);