]> sigrok.org Git - libsigrok.git/blobdiff - src/std.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / std.c
index 33e926563b2df1f6c0b82a181d017207b7f8953f..959d0005680c5d2ebad6abb1637ca28a9221f035 100644 (file)
--- a/src/std.c
+++ b/src/std.c
  * @file
  *
  * Standard API helper functions.
- *
- * @internal
  */
 
+/* Needed for gettimeofday(), at least on FreeBSD. */
+#define _XOPEN_SOURCE 700
+
 #include <config.h>
+#include <string.h>
+#include <math.h>
+#include <sys/time.h>
 #include <glib.h>
 #include <libsigrok/libsigrok.h>
 #include "libsigrok-internal.h"
@@ -33,6 +37,8 @@
 
 #define LOG_PREFIX "std"
 
+SR_PRIV const uint32_t NO_OPTS[1] = {};
+
 /**
  * Standard driver init() callback API helper.
  *
@@ -176,7 +182,6 @@ SR_PRIV int std_session_send_df_header(const struct sr_dev_inst *sdi)
        prefix = (sdi->driver) ? sdi->driver->name : "unknown";
 
        /* Send header packet to the session bus. */
-       sr_dbg("%s: Sending SR_DF_HEADER packet.", prefix);
        packet.type = SR_DF_HEADER;
        packet.payload = (uint8_t *)&header;
        header.feed_version = 1;
@@ -190,19 +195,7 @@ SR_PRIV int std_session_send_df_header(const struct sr_dev_inst *sdi)
        return SR_OK;
 }
 
-/**
- * Standard API helper for sending an SR_DF_END packet.
- *
- * This function can be used to simplify most drivers'
- * dev_acquisition_stop() API callback.
- *
- * @param[in] sdi The device instance to use. Must not be NULL.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid argument.
- * @retval other Other error.
- */
-SR_PRIV int std_session_send_df_end(const struct sr_dev_inst *sdi)
+static int send_df_without_payload(const struct sr_dev_inst *sdi, uint16_t packet_type)
 {
        const char *prefix;
        int ret;
@@ -215,20 +208,83 @@ SR_PRIV int std_session_send_df_end(const struct sr_dev_inst *sdi)
 
        prefix = (sdi->driver) ? sdi->driver->name : "unknown";
 
-       sr_dbg("%s: Sending SR_DF_END packet.", prefix);
-
-       packet.type = SR_DF_END;
+       packet.type = packet_type;
        packet.payload = NULL;
 
        if ((ret = sr_session_send(sdi, &packet)) < 0) {
-               sr_err("%s: Failed to send SR_DF_END packet: %d.", prefix, ret);
+               sr_err("%s: Failed to send packet of type %d: %d.", prefix, packet_type, ret);
                return ret;
        }
 
        return SR_OK;
 }
 
-#ifdef HAVE_LIBSERIALPORT
+/**
+ * Standard API helper for sending an SR_DF_END packet.
+ *
+ * This function can be used to simplify most drivers'
+ * dev_acquisition_stop() API callback.
+ *
+ * @param[in] sdi The device instance to use. Must not be NULL.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval other Other error.
+ */
+SR_PRIV int std_session_send_df_end(const struct sr_dev_inst *sdi)
+{
+       return send_df_without_payload(sdi, SR_DF_END);
+}
+
+/**
+ * Standard API helper for sending an SR_DF_TRIGGER packet.
+ *
+ * This function can be used to simplify most drivers' trigger handling.
+ *
+ * @param[in] sdi The device instance to use. Must not be NULL.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval other Other error.
+ */
+SR_PRIV int std_session_send_df_trigger(const struct sr_dev_inst *sdi)
+{
+       return send_df_without_payload(sdi, SR_DF_TRIGGER);
+}
+
+/**
+ * Standard API helper for sending an SR_DF_FRAME_BEGIN packet.
+ *
+ * This function can be used to simplify most drivers' frame handling.
+ *
+ * @param[in] sdi The device instance to use. Must not be NULL.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval other Other error.
+ */
+SR_PRIV int std_session_send_df_frame_begin(const struct sr_dev_inst *sdi)
+{
+       return send_df_without_payload(sdi, SR_DF_FRAME_BEGIN);
+}
+
+/**
+ * Standard API helper for sending an SR_DF_FRAME_END packet.
+ *
+ * This function can be used to simplify most drivers' frame handling.
+ *
+ * @param[in] sdi The device instance to use. Must not be NULL.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval other Other error.
+ */
+SR_PRIV int std_session_send_df_frame_end(const struct sr_dev_inst *sdi)
+{
+       return send_df_without_payload(sdi, SR_DF_FRAME_END);
+}
+
+#ifdef HAVE_SERIAL_COMM
 
 /**
  * Standard serial driver dev_open() callback API helper.
@@ -315,11 +371,6 @@ SR_PRIV int std_serial_dev_acquisition_stop(struct sr_dev_inst *sdi)
                return ret;
        }
 
-       if ((ret = sr_dev_close(sdi)) < 0) {
-               sr_err("%s: Failed to close device: %d.", prefix, ret);
-               return ret;
-       }
-
        return std_session_send_df_end(sdi);
 }
 
@@ -373,11 +424,11 @@ SR_PRIV int std_dev_clear_with_callback(const struct sr_dev_driver *driver,
                        ret = SR_ERR_BUG;
                        continue;
                }
-               if (driver->dev_close)
+               if (driver->dev_close && sdi->status == SR_ST_ACTIVE)
                        driver->dev_close(sdi);
 
                if (sdi->conn) {
-#ifdef HAVE_LIBSERIALPORT
+#ifdef HAVE_SERIAL_COMM
                        if (sdi->inst_type == SR_INST_SERIAL)
                                sr_serial_dev_inst_free(sdi->conn);
 #endif
@@ -506,7 +557,7 @@ SR_PRIV int std_opts_config_list(uint32_t key, GVariant **data,
        switch (key) {
        case SR_CONF_SCAN_OPTIONS:
                /* Always return scanopts, regardless of sdi or cg. */
