]> sigrok.org Git - libsigrok.git/blob - src/input/input.c
input: Frontends don't need to see SR_INPUT_META_*.
[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 *o)
161 {
162
163         if (!o || !o->options)
164                 return NULL;
165
166         return o->options();
167 }
168
169 /**
170  * After a call to sr_input_options_get(), this function cleans up all
171  * resources allocated by that call.
172  *
173  * @since 0.4.0
174  */
175 SR_API void sr_input_options_free(const struct sr_input_module *o)
176 {
177         struct sr_option *opt;
178
179         if (!o || !o->options)
180                 return;
181
182         for (opt = o->options(); opt->id; opt++) {
183                 if (opt->def) {
184                         g_variant_unref(opt->def);
185                         opt->def = NULL;
186                 }
187
188                 if (opt->values) {
189                         g_slist_free_full(opt->values, (GDestroyNotify)g_variant_unref);
190                         opt->values = NULL;
191                 }
192         }
193 }
194
195 /**
196  * Create a new input instance using the specified input module.
197  *
198  * This function is used when a client wants to use a specific input
199  * module to parse a stream. No effort is made to identify the format.
200  *
201  * @param options GHashTable consisting of keys corresponding with
202  * the module options \c id field. The values should be GVariant
203  * pointers with sunk references, of the same GVariantType as the option's
204  * default value.
205  *
206  * @since 0.4.0
207  */
208 SR_API struct sr_input *sr_input_new(const struct sr_input_module *imod,
209                 GHashTable *options)
210 {
211         struct sr_input *in;
212         struct sr_option *mod_opts;
213         const GVariantType *gvt;
214         GHashTable *new_opts;
215         GHashTableIter iter;
216         gpointer key, value;
217         int i;
218
219         in = g_malloc0(sizeof(struct sr_input));
220         in->module = imod;
221
222         new_opts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
223                         (GDestroyNotify)g_variant_unref);
224         if (imod->options) {
225                 mod_opts = imod->options();
226                 for (i = 0; mod_opts[i].id; i++) {
227                         if (options && g_hash_table_lookup_extended(options,
228                                         mod_opts[i].id, &key, &value)) {
229                                 /* Option not given: insert the default value. */
230                                 gvt = g_variant_get_type(mod_opts[i].def);
231                                 if (!g_variant_is_of_type(value, gvt)) {
232                                         sr_err("Invalid type for '%s' option.", key);
233                                         g_free(in);
234                                         return NULL;
235                                 }
236                                 g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
237                                                 g_variant_ref(value));
238                         } else {
239                                 /* Pass option along. */
240                                 g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
241                                                 g_variant_ref(mod_opts[i].def));
242                         }
243                 }
244
245                 /* Make sure no invalid options were given. */
246                 if (options) {
247                         g_hash_table_iter_init(&iter, options);
248                         while (g_hash_table_iter_next(&iter, &key, &value)) {
249                                 if (!g_hash_table_lookup(new_opts, key)) {
250                                         sr_err("Input module '%s' has no option '%s'", imod->id, key);
251                                         g_hash_table_destroy(new_opts);
252                                         g_free(in);
253                                         return NULL;
254                                 }
255                         }
256                 }
257         }
258
259         if (in->module->init && in->module->init(in, new_opts) != SR_OK) {
260                 g_hash_table_destroy(new_opts);
261                 g_free(in);
262                 in = NULL;
263         }
264         if (new_opts)
265                 g_hash_table_destroy(new_opts);
266
267         return in;
268 }
269
270 /* Returns TRUE is all required meta items are available. */
271 static gboolean check_required_metadata(const uint8_t *metadata, uint8_t *avail)
272 {
273         int m, a;
274         uint8_t reqd;
275
276         for (m = 0; metadata[m]; m++) {
277                 if (!(metadata[m] & SR_INPUT_META_REQUIRED))
278                         continue;
279                 reqd = metadata[m] & ~SR_INPUT_META_REQUIRED;
280                 for (a = 0; avail[a]; a++) {
281                         if (avail[a] == reqd)
282                                 break;
283                 }
284                 if (!avail[a])
285                         /* Found a required meta item that isn't available. */
286                         return FALSE;
287         }
288
289         return TRUE;
290 }
291
292 /**
293  * Try to find an input module that can parse the given buffer.
294  *
295  * The buffer must contain enough of the beginning of the file for
296  * the input modules to find a match. This is format-dependent, but
297  * 128 bytes is normally enough.
298  *
299  * If an input module is found, an instance is created and returned.
300  * Otherwise, NULL is returned.
301  *
302  */
303 SR_API const struct sr_input *sr_input_scan_buffer(GString *buf)
304 {
305         struct sr_input *in;
306         const struct sr_input_module *imod;
307         GHashTable *meta;
308         unsigned int m, i;
309         uint8_t mitem, avail_metadata[8];
310
311         /* No more metadata to be had from a buffer. */
312         avail_metadata[0] = SR_INPUT_META_HEADER;
313         avail_metadata[1] = 0;
314
315         in = NULL;
316         for (i = 0; input_module_list[i]; i++) {
317                 imod = input_module_list[i];
318                 if (!imod->metadata[0]) {
319                         /* Module has no metadata for matching so will take
320                          * any input. No point in letting it try to match. */
321                         continue;
322                 }
323                 if (!check_required_metadata(imod->metadata, avail_metadata))
324                         /* Cannot satisfy this module's requirements. */
325                         continue;
326
327                 meta = g_hash_table_new(NULL, NULL);
328                 for (m = 0; m < sizeof(imod->metadata); m++) {
329                         mitem = imod->metadata[m] & ~SR_INPUT_META_REQUIRED;
330                         if (mitem == SR_INPUT_META_HEADER)
331                                 g_hash_table_insert(meta, GINT_TO_POINTER(mitem), buf);
332                 }
333                 if (g_hash_table_size(meta) == 0) {
334                         /* No metadata for this module, so nothing to match. */
335                         g_hash_table_destroy(meta);
336                         continue;
337                 }
338                 if (!imod->format_match(meta)) {
339                         /* Module didn't recognize this buffer. */
340                         g_hash_table_destroy(meta);
341                         continue;
342                 }
343                 g_hash_table_destroy(meta);
344
345                 /* Found a matching module. */
346                 in = sr_input_new(imod, NULL);
347                 in->buf = g_string_new_len(buf->str, buf->len);
348                 break;
349         }
350
351         return in;
352 }
353
354 /**
355  * Try to find an input module that can parse the given file.
356  *
357  * If an input module is found, an instance is created and returned.
358  * Otherwise, NULL is returned.
359  *
360  */
361 SR_API const struct sr_input *sr_input_scan_file(const char *filename)
362 {
363         struct sr_input *in;
364         const struct sr_input_module *imod;
365         GHashTable *meta;
366         GString *buf;
367         struct stat st;
368         unsigned int midx, m, i;
369         int fd;
370         ssize_t size;
371         uint8_t mitem, avail_metadata[8];
372
373         if (!filename || !filename[0]) {
374                 sr_err("Invalid filename.");
375                 return NULL;
376         }
377
378         if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
379                 sr_err("No such file.");
380                 return NULL;
381         }
382
383         if (stat(filename, &st) < 0) {
384                 sr_err("%s", strerror(errno));
385                 return NULL;
386         }
387
388         midx = 0;
389         avail_metadata[midx++] = SR_INPUT_META_FILENAME;
390         avail_metadata[midx++] = SR_INPUT_META_FILESIZE;
391         avail_metadata[midx++] = SR_INPUT_META_HEADER;
392         /* TODO: MIME type */
393
394         in = NULL;
395         buf = NULL;
396         for (i = 0; input_module_list[i]; i++) {
397                 imod = input_module_list[i];
398                 if (!imod->metadata[0]) {
399                         /* Module has no metadata for matching so will take
400                          * any input. No point in letting it try to match. */
401                         continue;
402                 }
403                 if (!check_required_metadata(imod->metadata, avail_metadata))
404                         /* Cannot satisfy this module's requirements. */
405                         continue;
406
407                 meta = g_hash_table_new(NULL, NULL);
408                 for (m = 0; m < sizeof(imod->metadata); m++) {
409                         mitem = imod->metadata[m] & ~SR_INPUT_META_REQUIRED;
410                         if (mitem == SR_INPUT_META_FILENAME)
411                                 g_hash_table_insert(meta, GINT_TO_POINTER(mitem),
412                                                 (gpointer)filename);
413                         else if (mitem == SR_INPUT_META_FILESIZE)
414                                 g_hash_table_insert(meta, GINT_TO_POINTER(mitem),
415                                                 GINT_TO_POINTER(st.st_size));
416                         else if (mitem == SR_INPUT_META_HEADER) {
417                                 buf = g_string_sized_new(128);
418                                 if ((fd = open(filename, O_RDONLY)) < 0) {
419                                         sr_err("%s", strerror(errno));
420                                         return NULL;
421                                 }
422                                 size = read(fd, buf->str, 128);
423                                 buf->len = size;
424                                 close(fd);
425                                 if (size <= 0) {
426                                         g_string_free(buf, TRUE);
427                                         sr_err("%s", strerror(errno));
428                                         return NULL;
429                                 }
430                                 g_hash_table_insert(meta, GINT_TO_POINTER(mitem), buf);
431                                 g_string_free(buf, TRUE);
432                         }
433                 }
434                 if (g_hash_table_size(meta) == 0) {
435                         /* No metadata for this module, so there's no way it
436                          * can match. */
437                         g_hash_table_destroy(meta);
438                         continue;
439                 }
440                 if (!imod->format_match(meta))
441                         /* Module didn't recognize this buffer. */
442                         continue;
443
444                 /* Found a matching module. */
445                 in = sr_input_new(imod, NULL);
446                 in->buf = g_string_new_len(buf->str, buf->len);
447                 break;
448         }
449         if (!in && buf)
450                 g_string_free(buf, TRUE);
451
452         return in;
453 }
454
455 /**
456  * Return the input instance's (virtual) device instance. This can be
457  * used to find out the number of channels and other information.
458  *
459  * @since 0.4.0
460  */
461 SR_API struct sr_dev_inst *sr_input_dev_inst_get(const struct sr_input *in)
462 {
463         return in->sdi;
464 }
465
466 /**
467  * Send data to the specified input instance.
468  *
469  * When an input module instance is created with sr_input_new(), this
470  * function is used to feed data to the instance.
471  *
472  * @since 0.4.0
473  */
474 SR_API int sr_input_send(const struct sr_input *in, GString *buf)
475 {
476         return in->module->receive(in, buf);
477 }
478
479 /**
480  * Free the specified input instance and all associated resources.
481  *
482  * @since 0.4.0
483  */
484 SR_API int sr_input_free(const struct sr_input *in)
485 {
486         int ret;
487
488         if (!in)
489                 return SR_ERR_ARG;
490
491         ret = SR_OK;
492         if (in->module->cleanup)
493                 ret = in->module->cleanup((struct sr_input *)in);
494         if (in->sdi)
495                 sr_dev_inst_free(in->sdi);
496         if (in->buf)
497                 g_string_free(in->buf, TRUE);
498         g_free((gpointer)in);
499
500         return ret;
501 }
502
503
504 /** @} */