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:
parent
06bd935e16
commit
a755b0e122
|
@ -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 {
|
||||
|
|
|
@ -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 -------------------------------------------------------------*/
|
||||
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
if (options) {
|
||||
g_hash_table_iter_init(&iter, options);
|
||||
while (g_hash_table_iter_next(&iter, &key, &value)) {
|
||||
if (!strcmp(key, "width")) {
|
||||
if ((spl = strtoul(value, NULL, 10)) < 1) {
|
||||
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 parameter '%s'.", key);
|
||||
return SR_ERR_ARG;
|
||||
sr_err("Unknown option '%s'.", key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
if (options) {
|
||||
g_hash_table_iter_init(&iter, options);
|
||||
while (g_hash_table_iter_next(&iter, &key, &value)) {
|
||||
if (!strcmp(key, "width")) {
|
||||
if ((spl = strtoul(value, NULL, 10)) < 1) {
|
||||
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 parameter '%s'.", key);
|
||||
return SR_ERR_ARG;
|
||||
sr_err("Unknown option '%s'.", key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,24 +50,30 @@ 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);
|
||||
if (options) {
|
||||
g_hash_table_iter_init(&iter, options);
|
||||
while (g_hash_table_iter_next(&iter, &key, &value)) {
|
||||
if (!strcmp(key, "width")) {
|
||||
if ((spl = strtoul(value, NULL, 10)) < 1) {
|
||||
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 parameter '%s'.", key);
|
||||
sr_err("Unknown option '%s'.", key);
|
||||
return SR_ERR_ARG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx = g_malloc0(sizeof(struct context));
|
||||
o->internal = ctx;
|
||||
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
19
tests/lib.c
19
tests/lib.c
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue