Use common sw_limits and feed_queue helpers. Which makes --time specs
for acquisition duration available, and dramatically reduces complexity
in the send_chunk() routine. Which improves usability and reliability
and maintainability at the same time.
Assign default rate/depth/ratio in scan() already when the devc gets
created. Make an msecs timeout stop the acquisition if the hardware has
not seen the desired number of samples or exhausted its memory before.
Immediately start recording in the absence of trigger specs, drop the
pre-trigger phase in that case. Shuffle the order of activities in the
periodic receive callback. Send headers before enabling communication,
end communication before sending end markers to the session feed. Cope
when USB data is received after the configured acquisition got processed
(the hardware always overshoots due to compression and chunking). Extend
comments and diag messages.
USB receive timeouts are not fatal any longer. They even were seen
during regular operation at higher log levels. Which resulted in one
capture getting split across several "frames" unexpectedly.
Acquisition limits are not enforced most precisely in this commit, as
this would be more expensive. A little overshoot of up to 1.5kSa seems
acceptable (up to five packets with an 8bit repeat count each).
#include "libsigrok-internal.h"
#include "protocol.h"
#include "libsigrok-internal.h"
#include "protocol.h"
+/*
+ * Default device configuration. Must be applicable to any of the
+ * supported devices (no model specific default values yet). Specific
+ * firmware implementation details unfortunately won't let us detect
+ * and keep using previously configured values.
+ */
+#define LA2016_DFLT_SAMPLERATE SR_MHZ(100)
+#define LA2016_DFLT_SAMPLEDEPTH (5 * 1000 * 1000)
+#define LA2016_DFLT_CAPT_RATIO 5 /* Capture ratio, in percent. */
+
static const uint32_t scanopts[] = {
SR_CONF_CONN,
};
static const uint32_t scanopts[] = {
SR_CONF_CONN,
};
/* TODO: SR_CONF_CONTINUOUS, */
SR_CONF_CONN | SR_CONF_GET,
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
/* TODO: SR_CONF_CONTINUOUS, */
SR_CONF_CONN | SR_CONF_GET,
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
- SR_CONF_LIMIT_SAMPLES | SR_CONF_SET | SR_CONF_GET | SR_CONF_LIST,
+ SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+ SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
SR_CONF_VOLTAGE_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_LOGIC_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_LOGIC_THRESHOLD_CUSTOM | SR_CONF_GET | SR_CONF_SET,
SR_CONF_VOLTAGE_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_LOGIC_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_LOGIC_THRESHOLD_CUSTOM | SR_CONF_GET | SR_CONF_SET,
devc = g_malloc0(sizeof(*devc));
sdi->priv = devc;
devc->fw_uploaded = fw_uploaded;
devc = g_malloc0(sizeof(*devc));
sdi->priv = devc;
devc->fw_uploaded = fw_uploaded;
+ sr_sw_limits_init(&devc->sw_limits);
+ devc->sw_limits.limit_samples = LA2016_DFLT_SAMPLEDEPTH;
+ devc->capture_ratio = LA2016_DFLT_CAPT_RATIO;
+ devc->cur_samplerate = LA2016_DFLT_SAMPLERATE;
devc->threshold_voltage_idx = 0;
devc->threshold_voltage = logic_threshold_value[devc->threshold_voltage_idx];
devc->threshold_voltage_idx = 0;
devc->threshold_voltage = logic_threshold_value[devc->threshold_voltage_idx];
*data = g_variant_new_uint64(devc->cur_samplerate);
break;
case SR_CONF_LIMIT_SAMPLES:
*data = g_variant_new_uint64(devc->cur_samplerate);
break;
case SR_CONF_LIMIT_SAMPLES:
- *data = g_variant_new_uint64(devc->limit_samples);
- break;
+ case SR_CONF_LIMIT_MSEC:
+ return sr_sw_limits_config_get(&devc->sw_limits, key, data);
case SR_CONF_CAPTURE_RATIO:
*data = g_variant_new_uint64(devc->capture_ratio);
break;
case SR_CONF_CAPTURE_RATIO:
*data = g_variant_new_uint64(devc->capture_ratio);
break;
devc->cur_samplerate = g_variant_get_uint64(data);
break;
case SR_CONF_LIMIT_SAMPLES:
devc->cur_samplerate = g_variant_get_uint64(data);
break;
case SR_CONF_LIMIT_SAMPLES:
- devc->limit_samples = g_variant_get_uint64(data);
- break;
+ case SR_CONF_LIMIT_MSEC:
+ return sr_sw_limits_config_set(&devc->sw_limits, key, data);
case SR_CONF_CAPTURE_RATIO:
devc->capture_ratio = g_variant_get_uint64(data);
break;
case SR_CONF_CAPTURE_RATIO:
devc->capture_ratio = g_variant_get_uint64(data);
break;
{
struct dev_context *devc;
{
struct dev_context *devc;
+ devc = sdi ? sdi->priv : NULL;
+
switch (key) {
case SR_CONF_SCAN_OPTIONS:
case SR_CONF_DEVICE_OPTIONS:
switch (key) {
case SR_CONF_SCAN_OPTIONS:
case SR_CONF_DEVICE_OPTIONS:
case SR_CONF_SAMPLERATE:
if (!sdi)
return SR_ERR_ARG;
case SR_CONF_SAMPLERATE:
if (!sdi)
return SR_ERR_ARG;
if (devc->max_samplerate == SR_MHZ(200)) {
*data = std_gvar_samplerates(ARRAY_AND_SIZE(samplerates_la2016));
} else {
if (devc->max_samplerate == SR_MHZ(200)) {
*data = std_gvar_samplerates(ARRAY_AND_SIZE(samplerates_la2016));
} else {
ctx = drvc->sr_ctx;;
devc = sdi->priv;
ctx = drvc->sr_ctx;;
devc = sdi->priv;
- devc->convbuffer_size = LA2016_CONVBUFFER_SIZE;
- devc->convbuffer = g_try_malloc(devc->convbuffer_size);
- if (!devc->convbuffer) {
- sr_err("Cannot allocate conversion buffer.");
- return SR_ERR_MALLOC;
+ if (!devc->feed_queue) {
+ devc->feed_queue = feed_queue_logic_alloc(sdi,
+ LA2016_CONVBUFFER_SIZE, sizeof(uint16_t));
+ if (!devc->feed_queue) {
+ sr_err("Cannot allocate buffer for session feed.");
+ return SR_ERR_MALLOC;
+ }
+ sr_sw_limits_acquisition_start(&devc->sw_limits);
+
ret = la2016_setup_acquisition(sdi);
if (ret != SR_OK) {
ret = la2016_setup_acquisition(sdi);
if (ret != SR_OK) {
- g_free(devc->convbuffer);
- devc->convbuffer = NULL;
+ feed_queue_logic_free(devc->feed_queue);
+ devc->feed_queue = NULL;
return ret;
}
ret = la2016_start_acquisition(sdi);
if (ret != SR_OK) {
la2016_abort_acquisition(sdi);
return ret;
}
ret = la2016_start_acquisition(sdi);
if (ret != SR_OK) {
la2016_abort_acquisition(sdi);
- g_free(devc->convbuffer);
- devc->convbuffer = NULL;
+ feed_queue_logic_free(devc->feed_queue);
+ devc->feed_queue = NULL;
#define FPGA_FW_LA1016 "kingst-la1016-fpga.bitstream"
#define FPGA_FW_LA1016A "kingst-la1016a1-fpga.bitstream"
#define FPGA_FW_LA1016 "kingst-la1016-fpga.bitstream"
#define FPGA_FW_LA1016A "kingst-la1016a1-fpga.bitstream"
-/*
- * Default device configuration. Must be applicable to any of the
- * supported devices (no model specific default values yet). Specific
- * firmware implementation details unfortunately won't let us detect
- * and keep using previously configured values.
- */
-#define LA2016_DFLT_SAMPLERATE SR_MHZ(100)
-#define LA2016_DFLT_SAMPLEDEPTH (5 * 1000 * 1000)
-#define LA2016_DFLT_CAPT_RATIO 5 /* Capture ratio, in percent. */
-
/* USB vendor class control requests, executed by the Cypress FX2 MCU. */
#define CMD_FPGA_ENABLE 0x10
#define CMD_FPGA_SPI 0x20 /* R/W access to FPGA registers via SPI. */
/* USB vendor class control requests, executed by the Cypress FX2 MCU. */
#define CMD_FPGA_ENABLE 0x10
#define CMD_FPGA_SPI 0x20 /* R/W access to FPGA registers via SPI. */
- devc->capture_ratio = LA2016_DFLT_CAPT_RATIO;
- devc->limit_samples = LA2016_DFLT_SAMPLEDEPTH;
- devc->cur_samplerate = LA2016_DFLT_SAMPLERATE;
-
ret = set_threshold_voltage(sdi, devc->threshold_voltage);
if (ret)
return ret;
ret = set_threshold_voltage(sdi, devc->threshold_voltage);
if (ret)
return ret;
struct dev_context *devc;
double clock_divisor;
uint16_t divider_u16;
struct dev_context *devc;
double clock_divisor;
uint16_t divider_u16;
+ uint64_t limit_samples;
uint64_t pre_trigger_samples;
uint64_t pre_trigger_memory;
uint8_t buf[REG_TRIGGER - REG_SAMPLING]; /* Width of REG_SAMPLING. */
uint64_t pre_trigger_samples;
uint64_t pre_trigger_memory;
uint8_t buf[REG_TRIGGER - REG_SAMPLING]; /* Width of REG_SAMPLING. */
divider_u16 = (uint16_t)(clock_divisor + 0.5);
devc->cur_samplerate = devc->max_samplerate / divider_u16;
divider_u16 = (uint16_t)(clock_divisor + 0.5);
devc->cur_samplerate = devc->max_samplerate / divider_u16;
- if (devc->limit_samples > LA2016_NUM_SAMPLES_MAX) {
- sr_err("Too high a sample depth: %" PRIu64 ".",
- devc->limit_samples);
- return SR_ERR;
+ ret = sr_sw_limits_get_remain(&devc->sw_limits,
+ &limit_samples, NULL, NULL, NULL);
+ if (ret != SR_OK) {
+ sr_err("Cannot get acquisition limits.");
+ return ret;
- if (devc->limit_samples < LA2016_NUM_SAMPLES_MIN) {
- sr_err("Too low a sample depth: %" PRIu64 ".",
- devc->limit_samples);
- return SR_ERR;
+ if (limit_samples > LA2016_NUM_SAMPLES_MAX) {
+ sr_err("Too high a sample depth: %" PRIu64 ".", limit_samples);
+ return SR_ERR_ARG;
+ }
+ if (limit_samples < LA2016_NUM_SAMPLES_MIN) {
+ sr_err("Too low a sample depth: %" PRIu64 ".", limit_samples);
+ return SR_ERR_ARG;
* data. Only the upper 24 bits of that memory size spec get
* communicated to the device (written to its FPGA register).
*/
* data. Only the upper 24 bits of that memory size spec get
* communicated to the device (written to its FPGA register).
*/
- pre_trigger_samples = devc->limit_samples * devc->capture_ratio / 100;
+ pre_trigger_samples = limit_samples * devc->capture_ratio / 100;
pre_trigger_memory = LA2016_PRE_MEM_LIMIT_BASE;
pre_trigger_memory *= devc->capture_ratio;
pre_trigger_memory /= 100;
sr_dbg("Set sample config: %" PRIu64 "kHz, %" PRIu64 " samples.",
pre_trigger_memory = LA2016_PRE_MEM_LIMIT_BASE;
pre_trigger_memory *= devc->capture_ratio;
pre_trigger_memory /= 100;
sr_dbg("Set sample config: %" PRIu64 "kHz, %" PRIu64 " samples.",
- devc->cur_samplerate / 1000, devc->limit_samples);
+ devc->cur_samplerate / 1000, limit_samples);
sr_dbg("Capture ratio %" PRIu64 "%%, count %" PRIu64 ", mem %" PRIu64 ".",
devc->capture_ratio, pre_trigger_samples, pre_trigger_memory);
sr_dbg("Capture ratio %" PRIu64 "%%, count %" PRIu64 ", mem %" PRIu64 ".",
devc->capture_ratio, pre_trigger_samples, pre_trigger_memory);
+ if (!devc->trigger_involved) {
+ sr_dbg("Voiding pre-trigger setup. No trigger involved.");
+ pre_trigger_samples = 1;
+ pre_trigger_memory = 0x100;
+ }
+
/*
* The acquisition configuration occupies a total of 16 bytes:
* - A 34bit total samples count limit (up to 10 billions) that
/*
* The acquisition configuration occupies a total of 16 bytes:
* - A 34bit total samples count limit (up to 10 billions) that
* - An 8bit register of unknown meaning. Currently always 0.
*/
wrptr = buf;
* - An 8bit register of unknown meaning. Currently always 0.
*/
wrptr = buf;
- write_u40le_inc(&wrptr, devc->limit_samples);
+ write_u40le_inc(&wrptr, limit_samples);
write_u40le_inc(&wrptr, pre_trigger_samples);
write_u24le_inc(&wrptr, pre_trigger_memory >> 8);
write_u16le_inc(&wrptr, divider_u16);
write_u40le_inc(&wrptr, pre_trigger_samples);
write_u24le_inc(&wrptr, pre_trigger_memory >> 8);
write_u16le_inc(&wrptr, divider_u16);
const uint8_t *packets, size_t num_xfers)
{
struct dev_context *devc;
const uint8_t *packets, size_t num_xfers)
{
struct dev_context *devc;
- struct sr_datafeed_logic logic;
- struct sr_datafeed_packet sr_packet;
- unsigned int max_samples, n_samples, total_samples, free_n_samples;
- gboolean do_signal_trigger;
- uint8_t *wp;
const uint8_t *rp;
uint16_t sample_value;
size_t repetitions;
const uint8_t *rp;
uint16_t sample_value;
size_t repetitions;
- logic.unitsize = sizeof(sample_buff);
- logic.data = devc->convbuffer;
-
- sr_packet.type = SR_DF_LOGIC;
- sr_packet.payload = &logic;
-
- max_samples = devc->convbuffer_size / sizeof(sample_buff);
- n_samples = 0;
- wp = devc->convbuffer;
- total_samples = 0;
- do_signal_trigger = FALSE;
+ /* 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) {
if (devc->trigger_involved && !devc->trigger_marked && devc->info.n_rep_packets_before_trigger == 0) {
- std_session_send_df_trigger(sdi);
+ feed_queue_logic_send_trigger(devc->feed_queue);
devc->trigger_marked = TRUE;
}
devc->trigger_marked = TRUE;
}
while (num_xfers--) {
num_pkts = NUM_PACKETS_IN_CHUNK;
while (num_pkts--) {
while (num_xfers--) {
num_pkts = NUM_PACKETS_IN_CHUNK;
while (num_pkts--) {
- /*
- * Flush the conversion buffer when a trigger
- * location needs to get communicated, or when
- * an to-get-expected sample repetition count
- * would no longer fit into the buffer.
- */
- free_n_samples = max_samples - n_samples;
- if (free_n_samples < 256 || do_signal_trigger) {
- logic.length = n_samples * sizeof(sample_buff);;
- sr_session_send(sdi, &sr_packet);
- n_samples = 0;
- wp = devc->convbuffer;
- if (do_signal_trigger) {
- std_session_send_df_trigger(sdi);
- do_signal_trigger = FALSE;
- }
- }
sample_value = read_u16le_inc(&rp);
repetitions = read_u8_inc(&rp);
sample_value = read_u16le_inc(&rp);
repetitions = read_u8_inc(&rp);
- n_samples += repetitions;
- total_samples += repetitions;
devc->total_samples += repetitions;
write_u16le(sample_buff, sample_value);
devc->total_samples += repetitions;
write_u16le(sample_buff, sample_value);
- while (repetitions--) {
- memcpy(wp, sample_buff, logic.unitsize);
- wp += logic.unitsize;
- }
+ 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) {
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;
devc->trigger_marked = TRUE;
- do_signal_trigger = TRUE;
sr_dbg("Trigger position after %" PRIu64 " samples, %.6fms.",
devc->total_samples,
(double)devc->total_samples / devc->cur_samplerate * 1e3);
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. */
}
}
(void)read_u8_inc(&rp); /* Skip sequence number. */
}
- if (n_samples) {
- logic.length = n_samples * logic.unitsize;
- sr_session_send(sdi, &sr_packet);
- if (do_signal_trigger) {
- std_session_send_df_trigger(sdi);
- }
+
+ 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("Send_chunk done after %u samples.", total_samples);
+ sr_dbg("Total samples after chunk: %" PRIu64 ".", devc->total_samples);
}
static void LIBUSB_CALL 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;
struct sr_usb_dev_inst *usb;
struct sr_dev_inst *sdi;
struct dev_context *devc;
struct sr_usb_dev_inst *usb;
int ret;
sdi = transfer->user_data;
int ret;
sdi = transfer->user_data;
sr_dbg("receive_transfer(): status %s received %d bytes.",
libusb_error_name(transfer->status), transfer->actual_length);
sr_dbg("receive_transfer(): status %s received %d bytes.",
libusb_error_name(transfer->status), transfer->actual_length);
-
- if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) {
- sr_err("USB bulk transfer timeout.");
- devc->download_finished = TRUE;
- }
- send_chunk(sdi, transfer->buffer, transfer->actual_length / TRANSFER_PACKET_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) {
devc->n_bytes_to_read -= transfer->actual_length;
if (devc->n_bytes_to_read) {
struct dev_context *devc;
struct drv_context *drvc;
struct timeval tv;
struct dev_context *devc;
struct drv_context *drvc;
struct timeval tv;
devc = sdi->priv;
drvc = sdi->driver->context;
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 (!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;
}
/* 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;
devc->completion_seen = TRUE;
devc->download_finished = FALSE;
devc->trigger_marked = FALSE;
devc->total_samples = 0;
- /* We can start downloading sample data. */
- if (la2016_start_download(sdi, receive_transfer) != SR_OK) {
+
+ /* 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.");
sr_err("Cannot start acquisition data download.");
return FALSE;
}
sr_dbg("Acquisition data download started.");
- std_session_send_df_frame_begin(sdi);
+ /* Handle USB reception. Drives sample data download. */
tv.tv_sec = tv.tv_usec = 0;
libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
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.");
if (devc->download_finished) {
sr_dbg("Download finished, post processing.");
- std_session_send_df_frame_end(sdi);
-
- usb_source_remove(sdi->session, drvc->sr_ctx);
- std_session_send_df_end(sdi);
la2016_stop_acquisition(sdi);
la2016_stop_acquisition(sdi);
-
- g_free(devc->convbuffer);
- devc->convbuffer = NULL;
-
+ usb_source_remove(sdi->session, drvc->sr_ctx);
+ 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.");
}
sr_dbg("Download finished, done post processing.");
}
float threshold_voltage;
uint64_t max_samplerate;
uint64_t cur_samplerate;
float threshold_voltage;
uint64_t max_samplerate;
uint64_t cur_samplerate;
- uint64_t limit_samples;
+ struct sr_sw_limits sw_limits;
uint64_t capture_ratio;
/* Internal acquisition and download state. */
uint64_t capture_ratio;
/* Internal acquisition and download state. */
uint64_t total_samples;
uint32_t read_pos;
uint64_t total_samples;
uint32_t read_pos;
- size_t convbuffer_size;
- uint8_t *convbuffer;
+ struct feed_queue_logic *feed_queue;
struct libusb_transfer *transfer;
};
struct libusb_transfer *transfer;
};