#include <inttypes.h>
#include <libusb.h>
#include "config.h"
-#include "sigrok.h"
-#include "sigrok-internal.h"
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
#include "fx2lafw.h"
#include "command.h"
static const struct fx2lafw_profile supported_fx2[] = {
+ /*
+ * CWAV USBee DX
+ * XZL Studio DX
+ */
+ { 0x08a9, 0x0015, "CWAV", "USBee DX", NULL,
+ FIRMWARE_DIR "/fx2lafw-cwav-usbeedx.fw",
+ 0 },
/*
* CWAV USBee AX
* EE Electronics ESLA201A
static void abort_acquisition(struct context *ctx)
{
+ int i;
+
ctx->num_samples = -1;
+
+ for (i = ctx->num_transfers - 1; i >= 0; i--) {
+ if (ctx->transfers[i])
+ libusb_cancel_transfer(ctx->transfers[i]);
+ }
}
static void finish_acquisition(struct context *ctx)
for (i = 0; lupfd[i]; i++)
sr_source_remove(lupfd[i]->fd);
free(lupfd); /* NOT g_free()! */
+
+ ctx->num_transfers = 0;
+ g_free(ctx->transfers);
+}
+
+static void free_transfer(struct libusb_transfer *transfer)
+{
+ struct context *ctx = transfer->user_data;
+ unsigned int i;
+
+ g_free(transfer->buffer);
+ transfer->buffer = NULL;
+ libusb_free_transfer(transfer);
+
+ for (i = 0; i < ctx->num_transfers; i++) {
+ if (ctx->transfers[i] == transfer) {
+ ctx->transfers[i] = NULL;
+ break;
+ }
+ }
+
+ ctx->submitted_transfers--;
+ if (ctx->submitted_transfers == 0)
+ finish_acquisition(ctx);
+
+}
+
+static void resubmit_transfer(struct libusb_transfer *transfer)
+{
+ if (libusb_submit_transfer(transfer) != 0) {
+ free_transfer(transfer);
+ /* TODO: Stop session? */
+ /* TODO: Better error message. */
+ sr_err("fx2lafw: %s: libusb_submit_transfer error.", __func__);
+ }
}
static void receive_transfer(struct libusb_transfer *transfer)
{
- /* TODO: These statics have to move to the ctx struct. */
- static int empty_transfer_count = 0;
+ gboolean packet_has_error = FALSE;
struct sr_datafeed_packet packet;
struct sr_datafeed_logic logic;
struct context *ctx = transfer->user_data;
int trigger_offset, i;
- uint8_t *new_buf;
/*
* If acquisition has already ended, just free any queued up
* transfer that come in.
*/
if (ctx->num_samples == -1) {
- if (transfer)
- libusb_free_transfer(transfer);
-
- ctx->submitted_transfers--;
- if (ctx->submitted_transfers == 0)
- finish_acquisition(ctx);
-
+ free_transfer(transfer);
return;
}
const int sample_width = ctx->sample_wide ? 2 : 1;
const int cur_sample_count = transfer->actual_length / sample_width;
- /* Fire off a new request. */
- if (!(new_buf = g_try_malloc(4096))) {
- sr_err("fx2lafw: %s: new_buf malloc failed.", __func__);
- libusb_free_transfer(transfer);
- return; /* TODO: SR_ERR_MALLOC */
- }
-
- transfer->buffer = new_buf;
- transfer->length = 4096;
- if (libusb_submit_transfer(transfer) != 0) {
- /* TODO: Stop session? */
- /* TODO: Better error message. */
- sr_err("fx2lafw: %s: libusb_submit_transfer error.", __func__);
+ switch (transfer->status) {
+ case LIBUSB_TRANSFER_NO_DEVICE:
+ abort_acquisition(ctx);
+ 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) {
- empty_transfer_count++;
- if (empty_transfer_count > MAX_EMPTY_TRANSFERS) {
+ if (transfer->actual_length == 0 || packet_has_error) {
+ ctx->empty_transfer_count++;
+ if (ctx->empty_transfer_count > MAX_EMPTY_TRANSFERS) {
/*
* The FX2 gave up. End the acquisition, the frontend
* will work out that the samplecount is short.
*/
abort_acquisition(ctx);
+ free_transfer(transfer);
+ } else {
+ resubmit_transfer(transfer);
}
- g_free(cur_buf);
return;
} else {
- empty_transfer_count = 0;
+ ctx->empty_transfer_count = 0;
}
trigger_offset = 0;
if (ctx->limit_samples &&
(unsigned int)ctx->num_samples > ctx->limit_samples) {
abort_acquisition(ctx);
+ free_transfer(transfer);
+ return;
}
} else {
/*
* ratio-sized buffer.
*/
}
- g_free(cur_buf);
+
+ resubmit_transfer(transfer);
+}
+
+static unsigned int to_bytes_per_ms(unsigned int samplerate)
+{
+ return samplerate / 1000;
+}
+
+static size_t get_buffer_size(struct context *ctx)
+{
+ 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(ctx->cur_samplerate);
+ return (s + 511) & ~511;
+}
+
+static unsigned int get_number_of_transfers(struct context *ctx)
+{
+ unsigned int n;
+
+ /* Total buffer size should be able to hold about 500ms of data */
+ n = 500 * to_bytes_per_ms(ctx->cur_samplerate) / get_buffer_size(ctx);
+
+ if (n > NUM_SIMUL_TRANSFERS)
+ return NUM_SIMUL_TRANSFERS;
+
+ return n;
+}
+
+static unsigned int get_timeout(struct context *ctx)
+{
+ size_t total_size;
+ unsigned int timeout;
+
+ total_size = get_buffer_size(ctx) * get_number_of_transfers(ctx);
+ timeout = total_size / to_bytes_per_ms(ctx->cur_samplerate);
+ return timeout + timeout / 4; /* Leave a headroom of 25% percent */
}
static int hw_dev_acquisition_start(int dev_index, void *cb_data)
struct context *ctx;
struct libusb_transfer *transfer;
const struct libusb_pollfd **lupfd;
- int ret, size, i;
+ unsigned int i;
+ int ret;
unsigned char *buf;
if (!(sdi = sr_dev_inst_get(dev_insts, dev_index)))
return SR_ERR;
ctx = sdi->priv;
+
+ if (ctx->submitted_transfers != 0)
+ return SR_ERR;
+
ctx->session_dev_id = cb_data;
ctx->num_samples = 0;
+ ctx->empty_transfer_count = 0;
+
+ const unsigned int timeout = get_timeout(ctx);
+ const unsigned int num_transfers = get_number_of_transfers(ctx);
+ const size_t size = get_buffer_size(ctx);
+
+ ctx->transfers = g_try_malloc0(sizeof(*ctx->transfers) * num_transfers);
+ if (!ctx->transfers)
+ return SR_ERR;
+
+ ctx->num_transfers = num_transfers;
- /* Start with 2K transfer, subsequently increased to 4K. */
- size = 2048;
- for (i = 0; i < NUM_SIMUL_TRANSFERS; i++) {
+ for (i = 0; i < num_transfers; i++) {
if (!(buf = g_try_malloc(size))) {
sr_err("fx2lafw: %s: buf malloc failed.", __func__);
return SR_ERR_MALLOC;
transfer = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer(transfer, ctx->usb->devhdl,
2 | LIBUSB_ENDPOINT_IN, buf, size,
- receive_transfer, ctx, 40);
+ receive_transfer, ctx, timeout);
if (libusb_submit_transfer(transfer) != 0) {
- /* TODO: Free them all. */
libusb_free_transfer(transfer);
g_free(buf);
+ abort_acquisition(ctx);
return SR_ERR;
}
-
+ ctx->transfers[i] = transfer;
ctx->submitted_transfers++;
- size = 4096;
}
lupfd = libusb_get_pollfds(usb_context);
for (i = 0; lupfd[i]; i++)
sr_source_add(lupfd[i]->fd, lupfd[i]->events,
- 40, receive_data, NULL);
+ timeout, receive_data, NULL);
free(lupfd); /* NOT g_free()! */
packet.type = SR_DF_HEADER;
if ((ret = command_start_acquisition (ctx->usb->devhdl,
ctx->cur_samplerate, ctx->sample_wide)) != SR_OK) {
+ abort_acquisition(ctx);
return ret;
}