]> sigrok.org Git - libsigrok.git/blob - src/output/output.c
efb205c68192d8d020f590c86b04841cc9e3c886
[libsigrok.git] / src / output / output.c
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 */
56 extern SR_PRIV struct sr_output_module output_bits;
57 extern SR_PRIV struct sr_output_module output_hex;
58 extern SR_PRIV struct sr_output_module output_ascii;
59 extern SR_PRIV struct sr_output_module output_binary;
60 extern SR_PRIV struct sr_output_module output_vcd;
61 extern SR_PRIV struct sr_output_module output_ols;
62 extern SR_PRIV struct sr_output_module output_chronovu_la8;
63 extern SR_PRIV struct sr_output_module output_csv;
64 extern SR_PRIV struct sr_output_module output_analog;
65 extern SR_PRIV struct sr_output_module output_srzip;
66 extern SR_PRIV struct sr_output_module output_wav;
67 /* @endcond */
68
69 static 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  */
89 SR_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  */
99 SR_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  */
114 SR_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  */
129 SR_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  */
147 SR_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  */
164 SR_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  */
176 SR_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  */
197 SR_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  */
224 SR_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  */
258 SR_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  */
332 SR_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  */
343 SR_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 /** @} */