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