X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Ffx2lafw%2Fprotocol.c;h=95ce4bd3bd581e18459294b0e5ed011c3fa3a52d;hb=b0acb693f94d920887684eb9fdae77e036965975;hp=32a65c501b6257d16e85308b23b4c778d8b0a2ad;hpb=6ec6c43b4738dbc7091f4a49a4ec80ea6102cb52;p=libsigrok.git diff --git a/src/hardware/fx2lafw/protocol.c b/src/hardware/fx2lafw/protocol.c index 32a65c50..95ce4bd3 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)); @@ -78,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; @@ -125,6 +123,8 @@ SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi) /* Select the sampling width. */ cmd.flags |= devc->sample_wide ? CMD_START_FLAGS_SAMPLE_16BIT : CMD_START_FLAGS_SAMPLE_8BIT; + /* Enable CTL2 clock. */ + cmd.flags |= (g_slist_length(devc->enabled_analog_channels) > 0) ? CMD_START_FLAGS_CLK_CTL2 : 0; /* Send the control message. */ ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR | @@ -139,50 +139,6 @@ SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi) return SR_OK; } -/** - * Check the USB configuration to determine if this is an fx2lafw device. - * - * @return TRUE if the device's configuration profile matches fx2lafw - * configuration, FALSE otherwise. - */ -SR_PRIV gboolean match_manuf_prod(libusb_device *dev, const char *manufacturer, - const char *product) -{ - struct libusb_device_descriptor des; - struct libusb_device_handle *hdl; - gboolean ret; - unsigned char strdesc[64]; - - hdl = NULL; - ret = FALSE; - while (!ret) { - /* Assume the FW has not been loaded, unless proven wrong. */ - if (libusb_get_device_descriptor(dev, &des) != 0) - break; - - if (libusb_open(dev, &hdl) != 0) - break; - - if (libusb_get_string_descriptor_ascii(hdl, - des.iManufacturer, strdesc, sizeof(strdesc)) < 0) - break; - if (strcmp((const char *)strdesc, manufacturer)) - break; - - if (libusb_get_string_descriptor_ascii(hdl, - des.iProduct, strdesc, sizeof(strdesc)) < 0) - break; - if (strcmp((const char *)strdesc, product)) - break; - - ret = TRUE; - } - if (hdl) - libusb_close(hdl); - - return ret; -} - SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di) { libusb_device **devlist; @@ -211,11 +167,7 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di) } for (i = 0; i < device_count; i++) { - if ((ret = libusb_get_device_descriptor(devlist[i], &des))) { - sr_err("Failed to get device descriptor: %s.", - libusb_error_name(ret)); - continue; - } + libusb_get_device_descriptor(devlist[i], &des); if (des.idVendor != devc->profile->vid || des.idProduct != devc->profile->pid) @@ -328,21 +280,23 @@ SR_PRIV void fx2lafw_abort_acquisition(struct dev_context *devc) static void finish_acquisition(struct sr_dev_inst *sdi) { - struct sr_datafeed_packet packet; struct dev_context *devc; devc = sdi->priv; - /* Terminate session. */ - packet.type = SR_DF_END; - sr_session_send(sdi, &packet); + std_session_send_df_end(sdi); - /* Remove fds from polling. */ usb_source_remove(sdi->session, devc->ctx); devc->num_transfers = 0; g_free(devc->transfers); + /* Free the deinterlace buffers if we had them. */ + if (g_slist_length(devc->enabled_analog_channels) > 0) { + g_free(devc->logic_buffer); + g_free(devc->analog_buffer); + } + if (devc->stl) { soft_trigger_logic_free(devc->stl); devc->stl = NULL; @@ -386,13 +340,80 @@ static void resubmit_transfer(struct libusb_transfer *transfer) } -SR_PRIV void LIBUSB_CALL fx2lafw_receive_transfer(struct libusb_transfer *transfer) +static void mso_send_data_proc(struct sr_dev_inst *sdi, + uint8_t *data, size_t length, size_t sample_width) +{ + size_t i; + struct dev_context *devc; + struct sr_datafeed_analog analog; + struct sr_analog_encoding encoding; + struct sr_analog_meaning meaning; + struct sr_analog_spec spec; + + (void)sample_width; + + devc = sdi->priv; + + length /= 2; + + /* Send the logic */ + for (i = 0; i < length; i++) { + devc->logic_buffer[i] = data[i * 2]; + /* Rescale to -10V - +10V from 0-255. */ + devc->analog_buffer[i] = (data[i * 2 + 1] - 128.0f) / 12.8f; + }; + + const struct sr_datafeed_logic logic = { + .length = length, + .unitsize = 1, + .data = devc->logic_buffer + }; + + const struct sr_datafeed_packet logic_packet = { + .type = SR_DF_LOGIC, + .payload = &logic + }; + + sr_session_send(sdi, &logic_packet); + + sr_analog_init(&analog, &encoding, &meaning, &spec, 2); + analog.meaning->channels = devc->enabled_analog_channels; + analog.meaning->mq = SR_MQ_VOLTAGE; + analog.meaning->unit = SR_UNIT_VOLT; + analog.meaning->mqflags = 0 /* SR_MQFLAG_DC */; + analog.num_samples = length; + analog.data = devc->analog_buffer; + + const struct sr_datafeed_packet analog_packet = { + .type = SR_DF_ANALOG, + .payload = &analog + }; + + sr_session_send(sdi, &analog_packet); +} + +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 = { + .length = length, + .unitsize = sample_width, + .data = data + }; + + const struct sr_datafeed_packet packet = { + .type = SR_DF_LOGIC, + .payload = &logic + }; + + sr_session_send(sdi, &packet); +} + +static void LIBUSB_CALL 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; - struct sr_datafeed_logic logic; unsigned int num_samples; int trigger_offset, cur_sample_count, unitsize; int pre_trigger_samples; @@ -445,20 +466,16 @@ SR_PRIV void LIBUSB_CALL fx2lafw_receive_transfer(struct libusb_transfer *transf } 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. */ - packet.type = SR_DF_LOGIC; - packet.payload = &logic; 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; - logic.length = num_samples * unitsize; - logic.unitsize = unitsize; - logic.data = transfer->buffer; - sr_session_send(devc->cb_data, &packet); + + devc->send_data_proc(sdi, (uint8_t *)transfer->buffer, + num_samples * unitsize, unitsize); devc->sent_samples += num_samples; } } else { @@ -466,16 +483,14 @@ SR_PRIV void LIBUSB_CALL fx2lafw_receive_transfer(struct libusb_transfer *transf transfer->buffer, transfer->actual_length, &pre_trigger_samples); if (trigger_offset > -1) { devc->sent_samples += pre_trigger_samples; - packet.type = SR_DF_LOGIC; - packet.payload = &logic; num_samples = cur_sample_count - trigger_offset; if (devc->limit_samples && num_samples > devc->limit_samples - devc->sent_samples) num_samples = devc->limit_samples - devc->sent_samples; - logic.length = num_samples * unitsize; - logic.unitsize = unitsize; - logic.data = transfer->buffer + trigger_offset * unitsize; - sr_session_send(devc->cb_data, &packet); + + devc->send_data_proc(sdi, (uint8_t *)transfer->buffer + + trigger_offset * unitsize, + num_samples * unitsize, unitsize); devc->sent_samples += num_samples; devc->trigger_fired = TRUE; @@ -489,12 +504,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; @@ -506,13 +555,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; @@ -520,13 +569,153 @@ 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; + + 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; + + 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; +}