X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=blobdiff_plain;f=src%2Fhardware%2Ffx2lafw%2Fprotocol.c;h=fc6fd3315a2c2ab6f76a3612e7e30db1362888f0;hp=e2112af13abc6d96a0f1893f60451d0e04e22d72;hb=HEAD;hpb=f9592d65e9759b9a37c51a090c3504d4328ba4d4 diff --git a/src/hardware/fx2lafw/protocol.c b/src/hardware/fx2lafw/protocol.c index e2112af1..8854f5a6 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; @@ -114,7 +112,7 @@ SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi) sr_dbg("GPIF delay = %d, clocksource = %sMHz.", delay, (cmd.flags & CMD_START_FLAGS_CLK_48MHZ) ? "48" : "30"); - if (delay <= 0 || delay > MAX_SAMPLE_DELAY) { + if (delay < 0 || delay > MAX_SAMPLE_DELAY) { sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate); return SR_ERR; } @@ -141,49 +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. */ - libusb_get_device_descriptor(dev, &des); - - 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; @@ -192,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]; @@ -200,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.", @@ -223,7 +174,9 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di) /* * Check device by its physical USB bus/port address. */ - usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)); + if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0) + continue; + if (strcmp(sdi->connection_id, connection_id)) /* This is not the one. */ continue; @@ -239,6 +192,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; } @@ -247,7 +201,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; } } } @@ -276,7 +231,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, @@ -285,14 +239,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) @@ -301,13 +255,14 @@ SR_PRIV struct dev_context *fx2lafw_dev_new(void) devc = g_malloc0(sizeof(struct dev_context)); devc->profile = NULL; + devc->channel_names = NULL; devc->fw_updated = 0; devc->cur_samplerate = 0; + devc->limit_frames = 1; 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->num_frames = 0; devc->stl = NULL; return devc; @@ -387,7 +342,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; @@ -439,7 +394,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 = { @@ -456,14 +411,13 @@ 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; gboolean packet_has_error = FALSE; - struct sr_datafeed_packet packet; unsigned int num_samples; - int trigger_offset, cur_sample_count, unitsize; + int trigger_offset, cur_sample_count, unitsize, processed_samples; int pre_trigger_samples; sdi = transfer->user_data; @@ -484,6 +438,7 @@ SR_PRIV void LIBUSB_CALL fx2lafw_receive_transfer(struct libusb_transfer *transf /* Save incoming transfer before reusing the transfer struct. */ unitsize = devc->sample_wide ? 2 : 1; cur_sample_count = transfer->actual_length / unitsize; + processed_samples = 0; switch (transfer->status) { case LIBUSB_TRANSFER_NO_DEVICE: @@ -514,70 +469,113 @@ SR_PRIV void LIBUSB_CALL fx2lafw_receive_transfer(struct libusb_transfer *transf } else { devc->empty_transfer_count = 0; } + +check_trigger: 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 = cur_sample_count - processed_samples; + if (devc->limit_samples && devc->sent_samples + num_samples > devc->limit_samples) num_samples = devc->limit_samples - devc->sent_samples; - 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 + processed_samples * unitsize, + num_samples * unitsize, unitsize); + devc->sent_samples += num_samples; + processed_samples += num_samples; } } else { trigger_offset = soft_trigger_logic_check(devc->stl, - transfer->buffer, transfer->actual_length, &pre_trigger_samples); + transfer->buffer + processed_samples * unitsize, + transfer->actual_length - processed_samples * unitsize, + &pre_trigger_samples); if (trigger_offset > -1) { + std_session_send_df_frame_begin(sdi); devc->sent_samples += pre_trigger_samples; - num_samples = cur_sample_count - trigger_offset; + num_samples = cur_sample_count - processed_samples - trigger_offset; if (devc->limit_samples && - num_samples > devc->limit_samples - devc->sent_samples) + devc->sent_samples + num_samples > devc->limit_samples) num_samples = devc->limit_samples - devc->sent_samples; devc->send_data_proc(sdi, (uint8_t *)transfer->buffer + + processed_samples * unitsize + trigger_offset * unitsize, num_samples * unitsize, unitsize); devc->sent_samples += num_samples; + processed_samples += trigger_offset + num_samples; devc->trigger_fired = TRUE; } } - if (devc->limit_samples && devc->sent_samples >= devc->limit_samples) { + const int frame_ended = devc->limit_samples && (devc->sent_samples >= devc->limit_samples); + const int final_frame = devc->limit_frames && (devc->num_frames >= (devc->limit_frames - 1)); + + if (frame_ended) { + devc->num_frames++; + devc->sent_samples = 0; + devc->trigger_fired = FALSE; + std_session_send_df_frame_end(sdi); + + /* There may be another trigger in the remaining data, go back and check for it */ + if (processed_samples < cur_sample_count) { + /* Reset the trigger stage */ + if (devc->stl) + devc->stl->cur_stage = 0; + else { + std_session_send_df_frame_begin(sdi); + devc->trigger_fired = TRUE; + } + if (!final_frame) + goto check_trigger; + } + } + if (frame_ended && final_frame) { fx2lafw_abort_acquisition(devc); free_transfer(transfer); } else 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; @@ -589,13 +587,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; @@ -603,13 +601,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 { + std_session_send_df_frame_begin(sdi); + 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->num_frames = 0; + 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; +}