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)); + 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: - devc->limit_msec = g_variant_get_uint64(data); - break; 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);