]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/sysclk-lwla/api.c
Fix a few "value never read" scan-build warnings.
[libsigrok.git] / src / hardware / sysclk-lwla / api.c
index 7da96eec4e91c3bea57db1ba9ed5f1bd0952a60d..154d4f9000ee6247fb583f78eee49b93e0febbb5 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <config.h>
 #include <glib.h>
 #include <libusb.h>
 #include <stdlib.h>
 #include <string.h>
-#include "libsigrok.h"
+#include <libsigrok/libsigrok.h>
 #include "libsigrok-internal.h"
 #include "protocol.h"
 
@@ -100,10 +101,10 @@ static struct sr_dev_inst *dev_inst_new(void)
        devc->samplerate = DEFAULT_SAMPLERATE;
 
        sdi->priv = devc;
-       for (i = NUM_CHANNELS; i > 0; --i) {
+       for (i = 0; i < NUM_CHANNELS; ++i) {
                /* The LWLA series simply number channels from CH1 to CHxx. */
-               g_snprintf(name, sizeof(name), "CH%d", i);
-               sr_channel_new(sdi, i - 1, SR_CHANNEL_LOGIC, TRUE, name);
+               g_snprintf(name, sizeof(name), "CH%d", i + 1);
+               sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, name);
        }
 
        return sdi;
@@ -118,7 +119,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
        struct sr_config *src;
        const char *conn;
 
-       drvc = di->priv;
+       drvc = di->context;
        conn = USB_VID_PID;
 
        for (node = options; node != NULL; node = node->next) {
@@ -158,7 +159,7 @@ static GSList *dev_list(const struct sr_dev_driver *di)
 {
        struct drv_context *drvc;
 
-       drvc = di->priv;
+       drvc = di->context;
 
        return drvc->instances;
 }
@@ -186,61 +187,82 @@ static int dev_open(struct sr_dev_inst *sdi)
        struct sr_usb_dev_inst *usb;
        int ret;
 
-       drvc = di->priv;
+       drvc = di->context;
 
        if (!drvc) {
                sr_err("Driver was not initialized.");
                return SR_ERR;
        }
-
+       if (sdi->status != SR_ST_INACTIVE) {
+               sr_err("Device already open.");
+               return SR_ERR;
+       }
        usb = sdi->conn;
 
        ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb);
        if (ret != SR_OK)
                return ret;
 
+       /* Set the configuration twice to trigger a lightweight reset.
+        */
+       ret = libusb_set_configuration(usb->devhdl, USB_CONFIG);
+       if (ret == 0)
+               ret = libusb_set_configuration(usb->devhdl, USB_CONFIG);
+       if (ret != 0) {
+               sr_err("Failed to set USB configuration: %s.",
+                       libusb_error_name(ret));
+               sr_usb_close(usb);
+               return SR_ERR;
+       }
+
        ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
        if (ret < 0) {
                sr_err("Failed to claim interface: %s.",
                        libusb_error_name(ret));
+               sr_usb_close(usb);
                return SR_ERR;
        }
-
-       sdi->status = SR_ST_INITIALIZING;
+       sdi->status = SR_ST_ACTIVE;
 
        ret = lwla_init_device(sdi);
