output: Finish output module API wrappers.

The sr_output and sr_output_module structs are now no longer accessible
from the client.
This commit is contained in:
Bert Vermeulen 2014-07-25 05:56:52 +02:00
parent 06bd935e16
commit a755b0e122
18 changed files with 550 additions and 238 deletions

View File

@ -429,6 +429,20 @@ struct sr_datafeed_analog {
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 {
/**
@ -501,102 +515,8 @@ struct sr_input_format {
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 {

View File

@ -128,12 +128,18 @@ SR_API struct sr_input_format **sr_input_list(void);
/*--- 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 -------------------------------------------------------------*/

View File

@ -265,7 +265,7 @@ static int sanity_check_all_input_modules(void)
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.");
@ -280,7 +280,11 @@ static int sanity_check_all_output_modules(void)
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++;
}

View File

@ -159,6 +159,107 @@ struct sr_context {
#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 {

View File

@ -31,13 +31,13 @@ struct context {
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;
@ -215,7 +215,7 @@ static void fancyprint(int unit, int mqflags, float value, GString *out)
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;
@ -268,9 +268,11 @@ static int cleanup(struct sr_output *o)
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

View File

@ -44,7 +44,7 @@ struct context {
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;
@ -52,22 +52,27 @@ static int init(struct sr_output *o)
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;
}
}
@ -106,7 +111,7 @@ static int init(struct sr_output *o)
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;
@ -138,7 +143,7 @@ static GString *gen_header(struct sr_output *o)
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;
@ -250,9 +255,27 @@ static int cleanup(struct sr_output *o)
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,

View File

@ -26,7 +26,7 @@
#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;
@ -42,8 +42,10 @@ static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
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,
};

View File

@ -39,7 +39,7 @@ struct context {
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;
@ -47,22 +47,27 @@ static int init(struct sr_output *o)
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;
}
}
@ -100,7 +105,7 @@ static int init(struct sr_output *o)
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;
@ -132,7 +137,7 @@ static GString *gen_header(struct sr_output *o)
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;
@ -236,9 +241,27 @@ static int cleanup(struct sr_output *o)
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,

View File

@ -75,12 +75,14 @@ static uint8_t samplerate_to_divcount(uint64_t samplerate)
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;
@ -101,7 +103,7 @@ static int init(struct sr_output *o)
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;
@ -181,9 +183,11 @@ static int cleanup(struct sr_output *o)
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,

View File

@ -47,13 +47,15 @@ struct context {
* - 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;
@ -85,7 +87,7 @@ static int init(struct sr_output *o)
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;
@ -137,7 +139,7 @@ static GString *gen_header(struct sr_output *o)
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;
@ -211,9 +213,11 @@ static int cleanup(struct sr_output *o)
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,

View File

@ -44,13 +44,15 @@ static const char *gnuplot_header2 = "\
# 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;
@ -84,7 +86,7 @@ static int init(struct sr_output *o)
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;
@ -130,7 +132,7 @@ static GString *gen_header(struct sr_output *o)
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;
@ -215,9 +217,11 @@ static int cleanup(struct sr_output *o)
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,

View File

@ -42,7 +42,7 @@ struct context {
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;
@ -50,22 +50,28 @@ static int init(struct sr_output *o)
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;
}
}
@ -105,7 +111,7 @@ static int init(struct sr_output *o)
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;
@ -137,7 +143,7 @@ static GString *gen_header(struct sr_output *o)
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;
@ -250,9 +256,27 @@ static int cleanup(struct sr_output *o)
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,

View File

@ -38,10 +38,12 @@ struct context {
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;
@ -88,7 +90,7 @@ static GString *gen_header(const struct sr_dev_inst *sdi, struct context *ctx)
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;
@ -148,9 +150,11 @@ static int cleanup(struct sr_output *o)
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

View File

@ -17,23 +17,26 @@
* 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
@ -47,19 +50,19 @@
*/
/** @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,
@ -73,46 +76,182 @@ static struct sr_output_format *output_module_list[] = {
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)
{
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;
if (!o) {
sr_err("Invalid output module NULL!");
return NULL;
}
return o;
return o->id;
}
/** @since 0.3.0 */
SR_API int sr_output_send(struct sr_output *o,
/**
* 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_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;
}
}
}
/**
* 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;
}
/**
* 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;
}

View File

@ -42,13 +42,15 @@ struct context {
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;
@ -81,7 +83,7 @@ static int init(struct sr_output *o)
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;
@ -154,7 +156,7 @@ static GString *gen_header(struct sr_output *o)
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;
@ -260,9 +262,11 @@ static int cleanup(struct sr_output *o)
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,

View File

@ -26,13 +26,76 @@
/* 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;
@ -42,6 +105,11 @@ Suite *suite_output_all(void)
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;

View File

@ -64,25 +64,6 @@ struct sr_input_format *srtest_input_get(const char *id)
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)
{

View File

@ -25,7 +25,6 @@
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);