+/*
+ * A chunk (received via USB) contains a number of transfers (USB length
+ * divided by 16) which contain a number of packets (5 per transfer) which
+ * contain a number of samples (8bit repeat count per 16bit sample data).
+ */
+static void send_chunk(struct sr_dev_inst *sdi,
+ const uint8_t *packets, size_t num_xfers)
+{
+ struct dev_context *devc;
+ size_t num_pkts;
+ const uint8_t *rp;
+ uint16_t sample_value;
+ size_t repetitions;
+ uint8_t sample_buff[sizeof(sample_value)];
+
+ devc = sdi->priv;
+
+ /* Ignore incoming USB data after complete sample data download. */
+ if (devc->download_finished)
+ return;
+
+ if (devc->trigger_involved && !devc->trigger_marked && devc->info.n_rep_packets_before_trigger == 0) {
+ feed_queue_logic_send_trigger(devc->feed_queue);
+ devc->trigger_marked = TRUE;
+ }
+
+ rp = packets;
+ while (num_xfers--) {
+ num_pkts = NUM_PACKETS_IN_CHUNK;
+ while (num_pkts--) {
+
+ sample_value = read_u16le_inc(&rp);
+ repetitions = read_u8_inc(&rp);
+
+ devc->total_samples += repetitions;
+
+ write_u16le(sample_buff, sample_value);
+ feed_queue_logic_submit(devc->feed_queue,
+ sample_buff, repetitions);
+ sr_sw_limits_update_samples_read(&devc->sw_limits,
+ repetitions);
+
+ if (devc->trigger_involved && !devc->trigger_marked) {
+ if (!--devc->n_reps_until_trigger) {
+ feed_queue_logic_send_trigger(devc->feed_queue);
+ devc->trigger_marked = TRUE;
+ sr_dbg("Trigger position after %" PRIu64 " samples, %.6fms.",
+ devc->total_samples,
+ (double)devc->total_samples / devc->cur_samplerate * 1e3);
+ }
+ }
+ }
+ (void)read_u8_inc(&rp); /* Skip sequence number. */
+ }
+
+ if (!devc->download_finished && sr_sw_limits_check(&devc->sw_limits)) {
+ sr_dbg("Acquisition limit reached.");
+ devc->download_finished = TRUE;
+ }
+ if (devc->download_finished) {
+ sr_dbg("Download finished, flushing session feed queue.");
+ feed_queue_logic_flush(devc->feed_queue);
+ }
+ sr_dbg("Total samples after chunk: %" PRIu64 ".", devc->total_samples);
+}
+
+static void LIBUSB_CALL receive_transfer(struct libusb_transfer *transfer)
+{
+ struct sr_dev_inst *sdi;
+ struct dev_context *devc;
+ struct sr_usb_dev_inst *usb;
+ size_t num_xfers;
+ int ret;
+
+ sdi = transfer->user_data;
+ devc = sdi->priv;
+ usb = sdi->conn;
+
+ sr_dbg("receive_transfer(): status %s received %d bytes.",
+ libusb_error_name(transfer->status), transfer->actual_length);
+ /*
+ * Implementation detail: A USB transfer timeout is not fatal
+ * here. We just process whatever was received, empty input is
+ * perfectly acceptable. Reaching (or exceeding) the sw limits
+ * or exhausting the device's captured data will complete the
+ * sample data download.
+ */
+ num_xfers = transfer->actual_length / TRANSFER_PACKET_LENGTH;
+ send_chunk(sdi, transfer->buffer, num_xfers);
+
+ devc->n_bytes_to_read -= transfer->actual_length;
+ if (devc->n_bytes_to_read) {
+ uint32_t to_read = devc->n_bytes_to_read;
+ /*
+ * Determine read size for the next USB transfer. Make
+ * the buffer size a multiple of the endpoint packet
+ * size. Don't exceed a maximum value.
+ */
+ if (to_read >= LA2016_USB_BUFSZ)
+ to_read = LA2016_USB_BUFSZ;
+ else
+ to_read = (to_read + (LA2016_EP6_PKTSZ-1)) & ~(LA2016_EP6_PKTSZ-1);
+ libusb_fill_bulk_transfer(transfer,
+ usb->devhdl, USB_EP_CAPTURE_DATA | LIBUSB_ENDPOINT_IN,
+ transfer->buffer, to_read,
+ receive_transfer, (void *)sdi, DEFAULT_TIMEOUT_MS);
+
+ ret = libusb_submit_transfer(transfer);
+ if (ret == 0)
+ return;
+ sr_err("Cannot submit another USB transfer: %s.",
+ libusb_error_name(ret));
+ }
+
+ g_free(transfer->buffer);
+ libusb_free_transfer(transfer);
+ devc->download_finished = TRUE;
+}
+
+SR_PRIV int la2016_receive_data(int fd, int revents, void *cb_data)
+{
+ const struct sr_dev_inst *sdi;
+ struct dev_context *devc;
+ struct drv_context *drvc;
+ struct timeval tv;
+ int ret;
+
+ (void)fd;
+ (void)revents;
+
+ sdi = cb_data;
+ devc = sdi->priv;
+ drvc = sdi->driver->context;
+
+ /*
+ * Wait for the acquisition to complete in hardware.
+ * Periodically check a potentially configured msecs timeout.
+ */
+ if (!devc->completion_seen) {
+ if (!la2016_is_idle(sdi)) {
+ if (sr_sw_limits_check(&devc->sw_limits)) {
+ devc->sw_limits.limit_msec = 0;
+ sr_dbg("Limit reached. Stopping acquisition.");
+ la2016_stop_acquisition(sdi);
+ }
+ /* Not yet ready for sample data download. */
+ return TRUE;
+ }
+ sr_dbg("Acquisition completion seen (hardware).");
+ devc->sw_limits.limit_msec = 0;
+ devc->completion_seen = TRUE;
+ devc->download_finished = FALSE;
+ devc->trigger_marked = FALSE;
+ devc->total_samples = 0;
+
+ /* Initiate the download of acquired sample data. */
+ std_session_send_df_frame_begin(sdi);
+ ret = la2016_start_download(sdi, receive_transfer);
+ if (ret != SR_OK) {
+ sr_err("Cannot start acquisition data download.");
+ return FALSE;
+ }
+ sr_dbg("Acquisition data download started.");
+
+ return TRUE;
+ }
+
+ /* Handle USB reception. Drives sample data download. */
+ tv.tv_sec = tv.tv_usec = 0;
+ libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+
+ /* Postprocess completion of sample data download. */
+ if (devc->download_finished) {
+ sr_dbg("Download finished, post processing.");
+
+ la2016_stop_acquisition(sdi);
+ usb_source_remove(sdi->session, drvc->sr_ctx);
+ devc->transfer = NULL;
+
+ feed_queue_logic_flush(devc->feed_queue);
+ feed_queue_logic_free(devc->feed_queue);
+ devc->feed_queue = NULL;
+ std_session_send_df_frame_end(sdi);
+ std_session_send_df_end(sdi);
+
+ sr_dbg("Download finished, done post processing.");
+ }
+
+ return TRUE;
+}
+
+SR_PRIV int la2016_identify_device(const struct sr_dev_inst *sdi,
+ gboolean show_message)