-
-       if (ret == SR_OK)
-               sdi->status = SR_ST_ACTIVE;
-
+       if (ret != SR_OK) {
+               sr_usb_close(usb);
+               sdi->status = SR_ST_INACTIVE;
+       }
        return ret;
 }
 
 static int dev_close(struct sr_dev_inst *sdi)
 {
        struct sr_usb_dev_inst *usb;
+       struct dev_context *devc;
+       int ret;
 
-       if (!di->priv) {
+       if (!di->context) {
                sr_err("Driver was not initialized.");
                return SR_ERR;
        }
-
        usb = sdi->conn;
-       if (!usb->devhdl)
+       devc = sdi->priv;
+
+       if (sdi->status == SR_ST_INACTIVE)
                return SR_OK;
 
+       if (devc && devc->acquisition) {
+               sr_err("Attempt to close device during acquisition.");
+               return SR_ERR;
+       }
        sdi->status = SR_ST_INACTIVE;
 
        /* Trigger download of the shutdown bitstream. */
-       if (lwla_set_clock_config(sdi) != SR_OK)
+       ret = lwla_set_clock_config(sdi);
+       if (ret != SR_OK)
                sr_err("Unable to shut down device.");
 
        libusb_release_interface(usb->devhdl, USB_INTERFACE);
-       libusb_close(usb->devhdl);
+       sr_usb_close(usb);
 
-       usb->devhdl = NULL;
-
-       return SR_OK;
+       return ret;
 }
 
 static int cleanup(const struct sr_dev_driver *di)
@@ -277,19 +299,19 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
                break;
        case SR_CONF_CLOCK_EDGE:
                idx = devc->cfg_clock_edge;
-               if (idx >= G_N_ELEMENTS(signal_edge_names))
+               if (idx >= ARRAY_SIZE(signal_edge_names))
                        return SR_ERR_BUG;
                *data = g_variant_new_string(signal_edge_names[idx]);
                break;
        case SR_CONF_TRIGGER_SOURCE:
                idx = devc->cfg_trigger_source;
-               if (idx >= G_N_ELEMENTS(trigger_source_names))
+               if (idx >= ARRAY_SIZE(trigger_source_names))
                        return SR_ERR_BUG;
                *data = g_variant_new_string(trigger_source_names[idx]);
                break;
        case SR_CONF_TRIGGER_SLOPE:
                idx = devc->cfg_trigger_slope;
-               if (idx >= G_N_ELEMENTS(signal_edge_names))
+               if (idx >= ARRAY_SIZE(signal_edge_names))
                        return SR_ERR_BUG;
                *data = g_variant_new_string(signal_edge_names[idx]);
                break;
@@ -336,7 +358,7 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
        switch (key) {
        case SR_CONF_SAMPLERATE:
                value = g_variant_get_uint64(data);
-               if (value < samplerates[G_N_ELEMENTS(samplerates) - 1]
+               if (value < samplerates[ARRAY_SIZE(samplerates) - 1]
                                || value > samplerates[0])
                        return SR_ERR_SAMPLERATE;
                devc->samplerate = value;
@@ -359,21 +381,21 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
                break;
        case SR_CONF_CLOCK_EDGE:
                idx = lookup_index(data, signal_edge_names,
-                                  G_N_ELEMENTS(signal_edge_names));
+                                  ARRAY_SIZE(signal_edge_names));
                if (idx < 0)
                        return SR_ERR_ARG;
                devc->cfg_clock_edge = idx;
                break;
        case SR_CONF_TRIGGER_SOURCE:
                idx = lookup_index(data, trigger_source_names,
-                                  G_N_ELEMENTS(trigger_source_names));
+                                  ARRAY_SIZE(trigger_source_names));
                if (idx < 0)
                        return SR_ERR_ARG;
                devc->cfg_trigger_source = idx;
                break;
        case SR_CONF_TRIGGER_SLOPE:
                idx = lookup_index(data, signal_edge_names,
-                                  G_N_ELEMENTS(signal_edge_names));
+                                  ARRAY_SIZE(signal_edge_names));
                if (idx < 0)
                        return SR_ERR_ARG;
                devc->cfg_trigger_slope = idx;
@@ -412,12 +434,84 @@ static int config_channel_set(const struct sr_dev_inst *sdi,
        return SR_OK;
 }
 
