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