-               if (!scanopts)
+               if (!scanopts || scanopts == NO_OPTS)
                        return SR_ERR_ARG;
                *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
                        scanopts, scansize, sizeof(uint32_t));
@@ -514,13 +565,13 @@ SR_PRIV int std_opts_config_list(uint32_t key, GVariant **data,
        case SR_CONF_DEVICE_OPTIONS:
                if (!sdi) {
                        /* sdi == NULL: return drvopts. */
-                       if (!drvopts)
+                       if (!drvopts || drvopts == NO_OPTS)
                                return SR_ERR_ARG;
                        *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
                                drvopts, drvsize, sizeof(uint32_t));
                } else if (sdi && !cg) {
                        /* sdi != NULL, cg == NULL: return devopts. */
-                       if (!devopts)
+                       if (!devopts || devopts == NO_OPTS)
                                return SR_ERR_ARG;
                        *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
                                devopts, devsize, sizeof(uint32_t));
@@ -547,14 +598,15 @@ SR_PRIV GVariant *std_gvar_tuple_array(const uint64_t a[][2], unsigned int n)
        GVariant *rational[2];
        GVariantBuilder gvb;
 
-       g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+       g_variant_builder_init(&gvb, G_VARIANT_TYPE_TUPLE);
 
        for (i = 0; i < n; i++) {
                rational[0] = g_variant_new_uint64(a[i][0]);
                rational[1] = g_variant_new_uint64(a[i][1]);
 
                /* FIXME: Valgrind reports a memory leak here. */
-               g_variant_builder_add_value(&gvb, g_variant_new_tuple(rational, 2));
+               g_variant_builder_add_value(&gvb, g_variant_new_tuple(rational,
+                       ARRAY_SIZE(rational)));
        }
 
        return g_variant_builder_end(&gvb);
