X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Fsysclk-lwla%2Fapi.c;h=154d4f9000ee6247fb583f78eee49b93e0febbb5;hb=e57057aee778e723da572a6b5e2bd01526cc7beb;hp=b7e99ae4afc47caf54d35ffbeb256bf7c738097a;hpb=f254bc4bba68d2cade0c8f7993d8fa8d3d9b556a;p=libsigrok.git diff --git a/src/hardware/sysclk-lwla/api.c b/src/hardware/sysclk-lwla/api.c index b7e99ae4..154d4f90 100644 --- a/src/hardware/sysclk-lwla/api.c +++ b/src/hardware/sysclk-lwla/api.c @@ -17,28 +17,29 @@ * 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 hwopts[] = { +static const uint32_t scanopts[] = { SR_CONF_CONN, }; static const uint32_t devopts[] = { SR_CONF_LOGIC_ANALYZER, - SR_CONF_SAMPLERATE, - SR_CONF_EXTERNAL_CLOCK, - SR_CONF_CLOCK_EDGE, - SR_CONF_TRIGGER_MATCH, - SR_CONF_TRIGGER_SOURCE, - SR_CONF_TRIGGER_SLOPE, - SR_CONF_LIMIT_MSEC, - SR_CONF_LIMIT_SAMPLES, + SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET, + SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET, + SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_EXTERNAL_CLOCK | SR_CONF_GET | SR_CONF_SET, + SR_CONF_CLOCK_EDGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, + SR_CONF_TRIGGER_SOURCE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_TRIGGER_SLOPE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, }; static const int32_t trigger_matches[] = { @@ -74,63 +75,42 @@ 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(int device_index) +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_try_new0(struct dev_context, 1); - if (!devc) { - sr_err("Device context malloc failed."); - return NULL; - } + devc = g_malloc0(sizeof(struct dev_context)); /* Register the device with libsigrok. */ - sdi = sr_dev_inst_new(device_index, SR_ST_INACTIVE, - VENDOR_NAME, MODEL_NAME, NULL); - if (!sdi) { - sr_err("Failed to instantiate device."); - g_free(devc); - return NULL; - } + sdi = g_malloc0(sizeof(struct sr_dev_inst)); + sdi->status = SR_ST_INACTIVE; + sdi->vendor = g_strdup(VENDOR_NAME); + sdi->model = g_strdup(MODEL_NAME); /* Enable all channels to match the default channel configuration. */ devc->channel_mask = ALL_CHANNELS_MASK; 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; @@ -138,9 +118,8 @@ static GSList *scan(GSList *options) struct sr_usb_dev_inst *usb; struct sr_config *src; const char *conn; - int device_index; - drvc = di->priv; + drvc = di->context; conn = USB_VID_PID; for (node = options; node != NULL; node = node->next) { @@ -152,13 +131,12 @@ static GSList *scan(GSList *options) } usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn); devices = NULL; - device_index = g_slist_length(drvc->instances); for (node = usb_devices; node != NULL; node = node->next) { usb = node->data; /* Create sigrok device instance. */ - sdi = dev_inst_new(device_index); + sdi = dev_inst_new(); if (!sdi) { sr_usb_dev_inst_free(usb); continue; @@ -177,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; } @@ -198,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); } @@ -209,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, @@ -300,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; @@ -359,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; @@ -382,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; @@ -435,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); } @@ -457,16 +528,16 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst * switch (key) { case SR_CONF_SCAN_OPTIONS: *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - hwopts, G_N_ELEMENTS(hwopts), sizeof(uint32_t)); + scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t)); 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); @@ -478,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; @@ -505,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?"); @@ -515,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."); @@ -550,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; } @@ -580,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, };