]> sigrok.org Git - libsigrok.git/blob - src/input/input.c
2b5e3afbd8bae0f26018cd0a42cadc857fad0287
[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_binary,
70         &input_chronovu_la8,
71         &input_csv,
72         &input_vcd,
73         &input_wav,
74         NULL,
75 };
76
77 /**
78  * Returns a NULL-terminated list of all available input modules.
79  *
80  * @since 0.4.0
81  */
82 SR_API const struct sr_input_module **sr_input_list(void)
83 {
84         return input_module_list;
85 }
86
87 /**
88  * Returns the specified input module's ID.
89  *
90  * @since 0.4.0
91  */
92 SR_API const char *sr_input_id_get(const struct sr_input_module *imod)
93 {
94         if (!imod) {
95                 sr_err("Invalid input module NULL!");
96                 return NULL;
97         }
98
99         return imod->id;
100 }
101
102 /**
103  * Returns the specified input module's name.
104  *
105  * @since 0.4.0
106  */
107 SR_API const char *sr_input_name_get(const struct sr_input_module *imod)
108 {
109         if (!imod) {
110                 sr_err("Invalid input module NULL!");
111                 return NULL;
112         }
113
114         return imod->name;
115 }
116
117 /**
118  * Returns the specified input module's description.
119  *
120  * @since 0.4.0
121  */
122 SR_API const char *sr_input_description_get(const struct sr_input_module *imod)
123 {
124         if (!imod) {
125                 sr_err("Invalid input module NULL!");
126                 return NULL;
127         }
128
129         return imod->desc;
130 }
131
132 /**
133  * Returns the specified input module's file extensions typical for the file
134  * format, as a NULL terminated array, or returns a NULL pointer if there is
135  * no preferred extension.
136  * @note these are a suggestions only.
137  *
138  * @since 0.4.0
139  */
140 SR_API const char *const *sr_input_extensions_get(
141                 const struct sr_input_module *imod)
142 {
143         if (!imod) {
144                 sr_err("Invalid input module NULL!");
145                 return NULL;
146         }
147
148         return imod->exts;
149 }
150
151 /**
152  * Return the input module with the specified ID, or NULL if no module
153  * with that id is found.
154  *
155  * @since 0.4.0
156  */
157 SR_API const struct sr_input_module *sr_input_find(char *id)
158 {
159         int i;
160
161         for (i = 0; input_module_list[i]; i++) {
162                 if (!strcmp(input_module_list[i]->id, id))
163                         return input_module_list[i];
164         }
165
166         return NULL;
167 }
168
169 /**
170  * Returns a NULL-terminated array of struct sr_option, or NULL if the
171  * module takes no options.
172  *
173  * Each call to this function must be followed by a call to
174  * sr_input_options_free().
175  *
176  * @since 0.4.0
177  */
178 SR_API const struct sr_option **sr_input_options_get(const struct sr_input_module *imod)
179 {
180         const struct sr_option *mod_opts, **opts;
181         int size, i;
182
183         if (!imod || !imod->options)
184                 return NULL;
185
186         mod_opts = imod->options();
187
188         for (size = 0; mod_opts[size].id; size++)
189                 ;
190         opts = g_malloc((size + 1) * sizeof(struct sr_option *));
191
192         for (i = 0; i < size; i++)
193                 opts[i] = &mod_opts[i];
194         opts[i] = NULL;
195
196         return opts;
197 }
198
199 /**
200  * After a call to sr_input_options_get(), this function cleans up all
201  * resources returned by that call.
202  *
203  * @since 0.4.0
204  */
205 SR_API void sr_input_options_free(const struct sr_option **options)
206 {
207         int i;
208
209         if (!options)
210                 return;
211
212         for (i = 0; options[i]; i++) {
213                 if (options[i]->def) {
214                         g_variant_unref(options[i]->def);
215                         ((struct sr_option *)options[i])->def = NULL;
216                 }
217
218                 if (options[i]->values) {
219                         g_slist_free_full(options[i]->values, (GDestroyNotify)g_variant_unref);
220                         ((struct sr_option *)options[i])->values = NULL;
221                 }
222         }
223         g_free(options);
224 }
225
226 /**
227  * Create a new input instance using the specified input module.
228  *
229  * This function is used when a client wants to use a specific input
230  * module to parse a stream. No effort is made to identify the format.
231  *
232  * @param imod The input module to use. Must not be NULL.
233  * @param options GHashTable consisting of keys corresponding with
234  * the module options \c id field. The values should be GVariant
235  * pointers with sunk references, of the same GVariantType as the option's
236  * default value.
237  *
238  * @since 0.4.0
239  */
240 SR_API struct sr_input *sr_input_new(const struct sr_input_module *imod,
241                 GHashTable *options)
242 {
243         struct sr_input *in;
244         struct sr_option *mod_opts;
245         const GVariantType *gvt;
246         GHashTable *new_opts;
247         GHashTableIter iter;
248         gpointer key, value;
249         int i;
250
251         in = g_malloc0(sizeof(struct sr_input));
252         in->module = imod;
253
254         new_opts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
255                         (GDestroyNotify)g_variant_unref);
256         if (imod->options) {
257                 mod_opts = imod->options();
258                 for (i = 0; mod_opts[i].id; i++) {
259                         if (options && g_hash_table_lookup_extended(options,
260                                         mod_opts[i].id, &key, &value)) {
261                                 /* Option not given: insert the default value. */
262                                 gvt = g_variant_get_type(mod_opts[i].def);
263                                 if (!g_variant_is_of_type(value, gvt)) {
264                                         sr_err("Invalid type for '%s' option.", key);
265                                         g_free(in);
266                                         return NULL;
267                                 }
268                                 g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
269                                                 g_variant_ref(value));
270                         } else {
271                                 /* Pass option along. */
272                                 g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
273                                                 g_variant_ref(mod_opts[i].def));
274                         }
275                 }
276
277                 /* Make sure no invalid options were given. */
278                 if (options) {
279                         g_hash_table_iter_init(&iter, options);
280                         while (g_hash_table_iter_next(&iter, &key, &value)) {
281                                 if (!g_hash_table_lookup(new_opts, key)) {
282                                         sr_err("Input module '%s' has no option '%s'", imod->id, key);
283                                         g_hash_table_destroy(new_opts);
284                                         g_free(in);
285                                         return NULL;
286                                 }
287                         }
288                 }
289         }
290
291         if (in->module->init && in->module->init(in, new_opts) != SR_OK) {
292                 g_free(in);
293                 in = NULL;
294         } else {
295                 in->buf = g_string_sized_new(128);
296         }
297
298         if (new_opts)
299                 g_hash_table_destroy(new_opts);
300
301         return in;
302 }
303
304 /* Returns TRUE if all required meta items are available. */
305 static gboolean check_required_metadata(const uint8_t *metadata, uint8_t *avail)
306 {
307         int m, a;
308         uint8_t reqd;
309
310         for (m = 0; metadata[m]; m++) {
311                 if (!(metadata[m] & SR_INPUT_META_REQUIRED))
312                         continue;
313                 reqd = metadata[m] & ~SR_INPUT_META_REQUIRED;
314                 for (a = 0; avail[a]; a++) {
315                         if (avail[a] == reqd)
316                                 break;
317                 }
318                 if (!avail[a])
319                         /* Found a required meta item that isn't available. */
320                         return FALSE;
321         }
322
323         return TRUE;
324 }
325
326 /**
327  * Try to find an input module that can parse the given buffer.
328  *
329  * The buffer must contain enough of the beginning of the file for
330  * the input modules to find a match. This is format-dependent, but
331  * 128 bytes is normally enough.
332  *
333  * If an input module is found, an instance is created into *in.
334  * Otherwise, *in contains NULL.
335  *
336  * If an instance is created, it has the given buffer used for scanning
337  * already submitted to it, to be processed before more data is sent.
338  * This allows a frontend to submit an initial chunk of a non-seekable
339  * stream, such as stdin, without having to keep it around and submit
340  * it again later.
341  *
342  */
343 SR_API int sr_input_scan_buffer(GString *buf, const struct sr_input **in)
344 {
345         const struct sr_input_module *imod;
346         GHashTable *meta;
347         unsigned int m, i;
348         int ret;
349         uint8_t mitem, avail_metadata[8];
350
351         /* No more metadata to be had from a buffer. */
352         avail_metadata[0] = SR_INPUT_META_HEADER;
353         avail_metadata[1] = 0;
354
355         *in = NULL;
356         ret = SR_ERR;
357         for (i = 0; input_module_list[i]; i++) {
358                 imod = input_module_list[i];
359                 if (!imod->metadata[0]) {
360                         /* Module has no metadata for matching so will take
361                          * any input. No point in letting it try to match. */
362                         continue;
363                 }
364                 if (!check_required_metadata(imod->metadata, avail_metadata))
365                         /* Cannot satisfy this module's requirements. */
366                         continue;
367
368                 meta = g_hash_table_new(NULL, NULL);
369                 for (m = 0; m < sizeof(imod->metadata); m++) {
370                         mitem = imod->metadata[m] & ~SR_INPUT_META_REQUIRED;
371                         if (mitem == SR_INPUT_META_HEADER)
372                                 g_hash_table_insert(meta, GINT_TO_POINTER(mitem), buf);
373                 }
374                 if (g_hash_table_size(meta) == 0) {
375                         /* No metadata for this module, so nothing to match. */
376                         g_hash_table_destroy(meta);
377                         continue;
378                 }
379                 sr_spew("Trying module %s.", imod->id);
380                 ret = imod->format_match(meta);
381                 g_hash_table_destroy(meta);
382                 if (ret == SR_ERR_DATA) {
383                         /* Module recognized this buffer, but cannot handle it. */
384                         break;
385                 } else if (ret == SR_ERR) {
386                         /* Module didn't recognize this buffer. */
387                         continue;
388                 } else if (ret != SR_OK) {
389                         /* Can be SR_ERR_NA. */
390                         return ret;
391                 }
392
393                 /* Found a matching module. */
394                 sr_spew("Module %s matched.", imod->id);
395                 *in = sr_input_new(imod, NULL);
396                 g_string_insert_len((*in)->buf, 0, buf->str, buf->len);
397                 break;
398         }
399
400         return ret;
401 }
402
403 /**
404  * Try to find an input module that can parse the given file.
405  *
406  * If an input module is found, an instance is created into *in.
407  * Otherwise, *in contains NULL.
408  *
409  */
410 SR_API int sr_input_scan_file(const char *filename, const struct sr_input **in)
411 {
412         const struct sr_input_module *imod;
413         GHashTable *meta;
414         GString *header_buf;
415         struct stat st;
416         unsigned int midx, m, i;
417         int fd, ret;
418         ssize_t size;
419         uint8_t mitem, avail_metadata[8];
420
421         if (!filename || !filename[0]) {
422                 sr_err("Invalid filename.");
423                 return SR_ERR_ARG;
424         }
425
426         if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
427                 sr_err("No such file.");
428                 return SR_ERR_ARG;
429         }
430
431         if (stat(filename, &st) < 0) {
432                 sr_err("%s", strerror(errno));
433                 return SR_ERR_ARG;
434         }
435
436         midx = 0;
437         avail_metadata[midx++] = SR_INPUT_META_FILENAME;
438         avail_metadata[midx++] = SR_INPUT_META_FILESIZE;
439         avail_metadata[midx++] = SR_INPUT_META_HEADER;
440         /* TODO: MIME type */
441
442         *in = NULL;
443         ret = SR_ERR;
444         header_buf = g_string_sized_new(128);
445         for (i = 0; input_module_list[i]; i++) {
446                 g_string_truncate(header_buf, 0);
447
448                 imod = input_module_list[i];
449                 if (!imod->metadata[0]) {
450                         /* Module has no metadata for matching so will take
451                          * any input. No point in letting it try to match. */
452                         continue;
453                 }
454                 if (!check_required_metadata(imod->metadata, avail_metadata))
455                         /* Cannot satisfy this module's requirements. */
456                         continue;
457
458                 meta = g_hash_table_new(NULL, NULL);
459                 for (m = 0; m < sizeof(imod->metadata); m++) {
460                         mitem = imod->metadata[m] & ~SR_INPUT_META_REQUIRED;
461                         if (!mitem)
462                                 /* Metadata list is 0-terminated. */
463                                 break;
464                         if (mitem == SR_INPUT_META_FILENAME) {
465                                 g_hash_table_insert(meta, GINT_TO_POINTER(mitem),
466                                                 (gpointer)filename);
467                         } else if (mitem == SR_INPUT_META_FILESIZE) {
468                                 g_hash_table_insert(meta, GINT_TO_POINTER(mitem),
469                                                 GINT_TO_POINTER(st.st_size));
470                         } else if (mitem == SR_INPUT_META_HEADER) {
471                                 if ((fd = open(filename, O_RDONLY)) < 0) {
472                                         sr_err("%s", strerror(errno));
473                                         return SR_ERR;
474                                 }
475                                 size = read(fd, header_buf->str, 128);
476                                 header_buf->len = size;
477                                 close(fd);
478                                 if (size <= 0) {
479                                         g_string_free(header_buf, TRUE);
480                                         sr_err("%s", strerror(errno));
481                                         return SR_ERR;
482                                 }
483                                 g_hash_table_insert(meta, GINT_TO_POINTER(mitem), header_buf);
484                         }
485                 }
486                 if (g_hash_table_size(meta) == 0) {
487                         /* No metadata for this module, so there's no way it
488                          * can match. */
489                         g_hash_table_destroy(meta);
490                         continue;
491                 }
492                 sr_spew("Trying module %s.", imod->id);
493                 ret = imod->format_match(meta);
494                 g_hash_table_destroy(meta);
495                 if (ret == SR_ERR_DATA) {
496                         /* Module recognized this buffer, but cannot handle it. */
497                         break;
498                 } else if (ret == SR_ERR) {
499                         /* Module didn't recognize this buffer. */
500                         continue;
501                 } else if (ret != SR_OK) {
502                         /* Can be SR_ERR_NA. */
503                         return ret;
504                 }
505
506                 /* Found a matching module. */
507                 sr_spew("Module %s matched.", imod->id);
508                 *in = sr_input_new(imod, NULL);
509                 break;
510         }
511         g_string_free(header_buf, TRUE);
512
513         return ret;
514 }
515
516 /**
517  * Return the input instance's (virtual) device instance. This can be
518  * used to find out the number of channels and other information.
519  *
520  * If the device instance has not yet been fully populated by the input
521  * module, NULL is returned. This indicates the module needs more data
522  * to identify the number of channels and so on.
523  *
524  * @since 0.4.0
525  */
526 SR_API struct sr_dev_inst *sr_input_dev_inst_get(const struct sr_input *in)
527 {
528         if (in->sdi_ready)
529                 return in->sdi;
530         else
531                 return NULL;
532 }
533
534 /**
535  * Send data to the specified input instance.
536  *
537  * When an input module instance is created with sr_input_new(), this
538  * function is used to feed data to the instance.
539  *
540  * As enough data gets fed into this function to completely populate
541  * the device instance associated with this input instance, this is
542  * guaranteed to return the moment it's ready. This gives the caller
543  * the chance to examine the device instance, attach session callbacks
544  * and so on.
545  *
546  * @since 0.4.0
547  */
548 SR_API int sr_input_send(const struct sr_input *in, GString *buf)
549 {
550         sr_spew("Sending %d bytes to %s module.", buf->len, in->module->id);
551         return in->module->receive((struct sr_input *)in, buf);
552 }
553
554 /**
555  * Signal the input module no more data will come.
556  *
557  * This will cause the module to process any data it may have buffered.
558  * The SR_DF_END packet will also typically be sent at this time.
559  *
560  * @since 0.4.0
561  */
562 SR_API int sr_input_end(const struct sr_input *in)
563 {
564         sr_spew("Calling end() on %s module.", in->module->id);
565         return in->module->end((struct sr_input *)in);
566 }
567
568 /**
569  * Free the specified input instance and all associated resources.
570  *
571  * @since 0.4.0
572  */
573 SR_API void sr_input_free(const struct sr_input *in)
574 {
575         if (!in)
576                 return;
577
578         if (in->module->cleanup)
579                 in->module->cleanup((struct sr_input *)in);
580         if (in->sdi)
581                 sr_dev_inst_free(in->sdi);
582         if (in->buf->len > 64) {
583                 /* That seems more than just some sub-unitsize leftover... */
584                 sr_warn("Found %d unprocessed bytes at free time.", in->buf->len);
585         }
586         g_string_free(in->buf, TRUE);
587         g_free(in->priv);
588         g_free((gpointer)in);
589 }
590
591
592 /** @} */