buffer = devc->buffer;
limits = &devc->limit.submit;
- if (sr_sw_limits_check(limits))
+ if (!devc->use_triggers && sr_sw_limits_check(limits))
count = 0;
/*
return ret;
}
sr_sw_limits_update_samples_read(limits, 1);
- if (sr_sw_limits_check(limits))
+ if (!devc->use_triggers && sr_sw_limits_check(limits))
break;
}
loc->cluster = loc->cluster / EVENTS_PER_CLUSTER;
}
+static gboolean sigma_location_is_eq(struct sigma_location *loc1,
+ struct sigma_location *loc2, gboolean with_event)
+{
+
+ if (!loc1 || !loc2)
+ return FALSE;
+
+ if (loc1->line != loc2->line)
+ return FALSE;
+ if (loc1->cluster != loc2->cluster)
+ return FALSE;
+
+ if (with_event && loc1->event != loc2->event)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Decrement the broken-down location fields (leave 'raw' as is). */
+static void sigma_location_decrement(struct sigma_location *loc,
+ gboolean with_event)
+{
+
+ if (!loc)
+ return;
+
+ if (with_event) {
+ if (loc->event--)
+ return;
+ loc->event = EVENTS_PER_CLUSTER - 1;
+ }
+
+ if (loc->cluster--)
+ return;
+ loc->cluster = CLUSTERS_PER_ROW - 1;
+
+ if (loc->line--)
+ return;
+ loc->line = ROW_COUNT - 1;
+}
+
+static void sigma_location_increment(struct sigma_location *loc)
+{
+
+ if (!loc)
+ return;
+
+ if (++loc->event < EVENTS_PER_CLUSTER)
+ return;
+ loc->event = 0;
+ if (++loc->cluster < CLUSTERS_PER_ROW)
+ return;
+ loc->cluster = 0;
+ if (++loc->line < ROW_COUNT)
+ return;
+ loc->line = 0;
+}
+
+/*
+ * Determine the position where to open the period of trigger match
+ * checks. Setup an "impossible" location when triggers are not used.
+ * Start from the hardware provided 'trig' position otherwise, and
+ * go back a few clusters, but don't go before the 'start' position.
+ */
+static void rewind_trig_arm_pos(struct dev_context *devc, size_t count)
+{
+ struct sigma_sample_interp *interp;
+
+ if (!devc)
+ return;
+ interp = &devc->interp;
+
+ if (!devc->use_triggers) {
+ interp->trig_arm.raw = ~0;
+ sigma_location_break_down(&interp->trig_arm);
+ return;
+ }
+
+ interp->trig_arm = interp->trig;
+ while (count--) {
+ if (sigma_location_is_eq(&interp->trig_arm, &interp->start, TRUE))
+ break;
+ sigma_location_decrement(&interp->trig_arm, TRUE);
+ }
+}
+
static int alloc_sample_buffer(struct dev_context *devc,
size_t stop_pos, size_t trig_pos, uint8_t mode)
{
sigma_location_break_down(&interp->trig);
sigma_location_break_down(&interp->iter);
+ /*
+ * The hardware provided trigger location "is late" because of
+ * latency in hardware pipelines. It points to after the trigger
+ * condition match. Arrange for a software check of sample data
+ * matches starting just a little before the hardware provided
+ * location. The "4 clusters" distance is an arbitrary choice.
+ */
+ rewind_trig_arm_pos(devc, 4 * EVENTS_PER_CLUSTER);
+ memset(&interp->trig_chk, 0, sizeof(interp->trig_chk));
+
/* Determine which DRAM lines to fetch from the device. */
memset(&interp->fetch, 0, sizeof(interp->fetch));
interp->fetch.lines_total = interp->stop.line + 1;
return SR_OK;
}
-/* Software trigger to determine exact trigger position. */
-static int get_trigger_offset(uint8_t *samples, uint16_t last_sample,
- struct sigma_trigger *t)
+static gboolean sample_matches_trigger(struct dev_context *devc, uint16_t sample)
{
- const uint8_t *rdptr;
- size_t i;
- uint16_t sample;
-
- rdptr = samples;
- sample = 0;
- for (i = 0; i < 8; i++) {
- if (i > 0)
- last_sample = sample;
- sample = read_u16le_inc(&rdptr);
-
- /* Simple triggers. */
- if ((sample & t->simplemask) != t->simplevalue)
- continue;
-
- /* Rising edge. */
- if (((last_sample & t->risingmask) != 0) ||
- ((sample & t->risingmask) != t->risingmask))
- continue;
-
- /* Falling edge. */
- if ((last_sample & t->fallingmask) != t->fallingmask ||
- (sample & t->fallingmask) != 0)
- continue;
+ struct sigma_sample_interp *interp;
+ uint16_t last_sample;
+ struct sigma_trigger *t;
+ gboolean simple_match, rising_match, falling_match;
+ gboolean matched;
- break;
- }
+ /*
+ * This logic is about improving the precision of the hardware
+ * provided trigger match position. Software checks are only
+ * required for a short range of samples, and only when a user
+ * specified trigger condition was involved during acquisition.
+ */
+ if (!devc)
+ return FALSE;
+ if (!devc->use_triggers)
+ return FALSE;
+ interp = &devc->interp;
+ if (!interp->trig_chk.armed)
+ return FALSE;
- /* If we did not match, return original trigger pos. */
- return i & 0x7;
+ /*
+ * Check if the current sample and its most recent transition
+ * match the initially provided trigger condition. The data
+ * must not fail either of the individual checks. Unused
+ * trigger features remain neutral in the summary expression.
+ */
+ last_sample = interp->last.sample;
+ t = &devc->trigger;
+ simple_match = (sample & t->simplemask) == t->simplevalue;
+ rising_match = ((last_sample & t->risingmask) == 0) &&
+ ((sample & t->risingmask) == t->risingmask);
+ falling_match = ((last_sample & t->fallingmask) == t->fallingmask) &&
+ ((sample & t->fallingmask) == 0);
+ matched = simple_match && rising_match && falling_match;
+
+ return matched;
}
-static gboolean sample_matches_trigger(struct dev_context *devc, uint16_t sample)
+static int send_trigger_marker(struct dev_context *devc)
{
- /* TODO
- * Check whether the combination of this very sample and the
- * previous state match the configured trigger condition. This
- * improves the resolution of the trigger marker's position.
- * The hardware provided position is coarse, and may point to
- * a position before the actual match.
- *
- * See the previous get_trigger_offset() implementation. This
- * code needs to get re-used here.
- */
- if (!devc->use_triggers)
- return FALSE;
+ int ret;
- (void)sample;
- (void)get_trigger_offset;
+ ret = flush_submit_buffer(devc);
+ if (ret != SR_OK)
+ return ret;
+ ret = std_session_send_df_trigger(devc->buffer->sdi);
+ if (ret != SR_OK)
+ return ret;
- return FALSE;
+ return SR_OK;
}
static int check_and_submit_sample(struct dev_context *devc,
- uint16_t sample, size_t count, gboolean check_trigger)
+ uint16_t sample, size_t count)
{
gboolean triggered;
int ret;
- triggered = check_trigger && sample_matches_trigger(devc, sample);
+ triggered = sample_matches_trigger(devc, sample);
if (triggered) {
- ret = flush_submit_buffer(devc);
- if (ret != SR_OK)
- return ret;
- ret = std_session_send_df_trigger(devc->buffer->sdi);
- if (ret != SR_OK)
- return ret;
+ send_trigger_marker(devc);
+ devc->interp.trig_chk.matched = TRUE;
}
ret = addto_submit_buffer(devc, sample, count);
return SR_OK;
}
+static void sigma_location_check(struct dev_context *devc)
+{
+ struct sigma_sample_interp *interp;
+
+ if (!devc)
+ return;
+ interp = &devc->interp;
+
+ /*
+ * Manage the period of trigger match checks in software.
+ * Start supervision somewhere before the hardware provided
+ * location. Stop supervision after an arbitrary amount of
+ * event slots, or when a match was found.
+ */
+ if (interp->trig_chk.armed) {
+ interp->trig_chk.evt_remain--;
+ if (!interp->trig_chk.evt_remain || interp->trig_chk.matched)
+ interp->trig_chk.armed = FALSE;
+ }
+ if (!interp->trig_chk.armed && !interp->trig_chk.matched) {
+ if (sigma_location_is_eq(&interp->iter, &interp->trig_arm, TRUE)) {
+ interp->trig_chk.armed = TRUE;
+ interp->trig_chk.matched = FALSE;
+ interp->trig_chk.evt_remain = 8 * EVENTS_PER_CLUSTER;
+ }
+ }
+
+ /*
+ * Force a trigger marker when the software check found no match
+ * yet while the hardware provided position was reached. This
+ * very probably is a user initiated button press.
+ */
+ if (interp->trig_chk.armed) {
+ if (sigma_location_is_eq(&interp->iter, &interp->trig, TRUE)) {
+ (void)send_trigger_marker(devc);
+ interp->trig_chk.matched = TRUE;
+ }
+ }
+}
+
/*
* Return the timestamp of "DRAM cluster".
*/
if (tsdiff > 0) {
sample = devc->interp.last.sample;
count = tsdiff * devc->interp.samples_per_event;
- (void)check_and_submit_sample(devc, sample, count, FALSE);
+ (void)check_and_submit_sample(devc, sample, count);
}
devc->interp.last.ts = ts + EVENTS_PER_CLUSTER;
item16 = sigma_dram_cluster_data(dram_cluster, evt);
if (devc->interp.samples_per_event == 4) {
sample = sigma_deinterlace_data_4x4(item16, 0);
- check_and_submit_sample(devc, sample, 1, triggered);
+ check_and_submit_sample(devc, sample, 1);
+ devc->interp.last.sample = sample;
sample = sigma_deinterlace_data_4x4(item16, 1);
- check_and_submit_sample(devc, sample, 1, triggered);
+ check_and_submit_sample(devc, sample, 1);
+ devc->interp.last.sample = sample;
sample = sigma_deinterlace_data_4x4(item16, 2);
- check_and_submit_sample(devc, sample, 1, triggered);
+ check_and_submit_sample(devc, sample, 1);
+ devc->interp.last.sample = sample;
sample = sigma_deinterlace_data_4x4(item16, 3);
- check_and_submit_sample(devc, sample, 1, triggered);
+ check_and_submit_sample(devc, sample, 1);
+ devc->interp.last.sample = sample;
} else if (devc->interp.samples_per_event == 2) {
sample = sigma_deinterlace_data_2x8(item16, 0);
- check_and_submit_sample(devc, sample, 1, triggered);
+ check_and_submit_sample(devc, sample, 1);
+ devc->interp.last.sample = sample;
sample = sigma_deinterlace_data_2x8(item16, 1);
- check_and_submit_sample(devc, sample, 1, triggered);
+ check_and_submit_sample(devc, sample, 1);
+ devc->interp.last.sample = sample;
} else {
sample = item16;
- check_and_submit_sample(devc, sample, 1, triggered);
+ check_and_submit_sample(devc, sample, 1);
+ devc->interp.last.sample = sample;
}
+ sigma_location_increment(&devc->interp.iter);
+ sigma_location_check(devc);
}
- devc->interp.last.sample = sample;
}
/*
dl_events_in_line, trigger_event);
interp->fetch.curr_line++;
interp->fetch.lines_done++;
- interp->iter.line++;
- interp->iter.line %= ROW_COUNT;
}
}
flush_submit_buffer(devc);