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