]> sigrok.org Git - libsigrok.git/blob - src/std.c
d1e2eedf784289eeaf72323e608a84ba99956ab2
[libsigrok.git] / src / std.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2013 Uwe Hermann <uwe@hermann-uwe.de>
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 2 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 /**
21  * @file
22  *
23  * Standard API helper functions.
24  */
25
26 /* Needed for gettimeofday(), at least on FreeBSD. */
27 #define _XOPEN_SOURCE 700
28
29 #include <config.h>
30 #include <string.h>
31 #include <math.h>
32 #include <sys/time.h>
33 #include <glib.h>
34 #include <libsigrok/libsigrok.h>
35 #include "libsigrok-internal.h"
36 #include "scpi.h"
37
38 #define LOG_PREFIX "std"
39
40 SR_PRIV const uint32_t NO_OPTS[1] = {};
41
42 /**
43  * Standard driver init() callback API helper.
44  *
45  * This function can be used to simplify most driver's init() API callback.
46  *
47  * Create a new 'struct drv_context' (drvc), assign sr_ctx to it, and
48  * then assign 'drvc' to the 'struct sr_dev_driver' (di) that is passed.
49  *
50  * @param[in] di The driver instance to use. Must not be NULL.
51  * @param[in] sr_ctx The libsigrok context to assign. May be NULL.
52  *
53  * @retval SR_OK Success.
54  * @retval SR_ERR_ARG Invalid argument.
55  */
56 SR_PRIV int std_init(struct sr_dev_driver *di, struct sr_context *sr_ctx)
57 {
58         struct drv_context *drvc;
59
60         if (!di) {
61                 sr_err("%s: Invalid argument.", __func__);
62                 return SR_ERR_ARG;
63         }
64
65         drvc = g_malloc0(sizeof(struct drv_context));
66         drvc->sr_ctx = sr_ctx;
67         drvc->instances = NULL;
68         di->context = drvc;
69
70         return SR_OK;
71 }
72
73 /**
74  * Standard driver cleanup() callback API helper.
75  *
76  * This function can be used to simplify most driver's cleanup() API callback.
77  *
78  * Free all device instances by calling sr_dev_clear() and then release any
79  * resources allocated by std_init().
80  *
81  * @param[in] di The driver instance to use. Must not be NULL.
82  *
83  * @retval SR_OK Success.
84  * @retval SR_ERR_ARG Invalid argument.
85  * @retval other Other error.
86  */
87 SR_PRIV int std_cleanup(const struct sr_dev_driver *di)
88 {
89         int ret;
90
91         if (!di) {
92                 sr_err("%s: Invalid argument.", __func__);
93                 return SR_ERR_ARG;
94         }
95
96         ret = sr_dev_clear(di);
97         g_free(di->context);
98
99         return ret;
100 }
101
102 /**
103  * Dummmy driver dev_open() callback API helper.
104  *
105  * @param[in] sdi The device instance to use. May be NULL (unused).
106  *
107  * @retval SR_OK Success.
108  */
109 SR_PRIV int std_dummy_dev_open(struct sr_dev_inst *sdi)
110 {
111         (void)sdi;
112
113         return SR_OK;
114 }
115
116 /**
117  * Dummmy driver dev_close() callback API helper.
118  *
119  * @param[in] sdi The device instance to use. May be NULL (unused).
120  *
121  * @retval SR_OK Success.
122  */
123 SR_PRIV int std_dummy_dev_close(struct sr_dev_inst *sdi)
124 {
125         (void)sdi;
126
127         return SR_OK;
128 }
129
130 /**
131  * Dummmy driver dev_acquisition_start() callback API helper.
132  *
133  * @param[in] sdi The device instance to use. May be NULL (unused).
134  *
135  * @retval SR_OK Success.
136  */
137 SR_PRIV int std_dummy_dev_acquisition_start(const struct sr_dev_inst *sdi)
138 {
139         (void)sdi;
140
141         return SR_OK;
142 }
143
144 /**
145  * Dummmy driver dev_acquisition_stop() callback API helper.
146  *
147  * @param[in] sdi The device instance to use. May be NULL (unused).
148  *
149  * @retval SR_OK Success.
150  */
151 SR_PRIV int std_dummy_dev_acquisition_stop(struct sr_dev_inst *sdi)
152 {
153         (void)sdi;
154
155         return SR_OK;
156 }
157
158 /**
159  * Standard API helper for sending an SR_DF_HEADER packet.
160  *
161  * This function can be used to simplify most drivers'
162  * dev_acquisition_start() API callback.
163  *
164  * @param[in] sdi The device instance to use. Must not be NULL.
165  *
166  * @retval SR_OK Success.
167  * @retval SR_ERR_ARG Invalid argument.
168  * @retval other Other error.
169  */
170 SR_PRIV int std_session_send_df_header(const struct sr_dev_inst *sdi)
171 {
172         const char *prefix;
173         int ret;
174         struct sr_datafeed_packet packet;
175         struct sr_datafeed_header header;
176
177         if (!sdi) {
178                 sr_err("%s: Invalid argument.", __func__);
179                 return SR_ERR_ARG;
180         }
181
182         prefix = (sdi->driver) ? sdi->driver->name : "unknown";
183
184         /* Send header packet to the session bus. */
185         packet.type = SR_DF_HEADER;
186         packet.payload = (uint8_t *)&header;
187         header.feed_version = 1;
188         gettimeofday(&header.starttime, NULL);
189
190         if ((ret = sr_session_send(sdi, &packet)) < 0) {
191                 sr_err("%s: Failed to send SR_DF_HEADER packet: %d.", prefix, ret);
192                 return ret;
193         }
194
195         return SR_OK;
196 }
197
198 static int send_df_without_payload(const struct sr_dev_inst *sdi, uint16_t packet_type)
199 {
200         const char *prefix;
201         int ret;
202         struct sr_datafeed_packet packet;
203
204         if (!sdi) {
205                 sr_err("%s: Invalid argument.", __func__);
206                 return SR_ERR_ARG;
207         }
208
209         prefix = (sdi->driver) ? sdi->driver->name : "unknown";
210
211         packet.type = packet_type;
212         packet.payload = NULL;
213
214         if ((ret = sr_session_send(sdi, &packet)) < 0) {
215                 sr_err("%s: Failed to send packet of type %d: %d.", prefix, packet_type, ret);
216                 return ret;
217         }
218
219         return SR_OK;
220 }
221
222 /**
223  * Standard API helper for sending an SR_DF_END packet.
224  *
225  * This function can be used to simplify most drivers'
226  * dev_acquisition_stop() API callback.
227  *
228  * @param[in] sdi The device instance to use. Must not be NULL.
229  *
230  * @retval SR_OK Success.
231  * @retval SR_ERR_ARG Invalid argument.
232  * @retval other Other error.
233  */
234 SR_PRIV int std_session_send_df_end(const struct sr_dev_inst *sdi)
235 {
236         return send_df_without_payload(sdi, SR_DF_END);
237 }
238
239 /**
240  * Standard API helper for sending an SR_DF_TRIGGER packet.
241  *
242  * This function can be used to simplify most drivers' trigger handling.
243  *
244  * @param[in] sdi The device instance to use. Must not be NULL.
245  *
246  * @retval SR_OK Success.
247  * @retval SR_ERR_ARG Invalid argument.
248  * @retval other Other error.
249  */
250 SR_PRIV int std_session_send_df_trigger(const struct sr_dev_inst *sdi)
251 {
252         return send_df_without_payload(sdi, SR_DF_TRIGGER);
253 }
254
255 /**
256  * Standard API helper for sending an SR_DF_FRAME_BEGIN packet.
257  *
258  * This function can be used to simplify most drivers' frame handling.
259  *
260  * @param[in] sdi The device instance to use. Must not be NULL.
261  *
262  * @retval SR_OK Success.
263  * @retval SR_ERR_ARG Invalid argument.
264  * @retval other Other error.
265  */
266 SR_PRIV int std_session_send_df_frame_begin(const struct sr_dev_inst *sdi)
267 {
268         return send_df_without_payload(sdi, SR_DF_FRAME_BEGIN);
269 }
270
271 /**
272  * Standard API helper for sending an SR_DF_FRAME_END packet.
273  *
274  * This function can be used to simplify most drivers' frame handling.
275  *
276  * @param[in] sdi The device instance to use. Must not be NULL.
277  *
278  * @retval SR_OK Success.
279  * @retval SR_ERR_ARG Invalid argument.
280  * @retval other Other error.
281  */
282 SR_PRIV int std_session_send_df_frame_end(const struct sr_dev_inst *sdi)
283 {
284         return send_df_without_payload(sdi, SR_DF_FRAME_END);
285 }
286
287 #ifdef HAVE_SERIAL_COMM
288
289 /**
290  * Standard serial driver dev_open() callback API helper.
291  *
292  * This function can be used to implement the dev_open() driver API
293  * callback in drivers that use a serial port. The port is opened
294  * with the SERIAL_RDWR flag.
295  *
296  * @param[in] sdi The device instance to use. Must not be NULL.
297  *
298  * @retval SR_OK Success.
299  * @retval SR_ERR_ARG Invalid argument.
300  * @retval other Serial port open failed.
301  */
302 SR_PRIV int std_serial_dev_open(struct sr_dev_inst *sdi)
303 {
304         struct sr_serial_dev_inst *serial;
305
306         if (!sdi) {
307                 sr_err("%s: Invalid argument.", __func__);
308                 return SR_ERR_ARG;
309         }
310
311         serial = sdi->conn;
312
313         return serial_open(serial, SERIAL_RDWR);
314 }
315
316 /**
317  * Standard serial driver dev_close() callback API helper.
318  *
319  * This function can be used to implement the dev_close() driver API
320  * callback in drivers that use a serial port.
321  *
322  * @param[in] sdi The device instance to use. Must not be NULL.
323  *
324  * @retval SR_OK Success.
325  * @retval SR_ERR_ARG Invalid argument.
326  * @retval other Serial port close failed.
327  */
328 SR_PRIV int std_serial_dev_close(struct sr_dev_inst *sdi)
329 {
330         struct sr_serial_dev_inst *serial;
331
332         if (!sdi) {
333                 sr_err("%s: Invalid argument.", __func__);
334                 return SR_ERR_ARG;
335         }
336
337         serial = sdi->conn;
338
339         return serial_close(serial);
340 }
341
342 /**
343  * Standard serial driver dev_acquisition_stop() callback API helper.
344  *
345  * This function can be used to simplify most (serial port based) drivers'
346  * dev_acquisition_stop() API callback.
347  *
348  * @param[in] sdi The device instance for which acquisition should stop.
349  *                Must not be NULL.
350  *
351  * @retval SR_OK Success.
352  * @retval SR_ERR_ARG Invalid argument.
353  * @retval other Other error.
354  */
355 SR_PRIV int std_serial_dev_acquisition_stop(struct sr_dev_inst *sdi)
356 {
357         struct sr_serial_dev_inst *serial;
358         const char *prefix;
359         int ret;
360
361         if (!sdi) {
362                 sr_err("%s: Invalid argument.", __func__);
363                 return SR_ERR_ARG;
364         }
365
366         serial = sdi->conn;
367         prefix = sdi->driver->name;
368
369         if ((ret = serial_source_remove(sdi->session, serial)) < 0) {
370                 sr_err("%s: Failed to remove source: %d.", prefix, ret);
371                 return ret;
372         }
373
374         return std_session_send_df_end(sdi);
375 }
376
377 #endif
378
379 /**
380  * Standard driver dev_clear() callback API helper.
381  *
382  * Clear driver, this means, close all instances.
383  *
384  * This function can be used to implement the dev_clear() driver API
385  * callback. dev_close() is called before every sr_dev_inst is cleared.
386  *
387  * The only limitation is driver-specific device contexts (sdi->priv / devc).
388  * These are freed, but any dynamic allocation within structs stored
389  * there cannot be freed.
390  *
391  * @param[in] driver The driver which will have its instances released.
392  *                   Must not be NULL.
393  * @param[in] clear_private If not NULL, this points to a function called
394  *            with sdi->priv (devc) as argument. The function can then clear
395  *            any device instance-specific resources kept there.
396  *            It must NOT clear the struct pointed to by sdi->priv (devc),
397  *            since this function will always free it after clear_private()
398  *            has run.
399  *
400  * @retval SR_OK Success.
401  * @retval SR_ERR_ARG Invalid argument.
402  * @retval SR_ERR_BUG Implementation bug.
403  * @retval other Other error.
404  */
405 SR_PRIV int std_dev_clear_with_callback(const struct sr_dev_driver *driver,
406                 std_dev_clear_callback clear_private)
407 {
408         struct drv_context *drvc;
409         struct sr_dev_inst *sdi;
410         GSList *l;
411         int ret;
412
413         if (!driver) {
414                 sr_err("%s: Invalid argument.", __func__);
415                 return SR_ERR_ARG;
416         }
417
418         drvc = driver->context; /* Caller checked for context != NULL. */
419
420         ret = SR_OK;
421         for (l = drvc->instances; l; l = l->next) {
422                 if (!(sdi = l->data)) {
423                         sr_err("%s: Invalid device instance.", __func__);
424                         ret = SR_ERR_BUG;
425                         continue;
426                 }
427                 if (driver->dev_close && sdi->status == SR_ST_ACTIVE)
428                         driver->dev_close(sdi);
429
430                 if (sdi->conn) {
431 #ifdef HAVE_SERIAL_COMM
432                         if (sdi->inst_type == SR_INST_SERIAL)
433                                 sr_serial_dev_inst_free(sdi->conn);
434 #endif
435 #ifdef HAVE_LIBUSB_1_0
436                         if (sdi->inst_type == SR_INST_USB)
437                                 sr_usb_dev_inst_free(sdi->conn);
438 #endif
439                         if (sdi->inst_type == SR_INST_SCPI)
440                                 sr_scpi_free(sdi->conn);
441                         if (sdi->inst_type == SR_INST_MODBUS)
442                                 sr_modbus_free(sdi->conn);
443                 }
444
445                 /* Clear driver-specific stuff, if any. */
446                 if (clear_private)
447                         clear_private(sdi->priv);
448
449                 /* Clear sdi->priv (devc). */
450                 g_free(sdi->priv);
451
452                 sr_dev_inst_free(sdi);
453         }
454
455         g_slist_free(drvc->instances);
456         drvc->instances = NULL;
457
458         return ret;
459 }
460
461 SR_PRIV int std_dev_clear(const struct sr_dev_driver *driver)
462 {
463         return std_dev_clear_with_callback(driver, NULL);
464 }
465
466 /**
467  * Standard driver dev_list() callback API helper.
468  *
469  * This function can be used as the dev_list() callback by most drivers.
470  *
471  * Return the devices contained in the driver context instances list.
472  *
473  * @param[in] di The driver instance to use. Must not be NULL.
474  *
475  * @retval NULL Error, or the list is empty.
476  * @retval other The list of device instances of this driver.
477  */
478 SR_PRIV GSList *std_dev_list(const struct sr_dev_driver *di)
479 {
480         struct drv_context *drvc;
481
482         if (!di) {
483                 sr_err("%s: Invalid argument.", __func__);
484                 return NULL;
485         }
486
487         drvc = di->context;
488
489         return drvc->instances;
490 }
491
492 /**
493  * Standard driver scan() callback API helper.
494  *
495  * This function can be used to perform common tasks required by a driver's
496  * scan() callback. It will initialize the driver for each device on the list
497  * and add the devices on the list to the driver's device instance list.
498  * Usually it should be used as the last step in the scan() callback, right
499  * before returning.
500  *
501  * Note: This function can only be used if std_init() has been called
502  * previously by the driver.
503  *
504  * Example:
505  * @code{c}
506  * static GSList *scan(struct sr_dev_driver *di, GSList *options)
507  * {
508  *     struct GSList *device;
509  *     struct sr_dev_inst *sdi;
510  *
511  *     sdi = g_new0(sr_dev_inst, 1);
512  *     sdi->vendor = ...;
513  *     ...
514  *     devices = g_slist_append(devices, sdi);
515  *     ...
516  *     return std_scan_complete(di, devices);
517  * }
518  * @endcode
519  *
520  * @param[in] di The driver instance to use. Must not be NULL.
521  * @param[in] devices List of newly discovered devices (struct sr_dev_inst).
522  *                    May be NULL.
523  *
524  * @return The @p devices list.
525  */
526 SR_PRIV GSList *std_scan_complete(struct sr_dev_driver *di, GSList *devices)
527 {
528         struct drv_context *drvc;
529         GSList *l;
530
531         if (!di) {
532                 sr_err("Invalid driver instance (di), cannot complete scan.");
533                 return NULL;
534         }
535
536         drvc = di->context;
537
538         for (l = devices; l; l = l->next) {
539                 struct sr_dev_inst *sdi = l->data;
540                 if (!sdi) {
541                         sr_err("Invalid device instance, cannot complete scan.");
542                         return NULL;
543                 }
544                 sdi->driver = di;
545         }
546
547         drvc->instances = g_slist_concat(drvc->instances, g_slist_copy(devices));
548
549         return devices;
550 }
551
552 SR_PRIV int std_opts_config_list(uint32_t key, GVariant **data,
553         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg,
554         const uint32_t scanopts[], size_t scansize, const uint32_t drvopts[],
555         size_t drvsize, const uint32_t devopts[], size_t devsize)
556 {
557         switch (key) {
558         case SR_CONF_SCAN_OPTIONS:
559                 /* Always return scanopts, regardless of sdi or cg. */
560                 if (!scanopts || scanopts == NO_OPTS)
561                         return SR_ERR_ARG;
562                 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
563                         scanopts, scansize, sizeof(uint32_t));
564                 break;
565         case SR_CONF_DEVICE_OPTIONS:
566                 if (!sdi) {
567                         /* sdi == NULL: return drvopts. */
568                         if (!drvopts || drvopts == NO_OPTS)
569                                 return SR_ERR_ARG;
570                         *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
571                                 drvopts, drvsize, sizeof(uint32_t));
572                 } else if (sdi && !cg) {
573                         /* sdi != NULL, cg == NULL: return devopts. */
574                         if (!devopts || devopts == NO_OPTS)
575                                 return SR_ERR_ARG;
576                         *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
577                                 devopts, devsize, sizeof(uint32_t));
578                 } else {
579                         /*
580                          * Note: sdi != NULL, cg != NULL is not handled by
581                          * this function since it's very driver-specific.
582                          */
583                         sr_err("%s: %s: sdi/cg != NULL: not handling.",
584                                sdi->driver->name, __func__);
585                         return SR_ERR_ARG;
586                 }
587                 break;
588         default:
589                 return SR_ERR_NA;
590         }
591
592         return SR_OK;
593 }
594
595 SR_PRIV GVariant *std_gvar_tuple_array(const uint64_t a[][2], unsigned int n)
596 {
597         unsigned int i;
598         GVariant *rational[2];
599         GVariantBuilder gvb;
600
601         g_variant_builder_init(&gvb, G_VARIANT_TYPE_TUPLE);
602
603         for (i = 0; i < n; i++) {
604                 rational[0] = g_variant_new_uint64(a[i][0]);
605                 rational[1] = g_variant_new_uint64(a[i][1]);
606
607                 /* FIXME: Valgrind reports a memory leak here. */
608                 g_variant_builder_add_value(&gvb, g_variant_new_tuple(rational, 2));
609         }
610
611         return g_variant_builder_end(&gvb);
612 }
613
614 SR_PRIV GVariant *std_gvar_tuple_rational(const struct sr_rational *r, unsigned int n)
615 {
616         unsigned int i;
617         GVariant *rational[2];
618         GVariantBuilder gvb;
619
620         g_variant_builder_init(&gvb, G_VARIANT_TYPE_TUPLE);
621
622         for (i = 0; i < n; i++) {
623                 rational[0] = g_variant_new_uint64(r[i].p);
624                 rational[1] = g_variant_new_uint64(r[i].q);
625
626                 /* FIXME: Valgrind reports a memory leak here. */
627                 g_variant_builder_add_value(&gvb, g_variant_new_tuple(rational, 2));
628         }
629
630         return g_variant_builder_end(&gvb);
631 }
632
633 static GVariant *samplerate_helper(const uint64_t samplerates[], unsigned int n, const char *str)
634 {
635         GVariant *gvar;
636         GVariantBuilder gvb;
637
638         g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
639         gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
640                         n, sizeof(uint64_t));
641         g_variant_builder_add(&gvb, "{sv}", str, gvar);
642
643         return g_variant_builder_end(&gvb);
644 }
645
646 SR_PRIV GVariant *std_gvar_samplerates(const uint64_t samplerates[], unsigned int n)
647 {
648         return samplerate_helper(samplerates, n, "samplerates");
649 }
650
651 SR_PRIV GVariant *std_gvar_samplerates_steps(const uint64_t samplerates[], unsigned int n)
652 {
653         return samplerate_helper(samplerates, n, "samplerate-steps");
654 }
655
656 SR_PRIV GVariant *std_gvar_min_max_step(double min, double max, double step)
657 {
658         GVariantBuilder gvb;
659
660         g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
661
662         g_variant_builder_add_value(&gvb, g_variant_new_double(min));
663         g_variant_builder_add_value(&gvb, g_variant_new_double(max));
664         g_variant_builder_add_value(&gvb, g_variant_new_double(step));
665
666         return g_variant_builder_end(&gvb);
667 }
668
669 SR_PRIV GVariant *std_gvar_min_max_step_array(const double a[3])
670 {
671         unsigned int i;
672         GVariantBuilder gvb;
673
674         g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
675
676         for (i = 0; i < 3; i++)
677                 g_variant_builder_add_value(&gvb, g_variant_new_double(a[i]));
678
679         return g_variant_builder_end(&gvb);
680 }
681
682 SR_PRIV GVariant *std_gvar_min_max_step_thresholds(const double min, const double max, const double step)
683 {
684         double d, v;
685         GVariant *gvar, *range[2];
686         GVariantBuilder gvb;
687
688         g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
689
690         for (d = min; d <= max; d += step) {
691                 /*
692                  * We will never see exactly 0.0 because of the error we're
693                  * accumulating, so catch the "zero" value and force it to be 0.
694                  */
695                 v = ((d > (-step / 2)) && (d < (step / 2))) ? 0 : d;
696
697                 range[0] = g_variant_new_double(v);
698                 range[1] = g_variant_new_double(v);
699
700                 gvar = g_variant_new_tuple(range, 2);
701                 g_variant_builder_add_value(&gvb, gvar);
702         }
703
704         return g_variant_builder_end(&gvb);
705 }
706
707 SR_PRIV GVariant *std_gvar_tuple_u64(uint64_t low, uint64_t high)
708 {
709         GVariant *range[2];
710
711         range[0] = g_variant_new_uint64(low);
712         range[1] = g_variant_new_uint64(high);
713
714         return g_variant_new_tuple(range, 2);
715 }
716
717 SR_PRIV GVariant *std_gvar_tuple_double(double low, double high)
718 {
719         GVariant *range[2];
720
721         range[0] = g_variant_new_double(low);
722         range[1] = g_variant_new_double(high);
723
724         return g_variant_new_tuple(range, 2);
725 }
726
727 SR_PRIV GVariant *std_gvar_array_i32(const int32_t a[], unsigned int n)
728 {
729         return g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
730                                 a, n, sizeof(int32_t));
731 }
732
733 SR_PRIV GVariant *std_gvar_array_u32(const uint32_t a[], unsigned int n)
734 {
735         return g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
736                                 a, n, sizeof(uint32_t));
737 }
738
739 SR_PRIV GVariant *std_gvar_array_u64(const uint64_t a[], unsigned int n)
740 {
741         return g_variant_new_fixed_array(G_VARIANT_TYPE_UINT64,
742                                 a, n, sizeof(uint64_t));
743 }
744
745 SR_PRIV GVariant *std_gvar_array_str(const char *a[], unsigned int n)
746 {
747         GVariant *gvar;
748         GVariantBuilder *builder;
749         unsigned int i;
750
751         builder = g_variant_builder_new(G_VARIANT_TYPE ("as"));
752
753         for (i = 0; i < n; i++)
754                 g_variant_builder_add(builder, "s", a[i]);
755
756         gvar = g_variant_new("as", builder);
757         g_variant_builder_unref(builder);
758
759         return gvar;
760 }
761
762 SR_PRIV GVariant *std_gvar_thresholds(const double a[][2], unsigned int n)
763 {
764         unsigned int i;
765         GVariant *gvar, *range[2];
766         GVariantBuilder gvb;
767
768         g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
769
770         for (i = 0; i < n; i++) {
771                 range[0] = g_variant_new_double(a[i][0]);
772                 range[1] = g_variant_new_double(a[i][1]);
773                 gvar = g_variant_new_tuple(range, 2);
774                 g_variant_builder_add_value(&gvb, gvar);
775         }
776
777         return g_variant_builder_end(&gvb);
778 }
779
780 /* Return the index of 'data' in the array 'arr' (or -1). */
781 static int find_in_array(GVariant *data, const GVariantType *type,
782                          const void *arr, unsigned int n)
783 {
784         const char * const *sarr;
785         const char *s;
786         const uint64_t *u64arr;
787         const uint8_t *u8arr;
788         uint64_t u64;
789         uint8_t u8;
790         unsigned int i;
791
792         if (!g_variant_is_of_type(data, type))
793                 return -1;
794
795         switch (g_variant_classify(data)) {
796         case G_VARIANT_CLASS_STRING:
797                 s = g_variant_get_string(data, NULL);
798                 sarr = arr;
799
800                 for (i = 0; i < n; i++)
801                         if (!strcmp(s, sarr[i]))
802                                 return i;
803                 break;
804         case G_VARIANT_CLASS_UINT64:
805                 u64 = g_variant_get_uint64(data);
806                 u64arr = arr;
807
808                 for (i = 0; i < n; i++)
809                         if (u64 == u64arr[i])
810                                 return i;
811                 break;
812         case G_VARIANT_CLASS_BYTE:
813                 u8 = g_variant_get_byte(data);
814                 u8arr = arr;
815
816                 for (i = 0; i < n; i++)
817                         if (u8 == u8arr[i])
818                                 return i;
819         default:
820                 break;
821         }
822
823         return -1;
824 }
825
826 SR_PRIV int std_str_idx(GVariant *data, const char *a[], unsigned int n)
827 {
828         return find_in_array(data, G_VARIANT_TYPE_STRING, a, n);
829 }
830
831 SR_PRIV int std_u64_idx(GVariant *data, const uint64_t a[], unsigned int n)
832 {
833         return find_in_array(data, G_VARIANT_TYPE_UINT64, a, n);
834 }
835
836 SR_PRIV int std_u8_idx(GVariant *data, const uint8_t a[], unsigned int n)
837 {
838         return find_in_array(data, G_VARIANT_TYPE_BYTE, a, n);
839 }
840
841 SR_PRIV int std_str_idx_s(const char *s, const char *a[], unsigned int n)
842 {
843         int idx;
844         GVariant *data;
845
846         data = g_variant_new_string(s);
847         idx = find_in_array(data, G_VARIANT_TYPE_STRING, a, n);
848         g_variant_unref(data);
849
850         return idx;
851 }
852
853 SR_PRIV int std_u8_idx_s(uint8_t b, const uint8_t a[], unsigned int n)
854 {
855         int idx;
856         GVariant *data;
857
858         data = g_variant_new_byte(b);
859         idx = find_in_array(data, G_VARIANT_TYPE_BYTE, a, n);
860         g_variant_unref(data);
861
862         return idx;
863 }
864
865 SR_PRIV int std_u64_tuple_idx(GVariant *data, const uint64_t a[][2], unsigned int n)
866 {
867         unsigned int i;
868         uint64_t low, high;
869
870         g_variant_get(data, "(tt)", &low, &high);
871
872         for (i = 0; i < n; i++)
873                 if (a[i][0] == low && a[i][1] == high)
874                         return i;
875
876         return -1;
877 }
878
879 SR_PRIV int std_double_tuple_idx(GVariant *data, const double a[][2], unsigned int n)
880 {
881         unsigned int i;
882         double low, high;
883
884         g_variant_get(data, "(dd)", &low, &high);
885
886         for (i = 0; i < n; i++)
887                 if ((fabs(a[i][0] - low) < 0.1) && ((fabs(a[i][1] - high) < 0.1)))
888                         return i;
889
890         return -1;
891 }
892
893 SR_PRIV int std_double_tuple_idx_d0(const double d, const double a[][2], unsigned int n)
894 {
895         unsigned int i;
896
897         for (i = 0; i < n; i++)
898                 if (d == a[i][0])
899                         return i;
900
901         return -1;
902 }
903
904 SR_PRIV int std_cg_idx(const struct sr_channel_group *cg, struct sr_channel_group *a[], unsigned int n)
905 {
906         unsigned int i;
907
908         for (i = 0; i < n; i++)
909                 if (cg == a[i])
910                         return i;
911
912         return -1;
913 }
914
915 SR_PRIV int std_dummy_set_params(struct sr_serial_dev_inst *serial,
916         int baudrate, int bits, int parity, int stopbits,
917         int flowcontrol, int rts, int dtr)
918 {
919         (void)serial;
920         (void)baudrate;
921         (void)bits;
922         (void)parity;
923         (void)stopbits;
924         (void)flowcontrol;
925         (void)rts;
926         (void)dtr;
927
928         return SR_OK;
929 }
930