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