+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;
+
+ /* Arrange for the start of stream mode when requested. */
+ if (devc->continuous && !devc->frame_begin_sent) {
+ sr_dbg("First receive callback in stream mode.");
+ devc->download_finished = FALSE;
+ devc->trigger_marked = FALSE;
+ devc->total_samples = 0;
+
+ std_session_send_df_frame_begin(sdi);
+ devc->frame_begin_sent = TRUE;
+
+ ret = set_run_mode(sdi, RUNMODE_RUN);
+ if (ret != SR_OK) {
+ sr_err("Cannot set 'runmode' to 'run'.");
+ return FALSE;
+ }
+
+ ret = ctrl_out(sdi, CMD_BULK_START, 0x00, 0, NULL, 0);
+ if (ret != SR_OK) {
+ sr_err("Cannot start USB bulk transfers.");
+ return FALSE;
+ }
+ sr_dbg("Stream data reception initiated.");
+ }
+
+ /*
+ * Wait for the acquisition to complete in hardware.
+ * Periodically check a potentially configured msecs timeout.
+ */
+ if (!devc->continuous && !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;
+
+ la2016_dump_fpga_registers(sdi, "acquisition complete", 0, 0);
+
+ /* Initiate the download of acquired sample data. */
+ std_session_send_df_frame_begin(sdi);
+ devc->frame_begin_sent = TRUE;
+ ret = la2016_start_download(sdi);
+ 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. */
+ memset(&tv, 0, sizeof(tv));
+ libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+
+ /*
+ * Periodically flush acquisition data in streaming mode.
+ * Without this nudge, previously received and accumulated data
+ * keeps sitting in queues and is not seen by applications.
+ */
+ if (devc->continuous && devc->stream.flush_period_ms) {
+ uint64_t now, elapsed;
+ now = g_get_monotonic_time();
+ if (!devc->stream.last_flushed)
+ devc->stream.last_flushed = now;
+ elapsed = now - devc->stream.last_flushed;
+ elapsed /= 1000;
+ if (elapsed >= devc->stream.flush_period_ms) {
+ sr_dbg("Stream mode, flushing.");
+ feed_queue_logic_flush(devc->feed_queue);
+ devc->stream.last_flushed = now;
+ }
+ }
+
+ /* 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);
+
+ la2016_usbxfer_cancel_all(sdi);
+ memset(&tv, 0, sizeof(tv));
+ libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+
+ feed_queue_logic_flush(devc->feed_queue);
+ feed_queue_logic_free(devc->feed_queue);
+ devc->feed_queue = NULL;
+ if (devc->frame_begin_sent) {
+ std_session_send_df_frame_end(sdi);
+ devc->frame_begin_sent = FALSE;
+ }
+ 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)
+{
+ struct dev_context *devc;
+ uint8_t buf[8]; /* Larger size of manuf date and device type magic. */
+ size_t rdoff, rdlen;
+ const uint8_t *rdptr;
+ uint8_t date_yy, date_mm;
+ uint8_t dinv_yy, dinv_mm;
+ uint8_t magic;
+ size_t model_idx;
+ const struct kingst_model *model;
+ int ret;
+
+ devc = sdi->priv;
+
+ /*
+ * Four EEPROM bytes at offset 0x20 are the manufacturing date,
+ * year and month in BCD format, followed by inverted values for
+ * consistency checks. For example bytes 20 04 df fb translate
+ * to 2020-04. This information can help identify the vintage of
+ * devices when unknown magic numbers are seen.
+ */
+ rdoff = 0x20;
+ rdlen = 4 * sizeof(uint8_t);
+ ret = ctrl_in(sdi, CMD_EEPROM, rdoff, 0, buf, rdlen);
+ if (ret != SR_OK && !show_message) {
+ /* Non-fatal weak attempt during probe. Not worth logging. */
+ sr_dbg("Cannot access EEPROM.");
+ return SR_ERR_IO;
+ } else if (ret != SR_OK) {
+ /* Failed attempt in regular use. Non-fatal. Worth logging. */
+ sr_err("Cannot read manufacture date in EEPROM.");
+ } else {
+ if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+ GString *txt;
+ txt = sr_hexdump_new(buf, rdlen);
+ sr_spew("Manufacture date bytes %s.", txt->str);
+ sr_hexdump_free(txt);
+ }
+ rdptr = &buf[0];
+ date_yy = read_u8_inc(&rdptr);
+ date_mm = read_u8_inc(&rdptr);
+ dinv_yy = read_u8_inc(&rdptr);
+ dinv_mm = read_u8_inc(&rdptr);
+ sr_info("Manufacture date: 20%02hx-%02hx.", date_yy, date_mm);
+ if ((date_mm ^ dinv_mm) != 0xff || (date_yy ^ dinv_yy) != 0xff)
+ sr_warn("Manufacture date fails checksum test.");