@@ -566,14 +618,15 @@ SR_PRIV GVariant *std_gvar_tuple_rational(const struct sr_rational *r, unsigned
        GVariant *rational[2];
        GVariantBuilder gvb;
 
-       g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+       g_variant_builder_init(&gvb, G_VARIANT_TYPE_TUPLE);
 
        for (i = 0; i < n; i++) {
                rational[0] = g_variant_new_uint64(r[i].p);
                rational[1] = g_variant_new_uint64(r[i].q);
 
                /* FIXME: Valgrind reports a memory leak here. */
-               g_variant_builder_add_value(&gvb, g_variant_new_tuple(rational, 2));
+               g_variant_builder_add_value(&gvb, g_variant_new_tuple(rational,
+                       ARRAY_SIZE(rational)));
        }
 
        return g_variant_builder_end(&gvb);
@@ -630,17 +683,23 @@ SR_PRIV GVariant *std_gvar_min_max_step_array(const double a[3])
 
 SR_PRIV GVariant *std_gvar_min_max_step_thresholds(const double min, const double max, const double step)
 {
-       double d;
+       double d, v;
        GVariant *gvar, *range[2];
        GVariantBuilder gvb;
 
        g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
 
-       for (d = min; d <= max; d += step) {
-               range[0] = g_variant_new_double(d);
-               range[1] = g_variant_new_double(d);
+       for (d = min; d <= max + step / 2.0; d += step) {
+               /*
+                * We will never see exactly 0.0 because of the error we're
+                * accumulating, so catch the "zero" value and force it to be 0.
+                */
+               v = ((d > (-step / 2.0)) && (d < (step / 2.0))) ? 0 : d;
+
+               range[0] = g_variant_new_double(v);
+               range[1] = g_variant_new_double(v);
 
-               gvar = g_variant_new_tuple(range, 2);
+               gvar = g_variant_new_tuple(range, ARRAY_SIZE(range));
                g_variant_builder_add_value(&gvb, gvar);
        }
 
@@ -654,7 +713,7 @@ SR_PRIV GVariant *std_gvar_tuple_u64(uint64_t low, uint64_t high)
        range[0] = g_variant_new_uint64(low);
        range[1] = g_variant_new_uint64(high);
 
-       return g_variant_new_tuple(range, 2);
+       return g_variant_new_tuple(range, ARRAY_SIZE(range));
 }
 
 SR_PRIV GVariant *std_gvar_tuple_double(double low, double high)
@@ -664,28 +723,45 @@ SR_PRIV GVariant *std_gvar_tuple_double(double low, double high)
        range[0] = g_variant_new_double(low);
        range[1] = g_variant_new_double(high);
 
-       return g_variant_new_tuple(range, 2);
+       return g_variant_new_tuple(range, ARRAY_SIZE(range));
 }
 
-SR_PRIV GVariant *std_gvar_array_i32(const int32_t *a, unsigned int n)
+SR_PRIV GVariant *std_gvar_array_i32(const int32_t a[], unsigned int n)
 {
        return g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
                                a, n, sizeof(int32_t));
 }
 
-SR_PRIV GVariant *std_gvar_array_u32(const uint32_t *a, unsigned int n)
+SR_PRIV GVariant *std_gvar_array_u32(const uint32_t a[], unsigned int n)
 {
        return g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
                                a, n, sizeof(uint32_t));
 }
 
-SR_PRIV GVariant *std_gvar_array_u64(const uint64_t *a, unsigned int n)
+SR_PRIV GVariant *std_gvar_array_u64(const uint64_t a[], unsigned int n)
 {
        return g_variant_new_fixed_array(G_VARIANT_TYPE_UINT64,
                                a, n, sizeof(uint64_t));
 }
 
