sysclk-lwla: Implement SR_CONF_LIMIT_MSEC.

Allow the acquisition to be constrained by time in addition to
a sample count limit.  Since the LWLA protocol actually provides
only a duration natively, implement the sample count limit on top
of the new duration limit.

With this change, limiting an acquisition in external clock mode
should finally work properly.
This commit is contained in:
Daniel Elstner 2014-01-18 16:08:39 +01:00
parent 17794067f9
commit 29d587670d
3 changed files with 100 additions and 44 deletions

View File

@ -30,6 +30,7 @@ static const int32_t hwcaps[] = {
SR_CONF_SAMPLERATE,
SR_CONF_EXTERNAL_CLOCK,
SR_CONF_TRIGGER_TYPE,
SR_CONF_LIMIT_MSEC,
SR_CONF_LIMIT_SAMPLES,
};
@ -254,6 +255,9 @@ static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
case SR_CONF_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;
@ -271,8 +275,8 @@ static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_probe_group *probe_group)
{
uint64_t value;
struct dev_context *devc;
uint64_t rate;
(void)probe_group;
@ -282,15 +286,24 @@ static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
switch (key) {
case SR_CONF_SAMPLERATE:
rate = g_variant_get_uint64(data);
sr_info("Setting samplerate %" G_GUINT64_FORMAT, rate);
if (rate > samplerates[0]
|| rate < samplerates[G_N_ELEMENTS(samplerates) - 1])
value = g_variant_get_uint64(data);
sr_info("Setting samplerate %" PRIu64, value);
if (value < samplerates[G_N_ELEMENTS(samplerates) - 1]
|| value > samplerates[0])
return SR_ERR_SAMPLERATE;
devc->samplerate = rate;
devc->samplerate = value;
break;
case SR_CONF_LIMIT_MSEC:
value = g_variant_get_uint64(data);
if (value > MAX_LIMIT_MSEC)
return SR_ERR_ARG;
devc->limit_msec = value;
break;
case SR_CONF_LIMIT_SAMPLES:
devc->limit_samples = g_variant_get_uint64(data);
value = g_variant_get_uint64(data);
if (value > MAX_LIMIT_SAMPLES)
return SR_ERR_ARG;
devc->limit_samples = value;
break;
case SR_CONF_EXTERNAL_CLOCK:
if (g_variant_get_boolean(data)) {

View File

@ -64,11 +64,13 @@ static int submit_transfer(struct dev_context *devc,
static int capture_setup(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
struct acquisition_state *acq;
uint64_t divider_count;
uint64_t memory_limit;
uint16_t command[3 + 10*4];
devc = sdi->priv;
acq = devc->acquisition;
command[0] = LWLA_WORD(CMD_CAP_SETUP);
command[1] = LWLA_WORD(0); /* address */
@ -83,9 +85,7 @@ static int capture_setup(const struct sr_dev_inst *sdi)
* 100 MHz. At the highest samplerate of 125 MHz the clock divider
* is bypassed.
*/
if (devc->cur_clock_source == CLOCK_SOURCE_INT
&& devc->samplerate > 0
&& devc->samplerate < SR_MHZ(100))
if (!acq->bypass_clockdiv && devc->samplerate > 0)
divider_count = SR_MHZ(100) / devc->samplerate - 1;
else
divider_count = 0;
@ -231,8 +231,7 @@ static void issue_read_start(const struct sr_dev_inst *sdi)
acq->sample = 0;
acq->run_len = 0;
acq->captured_samples = 0;
acq->transferred_samples = 0;
acq->samples_done = 0;
/* For some reason, the start address is 4 rather than 0. */
acq->mem_addr_done = 4;
@ -348,7 +347,6 @@ static void issue_stop_capture(const struct sr_dev_inst *sdi)
static void process_capture_status(const struct sr_dev_inst *sdi)
{
uint64_t duration;
uint64_t timescale;
struct dev_context *devc;
struct acquisition_state *acq;
@ -371,17 +369,22 @@ static void process_capture_status(const struct sr_dev_inst *sdi)
acq->capture_flags = LWLA_READ32(&acq->xfer_buf_in[16])
& STATUS_FLAG_MASK;
/* The 125 MHz setting is special, and uses the same timebase
* for the duration field as the 100 MHz setting.
/* The LWLA1034 runs at 125 MHz if the clock divider is bypassed.
* However, the time base used for the duration is apparently not
* adjusted for this "boost" mode. Whereas normally the duration
* unit is 1 ms, it is 0.8 ms when the clock divider is bypassed.
* As 0.8 = 100 MHz / 125 MHz, it seems that the internal cycle
* counter period is the same as at the 100 MHz setting.
*/
timescale = MIN(devc->samplerate, SR_MHZ(100));
acq->captured_samples = duration * timescale / 1000;
if (acq->bypass_clockdiv)
acq->duration_now = duration * 4 / 5;
else
acq->duration_now = duration;
sr_spew("Captured %lu words, %" PRIu64 " samples, flags 0x%02X",
(unsigned long)acq->mem_addr_fill,
acq->captured_samples, acq->capture_flags);
sr_spew("Captured %zu words, %" PRIu64 " ms, flags 0x%02X",
acq->mem_addr_fill, acq->duration_now, acq->capture_flags);
if (acq->captured_samples >= devc->limit_samples) {
if (acq->duration_now >= acq->duration_max) {
issue_stop_capture(sdi);
return;
}
@ -447,7 +450,7 @@ static gboolean send_logic_packet(const struct sr_dev_inst *sdi)
devc = sdi->priv;
acq = devc->acquisition;
if (acq->transferred_samples >= devc->limit_samples)
if (acq->samples_done >= acq->samples_max)
return TRUE;
packet.type = SR_DF_LOGIC;
@ -460,12 +463,12 @@ static gboolean send_logic_packet(const struct sr_dev_inst *sdi)
last = FALSE;
/* Cut the packet short if necessary. */
if (acq->transferred_samples + samples >= devc->limit_samples) {
samples = devc->limit_samples - acq->transferred_samples;
if (acq->samples_done + samples >= acq->samples_max) {
samples = acq->samples_max - acq->samples_done;
logic.length = samples * UNIT_SIZE;
last = TRUE;
}
acq->transferred_samples += samples;
acq->samples_done += samples;
acq->out_offset = 0;
/* Send off logic datafeed packet. */
@ -500,7 +503,7 @@ static int process_sample_data(const struct sr_dev_inst *sdi)
acq = devc->acquisition;
if (acq->mem_addr_done >= acq->mem_addr_stop
|| acq->transferred_samples >= devc->limit_samples)
|| acq->samples_done >= acq->samples_max)
return SR_OK;
in_words_left = MIN(acq->mem_addr_stop - acq->mem_addr_done,
@ -681,7 +684,7 @@ static void receive_transfer_in(struct libusb_transfer *transfer)
case STATE_READ_RESPONSE:
if (process_sample_data(sdi) == SR_OK
&& acq->mem_addr_next < acq->mem_addr_stop
&& acq->transferred_samples < devc->limit_samples)
&& acq->samples_done < acq->samples_max)
request_read_mem(sdi);
else
issue_read_end(sdi);
@ -777,12 +780,43 @@ SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
struct sr_usb_dev_inst *usb;
struct acquisition_state *acq;
struct regval_pair regvals[7];
int ret;
gboolean bypass;
devc = sdi->priv;
usb = sdi->conn;
acq = devc->acquisition;
/* By default, run virtually unlimited. */
acq->duration_max = (devc->limit_msec > 0)
? devc->limit_msec : MAX_LIMIT_MSEC;
acq->samples_max = (devc->limit_samples > 0)
? devc->limit_samples : MAX_LIMIT_SAMPLES;
switch (devc->cur_clock_source) {
case CLOCK_SOURCE_INT:
if (devc->samplerate == 0)
return SR_ERR_BUG;
/* At 125 MHz, the clock divider is bypassed. */
acq->bypass_clockdiv = (devc->samplerate > SR_MHZ(100));
/* If only one of the limits is set, derive the other one. */
if (devc->limit_msec == 0 && devc->limit_samples > 0)
acq->duration_max = devc->limit_samples
* 1000 / devc->samplerate + 1;
else if (devc->limit_samples == 0 && devc->limit_msec > 0)
acq->samples_max = devc->limit_msec
* devc->samplerate / 1000;
break;
case CLOCK_SOURCE_EXT_FALL:
case CLOCK_SOURCE_EXT_RISE:
acq->bypass_clockdiv = TRUE;
break;
default:
sr_err("No valid clock source has been configured.");
return SR_ERR;
}
regvals[0].reg = REG_MEM_CTRL2;
regvals[0].val = 2;
@ -802,20 +836,8 @@ SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi)
regvals[5].reg = REG_CMD_CTRL1;
regvals[5].val = 0;
switch (devc->cur_clock_source) {
case CLOCK_SOURCE_INT:
bypass = (devc->samplerate > SR_MHZ(100));
break;
case CLOCK_SOURCE_EXT_FALL:
case CLOCK_SOURCE_EXT_RISE:
bypass = TRUE;
break;
default:
bypass = FALSE;
break;
}
regvals[6].reg = REG_DIV_BYPASS;
regvals[6].val = bypass;
regvals[6].val = acq->bypass_clockdiv;
ret = lwla_write_regs(usb, regvals, G_N_ELEMENTS(regvals));
if (ret != SR_OK)
@ -839,6 +861,8 @@ SR_PRIV int lwla_start_acquisition(const struct sr_dev_inst *sdi)
usb = sdi->conn;
acq = devc->acquisition;
acq->duration_now = 0;
libusb_fill_bulk_transfer(acq->xfer_out, usb->devhdl, EP_COMMAND,
(unsigned char *)acq->xfer_buf_out, 0,
&receive_transfer_out,

View File

@ -89,6 +89,14 @@
*/
#define DEFAULT_SAMPLERATE SR_MHZ(125)
/** Maximum configurable sample count limit.
*/
#define MAX_LIMIT_SAMPLES (UINT64_C(1) << 48)
/** Maximum configurable capture duration in milliseconds.
*/
#define MAX_LIMIT_MSEC (UINT64_C(1) << 32)
/** LWLA clock sources.
*/
enum clock_source {
@ -133,10 +141,15 @@ struct acquisition_state {
uint64_t sample;
uint64_t run_len;
/** Number of samples acquired so far. */
uint64_t captured_samples;
/** Maximum number of samples to process. */
uint64_t samples_max;
/** Number of samples sent to the session bus. */
uint64_t transferred_samples;
uint64_t samples_done;
/** Maximum duration of capture, in milliseconds. */
uint64_t duration_max;
/** Running capture duration since trigger event. */
uint64_t duration_now;
/** Capture memory fill level. */
size_t mem_addr_fill;
@ -154,6 +167,9 @@ struct acquisition_state {
enum rle_state rle;
/** Whether to bypass the clock divider. */
gboolean bypass_clockdiv;
/* Payload data buffers for outgoing and incoming transfers. */
uint16_t xfer_buf_out[MAX_ACQ_SEND_WORDS];
uint16_t xfer_buf_in[MAX_ACQ_RECV_WORDS];
@ -168,6 +184,9 @@ struct dev_context {
/** The samplerate selected by the user. */
uint64_t samplerate;
/** The maximimum sampling duration, in milliseconds. */
uint64_t limit_msec;
/** The maximimum number of samples to acquire. */
uint64_t limit_samples;