uint64_t count_msecs, acquire_msecs;
sr_sw_limits_init(&devc->limit.acquire);
+ devc->late_trigger_timeout = FALSE;
/* Get sample count limit, convert to msecs. */
ret = sr_sw_limits_config_get(&devc->limit.config,
user_count = g_variant_get_uint64(data);
g_variant_unref(data);
count_msecs = 0;
+ if (devc->use_triggers) {
+ user_count *= 100 - devc->capture_ratio;
+ user_count /= 100;
+ }
if (user_count)
count_msecs = 1000 * user_count / devc->clock.samplerate + 1;
return ret;
user_msecs = g_variant_get_uint64(data);
g_variant_unref(data);
+ if (devc->use_triggers) {
+ user_msecs *= 100 - devc->capture_ratio;
+ user_msecs /= 100;
+ }
/* Get the lesser of them, with both being optional. */
- acquire_msecs = ~0ull;
+ acquire_msecs = ~UINT64_C(0);
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)
+ if (acquire_msecs == ~UINT64_C(0))
return SR_OK;
/* Add some slack, and use that timeout for acquisition. */
if (ret != SR_OK)
return ret;
- sr_sw_limits_acquisition_start(&devc->limit.acquire);
+ /* Deferred or immediate (trigger-less) timeout period start. */
+ if (devc->use_triggers)
+ devc->late_trigger_timeout = TRUE;
+ else
+ sr_sw_limits_acquisition_start(&devc->limit.acquire);
+
return SR_OK;
}
{
g_free(devc->interp.fetch.rcvd_lines);
devc->interp.fetch.rcvd_lines = NULL;
+ devc->interp.fetch.lines_per_read = 0;
}
/*
- * In 100 and 200 MHz mode, only a single pin rising/falling can be
- * set as trigger. In other modes, two rising/falling triggers can be set,
- * in addition to value/mask trigger for any number of channels.
+ * Parse application provided trigger conditions to the driver's internal
+ * presentation. Yields a mask of pins of interest, and their expected
+ * pin levels or edges.
+ *
+ * In 100 and 200 MHz mode, only a single pin's rising/falling edge can be
+ * set as trigger. In 50- MHz modes, two rising/falling edges can be set,
+ * in addition to value/mask specs for any number of channels.
+ *
+ * Hardware implementation detail: When more than one edge is specified,
+ * then the condition is only considered a match when _all_ transitions
+ * are seen in the same 20ns check interval, regardless of the user's
+ * perceived samplerate which can be a fraction of 50MHz. Which reduces
+ * practical use to edges on a single pin in addition to data patterns.
+ * Which still covers a lot of users' typical scenarios. Not an issue,
+ * just something to remain aware of.
+ *
+ * The Sigma hardware also supports complex triggers which involve the
+ * logical combination of several patterns, pulse durations, counts of
+ * condition matches, A-then-B sequences, etc. But this has not been
+ * implemented yet here, and applications may lack means to express
+ * these conditions (present the complex conditions to users for entry
+ * and review, pass application specs to drivers covering the versatile
+ * combinations).
+ *
+ * Implementor's note: This routine currently exclusively accepts input
+ * in the form of sr_trigger stages, which results from "01rf-" choices
+ * on a multitude of individual GUI traces, or the CLI's --trigger spec
+ * which takes one list of <pin>=<value/edge> details.
*
- * The Sigma supports complex triggers using boolean expressions, but this
- * has not been implemented yet.
+ * TODO Consider the addition of SR_CONF_TRIGGER_PATTERN support, which
+ * accepts a single free form string argument, and could describe a
+ * multi-bit pattern without the tedious trace name/index selection.
+ * Fortunately the number of channels is fixed for this device, we need
+ * not come up with variable length support and counts beyond 64. _When_
+ * --trigger as well as SR_CONF_TRIGGER_PATTERN are supported, then the
+ * implementation needs to come up with priorities for these sources of
+ * input specs, or enforce exclusive use of either form (at one time,
+ * per acquisition / invocation).
+ *
+ * Text forms that may be worth supporting:
+ * - Simple forms, mere numbers, optional base specs. These are easiest
+ * to implement with existing common conversion helpers.
+ * triggerpattern=<value>[/<mask>]
+ * triggerpattern=255
+ * triggerpattern=45054
+ * triggerpattern=0xaffe
+ * triggerpattern=0xa0f0/0xf0f0
+ * triggerpattern=0b1010111111111110/0x7ffe
+ * - Alternative bit pattern form, including wildcards in a single value.
+ * This cannot use common conversion support, needs special handling.
+ * triggerpattern=0b1010xxxx1111xxx0
+ * This is most similar to SR_CONF_TRIGGER_PATTERN as hameg-hmo uses
+ * it. Passes the app's spec via SCPI to the device. See section 2.3.5
+ * "Pattern trigger" and :TRIG:A:PATT:SOUR in the Hameg document.
+ * - Prefixed form to tell the above variants apart, and support both of
+ * them at the same time. Additional optional separator for long digit
+ * runs, and edge support in the form which lists individual bits (not
+ * useful for dec/hex formats).
+ * triggerpattern=value=45054
+ * triggerpattern=value=0b1010111111111110
+ * triggerpattern=value=0xa0f0,mask=0xf0f0
+ * triggerpattern=bits=1010-xxxx-1111-xxxx
+ * triggerpattern=bits=0010-r100
+ *
+ * TODO Check this set of processing rules for completeness/correctness.
+ * - Do implement the prefixed format which covers most use cases, _and_
+ * should be usable from CLI and GUI environments.
+ * - Default to 'bits=' prefix if none was found (and only accept one
+ * single key/value pair in that case with the default key).
+ * - Accept dash and space separators in the 'bits=' value. Stick with
+ * mere unseparated values for value and mask, use common conversion.
+ * This results in transparent dec/bin/oct/hex support. Underscores?
+ * - Accept 0/1 binary digits in 'bits=', as well as r/f/e edge specs.
+ * - Only use --trigger (struct sr_trigger) when SR_CONF_TRIGGER_PATTERN
+ * is absent? Or always accept --trigger in addition to the data pattern
+ * spec? Then only accept edge specs from --trigger, since data pattern
+ * was most importantly motivated by address/data bus inspection?
+ * - TODO Consider edge=<pin><slope> as an optional additional spec in
+ * the value= and mask= group? Does that help make exclusive support
+ * for either --trigger or -c triggerpattern acceptable?
+ * triggerpattern=value=0xa0f0,mask=0xb0f0,edge=15r
+ * triggerpattern=bits=1r10-xxxx-1111-xxxx
+ * triggerpattern=1r10-xxxx-1111-xxxx
+ * - *Any* input spec regardless of format and origin must end up in the
+ * 'struct sigma_trigger' internal presentation used by this driver.
+ * It's desirable to have sigma_convert_trigger() do all the parsing,
+ * and constraint checking in a central location.
*/
SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi)
{
struct sr_trigger_match *match;
const GSList *l, *m;
uint16_t channelbit;
- size_t trigger_set;
+ size_t edge_count;
devc = sdi->priv;
memset(&devc->trigger, 0, sizeof(devc->trigger));
devc->use_triggers = FALSE;
+
+ /* TODO Consider additional SR_CONF_TRIGGER_PATTERN support. */
trigger = sr_session_trigger_get(sdi->session);
if (!trigger)
return SR_OK;
- if (!ASIX_SIGMA_WITH_TRIGGER) {
- sr_warn("Trigger support is not implemented. Ignoring the spec.");
- return SR_OK;
- }
-
- trigger_set = 0;
+ edge_count = 0;
for (l = trigger->stages; l; l = l->next) {
stage = l->data;
for (m = stage->matches; m; m = m->next) {
channelbit = BIT(match->channel->index);
if (devc->clock.samplerate >= SR_MHZ(100)) {
/* Fast trigger support. */
- if (trigger_set) {
+ if (edge_count > 0) {
sr_err("100/200MHz modes limited to single trigger pin.");
return SR_ERR;
}
return SR_ERR;
}
- trigger_set++;
+ edge_count++;
} else {
/* Simple trigger support (event). */
if (match->match == SR_TRIGGER_ONE) {
devc->trigger.simplemask |= channelbit;
} else if (match->match == SR_TRIGGER_FALLING) {
devc->trigger.fallingmask |= channelbit;
- trigger_set++;
+ edge_count++;
} else if (match->match == SR_TRIGGER_RISING) {
devc->trigger.risingmask |= channelbit;
- trigger_set++;
+ edge_count++;
}
/*
* but they are ORed and the current trigger syntax
* does not permit ORed triggers.
*/
- if (trigger_set > 1) {
+ if (edge_count > 1) {
sr_err("Limited to 1 edge trigger.");
return SR_ERR;
}
static void sigma_decode_dram_cluster(struct dev_context *devc,
struct sigma_dram_cluster *dram_cluster,
- size_t events_in_cluster, gboolean triggered)
+ size_t events_in_cluster)
{
uint16_t tsdiff, ts, sample, item16;
size_t count;
size_t evt;
- if (!devc->use_triggers || !ASIX_SIGMA_WITH_TRIGGER)
- triggered = FALSE;
-
/*
* If this cluster is not adjacent to the previously received
* cluster, then send the appropriate number of samples with the
*/
static int decode_chunk_ts(struct dev_context *devc,
struct sigma_dram_line *dram_line,
- size_t events_in_line, size_t trigger_event)
+ size_t events_in_line)
{
struct sigma_dram_cluster *dram_cluster;
size_t clusters_in_line;
size_t events_in_cluster;
size_t cluster;
- size_t trigger_cluster;
clusters_in_line = events_in_line;
clusters_in_line += EVENTS_PER_CLUSTER - 1;
clusters_in_line /= EVENTS_PER_CLUSTER;
- /* Check if trigger is in this chunk. */
- trigger_cluster = ~UINT64_C(0);
- if (trigger_event < EVENTS_PER_ROW) {
- if (devc->clock.samplerate <= SR_MHZ(50)) {
- trigger_event -= MIN(EVENTS_PER_CLUSTER - 1,
- trigger_event);
- }
-
- /* Find in which cluster the trigger occurred. */
- trigger_cluster = trigger_event / EVENTS_PER_CLUSTER;
- }
-
/* For each full DRAM cluster. */
for (cluster = 0; cluster < clusters_in_line; cluster++) {
dram_cluster = &dram_line->cluster[cluster];
}
sigma_decode_dram_cluster(devc, dram_cluster,
- events_in_cluster, cluster == trigger_cluster);
+ events_in_cluster);
}
return SR_OK;
uint32_t stoppos, triggerpos;
uint8_t modestatus;
int ret;
+ size_t chunks_per_receive_call;
devc = sdi->priv;
interp = &devc->interp;
- sr_info("Downloading sample data.");
- devc->state = SIGMA_DOWNLOAD;
-
/*
+ * Check the mode register. Force stop the current acquisition
+ * if it has not yet terminated before. Will block until the
+ * acquisition stops, assuming that this won't take long. Should
+ * execute exactly once, then keep finding its condition met.
+ *
* Ask the hardware to stop data acquisition. Reception of the
* FORCESTOP request makes the hardware "disable RLE" (store
* clusters to DRAM regardless of whether pin state changes) and
* raise the POSTTRIGGERED flag.
- *
- * Then switch the hardware from DRAM write (data acquisition)
- * to DRAM read (sample memory download).
*/
- modestatus = WMR_FORCESTOP | WMR_SDRAMWRITEEN;
- ret = sigma_set_register(devc, WRITE_MODE, modestatus);
- if (ret != SR_OK)
- return ret;
- do {
- ret = sigma_get_register(devc, READ_MODE, &modestatus);
- if (ret != SR_OK) {
- sr_err("Could not poll for post-trigger state.");
+ ret = sigma_get_register(devc, READ_MODE, &modestatus);
+ if (ret != SR_OK) {
+ sr_err("Could not determine current device state.");
+ return FALSE;
+ }
+ if (!(modestatus & RMR_POSTTRIGGERED)) {
+ sr_info("Downloading sample data.");
+ devc->state = SIGMA_DOWNLOAD;
+
+ modestatus = WMR_FORCESTOP | WMR_SDRAMWRITEEN;
+ ret = sigma_set_register(devc, WRITE_MODE, modestatus);
+ if (ret != SR_OK)
return FALSE;
- }
- } while (!(modestatus & RMR_POSTTRIGGERED));
- ret = sigma_set_register(devc, WRITE_MODE, WMR_SDRAMREADEN);
- if (ret != SR_OK)
- return ret;
+ do {
+ ret = sigma_get_register(devc, READ_MODE, &modestatus);
+ if (ret != SR_OK) {
+ sr_err("Could not poll for post-trigger state.");
+ return FALSE;
+ }
+ } while (!(modestatus & RMR_POSTTRIGGERED));
+ }
/*
+ * Switch the hardware from DRAM write (data acquisition) to
+ * DRAM read (sample memory download). Prepare resources for
+ * sample memory content retrieval. Should execute exactly once,
+ * then keep finding its condition met.
+ *
* Get the current positions (acquisition write pointer, and
* trigger match location). With disabled triggers, use a value
* for the location that will never match during interpretation.
+ * Determine which area of the sample memory to retrieve,
+ * allocate a receive buffer, and setup counters/pointers.
*/
- ret = sigma_read_pos(devc, &stoppos, &triggerpos, &modestatus);
- if (ret != SR_OK) {
- sr_err("Could not query capture positions/state.");
- return FALSE;
+ if (!interp->fetch.lines_per_read) {
+ ret = sigma_set_register(devc, WRITE_MODE, WMR_SDRAMREADEN);
+ if (ret != SR_OK)
+ return FALSE;
+
+ ret = sigma_read_pos(devc, &stoppos, &triggerpos, &modestatus);
+ if (ret != SR_OK) {
+ sr_err("Could not query capture positions/state.");
+ return FALSE;
+ }
+ if (!devc->use_triggers)
+ triggerpos = ~0;
+ if (!(modestatus & RMR_TRIGGERED))
+ triggerpos = ~0;
+
+ ret = alloc_sample_buffer(devc, stoppos, triggerpos, modestatus);
+ if (ret != SR_OK)
+ return FALSE;
+
+ ret = alloc_submit_buffer(sdi);
+ if (ret != SR_OK)
+ return FALSE;
+ ret = setup_submit_limit(devc);
+ if (ret != SR_OK)
+ return FALSE;
}
- if (!devc->use_triggers)
- triggerpos = ~0;
- if (!(modestatus & RMR_TRIGGERED))
- triggerpos = ~0;
/*
- * Determine which area of the sample memory to retrieve,
- * allocate a receive buffer, and setup counters/pointers.
+ * Get another set of sample memory rows, and interpret its
+ * content. Will execute as many times as it takes to complete
+ * the memory region that the recent acquisition spans.
+ *
+ * The size of a receive call's workload and the main loop's
+ * receive call poll period determine the UI responsiveness and
+ * the overall transfer time for the sample memory content.
*/
- ret = alloc_sample_buffer(devc, stoppos, triggerpos, modestatus);
- if (ret != SR_OK)
- return FALSE;
-
- ret = alloc_submit_buffer(sdi);
- if (ret != SR_OK)
- return FALSE;
- ret = setup_submit_limit(devc);
- if (ret != SR_OK)
- return FALSE;
+ chunks_per_receive_call = 50;
while (interp->fetch.lines_done < interp->fetch.lines_total) {
- size_t dl_events_in_line, trigger_event;
+ size_t dl_events_in_line;
/* Read another chunk of sample memory (several lines). */
ret = fetch_sample_buffer(devc);
if (interp->iter.line == interp->stop.line) {
dl_events_in_line = interp->stop.raw & ROW_MASK;
}
- trigger_event = ~UINT64_C(0);
- if (interp->iter.line == interp->trig.line) {
- trigger_event = interp->trig.raw & ROW_MASK;
- }
decode_chunk_ts(devc, interp->fetch.curr_line,
- dl_events_in_line, trigger_event);
+ dl_events_in_line);
interp->fetch.curr_line++;
interp->fetch.lines_done++;
}
+
+ /* Keep returning to application code for large data sets. */
+ if (!--chunks_per_receive_call) {
+ ret = flush_submit_buffer(devc);
+ if (ret != SR_OK)
+ return FALSE;
+ break;
+ }
}
- flush_submit_buffer(devc);
- free_submit_buffer(devc);
- free_sample_buffer(devc);
- std_session_send_df_end(sdi);
+ /*
+ * Release previously allocated resources, and adjust state when
+ * all of the sample memory was retrieved, and interpretation has
+ * completed. Should execute exactly once.
+ */
+ if (interp->fetch.lines_done >= interp->fetch.lines_total) {
+ ret = flush_submit_buffer(devc);
+ if (ret != SR_OK)
+ return FALSE;
+ free_submit_buffer(devc);
+ free_sample_buffer(devc);
- devc->state = SIGMA_IDLE;
- sr_dev_acquisition_stop(sdi);
+ ret = std_session_send_df_end(sdi);
+ if (ret != SR_OK)
+ return FALSE;
+
+ devc->state = SIGMA_IDLE;
+ sr_dev_acquisition_stop(sdi);
+ }
return TRUE;
}
static int sigma_capture_mode(struct sr_dev_inst *sdi)
{
struct dev_context *devc;
+ int ret;
+ uint32_t stoppos, triggerpos;
+ uint8_t mode;
+ gboolean full, wrapped, triggered, complete;
devc = sdi->priv;
+
+ /*
+ * Get and interpret current acquisition status. Some of these
+ * thresholds are rather arbitrary.
+ */
+ ret = sigma_read_pos(devc, &stoppos, &triggerpos, &mode);
+ if (ret != SR_OK)
+ return FALSE;
+ stoppos >>= ROW_SHIFT;
+ full = stoppos >= ROW_COUNT - 2;
+ wrapped = mode & RMR_ROUND;
+ triggered = mode & RMR_TRIGGERED;
+ complete = mode & RMR_POSTTRIGGERED;
+
+ /*
+ * Acquisition completed in the hardware? Start or continue
+ * sample memory content download.
+ * (Can user initiated button presses result in auto stop?
+ * Will they "trigger", and later result in expired time limit
+ * of post trigger conditions?)
+ */
+ if (complete)
+ return download_capture(sdi);
+
+ /*
+ * Previously configured acquisition period exceeded? Start
+ * sample download. Start the timeout period late when triggers
+ * are used (unknown period from acquisition start to trigger
+ * match).
+ */
if (sr_sw_limits_check(&devc->limit.acquire))
return download_capture(sdi);
+ if (devc->late_trigger_timeout && triggered) {
+ sr_sw_limits_acquisition_start(&devc->limit.acquire);
+ devc->late_trigger_timeout = FALSE;
+ }
+
+ /*
+ * No trigger specified, and sample memory exhausted? Start
+ * download (may otherwise keep acquiring, even for infinite
+ * amounts of time without a user specified time/count limit).
+ * This handles situations when users specify limits which
+ * exceed the device's capabilities.
+ */
+ (void)full;
+ if (!devc->use_triggers && wrapped)
+ return download_capture(sdi);
return TRUE;
}
/*
* When the application has requested to stop the acquisition,
- * then immediately start downloading sample data. Otherwise
+ * then immediately start downloading sample data. Continue a
+ * previously initiated download until completion. Otherwise
* keep checking configured limits which will terminate the
* acquisition and initiate download.
*/
if (devc->state == SIGMA_STOPPING)
return download_capture(sdi);
+ if (devc->state == SIGMA_DOWNLOAD)
+ return download_capture(sdi);
if (devc->state == SIGMA_CAPTURE)
return sigma_capture_mode(sdi);