From adcb9951f8a52852e65f99d45083a3e6b9a1981a Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 9 Jun 2017 18:02:29 -0600 Subject: [PATCH] fx2lafw/dslogic: Split DSLogic into a separate driver --- Makefile.am | 12 +- configure.ac | 1 + src/hardware/dslogic/api.c | 883 ++++++++++++++++++++ src/hardware/{fx2lafw => dslogic}/dslogic.c | 27 +- src/hardware/{fx2lafw => dslogic}/dslogic.h | 23 +- src/hardware/dslogic/protocol.c | 411 +++++++++ src/hardware/dslogic/protocol.h | 121 +++ src/hardware/fx2lafw/api.c | 389 +-------- src/hardware/fx2lafw/protocol.c | 40 +- src/hardware/fx2lafw/protocol.h | 18 - 10 files changed, 1477 insertions(+), 448 deletions(-) create mode 100644 src/hardware/dslogic/api.c rename src/hardware/{fx2lafw => dslogic}/dslogic.c (94%) rename src/hardware/{fx2lafw => dslogic}/dslogic.h (88%) create mode 100644 src/hardware/dslogic/protocol.c create mode 100644 src/hardware/dslogic/protocol.h diff --git a/Makefile.am b/Makefile.am index 7b74d03f..7338caf6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -272,6 +272,14 @@ src_libdrivers_la_SOURCES += \ src/hardware/demo/protocol.c \ src/hardware/demo/api.c endif +if HW_DSLOGIC +src_libdrivers_la_SOURCES += \ + src/hardware/dslogic/dslogic.h \ + src/hardware/dslogic/dslogic.c \ + src/hardware/dslogic/protocol.h \ + src/hardware/dslogic/protocol.c \ + src/hardware/dslogic/api.c +endif if HW_FLUKE_DMM src_libdrivers_la_SOURCES += \ src/hardware/fluke-dmm/protocol.h \ @@ -288,9 +296,7 @@ if HW_FX2LAFW src_libdrivers_la_SOURCES += \ src/hardware/fx2lafw/protocol.h \ src/hardware/fx2lafw/protocol.c \ - src/hardware/fx2lafw/api.c \ - src/hardware/fx2lafw/dslogic.c \ - src/hardware/fx2lafw/dslogic.h + src/hardware/fx2lafw/api.c endif if HW_GMC_MH_1X_2X src_libdrivers_la_SOURCES += \ diff --git a/configure.ac b/configure.ac index c9fd37de..2a24d414 100644 --- a/configure.ac +++ b/configure.ac @@ -234,6 +234,7 @@ SR_DRIVER([ChronoVu LA], [chronovu-la], [libusb libftdi]) SR_DRIVER([Colead SLM], [colead-slm], [libserialport]) SR_DRIVER([Conrad DIGI 35 CPU], [conrad-digi-35-cpu], [libserialport]) SR_DRIVER([demo], [demo]) +SR_DRIVER([DreamSourceLabs], [DSLogic], [libusb]) SR_DRIVER([Fluke DMM], [fluke-dmm], [libserialport]) SR_DRIVER([FTDI LA], [ftdi-la], [libusb libftdi]) SR_DRIVER([fx2lafw], [fx2lafw], [libusb]) diff --git a/src/hardware/dslogic/api.c b/src/hardware/dslogic/api.c new file mode 100644 index 00000000..d5899d55 --- /dev/null +++ b/src/hardware/dslogic/api.c @@ -0,0 +1,883 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2013 Bert Vermeulen + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "protocol.h" +#include "dslogic.h" +#include + +static const struct dslogic_profile supported_device[] = { + /* DreamSourceLab DSLogic (before FW upload) */ + { 0x2a0e, 0x0001, "DreamSourceLab", "DSLogic", NULL, + "dreamsourcelab-dslogic-fx2.fw", + 0, NULL, NULL}, + /* DreamSourceLab DSLogic (after FW upload) */ + { 0x2a0e, 0x0001, "DreamSourceLab", "DSLogic", NULL, + "dreamsourcelab-dslogic-fx2.fw", + 0, "DreamSourceLab", "DSLogic"}, + + /* DreamSourceLab DSCope (before FW upload) */ + { 0x2a0e, 0x0002, "DreamSourceLab", "DSCope", NULL, + "dreamsourcelab-dscope-fx2.fw", + 0, NULL, NULL}, + /* DreamSourceLab DSCope (after FW upload) */ + { 0x2a0e, 0x0002, "DreamSourceLab", "DSCope", NULL, + "dreamsourcelab-dscope-fx2.fw", + 0, "DreamSourceLab", "DSCope"}, + + /* DreamSourceLab DSLogic Pro (before FW upload) */ + { 0x2a0e, 0x0003, "DreamSourceLab", "DSLogic Pro", NULL, + "dreamsourcelab-dslogic-pro-fx2.fw", + 0, NULL, NULL}, + /* DreamSourceLab DSLogic Pro (after FW upload) */ + { 0x2a0e, 0x0003, "DreamSourceLab", "DSLogic Pro", NULL, + "dreamsourcelab-dslogic-pro-fx2.fw", + 0, "DreamSourceLab", "DSLogic"}, + + /* DreamSourceLab DSLogic Plus (before FW upload) */ + { 0x2a0e, 0x0020, "DreamSourceLab", "DSLogic Plus", NULL, + "dreamsourcelab-dslogic-plus-fx2.fw", + 0, NULL, NULL}, + /* DreamSourceLab DSLogic Plus (after FW upload) */ + { 0x2a0e, 0x0020, "DreamSourceLab", "DSLogic Plus", NULL, + "dreamsourcelab-dslogic-plus-fx2.fw", + 0, "DreamSourceLab", "DSLogic"}, + + /* DreamSourceLab DSLogic Basic (before FW upload) */ + { 0x2a0e, 0x0021, "DreamSourceLab", "DSLogic Basic", NULL, + "dreamsourcelab-dslogic-basic-fx2.fw", + 0, NULL, NULL}, + /* DreamSourceLab DSLogic Basic (after FW upload) */ + { 0x2a0e, 0x0021, "DreamSourceLab", "DSLogic Basic", NULL, + "dreamsourcelab-dslogic-basic-fx2.fw", + 0, "DreamSourceLab", "DSLogic"}, + + ALL_ZERO +}; + +static const uint32_t drvopts[] = { + SR_CONF_LOGIC_ANALYZER, +}; + +static const uint32_t scanopts[] = { + SR_CONF_CONN, +}; + +static const uint32_t devopts[] = { + SR_CONF_CONTINUOUS | SR_CONF_SET | SR_CONF_GET, + SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET, + SR_CONF_VOLTAGE_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_CONN | SR_CONF_GET, + SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, + SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, + SR_CONF_EXTERNAL_CLOCK | SR_CONF_GET | SR_CONF_SET, + SR_CONF_CLOCK_EDGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, +}; + +/* Names assigned to available edge slope choices. */ +static const char *const signal_edge_names[] = { + [DS_EDGE_RISING] = "rising", + [DS_EDGE_FALLING] = "falling", +}; + +static const struct { + int range; + gdouble low; + gdouble high; +} volt_thresholds[] = { + { DS_VOLTAGE_RANGE_18_33_V, 0.7, 1.4 }, + { DS_VOLTAGE_RANGE_5_V, 1.4, 3.6 }, +}; + +static const uint64_t samplerates[] = { + SR_KHZ(10), + SR_KHZ(20), + SR_KHZ(50), + SR_KHZ(100), + SR_KHZ(200), + SR_KHZ(500), + SR_MHZ(1), + SR_MHZ(2), + SR_MHZ(5), + SR_MHZ(10), + SR_MHZ(20), + SR_MHZ(25), + SR_MHZ(50), + SR_MHZ(100), + SR_MHZ(200), + SR_MHZ(400), +}; + +static gboolean is_plausible(const struct libusb_device_descriptor *des) +{ + int i; + + for (i = 0; supported_device[i].vid; i++) { + if (des->idVendor != supported_device[i].vid) + continue; + if (des->idProduct == supported_device[i].pid) + return TRUE; + } + + return FALSE; +} + +static GSList *scan(struct sr_dev_driver *di, GSList *options) +{ + struct drv_context *drvc; + struct dev_context *devc; + struct sr_dev_inst *sdi; + struct sr_usb_dev_inst *usb; + struct sr_channel *ch; + struct sr_channel_group *cg; + struct sr_config *src; + const struct dslogic_profile *prof; + GSList *l, *devices, *conn_devices; + gboolean has_firmware; + struct libusb_device_descriptor des; + libusb_device **devlist; + struct libusb_device_handle *hdl; + int ret, i, j; + const char *conn; + char manufacturer[64], product[64], serial_num[64], connection_id[64]; + char channel_name[16]; + + drvc = di->context; + + conn = NULL; + for (l = options; l; l = l->next) { + src = l->data; + switch (src->key) { + case SR_CONF_CONN: + conn = g_variant_get_string(src->data, NULL); + break; + } + } + if (conn) + conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn); + else + conn_devices = NULL; + + /* Find all dslogic compatible devices and upload firmware to them. */ + devices = NULL; + libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); + for (i = 0; devlist[i]; i++) { + if (conn) { + usb = NULL; + for (l = conn_devices; l; l = l->next) { + usb = l->data; + if (usb->bus == libusb_get_bus_number(devlist[i]) + && usb->address == libusb_get_device_address(devlist[i])) + break; + } + if (!l) + /* This device matched none of the ones that + * matched the conn specification. */ + continue; + } + + libusb_get_device_descriptor( devlist[i], &des); + + if (!is_plausible(&des)) + continue; + + if ((ret = libusb_open(devlist[i], &hdl)) < 0) { + sr_warn("Failed to open potential device with " + "VID:PID %04x:%04x: %s.", des.idVendor, + des.idProduct, libusb_error_name(ret)); + continue; + } + + if (des.iManufacturer == 0) { + manufacturer[0] = '\0'; + } else if ((ret = libusb_get_string_descriptor_ascii(hdl, + des.iManufacturer, (unsigned char *) manufacturer, + sizeof(manufacturer))) < 0) { + sr_warn("Failed to get manufacturer string descriptor: %s.", + libusb_error_name(ret)); + continue; + } + + if (des.iProduct == 0) { + product[0] = '\0'; + } else if ((ret = libusb_get_string_descriptor_ascii(hdl, + des.iProduct, (unsigned char *) product, + sizeof(product))) < 0) { + sr_warn("Failed to get product string descriptor: %s.", + libusb_error_name(ret)); + continue; + } + + if (des.iSerialNumber == 0) { + serial_num[0] = '\0'; + } else if ((ret = libusb_get_string_descriptor_ascii(hdl, + des.iSerialNumber, (unsigned char *) serial_num, + sizeof(serial_num))) < 0) { + sr_warn("Failed to get serial number string descriptor: %s.", + libusb_error_name(ret)); + continue; + } + + usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)); + + libusb_close(hdl); + + prof = NULL; + for (j = 0; supported_device[j].vid; j++) { + if (des.idVendor == supported_device[j].vid && + des.idProduct == supported_device[j].pid && + (!supported_device[j].usb_manufacturer || + !strcmp(manufacturer, supported_device[j].usb_manufacturer)) && + (!supported_device[j].usb_product || + !strcmp(product, supported_device[j].usb_product))) { + prof = &supported_device[j]; + break; + } + } + + /* Skip if the device was not found. */ + if (!prof) + continue; + + sdi = g_malloc0(sizeof(struct sr_dev_inst)); + sdi->status = SR_ST_INITIALIZING; + sdi->vendor = g_strdup(prof->vendor); + sdi->model = g_strdup(prof->model); + sdi->version = g_strdup(prof->model_version); + sdi->serial_num = g_strdup(serial_num); + sdi->connection_id = g_strdup(connection_id); + + /* Logic channels, all in one channel group. */ + cg = g_malloc0(sizeof(struct sr_channel_group)); + cg->name = g_strdup("Logic"); + for (j = 0; j < 16; j++) { + sprintf(channel_name, "D%d", j); + ch = sr_channel_new(sdi, j, SR_CHANNEL_LOGIC, + TRUE, channel_name); + cg->channels = g_slist_append(cg->channels, ch); + } + sdi->channel_groups = g_slist_append(NULL, cg); + + devc = dslogic_dev_new(); + devc->profile = prof; + sdi->priv = devc; + devices = g_slist_append(devices, sdi); + + devc->samplerates = samplerates; + devc->num_samplerates = ARRAY_SIZE(samplerates); + has_firmware = usb_match_manuf_prod(devlist[i], "DreamSourceLab", "DSLogic") + || usb_match_manuf_prod(devlist[i], "DreamSourceLab", "DSCope"); + + if (has_firmware) { + /* Already has the firmware, so fix the new address. */ + sr_dbg("Found an dslogic device."); + sdi->status = SR_ST_INACTIVE; + sdi->inst_type = SR_INST_USB; + sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), + libusb_get_device_address(devlist[i]), NULL); + } else { + if (ezusb_upload_firmware(drvc->sr_ctx, devlist[i], + USB_CONFIGURATION, prof->firmware) == SR_OK) + /* Store when this device's FW was updated. */ + devc->fw_updated = g_get_monotonic_time(); + else + sr_err("Firmware upload failed for " + "device %d.%d (logical).", + libusb_get_bus_number(devlist[i]), + libusb_get_device_address(devlist[i])); + sdi->inst_type = SR_INST_USB; + sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), + 0xff, NULL); + } + } + libusb_free_device_list(devlist, 1); + g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); + + return std_scan_complete(di, devices); +} + +static void clear_dev_context(void *priv) +{ + struct dev_context *devc; + + devc = priv; + g_free(devc); +} + +static int dev_clear(const struct sr_dev_driver *di) +{ + return std_dev_clear(di, clear_dev_context); +} + +static int dev_open(struct sr_dev_inst *sdi) +{ + struct sr_dev_driver *di = sdi->driver; + struct sr_usb_dev_inst *usb; + struct dev_context *devc; + const char *fpga_firmware = NULL; + int ret; + int64_t timediff_us, timediff_ms; + + devc = sdi->priv; + usb = sdi->conn; + + /* + * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS + * milliseconds for the FX2 to renumerate. + */ + ret = SR_ERR; + if (devc->fw_updated > 0) { + sr_info("Waiting for device to reset."); + /* Takes >= 300ms for the FX2 to be gone from the USB bus. */ + g_usleep(300 * 1000); + timediff_ms = 0; + while (timediff_ms < MAX_RENUM_DELAY_MS) { + if ((ret = dslogic_dev_open(sdi, di)) == SR_OK) + break; + g_usleep(100 * 1000); + + timediff_us = g_get_monotonic_time() - devc->fw_updated; + timediff_ms = timediff_us / 1000; + sr_spew("Waited %" PRIi64 "ms.", timediff_ms); + } + if (ret != SR_OK) { + sr_err("Device failed to renumerate."); + return SR_ERR; + } + sr_info("Device came back after %" PRIi64 "ms.", timediff_ms); + } else { + sr_info("Firmware upload was not needed."); + ret = dslogic_dev_open(sdi, di); + } + + if (ret != SR_OK) { + sr_err("Unable to open device."); + return SR_ERR; + } + + ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE); + if (ret != 0) { + switch (ret) { + case LIBUSB_ERROR_BUSY: + sr_err("Unable to claim USB interface. Another " + "program or driver has already claimed it."); + break; + case LIBUSB_ERROR_NO_DEVICE: + sr_err("Device has been disconnected."); + break; + default: + sr_err("Unable to claim interface: %s.", + libusb_error_name(ret)); + break; + } + + return SR_ERR; + } + + if (!strcmp(devc->profile->model, "DSLogic")) { + if (devc->voltage_threshold == DS_VOLTAGE_RANGE_18_33_V) + fpga_firmware = DSLOGIC_FPGA_FIRMWARE_3V3; + else + fpga_firmware = DSLOGIC_FPGA_FIRMWARE_5V; + } else if (!strcmp(devc->profile->model, "DSLogic Pro")){ + fpga_firmware = DSLOGIC_PRO_FPGA_FIRMWARE; + } else if (!strcmp(devc->profile->model, "DSLogic Plus")){ + fpga_firmware = DSLOGIC_PLUS_FPGA_FIRMWARE; + } else if (!strcmp(devc->profile->model, "DSLogic Basic")){ + fpga_firmware = DSLOGIC_BASIC_FPGA_FIRMWARE; + } else if (!strcmp(devc->profile->model, "DSCope")) { + fpga_firmware = DSCOPE_FPGA_FIRMWARE; + } + + if ((ret = dslogic_fpga_firmware_upload(sdi, fpga_firmware)) != SR_OK) + return ret; + + if (devc->cur_samplerate == 0) { + /* Samplerate hasn't been set; default to the slowest one. */ + devc->cur_samplerate = devc->samplerates[0]; + } + + return SR_OK; +} + +static int dev_close(struct sr_dev_inst *sdi) +{ + struct sr_usb_dev_inst *usb; + + usb = sdi->conn; + + if (!usb->devhdl) + return SR_ERR; + + sr_info("dslogic: Closing device on %d.%d (logical) / %s (physical) interface %d.", + usb->bus, usb->address, sdi->connection_id, USB_INTERFACE); + libusb_release_interface(usb->devhdl, USB_INTERFACE); + libusb_close(usb->devhdl); + usb->devhdl = NULL; + sdi->status = SR_ST_INACTIVE; + + return SR_OK; +} + +static int config_get(uint32_t key, GVariant **data, + const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) +{ + struct dev_context *devc; + struct sr_usb_dev_inst *usb; + GVariant *range[2]; + unsigned int i; + char str[128]; + + (void)cg; + + if (!sdi) + return SR_ERR_ARG; + + devc = sdi->priv; + + switch (key) { + case SR_CONF_CONN: + if (!sdi->conn) + return SR_ERR_ARG; + usb = sdi->conn; + if (usb->address == 255) + /* Device still needs to re-enumerate after firmware + * upload, so we don't know its (future) address. */ + return SR_ERR; + snprintf(str, 128, "%d.%d", usb->bus, usb->address); + *data = g_variant_new_string(str); + break; + case SR_CONF_VOLTAGE_THRESHOLD: + for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) { + if (volt_thresholds[i].range != devc->voltage_threshold) + continue; + range[0] = g_variant_new_double(volt_thresholds[i].low); + range[1] = g_variant_new_double(volt_thresholds[i].high); + *data = g_variant_new_tuple(range, 2); + break; + } + break; + case SR_CONF_LIMIT_SAMPLES: + *data = g_variant_new_uint64(devc->limit_samples); + break; + case SR_CONF_SAMPLERATE: + *data = g_variant_new_uint64(devc->cur_samplerate); + break; + case SR_CONF_CAPTURE_RATIO: + *data = g_variant_new_uint64(devc->capture_ratio); + break; + case SR_CONF_EXTERNAL_CLOCK: + *data = g_variant_new_boolean(devc->external_clock); + break; + case SR_CONF_CONTINUOUS: + *data = g_variant_new_boolean(devc->continuous_mode); + break; + case SR_CONF_CLOCK_EDGE: + i = devc->clock_edge; + if (i >= ARRAY_SIZE(signal_edge_names)) + return SR_ERR_BUG; + *data = g_variant_new_string(signal_edge_names[0]); + break; + default: + return SR_ERR_NA; + } + + return SR_OK; +} + +/* + * Helper for mapping a string-typed configuration value to an index + * within a table of possible values. + */ +static int lookup_index(GVariant *value, const char *const *table, int len) +{ + const char *entry; + int i; + + entry = g_variant_get_string(value, NULL); + if (!entry) + return -1; + + /* Linear search is fine for very small tables. */ + for (i = 0; i < len; i++) { + if (strcmp(entry, table[i]) == 0) + return i; + } + + return -1; +} + +static int config_set(uint32_t key, GVariant *data, + const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) +{ + struct dev_context *devc; + uint64_t arg; + int i, ret; + gdouble low, high; + + (void)cg; + + if (!sdi) + return SR_ERR_ARG; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR; + + devc = sdi->priv; + + ret = SR_OK; + + switch (key) { + case SR_CONF_SAMPLERATE: + arg = g_variant_get_uint64(data); + for (i = 0; i < devc->num_samplerates; i++) { + if (devc->samplerates[i] == arg) { + devc->cur_samplerate = arg; + break; + } + } + if (i == devc->num_samplerates) + ret = SR_ERR_ARG; + break; + case SR_CONF_LIMIT_SAMPLES: + devc->limit_samples = g_variant_get_uint64(data); + break; + case SR_CONF_CAPTURE_RATIO: + devc->capture_ratio = g_variant_get_uint64(data); + ret = (devc->capture_ratio > 100) ? SR_ERR : SR_OK; + break; + case SR_CONF_VOLTAGE_THRESHOLD: + g_variant_get(data, "(dd)", &low, &high); + ret = SR_ERR_ARG; + for (i = 0; (unsigned int)i < ARRAY_SIZE(volt_thresholds); i++) { + if (fabs(volt_thresholds[i].low - low) < 0.1 && + fabs(volt_thresholds[i].high - high) < 0.1) { + devc->voltage_threshold = volt_thresholds[i].range; + break; + } + } + if (!strcmp(devc->profile->model, "DSLogic")) { + if (devc->voltage_threshold == DS_VOLTAGE_RANGE_5_V) + ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_FPGA_FIRMWARE_5V); + else + ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_FPGA_FIRMWARE_3V3); + } else if (!strcmp(devc->profile->model, "DSLogic Pro")) { + ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_PRO_FPGA_FIRMWARE); + } else if (!strcmp(devc->profile->model, "DSLogic Plus")) { + ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_PLUS_FPGA_FIRMWARE); + } else if (!strcmp(devc->profile->model, "DSLogic Basic")) { + ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_BASIC_FPGA_FIRMWARE); + } + break; + case SR_CONF_EXTERNAL_CLOCK: + devc->external_clock = g_variant_get_boolean(data); + break; + case SR_CONF_CONTINUOUS: + devc->continuous_mode = g_variant_get_boolean(data); + break; + case SR_CONF_CLOCK_EDGE: + i = lookup_index(data, signal_edge_names, + ARRAY_SIZE(signal_edge_names)); + if (i < 0) + return SR_ERR_ARG; + devc->clock_edge = i; + break; + default: + ret = SR_ERR_NA; + } + + return ret; +} + +static int config_list(uint32_t key, GVariant **data, + const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) +{ + struct dev_context *devc; + GVariant *gvar, *range[2]; + GVariantBuilder gvb; + unsigned int i; + + (void)cg; + + switch (key) { + case SR_CONF_SCAN_OPTIONS: + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, + scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t)); + break; + case SR_CONF_DEVICE_OPTIONS: + if (!sdi) { + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, + drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t)); + } else { + devc = sdi->priv; + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, + devopts, ARRAY_SIZE(devopts), sizeof(uint32_t)); + } + break; + case SR_CONF_VOLTAGE_THRESHOLD: + if (!sdi->priv) + return SR_ERR_ARG; + devc = sdi->priv; + g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY); + for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) { + range[0] = g_variant_new_double(volt_thresholds[i].low); + range[1] = g_variant_new_double(volt_thresholds[i].high); + gvar = g_variant_new_tuple(range, 2); + g_variant_builder_add_value(&gvb, gvar); + } + *data = g_variant_builder_end(&gvb); + break; + case SR_CONF_SAMPLERATE: + devc = sdi->priv; + g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); + gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), devc->samplerates, + devc->num_samplerates, sizeof(uint64_t)); + g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); + *data = g_variant_builder_end(&gvb); + break; + case SR_CONF_CLOCK_EDGE: + *data = g_variant_new_strv(signal_edge_names, + ARRAY_SIZE(signal_edge_names)); + break; + default: + return SR_ERR_NA; + } + + return SR_OK; +} + +static int receive_data(int fd, int revents, void *cb_data) +{ + struct timeval tv; + struct drv_context *drvc; + + (void)fd; + (void)revents; + + drvc = (struct drv_context *)cb_data; + + tv.tv_sec = tv.tv_usec = 0; + libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv); + + return TRUE; +} + +static int start_transfers(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + struct sr_usb_dev_inst *usb; + struct libusb_transfer *transfer; + unsigned int i, num_transfers; + int timeout, ret; + unsigned char *buf; + size_t size; + + devc = sdi->priv; + usb = sdi->conn; + + devc->sent_samples = 0; + devc->acq_aborted = FALSE; + devc->empty_transfer_count = 0; + devc->trigger_fired = TRUE; + + num_transfers = dslogic_get_number_of_transfers(devc); + + if (devc->cur_samplerate == SR_MHZ(100)) + num_transfers = 16; + else if (devc->cur_samplerate == SR_MHZ(200)) + num_transfers = 8; + else if (devc->cur_samplerate == SR_MHZ(400)) + num_transfers = 4; + + size = dslogic_get_buffer_size(devc); + devc->submitted_transfers = 0; + + devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers); + if (!devc->transfers) { + sr_err("USB transfers malloc failed."); + return SR_ERR_MALLOC; + } + + timeout = dslogic_get_timeout(devc); + devc->num_transfers = num_transfers; + for (i = 0; i < num_transfers; i++) { + if (!(buf = g_try_malloc(size))) { + sr_err("USB transfer buffer malloc failed."); + return SR_ERR_MALLOC; + } + transfer = libusb_alloc_transfer(0); + libusb_fill_bulk_transfer(transfer, usb->devhdl, + 6 | LIBUSB_ENDPOINT_IN, buf, size, + dslogic_receive_transfer, (void *)sdi, timeout); + sr_info("submitting transfer: %d", i); + if ((ret = libusb_submit_transfer(transfer)) != 0) { + sr_err("Failed to submit transfer: %s.", + libusb_error_name(ret)); + libusb_free_transfer(transfer); + g_free(buf); + dslogic_abort_acquisition(devc); + return SR_ERR; + } + devc->transfers[i] = transfer; + devc->submitted_transfers++; + } + + std_session_send_df_header(sdi); + + return SR_OK; +} + +static void LIBUSB_CALL trigger_receive(struct libusb_transfer *transfer) +{ + const struct sr_dev_inst *sdi; + struct dslogic_trigger_pos *tpos; + struct dev_context *devc; + + sdi = transfer->user_data; + devc = sdi->priv; + if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { + sr_dbg("Trigger transfer canceled."); + /* Terminate session. */ + std_session_send_df_end(sdi); + usb_source_remove(sdi->session, devc->ctx); + devc->num_transfers = 0; + g_free(devc->transfers); + } else if (transfer->status == LIBUSB_TRANSFER_COMPLETED + && transfer->actual_length == sizeof(struct dslogic_trigger_pos)) { + tpos = (struct dslogic_trigger_pos *)transfer->buffer; + sr_info("tpos real_pos %d ram_saddr %d cnt %d", tpos->real_pos, + tpos->ram_saddr, tpos->remain_cnt); + devc->trigger_pos = tpos->real_pos; + g_free(tpos); + start_transfers(sdi); + } + libusb_free_transfer(transfer); +} + +static int trigger_request(const struct sr_dev_inst *sdi) +{ + struct sr_usb_dev_inst *usb; + struct libusb_transfer *transfer; + struct dslogic_trigger_pos *tpos; + struct dev_context *devc; + int ret; + + usb = sdi->conn; + devc = sdi->priv; + + if ((ret = dslogic_stop_acquisition(sdi)) != SR_OK) + return ret; + + if ((ret = dslogic_fpga_configure(sdi)) != SR_OK) + return ret; + + /* If this is a DSLogic Pro, set the voltage threshold. */ + if (!strcmp(devc->profile->model, "DSLogic Pro")){ + if (devc->voltage_threshold == DS_VOLTAGE_RANGE_18_33_V) { + dslogic_set_vth(sdi, 1.4); + } else { + dslogic_set_vth(sdi, 3.3); + } + } + + if ((ret = dslogic_start_acquisition(sdi)) != SR_OK) + return ret; + + sr_dbg("Getting trigger."); + tpos = g_malloc(sizeof(struct dslogic_trigger_pos)); + transfer = libusb_alloc_transfer(0); + libusb_fill_bulk_transfer(transfer, usb->devhdl, 6 | LIBUSB_ENDPOINT_IN, + (unsigned char *)tpos, sizeof(struct dslogic_trigger_pos), + trigger_receive, (void *)sdi, 0); + if ((ret = libusb_submit_transfer(transfer)) < 0) { + sr_err("Failed to request trigger: %s.", libusb_error_name(ret)); + libusb_free_transfer(transfer); + g_free(tpos); + return SR_ERR; + } + + devc->transfers = g_try_malloc0(sizeof(*devc->transfers)); + if (!devc->transfers) { + sr_err("USB trigger_pos transfer malloc failed."); + return SR_ERR_MALLOC; + } + devc->num_transfers = 1; + devc->submitted_transfers++; + devc->transfers[0] = transfer; + + return ret; +} + +static int dev_acquisition_start(const struct sr_dev_inst *sdi) +{ + struct sr_dev_driver *di; + struct drv_context *drvc; + struct dev_context *devc; + int timeout; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR_DEV_CLOSED; + + di = sdi->driver; + drvc = di->context; + devc = sdi->priv; + + devc->ctx = drvc->sr_ctx; + devc->sent_samples = 0; + devc->empty_transfer_count = 0; + devc->acq_aborted = FALSE; + + timeout = dslogic_get_timeout(devc); + usb_source_add(sdi->session, devc->ctx, timeout, receive_data, drvc); + + trigger_request(sdi); + + return SR_OK; +} + +static int dev_acquisition_stop(struct sr_dev_inst *sdi) +{ + dslogic_stop_acquisition(sdi); + + dslogic_abort_acquisition(sdi->priv); + + return SR_OK; +} + +static struct sr_dev_driver dslogic_driver_info = { + .name = "dslogic", + .longname = "DreamSourceLabs DSLogic", + .api_version = 1, + .init = std_init, + .cleanup = std_cleanup, + .scan = scan, + .dev_list = std_dev_list, + .dev_clear = dev_clear, + .config_get = config_get, + .config_set = config_set, + .config_list = config_list, + .dev_open = dev_open, + .dev_close = dev_close, + .dev_acquisition_start = dev_acquisition_start, + .dev_acquisition_stop = dev_acquisition_stop, + .context = NULL, +}; +SR_REGISTER_DEV_DRIVER(dslogic_driver_info); diff --git a/src/hardware/fx2lafw/dslogic.c b/src/hardware/dslogic/dslogic.c similarity index 94% rename from src/hardware/fx2lafw/dslogic.c rename to src/hardware/dslogic/dslogic.c index b913e472..d0a98de2 100644 --- a/src/hardware/fx2lafw/dslogic.c +++ b/src/hardware/dslogic/dslogic.c @@ -133,16 +133,12 @@ SR_PRIV int dslogic_fpga_firmware_upload(const struct sr_dev_inst *sdi, SR_PRIV int dslogic_start_acquisition(const struct sr_dev_inst *sdi) { - struct dev_context *devc; struct sr_usb_dev_inst *usb; struct dslogic_mode mode; int ret; - devc = sdi->priv; - mode.flags = DS_START_FLAGS_MODE_LA; + mode.flags = DS_START_FLAGS_MODE_LA | DS_START_FLAGS_SAMPLE_WIDE; mode.sample_delay_h = mode.sample_delay_l = 0; - if (devc->sample_wide) - mode.flags |= DS_START_FLAGS_SAMPLE_WIDE; usb = sdi->conn; ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR | @@ -216,7 +212,7 @@ static int dslogic_set_trigger(const struct sr_dev_inst *sdi, cfg->trig_glb = 0; - for (i = 1; i < DS_NUM_TRIGGER_STAGES; i++) { + for (i = 1; i < NUM_TRIGGER_STAGES; i++) { cfg->trig_mask0[i] = 0xff; cfg->trig_mask1[i] = 0xff; cfg->trig_value0[i] = 0; @@ -323,22 +319,22 @@ SR_PRIV int dslogic_fpga_configure(const struct sr_dev_inst *sdi) v16 = 0x0000; - if (devc->dslogic_mode == DS_OP_INTERNAL_TEST) + if (devc->mode == DS_OP_INTERNAL_TEST) v16 = DS_MODE_INT_TEST; - else if (devc->dslogic_mode == DS_OP_EXTERNAL_TEST) + else if (devc->mode == DS_OP_EXTERNAL_TEST) v16 = DS_MODE_EXT_TEST; - else if (devc->dslogic_mode == DS_OP_LOOPBACK_TEST) + else if (devc->mode == DS_OP_LOOPBACK_TEST) v16 = DS_MODE_LPB_TEST; - if (devc->dslogic_continuous_mode) + if (devc->continuous_mode) v16 |= DS_MODE_STREAM_MODE; - if (devc->dslogic_external_clock) { + if (devc->external_clock) { v16 |= DS_MODE_CLK_TYPE; - if (devc->dslogic_clock_edge == DS_EDGE_FALLING) + if (devc->clock_edge == DS_EDGE_FALLING) v16 |= DS_MODE_CLK_EDGE; } if (devc->limit_samples > DS_MAX_LOGIC_DEPTH * ceil(devc->cur_samplerate * 1.0 / DS_MAX_LOGIC_SAMPLERATE) - && !devc->dslogic_continuous_mode) { + && !devc->continuous_mode) { /* Enable RLE for long captures. * Without this, captured data present errors. */ @@ -366,9 +362,8 @@ SR_PRIV int dslogic_fpga_configure(const struct sr_dev_inst *sdi) static int to_bytes_per_ms(struct dev_context *devc) { if (devc->cur_samplerate > SR_MHZ(100)) - return SR_MHZ(100) / 1000 * (devc->sample_wide ? 2 : 1); - - return devc->cur_samplerate / 1000 * (devc->sample_wide ? 2 : 1); + return SR_MHZ(100) / 1000 * 2; + return devc->cur_samplerate / 1000 * 2; } static size_t get_buffer_size(struct dev_context *devc) diff --git a/src/hardware/fx2lafw/dslogic.h b/src/hardware/dslogic/dslogic.h similarity index 88% rename from src/hardware/fx2lafw/dslogic.h rename to src/hardware/dslogic/dslogic.h index 675bf7bf..93850107 100644 --- a/src/hardware/fx2lafw/dslogic.h +++ b/src/hardware/dslogic/dslogic.h @@ -18,8 +18,8 @@ * along with this program. If not, see . */ -#ifndef LIBSIGROK_HARDWARE_FX2LAFW_DSLOGIC_H -#define LIBSIGROK_HARDWARE_FX2LAFW_DSLOGIC_H +#ifndef LIBSIGROK_HARDWARE_DSLOGIC_DSLOGIC_H +#define LIBSIGROK_HARDWARE_DSLOGIC_DSLOGIC_H /* Modified protocol commands & flags used by DSLogic */ #define DS_CMD_GET_FW_VERSION 0xb0 @@ -36,7 +36,6 @@ #define DS_CMD_RD_NVM_PRE 0xbb #define DS_CMD_GET_HW_INFO 0xbc -#define DS_NUM_TRIGGER_STAGES 16 #define DS_START_FLAGS_STOP (1 << 7) #define DS_START_FLAGS_CLK_48MHZ (1 << 6) #define DS_START_FLAGS_SAMPLE_WIDE (1 << 5) @@ -134,15 +133,15 @@ struct dslogic_fpga_config { uint16_t ch_en; uint16_t trig_header; - uint16_t trig_mask0[DS_NUM_TRIGGER_STAGES]; - uint16_t trig_mask1[DS_NUM_TRIGGER_STAGES]; - uint16_t trig_value0[DS_NUM_TRIGGER_STAGES]; - uint16_t trig_value1[DS_NUM_TRIGGER_STAGES]; - uint16_t trig_edge0[DS_NUM_TRIGGER_STAGES]; - uint16_t trig_edge1[DS_NUM_TRIGGER_STAGES]; - uint16_t trig_logic0[DS_NUM_TRIGGER_STAGES]; - uint16_t trig_logic1[DS_NUM_TRIGGER_STAGES]; - uint32_t trig_count[DS_NUM_TRIGGER_STAGES]; + uint16_t trig_mask0[NUM_TRIGGER_STAGES]; + uint16_t trig_mask1[NUM_TRIGGER_STAGES]; + uint16_t trig_value0[NUM_TRIGGER_STAGES]; + uint16_t trig_value1[NUM_TRIGGER_STAGES]; + uint16_t trig_edge0[NUM_TRIGGER_STAGES]; + uint16_t trig_edge1[NUM_TRIGGER_STAGES]; + uint16_t trig_logic0[NUM_TRIGGER_STAGES]; + uint16_t trig_logic1[NUM_TRIGGER_STAGES]; + uint32_t trig_count[NUM_TRIGGER_STAGES]; uint32_t end_sync; }; diff --git a/src/hardware/dslogic/protocol.c b/src/hardware/dslogic/protocol.c new file mode 100644 index 00000000..76e82a97 --- /dev/null +++ b/src/hardware/dslogic/protocol.c @@ -0,0 +1,411 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2013 Bert Vermeulen + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include "protocol.h" +#include "dslogic.h" + +#pragma pack(push, 1) + +struct version_info { + uint8_t major; + uint8_t minor; +}; + +struct cmd_start_acquisition { + uint8_t flags; + uint8_t sample_delay_h; + uint8_t sample_delay_l; +}; + +#pragma pack(pop) + +#define USB_TIMEOUT 100 + +static int command_get_fw_version(libusb_device_handle *devhdl, + struct version_info *vi) +{ + int ret; + + ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_ENDPOINT_IN, DS_CMD_GET_FW_VERSION, 0x0000, 0x0000, + (unsigned char *)vi, sizeof(struct version_info), USB_TIMEOUT); + + if (ret < 0) { + sr_err("Unable to get version info: %s.", + libusb_error_name(ret)); + return SR_ERR; + } + + return SR_OK; +} + +static int command_get_revid_version(struct sr_dev_inst *sdi, uint8_t *revid) +{ + struct sr_usb_dev_inst *usb = sdi->conn; + libusb_device_handle *devhdl = usb->devhdl; + int ret; + + ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_ENDPOINT_IN, DS_CMD_GET_REVID_VERSION, 0x0000, 0x0000, + revid, 1, USB_TIMEOUT); + + if (ret < 0) { + sr_err("Unable to get REVID: %s.", libusb_error_name(ret)); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int dslogic_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di) +{ + libusb_device **devlist; + struct sr_usb_dev_inst *usb; + struct libusb_device_descriptor des; + struct dev_context *devc; + struct drv_context *drvc; + struct version_info vi; + int ret, i, device_count; + uint8_t revid; + char connection_id[64]; + + drvc = di->context; + devc = sdi->priv; + usb = sdi->conn; + + if (sdi->status == SR_ST_ACTIVE) + /* Device is already in use. */ + return SR_ERR; + + device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); + if (device_count < 0) { + sr_err("Failed to get device list: %s.", + libusb_error_name(device_count)); + return SR_ERR; + } + + for (i = 0; i < device_count; i++) { + libusb_get_device_descriptor(devlist[i], &des); + + if (des.idVendor != devc->profile->vid + || des.idProduct != devc->profile->pid) + continue; + + if ((sdi->status == SR_ST_INITIALIZING) || + (sdi->status == SR_ST_INACTIVE)) { + /* + * Check device by its physical USB bus/port address. + */ + usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)); + if (strcmp(sdi->connection_id, connection_id)) + /* This is not the one. */ + continue; + } + + if (!(ret = libusb_open(devlist[i], &usb->devhdl))) { + if (usb->address == 0xff) + /* + * First time we touch this device after FW + * upload, so we don't know the address yet. + */ + usb->address = libusb_get_device_address(devlist[i]); + } else { + sr_err("Failed to open device: %s.", + libusb_error_name(ret)); + break; + } + + if (libusb_has_capability(LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER)) { + if (libusb_kernel_driver_active(usb->devhdl, USB_INTERFACE) == 1) { + if ((ret = libusb_detach_kernel_driver(usb->devhdl, USB_INTERFACE)) < 0) { + sr_err("Failed to detach kernel driver: %s.", + libusb_error_name(ret)); + return SR_ERR; + } + } + } + + ret = command_get_fw_version(usb->devhdl, &vi); + if (ret != SR_OK) { + sr_err("Failed to get firmware version."); + break; + } + + ret = command_get_revid_version(sdi, &revid); + if (ret != SR_OK) { + sr_err("Failed to get REVID."); + break; + } + + /* + * Changes in major version mean incompatible/API changes, so + * bail out if we encounter an incompatible version. + * Different minor versions are OK, they should be compatible. + */ + if (vi.major != DSLOGIC_REQUIRED_VERSION_MAJOR) { + sr_err("Expected firmware version %d.x, " + "got %d.%d.", DSLOGIC_REQUIRED_VERSION_MAJOR, + vi.major, vi.minor); + break; + } + + sdi->status = SR_ST_ACTIVE; + sr_info("Opened device on %d.%d (logical) / %s (physical), " + "interface %d, firmware %d.%d.", + usb->bus, usb->address, connection_id, + USB_INTERFACE, vi.major, vi.minor); + + sr_info("Detected REVID=%d, it's a Cypress CY7C68013%s.", + revid, (revid != 1) ? " (FX2)" : "A (FX2LP)"); + + break; + } + libusb_free_device_list(devlist, 1); + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR; + + return SR_OK; +} + +SR_PRIV struct dev_context *dslogic_dev_new(void) +{ + struct dev_context *devc; + + devc = g_malloc0(sizeof(struct dev_context)); + devc->profile = NULL; + devc->fw_updated = 0; + devc->cur_samplerate = 0; + devc->limit_samples = 0; + devc->capture_ratio = 0; + devc->continuous_mode = FALSE; + devc->clock_edge = DS_EDGE_RISING; + + return devc; +} + +SR_PRIV void dslogic_abort_acquisition(struct dev_context *devc) +{ + int i; + + devc->acq_aborted = TRUE; + + for (i = devc->num_transfers - 1; i >= 0; i--) { + if (devc->transfers[i]) + libusb_cancel_transfer(devc->transfers[i]); + } +} + +static void finish_acquisition(struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + + devc = sdi->priv; + + std_session_send_df_end(sdi); + + usb_source_remove(sdi->session, devc->ctx); + + devc->num_transfers = 0; + g_free(devc->transfers); +} + +static void free_transfer(struct libusb_transfer *transfer) +{ + struct sr_dev_inst *sdi; + struct dev_context *devc; + unsigned int i; + + sdi = transfer->user_data; + devc = sdi->priv; + + g_free(transfer->buffer); + transfer->buffer = NULL; + libusb_free_transfer(transfer); + + for (i = 0; i < devc->num_transfers; i++) { + if (devc->transfers[i] == transfer) { + devc->transfers[i] = NULL; + break; + } + } + + devc->submitted_transfers--; + if (devc->submitted_transfers == 0) + finish_acquisition(sdi); +} + +static void resubmit_transfer(struct libusb_transfer *transfer) +{ + int ret; + + if ((ret = libusb_submit_transfer(transfer)) == LIBUSB_SUCCESS) + return; + + sr_err("%s: %s", __func__, libusb_error_name(ret)); + free_transfer(transfer); + +} + +SR_PRIV void dslogic_send_data(struct sr_dev_inst *sdi, + uint8_t *data, size_t length, size_t sample_width) +{ + const struct sr_datafeed_logic logic = { + .length = length, + .unitsize = sample_width, + .data = data + }; + + const struct sr_datafeed_packet packet = { + .type = SR_DF_LOGIC, + .payload = &logic + }; + + sr_session_send(sdi, &packet); +} + +SR_PRIV void LIBUSB_CALL dslogic_receive_transfer(struct libusb_transfer *transfer) +{ + struct sr_dev_inst *sdi; + struct dev_context *devc; + gboolean packet_has_error = FALSE; + struct sr_datafeed_packet packet; + unsigned int num_samples; + int trigger_offset, cur_sample_count; + const int unitsize = 2; + + sdi = transfer->user_data; + devc = sdi->priv; + + /* + * If acquisition has already ended, just free any queued up + * transfer that come in. + */ + if (devc->acq_aborted) { + free_transfer(transfer); + return; + } + + sr_dbg("receive_transfer(): status %s received %d bytes.", + libusb_error_name(transfer->status), transfer->actual_length); + + /* Save incoming transfer before reusing the transfer struct. */ + cur_sample_count = transfer->actual_length / unitsize; + + switch (transfer->status) { + case LIBUSB_TRANSFER_NO_DEVICE: + dslogic_abort_acquisition(devc); + free_transfer(transfer); + return; + case LIBUSB_TRANSFER_COMPLETED: + case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */ + break; + default: + packet_has_error = TRUE; + break; + } + + if (transfer->actual_length == 0 || packet_has_error) { + devc->empty_transfer_count++; + if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) { + /* + * The FX2 gave up. End the acquisition, the frontend + * will work out that the samplecount is short. + */ + dslogic_abort_acquisition(devc); + free_transfer(transfer); + } else { + resubmit_transfer(transfer); + } + return; + } else { + devc->empty_transfer_count = 0; + } + if (devc->trigger_fired) { + if (!devc->limit_samples || devc->sent_samples < devc->limit_samples) { + /* Send the incoming transfer to the session bus. */ + if (devc->limit_samples && devc->sent_samples + cur_sample_count > devc->limit_samples) + num_samples = devc->limit_samples - devc->sent_samples; + else + num_samples = cur_sample_count; + + if (devc->trigger_pos > devc->sent_samples + && devc->trigger_pos <= devc->sent_samples + num_samples) { + /* DSLogic trigger in this block. Send trigger position. */ + trigger_offset = devc->trigger_pos - devc->sent_samples; + /* Pre-trigger samples. */ + dslogic_send_data(sdi, (uint8_t *)transfer->buffer, + trigger_offset * unitsize, unitsize); + devc->sent_samples += trigger_offset; + /* Trigger position. */ + devc->trigger_pos = 0; + packet.type = SR_DF_TRIGGER; + packet.payload = NULL; + sr_session_send(sdi, &packet); + /* Post trigger samples. */ + num_samples -= trigger_offset; + dslogic_send_data(sdi, (uint8_t *)transfer->buffer + + trigger_offset * unitsize, num_samples * unitsize, unitsize); + devc->sent_samples += num_samples; + } else { + dslogic_send_data(sdi, (uint8_t *)transfer->buffer, + num_samples * unitsize, unitsize); + devc->sent_samples += num_samples; + } + } + } + + if (devc->limit_samples && devc->sent_samples >= devc->limit_samples) { + dslogic_abort_acquisition(devc); + free_transfer(transfer); + } else + resubmit_transfer(transfer); +} + +static unsigned int to_bytes_per_ms(unsigned int samplerate) +{ + return samplerate / 1000; +} + +SR_PRIV size_t dslogic_get_buffer_size(struct dev_context *devc) +{ + size_t s; + + /* + * The buffer should be large enough to hold 10ms of data and + * a multiple of 512. + */ + s = 10 * to_bytes_per_ms(devc->cur_samplerate); + return (s + 511) & ~511; +} + +SR_PRIV unsigned int dslogic_get_timeout(struct dev_context *devc) +{ + size_t total_size; + unsigned int timeout; + + total_size = dslogic_get_buffer_size(devc) * + dslogic_get_number_of_transfers(devc); + timeout = total_size / to_bytes_per_ms(devc->cur_samplerate); + return timeout + timeout / 4; /* Leave a headroom of 25% percent. */ +} diff --git a/src/hardware/dslogic/protocol.h b/src/hardware/dslogic/protocol.h new file mode 100644 index 00000000..b5edb96d --- /dev/null +++ b/src/hardware/dslogic/protocol.h @@ -0,0 +1,121 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2013 Bert Vermeulen + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LIBSIGROK_HARDWARE_DSLOGIC_PROTOCOL_H +#define LIBSIGROK_HARDWARE_DSLOGIC_PROTOCOL_H + +#include +#include +#include +#include +#include +#include +#include "libsigrok-internal.h" + +#define LOG_PREFIX "dslogic" + +#define USB_INTERFACE 0 +#define USB_CONFIGURATION 1 + +#define MAX_RENUM_DELAY_MS 3000 +#define NUM_SIMUL_TRANSFERS 32 +#define MAX_EMPTY_TRANSFERS (NUM_SIMUL_TRANSFERS * 2) + +#define NUM_CHANNELS 16 +#define NUM_TRIGGER_STAGES 16 + +#define DSLOGIC_REQUIRED_VERSION_MAJOR 1 + +/* 6 delay states of up to 256 clock ticks */ +#define MAX_SAMPLE_DELAY (6 * 256) + +#define DSLOGIC_FPGA_FIRMWARE_5V "dreamsourcelab-dslogic-fpga-5v.fw" +#define DSLOGIC_FPGA_FIRMWARE_3V3 "dreamsourcelab-dslogic-fpga-3v3.fw" +#define DSCOPE_FPGA_FIRMWARE "dreamsourcelab-dscope-fpga.fw" +#define DSLOGIC_PRO_FPGA_FIRMWARE "dreamsourcelab-dslogic-pro-fpga.fw" +#define DSLOGIC_PLUS_FPGA_FIRMWARE "dreamsourcelab-dslogic-plus-fpga.fw" +#define DSLOGIC_BASIC_FPGA_FIRMWARE "dreamsourcelab-dslogic-basic-fpga.fw" + +struct dslogic_profile { + uint16_t vid; + uint16_t pid; + + const char *vendor; + const char *model; + const char *model_version; + + const char *firmware; + + uint32_t dev_caps; + + const char *usb_manufacturer; + const char *usb_product; +}; + +struct dev_context { + const struct dslogic_profile *profile; + /* + * Since we can't keep track of an dslogic device after upgrading + * the firmware (it renumerates into a different device address + * after the upgrade) this is like a global lock. No device will open + * until a proper delay after the last device was upgraded. + */ + int64_t fw_updated; + + /* Supported samplerates */ + const uint64_t *samplerates; + int num_samplerates; + + /* Device/capture settings */ + uint64_t cur_samplerate; + uint64_t limit_samples; + uint64_t capture_ratio; + + /* Operational settings */ + gboolean trigger_fired; + gboolean acq_aborted; + + unsigned int sent_samples; + int submitted_transfers; + int empty_transfer_count; + + unsigned int num_transfers; + struct libusb_transfer **transfers; + struct sr_context *ctx; + + uint16_t mode; + uint32_t trigger_pos; + gboolean external_clock; + gboolean continuous_mode; + int clock_edge; + int voltage_threshold; +}; + +SR_PRIV int dslogic_command_start_acquisition(const struct sr_dev_inst *sdi); +SR_PRIV int dslogic_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di); +SR_PRIV struct dev_context *dslogic_dev_new(void); +SR_PRIV void dslogic_abort_acquisition(struct dev_context *devc); +SR_PRIV void LIBUSB_CALL dslogic_receive_transfer(struct libusb_transfer *transfer); +SR_PRIV size_t dslogic_get_buffer_size(struct dev_context *devc); +SR_PRIV unsigned int dslogic_get_timeout(struct dev_context *devc); +SR_PRIV void dslogic_send_data(struct sr_dev_inst *sdi, uint8_t *data, + size_t length, size_t sample_width); + +#endif diff --git a/src/hardware/fx2lafw/api.c b/src/hardware/fx2lafw/api.c index 58ed64d7..b6e708b9 100644 --- a/src/hardware/fx2lafw/api.c +++ b/src/hardware/fx2lafw/api.c @@ -20,7 +20,6 @@ #include #include "protocol.h" -#include "dslogic.h" #include static const struct fx2lafw_profile supported_fx2[] = { @@ -54,51 +53,6 @@ static const struct fx2lafw_profile supported_fx2[] = { "fx2lafw-cwav-usbeezx.fw", 0, NULL, NULL}, - /* DreamSourceLab DSLogic (before FW upload) */ - { 0x2a0e, 0x0001, "DreamSourceLab", "DSLogic", NULL, - "dreamsourcelab-dslogic-fx2.fw", - DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, NULL, NULL}, - /* DreamSourceLab DSLogic (after FW upload) */ - { 0x2a0e, 0x0001, "DreamSourceLab", "DSLogic", NULL, - "dreamsourcelab-dslogic-fx2.fw", - DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, "DreamSourceLab", "DSLogic"}, - - /* DreamSourceLab DSCope (before FW upload) */ - { 0x2a0e, 0x0002, "DreamSourceLab", "DSCope", NULL, - "dreamsourcelab-dscope-fx2.fw", - DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, NULL, NULL}, - /* DreamSourceLab DSCope (after FW upload) */ - { 0x2a0e, 0x0002, "DreamSourceLab", "DSCope", NULL, - "dreamsourcelab-dscope-fx2.fw", - DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, "DreamSourceLab", "DSCope"}, - - /* DreamSourceLab DSLogic Pro (before FW upload) */ - { 0x2a0e, 0x0003, "DreamSourceLab", "DSLogic Pro", NULL, - "dreamsourcelab-dslogic-pro-fx2.fw", - DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, NULL, NULL}, - /* DreamSourceLab DSLogic Pro (after FW upload) */ - { 0x2a0e, 0x0003, "DreamSourceLab", "DSLogic Pro", NULL, - "dreamsourcelab-dslogic-pro-fx2.fw", - DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, "DreamSourceLab", "DSLogic"}, - - /* DreamSourceLab DSLogic Plus (before FW upload) */ - { 0x2a0e, 0x0020, "DreamSourceLab", "DSLogic Plus", NULL, - "dreamsourcelab-dslogic-plus-fx2.fw", - DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, NULL, NULL}, - /* DreamSourceLab DSLogic Plus (after FW upload) */ - { 0x2a0e, 0x0020, "DreamSourceLab", "DSLogic Plus", NULL, - "dreamsourcelab-dslogic-plus-fx2.fw", - DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, "DreamSourceLab", "DSLogic"}, - - /* DreamSourceLab DSLogic Basic (before FW upload) */ - { 0x2a0e, 0x0021, "DreamSourceLab", "DSLogic Basic", NULL, - "dreamsourcelab-dslogic-basic-fx2.fw", - DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, NULL, NULL}, - /* DreamSourceLab DSLogic Basic (after FW upload) */ - { 0x2a0e, 0x0021, "DreamSourceLab", "DSLogic Basic", NULL, - "dreamsourcelab-dslogic-basic-fx2.fw", - DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, "DreamSourceLab", "DSLogic"}, - /* * Saleae Logic * EE Electronics ESLA100 @@ -159,18 +113,6 @@ static const uint32_t devopts[] = { SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, }; -static const uint32_t dslogic_devopts[] = { - SR_CONF_CONTINUOUS | SR_CONF_SET | SR_CONF_GET, - SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET, - SR_CONF_VOLTAGE_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, - SR_CONF_CONN | SR_CONF_GET, - SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, - SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, - SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, - SR_CONF_EXTERNAL_CLOCK | SR_CONF_GET | SR_CONF_SET, - SR_CONF_CLOCK_EDGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, -}; - static const int32_t soft_trigger_matches[] = { SR_TRIGGER_ZERO, SR_TRIGGER_ONE, @@ -179,21 +121,6 @@ static const int32_t soft_trigger_matches[] = { SR_TRIGGER_EDGE, }; -/* Names assigned to available edge slope choices. */ -static const char *const signal_edge_names[] = { - [DS_EDGE_RISING] = "rising", - [DS_EDGE_FALLING] = "falling", -}; - -static const struct { - int range; - gdouble low; - gdouble high; -} volt_thresholds[] = { - { DS_VOLTAGE_RANGE_18_33_V, 0.7, 1.4 }, - { DS_VOLTAGE_RANGE_5_V, 1.4, 3.6 }, -}; - static const uint64_t samplerates[] = { SR_KHZ(20), SR_KHZ(25), @@ -213,25 +140,6 @@ static const uint64_t samplerates[] = { SR_MHZ(24), }; -static const uint64_t dslogic_samplerates[] = { - SR_KHZ(10), - SR_KHZ(20), - SR_KHZ(50), - SR_KHZ(100), - SR_KHZ(200), - SR_KHZ(500), - SR_MHZ(1), - SR_MHZ(2), - SR_MHZ(5), - SR_MHZ(10), - SR_MHZ(20), - SR_MHZ(25), - SR_MHZ(50), - SR_MHZ(100), - SR_MHZ(200), - SR_MHZ(400), -}; - static gboolean is_plausible(const struct libusb_device_descriptor *des) { int i; @@ -404,23 +312,10 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) sdi->priv = devc; devices = g_slist_append(devices, sdi); - if (!strcmp(prof->model, "DSLogic") - || !strcmp(prof->model, "DSLogic Pro") - || !strcmp(prof->model, "DSLogic Plus") - || !strcmp(prof->model, "DSLogic Basic") - || !strcmp(prof->model, "DSCope")) { - devc->dslogic = TRUE; - devc->samplerates = dslogic_samplerates; - devc->num_samplerates = ARRAY_SIZE(dslogic_samplerates); - has_firmware = usb_match_manuf_prod(devlist[i], "DreamSourceLab", "DSLogic") - || usb_match_manuf_prod(devlist[i], "DreamSourceLab", "DSCope"); - } else { - devc->dslogic = FALSE; - devc->samplerates = samplerates; - devc->num_samplerates = ARRAY_SIZE(samplerates); - has_firmware = usb_match_manuf_prod(devlist[i], - "sigrok", "fx2lafw"); - } + devc->samplerates = samplerates; + devc->num_samplerates = ARRAY_SIZE(samplerates); + has_firmware = usb_match_manuf_prod(devlist[i], + "sigrok", "fx2lafw"); if (has_firmware) { /* Already has the firmware, so fix the new address. */ @@ -469,7 +364,6 @@ static int dev_open(struct sr_dev_inst *sdi) struct sr_dev_driver *di = sdi->driver; struct sr_usb_dev_inst *usb; struct dev_context *devc; - const char *fpga_firmware = NULL; int ret; int64_t timediff_us, timediff_ms; @@ -529,25 +423,6 @@ static int dev_open(struct sr_dev_inst *sdi) return SR_ERR; } - if (devc->dslogic) { - if (!strcmp(devc->profile->model, "DSLogic")) { - if (devc->dslogic_voltage_threshold == DS_VOLTAGE_RANGE_18_33_V) - fpga_firmware = DSLOGIC_FPGA_FIRMWARE_3V3; - else - fpga_firmware = DSLOGIC_FPGA_FIRMWARE_5V; - } else if (!strcmp(devc->profile->model, "DSLogic Pro")){ - fpga_firmware = DSLOGIC_PRO_FPGA_FIRMWARE; - } else if (!strcmp(devc->profile->model, "DSLogic Plus")){ - fpga_firmware = DSLOGIC_PLUS_FPGA_FIRMWARE; - } else if (!strcmp(devc->profile->model, "DSLogic Basic")){ - fpga_firmware = DSLOGIC_BASIC_FPGA_FIRMWARE; - } else if (!strcmp(devc->profile->model, "DSCope")) { - fpga_firmware = DSCOPE_FPGA_FIRMWARE; - } - - if ((ret = dslogic_fpga_firmware_upload(sdi, fpga_firmware)) != SR_OK) - return ret; - } if (devc->cur_samplerate == 0) { /* Samplerate hasn't been set; default to the slowest one. */ devc->cur_samplerate = devc->samplerates[0]; @@ -580,8 +455,6 @@ static int config_get(uint32_t key, GVariant **data, { struct dev_context *devc; struct sr_usb_dev_inst *usb; - GVariant *range[2]; - unsigned int i; char str[128]; (void)cg; @@ -603,16 +476,6 @@ static int config_get(uint32_t key, GVariant **data, snprintf(str, 128, "%d.%d", usb->bus, usb->address); *data = g_variant_new_string(str); break; - case SR_CONF_VOLTAGE_THRESHOLD: - for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) { - if (volt_thresholds[i].range != devc->dslogic_voltage_threshold) - continue; - range[0] = g_variant_new_double(volt_thresholds[i].low); - range[1] = g_variant_new_double(volt_thresholds[i].high); - *data = g_variant_new_tuple(range, 2); - break; - } - break; case SR_CONF_LIMIT_SAMPLES: *data = g_variant_new_uint64(devc->limit_samples); break; @@ -622,18 +485,6 @@ static int config_get(uint32_t key, GVariant **data, case SR_CONF_CAPTURE_RATIO: *data = g_variant_new_uint64(devc->capture_ratio); break; - case SR_CONF_EXTERNAL_CLOCK: - *data = g_variant_new_boolean(devc->dslogic_external_clock); - break; - case SR_CONF_CONTINUOUS: - *data = g_variant_new_boolean(devc->dslogic_continuous_mode); - break; - case SR_CONF_CLOCK_EDGE: - i = devc->dslogic_clock_edge; - if (i >= ARRAY_SIZE(signal_edge_names)) - return SR_ERR_BUG; - *data = g_variant_new_string(signal_edge_names[0]); - break; default: return SR_ERR_NA; } @@ -641,35 +492,12 @@ static int config_get(uint32_t key, GVariant **data, return SR_OK; } -/* - * Helper for mapping a string-typed configuration value to an index - * within a table of possible values. - */ -static int lookup_index(GVariant *value, const char *const *table, int len) -{ - const char *entry; - int i; - - entry = g_variant_get_string(value, NULL); - if (!entry) - return -1; - - /* Linear search is fine for very small tables. */ - for (i = 0; i < len; i++) { - if (strcmp(entry, table[i]) == 0) - return i; - } - - return -1; -} - static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; uint64_t arg; int i, ret; - gdouble low, high; (void)cg; @@ -702,42 +530,6 @@ static int config_set(uint32_t key, GVariant *data, devc->capture_ratio = g_variant_get_uint64(data); ret = (devc->capture_ratio > 100) ? SR_ERR : SR_OK; break; - case SR_CONF_VOLTAGE_THRESHOLD: - g_variant_get(data, "(dd)", &low, &high); - ret = SR_ERR_ARG; - for (i = 0; (unsigned int)i < ARRAY_SIZE(volt_thresholds); i++) { - if (fabs(volt_thresholds[i].low - low) < 0.1 && - fabs(volt_thresholds[i].high - high) < 0.1) { - devc->dslogic_voltage_threshold = volt_thresholds[i].range; - break; - } - } - if (!strcmp(devc->profile->model, "DSLogic")) { - if (devc->dslogic_voltage_threshold == DS_VOLTAGE_RANGE_5_V) - ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_FPGA_FIRMWARE_5V); - else - ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_FPGA_FIRMWARE_3V3); - } else if (!strcmp(devc->profile->model, "DSLogic Pro")) { - ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_PRO_FPGA_FIRMWARE); - } else if (!strcmp(devc->profile->model, "DSLogic Plus")) { - ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_PLUS_FPGA_FIRMWARE); - } else if (!strcmp(devc->profile->model, "DSLogic Basic")) { - ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_BASIC_FPGA_FIRMWARE); - } - break; - case SR_CONF_EXTERNAL_CLOCK: - devc->dslogic_external_clock = g_variant_get_boolean(data); - break; - case SR_CONF_CONTINUOUS: - devc->dslogic_continuous_mode = g_variant_get_boolean(data); - break; - case SR_CONF_CLOCK_EDGE: - i = lookup_index(data, signal_edge_names, - ARRAY_SIZE(signal_edge_names)); - if (i < 0) - return SR_ERR_ARG; - devc->dslogic_clock_edge = i; - break; default: ret = SR_ERR_NA; } @@ -749,9 +541,8 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; - GVariant *gvar, *range[2]; + GVariant *gvar; GVariantBuilder gvb; - unsigned int i; (void)cg; @@ -766,29 +557,10 @@ static int config_list(uint32_t key, GVariant **data, drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t)); } else { devc = sdi->priv; - if (!devc->dslogic) - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - devopts, ARRAY_SIZE(devopts), sizeof(uint32_t)); - else - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - dslogic_devopts, ARRAY_SIZE(dslogic_devopts), sizeof(uint32_t)); + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, + devopts, ARRAY_SIZE(devopts), sizeof(uint32_t)); } break; - case SR_CONF_VOLTAGE_THRESHOLD: - if (!sdi->priv) - return SR_ERR_ARG; - devc = sdi->priv; - if (!devc->dslogic) - return SR_ERR_NA; - g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY); - for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) { - range[0] = g_variant_new_double(volt_thresholds[i].low); - range[1] = g_variant_new_double(volt_thresholds[i].high); - gvar = g_variant_new_tuple(range, 2); - g_variant_builder_add_value(&gvb, gvar); - } - *data = g_variant_builder_end(&gvb); - break; case SR_CONF_SAMPLERATE: devc = sdi->priv; g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); @@ -802,10 +574,6 @@ static int config_list(uint32_t key, GVariant **data, soft_trigger_matches, ARRAY_SIZE(soft_trigger_matches), sizeof(int32_t)); break; - case SR_CONF_CLOCK_EDGE: - *data = g_variant_new_strv(signal_edge_names, - ARRAY_SIZE(signal_edge_names)); - break; default: return SR_ERR_NA; } @@ -836,7 +604,7 @@ static int start_transfers(const struct sr_dev_inst *sdi) struct sr_trigger *trigger; struct libusb_transfer *transfer; unsigned int i, num_transfers; - int endpoint, timeout, ret; + int timeout, ret; unsigned char *buf; size_t size; @@ -847,7 +615,7 @@ static int start_transfers(const struct sr_dev_inst *sdi) devc->acq_aborted = FALSE; devc->empty_transfer_count = 0; - if ((trigger = sr_session_trigger_get(sdi->session)) && !devc->dslogic) { + if ((trigger = sr_session_trigger_get(sdi->session))) { int pre_trigger_samples = 0; if (devc->limit_samples > 0) pre_trigger_samples = devc->capture_ratio * devc->limit_samples/100; @@ -860,15 +628,6 @@ static int start_transfers(const struct sr_dev_inst *sdi) num_transfers = fx2lafw_get_number_of_transfers(devc); - if (devc->dslogic) { - if (devc->cur_samplerate == SR_MHZ(100)) - num_transfers = 16; - else if (devc->cur_samplerate == SR_MHZ(200)) - num_transfers = 8; - else if (devc->cur_samplerate == SR_MHZ(400)) - num_transfers = 4; - } - size = fx2lafw_get_buffer_size(devc); devc->submitted_transfers = 0; @@ -879,7 +638,6 @@ static int start_transfers(const struct sr_dev_inst *sdi) } timeout = fx2lafw_get_timeout(devc); - endpoint = devc->dslogic ? 6 : 2; devc->num_transfers = num_transfers; for (i = 0; i < num_transfers; i++) { if (!(buf = g_try_malloc(size))) { @@ -888,7 +646,7 @@ static int start_transfers(const struct sr_dev_inst *sdi) } transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(transfer, usb->devhdl, - endpoint | LIBUSB_ENDPOINT_IN, buf, size, + 2 | LIBUSB_ENDPOINT_IN, buf, size, fx2lafw_receive_transfer, (void *)sdi, timeout); sr_info("submitting transfer: %d", i); if ((ret = libusb_submit_transfer(transfer)) != 0) { @@ -918,91 +676,6 @@ static int start_transfers(const struct sr_dev_inst *sdi) return SR_OK; } -static void LIBUSB_CALL dslogic_trigger_receive(struct libusb_transfer *transfer) -{ - const struct sr_dev_inst *sdi; - struct dslogic_trigger_pos *tpos; - struct dev_context *devc; - - sdi = transfer->user_data; - devc = sdi->priv; - if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { - sr_dbg("Trigger transfer canceled."); - /* Terminate session. */ - std_session_send_df_end(sdi); - usb_source_remove(sdi->session, devc->ctx); - devc->num_transfers = 0; - g_free(devc->transfers); - if (devc->stl) { - soft_trigger_logic_free(devc->stl); - devc->stl = NULL; - } - } else if (transfer->status == LIBUSB_TRANSFER_COMPLETED - && transfer->actual_length == sizeof(struct dslogic_trigger_pos)) { - tpos = (struct dslogic_trigger_pos *)transfer->buffer; - sr_info("tpos real_pos %d ram_saddr %d cnt %d", tpos->real_pos, - tpos->ram_saddr, tpos->remain_cnt); - devc->trigger_pos = tpos->real_pos; - g_free(tpos); - start_transfers(sdi); - } - libusb_free_transfer(transfer); -} - -static int dslogic_trigger_request(const struct sr_dev_inst *sdi) -{ - struct sr_usb_dev_inst *usb; - struct libusb_transfer *transfer; - struct dslogic_trigger_pos *tpos; - struct dev_context *devc; - int ret; - - usb = sdi->conn; - devc = sdi->priv; - - if ((ret = dslogic_stop_acquisition(sdi)) != SR_OK) - return ret; - - if ((ret = dslogic_fpga_configure(sdi)) != SR_OK) - return ret; - - /* If this is a DSLogic Pro, set the voltage threshold. */ - if (!strcmp(devc->profile->model, "DSLogic Pro")){ - if (devc->dslogic_voltage_threshold == DS_VOLTAGE_RANGE_18_33_V) { - dslogic_set_vth(sdi, 1.4); - } else { - dslogic_set_vth(sdi, 3.3); - } - } - - if ((ret = dslogic_start_acquisition(sdi)) != SR_OK) - return ret; - - sr_dbg("Getting trigger."); - tpos = g_malloc(sizeof(struct dslogic_trigger_pos)); - transfer = libusb_alloc_transfer(0); - libusb_fill_bulk_transfer(transfer, usb->devhdl, 6 | LIBUSB_ENDPOINT_IN, - (unsigned char *)tpos, sizeof(struct dslogic_trigger_pos), - dslogic_trigger_receive, (void *)sdi, 0); - if ((ret = libusb_submit_transfer(transfer)) < 0) { - sr_err("Failed to request trigger: %s.", libusb_error_name(ret)); - libusb_free_transfer(transfer); - g_free(tpos); - return SR_ERR; - } - - devc->transfers = g_try_malloc0(sizeof(*devc->transfers)); - if (!devc->transfers) { - sr_err("USB trigger_pos transfer malloc failed."); - return SR_ERR_MALLOC; - } - devc->num_transfers = 1; - devc->submitted_transfers++; - devc->transfers[0] = transfer; - - return ret; -} - static int configure_channels(const struct sr_dev_inst *sdi) { struct dev_context *devc; @@ -1030,12 +703,9 @@ static int configure_channels(const struct sr_dev_inst *sdi) /* * Use wide sampling if either any of the LA channels 8..15 is enabled, - * and/or at least one analog channel is enabled, and/or the device - * is running DSLogic firmware (not fx2lafw). + * and/or at least one analog channel is enabled. */ - devc->sample_wide = (channel_mask > 0xff - || num_analog > 0 - || (devc->profile->dev_caps & DEV_CAPS_DSLOGIC_FW)); + devc->sample_wide = channel_mask > 0xff || num_analog > 0; return SR_OK; } @@ -1068,22 +738,18 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) timeout = fx2lafw_get_timeout(devc); usb_source_add(sdi->session, devc->ctx, timeout, receive_data, drvc); - if (devc->dslogic) { - dslogic_trigger_request(sdi); - } else { - size = fx2lafw_get_buffer_size(devc); - /* Prepare for analog sampling. */ - if (g_slist_length(devc->enabled_analog_channels) > 0) { - /* We need a buffer half the size of a transfer. */ - devc->logic_buffer = g_try_malloc(size / 2); - devc->analog_buffer = g_try_malloc( - sizeof(float) * size / 2); - } - start_transfers(sdi); - if ((ret = fx2lafw_command_start_acquisition(sdi)) != SR_OK) { - fx2lafw_abort_acquisition(devc); - return ret; - } + size = fx2lafw_get_buffer_size(devc); + /* Prepare for analog sampling. */ + if (g_slist_length(devc->enabled_analog_channels) > 0) { + /* We need a buffer half the size of a transfer. */ + devc->logic_buffer = g_try_malloc(size / 2); + devc->analog_buffer = g_try_malloc( + sizeof(float) * size / 2); + } + start_transfers(sdi); + if ((ret = fx2lafw_command_start_acquisition(sdi)) != SR_OK) { + fx2lafw_abort_acquisition(devc); + return ret; } return SR_OK; @@ -1091,13 +757,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) static int dev_acquisition_stop(struct sr_dev_inst *sdi) { - struct dev_context *devc; - - devc = sdi->priv; - - if (devc->dslogic) - dslogic_stop_acquisition(sdi); - fx2lafw_abort_acquisition(sdi->priv); return SR_OK; diff --git a/src/hardware/fx2lafw/protocol.c b/src/hardware/fx2lafw/protocol.c index 6aca1808..9ca749a5 100644 --- a/src/hardware/fx2lafw/protocol.c +++ b/src/hardware/fx2lafw/protocol.c @@ -22,7 +22,6 @@ #include #include #include "protocol.h" -#include "dslogic.h" #pragma pack(push, 1) @@ -61,14 +60,13 @@ static int command_get_fw_version(libusb_device_handle *devhdl, static int command_get_revid_version(struct sr_dev_inst *sdi, uint8_t *revid) { - struct dev_context *devc = sdi->priv; struct sr_usb_dev_inst *usb = sdi->conn; libusb_device_handle *devhdl = usb->devhdl; - int cmd, ret; + int ret; - cmd = devc->dslogic ? DS_CMD_GET_REVID_VERSION : CMD_GET_REVID_VERSION; ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR | - LIBUSB_ENDPOINT_IN, cmd, 0x0000, 0x0000, revid, 1, USB_TIMEOUT); + LIBUSB_ENDPOINT_IN, CMD_GET_REVID_VERSION, 0x0000, 0x0000, + revid, 1, USB_TIMEOUT); if (ret < 0) { sr_err("Unable to get REVID: %s.", libusb_error_name(ret)); @@ -263,8 +261,6 @@ SR_PRIV struct dev_context *fx2lafw_dev_new(void) devc->limit_samples = 0; devc->capture_ratio = 0; devc->sample_wide = FALSE; - devc->dslogic_continuous_mode = FALSE; - devc->dslogic_clock_edge = DS_EDGE_RISING; devc->stl = NULL; return devc; @@ -418,7 +414,6 @@ SR_PRIV void LIBUSB_CALL fx2lafw_receive_transfer(struct libusb_transfer *transf struct sr_dev_inst *sdi; struct dev_context *devc; gboolean packet_has_error = FALSE; - struct sr_datafeed_packet packet; unsigned int num_samples; int trigger_offset, cur_sample_count, unitsize; int pre_trigger_samples; @@ -479,29 +474,9 @@ SR_PRIV void LIBUSB_CALL fx2lafw_receive_transfer(struct libusb_transfer *transf else num_samples = cur_sample_count; - if (devc->dslogic && devc->trigger_pos > devc->sent_samples - && devc->trigger_pos <= devc->sent_samples + num_samples) { - /* DSLogic trigger in this block. Send trigger position. */ - trigger_offset = devc->trigger_pos - devc->sent_samples; - /* Pre-trigger samples. */ - devc->send_data_proc(sdi, (uint8_t *)transfer->buffer, - trigger_offset * unitsize, unitsize); - devc->sent_samples += trigger_offset; - /* Trigger position. */ - devc->trigger_pos = 0; - packet.type = SR_DF_TRIGGER; - packet.payload = NULL; - sr_session_send(sdi, &packet); - /* Post trigger samples. */ - num_samples -= trigger_offset; - devc->send_data_proc(sdi, (uint8_t *)transfer->buffer - + trigger_offset * unitsize, num_samples * unitsize, unitsize); - devc->sent_samples += num_samples; - } else { - devc->send_data_proc(sdi, (uint8_t *)transfer->buffer, - num_samples * unitsize, unitsize); - devc->sent_samples += num_samples; - } + devc->send_data_proc(sdi, (uint8_t *)transfer->buffer, + num_samples * unitsize, unitsize); + devc->sent_samples += num_samples; } } else { trigger_offset = soft_trigger_logic_check(devc->stl, @@ -550,9 +525,6 @@ SR_PRIV unsigned int fx2lafw_get_number_of_transfers(struct dev_context *devc) { unsigned int n; - if (devc->dslogic) - return dslogic_get_number_of_transfers(devc); - /* Total buffer size should be able to hold about 500ms of data. */ n = (500 * to_bytes_per_ms(devc->cur_samplerate) / fx2lafw_get_buffer_size(devc)); diff --git a/src/hardware/fx2lafw/protocol.h b/src/hardware/fx2lafw/protocol.h index 6113af8f..a18696c6 100644 --- a/src/hardware/fx2lafw/protocol.h +++ b/src/hardware/fx2lafw/protocol.h @@ -51,18 +51,9 @@ #define DEV_CAPS_16BIT_POS 0 #define DEV_CAPS_AX_ANALOG_POS 1 -#define DEV_CAPS_DSLOGIC_FW_POS 2 #define DEV_CAPS_16BIT (1 << DEV_CAPS_16BIT_POS) #define DEV_CAPS_AX_ANALOG (1 << DEV_CAPS_AX_ANALOG_POS) -#define DEV_CAPS_DSLOGIC_FW (1 << DEV_CAPS_DSLOGIC_FW_POS) - -#define DSLOGIC_FPGA_FIRMWARE_5V "dreamsourcelab-dslogic-fpga-5v.fw" -#define DSLOGIC_FPGA_FIRMWARE_3V3 "dreamsourcelab-dslogic-fpga-3v3.fw" -#define DSCOPE_FPGA_FIRMWARE "dreamsourcelab-dscope-fpga.fw" -#define DSLOGIC_PRO_FPGA_FIRMWARE "dreamsourcelab-dslogic-pro-fpga.fw" -#define DSLOGIC_PLUS_FPGA_FIRMWARE "dreamsourcelab-dslogic-plus-fpga.fw" -#define DSLOGIC_BASIC_FPGA_FIRMWARE "dreamsourcelab-dslogic-basic-fpga.fw" /* Protocol commands */ #define CMD_GET_FW_VERSION 0xb0 @@ -133,15 +124,6 @@ struct dev_context { uint8_t *data, size_t length, size_t sample_width); uint8_t *logic_buffer; float *analog_buffer; - - /* Is this a DSLogic? */ - gboolean dslogic; - uint16_t dslogic_mode; - uint32_t trigger_pos; - gboolean dslogic_external_clock; - gboolean dslogic_continuous_mode; - int dslogic_clock_edge; - int dslogic_voltage_threshold; }; SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi);