]> sigrok.org Git - libsigrok.git/blobdiff - src/device.c
scpi-dmm: add support to get/set range on Agilent protocol using meters
[libsigrok.git] / src / device.c
index dbbb2e26ac122e446f4c4c4efcf66e16260a5a2a..5a144d97ebccf3b160117b64f17c3be604e9367f 100644 (file)
  */
 
 #include <config.h>
-#include <stdio.h>
 #include <glib.h>
+#include <stdio.h>
+#include <string.h>
 #include <libsigrok/libsigrok.h>
 #include "libsigrok-internal.h"
+#include "scpi.h"
 
 /** @cond PRIVATE */
 #define LOG_PREFIX "device"
@@ -60,7 +62,7 @@ SR_PRIV struct sr_channel *sr_channel_new(struct sr_dev_inst *sdi,
 {
        struct sr_channel *ch;
 
-       ch = g_malloc0(sizeof(struct sr_channel));
+       ch = g_malloc0(sizeof(*ch));
        ch->sdi = sdi;
        ch->index = index;
        ch->type = type;
@@ -90,7 +92,9 @@ SR_PRIV void sr_channel_free(struct sr_channel *ch)
 }
 
 /**
- * Wrapper around @ref sr_channel_free(), suitable for glib iterators.
+ * Wrapper around sr_channel_free(), suitable for glib iterators.
+ *
+ * @private
  */
 SR_PRIV void sr_channel_free_cb(void *p)
 {
@@ -188,6 +192,69 @@ SR_PRIV struct sr_channel *sr_next_enabled_channel(const struct sr_dev_inst *sdi
        return next_channel;
 }
 
+/**
+ * Compare two channels, return whether they differ.
+ *
+ * The channels' names and types are checked. The enabled state is not
+ * considered a condition for difference. The test is motivated by the
+ * desire to detect changes in the configuration of acquisition setups
+ * between re-reads of an input file.
+ *
+ * @param[in] ch1 First channel.
+ * @param[in] ch2 Second channel.
+ *
+ * @return TRUE upon differences or unexpected input, FALSE otherwise.
+ *
+ * @private
+ */
+SR_PRIV gboolean sr_channels_differ(struct sr_channel *ch1, struct sr_channel *ch2)
+{
+       if (!ch1 || !ch2)
+               return TRUE;
+
+       if (ch1->type != ch2->type)
+               return TRUE;
+       if (strcmp(ch1->name, ch2->name))
+               return TRUE;
+
+       return FALSE;
+}
+
+/**
+ * Compare two channel lists, return whether they differ.
+ *
+ * Listing the same set of channels but in a different order is considered
+ * a difference in the lists.
+ *
+ * @param[in] l1 First channel list.
+ * @param[in] l2 Second channel list.
+ *
+ * @return TRUE upon differences or unexpected input, FALSE otherwise.
+ *
+ * @private
+ */
+SR_PRIV gboolean sr_channel_lists_differ(GSList *l1, GSList *l2)
+{
+       struct sr_channel *ch1, *ch2;
+
+       while (l1 && l2) {
+               ch1 = l1->data;
+               ch2 = l2->data;
+               l1 = l1->next;
+               l2 = l2->next;
+               if (!ch1 || !ch2)
+                       return TRUE;
+               if (sr_channels_differ(ch1, ch2))
+                       return TRUE;
+               if (ch1->index != ch2->index)
+                       return TRUE;
+       }
+       if (l1 || l2)
+               return TRUE;
+
+       return FALSE;
+}
+
 /**
  * Determine whether the specified device instance has the specified
  * capability.
@@ -340,7 +407,7 @@ SR_API struct sr_dev_inst *sr_dev_inst_user_new(const char *vendor,
 {
        struct sr_dev_inst *sdi;
 
-       sdi = g_malloc0(sizeof(struct sr_dev_inst));
+       sdi = g_malloc0(sizeof(*sdi));
 
        sdi->vendor = g_strdup(vendor);
        sdi->model = g_strdup(model);
@@ -353,6 +420,7 @@ SR_API struct sr_dev_inst *sr_dev_inst_user_new(const char *vendor,
 /**
  * Add a new channel to the specified device instance.
  *
+ * @param[in] sdi Device instance to use. Must not be NULL.
  * @param[in] index @copydoc sr_channel::index
  * @param[in] type @copydoc sr_channel::type
  * @param[in] name @copydoc sr_channel::name
@@ -430,7 +498,7 @@ SR_PRIV struct sr_usb_dev_inst *sr_usb_dev_inst_new(uint8_t bus,
 {
        struct sr_usb_dev_inst *udi;
 
-       udi = g_malloc0(sizeof(struct sr_usb_dev_inst));
+       udi = g_malloc0(sizeof(*udi));
        udi->bus = bus;
        udi->address = address;
        udi->devhdl = hdl;
@@ -453,7 +521,7 @@ SR_PRIV void sr_usb_dev_inst_free(struct sr_usb_dev_inst *usb)
 
 #endif
 
-#ifdef HAVE_LIBSERIALPORT
+#ifdef HAVE_SERIAL_COMM
 
 /**
  * Allocate and init a struct for a serial device instance.
@@ -479,7 +547,7 @@ SR_PRIV struct sr_serial_dev_inst *sr_serial_dev_inst_new(const char *port,
 {
        struct sr_serial_dev_inst *serial;
 
-       serial = g_malloc0(sizeof(struct sr_serial_dev_inst));
+       serial = g_malloc0(sizeof(*serial));
        serial->port = g_strdup(port);
        if (serialcomm)
                serial->serialcomm = g_strdup(serialcomm);
@@ -511,7 +579,7 @@ SR_PRIV struct sr_usbtmc_dev_inst *sr_usbtmc_dev_inst_new(const char *device)
 {
        struct sr_usbtmc_dev_inst *usbtmc;
 
-       usbtmc = g_malloc0(sizeof(struct sr_usbtmc_dev_inst));
+       usbtmc = g_malloc0(sizeof(*usbtmc));
        usbtmc->device = g_strdup(device);
        usbtmc->fd = -1;
 
@@ -744,19 +812,24 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
 #ifdef HAVE_LIBUSB_1_0
        struct drv_context *drvc;
        int cnt, i, a, b;
-       char connection_id[64];
+       char conn_id_usb[64];
        struct sr_usb_dev_inst *usb;
        struct libusb_device **devlist;
 #endif
 
+#ifdef HAVE_SERIAL_COMM
+       struct sr_serial_dev_inst *serial;
+#endif
+
+       struct sr_scpi_dev_inst *scpi;
+       char *conn_id_scpi;
+
        if (!sdi)
                return NULL;
 
-#ifdef HAVE_LIBSERIALPORT
-       struct sr_serial_dev_inst *serial;
-
+#ifdef HAVE_SERIAL_COMM
        if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_SERIAL)) {
-               /* connection_id isn't populated, let's do that here. */
+               /* connection_id isn't populated, let's do that for serial devices. */
 
                serial = sdi->conn;
                ((struct sr_dev_inst *)sdi)->connection_id = g_strdup(serial->port);
@@ -765,7 +838,7 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
 
 #ifdef HAVE_LIBUSB_1_0
        if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_USB)) {
-               /* connection_id isn't populated, let's do that here. */
+               /* connection_id isn't populated, let's do that for USB devices. */
 
                drvc = sdi->driver->context;
                usb = sdi->conn;
@@ -783,10 +856,10 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
                        if (b != usb->bus || a != usb->address)
                                continue;
 
-                       if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0)
+                       if (usb_get_port_path(devlist[i], conn_id_usb, sizeof(conn_id_usb)) < 0)
                                continue;
 
-                       ((struct sr_dev_inst *)sdi)->connection_id = g_strdup(connection_id);
+                       ((struct sr_dev_inst *)sdi)->connection_id = g_strdup(conn_id_usb);
                        break;
                }
 
@@ -794,6 +867,15 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
        }
 #endif
 
+       if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_SCPI)) {
+               /* connection_id isn't populated, let's do that for SCPI devices. */
+
+               scpi = sdi->conn;
+               sr_scpi_connection_id(scpi, &conn_id_scpi);
+               ((struct sr_dev_inst *)sdi)->connection_id = g_strdup(conn_id_scpi);
+               g_free(conn_id_scpi);
+       }
+
        return sdi->connection_id;
 }