X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=blobdiff_plain;f=src%2Fhardware%2Fasix-sigma%2Fprotocol.c;h=142316514c7ceab0ebda7fc8a157fa66cc495302;hp=e87795e8e6e82ee6067797bd6738b485953c9935;hb=HEAD;hpb=ea57157d0d2e17e418463cf8e4f25453e5b903d7 diff --git a/src/hardware/asix-sigma/protocol.c b/src/hardware/asix-sigma/protocol.c index e87795e8..14231651 100644 --- a/src/hardware/asix-sigma/protocol.c +++ b/src/hardware/asix-sigma/protocol.c @@ -435,8 +435,9 @@ SR_PRIV int sigma_write_trigger_lut(struct dev_context *devc, size_t lut_addr; uint16_t bit; uint8_t m3d, m2d, m1d, m0d; - uint8_t buf[6], *wrptr, v8; - uint16_t selreg; + uint8_t buf[6], *wrptr; + uint8_t trgsel2; + uint16_t lutreg, selreg; int ret; /* @@ -497,15 +498,19 @@ SR_PRIV int sigma_write_trigger_lut(struct dev_context *devc, * programming. */ wrptr = buf; - write_u8_inc(&wrptr, (m3d << 4) | (m2d << 0)); - write_u8_inc(&wrptr, (m1d << 4) | (m0d << 0)); + lutreg = 0; + lutreg <<= 4; lutreg |= m3d; + lutreg <<= 4; lutreg |= m2d; + lutreg <<= 4; lutreg |= m1d; + lutreg <<= 4; lutreg |= m0d; + write_u16be_inc(&wrptr, lutreg); ret = sigma_write_register(devc, WRITE_TRIGGER_SELECT, buf, wrptr - buf); if (ret != SR_OK) return ret; - v8 = TRGSEL2_RESET | TRGSEL2_LUT_WRITE | + trgsel2 = TRGSEL2_RESET | TRGSEL2_LUT_WRITE | (lut_addr & TRGSEL2_LUT_ADDR_MASK); - ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, v8); + ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, trgsel2); if (ret != SR_OK) return ret; } @@ -620,7 +625,7 @@ static int sigma_fpga_init_bitbang_once(struct dev_context *devc) if (ret != SR_OK) return ret; g_usleep(10 * 1000); - ftdi_usb_purge_buffers(&devc->ftdi.ctx); + PURGE_FTDI_BOTH(&devc->ftdi.ctx); /* * Wait until the FPGA asserts INIT_B. Check in a maximum number @@ -838,7 +843,7 @@ static int upload_firmware(struct sr_context *ctx, struct dev_context *devc, return SR_OK; } - devc->state.state = SIGMA_CONFIG; + devc->state = SIGMA_CONFIG; /* Set the cable to bitbang mode. */ ret = ftdi_set_bitmode(&devc->ftdi.ctx, BB_PINMASK, BITMODE_BITBANG); @@ -884,7 +889,7 @@ static int upload_firmware(struct sr_context *ctx, struct dev_context *devc, ftdi_get_error_string(&devc->ftdi.ctx)); return SR_ERR; } - ftdi_usb_purge_buffers(&devc->ftdi.ctx); + PURGE_FTDI_BOTH(&devc->ftdi.ctx); while (sigma_read_raw(devc, &pins, sizeof(pins)) > 0) ; @@ -896,7 +901,7 @@ static int upload_firmware(struct sr_context *ctx, struct dev_context *devc, } /* Keep track of successful firmware download completion. */ - devc->state.state = SIGMA_IDLE; + devc->state = SIGMA_IDLE; devc->firmware_idx = firmware_idx; sr_info("Firmware uploaded."); @@ -934,6 +939,7 @@ SR_PRIV int sigma_set_acquire_timeout(struct dev_context *devc) 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, @@ -943,6 +949,10 @@ SR_PRIV int sigma_set_acquire_timeout(struct dev_context *devc) 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; @@ -953,14 +963,18 @@ SR_PRIV int sigma_set_acquire_timeout(struct dev_context *devc) 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. */ @@ -973,7 +987,12 @@ SR_PRIV int sigma_set_acquire_timeout(struct dev_context *devc) 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; } @@ -1083,7 +1102,7 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi) * firmware is required and higher rates might limit the set * of available channels. */ - num_channels = devc->num_channels; + num_channels = devc->interp.num_channels; if (samplerate <= SR_MHZ(50)) { ret = upload_firmware(drvc->sr_ctx, devc, SIGMA_FW_50MHZ); num_channels = 16; @@ -1101,8 +1120,8 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi) * which the device will communicate within an "event"). */ if (ret == SR_OK) { - devc->num_channels = num_channels; - devc->samples_per_event = 16 / devc->num_channels; + devc->interp.num_channels = num_channels; + devc->interp.samples_per_event = 16 / devc->interp.num_channels; } /* @@ -1250,7 +1269,7 @@ static int addto_submit_buffer(struct dev_context *devc, buffer = devc->buffer; limits = &devc->limit.submit; - if (sr_sw_limits_check(limits)) + if (!devc->use_triggers && sr_sw_limits_check(limits)) count = 0; /* @@ -1267,20 +1286,319 @@ static int addto_submit_buffer(struct dev_context *devc, 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; } return SR_OK; } +static void sigma_location_break_down(struct sigma_location *loc) +{ + + loc->line = loc->raw / ROW_LENGTH_U16; + loc->line += ROW_COUNT; + loc->line %= ROW_COUNT; + loc->cluster = loc->raw % ROW_LENGTH_U16; + loc->event = loc->cluster % EVENTS_PER_CLUSTER; + 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) +{ + struct sigma_sample_interp *interp; + gboolean wrapped; + size_t alloc_size; + + interp = &devc->interp; + + /* + * Either fetch sample memory from absolute start of DRAM to the + * current write position. Or from after the current write position + * to before the current write position, if the write pointer has + * wrapped around at the upper DRAM boundary. Assume that the line + * which most recently got written to is of unknown state, ignore + * its content in the "wrapped" case. + */ + wrapped = mode & RMR_ROUND; + interp->start.raw = 0; + interp->stop.raw = stop_pos; + if (wrapped) { + interp->start.raw = stop_pos; + interp->start.raw >>= ROW_SHIFT; + interp->start.raw++; + interp->start.raw <<= ROW_SHIFT; + interp->stop.raw = stop_pos; + interp->stop.raw >>= ROW_SHIFT; + interp->stop.raw--; + interp->stop.raw <<= ROW_SHIFT; + } + interp->trig.raw = trig_pos; + interp->iter.raw = 0; + + /* Break down raw values to line, cluster, event fields. */ + sigma_location_break_down(&interp->start); + sigma_location_break_down(&interp->stop); + 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; + interp->fetch.lines_total -= interp->start.line; + interp->fetch.lines_total += ROW_COUNT; + interp->fetch.lines_total %= ROW_COUNT; + interp->fetch.lines_done = 0; + + /* Arrange for chunked download, N lines per USB request. */ + interp->fetch.lines_per_read = 32; + alloc_size = sizeof(devc->interp.fetch.rcvd_lines[0]); + alloc_size *= devc->interp.fetch.lines_per_read; + devc->interp.fetch.rcvd_lines = g_try_malloc0(alloc_size); + if (!devc->interp.fetch.rcvd_lines) + return SR_ERR_MALLOC; + + return SR_OK; +} + +static uint16_t sigma_deinterlace_data_4x4(uint16_t indata, int idx); +static uint16_t sigma_deinterlace_data_2x8(uint16_t indata, int idx); + +static int fetch_sample_buffer(struct dev_context *devc) +{ + struct sigma_sample_interp *interp; + size_t count; + int ret; + const uint8_t *rdptr; + uint16_t ts, data; + + interp = &devc->interp; + + /* First invocation? Seed the iteration position. */ + if (!interp->fetch.lines_done) { + interp->iter = interp->start; + } + + /* Get another set of DRAM lines in one read call. */ + count = interp->fetch.lines_total - interp->fetch.lines_done; + if (count > interp->fetch.lines_per_read) + count = interp->fetch.lines_per_read; + ret = sigma_read_dram(devc, interp->iter.line, count, + (uint8_t *)interp->fetch.rcvd_lines); + if (ret != SR_OK) + return ret; + interp->fetch.lines_rcvd = count; + interp->fetch.curr_line = &interp->fetch.rcvd_lines[0]; + + /* First invocation? Get initial timestamp and sample data. */ + if (!interp->fetch.lines_done) { + rdptr = (void *)interp->fetch.curr_line; + ts = read_u16le_inc(&rdptr); + data = read_u16le_inc(&rdptr); + if (interp->samples_per_event == 4) { + data = sigma_deinterlace_data_4x4(data, 0); + } else if (interp->samples_per_event == 2) { + data = sigma_deinterlace_data_2x8(data, 0); + } + interp->last.ts = ts; + interp->last.sample = data; + } + + return SR_OK; +} + +static void free_sample_buffer(struct dev_context *devc) +{ + 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. * - * The Sigma supports complex triggers using boolean expressions, but this - * has not been implemented yet. + * 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 = details. + * + * 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=[/] + * 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= 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) { @@ -1290,21 +1608,18 @@ 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) { @@ -1315,7 +1630,7 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi) 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; } @@ -1328,7 +1643,7 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi) return SR_ERR; } - trigger_set++; + edge_count++; } else { /* Simple trigger support (event). */ if (match->match == SR_TRIGGER_ONE) { @@ -1339,10 +1654,10 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi) 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++; } /* @@ -1350,7 +1665,7 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi) * 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; } @@ -1364,77 +1679,70 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi) 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; + struct sigma_sample_interp *interp; + uint16_t last_sample; + struct sigma_trigger *t; + gboolean simple_match, rising_match, falling_match; + gboolean matched; - 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; - - 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); @@ -1444,6 +1752,46 @@ static int check_and_submit_sample(struct dev_context *devc, 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". */ @@ -1465,7 +1813,7 @@ static uint16_t sigma_dram_cluster_data(struct sigma_dram_cluster *cl, int idx) * One 16bit item contains two samples of 8bits each. The bits of * multiple samples are interleaved. */ -static uint16_t sigma_deinterlace_100mhz_data(uint16_t indata, int idx) +static uint16_t sigma_deinterlace_data_2x8(uint16_t indata, int idx) { uint16_t outdata; @@ -1487,7 +1835,7 @@ static uint16_t sigma_deinterlace_100mhz_data(uint16_t indata, int idx) * One 16bit item contains four samples of 4bits each. The bits of * multiple samples are interleaved. */ -static uint16_t sigma_deinterlace_200mhz_data(uint16_t indata, int idx) +static uint16_t sigma_deinterlace_data_4x4(uint16_t indata, int idx) { uint16_t outdata; @@ -1502,16 +1850,12 @@ static uint16_t sigma_deinterlace_200mhz_data(uint16_t indata, int idx) 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) { - struct sigma_state *ss; 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 @@ -1522,15 +1866,14 @@ static void sigma_decode_dram_cluster(struct dev_context *devc, * for simple level and edge triggers. It would not for timed or * counted conditions, which currently are not supported.) */ - ss = &devc->state; ts = sigma_dram_cluster_ts(dram_cluster); - tsdiff = ts - ss->lastts; + tsdiff = ts - devc->interp.last.ts; if (tsdiff > 0) { - sample = ss->lastsample; - count = tsdiff * devc->samples_per_event; - (void)check_and_submit_sample(devc, sample, count, FALSE); + sample = devc->interp.last.sample; + count = tsdiff * devc->interp.samples_per_event; + (void)check_and_submit_sample(devc, sample, count); } - ss->lastts = ts + EVENTS_PER_CLUSTER; + devc->interp.last.ts = ts + EVENTS_PER_CLUSTER; /* * Grab sample data from the current cluster and prepare their @@ -1542,26 +1885,34 @@ static void sigma_decode_dram_cluster(struct dev_context *devc, sample = 0; for (evt = 0; evt < events_in_cluster; evt++) { item16 = sigma_dram_cluster_data(dram_cluster, evt); - if (devc->clock.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); - check_and_submit_sample(devc, sample, 1, triggered); - sample = sigma_deinterlace_200mhz_data(item16, 2); - 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->clock.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); - check_and_submit_sample(devc, sample, 1, triggered); + if (devc->interp.samples_per_event == 4) { + sample = sigma_deinterlace_data_4x4(item16, 0); + 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); + devc->interp.last.sample = sample; + sample = sigma_deinterlace_data_4x4(item16, 2); + 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); + 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); + devc->interp.last.sample = sample; + sample = sigma_deinterlace_data_2x8(item16, 1); + 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); } - ss->lastsample = sample; } /* @@ -1575,30 +1926,17 @@ static void sigma_decode_dram_cluster(struct dev_context *devc, */ 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 = ~0UL; - 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]; @@ -1612,7 +1950,7 @@ static int decode_chunk_ts(struct dev_context *devc, } sigma_decode_dram_cluster(devc, dram_cluster, - events_in_cluster, cluster == trigger_cluster); + events_in_cluster); } return SR_OK; @@ -1620,131 +1958,146 @@ static int decode_chunk_ts(struct dev_context *devc, static int download_capture(struct sr_dev_inst *sdi) { - const uint32_t chunks_per_read = 32; - struct dev_context *devc; - struct sigma_dram_line *dram_line; + struct sigma_sample_interp *interp; uint32_t stoppos, triggerpos; uint8_t modestatus; - size_t line_idx; - size_t dl_lines_total, dl_lines_curr, dl_lines_done; - size_t dl_first_line, dl_line; - size_t dl_events_in_line, trigger_event; - size_t trg_line, trg_event; int ret; + size_t chunks_per_receive_call; devc = sdi->priv; - - sr_info("Downloading sample data."); - devc->state.state = SIGMA_DOWNLOAD; + interp = &devc->interp; /* + * 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. */ - 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."); - return FALSE; - } - } while (!(modestatus & RMR_POSTTRIGGERED)); - - /* Set SDRAM Read Enable. */ - ret = sigma_set_register(devc, WRITE_MODE, WMR_SDRAMREADEN); - if (ret != SR_OK) - return ret; - - /* Get the current position. Check if trigger has fired. */ - ret = sigma_read_pos(devc, &stoppos, &triggerpos, &modestatus); + ret = sigma_get_register(devc, READ_MODE, &modestatus); if (ret != SR_OK) { - sr_err("Could not query capture positions/state."); + sr_err("Could not determine current device state."); return FALSE; } - if (!devc->use_triggers) - triggerpos = ~0; - trg_line = ~0UL; - trg_event = ~0UL; - if (modestatus & RMR_TRIGGERED) { - trg_line = triggerpos >> ROW_SHIFT; - trg_event = triggerpos & ROW_MASK; + 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; + 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)); } /* - * Determine how many "DRAM lines" of 1024 bytes each we need to - * retrieve from the Sigma hardware, so that we have a complete - * set of samples. Note that the last line need not contain 64 - * clusters, it might be partially filled only. + * 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. * - * When RMR_ROUND is set, the circular buffer in DRAM has wrapped - * around. Since the status of the very next line is uncertain in - * that case, we skip it and start reading from the next line. + * 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. */ - dl_first_line = 0; - dl_lines_total = (stoppos >> ROW_SHIFT) + 1; - if (modestatus & RMR_ROUND) { - dl_first_line = dl_lines_total + 1; - dl_lines_total = ROW_COUNT - 2; - } - dram_line = g_try_malloc0(chunks_per_read * sizeof(*dram_line)); - if (!dram_line) - return FALSE; - ret = alloc_submit_buffer(sdi); - if (ret != SR_OK) - return FALSE; - ret = setup_submit_limit(devc); - if (ret != SR_OK) - return FALSE; - dl_lines_done = 0; - while (dl_lines_total > dl_lines_done) { - /* We can download only up-to 32 DRAM lines in one go! */ - dl_lines_curr = MIN(chunks_per_read, dl_lines_total - dl_lines_done); - - dl_line = dl_first_line + dl_lines_done; - dl_line %= ROW_COUNT; - ret = sigma_read_dram(devc, dl_line, dl_lines_curr, - (uint8_t *)dram_line); + if (!interp->fetch.lines_per_read) { + ret = sigma_set_register(devc, WRITE_MODE, WMR_SDRAMREADEN); if (ret != SR_OK) return FALSE; - /* This is the first DRAM line, so find the initial timestamp. */ - if (dl_lines_done == 0) { - devc->state.lastts = - sigma_dram_cluster_ts(&dram_line[0].cluster[0]); - devc->state.lastsample = 0; + 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; - for (line_idx = 0; line_idx < dl_lines_curr; line_idx++) { - /* The last "DRAM line" need not span its full length. */ - dl_events_in_line = EVENTS_PER_ROW; - if (dl_lines_done + line_idx == dl_lines_total - 1) - dl_events_in_line = stoppos & ROW_MASK; + 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; + } - /* Test if the trigger happened on this line. */ - trigger_event = ~0UL; - if (dl_lines_done + line_idx == trg_line) - trigger_event = trg_event; + /* + * 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. + */ + chunks_per_receive_call = 50; + while (interp->fetch.lines_done < interp->fetch.lines_total) { + size_t dl_events_in_line; - decode_chunk_ts(devc, dram_line + line_idx, - dl_events_in_line, trigger_event); + /* Read another chunk of sample memory (several lines). */ + ret = fetch_sample_buffer(devc); + if (ret != SR_OK) + return FALSE; + + /* Process lines of sample data. Last line may be short. */ + while (interp->fetch.lines_rcvd--) { + dl_events_in_line = EVENTS_PER_ROW; + if (interp->iter.line == interp->stop.line) { + dl_events_in_line = interp->stop.raw & ROW_MASK; + } + decode_chunk_ts(devc, interp->fetch.curr_line, + dl_events_in_line); + interp->fetch.curr_line++; + interp->fetch.lines_done++; } - dl_lines_done += dl_lines_curr; + /* 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); - g_free(dram_line); - 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.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; } @@ -1757,10 +2110,59 @@ static int download_capture(struct sr_dev_inst *sdi) 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; } @@ -1776,18 +2178,21 @@ SR_PRIV int sigma_receive_data(int fd, int revents, void *cb_data) sdi = cb_data; devc = sdi->priv; - if (devc->state.state == SIGMA_IDLE) + if (devc->state == SIGMA_IDLE) 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.state == SIGMA_STOPPING) + if (devc->state == SIGMA_STOPPING) + return download_capture(sdi); + if (devc->state == SIGMA_DOWNLOAD) return download_capture(sdi); - if (devc->state.state == SIGMA_CAPTURE) + if (devc->state == SIGMA_CAPTURE) return sigma_capture_mode(sdi); return TRUE;