X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Ffx2lafw%2Fprotocol.c;h=e88bbd2fd6fa47e7dcda8e7d700993c3cd719ce5;hb=ca314e060f653e6a0b5ec0f58914bac4d426217f;hp=9ca749a50bd6f3fea41b254e87121f55bb9a1ffd;hpb=adcb9951f8a52852e65f99d45083a3e6b9a1981a;p=libsigrok.git diff --git a/src/hardware/fx2lafw/protocol.c b/src/hardware/fx2lafw/protocol.c index 9ca749a5..e88bbd2f 100644 --- a/src/hardware/fx2lafw/protocol.c +++ b/src/hardware/fx2lafw/protocol.c @@ -76,7 +76,7 @@ static int command_get_revid_version(struct sr_dev_inst *sdi, uint8_t *revid) return SR_OK; } -SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi) +static int command_start_acquisition(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_usb_dev_inst *usb; @@ -147,7 +147,7 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di) struct dev_context *devc; struct drv_context *drvc; struct version_info vi; - int ret, i, device_count; + int ret = SR_ERR, i, device_count; uint8_t revid; char connection_id[64]; @@ -155,10 +155,6 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di) 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.", @@ -194,6 +190,7 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di) } else { sr_err("Failed to open device: %s.", libusb_error_name(ret)); + ret = SR_ERR; break; } @@ -202,7 +199,8 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di) 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 = SR_ERR; + break; } } } @@ -231,7 +229,6 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di) 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, @@ -240,14 +237,14 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di) sr_info("Detected REVID=%d, it's a Cypress CY7C68013%s.", revid, (revid != 1) ? " (FX2)" : "A (FX2LP)"); + ret = SR_OK; + break; } - libusb_free_device_list(devlist, 1); - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR; + libusb_free_device_list(devlist, 1); - return SR_OK; + return ret; } SR_PRIV struct dev_context *fx2lafw_dev_new(void) @@ -340,7 +337,7 @@ static void resubmit_transfer(struct libusb_transfer *transfer) } -SR_PRIV void mso_send_data_proc(struct sr_dev_inst *sdi, +static void mso_send_data_proc(struct sr_dev_inst *sdi, uint8_t *data, size_t length, size_t sample_width) { size_t i; @@ -392,7 +389,7 @@ SR_PRIV void mso_send_data_proc(struct sr_dev_inst *sdi, sr_session_send(sdi, &analog_packet); } -SR_PRIV void la_send_data_proc(struct sr_dev_inst *sdi, +static void la_send_data_proc(struct sr_dev_inst *sdi, uint8_t *data, size_t length, size_t sample_width) { const struct sr_datafeed_logic logic = { @@ -409,7 +406,7 @@ SR_PRIV void la_send_data_proc(struct sr_dev_inst *sdi, sr_session_send(sdi, &packet); } -SR_PRIV void LIBUSB_CALL fx2lafw_receive_transfer(struct libusb_transfer *transfer) +static void LIBUSB_CALL receive_transfer(struct libusb_transfer *transfer) { struct sr_dev_inst *sdi; struct dev_context *devc; @@ -504,12 +501,46 @@ SR_PRIV void LIBUSB_CALL fx2lafw_receive_transfer(struct libusb_transfer *transf resubmit_transfer(transfer); } +static int configure_channels(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + const GSList *l; + int p; + struct sr_channel *ch; + uint32_t channel_mask = 0, num_analog = 0; + + devc = sdi->priv; + + g_slist_free(devc->enabled_analog_channels); + devc->enabled_analog_channels = NULL; + + for (l = sdi->channels, p = 0; l; l = l->next, p++) { + ch = l->data; + if ((p <= NUM_CHANNELS) && (ch->type == SR_CHANNEL_ANALOG) + && (ch->enabled)) { + num_analog++; + devc->enabled_analog_channels = + g_slist_append(devc->enabled_analog_channels, ch); + } else { + channel_mask |= ch->enabled << p; + } + } + + /* + * Use wide sampling if either any of the LA channels 8..15 is enabled, + * and/or at least one analog channel is enabled. + */ + devc->sample_wide = channel_mask > 0xff || num_analog > 0; + + return SR_OK; +} + static unsigned int to_bytes_per_ms(unsigned int samplerate) { return samplerate / 1000; } -SR_PRIV size_t fx2lafw_get_buffer_size(struct dev_context *devc) +static size_t get_buffer_size(struct dev_context *devc) { size_t s; @@ -521,13 +552,13 @@ SR_PRIV size_t fx2lafw_get_buffer_size(struct dev_context *devc) return (s + 511) & ~511; } -SR_PRIV unsigned int fx2lafw_get_number_of_transfers(struct dev_context *devc) +static unsigned int get_number_of_transfers(struct dev_context *devc) { unsigned int n; /* 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)); + get_buffer_size(devc)); if (n > NUM_SIMUL_TRANSFERS) return NUM_SIMUL_TRANSFERS; @@ -535,13 +566,150 @@ SR_PRIV unsigned int fx2lafw_get_number_of_transfers(struct dev_context *devc) return n; } -SR_PRIV unsigned int fx2lafw_get_timeout(struct dev_context *devc) +static unsigned int get_timeout(struct dev_context *devc) { size_t total_size; unsigned int timeout; - total_size = fx2lafw_get_buffer_size(devc) * - fx2lafw_get_number_of_transfers(devc); + total_size = get_buffer_size(devc) * + 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. */ } + +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 sr_trigger *trigger; + 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; + + 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; + devc->stl = soft_trigger_logic_new(sdi, trigger, pre_trigger_samples); + if (!devc->stl) + return SR_ERR_MALLOC; + devc->trigger_fired = FALSE; + } else + devc->trigger_fired = TRUE; + + num_transfers = get_number_of_transfers(devc); + + size = 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 = 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, + 2 | LIBUSB_ENDPOINT_IN, buf, size, + 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); + fx2lafw_abort_acquisition(devc); + return SR_ERR; + } + devc->transfers[i] = transfer; + devc->submitted_transfers++; + } + + /* + * If this device has analog channels and at least one of them is + * enabled, use mso_send_data_proc() to properly handle the analog + * data. Otherwise use la_send_data_proc(). + */ + if (g_slist_length(devc->enabled_analog_channels) > 0) + devc->send_data_proc = mso_send_data_proc; + else + devc->send_data_proc = la_send_data_proc; + + std_session_send_df_header(sdi); + + return SR_OK; +} + +SR_PRIV int fx2lafw_start_acquisition(const struct sr_dev_inst *sdi) +{ + struct sr_dev_driver *di; + struct drv_context *drvc; + struct dev_context *devc; + int timeout, ret; + size_t size; + + 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; + + if (configure_channels(sdi) != SR_OK) { + sr_err("Failed to configure channels."); + return SR_ERR; + } + + timeout = get_timeout(devc); + usb_source_add(sdi->session, devc->ctx, timeout, receive_data, drvc); + + size = 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 = command_start_acquisition(sdi)) != SR_OK) { + fx2lafw_abort_acquisition(devc); + return ret; + } + + return SR_OK; +}