]> sigrok.org Git - libsigrok.git/blob - src/input/input.c
input: Fix option enumeration.
[libsigrok.git] / src / input / input.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 <string.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 #include "libsigrok.h"
27 #include "libsigrok-internal.h"
28
29 #define LOG_PREFIX "input"
30
31 /**
32  * @file
33  *
34  * Input module handling.
35  */
36
37 /**
38  * @defgroup grp_input Input modules
39  *
40  * Input file/data module handling.
41  *
42  * libsigrok can process acquisition data in several different ways.
43  * Aside from acquiring data from a hardware device, it can also take it
44  * from a file in various formats (binary, CSV, VCD, and so on).
45  *
46  * Like all libsigrok data handling, processing is done in a streaming
47  * manner: input should be supplied a chunk at a time. This way anything
48  * that processes data can do so in real time, without the user having
49  * to wait for the whole thing to be finished.
50  *
51  * Every input module is "pluggable", meaning it's handled as being separate
52  * from the main libsigrok, but linked in to it statically. To keep things
53  * modular and separate like this, functions within an input module should be
54  * declared static, with only the respective 'struct sr_input_module' being
55  * exported for use into the wider libsigrok namespace.
56  *
57  * @{
58  */
59
60 /** @cond PRIVATE */
61 extern SR_PRIV struct sr_input_module input_chronovu_la8;
62 extern SR_PRIV struct sr_input_module input_csv;
63 extern SR_PRIV struct sr_input_module input_binary;
64 extern SR_PRIV struct sr_input_module input_vcd;
65 extern SR_PRIV struct sr_input_module input_wav;
66 /* @endcond */
67
68 static const struct sr_input_module *input_module_list[] = {
69         &input_vcd,
70 //      &input_chronovu_la8,
71         &input_wav,
72 //      &input_csv,
73         /* This one has to be last, because it will take any input. */
74 //      &input_binary,
75         NULL,
76 };
77
78 /**
79  * Returns a NULL-terminated list of all available input modules.
80  *
81  * @since 0.4.0
82  */
83 SR_API const struct sr_input_module **sr_input_list(void)
84 {
85         return input_module_list;
86 }
87
88 /**
89  * Returns the specified input module's ID.
90  *
91  * @since 0.4.0
92  */
93 SR_API const char *sr_input_id_get(const struct sr_input_module *o)
94 {
95         if (!o) {
96                 sr_err("Invalid input module NULL!");
97                 return NULL;
98         }
99
100         return o->id;
101 }
102
103 /**
104  * Returns the specified input module's name.
105  *
106  * @since 0.4.0
107  */
108 SR_API const char *sr_input_name_get(const struct sr_input_module *o)
109 {
110         if (!o) {
111                 sr_err("Invalid input module NULL!");
112                 return NULL;
113         }
114
115         return o->name;
116 }
117
118 /**
119  * Returns the specified input module's description.
120  *
121  * @since 0.4.0
122  */
123 SR_API const char *sr_input_description_get(const struct sr_input_module *o)
124 {
125         if (!o) {
126                 sr_err("Invalid input module NULL!");
127                 return NULL;
128         }
129
130         return o->desc;
131 }
132
133 /**
134  * Return the input module with the specified ID, or NULL if no module
135  * with that id is found.
136  *
137  * @since 0.4.0
138  */
139 SR_API const struct sr_input_module *sr_input_find(char *id)
140 {
141         int i;
142
143         for (i = 0; input_module_list[i]; i++) {
144                 if (!strcmp(input_module_list[i]->id, id))
145                         return input_module_list[i];
146         }
147
148         return NULL;
149 }
150
151 /**
152  * Returns a NULL-terminated array of struct sr_option, or NULL if the
153  * module takes no options.
154  *
155  * Each call to this function must be followed by a call to
156  * sr_input_options_free().
157  *
158  * @since 0.4.0
159  */
160 SR_API const struct sr_option **sr_input_options_get(const struct sr_input_module *imod)
161 {
162         const struct sr_option *mod_opts, **opts;
163         int size, i;
164
165         if (!imod || !imod->options)
166                 return NULL;
167
168         mod_opts = imod->options();
169
170         for (size = 0; mod_opts[size].id; size++)
171                 ;
172         opts = g_malloc((size + 1) * sizeof(struct sr_option *));
173
174         for (i = 0; i < size; i++)
175                 opts[i] = &mod_opts[i];
176         opts[i] = NULL;
177
178         return opts;
179 }
180
181 /**
182  * After a call to sr_input_options_get(), this function cleans up all
183  * resources returned by that call.
184  *
185  * @since 0.4.0
186  */
187 SR_API void sr_input_options_free(const struct sr_option **options)
188 {
189         int i;
190
191         if (!options)
192                 return;
193
194         for (i = 0; options[i]; i++) {
195                 if (options[i]->def) {
196                         g_variant_unref(options[i]->def);
197                         ((struct sr_option *)options[i])->def = NULL;
198                 }
199
200                 if (options[i]->values) {
201                         g_slist_free_full(options[i]->values, (GDestroyNotify)g_variant_unref);
202                         ((struct sr_option *)options[i])->values = NULL;
203                 }
204         }
205         g_free(options);
206 }
207
208 /**
209  * Create a new input instance using the specified input module.
210  *
211  * This function is used when a client wants to use a specific input
212  * module to parse a stream. No effort is made to identify the format.
213  *
214  * @param options GHashTable consisting of keys corresponding with
215  * the module options \c id field. The values should be GVariant
216  * pointers with sunk references, of the same GVariantType as the option's
217  * default value.
218  *
219  * @since 0.4.0
220  */
221 SR_API struct sr_input *sr_input_new(const struct sr_input_module *imod,
222                 GHashTable *options)
223 {
224         struct sr_input *in;
225         struct sr_option *mod_opts;
226         const GVariantType *gvt;
227         GHashTable *new_opts;
228         GHashTableIter iter;
229         gpointer key, value;
230         int i;
231
232         in = g_malloc0(sizeof(struct sr_input));
233         in->module = imod;
234
235         new_opts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
236                         (GDestroyNotify)g_variant_unref);
237         if (imod->options) {
238                 mod_opts = imod->options();
239                 for (i = 0; mod_opts[i].id; i++) {
240                         if (options && g_hash_table_lookup_extended(options,
241                                         mod_opts[i].id, &key, &value)) {
242                                 /* Option not given: insert the default value. */
243                                 gvt = g_variant_get_type(mod_opts[i].def);
244                                 if (!g_variant_is_of_type(value, gvt)) {
245                                         sr_err("Invalid type for '%s' option.", key);
246                                         g_free(in);
247                                         return NULL;
248                                 }
249                                 g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
250                                                 g_variant_ref(value));
251                         } else {
252                                 /* Pass option along. */
253                                 g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
254                                                 g_variant_ref(mod_opts[i].def));
255                         }
256                 }
257
258                 /* Make sure no invalid options were given. */
259                 if (options) {
260                         g_hash_table_iter_init(&iter, options);
261                         while (g_hash_table_iter_next(&iter, &key, &value)) {
262                                 if (!g_hash_table_lookup(new_opts, key)) {
263                                         sr_err("Input module '%s' has no option '%s'", imod->id, key);
264                                         g_hash_table_destroy(new_opts);
265                                         g_free(in);
266                                         return NULL;
267                                 }
268                         }
269                 }
270         }
271
272         if (in->module->init && in->module->init(in, new_opts) != SR_OK) {
273                 g_hash_table_destroy(new_opts);
274                 g_free(in);
275                 in = NULL;
276         }
277         if (new_opts)
278                 g_hash_table_destroy(new_opts);
279
280         return in;
281 }
282
283 /* Returns TRUE is all required meta items are available. */
284 static gboolean check_required_metadata(const uint8_t *metadata, uint8_t *avail)
285 {
286         int m, a;
287         uint8_t reqd;
288
289         for (m = 0; metadata[m]; m++) {
290                 if (!(metadata[m] & SR_INPUT_META_REQUIRED))
291                         continue;
292                 reqd = metadata[m] & ~SR_INPUT_META_REQUIRED;
293                 for (a = 0; avail[a]; a++) {
294                         if (avail[a] == reqd)
295                                 break;
296                 }
297                 if (!avail[a])
298                         /* Found a required meta item that isn't available. */
299                         return FALSE;
300         }
301
302         return TRUE;
303 }
304
305 /**
306  * Try to find an input module that can parse the given buffer.
307  *
308  * The buffer must contain enough of the beginning of the file for
309  * the input modules to find a match. This is format-dependent, but
310  * 128 bytes is normally enough.
311  *
312  * If an input module is found, an instance is created and returned.
313  * Otherwise, NULL is returned.
314  *
315  */
316 SR_API const struct sr_input *sr_input_scan_buffer(GString *buf)
317 {
318         struct sr_input *in;
319         const struct sr_input_module *imod;
320         GHashTable *meta;
321         unsigned int m, i;
322         uint8_t mitem, avail_metadata[8];
323
324         /* No more metadata to be had from a buffer. */
325         avail_metadata[0] = SR_INPUT_META_HEADER;
326         avail_metadata[1] = 0;
327
328         in = NULL;
329         for (i = 0; input_module_list[i]; i++) {
330                 imod = input_module_list[i];
331                 if (!imod->metadata[0]) {
332                         /* Module has no metadata for matching so will take
333                          * any input. No point in letting it try to match. */
334                         continue;
335                 }
336                 if (!check_required_metadata(imod->metadata, avail_metadata))
337                         /* Cannot satisfy this module's requirements. */
338                         continue;
339
340                 meta = g_hash_table_new(NULL, NULL);
341                 for (m = 0; m < sizeof(imod->metadata); m++) {
342                         mitem = imod->metadata[m] & ~SR_INPUT_META_REQUIRED;
343                         if (mitem == SR_INPUT_META_HEADER)
344                                 g_hash_table_insert(meta, GINT_TO_POINTER(mitem), buf);
345                 }
346                 if (g_hash_table_size(meta) == 0) {
347                         /* No metadata for this module, so nothing to match. */
348                         g_hash_table_destroy(meta);
349                         continue;
350                 }
351                 if (!imod->format_match(meta)) {
352                         /* Module didn't recognize this buffer. */
353                         g_hash_table_destroy(meta);
354                         continue;
355                 }
356                 g_hash_table_destroy(meta);
357
358                 /* Found a matching module. */
359                 in = sr_input_new(imod, NULL);
360                 in->buf = g_string_new_len(buf->str, buf->len);
361                 break;
362         }
363
364         return in;
365 }
366
367 /**
368  * Try to find an input module that can parse the given file.
369  *
370  * If an input module is found, an instance is created and returned.
371  * Otherwise, NULL is returned.
372  *
373  */
374 SR_API const struct sr_input *sr_input_scan_file(const char *filename)
375 {
376         struct sr_input *in;
377         const struct sr_input_module *imod;
378         GHashTable *meta;
379         GString *buf;
380         struct stat st;
381         unsigned int midx, m, i;
382         int fd;
383         ssize_t size;
384         uint8_t mitem, avail_metadata[8];
385
386         if (!filename || !filename[0]) {
387                 sr_err("Invalid filename.");
388                 return NULL;
389         }
390
391         if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
392                 sr_err("No such file.");
393                 return NULL;
394         }
395
396         if (stat(filename, &st) < 0) {
397                 sr_err("%s", strerror(errno));
398                 return NULL;
399         }
400
401         midx = 0;
402         avail_metadata[midx++] = SR_INPUT_META_FILENAME;
403         avail_metadata[midx++] = SR_INPUT_META_FILESIZE;
404         avail_metadata[midx++] = SR_INPUT_META_HEADER;
405         /* TODO: MIME type */
406
407         in = NULL;
408         buf = NULL;
409         for (i = 0; input_module_list[i]; i++) {
410                 imod = input_module_list[i];
411                 if (!imod->metadata[0]) {
412                         /* Module has no metadata for matching so will take
413                          * any input. No point in letting it try to match. */
414                         continue;
415                 }
416                 if (!check_required_metadata(imod->metadata, avail_metadata))
417                         /* Cannot satisfy this module's requirements. */
418                         continue;
419
420                 meta = g_hash_table_new(NULL, NULL);
421                 for (m = 0; m < sizeof(imod->metadata); m++) {
422                         mitem = imod->metadata[m] & ~SR_INPUT_META_REQUIRED;
423                         if (mitem == SR_INPUT_META_FILENAME)
424                                 g_hash_table_insert(meta, GINT_TO_POINTER(mitem),
425                                                 (gpointer)filename);
426                         else if (mitem == SR_INPUT_META_FILESIZE)
427                                 g_hash_table_insert(meta, GINT_TO_POINTER(mitem),
428                                                 GINT_TO_POINTER(st.st_size));
429                         else if (mitem == SR_INPUT_META_HEADER) {
430                                 buf = g_string_sized_new(128);
431                                 if ((fd = open(filename, O_RDONLY)) < 0) {
432                                         sr_err("%s", strerror(errno));
433                                         return NULL;
434                                 }
435                                 size = read(fd, buf->str, 128);
436                                 buf->len = size;
437                                 close(fd);
438                                 if (size <= 0) {
439                                         g_string_free(buf, TRUE);
440                                         sr_err("%s", strerror(errno));
441                                         return NULL;
442                                 }
443                                 g_hash_table_insert(meta, GINT_TO_POINTER(mitem), buf);
444                                 g_string_free(buf, TRUE);
445                         }
446                 }
447                 if (g_hash_table_size(meta) == 0) {
448                         /* No metadata for this module, so there's no way it
449                          * can match. */
450                         g_hash_table_destroy(meta);
451                         continue;
452                 }
453                 if (!imod->format_match(meta))
454                         /* Module didn't recognize this buffer. */
455                         continue;
456
457                 /* Found a matching module. */
458                 in = sr_input_new(imod, NULL);
459                 in->buf = g_string_new_len(buf->str, buf->len);
460                 break;
461         }
462         if (!in && buf)
463                 g_string_free(buf, TRUE);
464
465         return in;
466 }
467
468 /**
469  * Return the input instance's (virtual) device instance. This can be
470  * used to find out the number of channels and other information.
471  *
472  * @since 0.4.0
473  */
474 SR_API struct sr_dev_inst *sr_input_dev_inst_get(const struct sr_input *in)
475 {
476         return in->sdi;
477 }
478
479 /**
480  * Send data to the specified input instance.
481  *
482  * When an input module instance is created with sr_input_new(), this
483  * function is used to feed data to the instance.
484  *
485  * @since 0.4.0
486  */
487 SR_API int sr_input_send(const struct sr_input *in, GString *buf)
488 {
489         return in->module->receive(in, buf);
490 }
491
492 /**
493  * Free the specified input instance and all associated resources.
494  *
495  * @since 0.4.0
496  */
497 SR_API int sr_input_free(const struct sr_input *in)
498 {
499         int ret;
500
501         if (!in)
502                 return SR_ERR_ARG;
503
504         ret = SR_OK;
505         if (in->module->cleanup)
506                 ret = in->module->cleanup((struct sr_input *)in);
507         if (in->sdi)
508                 sr_dev_inst_free(in->sdi);
509         if (in->buf)
510                 g_string_free(in->buf, TRUE);
511         g_free((gpointer)in);
512
513         return ret;
514 }
515
516
517 /** @} */