devc->id.serno = serno_num;
devc->id.prefix = serno_pre;
devc->id.type = dev_type;
- devc->cur_samplerate = samplerates[0];
- devc->limit_msec = 0;
- devc->limit_samples = 0;
+ devc->samplerate = samplerates[0];
+ sr_sw_limits_init(&devc->cfg_limits);
devc->cur_firmware = -1;
- devc->num_channels = 0;
- devc->samples_per_event = 0;
devc->capture_ratio = 50;
devc->use_triggers = 0;
}
*data = g_variant_new_string(sdi->connection_id);
break;
case SR_CONF_SAMPLERATE:
- *data = g_variant_new_uint64(devc->cur_samplerate);
+ *data = g_variant_new_uint64(devc->samplerate);
break;
case SR_CONF_LIMIT_MSEC:
- *data = g_variant_new_uint64(devc->limit_msec);
- break;
case SR_CONF_LIMIT_SAMPLES:
- *data = g_variant_new_uint64(devc->limit_samples);
- break;
+ return sr_sw_limits_config_get(&devc->cfg_limits, key, data);
#if ASIX_SIGMA_WITH_TRIGGER
case SR_CONF_CAPTURE_RATIO:
*data = g_variant_new_uint64(devc->capture_ratio);
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
+ int ret;
+ uint64_t want_rate, have_rate;
(void)cg;
switch (key) {
case SR_CONF_SAMPLERATE:
- return sigma_set_samplerate(sdi, g_variant_get_uint64(data));
- case SR_CONF_LIMIT_MSEC:
- devc->limit_msec = g_variant_get_uint64(data);
+ want_rate = g_variant_get_uint64(data);
+ ret = sigma_normalize_samplerate(want_rate, &have_rate);
+ if (ret != SR_OK)
+ return ret;
+ if (have_rate != want_rate) {
+ char *text_want, *text_have;
+ text_want = sr_samplerate_string(want_rate);
+ text_have = sr_samplerate_string(have_rate);
+ sr_info("Adjusted samplerate %s to %s.",
+ text_want, text_have);
+ g_free(text_want);
+ g_free(text_have);
+ }
+ devc->samplerate = have_rate;
break;
+ case SR_CONF_LIMIT_MSEC:
case SR_CONF_LIMIT_SAMPLES:
- devc->limit_samples = g_variant_get_uint64(data);
- devc->limit_msec = sigma_limit_samples_to_msec(devc,
- devc->limit_samples);
- break;
+ return sr_sw_limits_config_set(&devc->cfg_limits, key, data);
#if ASIX_SIGMA_WITH_TRIGGER
case SR_CONF_CAPTURE_RATIO:
devc->capture_ratio = g_variant_get_uint64(data);
devc = sdi->priv;
+ /*
+ * Setup the device's samplerate from the value which up to now
+ * just got checked and stored. As a byproduct this can pick and
+ * send firmware to the device, reduce the number of available
+ * logic channels, etc.
+ *
+ * Determine an acquisition timeout from optionally configured
+ * sample count or time limits. Which depends on the samplerate.
+ */
+ ret = sigma_set_samplerate(sdi);
+ if (ret != SR_OK)
+ return ret;
+ ret = sigma_set_acquire_timeout(devc);
+ if (ret != SR_OK)
+ return ret;
+
if (sigma_convert_trigger(sdi) != SR_OK) {
sr_err("Failed to configure triggers.");
return SR_ERR;
}
- /* If the samplerate has not been set, default to 200 kHz. */
- if (devc->cur_firmware == -1) {
- if ((ret = sigma_set_samplerate(sdi, SR_KHZ(200))) != SR_OK)
- return ret;
- }
-
/* Enter trigger programming mode. */
sigma_set_register(WRITE_TRIGGER_SELECT2, 0x20, devc);
triggerselect = 0;
- if (devc->cur_samplerate >= SR_MHZ(100)) {
+ if (devc->samplerate >= SR_MHZ(100)) {
/* 100 and 200 MHz mode. */
sigma_set_register(WRITE_TRIGGER_SELECT2, 0x81, devc);
if (devc->trigger.fallingmask)
triggerselect |= 1 << 3;
- } else if (devc->cur_samplerate <= SR_MHZ(50)) {
+ } else if (devc->samplerate <= SR_MHZ(50)) {
/* All other modes. */
sigma_build_basic_trigger(&lut, devc);
clockselect.async = 0;
clockselect.fraction = 1 - 1; /* Divider 1. */
clockselect.disabled_channels = 0x0000; /* All channels enabled. */
- if (devc->cur_samplerate == SR_MHZ(200)) {
+ if (devc->samplerate == SR_MHZ(200)) {
/* Enable 4 channels. */
clockselect.disabled_channels = 0xf0ff;
- } else if (devc->cur_samplerate == SR_MHZ(100)) {
+ } else if (devc->samplerate == SR_MHZ(100)) {
/* Enable 8 channels. */
clockselect.disabled_channels = 0x00ff;
} else {
* (The driver lists a discrete set of sample rates, but
* all of them fit the above description.)
*/
- clockselect.fraction = SR_MHZ(50) / devc->cur_samplerate - 1;
+ clockselect.fraction = SR_MHZ(50) / devc->samplerate - 1;
}
clock_idx = 0;
clock_bytes[clock_idx++] = clockselect.async;
(devc->capture_ratio * 255) / 100, devc);
/* Start acqusition. */
- devc->start_time = g_get_monotonic_time();
regval = WMR_TRGRES | WMR_SDRAMWRITEEN;
#if ASIX_SIGMA_WITH_TRIGGER
regval |= WMR_TRGEN;
}
/*
- * Sigma doesn't support limiting the number of samples, so we have to
- * translate the number and the samplerate to an elapsed time.
+ * The driver supports user specified time or sample count limits. The
+ * device's hardware supports neither, and hardware compression prevents
+ * reliable detection of "fill levels" (currently reached sample counts)
+ * from register values during acquisition. That's why the driver needs
+ * to apply some heuristics:
*
- * In addition we need to ensure that the last data cluster has passed
- * the hardware pipeline, and became available to the PC side. With RLE
- * compression up to 327ms could pass before another cluster accumulates
- * at 200kHz samplerate when input pins don't change.
+ * - The (optional) sample count limit and the (normalized) samplerate
+ * get mapped to an estimated duration for these samples' acquisition.
+ * - The (optional) time limit gets checked as well. The lesser of the
+ * two limits will terminate the data acquisition phase. The exact
+ * sample count limit gets enforced in session feed submission paths.
+ * - Some slack needs to be given to account for hardware pipelines as
+ * well as late storage of last chunks after compression thresholds
+ * are tripped. The resulting data set will span at least the caller
+ * specified period of time, which shall be perfectly acceptable.
+ *
+ * With RLE compression active, up to 64K sample periods can pass before
+ * a cluster accumulates. Which translates to 327ms at 200kHz. Add two
+ * times that period for good measure, one is not enough to flush the
+ * hardware pipeline (observation from an earlier experiment).
*/
-SR_PRIV uint64_t sigma_limit_samples_to_msec(const struct dev_context *devc,
- uint64_t limit_samples)
+SR_PRIV int sigma_set_acquire_timeout(struct dev_context *devc)
{
- uint64_t limit_msec;
+ int ret;
+ GVariant *data;
+ uint64_t user_count, user_msecs;
uint64_t worst_cluster_time_ms;
+ uint64_t count_msecs, acquire_msecs;
- limit_msec = limit_samples * 1000 / devc->cur_samplerate;
- worst_cluster_time_ms = 65536 * 1000 / devc->cur_samplerate;
- /*
- * One cluster time is not enough to flush pipeline when sampling
- * grounded pins with 1 sample limit at 200kHz. Hence the 2* fix.
- */
- return limit_msec + 2 * worst_cluster_time_ms;
+ sr_sw_limits_init(&devc->acq_limits);
+
+ /* Get sample count limit, convert to msecs. */
+ ret = sr_sw_limits_config_get(&devc->cfg_limits,
+ SR_CONF_LIMIT_SAMPLES, &data);
+ if (ret != SR_OK)
+ return ret;
+ user_count = g_variant_get_uint64(data);
+ g_variant_unref(data);
+ count_msecs = 0;
+ if (user_count)
+ count_msecs = 1000 * user_count / devc->samplerate + 1;
+
+ /* Get time limit, which is in msecs. */
+ ret = sr_sw_limits_config_get(&devc->cfg_limits,
+ SR_CONF_LIMIT_MSEC, &data);
+ if (ret != SR_OK)
+ return ret;
+ user_msecs = g_variant_get_uint64(data);
+ g_variant_unref(data);
+
+ /* Get the lesser of them, with both being optional. */
+ acquire_msecs = ~0ull;
+ if (user_count && count_msecs < acquire_msecs)
+ acquire_msecs = count_msecs;
+ if (user_msecs && user_msecs < acquire_msecs)
+ acquire_msecs = user_msecs;
+ if (acquire_msecs == ~0ull)
+ return SR_OK;
+
+ /* Add some slack, and use that timeout for acquisition. */
+ worst_cluster_time_ms = 1000 * 65536 / devc->samplerate;
+ acquire_msecs += 2 * worst_cluster_time_ms;
+ data = g_variant_new_uint64(acquire_msecs);
+ ret = sr_sw_limits_config_set(&devc->acq_limits,
+ SR_CONF_LIMIT_MSEC, data);
+ g_variant_unref(data);
+ if (ret != SR_OK)
+ return ret;
+
+ sr_sw_limits_acquisition_start(&devc->acq_limits);
+ return SR_OK;
}
-SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate)
+/*
+ * Check whether a caller specified samplerate matches the device's
+ * hardware constraints (can be used for acquisition). Optionally yield
+ * a value that approximates the original spec.
+ *
+ * This routine assumes that input specs are in the 200kHz to 200MHz
+ * range of supported rates, and callers typically want to normalize a
+ * given value to the hardware capabilities. Values in the 50MHz range
+ * get rounded up by default, to avoid a more expensive check for the
+ * closest match, while higher sampling rate is always desirable during
+ * measurement. Input specs which exactly match hardware capabilities
+ * remain unaffected. Because 100/200MHz rates also limit the number of
+ * available channels, they are not suggested by this routine, instead
+ * callers need to pick them consciously.
+ */
+SR_PRIV int sigma_normalize_samplerate(uint64_t want_rate, uint64_t *have_rate)
+{
+ uint64_t div, rate;
+
+ /* Accept exact matches for 100/200MHz. */
+ if (want_rate == SR_MHZ(200) || want_rate == SR_MHZ(100)) {
+ if (have_rate)
+ *have_rate = want_rate;
+ return SR_OK;
+ }
+
+ /* Accept 200kHz to 50MHz range, and map to near value. */
+ if (want_rate >= SR_KHZ(200) && want_rate <= SR_MHZ(50)) {
+ div = SR_MHZ(50) / want_rate;
+ rate = SR_MHZ(50) / div;
+ if (have_rate)
+ *have_rate = rate;
+ return SR_OK;
+ }
+
+ return SR_ERR_ARG;
+}
+
+SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
struct drv_context *drvc;
- size_t i;
+ uint64_t samplerate;
int ret;
int num_channels;
devc = sdi->priv;
drvc = sdi->driver->context;
- ret = SR_OK;
- /* Reject rates that are not in the list of supported rates. */
- for (i = 0; i < samplerates_count; i++) {
- if (samplerates[i] == samplerate)
- break;
- }
- if (i >= samplerates_count || samplerates[i] == 0)
- return SR_ERR_SAMPLERATE;
+ /* Accept any caller specified rate which the hardware supports. */
+ ret = sigma_normalize_samplerate(devc->samplerate, &samplerate);
+ if (ret != SR_OK)
+ return ret;
/*
* Depending on the samplerates of 200/100/50- MHz, specific
}
/*
- * Derive the sample period from the sample rate as well as the
- * number of samples that the device will communicate within
- * an "event" (memory organization internal to the device).
+ * The samplerate affects the number of available logic channels
+ * as well as a sample memory layout detail (the number of samples
+ * which the device will communicate within an "event").
*/
if (ret == SR_OK) {
devc->num_channels = num_channels;
- devc->cur_samplerate = samplerate;
devc->samples_per_event = 16 / devc->num_channels;
devc->state.state = SIGMA_IDLE;
}
- /*
- * Support for "limit_samples" is implemented by stopping
- * acquisition after a corresponding period of time.
- * Re-calculate that period of time, in case the limit is
- * set first and the samplerate gets (re-)configured later.
- */
- if (ret == SR_OK && devc->limit_samples) {
- uint64_t msecs;
- msecs = sigma_limit_samples_to_msec(devc, devc->limit_samples);
- devc->limit_msec = msecs;
- }
-
return ret;
}
struct sr_dev_inst *sdi;
struct sr_datafeed_packet packet;
struct sr_datafeed_logic logic;
- struct sr_sw_limits limit_samples;
};
static int alloc_submit_buffer(struct sr_dev_inst *sdi)
if (!buffer->sample_data)
return SR_ERR_MALLOC;
buffer->write_pointer = buffer->sample_data;
- sr_sw_limits_init(&buffer->limit_samples);
+ sr_sw_limits_init(&devc->feed_limits);
buffer->sdi = sdi;
memset(&buffer->logic, 0, sizeof(buffer->logic));
return SR_OK;
}
-static int setup_submit_buffer(struct dev_context *devc)
+static int setup_submit_limit(struct dev_context *devc)
{
- struct submit_buffer *buffer;
+ struct sr_sw_limits *limits;
int ret;
GVariant *data;
uint64_t total;
- buffer = devc->buffer;
+ limits = &devc->feed_limits;
- total = devc->limit_samples;
+ ret = sr_sw_limits_config_get(&devc->cfg_limits,
+ SR_CONF_LIMIT_SAMPLES, &data);
+ if (ret != SR_OK)
+ return ret;
+ total = g_variant_get_uint64(data);
+ g_variant_unref(data);
+
+ sr_sw_limits_init(limits);
if (total) {
data = g_variant_new_uint64(total);
- ret = sr_sw_limits_config_set(&buffer->limit_samples,
+ ret = sr_sw_limits_config_set(limits,
SR_CONF_LIMIT_SAMPLES, data);
g_variant_unref(data);
if (ret != SR_OK)
return ret;
}
- sr_sw_limits_acquisition_start(&buffer->limit_samples);
+ sr_sw_limits_acquisition_start(limits);
return SR_OK;
}
uint16_t sample, size_t count)
{
struct submit_buffer *buffer;
+ struct sr_sw_limits *limits;
int ret;
buffer = devc->buffer;
- if (sr_sw_limits_check(&buffer->limit_samples))
+ limits = &devc->feed_limits;
+ if (sr_sw_limits_check(limits))
count = 0;
/*
if (ret != SR_OK)
return ret;
}
- sr_sw_limits_update_samples_read(&buffer->limit_samples, 1);
- if (sr_sw_limits_check(&buffer->limit_samples))
+ sr_sw_limits_update_samples_read(limits, 1);
+ if (sr_sw_limits_check(limits))
break;
}
/* Ignore disabled channels with a trigger. */
continue;
channelbit = 1 << (match->channel->index);
- if (devc->cur_samplerate >= SR_MHZ(100)) {
+ if (devc->samplerate >= SR_MHZ(100)) {
/* Fast trigger support. */
if (trigger_set) {
sr_err("Only a single pin trigger is "
sample = 0;
for (i = 0; i < events_in_cluster; i++) {
item16 = sigma_dram_cluster_data(dram_cluster, i);
- if (devc->cur_samplerate == SR_MHZ(200)) {
+ if (devc->samplerate == SR_MHZ(200)) {
sample = sigma_deinterlace_200mhz_data(item16, 0);
check_and_submit_sample(devc, sample, 1, triggered);
sample = sigma_deinterlace_200mhz_data(item16, 1);
check_and_submit_sample(devc, sample, 1, triggered);
sample = sigma_deinterlace_200mhz_data(item16, 3);
check_and_submit_sample(devc, sample, 1, triggered);
- } else if (devc->cur_samplerate == SR_MHZ(100)) {
+ } else if (devc->samplerate == SR_MHZ(100)) {
sample = sigma_deinterlace_100mhz_data(item16, 0);
check_and_submit_sample(devc, sample, 1, triggered);
sample = sigma_deinterlace_100mhz_data(item16, 1);
/* Check if trigger is in this chunk. */
if (trigger_event < EVENTS_PER_ROW) {
- if (devc->cur_samplerate <= SR_MHZ(50)) {
+ if (devc->samplerate <= SR_MHZ(50)) {
trigger_event -= MIN(EVENTS_PER_CLUSTER - 1,
trigger_event);
}
trg_event = triggerpos & 0x1ff;
}
- devc->sent_samples = 0;
-
/*
* Determine how many "DRAM lines" of 1024 bytes each we need to
* retrieve from the Sigma hardware, so that we have a complete
ret = alloc_submit_buffer(sdi);
if (ret != SR_OK)
return FALSE;
- ret = setup_submit_buffer(devc);
+ ret = setup_submit_limit(devc);
if (ret != SR_OK)
return FALSE;
dl_lines_done = 0;
static int sigma_capture_mode(struct sr_dev_inst *sdi)
{
struct dev_context *devc;
- uint64_t running_msec;
- uint64_t current_time;
devc = sdi->priv;
-
- /*
- * Check if the selected sampling duration passed. Sample count
- * limits are covered by this enforced timeout as well.
- */
- current_time = g_get_monotonic_time();
- running_msec = (current_time - devc->start_time) / 1000;
- if (running_msec >= devc->limit_msec)
+ if (sr_sw_limits_check(&devc->acq_limits))
return download_capture(sdi);
return TRUE;