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