+static int prepare_trigger_masks(const struct sr_dev_inst *sdi)
+{
+       uint64_t trigger_mask;
+       uint64_t trigger_values;
+       uint64_t trigger_edge_mask;
+       uint64_t channel_bit;
+       struct dev_context *devc;
+       struct sr_trigger *trigger;
+       struct sr_trigger_stage *stage;
+       struct sr_trigger_match *match;
+       const GSList *node;
+
+       devc = sdi->priv;
+
+       trigger = sr_session_trigger_get(sdi->session);
+       if (!trigger || !trigger->stages)
+               return SR_OK;
+
+       if (trigger->stages->next) {
+               sr_err("This device only supports 1 trigger stage.");
+               return SR_ERR_ARG;
+       }
+       stage = trigger->stages->data;
+
+       trigger_mask = 0;
+       trigger_values = 0;
+       trigger_edge_mask = 0;
+
+       for (node = stage->matches; node; node = node->next) {
+               match = node->data;
+
+               if (!match->channel->enabled)
+                       continue; /* ignore disabled channel */
+
+               channel_bit = (uint64_t)1 << match->channel->index;
+               trigger_mask |= channel_bit;
+
+               switch (match->match) {
+               case SR_TRIGGER_ZERO:
+                       break;
+               case SR_TRIGGER_ONE:
+                       trigger_values |= channel_bit;
+                       break;
+               case SR_TRIGGER_RISING:
+                       trigger_values |= channel_bit;
+                       /* Fall through for edge mask. */
+               case SR_TRIGGER_FALLING:
+                       trigger_edge_mask |= channel_bit;
+                       break;
+               default:
+                       sr_err("Unsupported trigger match for CH%d.",
+                               match->channel->index + 1);
+                       return SR_ERR_ARG;
+               }
+       }
+       devc->trigger_mask = trigger_mask;
+       devc->trigger_values = trigger_values;
+       devc->trigger_edge_mask = trigger_edge_mask;
+
+       return SR_OK;
+}
+
 static int config_commit(const struct sr_dev_inst *sdi)
 {
-       if (sdi->status != SR_ST_ACTIVE) {
-               sr_err("Device not ready (status %d).", (int)sdi->status);
+       struct dev_context *devc;
+       int rc;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       if (devc->acquisition) {
+               sr_err("Acquisition still in progress?");
                return SR_ERR;
        }
+       rc = prepare_trigger_masks(sdi);
+       if (rc != SR_OK)
+               return rc;
 
        return lwla_set_clock_config(sdi);
 }
@@ -438,12 +532,12 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *
                break;
        case SR_CONF_DEVICE_OPTIONS:
                *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
-                               devopts, G_N_ELEMENTS(devopts), sizeof(uint32_t));
+                               devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
                break;
        case SR_CONF_SAMPLERATE:
                g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
                gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
-                               samplerates, G_N_ELEMENTS(samplerates),
+                               samplerates, ARRAY_SIZE(samplerates),
                                sizeof(uint64_t));
                g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
                *data = g_variant_builder_end(&gvb);
@@ -455,12 +549,12 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *
                break;
        case SR_CONF_TRIGGER_SOURCE:
                *data = g_variant_new_strv(trigger_source_names,
-                                          G_N_ELEMENTS(trigger_source_names));
+                                          ARRAY_SIZE(trigger_source_names));
                break;
        case SR_CONF_TRIGGER_SLOPE:
        case SR_CONF_CLOCK_EDGE:
                *data = g_variant_new_strv(signal_edge_names,
-                                          G_N_ELEMENTS(signal_edge_names));
+                                          ARRAY_SIZE(signal_edge_names));
                break;
        default:
                return SR_ERR_NA;
@@ -482,7 +576,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
                return SR_ERR_DEV_CLOSED;
 
        devc = sdi->priv;
-       drvc = di->priv;
+       drvc = di->context;
 
        if (devc->acquisition) {
                sr_err("Acquisition still in progress?");
@@ -492,13 +586,13 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
        if (!acq)
                return SR_ERR_MALLOC;
 
+       devc->cancel_requested = FALSE;
        devc->stopping_in_progress = FALSE;
        devc->transfer_error = FALSE;
 
        sr_info("Starting acquisition.");
 
        devc->acquisition = acq;
-       lwla_convert_trigger(sdi);
        ret = lwla_setup_acquisition(sdi);
        if (ret != SR_OK) {
                sr_err("Failed to set up acquisition.");
@@ -527,15 +621,18 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
 
 static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
 {
+       struct dev_context *devc;
+
        (void)cb_data;
+       devc = sdi->priv;
 
        if (sdi->status != SR_ST_ACTIVE)
                return SR_ERR_DEV_CLOSED;
 
-       sr_dbg("Stopping acquisition.");
-
-       sdi->status = SR_ST_STOPPING;
-
+       if (devc->acquisition && !devc->cancel_requested) {
+               devc->cancel_requested = TRUE;
+               sr_dbg("Stopping acquisition.");
+       }
        return SR_OK;
 }
 
@@ -557,5 +654,5 @@ SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info = {
        .dev_close = dev_close,
        .dev_acquisition_start = dev_acquisition_start,
        .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
+       .context = NULL,
 };