From: Gerhard Sittig Date: Sun, 10 May 2020 14:45:17 +0000 (+0200) Subject: asix-sigma: rework time/count limits support, accept more samplerates X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=5e78a56481769db6ffe9b9fd392d71be3fcf0319;p=libsigrok.git asix-sigma: rework time/count limits support, accept more samplerates Use common support for SW limits, and untangle the formerly convoluted logic for sample count or time limits. Accept user provided samplerate values when the hardware supports them, also those which are not listed. The previous implementation mapped sample count limits to timeout specs which depend on the samplerate. The order of applications' calls into the config set routines is unspecified, the use of one common storage space led to an arbitrary resulting value for the msecs limit, and loss of user specified values for read-back. Separate the input which was specified by applications, from limits which were derived from this input and determine the acquisition phase's duration, from sample count limits which apply to sample data download and session feed submission after the acquisition finished. This allows to configure the values in any order, to read back previously configured values, and to run arbitrary numbers of acquisition and download cycles without losing input specs. This commit also concentrates all the limits related computation in a single location at the start of the acquisition. Moves the submission buffer's count limit container to the device context where the other limits are kept as well. Renames the samplerate variable, and drops an aggressive check for supported rates (now uses hardware constraints as the only condition). Removes an unused variable in the device context. --- diff --git a/src/hardware/asix-sigma/api.c b/src/hardware/asix-sigma/api.c index 15c22252..38814872 100644 --- a/src/hardware/asix-sigma/api.c +++ b/src/hardware/asix-sigma/api.c @@ -233,12 +233,9 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) 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; } @@ -310,14 +307,11 @@ static int config_get(uint32_t key, GVariant **data, *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); @@ -334,6 +328,8 @@ static int config_set(uint32_t key, GVariant *data, 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; @@ -341,15 +337,24 @@ static int config_set(uint32_t key, GVariant *data, 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); @@ -400,22 +405,32 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) 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); @@ -432,7 +447,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) 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); @@ -457,10 +472,10 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) 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 { @@ -471,7 +486,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) * (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; @@ -485,7 +500,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) (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; diff --git a/src/hardware/asix-sigma/protocol.c b/src/hardware/asix-sigma/protocol.c index 1a667d48..fe90274f 100644 --- a/src/hardware/asix-sigma/protocol.c +++ b/src/hardware/asix-sigma/protocol.c @@ -568,48 +568,132 @@ static int upload_firmware(struct sr_context *ctx, } /* - * 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 @@ -629,29 +713,16 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler } /* - * 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; } @@ -674,7 +745,6 @@ struct submit_buffer { 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) @@ -697,7 +767,7 @@ 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)); @@ -710,26 +780,33 @@ static int alloc_submit_buffer(struct sr_dev_inst *sdi) 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; } @@ -778,10 +855,12 @@ static int addto_submit_buffer(struct dev_context *devc, 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; /* @@ -798,8 +877,8 @@ static int addto_submit_buffer(struct dev_context *devc, 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; } @@ -837,7 +916,7 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi) /* 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 " @@ -1066,7 +1145,7 @@ static void sigma_decode_dram_cluster(struct dev_context *devc, 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); @@ -1075,7 +1154,7 @@ static void sigma_decode_dram_cluster(struct dev_context *devc, 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); @@ -1114,7 +1193,7 @@ static int decode_chunk_ts(struct dev_context *devc, /* 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); } @@ -1196,8 +1275,6 @@ static int download_capture(struct sr_dev_inst *sdi) 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 @@ -1220,7 +1297,7 @@ static int download_capture(struct sr_dev_inst *sdi) 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; @@ -1278,18 +1355,9 @@ static int download_capture(struct sr_dev_inst *sdi) 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; diff --git a/src/hardware/asix-sigma/protocol.h b/src/hardware/asix-sigma/protocol.h index 99d62a6c..1379b071 100644 --- a/src/hardware/asix-sigma/protocol.h +++ b/src/hardware/asix-sigma/protocol.h @@ -303,14 +303,12 @@ struct dev_context { enum asix_device_type type; } id; struct ftdi_context ftdic; - uint64_t cur_samplerate; - uint64_t limit_msec; - uint64_t limit_samples; - uint64_t sent_samples; - uint64_t start_time; + uint64_t samplerate; + struct sr_sw_limits cfg_limits; /* Configured limits (user specified). */ + struct sr_sw_limits acq_limits; /* Acquisition limits (internal use). */ + struct sr_sw_limits feed_limits; /* Datafeed limits (internal use). */ int cur_firmware; int num_channels; - int cur_channels; int samples_per_event; uint64_t capture_ratio; struct sigma_trigger trigger; @@ -326,9 +324,9 @@ SR_PRIV int sigma_write_register(uint8_t reg, uint8_t *data, size_t len, struct dev_context *devc); SR_PRIV int sigma_set_register(uint8_t reg, uint8_t value, struct dev_context *devc); SR_PRIV int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *devc); -SR_PRIV uint64_t sigma_limit_samples_to_msec(const struct dev_context *devc, - uint64_t limit_samples); -SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate); +SR_PRIV int sigma_normalize_samplerate(uint64_t want_rate, uint64_t *have_rate); +SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi); +SR_PRIV int sigma_set_acquire_timeout(struct dev_context *devc); SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi); SR_PRIV int sigma_receive_data(int fd, int revents, void *cb_data); SR_PRIV int sigma_build_basic_trigger(struct triggerlut *lut, struct dev_context *devc);