-SR_PRIV GVariant *std_gvar_thresholds(const struct voltage_threshold a[], unsigned int n)
+SR_PRIV GVariant *std_gvar_array_str(const char *a[], unsigned int n)
+{
+       GVariant *gvar;
+       GVariantBuilder *builder;
+       unsigned int i;
+
+       builder = g_variant_builder_new(G_VARIANT_TYPE ("as"));
+
+       for (i = 0; i < n; i++)
+               g_variant_builder_add(builder, "s", a[i]);
+
+       gvar = g_variant_new("as", builder);
+       g_variant_builder_unref(builder);
+
+       return gvar;
+}
+
+SR_PRIV GVariant *std_gvar_thresholds(const double a[][2], unsigned int n)
 {
        unsigned int i;
        GVariant *gvar, *range[2];
@@ -694,11 +770,172 @@ SR_PRIV GVariant *std_gvar_thresholds(const struct voltage_threshold a[], unsign
        g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
 
        for (i = 0; i < n; i++) {
-               range[0] = g_variant_new_double(a[i].low);
-               range[1] = g_variant_new_double(a[i].high);
-               gvar = g_variant_new_tuple(range, 2);
+               range[0] = g_variant_new_double(a[i][0]);
+               range[1] = g_variant_new_double(a[i][1]);
+               gvar = g_variant_new_tuple(range, ARRAY_SIZE(range));
                g_variant_builder_add_value(&gvb, gvar);
        }
 
        return g_variant_builder_end(&gvb);
 }
+
+/* Return the index of 'data' in the array 'arr' (or -1). */
+static int find_in_array(GVariant *data, const GVariantType *type,
+                        const void *arr, unsigned int n)
+{
+       const char * const *sarr;
+       const char *s;
+       const uint64_t *u64arr;
+       const uint8_t *u8arr;
+       uint64_t u64;
+       uint8_t u8;
+       unsigned int i;
+
+       if (!g_variant_is_of_type(data, type))
+               return -1;
+
+       switch (g_variant_classify(data)) {
+       case G_VARIANT_CLASS_STRING:
+               s = g_variant_get_string(data, NULL);
+               sarr = arr;
+
+               for (i = 0; i < n; i++)
+                       if (!strcmp(s, sarr[i]))
+                               return i;
+               break;
+       case G_VARIANT_CLASS_UINT64:
+               u64 = g_variant_get_uint64(data);
+               u64arr = arr;
+
+               for (i = 0; i < n; i++)
+                       if (u64 == u64arr[i])
+                               return i;
+               break;
+       case G_VARIANT_CLASS_BYTE:
+               u8 = g_variant_get_byte(data);
+               u8arr = arr;
+
+               for (i = 0; i < n; i++)
+                       if (u8 == u8arr[i])
+                               return i;
+       default:
+               break;
+       }
+
+       return -1;
+}
+
+SR_PRIV int std_str_idx(GVariant *data, const char *a[], unsigned int n)
+{
+       return find_in_array(data, G_VARIANT_TYPE_STRING, a, n);
+}
+
+SR_PRIV int std_u64_idx(GVariant *data, const uint64_t a[], unsigned int n)
+{
+       return find_in_array(data, G_VARIANT_TYPE_UINT64, a, n);
+}
+
+SR_PRIV int std_u8_idx(GVariant *data, const uint8_t a[], unsigned int n)
+{
+       return find_in_array(data, G_VARIANT_TYPE_BYTE, a, n);
+}
+
+SR_PRIV int std_str_idx_s(const char *s, const char *a[], unsigned int n)
+{
+       int idx;
+       GVariant *data;
+
+       data = g_variant_new_string(s);
+       idx = find_in_array(data, G_VARIANT_TYPE_STRING, a, n);
+       g_variant_unref(data);
+
+       return idx;
+}
+
+SR_PRIV int std_u8_idx_s(uint8_t b, const uint8_t a[], unsigned int n)
+{
+       int idx;
+       GVariant *data;
+
+       data = g_variant_new_byte(b);
+       idx = find_in_array(data, G_VARIANT_TYPE_BYTE, a, n);
+       g_variant_unref(data);
+
+       return idx;
+}
+
+SR_PRIV int std_u64_tuple_idx(GVariant *data, const uint64_t a[][2], unsigned int n)
+{
+       unsigned int i;
+       uint64_t low, high;
+
+       g_variant_get(data, "(tt)", &low, &high);
+
+       for (i = 0; i < n; i++)
+               if (a[i][0] == low && a[i][1] == high)
+                       return i;
+
+       return -1;
+}
+
+SR_PRIV int std_double_tuple_idx(GVariant *data, const double a[][2], unsigned int n)
+{
+       unsigned int i;
+       double low, high;
+
+       g_variant_get(data, "(dd)", &low, &high);
+
+       for (i = 0; i < n; i++)
+               if ((fabs(a[i][0] - low) < 0.1) && ((fabs(a[i][1] - high) < 0.1)))
+                       return i;
+
+       return -1;
+}
+
+SR_PRIV int std_double_tuple_idx_d0(const double d, const double a[][2], unsigned int n)
+{
+       unsigned int i;
+
+       for (i = 0; i < n; i++)
+               if (d == a[i][0])
+                       return i;
+
+       return -1;
+}
+
+SR_PRIV int std_cg_idx(const struct sr_channel_group *cg, struct sr_channel_group *a[], unsigned int n)
+{
+       unsigned int i;
+
+       for (i = 0; i < n; i++)
+               if (cg == a[i])
+                       return i;
+
+       return -1;
+}
+
+SR_PRIV int std_dummy_set_params(struct sr_serial_dev_inst *serial,
+       int baudrate, int bits, int parity, int stopbits,
+       int flowcontrol, int rts, int dtr)
+{
+       (void)serial;
+       (void)baudrate;
+       (void)bits;
+       (void)parity;
+       (void)stopbits;
+       (void)flowcontrol;
+       (void)rts;
+       (void)dtr;
+
+       return SR_OK;
+}
+
+SR_PRIV int std_dummy_set_handshake(struct sr_serial_dev_inst *serial,
+       int rts, int dtr)
+{
+       (void)serial;
+       (void)rts;
+       (void)dtr;
+
+       return SR_OK;
+}