From: Joel Holdsworth Date: Sat, 10 Jun 2017 00:02:29 +0000 (-0600) Subject: fx2lafw/dslogic: Split DSLogic into a separate driver X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=adcb9951f8a52852e65f99d45083a3e6b9a1981a;p=libsigrok.git fx2lafw/dslogic: Split DSLogic into a separate driver --- 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/dslogic/dslogic.c b/src/hardware/dslogic/dslogic.c new file mode 100644 index 00000000..d0a98de2 --- /dev/null +++ b/src/hardware/dslogic/dslogic.c @@ -0,0 +1,394 @@ +/* + * 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 +#include "protocol.h" +#include "dslogic.h" + +/* + * This should be larger than the FPGA bitstream image so that it'll get + * uploaded in one big operation. There seem to be issues when uploading + * it in chunks. + */ +#define FW_BUFSIZE (1024 * 1024) + +#define FPGA_UPLOAD_DELAY (10 * 1000) + +#define USB_TIMEOUT (3 * 1000) + +SR_PRIV int dslogic_set_vth(const struct sr_dev_inst *sdi, double vth) +{ + struct sr_usb_dev_inst *usb; + int ret; + const uint8_t value = (vth / 5.0) * 255; + const uint16_t cmd = value | (DS_ADDR_VTH << 8); + + usb = sdi->conn; + + /* Send the control command. */ + ret = libusb_control_transfer(usb->devhdl, + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, + DS_CMD_WR_REG, 0x0000, 0x0000, + (unsigned char *)&cmd, sizeof(cmd), 3000); + if (ret < 0) { + sr_err("Unable to send VTH command: %s.", + libusb_error_name(ret)); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int dslogic_fpga_firmware_upload(const struct sr_dev_inst *sdi, + const char *name) +{ + uint64_t sum; + struct sr_resource bitstream; + struct drv_context *drvc; + struct sr_usb_dev_inst *usb; + unsigned char *buf; + ssize_t chunksize; + int transferred; + int result, ret; + const uint8_t cmd[3] = {0, 0, 0}; + + drvc = sdi->driver->context; + usb = sdi->conn; + + sr_dbg("Uploading FPGA firmware '%s'.", name); + + result = sr_resource_open(drvc->sr_ctx, &bitstream, + SR_RESOURCE_FIRMWARE, name); + if (result != SR_OK) + return result; + + /* Tell the device firmware is coming. */ + if ((ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_ENDPOINT_OUT, DS_CMD_CONFIG, 0x0000, 0x0000, + (unsigned char *)&cmd, sizeof(cmd), USB_TIMEOUT)) < 0) { + sr_err("Failed to upload FPGA firmware: %s.", libusb_error_name(ret)); + sr_resource_close(drvc->sr_ctx, &bitstream); + return SR_ERR; + } + + /* Give the FX2 time to get ready for FPGA firmware upload. */ + g_usleep(FPGA_UPLOAD_DELAY); + + buf = g_malloc(FW_BUFSIZE); + sum = 0; + result = SR_OK; + while (1) { + chunksize = sr_resource_read(drvc->sr_ctx, &bitstream, + buf, FW_BUFSIZE); + if (chunksize < 0) + result = SR_ERR; + if (chunksize <= 0) + break; + + if ((ret = libusb_bulk_transfer(usb->devhdl, 2 | LIBUSB_ENDPOINT_OUT, + buf, chunksize, &transferred, USB_TIMEOUT)) < 0) { + sr_err("Unable to configure FPGA firmware: %s.", + libusb_error_name(ret)); + result = SR_ERR; + break; + } + sum += transferred; + sr_spew("Uploaded %" PRIu64 "/%" PRIu64 " bytes.", + sum, bitstream.size); + + if (transferred != chunksize) { + sr_err("Short transfer while uploading FPGA firmware."); + result = SR_ERR; + break; + } + } + g_free(buf); + sr_resource_close(drvc->sr_ctx, &bitstream); + + if (result == SR_OK) + sr_dbg("FPGA firmware upload done."); + + return result; +} + +SR_PRIV int dslogic_start_acquisition(const struct sr_dev_inst *sdi) +{ + struct sr_usb_dev_inst *usb; + struct dslogic_mode mode; + int ret; + + mode.flags = DS_START_FLAGS_MODE_LA | DS_START_FLAGS_SAMPLE_WIDE; + mode.sample_delay_h = mode.sample_delay_l = 0; + + usb = sdi->conn; + ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_ENDPOINT_OUT, DS_CMD_START, 0x0000, 0x0000, + (unsigned char *)&mode, sizeof(mode), USB_TIMEOUT); + if (ret < 0) { + sr_err("Failed to send start command: %s.", libusb_error_name(ret)); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int dslogic_stop_acquisition(const struct sr_dev_inst *sdi) +{ + struct sr_usb_dev_inst *usb; + struct dslogic_mode mode; + int ret; + + mode.flags = DS_START_FLAGS_STOP; + mode.sample_delay_h = mode.sample_delay_l = 0; + + usb = sdi->conn; + ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_ENDPOINT_OUT, DS_CMD_START, 0x0000, 0x0000, + (unsigned char *)&mode, sizeof(struct dslogic_mode), USB_TIMEOUT); + if (ret < 0) { + sr_err("Failed to send stop command: %s.", libusb_error_name(ret)); + return SR_ERR; + } + + return SR_OK; +} + +/* + * Get the session trigger and configure the FPGA structure + * accordingly. + */ +static int dslogic_set_trigger(const struct sr_dev_inst *sdi, + struct dslogic_fpga_config *cfg) +{ + struct sr_trigger *trigger; + struct sr_trigger_stage *stage; + struct sr_trigger_match *match; + struct dev_context *devc; + const GSList *l, *m; + int channelbit, i = 0; + uint16_t v16; + + devc = sdi->priv; + + cfg->ch_en = 0; + for (l = sdi->channels; l; l = l->next) { + const struct sr_channel *const probe = (struct sr_channel *)l->data; + cfg->ch_en |= probe->enabled << probe->index; + } + + cfg->trig_mask0[0] = 0xffff; + cfg->trig_mask1[0] = 0xffff; + + cfg->trig_value0[0] = 0; + cfg->trig_value1[0] = 0; + + cfg->trig_edge0[0] = 0; + cfg->trig_edge1[0] = 0; + + cfg->trig_logic0[0] = 0; + cfg->trig_logic1[0] = 0; + + cfg->trig_count[0] = 0; + + cfg->trig_glb = 0; + + for (i = 1; i < NUM_TRIGGER_STAGES; i++) { + cfg->trig_mask0[i] = 0xff; + cfg->trig_mask1[i] = 0xff; + cfg->trig_value0[i] = 0; + cfg->trig_value1[i] = 0; + cfg->trig_edge0[i] = 0; + cfg->trig_edge1[i] = 0; + cfg->trig_logic0[i] = 2; + cfg->trig_logic1[i] = 2; + cfg->trig_count[i] = 0; + } + + cfg->trig_pos = (uint32_t)(devc->capture_ratio / 100.0 * devc->limit_samples); + sr_dbg("pos: %d", cfg->trig_pos); + + sr_dbg("configuring trigger"); + + if (!(trigger = sr_session_trigger_get(sdi->session))) { + sr_dbg("No session trigger found"); + return SR_OK; + } + + for (l = trigger->stages; l; l = l->next) { + stage = l->data; + for (m = stage->matches; m; m = m->next) { + match = m->data; + if (!match->channel->enabled) + /* Ignore disabled channels with a trigger. */ + continue; + channelbit = 1 << (match->channel->index); + /* Simple trigger support (event). */ + if (match->match == SR_TRIGGER_ONE) { + cfg->trig_mask0[0] &= ~channelbit; + cfg->trig_mask1[0] &= ~channelbit; + cfg->trig_value0[0] |= channelbit; + cfg->trig_value1[0] |= channelbit; + } else if (match->match == SR_TRIGGER_ZERO) { + cfg->trig_mask0[0] &= ~channelbit; + cfg->trig_mask1[0] &= ~channelbit; + } else if (match->match == SR_TRIGGER_FALLING) { + cfg->trig_mask0[0] &= ~channelbit; + cfg->trig_mask1[0] &= ~channelbit; + cfg->trig_edge0[0] |= channelbit; + cfg->trig_edge1[0] |= channelbit; + } else if (match->match == SR_TRIGGER_RISING) { + cfg->trig_mask0[0] &= ~channelbit; + cfg->trig_mask1[0] &= ~channelbit; + cfg->trig_value0[0] |= channelbit; + cfg->trig_value1[0] |= channelbit; + cfg->trig_edge0[0] |= channelbit; + cfg->trig_edge1[0] |= channelbit; + } else if (match->match == SR_TRIGGER_EDGE) { + cfg->trig_edge0[0] |= channelbit; + cfg->trig_edge1[0] |= channelbit; + } + } + } + + v16 = RL16(&cfg->mode); + v16 |= 1 << 0; + WL16(&cfg->mode, v16); + + return SR_OK; +} + +SR_PRIV int dslogic_fpga_configure(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + struct sr_usb_dev_inst *usb; + uint8_t c[3]; + struct dslogic_fpga_config cfg; + uint16_t v16; + uint32_t v32; + int transferred, len, ret; + + sr_dbg("Configuring FPGA."); + + usb = sdi->conn; + devc = sdi->priv; + + WL32(&cfg.sync, DS_CFG_START); + WL16(&cfg.mode_header, DS_CFG_MODE); + WL16(&cfg.divider_header, DS_CFG_DIVIDER); + WL16(&cfg.count_header, DS_CFG_COUNT); + WL16(&cfg.trig_pos_header, DS_CFG_TRIG_POS); + WL16(&cfg.trig_glb_header, DS_CFG_TRIG_GLB); + WL16(&cfg.ch_en_header, DS_CFG_CH_EN); + WL16(&cfg.trig_header, DS_CFG_TRIG); + WL32(&cfg.end_sync, DS_CFG_END); + + /* Pass in the length of a fixed-size struct. Really. */ + len = sizeof(struct dslogic_fpga_config) / 2; + c[0] = len & 0xff; + c[1] = (len >> 8) & 0xff; + c[2] = (len >> 16) & 0xff; + + ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_ENDPOINT_OUT, DS_CMD_SETTING, 0x0000, 0x0000, + c, sizeof(c), USB_TIMEOUT); + if (ret < 0) { + sr_err("Failed to send FPGA configure command: %s.", + libusb_error_name(ret)); + return SR_ERR; + } + + v16 = 0x0000; + + if (devc->mode == DS_OP_INTERNAL_TEST) + v16 = DS_MODE_INT_TEST; + else if (devc->mode == DS_OP_EXTERNAL_TEST) + v16 = DS_MODE_EXT_TEST; + else if (devc->mode == DS_OP_LOOPBACK_TEST) + v16 = DS_MODE_LPB_TEST; + if (devc->continuous_mode) + v16 |= DS_MODE_STREAM_MODE; + if (devc->external_clock) { + v16 |= DS_MODE_CLK_TYPE; + 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->continuous_mode) { + /* Enable RLE for long captures. + * Without this, captured data present errors. + */ + v16 |= DS_MODE_RLE_MODE; + } + + WL16(&cfg.mode, v16); + v32 = ceil(DS_MAX_LOGIC_SAMPLERATE * 1.0 / devc->cur_samplerate); + WL32(&cfg.divider, v32); + WL32(&cfg.count, devc->limit_samples); + + dslogic_set_trigger(sdi, &cfg); + + len = sizeof(struct dslogic_fpga_config); + ret = libusb_bulk_transfer(usb->devhdl, 2 | LIBUSB_ENDPOINT_OUT, + (unsigned char *)&cfg, len, &transferred, USB_TIMEOUT); + if (ret < 0 || transferred != len) { + sr_err("Failed to send FPGA configuration: %s.", libusb_error_name(ret)); + return SR_ERR; + } + + return SR_OK; +} + +static int to_bytes_per_ms(struct dev_context *devc) +{ + if (devc->cur_samplerate > SR_MHZ(100)) + return SR_MHZ(100) / 1000 * 2; + return devc->cur_samplerate / 1000 * 2; +} + +static size_t 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); + // s = to_bytes_per_ms(devc->cur_samplerate); + return (s + 511) & ~511; +} + +SR_PRIV int dslogic_get_number_of_transfers(struct dev_context *devc) +{ + unsigned int n; + + /* Total buffer size should be able to hold about 100ms of data. */ + n = (100 * to_bytes_per_ms(devc) / get_buffer_size(devc)); + sr_info("New calculation: %d", n); + + if (n > NUM_SIMUL_TRANSFERS) + return NUM_SIMUL_TRANSFERS; + + return n; +} diff --git a/src/hardware/dslogic/dslogic.h b/src/hardware/dslogic/dslogic.h new file mode 100644 index 00000000..93850107 --- /dev/null +++ b/src/hardware/dslogic/dslogic.h @@ -0,0 +1,159 @@ +/* + * 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_DSLOGIC_H +#define LIBSIGROK_HARDWARE_DSLOGIC_DSLOGIC_H + +/* Modified protocol commands & flags used by DSLogic */ +#define DS_CMD_GET_FW_VERSION 0xb0 +#define DS_CMD_GET_REVID_VERSION 0xb1 +#define DS_CMD_START 0xb2 +#define DS_CMD_CONFIG 0xb3 +#define DS_CMD_SETTING 0xb4 +#define DS_CMD_CONTROL 0xb5 +#define DS_CMD_STATUS 0xb6 +#define DS_CMD_STATUS_INFO 0xb7 +#define DS_CMD_WR_REG 0xb8 +#define DS_CMD_WR_NVM 0xb9 +#define DS_CMD_RD_NVM 0xba +#define DS_CMD_RD_NVM_PRE 0xbb +#define DS_CMD_GET_HW_INFO 0xbc + +#define DS_START_FLAGS_STOP (1 << 7) +#define DS_START_FLAGS_CLK_48MHZ (1 << 6) +#define DS_START_FLAGS_SAMPLE_WIDE (1 << 5) +#define DS_START_FLAGS_MODE_LA (1 << 4) + +#define DS_ADDR_COMB 0x68 +#define DS_ADDR_EEWP 0x70 +#define DS_ADDR_VTH 0x78 + +#define DS_MAX_LOGIC_DEPTH SR_MHZ(16) +#define DS_MAX_LOGIC_SAMPLERATE SR_MHZ(100) + +#define DS_MODE_TRIG_EN (1 << 0) +#define DS_MODE_CLK_TYPE (1 << 1) +#define DS_MODE_CLK_EDGE (1 << 2) +#define DS_MODE_RLE_MODE (1 << 3) +#define DS_MODE_DSO_MODE (1 << 4) +#define DS_MODE_HALF_MODE (1 << 5) +#define DS_MODE_QUAR_MODE (1 << 6) +#define DS_MODE_ANALOG_MODE (1 << 7) +#define DS_MODE_FILTER (1 << 8) +#define DS_MODE_INSTANT (1 << 9) +#define DS_MODE_STRIG_MODE (1 << 11) +#define DS_MODE_STREAM_MODE (1 << 12) +#define DS_MODE_LPB_TEST (1 << 13) +#define DS_MODE_EXT_TEST (1 << 14) +#define DS_MODE_INT_TEST (1 << 15) + +enum dslogic_operation_modes { + DS_OP_NORMAL, + DS_OP_INTERNAL_TEST, + DS_OP_EXTERNAL_TEST, + DS_OP_LOOPBACK_TEST, +}; + +enum { + DS_VOLTAGE_RANGE_18_33_V, /* 1.8V and 3.3V logic */ + DS_VOLTAGE_RANGE_5_V, /* 5V logic */ +}; + +enum { + DS_EDGE_RISING, + DS_EDGE_FALLING, +}; + +struct dslogic_version { + uint8_t major; + uint8_t minor; +}; + +struct dslogic_mode { + uint8_t flags; + uint8_t sample_delay_h; + uint8_t sample_delay_l; +}; + +struct dslogic_trigger_pos { + uint32_t real_pos; + uint32_t ram_saddr; + uint32_t remain_cnt; + uint8_t first_block[500]; +}; + +/* + * The FPGA is configured with TLV tuples. Length is specified as the + * number of 16-bit words. + */ +#define _DS_CFG(variable, wordcnt) ((variable << 8) | wordcnt) +#define DS_CFG_START 0xf5a5f5a5 +#define DS_CFG_MODE _DS_CFG(0, 1) +#define DS_CFG_DIVIDER _DS_CFG(1, 2) +#define DS_CFG_COUNT _DS_CFG(3, 2) +#define DS_CFG_TRIG_POS _DS_CFG(5, 2) +#define DS_CFG_TRIG_GLB _DS_CFG(7, 1) +#define DS_CFG_CH_EN _DS_CFG(8, 1) +#define DS_CFG_TRIG _DS_CFG(64, 160) +#define DS_CFG_END 0xfa5afa5a + +#pragma pack(push, 1) + +struct dslogic_fpga_config { + uint32_t sync; + + uint16_t mode_header; + uint16_t mode; + uint16_t divider_header; + uint32_t divider; + uint16_t count_header; + uint32_t count; + uint16_t trig_pos_header; + uint32_t trig_pos; + uint16_t trig_glb_header; + uint16_t trig_glb; + uint16_t ch_en_header; + uint16_t ch_en; + + uint16_t trig_header; + 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; +}; + +#pragma pack(pop) + +SR_PRIV int dslogic_fpga_firmware_upload(const struct sr_dev_inst *sdi, + const char *name); +SR_PRIV int dslogic_start_acquisition(const struct sr_dev_inst *sdi); +SR_PRIV int dslogic_stop_acquisition(const struct sr_dev_inst *sdi); +SR_PRIV int dslogic_fpga_configure(const struct sr_dev_inst *sdi); +SR_PRIV int dslogic_set_vth(const struct sr_dev_inst *sdi, double vth); +SR_PRIV int dslogic_get_number_of_transfers(struct dev_context *devc); + +#endif 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,28 +557,9 @@ 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)); - } - 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_new_fixed_array(G_VARIANT_TYPE_UINT32, + devopts, ARRAY_SIZE(devopts), sizeof(uint32_t)); } - *data = g_variant_builder_end(&gvb); break; case SR_CONF_SAMPLERATE: devc = sdi->priv; @@ -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/dslogic.c b/src/hardware/fx2lafw/dslogic.c deleted file mode 100644 index b913e472..00000000 --- a/src/hardware/fx2lafw/dslogic.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * 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 -#include "protocol.h" -#include "dslogic.h" - -/* - * This should be larger than the FPGA bitstream image so that it'll get - * uploaded in one big operation. There seem to be issues when uploading - * it in chunks. - */ -#define FW_BUFSIZE (1024 * 1024) - -#define FPGA_UPLOAD_DELAY (10 * 1000) - -#define USB_TIMEOUT (3 * 1000) - -SR_PRIV int dslogic_set_vth(const struct sr_dev_inst *sdi, double vth) -{ - struct sr_usb_dev_inst *usb; - int ret; - const uint8_t value = (vth / 5.0) * 255; - const uint16_t cmd = value | (DS_ADDR_VTH << 8); - - usb = sdi->conn; - - /* Send the control command. */ - ret = libusb_control_transfer(usb->devhdl, - LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, - DS_CMD_WR_REG, 0x0000, 0x0000, - (unsigned char *)&cmd, sizeof(cmd), 3000); - if (ret < 0) { - sr_err("Unable to send VTH command: %s.", - libusb_error_name(ret)); - return SR_ERR; - } - - return SR_OK; -} - -SR_PRIV int dslogic_fpga_firmware_upload(const struct sr_dev_inst *sdi, - const char *name) -{ - uint64_t sum; - struct sr_resource bitstream; - struct drv_context *drvc; - struct sr_usb_dev_inst *usb; - unsigned char *buf; - ssize_t chunksize; - int transferred; - int result, ret; - const uint8_t cmd[3] = {0, 0, 0}; - - drvc = sdi->driver->context; - usb = sdi->conn; - - sr_dbg("Uploading FPGA firmware '%s'.", name); - - result = sr_resource_open(drvc->sr_ctx, &bitstream, - SR_RESOURCE_FIRMWARE, name); - if (result != SR_OK) - return result; - - /* Tell the device firmware is coming. */ - if ((ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR | - LIBUSB_ENDPOINT_OUT, DS_CMD_CONFIG, 0x0000, 0x0000, - (unsigned char *)&cmd, sizeof(cmd), USB_TIMEOUT)) < 0) { - sr_err("Failed to upload FPGA firmware: %s.", libusb_error_name(ret)); - sr_resource_close(drvc->sr_ctx, &bitstream); - return SR_ERR; - } - - /* Give the FX2 time to get ready for FPGA firmware upload. */ - g_usleep(FPGA_UPLOAD_DELAY); - - buf = g_malloc(FW_BUFSIZE); - sum = 0; - result = SR_OK; - while (1) { - chunksize = sr_resource_read(drvc->sr_ctx, &bitstream, - buf, FW_BUFSIZE); - if (chunksize < 0) - result = SR_ERR; - if (chunksize <= 0) - break; - - if ((ret = libusb_bulk_transfer(usb->devhdl, 2 | LIBUSB_ENDPOINT_OUT, - buf, chunksize, &transferred, USB_TIMEOUT)) < 0) { - sr_err("Unable to configure FPGA firmware: %s.", - libusb_error_name(ret)); - result = SR_ERR; - break; - } - sum += transferred; - sr_spew("Uploaded %" PRIu64 "/%" PRIu64 " bytes.", - sum, bitstream.size); - - if (transferred != chunksize) { - sr_err("Short transfer while uploading FPGA firmware."); - result = SR_ERR; - break; - } - } - g_free(buf); - sr_resource_close(drvc->sr_ctx, &bitstream); - - if (result == SR_OK) - sr_dbg("FPGA firmware upload done."); - - return result; -} - -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.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 | - LIBUSB_ENDPOINT_OUT, DS_CMD_START, 0x0000, 0x0000, - (unsigned char *)&mode, sizeof(mode), USB_TIMEOUT); - if (ret < 0) { - sr_err("Failed to send start command: %s.", libusb_error_name(ret)); - return SR_ERR; - } - - return SR_OK; -} - -SR_PRIV int dslogic_stop_acquisition(const struct sr_dev_inst *sdi) -{ - struct sr_usb_dev_inst *usb; - struct dslogic_mode mode; - int ret; - - mode.flags = DS_START_FLAGS_STOP; - mode.sample_delay_h = mode.sample_delay_l = 0; - - usb = sdi->conn; - ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR | - LIBUSB_ENDPOINT_OUT, DS_CMD_START, 0x0000, 0x0000, - (unsigned char *)&mode, sizeof(struct dslogic_mode), USB_TIMEOUT); - if (ret < 0) { - sr_err("Failed to send stop command: %s.", libusb_error_name(ret)); - return SR_ERR; - } - - return SR_OK; -} - -/* - * Get the session trigger and configure the FPGA structure - * accordingly. - */ -static int dslogic_set_trigger(const struct sr_dev_inst *sdi, - struct dslogic_fpga_config *cfg) -{ - struct sr_trigger *trigger; - struct sr_trigger_stage *stage; - struct sr_trigger_match *match; - struct dev_context *devc; - const GSList *l, *m; - int channelbit, i = 0; - uint16_t v16; - - devc = sdi->priv; - - cfg->ch_en = 0; - for (l = sdi->channels; l; l = l->next) { - const struct sr_channel *const probe = (struct sr_channel *)l->data; - cfg->ch_en |= probe->enabled << probe->index; - } - - cfg->trig_mask0[0] = 0xffff; - cfg->trig_mask1[0] = 0xffff; - - cfg->trig_value0[0] = 0; - cfg->trig_value1[0] = 0; - - cfg->trig_edge0[0] = 0; - cfg->trig_edge1[0] = 0; - - cfg->trig_logic0[0] = 0; - cfg->trig_logic1[0] = 0; - - cfg->trig_count[0] = 0; - - cfg->trig_glb = 0; - - for (i = 1; i < DS_NUM_TRIGGER_STAGES; i++) { - cfg->trig_mask0[i] = 0xff; - cfg->trig_mask1[i] = 0xff; - cfg->trig_value0[i] = 0; - cfg->trig_value1[i] = 0; - cfg->trig_edge0[i] = 0; - cfg->trig_edge1[i] = 0; - cfg->trig_logic0[i] = 2; - cfg->trig_logic1[i] = 2; - cfg->trig_count[i] = 0; - } - - cfg->trig_pos = (uint32_t)(devc->capture_ratio / 100.0 * devc->limit_samples); - sr_dbg("pos: %d", cfg->trig_pos); - - sr_dbg("configuring trigger"); - - if (!(trigger = sr_session_trigger_get(sdi->session))) { - sr_dbg("No session trigger found"); - return SR_OK; - } - - for (l = trigger->stages; l; l = l->next) { - stage = l->data; - for (m = stage->matches; m; m = m->next) { - match = m->data; - if (!match->channel->enabled) - /* Ignore disabled channels with a trigger. */ - continue; - channelbit = 1 << (match->channel->index); - /* Simple trigger support (event). */ - if (match->match == SR_TRIGGER_ONE) { - cfg->trig_mask0[0] &= ~channelbit; - cfg->trig_mask1[0] &= ~channelbit; - cfg->trig_value0[0] |= channelbit; - cfg->trig_value1[0] |= channelbit; - } else if (match->match == SR_TRIGGER_ZERO) { - cfg->trig_mask0[0] &= ~channelbit; - cfg->trig_mask1[0] &= ~channelbit; - } else if (match->match == SR_TRIGGER_FALLING) { - cfg->trig_mask0[0] &= ~channelbit; - cfg->trig_mask1[0] &= ~channelbit; - cfg->trig_edge0[0] |= channelbit; - cfg->trig_edge1[0] |= channelbit; - } else if (match->match == SR_TRIGGER_RISING) { - cfg->trig_mask0[0] &= ~channelbit; - cfg->trig_mask1[0] &= ~channelbit; - cfg->trig_value0[0] |= channelbit; - cfg->trig_value1[0] |= channelbit; - cfg->trig_edge0[0] |= channelbit; - cfg->trig_edge1[0] |= channelbit; - } else if (match->match == SR_TRIGGER_EDGE) { - cfg->trig_edge0[0] |= channelbit; - cfg->trig_edge1[0] |= channelbit; - } - } - } - - v16 = RL16(&cfg->mode); - v16 |= 1 << 0; - WL16(&cfg->mode, v16); - - return SR_OK; -} - -SR_PRIV int dslogic_fpga_configure(const struct sr_dev_inst *sdi) -{ - struct dev_context *devc; - struct sr_usb_dev_inst *usb; - uint8_t c[3]; - struct dslogic_fpga_config cfg; - uint16_t v16; - uint32_t v32; - int transferred, len, ret; - - sr_dbg("Configuring FPGA."); - - usb = sdi->conn; - devc = sdi->priv; - - WL32(&cfg.sync, DS_CFG_START); - WL16(&cfg.mode_header, DS_CFG_MODE); - WL16(&cfg.divider_header, DS_CFG_DIVIDER); - WL16(&cfg.count_header, DS_CFG_COUNT); - WL16(&cfg.trig_pos_header, DS_CFG_TRIG_POS); - WL16(&cfg.trig_glb_header, DS_CFG_TRIG_GLB); - WL16(&cfg.ch_en_header, DS_CFG_CH_EN); - WL16(&cfg.trig_header, DS_CFG_TRIG); - WL32(&cfg.end_sync, DS_CFG_END); - - /* Pass in the length of a fixed-size struct. Really. */ - len = sizeof(struct dslogic_fpga_config) / 2; - c[0] = len & 0xff; - c[1] = (len >> 8) & 0xff; - c[2] = (len >> 16) & 0xff; - - ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR | - LIBUSB_ENDPOINT_OUT, DS_CMD_SETTING, 0x0000, 0x0000, - c, sizeof(c), USB_TIMEOUT); - if (ret < 0) { - sr_err("Failed to send FPGA configure command: %s.", - libusb_error_name(ret)); - return SR_ERR; - } - - v16 = 0x0000; - - if (devc->dslogic_mode == DS_OP_INTERNAL_TEST) - v16 = DS_MODE_INT_TEST; - else if (devc->dslogic_mode == DS_OP_EXTERNAL_TEST) - v16 = DS_MODE_EXT_TEST; - else if (devc->dslogic_mode == DS_OP_LOOPBACK_TEST) - v16 = DS_MODE_LPB_TEST; - if (devc->dslogic_continuous_mode) - v16 |= DS_MODE_STREAM_MODE; - if (devc->dslogic_external_clock) { - v16 |= DS_MODE_CLK_TYPE; - if (devc->dslogic_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) { - /* Enable RLE for long captures. - * Without this, captured data present errors. - */ - v16 |= DS_MODE_RLE_MODE; - } - - WL16(&cfg.mode, v16); - v32 = ceil(DS_MAX_LOGIC_SAMPLERATE * 1.0 / devc->cur_samplerate); - WL32(&cfg.divider, v32); - WL32(&cfg.count, devc->limit_samples); - - dslogic_set_trigger(sdi, &cfg); - - len = sizeof(struct dslogic_fpga_config); - ret = libusb_bulk_transfer(usb->devhdl, 2 | LIBUSB_ENDPOINT_OUT, - (unsigned char *)&cfg, len, &transferred, USB_TIMEOUT); - if (ret < 0 || transferred != len) { - sr_err("Failed to send FPGA configuration: %s.", libusb_error_name(ret)); - return SR_ERR; - } - - return SR_OK; -} - -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); -} - -static size_t 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); - // s = to_bytes_per_ms(devc->cur_samplerate); - return (s + 511) & ~511; -} - -SR_PRIV int dslogic_get_number_of_transfers(struct dev_context *devc) -{ - unsigned int n; - - /* Total buffer size should be able to hold about 100ms of data. */ - n = (100 * to_bytes_per_ms(devc) / get_buffer_size(devc)); - sr_info("New calculation: %d", n); - - if (n > NUM_SIMUL_TRANSFERS) - return NUM_SIMUL_TRANSFERS; - - return n; -} diff --git a/src/hardware/fx2lafw/dslogic.h b/src/hardware/fx2lafw/dslogic.h deleted file mode 100644 index 675bf7bf..00000000 --- a/src/hardware/fx2lafw/dslogic.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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_FX2LAFW_DSLOGIC_H -#define LIBSIGROK_HARDWARE_FX2LAFW_DSLOGIC_H - -/* Modified protocol commands & flags used by DSLogic */ -#define DS_CMD_GET_FW_VERSION 0xb0 -#define DS_CMD_GET_REVID_VERSION 0xb1 -#define DS_CMD_START 0xb2 -#define DS_CMD_CONFIG 0xb3 -#define DS_CMD_SETTING 0xb4 -#define DS_CMD_CONTROL 0xb5 -#define DS_CMD_STATUS 0xb6 -#define DS_CMD_STATUS_INFO 0xb7 -#define DS_CMD_WR_REG 0xb8 -#define DS_CMD_WR_NVM 0xb9 -#define DS_CMD_RD_NVM 0xba -#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) -#define DS_START_FLAGS_MODE_LA (1 << 4) - -#define DS_ADDR_COMB 0x68 -#define DS_ADDR_EEWP 0x70 -#define DS_ADDR_VTH 0x78 - -#define DS_MAX_LOGIC_DEPTH SR_MHZ(16) -#define DS_MAX_LOGIC_SAMPLERATE SR_MHZ(100) - -#define DS_MODE_TRIG_EN (1 << 0) -#define DS_MODE_CLK_TYPE (1 << 1) -#define DS_MODE_CLK_EDGE (1 << 2) -#define DS_MODE_RLE_MODE (1 << 3) -#define DS_MODE_DSO_MODE (1 << 4) -#define DS_MODE_HALF_MODE (1 << 5) -#define DS_MODE_QUAR_MODE (1 << 6) -#define DS_MODE_ANALOG_MODE (1 << 7) -#define DS_MODE_FILTER (1 << 8) -#define DS_MODE_INSTANT (1 << 9) -#define DS_MODE_STRIG_MODE (1 << 11) -#define DS_MODE_STREAM_MODE (1 << 12) -#define DS_MODE_LPB_TEST (1 << 13) -#define DS_MODE_EXT_TEST (1 << 14) -#define DS_MODE_INT_TEST (1 << 15) - -enum dslogic_operation_modes { - DS_OP_NORMAL, - DS_OP_INTERNAL_TEST, - DS_OP_EXTERNAL_TEST, - DS_OP_LOOPBACK_TEST, -}; - -enum { - DS_VOLTAGE_RANGE_18_33_V, /* 1.8V and 3.3V logic */ - DS_VOLTAGE_RANGE_5_V, /* 5V logic */ -}; - -enum { - DS_EDGE_RISING, - DS_EDGE_FALLING, -}; - -struct dslogic_version { - uint8_t major; - uint8_t minor; -}; - -struct dslogic_mode { - uint8_t flags; - uint8_t sample_delay_h; - uint8_t sample_delay_l; -}; - -struct dslogic_trigger_pos { - uint32_t real_pos; - uint32_t ram_saddr; - uint32_t remain_cnt; - uint8_t first_block[500]; -}; - -/* - * The FPGA is configured with TLV tuples. Length is specified as the - * number of 16-bit words. - */ -#define _DS_CFG(variable, wordcnt) ((variable << 8) | wordcnt) -#define DS_CFG_START 0xf5a5f5a5 -#define DS_CFG_MODE _DS_CFG(0, 1) -#define DS_CFG_DIVIDER _DS_CFG(1, 2) -#define DS_CFG_COUNT _DS_CFG(3, 2) -#define DS_CFG_TRIG_POS _DS_CFG(5, 2) -#define DS_CFG_TRIG_GLB _DS_CFG(7, 1) -#define DS_CFG_CH_EN _DS_CFG(8, 1) -#define DS_CFG_TRIG _DS_CFG(64, 160) -#define DS_CFG_END 0xfa5afa5a - -#pragma pack(push, 1) - -struct dslogic_fpga_config { - uint32_t sync; - - uint16_t mode_header; - uint16_t mode; - uint16_t divider_header; - uint32_t divider; - uint16_t count_header; - uint32_t count; - uint16_t trig_pos_header; - uint32_t trig_pos; - uint16_t trig_glb_header; - uint16_t trig_glb; - uint16_t ch_en_header; - 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]; - - uint32_t end_sync; -}; - -#pragma pack(pop) - -SR_PRIV int dslogic_fpga_firmware_upload(const struct sr_dev_inst *sdi, - const char *name); -SR_PRIV int dslogic_start_acquisition(const struct sr_dev_inst *sdi); -SR_PRIV int dslogic_stop_acquisition(const struct sr_dev_inst *sdi); -SR_PRIV int dslogic_fpga_configure(const struct sr_dev_inst *sdi); -SR_PRIV int dslogic_set_vth(const struct sr_dev_inst *sdi, double vth); -SR_PRIV int dslogic_get_number_of_transfers(struct dev_context *devc); - -#endif 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);