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