X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Fsysclk-lwla%2Fapi.c;h=154d4f9000ee6247fb583f78eee49b93e0febbb5;hb=e57057aee778e723da572a6b5e2bd01526cc7beb;hp=1e3dd1d28ff6f725aa2d6b7571f5ebc3e7605e08;hpb=f57d8ffe66612a1fdc20ed09c222f8ea59bd84d4;p=libsigrok.git diff --git a/src/hardware/sysclk-lwla/api.c b/src/hardware/sysclk-lwla/api.c index 1e3dd1d2..154d4f90 100644 --- a/src/hardware/sysclk-lwla/api.c +++ b/src/hardware/sysclk-lwla/api.c @@ -17,13 +17,14 @@ * along with this program. If not, see . */ -#include "protocol.h" -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include #include #include #include #include +#include +#include "libsigrok-internal.h" +#include "protocol.h" static const uint32_t scanopts[] = { SR_CONF_CONN, @@ -74,35 +75,17 @@ static const char *const signal_edge_names[] = { "r", "f" }; SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info; static struct sr_dev_driver *const di = &sysclk_lwla_driver_info; -static int init(struct sr_context *sr_ctx) +static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx) { return std_init(sr_ctx, di, LOG_PREFIX); } -static GSList *gen_channel_list(int num_channels) -{ - GSList *list; - struct sr_channel *ch; - int i; - char name[8]; - - list = NULL; - - for (i = num_channels; i > 0; --i) { - /* The LWLA series simply number channels from CH1 to CHxx. */ - g_snprintf(name, sizeof(name), "CH%d", i); - - ch = sr_channel_new(i - 1, SR_CHANNEL_LOGIC, TRUE, name); - list = g_slist_prepend(list, ch); - } - - return list; -} - static struct sr_dev_inst *dev_inst_new(void) { struct sr_dev_inst *sdi; struct dev_context *devc; + int i; + char name[8]; /* Allocate memory for our private driver context. */ devc = g_malloc0(sizeof(struct dev_context)); @@ -118,12 +101,16 @@ static struct sr_dev_inst *dev_inst_new(void) devc->samplerate = DEFAULT_SAMPLERATE; sdi->priv = devc; - sdi->channels = gen_channel_list(NUM_CHANNELS); + 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 + 1); + sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, name); + } return sdi; } -static GSList *scan(GSList *options) +static GSList *scan(struct sr_dev_driver *di, GSList *options) { GSList *usb_devices, *devices, *node; struct drv_context *drvc; @@ -132,7 +119,7 @@ static GSList *scan(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) { @@ -168,11 +155,11 @@ static GSList *scan(GSList *options) return devices; } -static GSList *dev_list(void) +static GSList *dev_list(const struct sr_dev_driver *di) { struct drv_context *drvc; - drvc = di->priv; + drvc = di->context; return drvc->instances; } @@ -189,7 +176,7 @@ static void clear_dev_context(void *priv) g_free(devc); } -static int dev_clear(void) +static int dev_clear(const struct sr_dev_driver *di) { return std_dev_clear(di, &clear_dev_context); } @@ -200,66 +187,87 @@ 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(void) +static int cleanup(const struct sr_dev_driver *di) { - return dev_clear(); + return dev_clear(di); } static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi, @@ -291,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; @@ -350,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; @@ -373,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; @@ -426,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); } @@ -452,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); @@ -469,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; @@ -496,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?"); @@ -506,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."); @@ -541,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; } @@ -571,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, };