]> sigrok.org Git - libsigrok.git/blame_incremental - src/output/output.c
output/csv: Nit, remove an unused loop iteration variable
[libsigrok.git] / src / output / output.c
... / ...
CommitLineData
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <config.h>
21#include <string.h>
22#include <libsigrok/libsigrok.h>
23#include "libsigrok-internal.h"
24
25/** @cond PRIVATE */
26#define LOG_PREFIX "output"
27/** @endcond */
28
29/**
30 * @file
31 *
32 * Output module handling.
33 */
34
35/**
36 * @defgroup grp_output Output modules
37 *
38 * Output module handling.
39 *
40 * libsigrok supports several output modules for file formats such as binary,
41 * VCD, csv, and so on. It provides an output API that frontends can use.
42 * New output modules can be added/implemented in libsigrok without having
43 * to change the frontends at all.
44 *
45 * All output modules are fed data in a stream. Devices that can stream data
46 * into libsigrok, instead of storing and then transferring the whole buffer,
47 * can thus generate output live.
48 *
49 * Output modules generate a newly allocated GString. The caller is then
50 * expected to free this with g_string_free() when finished with it.
51 *
52 * @{
53 */
54
55/** @cond PRIVATE */
56extern SR_PRIV struct sr_output_module output_bits;
57extern SR_PRIV struct sr_output_module output_hex;
58extern SR_PRIV struct sr_output_module output_ascii;
59extern SR_PRIV struct sr_output_module output_binary;
60extern SR_PRIV struct sr_output_module output_vcd;
61extern SR_PRIV struct sr_output_module output_ols;
62extern SR_PRIV struct sr_output_module output_chronovu_la8;
63extern SR_PRIV struct sr_output_module output_csv;
64extern SR_PRIV struct sr_output_module output_analog;
65extern SR_PRIV struct sr_output_module output_srzip;
66extern SR_PRIV struct sr_output_module output_wav;
67/* @endcond */
68
69static const struct sr_output_module *output_module_list[] = {
70 &output_ascii,
71 &output_binary,
72 &output_bits,
73 &output_csv,
74 &output_hex,
75 &output_ols,
76 &output_vcd,
77 &output_chronovu_la8,
78 &output_analog,
79 &output_srzip,
80 &output_wav,
81 NULL,
82};
83
84/**
85 * Returns a NULL-terminated list of all available output modules.
86 *
87 * @since 0.4.0
88 */
89SR_API const struct sr_output_module **sr_output_list(void)
90{
91 return output_module_list;
92}
93
94/**
95 * Returns the specified output module's ID.
96 *
97 * @since 0.4.0
98 */
99SR_API const char *sr_output_id_get(const struct sr_output_module *omod)
100{
101 if (!omod) {
102 sr_err("Invalid output module NULL!");
103 return NULL;
104 }
105
106 return omod->id;
107}
108
109/**
110 * Returns the specified output module's name.
111 *
112 * @since 0.4.0
113 */
114SR_API const char *sr_output_name_get(const struct sr_output_module *omod)
115{
116 if (!omod) {
117 sr_err("Invalid output module NULL!");
118 return NULL;
119 }
120
121 return omod->name;
122}
123
124/**
125 * Returns the specified output module's description.
126 *
127 * @since 0.4.0
128 */
129SR_API const char *sr_output_description_get(const struct sr_output_module *omod)
130{
131 if (!omod) {
132 sr_err("Invalid output module NULL!");
133 return NULL;
134 }
135
136 return omod->desc;
137}
138
139/**
140 * Returns the specified output module's file extensions typical for the file
141 * format, as a NULL terminated array, or returns a NULL pointer if there is
142 * no preferred extension.
143 * @note these are a suggestions only.
144 *
145 * @since 0.4.0
146 */
147SR_API const char *const *sr_output_extensions_get(
148 const struct sr_output_module *omod)
149{
150 if (!omod) {
151 sr_err("Invalid output module NULL!");
152 return NULL;
153 }
154
155 return omod->exts;
156}
157
158/*
159 * Checks whether a given flag is set.
160 *
161 * @see sr_output_flag
162 * @since 0.4.0
163 */
164SR_API gboolean sr_output_test_flag(const struct sr_output_module *omod,
165 uint64_t flag)
166{
167 return (flag & omod->flags);
168}
169
170/**
171 * Return the output module with the specified ID, or NULL if no module
172 * with that id is found.
173 *
174 * @since 0.4.0
175 */
176SR_API const struct sr_output_module *sr_output_find(char *id)
177{
178 int i;
179
180 for (i = 0; output_module_list[i]; i++) {
181 if (!strcmp(output_module_list[i]->id, id))
182 return output_module_list[i];
183 }
184
185 return NULL;
186}
187
188/**
189 * Returns a NULL-terminated array of struct sr_option, or NULL if the
190 * module takes no options.
191 *
192 * Each call to this function must be followed by a call to
193 * sr_output_options_free().
194 *
195 * @since 0.4.0
196 */
197SR_API const struct sr_option **sr_output_options_get(const struct sr_output_module *omod)
198{
199 const struct sr_option *mod_opts, **opts;
200 int size, i;
201
202 if (!omod || !omod->options)
203 return NULL;
204
205 mod_opts = omod->options();
206
207 for (size = 0; mod_opts[size].id; size++)
208 ;
209 opts = g_malloc((size + 1) * sizeof(struct sr_option *));
210
211 for (i = 0; i < size; i++)
212 opts[i] = &mod_opts[i];
213 opts[i] = NULL;
214
215 return opts;
216}
217
218/**
219 * After a call to sr_output_options_get(), this function cleans up all
220 * resources returned by that call.
221 *
222 * @since 0.4.0
223 */
224SR_API void sr_output_options_free(const struct sr_option **options)
225{
226 int i;
227
228 if (!options)
229 return;
230
231 for (i = 0; options[i]; i++) {
232 if (options[i]->def) {
233 g_variant_unref(options[i]->def);
234 ((struct sr_option *)options[i])->def = NULL;
235 }
236
237 if (options[i]->values) {
238 g_slist_free_full(options[i]->values, (GDestroyNotify)g_variant_unref);
239 ((struct sr_option *)options[i])->values = NULL;
240 }
241 }
242 g_free(options);
243}
244
245/**
246 * Create a new output instance using the specified output module.
247 *
248 * <code>options</code> is a *HashTable with the keys corresponding with
249 * the module options' <code>id</code> field. The values should be GVariant
250 * pointers with sunk * references, of the same GVariantType as the option's
251 * default value.
252 *
253 * The sr_dev_inst passed in can be used by the instance to determine
254 * channel names, samplerate, and so on.
255 *
256 * @since 0.4.0
257 */
258SR_API const struct sr_output *sr_output_new(const struct sr_output_module *omod,
259 GHashTable *options, const struct sr_dev_inst *sdi,
260 const char *filename)
261{
262 struct sr_output *op;
263 const struct sr_option *mod_opts;
264 const GVariantType *gvt;
265 GHashTable *new_opts;
266 GHashTableIter iter;
267 gpointer key, value;
268 int i;
269
270 op = g_malloc(sizeof(struct sr_output));
271 op->module = omod;
272 op->sdi = sdi;
273 op->filename = g_strdup(filename);
274
275 new_opts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
276 (GDestroyNotify)g_variant_unref);
277 if (omod->options) {
278 mod_opts = omod->options();
279 for (i = 0; mod_opts[i].id; i++) {
280 if (options && g_hash_table_lookup_extended(options,
281 mod_opts[i].id, &key, &value)) {
282 /* Pass option along. */
283 gvt = g_variant_get_type(mod_opts[i].def);
284 if (!g_variant_is_of_type(value, gvt)) {
285 sr_err("Invalid type for '%s' option.",
286 (char *)key);
287 g_free(op);
288 return NULL;
289 }
290 g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
291 g_variant_ref(value));
292 } else {
293 /* Option not given: insert the default value. */
294 g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
295 g_variant_ref(mod_opts[i].def));
296 }
297 }
298
299 /* Make sure no invalid options were given. */
300 if (options) {
301 g_hash_table_iter_init(&iter, options);
302 while (g_hash_table_iter_next(&iter, &key, &value)) {
303 if (!g_hash_table_lookup(new_opts, key)) {
304 sr_err("Output module '%s' has no option '%s'",
305 omod->id, (char *)key);
306 g_hash_table_destroy(new_opts);
307 g_free(op);
308 return NULL;
309 }
310 }
311 }
312 }
313
314 if (op->module->init && op->module->init(op, new_opts) != SR_OK) {
315 g_free(op);
316 op = NULL;
317 }
318 if (new_opts)
319 g_hash_table_destroy(new_opts);
320
321 return op;
322}
323
324/**
325 * Send a packet to the specified output instance.
326 *
327 * The instance's output is returned as a newly allocated GString,
328 * which must be freed by the caller.
329 *
330 * @since 0.4.0
331 */
332SR_API int sr_output_send(const struct sr_output *o,
333 const struct sr_datafeed_packet *packet, GString **out)
334{
335 return o->module->receive(o, packet, out);
336}
337
338/**
339 * Free the specified output instance and all associated resources.
340 *
341 * @since 0.4.0
342 */
343SR_API int sr_output_free(const struct sr_output *o)
344{
345 int ret;
346
347 if (!o)
348 return SR_ERR_ARG;
349
350 ret = SR_OK;
351 if (o->module->cleanup)
352 ret = o->module->cleanup((struct sr_output *)o);
353 g_free((char *)o->filename);
354 g_free((gpointer)o);
355
356 return ret;
357}
358
359/** @} */