From 549f03cdd045f1b67f3633abe62e4469452336d1 Mon Sep 17 00:00:00 2001 From: v1ne Date: Wed, 18 Nov 2020 23:54:46 +0100 Subject: [PATCH 01/29] ols: Clean up: Prefix private function for consistency --- src/hardware/openbench-logic-sniffer/protocol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 8758ef88c..b9a4ffa27 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -151,7 +151,7 @@ static void ols_channel_new(struct sr_dev_inst *sdi, int num_chan) devc->max_channels = num_chan; } -static void metadata_quirks(struct sr_dev_inst *sdi) +static void ols_metadata_quirks(struct sr_dev_inst *sdi) { struct dev_context *devc; gboolean is_shrimp; @@ -302,7 +302,7 @@ SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial) g_string_free(version, FALSE); /* Optionally amend received metadata, model specific quirks. */ - metadata_quirks(sdi); + ols_metadata_quirks(sdi); return sdi; } From fbe2bd2aa364d569acbfd61f89515844f2160b94 Mon Sep 17 00:00:00 2001 From: v1ne Date: Wed, 1 Apr 2020 16:15:36 +0200 Subject: [PATCH 02/29] ols: Display actual expanded sample instead of the raw sample While the raw sample is the actual received data, the expanded sample is the crucial data I as a developer am interested in seeing. At least if I assume that the sample expansion works. --- src/hardware/openbench-logic-sniffer/protocol.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index b9a4ffa27..bedf29500 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -463,7 +463,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) } } memcpy(devc->sample, devc->tmp_sample, 4); - sr_spew("Expanded sample: 0x%.8x.", sample); + sr_spew("Expanded sample: 0x%.2hhx%.2hhx%.2hhx%.2hhx ", + devc->sample[3], devc->sample[2], devc->sample[1], devc->sample[0]); } /* From f793969179d2270cf45361e7198d67c5edb96ba1 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 31 Mar 2020 20:21:47 +0200 Subject: [PATCH 03/29] ols: Clear "disabled groups" flags before setting them This fixes a bug where the channel group setting would not be overwritten in a new run, but instead the channel group settings of both runs would be merged together. --- src/hardware/openbench-logic-sniffer/api.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 8e4efb940..a9812ce96 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -497,10 +497,12 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) devc->capture_flags & CAPTURE_FLAG_RLE ? "on" : "off", devc->capture_flags & CAPTURE_FLAG_NOISE_FILTER ? "on": "off", devc->capture_flags & CAPTURE_FLAG_DEMUX ? "on" : "off"); + /* * Enable/disable OLS channel groups in the flag register according * to the channel mask. 1 means "disable channel". */ + devc->capture_flags &= ~0x3c; devc->capture_flags |= ~(ols_changrp_mask << 2) & 0x3c; /* RLE mode is always zero, for now. */ From dc03fcfb7ec53fb08ba63f204ae819c3a13116fd Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 31 Mar 2020 20:29:48 +0200 Subject: [PATCH 04/29] ols: Add option to use the falling edge of the external clock --- src/hardware/openbench-logic-sniffer/api.c | 30 ++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index a9812ce96..2815a50a9 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -37,6 +37,7 @@ static const uint32_t devopts[] = { SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, SR_CONF_EXTERNAL_CLOCK | SR_CONF_SET, + SR_CONF_CLOCK_EDGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, SR_CONF_PATTERN_MODE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, SR_CONF_SWAP | SR_CONF_SET, SR_CONF_RLE | SR_CONF_GET | SR_CONF_SET, @@ -47,6 +48,11 @@ static const int32_t trigger_matches[] = { SR_TRIGGER_ONE, }; +static const char* external_clock_edges[] = { + "rising", // positive edge + "falling" // negative edge +}; + #define STR_PATTERN_NONE "None" #define STR_PATTERN_EXTERNAL "External" #define STR_PATTERN_INTERNAL "Internal" @@ -223,6 +229,10 @@ static int config_get(uint32_t key, GVariant **data, case SR_CONF_RLE: *data = g_variant_new_boolean(devc->capture_flags & CAPTURE_FLAG_RLE ? TRUE : FALSE); break; + case SR_CONF_CLOCK_EDGE: + *data = g_variant_new_string(external_clock_edges[ + devc->capture_flags & CAPTURE_FLAG_INVERT_EXT_CLOCK ? 1 : 0]); + break; default: return SR_ERR_NA; } @@ -266,6 +276,16 @@ static int config_set(uint32_t key, GVariant *data, devc->capture_flags &= ~CAPTURE_FLAG_CLOCK_EXTERNAL; } break; + case SR_CONF_CLOCK_EDGE: + stropt = g_variant_get_string(data, NULL); + if (!strcmp(stropt, external_clock_edges[1])) { + sr_info("Triggering on falling edge of external clock."); + devc->capture_flags |= CAPTURE_FLAG_INVERT_EXT_CLOCK; + } else { + sr_info("Triggering on rising edge of external clock."); + devc->capture_flags &= ~CAPTURE_FLAG_INVERT_EXT_CLOCK; + } + break; case SR_CONF_PATTERN_MODE: stropt = g_variant_get_string(data, NULL); if (!strcmp(stropt, STR_PATTERN_NONE)) { @@ -325,6 +345,9 @@ static int config_list(uint32_t key, GVariant **data, case SR_CONF_TRIGGER_MATCH: *data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches)); break; + case SR_CONF_CLOCK_EDGE: + *data = std_gvar_array_str(ARRAY_AND_SIZE(external_clock_edges)); + break; case SR_CONF_PATTERN_MODE: *data = g_variant_new_strv(ARRAY_AND_SIZE(patterns)); break; @@ -491,12 +514,15 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) } /* Flag register. */ - sr_dbg("Setting intpat %s, extpat %s, RLE %s, noise_filter %s, demux %s", + sr_dbg("Setting intpat %s, extpat %s, RLE %s, noise_filter %s, demux %s, %s clock%s", devc->capture_flags & CAPTURE_FLAG_INTERNAL_TEST_MODE ? "on": "off", devc->capture_flags & CAPTURE_FLAG_EXTERNAL_TEST_MODE ? "on": "off", devc->capture_flags & CAPTURE_FLAG_RLE ? "on" : "off", devc->capture_flags & CAPTURE_FLAG_NOISE_FILTER ? "on": "off", - devc->capture_flags & CAPTURE_FLAG_DEMUX ? "on" : "off"); + devc->capture_flags & CAPTURE_FLAG_DEMUX ? "on" : "off", + devc->capture_flags & CAPTURE_FLAG_CLOCK_EXTERNAL ? "external" : "internal", + devc->capture_flags & CAPTURE_FLAG_CLOCK_EXTERNAL ? (devc->capture_flags & CAPTURE_FLAG_INVERT_EXT_CLOCK + ? " on falling edge" : "on rising edge") : ""); /* * Enable/disable OLS channel groups in the flag register according From 552ce33fcde6e783d275bc84221700514ef337ab Mon Sep 17 00:00:00 2001 From: v1ne Date: Wed, 1 Apr 2020 00:05:37 +0200 Subject: [PATCH 05/29] ols: Make external clock setting queriable ... and thus selectable in PulseView. --- src/hardware/openbench-logic-sniffer/api.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 2815a50a9..23f68c575 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -36,7 +36,7 @@ static const uint32_t devopts[] = { SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, - SR_CONF_EXTERNAL_CLOCK | SR_CONF_SET, + SR_CONF_EXTERNAL_CLOCK | SR_CONF_GET | SR_CONF_SET, SR_CONF_CLOCK_EDGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, SR_CONF_PATTERN_MODE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, SR_CONF_SWAP | SR_CONF_SET, @@ -229,6 +229,10 @@ static int config_get(uint32_t key, GVariant **data, case SR_CONF_RLE: *data = g_variant_new_boolean(devc->capture_flags & CAPTURE_FLAG_RLE ? TRUE : FALSE); break; + case SR_CONF_EXTERNAL_CLOCK: + *data = g_variant_new_boolean( + devc->capture_flags & CAPTURE_FLAG_CLOCK_EXTERNAL ? TRUE : FALSE); + break; case SR_CONF_CLOCK_EDGE: *data = g_variant_new_string(external_clock_edges[ devc->capture_flags & CAPTURE_FLAG_INVERT_EXT_CLOCK ? 1 : 0]); From 626a33c61a9647761375567442e2b6b4f8b05f68 Mon Sep 17 00:00:00 2001 From: v1ne Date: Wed, 1 Apr 2020 05:35:02 +0200 Subject: [PATCH 06/29] ols: Refactor: Extract trigger setup into private place This copies the code verbatim from one place to another in preparation to adding support for complex triggers. --- src/hardware/openbench-logic-sniffer/api.c | 157 +------------ .../openbench-logic-sniffer/protocol.c | 210 +++++++++++++++--- .../openbench-logic-sniffer/protocol.h | 10 +- 3 files changed, 190 insertions(+), 187 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 23f68c575..7a5f22011 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -368,10 +368,10 @@ static int config_list(uint32_t key, GVariant **data, * Channel groups are turned off if no channels in that group are * enabled, making more room for samples for the enabled group. */ - ols_channel_mask(sdi); + uint32_t channel_mask = ols_channel_mask(sdi); num_ols_changrp = 0; for (i = 0; i < 4; i++) { - if (devc->channel_mask & (0xff << (i * 8))) + if (channel_mask & (0xff << (i * 8))) num_ols_changrp++; } @@ -385,163 +385,18 @@ static int config_list(uint32_t key, GVariant **data, return SR_OK; } -static int set_basic_trigger(const struct sr_dev_inst *sdi, int stage) -{ - struct dev_context *devc; - struct sr_serial_dev_inst *serial; - uint8_t cmd, arg[4]; - - devc = sdi->priv; - serial = sdi->conn; - - cmd = CMD_SET_BASIC_TRIGGER_MASK0 + stage * 4; - arg[0] = devc->trigger_mask[stage] & 0xff; - arg[1] = (devc->trigger_mask[stage] >> 8) & 0xff; - arg[2] = (devc->trigger_mask[stage] >> 16) & 0xff; - arg[3] = (devc->trigger_mask[stage] >> 24) & 0xff; - if (send_longcommand(serial, cmd, arg) != SR_OK) - return SR_ERR; - - cmd = CMD_SET_BASIC_TRIGGER_VALUE0 + stage * 4; - arg[0] = devc->trigger_value[stage] & 0xff; - arg[1] = (devc->trigger_value[stage] >> 8) & 0xff; - arg[2] = (devc->trigger_value[stage] >> 16) & 0xff; - arg[3] = (devc->trigger_value[stage] >> 24) & 0xff; - if (send_longcommand(serial, cmd, arg) != SR_OK) - return SR_ERR; - - cmd = CMD_SET_BASIC_TRIGGER_CONFIG0 + stage * 4; - arg[0] = arg[1] = arg[3] = 0x00; - arg[2] = stage; - if (stage == devc->num_stages) - /* Last stage, fire when this one matches. */ - arg[3] |= TRIGGER_START; - if (send_longcommand(serial, cmd, arg) != SR_OK) - return SR_ERR; - - return SR_OK; -} - static int dev_acquisition_start(const struct sr_dev_inst *sdi) { + int ret; struct dev_context *devc; struct sr_serial_dev_inst *serial; - uint32_t samplecount, readcount, delaycount; - uint8_t ols_changrp_mask, arg[4]; - int num_ols_changrp; - int ret, i; devc = sdi->priv; serial = sdi->conn; - ols_channel_mask(sdi); - - num_ols_changrp = 0; - ols_changrp_mask = 0; - for (i = 0; i < 4; i++) { - if (devc->channel_mask & (0xff << (i * 8))) { - ols_changrp_mask |= (1 << i); - num_ols_changrp++; - } - } - - /* - * Limit readcount to prevent reading past the end of the hardware - * buffer. Rather read too many samples than too few. - */ - samplecount = MIN(devc->max_samples / num_ols_changrp, devc->limit_samples); - readcount = (samplecount + 3) / 4; - - /* Basic triggers. */ - if (ols_convert_trigger(sdi) != SR_OK) { - sr_err("Failed to configure channels."); - return SR_ERR; - } - if (devc->num_stages > 0) { - /* - * According to http://mygizmos.org/ols/Logic-Sniffer-FPGA-Spec.pdf - * reset command must be send prior each arm command - */ - sr_dbg("Send reset command before trigger configure"); - if (ols_send_reset(serial) != SR_OK) - return SR_ERR; - - delaycount = readcount * (1 - devc->capture_ratio / 100.0); - devc->trigger_at_smpl = (readcount - delaycount) * 4 - devc->num_stages; - for (i = 0; i <= devc->num_stages; i++) { - sr_dbg("Setting OLS stage %d trigger.", i); - if ((ret = set_basic_trigger(sdi, i)) != SR_OK) - return ret; - } - } else { - /* No triggers configured, force trigger on first stage. */ - sr_dbg("Forcing trigger at stage 0."); - if ((ret = set_basic_trigger(sdi, 0)) != SR_OK) - return ret; - delaycount = readcount; - } - - /* Samplerate. */ - sr_dbg("Setting samplerate to %" PRIu64 "Hz (divider %u)", - devc->cur_samplerate, devc->cur_samplerate_divider); - arg[0] = devc->cur_samplerate_divider & 0xff; - arg[1] = (devc->cur_samplerate_divider & 0xff00) >> 8; - arg[2] = (devc->cur_samplerate_divider & 0xff0000) >> 16; - arg[3] = 0x00; - if (send_longcommand(serial, CMD_SET_DIVIDER, arg) != SR_OK) - return SR_ERR; - - /* Send sample limit and pre/post-trigger capture ratio. */ - sr_dbg("Setting sample limit %d, trigger point at %d", - (readcount - 1) * 4, (delaycount - 1) * 4); - - if (devc->max_samples > 256 * 1024) { - arg[0] = ((readcount - 1) & 0xff); - arg[1] = ((readcount - 1) & 0xff00) >> 8; - arg[2] = ((readcount - 1) & 0xff0000) >> 16; - arg[3] = ((readcount - 1) & 0xff000000) >> 24; - if (send_longcommand(serial, CMD_CAPTURE_READCOUNT, arg) != SR_OK) - return SR_ERR; - arg[0] = ((delaycount - 1) & 0xff); - arg[1] = ((delaycount - 1) & 0xff00) >> 8; - arg[2] = ((delaycount - 1) & 0xff0000) >> 16; - arg[3] = ((delaycount - 1) & 0xff000000) >> 24; - if (send_longcommand(serial, CMD_CAPTURE_DELAYCOUNT, arg) != SR_OK) - return SR_ERR; - } else { - arg[0] = ((readcount - 1) & 0xff); - arg[1] = ((readcount - 1) & 0xff00) >> 8; - arg[2] = ((delaycount - 1) & 0xff); - arg[3] = ((delaycount - 1) & 0xff00) >> 8; - if (send_longcommand(serial, CMD_CAPTURE_SIZE, arg) != SR_OK) - return SR_ERR; - } - - /* Flag register. */ - sr_dbg("Setting intpat %s, extpat %s, RLE %s, noise_filter %s, demux %s, %s clock%s", - devc->capture_flags & CAPTURE_FLAG_INTERNAL_TEST_MODE ? "on": "off", - devc->capture_flags & CAPTURE_FLAG_EXTERNAL_TEST_MODE ? "on": "off", - devc->capture_flags & CAPTURE_FLAG_RLE ? "on" : "off", - devc->capture_flags & CAPTURE_FLAG_NOISE_FILTER ? "on": "off", - devc->capture_flags & CAPTURE_FLAG_DEMUX ? "on" : "off", - devc->capture_flags & CAPTURE_FLAG_CLOCK_EXTERNAL ? "external" : "internal", - devc->capture_flags & CAPTURE_FLAG_CLOCK_EXTERNAL ? (devc->capture_flags & CAPTURE_FLAG_INVERT_EXT_CLOCK - ? " on falling edge" : "on rising edge") : ""); - - /* - * Enable/disable OLS channel groups in the flag register according - * to the channel mask. 1 means "disable channel". - */ - devc->capture_flags &= ~0x3c; - devc->capture_flags |= ~(ols_changrp_mask << 2) & 0x3c; - - /* RLE mode is always zero, for now. */ - - arg[0] = devc->capture_flags & 0xff; - arg[1] = devc->capture_flags >> 8; - arg[2] = arg[3] = 0x00; - if (send_longcommand(serial, CMD_SET_FLAGS, arg) != SR_OK) - return SR_ERR; + ret = ols_prepare_acquisition(sdi); + if (ret != SR_OK) + return ret; /* Start acquisition on the device. */ if (send_shortcommand(serial, CMD_ARM_BASIC_TRIGGER) != SR_OK) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index bedf29500..949b2c045 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -20,6 +20,13 @@ #include #include "protocol.h" + +struct ols_basic_trigger_desc { + uint32_t trigger_mask[NUM_BASIC_TRIGGER_STAGES]; + uint32_t trigger_value[NUM_BASIC_TRIGGER_STAGES]; + int num_stages; +}; + SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial, uint8_t command) { @@ -70,46 +77,39 @@ SR_PRIV int ols_send_reset(struct sr_serial_dev_inst *serial) } /* Configures the channel mask based on which channels are enabled. */ -SR_PRIV void ols_channel_mask(const struct sr_dev_inst *sdi) +SR_PRIV uint32_t ols_channel_mask(const struct sr_dev_inst *sdi) { - struct dev_context *devc; - struct sr_channel *channel; - const GSList *l; - - devc = sdi->priv; - - devc->channel_mask = 0; - for (l = sdi->channels; l; l = l->next) { - channel = l->data; + uint32_t channel_mask = 0; + for (const GSList *l = sdi->channels; l; l = l->next) { + struct sr_channel *channel = l->data; if (channel->enabled) - devc->channel_mask |= 1 << channel->index; + channel_mask |= 1 << channel->index; } + + return channel_mask; } -SR_PRIV int ols_convert_trigger(const struct sr_dev_inst *sdi) +static int convert_trigger(const struct sr_dev_inst *sdi, struct ols_basic_trigger_desc *ols_trigger) { - struct dev_context *devc; struct sr_trigger *trigger; struct sr_trigger_stage *stage; struct sr_trigger_match *match; const GSList *l, *m; int i; - devc = sdi->priv; - - devc->num_stages = 0; - for (i = 0; i < NUM_TRIGGER_STAGES; i++) { - devc->trigger_mask[i] = 0; - devc->trigger_value[i] = 0; + ols_trigger->num_stages = 0; + for (i = 0; i < NUM_BASIC_TRIGGER_STAGES; i++) { + ols_trigger->trigger_mask[i] = 0; + ols_trigger->trigger_value[i] = 0; } if (!(trigger = sr_session_trigger_get(sdi->session))) return SR_OK; - devc->num_stages = g_slist_length(trigger->stages); - if (devc->num_stages > NUM_TRIGGER_STAGES) { + ols_trigger->num_stages = g_slist_length(trigger->stages); + if (ols_trigger->num_stages > NUM_BASIC_TRIGGER_STAGES) { sr_err("This device only supports %d trigger stages.", - NUM_TRIGGER_STAGES); + NUM_BASIC_TRIGGER_STAGES); return SR_ERR; } @@ -120,9 +120,9 @@ SR_PRIV int ols_convert_trigger(const struct sr_dev_inst *sdi) if (!match->channel->enabled) /* Ignore disabled channels with a trigger. */ continue; - devc->trigger_mask[stage->stage] |= 1 << match->channel->index; + ols_trigger->trigger_mask[stage->stage] |= 1 << match->channel->index; if (match->match == SR_TRIGGER_ONE) - devc->trigger_value[stage->stage] |= 1 << match->channel->index; + ols_trigger->trigger_value[stage->stage] |= 1 << match->channel->index; } } @@ -361,7 +361,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; uint32_t sample; - int num_ols_changrp, offset, j; + int num_changroups, offset, j; unsigned int i; unsigned char byte; @@ -386,10 +386,10 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) memset(devc->raw_sample_buf, 0x82, devc->limit_samples * 4); } - num_ols_changrp = 0; + num_changroups = 0; for (i = 0x20; i > 0x02; i >>= 1) { if ((devc->capture_flags & i) == 0) { - num_ols_changrp++; + num_changroups++; } } @@ -404,7 +404,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) devc->sample[devc->num_bytes++] = byte; sr_spew("Received byte 0x%.2x.", byte); - if (devc->num_bytes == num_ols_changrp) { + if (devc->num_bytes == num_changroups) { devc->cnt_samples++; devc->cnt_samples_rle++; /* @@ -437,7 +437,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) devc->num_samples = devc->limit_samples; } - if (num_ols_changrp < 4) { + if (num_changroups < 4) { /* * Some channel groups may have been turned * off, to speed up transfer between the @@ -529,3 +529,155 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) return TRUE; } + +static int ols_set_basic_trigger_stage(const struct ols_basic_trigger_desc *trigger_desc, struct sr_serial_dev_inst *serial, int stage) +{ + uint8_t cmd, arg[4]; + + cmd = CMD_SET_BASIC_TRIGGER_MASK0 + stage * 4; + arg[0] = trigger_desc->trigger_mask[stage] & 0xff; + arg[1] = (trigger_desc->trigger_mask[stage] >> 8) & 0xff; + arg[2] = (trigger_desc->trigger_mask[stage] >> 16) & 0xff; + arg[3] = (trigger_desc->trigger_mask[stage] >> 24) & 0xff; + if (send_longcommand(serial, cmd, arg) != SR_OK) + return SR_ERR; + + cmd = CMD_SET_BASIC_TRIGGER_VALUE0 + stage * 4; + arg[0] = trigger_desc->trigger_value[stage] & 0xff; + arg[1] = (trigger_desc->trigger_value[stage] >> 8) & 0xff; + arg[2] = (trigger_desc->trigger_value[stage] >> 16) & 0xff; + arg[3] = (trigger_desc->trigger_value[stage] >> 24) & 0xff; + if (send_longcommand(serial, cmd, arg) != SR_OK) + return SR_ERR; + + cmd = CMD_SET_BASIC_TRIGGER_CONFIG0 + stage * 4; + arg[0] = arg[1] = arg[3] = 0x00; + arg[2] = stage; + if (stage == trigger_desc->num_stages) + /* Last stage, fire when this one matches. */ + arg[3] |= TRIGGER_START; + if (send_longcommand(serial, cmd, arg) != SR_OK) + return SR_ERR; + + return SR_OK; +} + +SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { + int ret; + uint8_t arg[4]; + + struct dev_context *devc = sdi->priv; + struct sr_serial_dev_inst *serial = sdi->conn; + + int num_changroups = 0; + uint8_t changroup_mask = 0; + uint32_t channel_mask = ols_channel_mask(sdi); + for (unsigned int i = 0; i < 4; i++) { + if (channel_mask & (0xff << (i * 8))) { + changroup_mask |= (1 << i); + num_changroups++; + } + } + + /* + * Limit readcount to prevent reading past the end of the hardware + * buffer. Rather read too many samples than too few. + */ + uint32_t samplecount = MIN(devc->max_samples / num_changroups, devc->limit_samples); + uint32_t readcount = (samplecount + 3) / 4; + uint32_t delaycount; + + /* Basic triggers. */ + struct ols_basic_trigger_desc basic_trigger_desc; + if (convert_trigger(sdi, &basic_trigger_desc) != SR_OK) { + sr_err("Failed to configure channels."); + return SR_ERR; + } + if (basic_trigger_desc.num_stages > 0) { + /* + * According to http://mygizmos.org/ols/Logic-Sniffer-FPGA-Spec.pdf + * reset command must be send prior each arm command + */ + sr_dbg("Send reset command before trigger configure"); + if (ols_send_reset(serial) != SR_OK) + return SR_ERR; + + delaycount = readcount * (1 - devc->capture_ratio / 100.0); + devc->trigger_at_smpl = (readcount - delaycount) * 4 - basic_trigger_desc.num_stages; + for (int i = 0; i <= basic_trigger_desc.num_stages; i++) { + sr_dbg("Setting OLS stage %d trigger.", i); + if ((ret = ols_set_basic_trigger_stage(&basic_trigger_desc, serial, i)) != SR_OK) + return ret; + } + } else { + /* No triggers configured, force trigger on first stage. */ + sr_dbg("Forcing trigger at stage 0."); + if ((ret = ols_set_basic_trigger_stage(&basic_trigger_desc, serial, 0)) != SR_OK) + return ret; + delaycount = readcount; + } + + /* Samplerate. */ + sr_dbg("Setting samplerate to %" PRIu64 "Hz (divider %u)", + devc->cur_samplerate, devc->cur_samplerate_divider); + arg[0] = devc->cur_samplerate_divider & 0xff; + arg[1] = (devc->cur_samplerate_divider & 0xff00) >> 8; + arg[2] = (devc->cur_samplerate_divider & 0xff0000) >> 16; + arg[3] = 0x00; + if (send_longcommand(serial, CMD_SET_DIVIDER, arg) != SR_OK) + return SR_ERR; + + /* Send sample limit and pre/post-trigger capture ratio. */ + sr_dbg("Setting sample limit %d, trigger point at %d", + (readcount - 1) * 4, (delaycount - 1) * 4); + + if (devc->max_samples > 256 * 1024) { + arg[0] = ((readcount - 1) & 0xff); + arg[1] = ((readcount - 1) & 0xff00) >> 8; + arg[2] = ((readcount - 1) & 0xff0000) >> 16; + arg[3] = ((readcount - 1) & 0xff000000) >> 24; + if (send_longcommand(serial, CMD_CAPTURE_READCOUNT, arg) != SR_OK) + return SR_ERR; + arg[0] = ((delaycount - 1) & 0xff); + arg[1] = ((delaycount - 1) & 0xff00) >> 8; + arg[2] = ((delaycount - 1) & 0xff0000) >> 16; + arg[3] = ((delaycount - 1) & 0xff000000) >> 24; + if (send_longcommand(serial, CMD_CAPTURE_DELAYCOUNT, arg) != SR_OK) + return SR_ERR; + } else { + arg[0] = ((readcount - 1) & 0xff); + arg[1] = ((readcount - 1) & 0xff00) >> 8; + arg[2] = ((delaycount - 1) & 0xff); + arg[3] = ((delaycount - 1) & 0xff00) >> 8; + if (send_longcommand(serial, CMD_CAPTURE_SIZE, arg) != SR_OK) + return SR_ERR; + } + + /* Flag register. */ + sr_dbg("Setting intpat %s, extpat %s, RLE %s, noise_filter %s, demux %s, %s clock%s", + devc->capture_flags & CAPTURE_FLAG_INTERNAL_TEST_MODE ? "on": "off", + devc->capture_flags & CAPTURE_FLAG_EXTERNAL_TEST_MODE ? "on": "off", + devc->capture_flags & CAPTURE_FLAG_RLE ? "on" : "off", + devc->capture_flags & CAPTURE_FLAG_NOISE_FILTER ? "on": "off", + devc->capture_flags & CAPTURE_FLAG_DEMUX ? "on" : "off", + devc->capture_flags & CAPTURE_FLAG_CLOCK_EXTERNAL ? "external" : "internal", + devc->capture_flags & CAPTURE_FLAG_CLOCK_EXTERNAL ? (devc->capture_flags & CAPTURE_FLAG_INVERT_EXT_CLOCK + ? " on falling edge" : "on rising edge") : ""); + + /* + * Enable/disable OLS channel groups in the flag register according + * to the channel mask. 1 means "disable channel". + */ + devc->capture_flags &= ~0x3c; + devc->capture_flags |= ~(changroup_mask << 2) & 0x3c; + + /* RLE mode is always zero, for now. */ + + arg[0] = devc->capture_flags & 0xff; + arg[1] = devc->capture_flags >> 8; + arg[2] = arg[3] = 0x00; + if (send_longcommand(serial, CMD_SET_FLAGS, arg) != SR_OK) + return SR_ERR; + + return SR_OK; +} diff --git a/src/hardware/openbench-logic-sniffer/protocol.h b/src/hardware/openbench-logic-sniffer/protocol.h index e164b9fa1..6b8c2422b 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -28,7 +28,7 @@ #define LOG_PREFIX "openbench-logic-sniffer" -#define NUM_TRIGGER_STAGES 4 +#define NUM_BASIC_TRIGGER_STAGES 4 #define CLOCK_RATE SR_MHZ(100) #define MIN_NUM_SAMPLES 4 #define DEFAULT_SAMPLERATE SR_KHZ(200) @@ -112,10 +112,6 @@ struct dev_context { uint64_t limit_samples; uint64_t capture_ratio; int trigger_at_smpl; - uint32_t channel_mask; - uint32_t trigger_mask[NUM_TRIGGER_STAGES]; - uint32_t trigger_value[NUM_TRIGGER_STAGES]; - int num_stages; uint16_t capture_flags; unsigned int num_transfers; @@ -138,8 +134,8 @@ SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial, SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial, uint8_t command, uint8_t *data); SR_PRIV int ols_send_reset(struct sr_serial_dev_inst *serial); -SR_PRIV void ols_channel_mask(const struct sr_dev_inst *sdi); -SR_PRIV int ols_convert_trigger(const struct sr_dev_inst *sdi); +SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi); +SR_PRIV uint32_t ols_channel_mask(const struct sr_dev_inst *sdi); SR_PRIV struct dev_context *ols_dev_new(void); SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial); SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi, From d5de5036b891a62801ea9f8399184b62ce55c704 Mon Sep 17 00:00:00 2001 From: v1ne Date: Wed, 1 Apr 2020 00:29:05 +0200 Subject: [PATCH 07/29] ols: Clean up: Replace hand-rolled byte order conversion with existing macros --- .../openbench-logic-sniffer/protocol.c | 52 ++++++------------- 1 file changed, 17 insertions(+), 35 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 949b2c045..9ac91982a 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -20,7 +20,6 @@ #include #include "protocol.h" - struct ols_basic_trigger_desc { uint32_t trigger_mask[NUM_BASIC_TRIGGER_STAGES]; uint32_t trigger_value[NUM_BASIC_TRIGGER_STAGES]; @@ -64,6 +63,14 @@ SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial, return SR_OK; } +static int ols_send_longdata(struct sr_serial_dev_inst *serial, + uint8_t command, uint32_t value) +{ + uint8_t data[4]; + WL32(data, value); + return send_longcommand(serial, command, data); +} + SR_PRIV int ols_send_reset(struct sr_serial_dev_inst *serial) { unsigned int i; @@ -535,19 +542,11 @@ static int ols_set_basic_trigger_stage(const struct ols_basic_trigger_desc *trig uint8_t cmd, arg[4]; cmd = CMD_SET_BASIC_TRIGGER_MASK0 + stage * 4; - arg[0] = trigger_desc->trigger_mask[stage] & 0xff; - arg[1] = (trigger_desc->trigger_mask[stage] >> 8) & 0xff; - arg[2] = (trigger_desc->trigger_mask[stage] >> 16) & 0xff; - arg[3] = (trigger_desc->trigger_mask[stage] >> 24) & 0xff; - if (send_longcommand(serial, cmd, arg) != SR_OK) + if (ols_send_longdata(serial, cmd, trigger_desc->trigger_mask[stage]) != SR_OK) return SR_ERR; cmd = CMD_SET_BASIC_TRIGGER_VALUE0 + stage * 4; - arg[0] = trigger_desc->trigger_value[stage] & 0xff; - arg[1] = (trigger_desc->trigger_value[stage] >> 8) & 0xff; - arg[2] = (trigger_desc->trigger_value[stage] >> 16) & 0xff; - arg[3] = (trigger_desc->trigger_value[stage] >> 24) & 0xff; - if (send_longcommand(serial, cmd, arg) != SR_OK) + if (ols_send_longdata(serial, cmd, trigger_desc->trigger_value[stage]) != SR_OK) return SR_ERR; cmd = CMD_SET_BASIC_TRIGGER_CONFIG0 + stage * 4; @@ -564,7 +563,6 @@ static int ols_set_basic_trigger_stage(const struct ols_basic_trigger_desc *trig SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { int ret; - uint8_t arg[4]; struct dev_context *devc = sdi->priv; struct sr_serial_dev_inst *serial = sdi->conn; @@ -620,11 +618,7 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { /* Samplerate. */ sr_dbg("Setting samplerate to %" PRIu64 "Hz (divider %u)", devc->cur_samplerate, devc->cur_samplerate_divider); - arg[0] = devc->cur_samplerate_divider & 0xff; - arg[1] = (devc->cur_samplerate_divider & 0xff00) >> 8; - arg[2] = (devc->cur_samplerate_divider & 0xff0000) >> 16; - arg[3] = 0x00; - if (send_longcommand(serial, CMD_SET_DIVIDER, arg) != SR_OK) + if (ols_send_longdata(serial, CMD_SET_DIVIDER, devc->cur_samplerate_divider & 0x00FFFFFF) != SR_OK) return SR_ERR; /* Send sample limit and pre/post-trigger capture ratio. */ @@ -632,23 +626,14 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { (readcount - 1) * 4, (delaycount - 1) * 4); if (devc->max_samples > 256 * 1024) { - arg[0] = ((readcount - 1) & 0xff); - arg[1] = ((readcount - 1) & 0xff00) >> 8; - arg[2] = ((readcount - 1) & 0xff0000) >> 16; - arg[3] = ((readcount - 1) & 0xff000000) >> 24; - if (send_longcommand(serial, CMD_CAPTURE_READCOUNT, arg) != SR_OK) + if (ols_send_longdata(serial, CMD_CAPTURE_READCOUNT, readcount-1) != SR_OK) return SR_ERR; - arg[0] = ((delaycount - 1) & 0xff); - arg[1] = ((delaycount - 1) & 0xff00) >> 8; - arg[2] = ((delaycount - 1) & 0xff0000) >> 16; - arg[3] = ((delaycount - 1) & 0xff000000) >> 24; - if (send_longcommand(serial, CMD_CAPTURE_DELAYCOUNT, arg) != SR_OK) + if (ols_send_longdata(serial, CMD_CAPTURE_DELAYCOUNT, delaycount-1) != SR_OK) return SR_ERR; } else { - arg[0] = ((readcount - 1) & 0xff); - arg[1] = ((readcount - 1) & 0xff00) >> 8; - arg[2] = ((delaycount - 1) & 0xff); - arg[3] = ((delaycount - 1) & 0xff00) >> 8; + uint8_t arg[4]; + WL16(&arg[0], readcount-1); + WL16(&arg[2], delaycount-1); if (send_longcommand(serial, CMD_CAPTURE_SIZE, arg) != SR_OK) return SR_ERR; } @@ -673,10 +658,7 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { /* RLE mode is always zero, for now. */ - arg[0] = devc->capture_flags & 0xff; - arg[1] = devc->capture_flags >> 8; - arg[2] = arg[3] = 0x00; - if (send_longcommand(serial, CMD_SET_FLAGS, arg) != SR_OK) + if (ols_send_longdata(serial, CMD_SET_FLAGS, devc->capture_flags) != SR_OK) return SR_ERR; return SR_OK; From 535d1ebe70fd9c4cd5bcbefe636ef807609fbf3e Mon Sep 17 00:00:00 2001 From: v1ne Date: Thu, 2 Apr 2020 00:18:46 +0200 Subject: [PATCH 08/29] ols: Provide sample count in RLE mode It just means "number of compressed samples", but it's still highly useful to decice how much data to capture. If this is unavailable, PulseView provides a weird list of up to 1 TSmpl, which makes even less sense. --- src/hardware/openbench-logic-sniffer/api.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 7a5f22011..e7dbf1e37 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -359,8 +359,6 @@ static int config_list(uint32_t key, GVariant **data, if (!sdi) return SR_ERR_ARG; devc = sdi->priv; - if (devc->capture_flags & CAPTURE_FLAG_RLE) - return SR_ERR_NA; if (devc->max_samples == 0) /* Device didn't specify sample memory size in metadata. */ return SR_ERR_NA; From 1841da4678c1d32c48955413d054007b3a809dde Mon Sep 17 00:00:00 2001 From: v1ne Date: Wed, 1 Apr 2020 16:15:51 +0200 Subject: [PATCH 09/29] ols: Don't store temporary data in device context --- src/hardware/openbench-logic-sniffer/protocol.c | 8 ++++---- src/hardware/openbench-logic-sniffer/protocol.h | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 9ac91982a..5905cf676 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -455,7 +455,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * the number of channels. */ j = 0; - memset(devc->tmp_sample, 0, 4); + uint8_t tmp_sample[4] = {0,0,0,0}; for (i = 0; i < 4; i++) { if (((devc->capture_flags >> 2) & (1 << i)) == 0) { /* @@ -463,13 +463,13 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * enabled, copy from received * sample. */ - devc->tmp_sample[i] = devc->sample[j++]; + tmp_sample[i] = devc->sample[j++]; } else if (devc->capture_flags & CAPTURE_FLAG_DEMUX && (i > 2)) { /* group 2 & 3 get added to 0 & 1 */ - devc->tmp_sample[i - 2] = devc->sample[j++]; + tmp_sample[i - 2] = devc->sample[j++]; } } - memcpy(devc->sample, devc->tmp_sample, 4); + memcpy(devc->sample, tmp_sample, 4); sr_spew("Expanded sample: 0x%.2hhx%.2hhx%.2hhx%.2hhx ", devc->sample[3], devc->sample[2], devc->sample[1], devc->sample[0]); } diff --git a/src/hardware/openbench-logic-sniffer/protocol.h b/src/hardware/openbench-logic-sniffer/protocol.h index 6b8c2422b..147b15113 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -123,7 +123,6 @@ struct dev_context { unsigned int rle_count; unsigned char sample[4]; - unsigned char tmp_sample[4]; unsigned char *raw_sample_buf; }; From 6b7d06f99a0d31cd6528af99c42d88db214b08ac Mon Sep 17 00:00:00 2001 From: v1ne Date: Wed, 1 Apr 2020 22:57:10 +0200 Subject: [PATCH 10/29] ols: Don't silently ignore error when setting up the device --- src/hardware/openbench-logic-sniffer/api.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index e7dbf1e37..671314ed3 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -411,10 +411,8 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) /* If the device stops sending for longer than it takes to send a byte, * that means it's finished. But wait at least 100 ms to be safe. */ - serial_source_add(sdi->session, serial, G_IO_IN, 100, + return serial_source_add(sdi->session, serial, G_IO_IN, 100, ols_receive_data, (struct sr_dev_inst *)sdi); - - return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi) From 094bd3f2a14452ae68216e3cf10929bc901c1867 Mon Sep 17 00:00:00 2001 From: v1ne Date: Wed, 1 Apr 2020 16:57:57 +0200 Subject: [PATCH 11/29] ols: Forward errors to callers in a generic way This further reduces clutter. An exception is where an error message is logged. In those cases, I left the old pattern in place. --- .../openbench-logic-sniffer/protocol.c | 51 ++++++++----------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 5905cf676..758af76a5 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -20,6 +20,13 @@ #include #include "protocol.h" +#define RETURN_ON_ERROR(statement) \ + do{ \ + int retval; \ + if ((retval=(statement)) != SR_OK)\ + return retval; \ + } while(0) + struct ols_basic_trigger_desc { uint32_t trigger_mask[NUM_BASIC_TRIGGER_STAGES]; uint32_t trigger_value[NUM_BASIC_TRIGGER_STAGES]; @@ -36,8 +43,7 @@ SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial, if (serial_write_blocking(serial, buf, 1, serial_timeout(serial, 1)) != 1) return SR_ERR; - if (serial_drain(serial) != SR_OK) - return SR_ERR; + RETURN_ON_ERROR(serial_drain(serial)); return SR_OK; } @@ -57,8 +63,7 @@ SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial, if (serial_write_blocking(serial, buf, 5, serial_timeout(serial, 1)) != 5) return SR_ERR; - if (serial_drain(serial) != SR_OK) - return SR_ERR; + RETURN_ON_ERROR(serial_drain(serial)); return SR_OK; } @@ -76,8 +81,7 @@ SR_PRIV int ols_send_reset(struct sr_serial_dev_inst *serial) unsigned int i; for (i = 0; i < 5; i++) { - if (send_shortcommand(serial, CMD_RESET) != SR_OK) - return SR_ERR; + RETURN_ON_ERROR(send_shortcommand(serial, CMD_RESET)); } return SR_OK; @@ -542,12 +546,10 @@ static int ols_set_basic_trigger_stage(const struct ols_basic_trigger_desc *trig uint8_t cmd, arg[4]; cmd = CMD_SET_BASIC_TRIGGER_MASK0 + stage * 4; - if (ols_send_longdata(serial, cmd, trigger_desc->trigger_mask[stage]) != SR_OK) - return SR_ERR; + RETURN_ON_ERROR(ols_send_longdata(serial, cmd, trigger_desc->trigger_mask[stage])); cmd = CMD_SET_BASIC_TRIGGER_VALUE0 + stage * 4; - if (ols_send_longdata(serial, cmd, trigger_desc->trigger_value[stage]) != SR_OK) - return SR_ERR; + RETURN_ON_ERROR(ols_send_longdata(serial, cmd, trigger_desc->trigger_value[stage])); cmd = CMD_SET_BASIC_TRIGGER_CONFIG0 + stage * 4; arg[0] = arg[1] = arg[3] = 0x00; @@ -555,15 +557,12 @@ static int ols_set_basic_trigger_stage(const struct ols_basic_trigger_desc *trig if (stage == trigger_desc->num_stages) /* Last stage, fire when this one matches. */ arg[3] |= TRIGGER_START; - if (send_longcommand(serial, cmd, arg) != SR_OK) - return SR_ERR; + RETURN_ON_ERROR(send_longcommand(serial, cmd, arg)); return SR_OK; } SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { - int ret; - struct dev_context *devc = sdi->priv; struct sr_serial_dev_inst *serial = sdi->conn; @@ -597,45 +596,38 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { * reset command must be send prior each arm command */ sr_dbg("Send reset command before trigger configure"); - if (ols_send_reset(serial) != SR_OK) - return SR_ERR; + RETURN_ON_ERROR(ols_send_reset(serial)); delaycount = readcount * (1 - devc->capture_ratio / 100.0); devc->trigger_at_smpl = (readcount - delaycount) * 4 - basic_trigger_desc.num_stages; for (int i = 0; i <= basic_trigger_desc.num_stages; i++) { sr_dbg("Setting OLS stage %d trigger.", i); - if ((ret = ols_set_basic_trigger_stage(&basic_trigger_desc, serial, i)) != SR_OK) - return ret; + RETURN_ON_ERROR(ols_set_basic_trigger_stage(&basic_trigger_desc, serial, i)); } } else { /* No triggers configured, force trigger on first stage. */ sr_dbg("Forcing trigger at stage 0."); - if ((ret = ols_set_basic_trigger_stage(&basic_trigger_desc, serial, 0)) != SR_OK) - return ret; + RETURN_ON_ERROR(ols_set_basic_trigger_stage(&basic_trigger_desc, serial, 0)); delaycount = readcount; } /* Samplerate. */ sr_dbg("Setting samplerate to %" PRIu64 "Hz (divider %u)", devc->cur_samplerate, devc->cur_samplerate_divider); - if (ols_send_longdata(serial, CMD_SET_DIVIDER, devc->cur_samplerate_divider & 0x00FFFFFF) != SR_OK) - return SR_ERR; + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_DIVIDER, devc->cur_samplerate_divider & 0x00FFFFFF)); /* Send sample limit and pre/post-trigger capture ratio. */ sr_dbg("Setting sample limit %d, trigger point at %d", (readcount - 1) * 4, (delaycount - 1) * 4); if (devc->max_samples > 256 * 1024) { - if (ols_send_longdata(serial, CMD_CAPTURE_READCOUNT, readcount-1) != SR_OK) - return SR_ERR; - if (ols_send_longdata(serial, CMD_CAPTURE_DELAYCOUNT, delaycount-1) != SR_OK) - return SR_ERR; + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_CAPTURE_READCOUNT, readcount-1)); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_CAPTURE_DELAYCOUNT, delaycount-1)); } else { uint8_t arg[4]; WL16(&arg[0], readcount-1); WL16(&arg[2], delaycount-1); - if (send_longcommand(serial, CMD_CAPTURE_SIZE, arg) != SR_OK) - return SR_ERR; + RETURN_ON_ERROR(send_longcommand(serial, CMD_CAPTURE_SIZE, arg)); } /* Flag register. */ @@ -658,8 +650,7 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { /* RLE mode is always zero, for now. */ - if (ols_send_longdata(serial, CMD_SET_FLAGS, devc->capture_flags) != SR_OK) - return SR_ERR; + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_FLAGS, devc->capture_flags)); return SR_OK; } From 26177a3a971c9beb723cedc57a340a9c36b990fe Mon Sep 17 00:00:00 2001 From: v1ne Date: Wed, 1 Apr 2020 16:13:03 +0200 Subject: [PATCH 12/29] ols: Fix demuxer operation On my OLS with Demon Core (v3.07), the following command produces only low levels on channels 8-15: sigrok-cli -d ols:conn=/dev/ttyACM0 --output-format ascii:width=128 \ --config='samplerate=200M:pattern=Internal:captureratio=50' \ --channels 0-15 --samples 32 --triggers "12=1" This doesn't make sense since it only triggers if channel 12 is high. By not overwriting the channel data, I get the desired output. The data is processed in groups of 2 bytes, so there's no need to fold back "input" from devc->sample[2..3] because these bytes are always zero. --- src/hardware/openbench-logic-sniffer/protocol.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 758af76a5..df136d4ed 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -468,9 +468,6 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * sample. */ tmp_sample[i] = devc->sample[j++]; - } else if (devc->capture_flags & CAPTURE_FLAG_DEMUX && (i > 2)) { - /* group 2 & 3 get added to 0 & 1 */ - tmp_sample[i - 2] = devc->sample[j++]; } } memcpy(devc->sample, tmp_sample, 4); From e984bd15a988eaf74d4dc81c70cd473a3bebe0d6 Mon Sep 17 00:00:00 2001 From: v1ne Date: Wed, 1 Apr 2020 19:27:51 +0200 Subject: [PATCH 13/29] ols: Fix off-by-one when setting up trigger stages The additional stage prevented OLS from using 4 stages. --- src/hardware/openbench-logic-sniffer/protocol.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index df136d4ed..2c826a7b6 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -551,7 +551,7 @@ static int ols_set_basic_trigger_stage(const struct ols_basic_trigger_desc *trig cmd = CMD_SET_BASIC_TRIGGER_CONFIG0 + stage * 4; arg[0] = arg[1] = arg[3] = 0x00; arg[2] = stage; - if (stage == trigger_desc->num_stages) + if (stage == trigger_desc->num_stages - 1) /* Last stage, fire when this one matches. */ arg[3] |= TRIGGER_START; RETURN_ON_ERROR(send_longcommand(serial, cmd, arg)); @@ -597,13 +597,14 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { delaycount = readcount * (1 - devc->capture_ratio / 100.0); devc->trigger_at_smpl = (readcount - delaycount) * 4 - basic_trigger_desc.num_stages; - for (int i = 0; i <= basic_trigger_desc.num_stages; i++) { + for (int i = 0; i < basic_trigger_desc.num_stages; i++) { sr_dbg("Setting OLS stage %d trigger.", i); RETURN_ON_ERROR(ols_set_basic_trigger_stage(&basic_trigger_desc, serial, i)); } } else { /* No triggers configured, force trigger on first stage. */ sr_dbg("Forcing trigger at stage 0."); + basic_trigger_desc.num_stages = 1; RETURN_ON_ERROR(ols_set_basic_trigger_stage(&basic_trigger_desc, serial, 0)); delaycount = readcount; } From 566e726a97322079019c6973eea573a10c2a52db Mon Sep 17 00:00:00 2001 From: v1ne Date: Wed, 1 Apr 2020 19:28:59 +0200 Subject: [PATCH 14/29] ols: Adjust pre-trigger delay On my unit with Demon Core v3.07, I don't see a stage-dependent delay. Thus, set the delay so that in my tests, the trigger point lines up with the edge of a test signal. --- src/hardware/openbench-logic-sniffer/protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 2c826a7b6..8a09a209d 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -596,7 +596,7 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { RETURN_ON_ERROR(ols_send_reset(serial)); delaycount = readcount * (1 - devc->capture_ratio / 100.0); - devc->trigger_at_smpl = (readcount - delaycount) * 4 - basic_trigger_desc.num_stages; + devc->trigger_at_smpl = (readcount - delaycount) * 4 - 1; for (int i = 0; i < basic_trigger_desc.num_stages; i++) { sr_dbg("Setting OLS stage %d trigger.", i); RETURN_ON_ERROR(ols_set_basic_trigger_stage(&basic_trigger_desc, serial, i)); From 11d03e39b5bcdba93bd3f3a8d8576a8a1cc174bb Mon Sep 17 00:00:00 2001 From: v1ne Date: Thu, 2 Apr 2020 00:21:15 +0200 Subject: [PATCH 15/29] ols: Flip samples after reading everything Because in RLE mode, we don't know how many samples we could read. The limit that we tell the hardware is only the limit in number of compressed samples, not the number of uncompressed samples. --- .../openbench-logic-sniffer/protocol.c | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 8a09a209d..5c5acf32c 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -372,7 +372,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; uint32_t sample; - int num_changroups, offset, j; + int num_changroups, j; unsigned int i; unsigned char byte; @@ -441,12 +441,6 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) return TRUE; } } - devc->num_samples += devc->rle_count + 1; - if (devc->num_samples > devc->limit_samples) { - /* Save us from overrunning the buffer. */ - devc->rle_count -= devc->num_samples - devc->limit_samples; - devc->num_samples = devc->limit_samples; - } if (num_changroups < 4) { /* @@ -475,16 +469,12 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) devc->sample[3], devc->sample[2], devc->sample[1], devc->sample[0]); } - /* - * the OLS sends its sample buffer backwards. - * store it in reverse order here, so we can dump - * this on the session bus later. - */ - offset = (devc->limit_samples - devc->num_samples) * 4; - for (i = 0; i <= devc->rle_count; i++) { - memcpy(devc->raw_sample_buf + offset + (i * 4), - devc->sample, 4); - } + unsigned int samples_to_write = devc->rle_count + 1; + for (i = 0; i < samples_to_write; i++) + memcpy(devc->raw_sample_buf + (devc->num_samples + i) * 4, devc->sample, 4); + + devc->num_samples += samples_to_write; + memset(devc->sample, 0, 4); devc->num_bytes = 0; devc->rle_count = 0; @@ -498,6 +488,18 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) sr_dbg("Received %d bytes, %d samples, %d decompressed samples.", devc->cnt_bytes, devc->cnt_samples, devc->cnt_samples_rle); + + /* + * The OLS sends its sample buffer backwards. + * Flip it back before sending it on the session bus. + */ + for(i = 0; i < devc->num_samples/2; i++) { + uint8_t temp[4]; + memcpy(temp, &devc->raw_sample_buf[4*i], 4); + memmove(&devc->raw_sample_buf[4*i], &devc->raw_sample_buf[4*(devc->num_samples-i-1)], 4); + memcpy(&devc->raw_sample_buf[4*(devc->num_samples-i-1)], temp, 4); + } + if (devc->trigger_at_smpl != OLS_NO_TRIGGER) { /* * A trigger was set up, so we need to tell the frontend From 83682b215b88504d15323049d4b3bad8ad3710ab Mon Sep 17 00:00:00 2001 From: v1ne Date: Thu, 2 Apr 2020 00:32:58 +0200 Subject: [PATCH 16/29] ols: Use a dynamic sample buffer The number of samples to be received is pretty clear if no RLE is being used. But if RLE is being used, the number of raw samples must be counted. For now, read samples until we time out. This should work for RLE and non-RLE, but may break if the device is connected via a high-latency network connection. --- src/hardware/openbench-logic-sniffer/api.c | 2 +- .../openbench-logic-sniffer/protocol.c | 41 ++++++++++--------- .../openbench-logic-sniffer/protocol.h | 2 +- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 671314ed3..629effd0f 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -401,7 +401,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) return SR_ERR; /* Reset all operational states. */ - devc->rle_count = devc->num_transfers = 0; + devc->rle_count = devc->raw_sample_buf_size = 0; devc->num_samples = devc->num_bytes = 0; devc->cnt_bytes = devc->cnt_samples = devc->cnt_samples_rle = 0; memset(devc->sample, 0, 4); diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 5c5acf32c..1bdc1929d 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -382,21 +382,11 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) serial = sdi->conn; devc = sdi->priv; - if (devc->num_transfers == 0 && revents == 0) { + if (devc->cnt_bytes == 0 && revents == 0) { /* Ignore timeouts as long as we haven't received anything */ return TRUE; } - if (devc->num_transfers++ == 0) { - devc->raw_sample_buf = g_try_malloc(devc->limit_samples * 4); - if (!devc->raw_sample_buf) { - sr_err("Sample buffer malloc failed."); - return FALSE; - } - /* fill with 1010... for debugging */ - memset(devc->raw_sample_buf, 0x82, devc->limit_samples * 4); - } - num_changroups = 0; for (i = 0x20; i > 0x02; i >>= 1) { if ((devc->capture_flags & i) == 0) { @@ -404,15 +394,11 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) } } - if (revents == G_IO_IN && devc->num_samples < devc->limit_samples) { + if (revents == G_IO_IN) { if (serial_read_nonblocking(serial, &byte, 1) != 1) return FALSE; devc->cnt_bytes++; - /* Ignore it if we've read enough. */ - if (devc->num_samples >= devc->limit_samples) - return TRUE; - devc->sample[devc->num_bytes++] = byte; sr_spew("Received byte 0x%.2x.", byte); if (devc->num_bytes == num_changroups) { @@ -470,6 +456,22 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) } unsigned int samples_to_write = devc->rle_count + 1; + unsigned int new_sample_buf_size = + 4 * MAX(devc->limit_samples, devc->num_samples + samples_to_write); + if (devc->raw_sample_buf_size < new_sample_buf_size) { + unsigned int old_size = devc->raw_sample_buf_size; + new_sample_buf_size *= 2; + devc->raw_sample_buf = g_try_realloc(devc->raw_sample_buf, new_sample_buf_size); + devc->raw_sample_buf_size = new_sample_buf_size; + + if (!devc->raw_sample_buf) { + sr_err("Sample buffer malloc failed."); + return FALSE; + } + /* fill with 1010... for debugging */ + memset(devc->raw_sample_buf + old_size, 0x82, new_sample_buf_size - old_size); + } + for (i = 0; i < samples_to_write; i++) memcpy(devc->raw_sample_buf + (devc->num_samples + i) * 4, devc->sample, 4); @@ -511,8 +513,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) packet.payload = &logic; logic.length = devc->trigger_at_smpl * 4; logic.unitsize = 4; - logic.data = devc->raw_sample_buf + - (devc->limit_samples - devc->num_samples) * 4; + logic.data = devc->raw_sample_buf; sr_session_send(sdi, &packet); } @@ -527,11 +528,11 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) packet.payload = &logic; logic.length = (devc->num_samples - num_pre_trigger_samples) * 4; logic.unitsize = 4; - logic.data = devc->raw_sample_buf + (num_pre_trigger_samples + - devc->limit_samples - devc->num_samples) * 4; + logic.data = devc->raw_sample_buf + num_pre_trigger_samples *4; sr_session_send(sdi, &packet); g_free(devc->raw_sample_buf); + devc->raw_sample_buf = 0; serial_flush(serial); abort_acquisition(sdi); diff --git a/src/hardware/openbench-logic-sniffer/protocol.h b/src/hardware/openbench-logic-sniffer/protocol.h index 147b15113..8aab052ea 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -114,7 +114,6 @@ struct dev_context { int trigger_at_smpl; uint16_t capture_flags; - unsigned int num_transfers; unsigned int num_samples; int num_bytes; int cnt_bytes; @@ -124,6 +123,7 @@ struct dev_context { unsigned int rle_count; unsigned char sample[4]; unsigned char *raw_sample_buf; + unsigned int raw_sample_buf_size; }; SR_PRIV extern const char *ols_channel_names[]; From cdef4c442f0d010301b48812b0ba6367ac7ab220 Mon Sep 17 00:00:00 2001 From: v1ne Date: Thu, 2 Apr 2020 01:13:35 +0200 Subject: [PATCH 17/29] ols: Be more robust against short reads If the devices times out during a transfer, it can be that num_samples is smaller than trigger_at_smpl. --- .../openbench-logic-sniffer/protocol.c | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 1bdc1929d..82d68cebf 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -507,7 +507,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * A trigger was set up, so we need to tell the frontend * about it. */ - if (devc->trigger_at_smpl > 0) { + if (devc->trigger_at_smpl > 0 + && (unsigned int)devc->trigger_at_smpl <= devc->num_samples) { /* There are pre-trigger samples, send those first. */ packet.type = SR_DF_LOGIC; packet.payload = &logic; @@ -522,14 +523,16 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) } /* Send post-trigger / all captured samples. */ - int num_pre_trigger_samples = devc->trigger_at_smpl == OLS_NO_TRIGGER - ? 0 : devc->trigger_at_smpl; - packet.type = SR_DF_LOGIC; - packet.payload = &logic; - logic.length = (devc->num_samples - num_pre_trigger_samples) * 4; - logic.unitsize = 4; - logic.data = devc->raw_sample_buf + num_pre_trigger_samples *4; - sr_session_send(sdi, &packet); + unsigned int num_pre_trigger_samples = devc->trigger_at_smpl == OLS_NO_TRIGGER + ? 0 : MIN((unsigned int)devc->trigger_at_smpl, devc->num_samples); + if (devc->num_samples > num_pre_trigger_samples) { + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + logic.length = (devc->num_samples - num_pre_trigger_samples) * 4; + logic.unitsize = 4; + logic.data = devc->raw_sample_buf + num_pre_trigger_samples *4; + sr_session_send(sdi, &packet); + } g_free(devc->raw_sample_buf); devc->raw_sample_buf = 0; From ce4e4a80f649d4adde49db2ca51ddbb5084f1ddc Mon Sep 17 00:00:00 2001 From: v1ne Date: Thu, 2 Apr 2020 00:26:13 +0200 Subject: [PATCH 18/29] ols: Make resetting more robust, reset at the end In my experiments, this helped when not all data was read from the device. Otherwise, sigrok-cli would just hang. Also, be nice and reset the device when an acquisition ends. This is not strictly necessary, but is a nice touch, I think. --- .../openbench-logic-sniffer/protocol.c | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 82d68cebf..00b133697 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -78,13 +78,26 @@ static int ols_send_longdata(struct sr_serial_dev_inst *serial, SR_PRIV int ols_send_reset(struct sr_serial_dev_inst *serial) { - unsigned int i; + int i, ret; + char dummy[16]; + + /* Drain all data so that the remote side is surely listening. */ + while ((ret = serial_read_nonblocking(serial, &dummy, 16)) > 0); + if (ret != SR_OK) + return ret; - for (i = 0; i < 5; i++) { + for (i = 0; i < 5; i++) RETURN_ON_ERROR(send_shortcommand(serial, CMD_RESET)); - } - return SR_OK; + /* + * Remove all stray output that arrived in between. + * This is likely to happen when RLE is being used because + * the device seems to return a bit more data than we request. + */ + int delay_ms = serial_timeout(serial, 16); + while ((ret = serial_read_blocking(serial, &dummy, 16, delay_ms)) > 0); + + return ret; } /* Configures the channel mask based on which channels are enabled. */ @@ -354,13 +367,11 @@ SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi, SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi) { - struct sr_serial_dev_inst *serial; + struct sr_serial_dev_inst *serial = sdi->conn; - serial = sdi->conn; ols_send_reset(serial); serial_source_remove(sdi->session, serial); - std_session_send_df_end(sdi); } From eeeceb91d9c8d19b8461194e8e7372820525dfd7 Mon Sep 17 00:00:00 2001 From: v1ne Date: Thu, 2 Apr 2020 18:21:39 +0200 Subject: [PATCH 19/29] ols: Clean up: Rename variables, remove misleading counter cnt_samples_rle was larger than num_samples in RLE mode. Instead of correcting that, use num_samples instead. --- src/hardware/openbench-logic-sniffer/api.c | 8 +- .../openbench-logic-sniffer/protocol.c | 85 +++++++++---------- .../openbench-logic-sniffer/protocol.h | 15 ++-- 3 files changed, 52 insertions(+), 56 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 629effd0f..f1967f4ce 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -401,10 +401,10 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) return SR_ERR; /* Reset all operational states. */ - devc->rle_count = devc->raw_sample_buf_size = 0; - devc->num_samples = devc->num_bytes = 0; - devc->cnt_bytes = devc->cnt_samples = devc->cnt_samples_rle = 0; - memset(devc->sample, 0, 4); + devc->rle_count = devc->sample_buf_size = 0; + devc->cnt_samples = devc->raw_sample_size = 0; + devc->cnt_rx_bytes = devc->cnt_rx_raw_samples = 0; + memset(devc->raw_sample, 0, 4); std_session_send_df_header(sdi); diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 00b133697..7776c81ec 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -383,8 +383,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; uint32_t sample; - int num_changroups, j; - unsigned int i; + unsigned int i, j, num_changroups; unsigned char byte; (void)fd; @@ -393,7 +392,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) serial = sdi->conn; devc = sdi->priv; - if (devc->cnt_bytes == 0 && revents == 0) { + if (devc->cnt_rx_bytes == 0 && revents == 0) { /* Ignore timeouts as long as we haven't received anything */ return TRUE; } @@ -408,33 +407,31 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) if (revents == G_IO_IN) { if (serial_read_nonblocking(serial, &byte, 1) != 1) return FALSE; - devc->cnt_bytes++; + devc->cnt_rx_bytes++; - devc->sample[devc->num_bytes++] = byte; + devc->raw_sample[devc->raw_sample_size++] = byte; sr_spew("Received byte 0x%.2x.", byte); - if (devc->num_bytes == num_changroups) { - devc->cnt_samples++; - devc->cnt_samples_rle++; + if (devc->raw_sample_size == num_changroups) { + devc->cnt_rx_raw_samples++; /* * Got a full sample. Convert from the OLS's little-endian * sample to the local format. */ - sample = devc->sample[0] | (devc->sample[1] << 8) \ - | (devc->sample[2] << 16) | (devc->sample[3] << 24); - sr_dbg("Received sample 0x%.*x.", devc->num_bytes * 2, sample); + sample = devc->raw_sample[0] | (devc->raw_sample[1] << 8) \ + | (devc->raw_sample[2] << 16) | (devc->raw_sample[3] << 24); + sr_dbg("Received sample 0x%.*x.", devc->raw_sample_size * 2, sample); if (devc->capture_flags & CAPTURE_FLAG_RLE) { /* * In RLE mode the high bit of the sample is the * "count" flag, meaning this sample is the number * of times the previous sample occurred. */ - if (devc->sample[devc->num_bytes - 1] & 0x80) { + if (devc->raw_sample[devc->raw_sample_size - 1] & 0x80) { /* Clear the high bit. */ - sample &= ~(0x80 << (devc->num_bytes - 1) * 8); + sample &= ~(0x80 << (devc->raw_sample_size - 1) * 8); devc->rle_count = sample; - devc->cnt_samples_rle += devc->rle_count; sr_dbg("RLE count: %u.", devc->rle_count); - devc->num_bytes = 0; + devc->raw_sample_size = 0; return TRUE; } } @@ -458,38 +455,38 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * enabled, copy from received * sample. */ - tmp_sample[i] = devc->sample[j++]; + tmp_sample[i] = devc->raw_sample[j++]; } } - memcpy(devc->sample, tmp_sample, 4); + memcpy(devc->raw_sample, tmp_sample, 4); sr_spew("Expanded sample: 0x%.2hhx%.2hhx%.2hhx%.2hhx ", - devc->sample[3], devc->sample[2], devc->sample[1], devc->sample[0]); + devc->raw_sample[3], devc->raw_sample[2], devc->raw_sample[1], devc->raw_sample[0]); } unsigned int samples_to_write = devc->rle_count + 1; unsigned int new_sample_buf_size = - 4 * MAX(devc->limit_samples, devc->num_samples + samples_to_write); - if (devc->raw_sample_buf_size < new_sample_buf_size) { - unsigned int old_size = devc->raw_sample_buf_size; + 4 * MAX(devc->limit_samples, devc->cnt_samples + samples_to_write); + if (devc->sample_buf_size < new_sample_buf_size) { + unsigned int old_size = devc->sample_buf_size; new_sample_buf_size *= 2; - devc->raw_sample_buf = g_try_realloc(devc->raw_sample_buf, new_sample_buf_size); - devc->raw_sample_buf_size = new_sample_buf_size; + devc->sample_buf = g_try_realloc(devc->sample_buf, new_sample_buf_size); + devc->sample_buf_size = new_sample_buf_size; - if (!devc->raw_sample_buf) { + if (!devc->sample_buf) { sr_err("Sample buffer malloc failed."); return FALSE; } /* fill with 1010... for debugging */ - memset(devc->raw_sample_buf + old_size, 0x82, new_sample_buf_size - old_size); + memset(devc->sample_buf + old_size, 0x82, new_sample_buf_size - old_size); } for (i = 0; i < samples_to_write; i++) - memcpy(devc->raw_sample_buf + (devc->num_samples + i) * 4, devc->sample, 4); + memcpy(devc->sample_buf + (devc->cnt_samples + i) * 4, devc->raw_sample, 4); - devc->num_samples += samples_to_write; + devc->cnt_samples += samples_to_write; - memset(devc->sample, 0, 4); - devc->num_bytes = 0; + memset(devc->raw_sample, 0, 4); + devc->raw_sample_size = 0; devc->rle_count = 0; } } else { @@ -498,19 +495,19 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * we've acquired all the samples we asked for -- we're done. * Send the (properly-ordered) buffer to the frontend. */ - sr_dbg("Received %d bytes, %d samples, %d decompressed samples.", - devc->cnt_bytes, devc->cnt_samples, - devc->cnt_samples_rle); + sr_dbg("Received %d bytes, %d raw samples, %d decompressed samples.", + devc->cnt_rx_bytes, devc->cnt_rx_raw_samples, + devc->cnt_samples); /* * The OLS sends its sample buffer backwards. * Flip it back before sending it on the session bus. */ - for(i = 0; i < devc->num_samples/2; i++) { + for(i = 0; i < devc->cnt_samples/2; i++) { uint8_t temp[4]; - memcpy(temp, &devc->raw_sample_buf[4*i], 4); - memmove(&devc->raw_sample_buf[4*i], &devc->raw_sample_buf[4*(devc->num_samples-i-1)], 4); - memcpy(&devc->raw_sample_buf[4*(devc->num_samples-i-1)], temp, 4); + memcpy(temp, &devc->sample_buf[4*i], 4); + memmove(&devc->sample_buf[4*i], &devc->sample_buf[4*(devc->cnt_samples-i-1)], 4); + memcpy(&devc->sample_buf[4*(devc->cnt_samples-i-1)], temp, 4); } if (devc->trigger_at_smpl != OLS_NO_TRIGGER) { @@ -519,13 +516,13 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * about it. */ if (devc->trigger_at_smpl > 0 - && (unsigned int)devc->trigger_at_smpl <= devc->num_samples) { + && (unsigned int)devc->trigger_at_smpl <= devc->cnt_samples) { /* There are pre-trigger samples, send those first. */ packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = devc->trigger_at_smpl * 4; logic.unitsize = 4; - logic.data = devc->raw_sample_buf; + logic.data = devc->sample_buf; sr_session_send(sdi, &packet); } @@ -535,18 +532,18 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) /* Send post-trigger / all captured samples. */ unsigned int num_pre_trigger_samples = devc->trigger_at_smpl == OLS_NO_TRIGGER - ? 0 : MIN((unsigned int)devc->trigger_at_smpl, devc->num_samples); - if (devc->num_samples > num_pre_trigger_samples) { + ? 0 : MIN((unsigned int)devc->trigger_at_smpl, devc->cnt_samples); + if (devc->cnt_samples > num_pre_trigger_samples) { packet.type = SR_DF_LOGIC; packet.payload = &logic; - logic.length = (devc->num_samples - num_pre_trigger_samples) * 4; + logic.length = (devc->cnt_samples - num_pre_trigger_samples) * 4; logic.unitsize = 4; - logic.data = devc->raw_sample_buf + num_pre_trigger_samples *4; + logic.data = devc->sample_buf + num_pre_trigger_samples *4; sr_session_send(sdi, &packet); } - g_free(devc->raw_sample_buf); - devc->raw_sample_buf = 0; + g_free(devc->sample_buf); + devc->sample_buf = 0; serial_flush(serial); abort_acquisition(sdi); diff --git a/src/hardware/openbench-logic-sniffer/protocol.h b/src/hardware/openbench-logic-sniffer/protocol.h index 8aab052ea..0af8cd57b 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -114,16 +114,15 @@ struct dev_context { int trigger_at_smpl; uint16_t capture_flags; - unsigned int num_samples; - int num_bytes; - int cnt_bytes; - int cnt_samples; - int cnt_samples_rle; + unsigned int cnt_rx_bytes; /* number of bytes received */ + unsigned int raw_sample_size; /* valid bytes in sample[4] */ + unsigned char raw_sample[4]; /* raw sample, assembled from received bytes */ + unsigned int cnt_rx_raw_samples; /* number of raw samples received */ unsigned int rle_count; - unsigned char sample[4]; - unsigned char *raw_sample_buf; - unsigned int raw_sample_buf_size; + unsigned char *sample_buf; + unsigned int sample_buf_size; + unsigned int cnt_samples; /* number of final samples in sample_buf */ }; SR_PRIV extern const char *ols_channel_names[]; From 04541cec1f2c6cd8d74ae998998be0e579252116 Mon Sep 17 00:00:00 2001 From: v1ne Date: Thu, 2 Apr 2020 18:56:17 +0200 Subject: [PATCH 20/29] ols: Clean up: Always keep sample_buf_size up to date --- src/hardware/openbench-logic-sniffer/api.c | 2 +- src/hardware/openbench-logic-sniffer/protocol.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index f1967f4ce..28767c4bb 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -401,7 +401,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) return SR_ERR; /* Reset all operational states. */ - devc->rle_count = devc->sample_buf_size = 0; + devc->rle_count = 0; devc->cnt_samples = devc->raw_sample_size = 0; devc->cnt_rx_bytes = devc->cnt_rx_raw_samples = 0; memset(devc->raw_sample, 0, 4); diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 7776c81ec..c74adaf68 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -544,6 +544,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) g_free(devc->sample_buf); devc->sample_buf = 0; + devc->sample_buf_size = 0; serial_flush(serial); abort_acquisition(sdi); From bf3e2cf14d81477670af9358c3670d76a4e89845 Mon Sep 17 00:00:00 2001 From: v1ne Date: Thu, 2 Apr 2020 19:40:08 +0200 Subject: [PATCH 21/29] ols: Communicate internally that the number of samples is a multiple of 4 The exact number must be known when reading data so that we can read the right number of samples without incuring a timeout penalty. --- src/hardware/openbench-logic-sniffer/protocol.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index c74adaf68..4291d5b11 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -589,11 +589,11 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { } /* - * Limit readcount to prevent reading past the end of the hardware - * buffer. Rather read too many samples than too few. + * Limit the number of samples to what the hardware can do. + * The sample count is always a multiple of four. */ - uint32_t samplecount = MIN(devc->max_samples / num_changroups, devc->limit_samples); - uint32_t readcount = (samplecount + 3) / 4; + devc->limit_samples = (MIN(devc->max_samples / num_changroups, devc->limit_samples) + 3) / 4 * 4; + uint32_t readcount = devc->limit_samples / 4; uint32_t delaycount; /* Basic triggers. */ From ee81d50c01f040c5731fc04e222380a6adf5a7f2 Mon Sep 17 00:00:00 2001 From: v1ne Date: Thu, 2 Apr 2020 18:54:01 +0200 Subject: [PATCH 22/29] ols: Immediately process data after expected sample count Even with RLE enabled, we know how many samples to expect: Exactly the configured number, no less, no more. Thus, when that number is received, begin processing immediately. Also, put a warning so that we can get to know if the calculation is off. Since this works, the timeout can be bumped to provide for better usability if the logic sniffer is used over a slow network connection. --- src/hardware/openbench-logic-sniffer/api.c | 5 +++-- src/hardware/openbench-logic-sniffer/protocol.c | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 28767c4bb..dc66e3133 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -409,9 +409,10 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) std_session_send_df_header(sdi); /* If the device stops sending for longer than it takes to send a byte, - * that means it's finished. But wait at least 100 ms to be safe. + * that means it's finished. Since the device can be used over a slow + * network link, give it 10 seconds to reply. */ - return serial_source_add(sdi->session, serial, G_IO_IN, 100, + return serial_source_add(sdi->session, serial, G_IO_IN, 10*1000, ols_receive_data, (struct sr_dev_inst *)sdi); } diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 4291d5b11..f2884bf5d 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -432,7 +432,12 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) devc->rle_count = sample; sr_dbg("RLE count: %u.", devc->rle_count); devc->raw_sample_size = 0; - return TRUE; + + /* + * Even on the rare occasion that the sampling ends with an RLE message, + * the acquisition should end immediately, without any timeout. + */ + goto process_and_forward; } } @@ -489,7 +494,13 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) devc->raw_sample_size = 0; devc->rle_count = 0; } - } else { + } + +process_and_forward: + if (revents != G_IO_IN || devc->cnt_rx_raw_samples == devc->limit_samples) { + if (devc->cnt_rx_raw_samples != devc->limit_samples) + sr_warn("Finished with unexpected sample count. Timeout?"); + /* * This is the main loop telling us a timeout was reached, or * we've acquired all the samples we asked for -- we're done. From 8e33794b18452f28cc6a5330a6e4dcb60cfee857 Mon Sep 17 00:00:00 2001 From: v1ne Date: Thu, 2 Apr 2020 19:14:17 +0200 Subject: [PATCH 23/29] ols: Receive many bytes in a row We're talking about 20 kB, so there's little need to go back to the event loop in between. But there's also no reason why we should go back to the event loop if we can read more data immediately. --- src/hardware/openbench-logic-sniffer/protocol.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index f2884bf5d..32414d44a 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -385,6 +385,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) uint32_t sample; unsigned int i, j, num_changroups; unsigned char byte; + gboolean received_a_byte; (void)fd; @@ -404,9 +405,9 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) } } - if (revents == G_IO_IN) { - if (serial_read_nonblocking(serial, &byte, 1) != 1) - return FALSE; + received_a_byte = FALSE; + while (revents == G_IO_IN && serial_read_nonblocking(serial, &byte, 1) == 1) { + received_a_byte = TRUE; devc->cnt_rx_bytes++; devc->raw_sample[devc->raw_sample_size++] = byte; @@ -495,6 +496,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) devc->rle_count = 0; } } + if (revents == G_IO_IN && !received_a_byte) + return FALSE; process_and_forward: if (revents != G_IO_IN || devc->cnt_rx_raw_samples == devc->limit_samples) { From cecf50e0b485d10973b5d7cc69e69579adad4666 Mon Sep 17 00:00:00 2001 From: v1ne Date: Thu, 2 Apr 2020 19:28:54 +0200 Subject: [PATCH 24/29] ols: Capture multiple bytes at once Why just read a single byte when you can read a whole sample? --- src/hardware/openbench-logic-sniffer/protocol.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 32414d44a..72354cde2 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -383,8 +383,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; uint32_t sample; + int num_bytes_read; unsigned int i, j, num_changroups; - unsigned char byte; gboolean received_a_byte; (void)fd; @@ -406,12 +406,18 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) } received_a_byte = FALSE; - while (revents == G_IO_IN && serial_read_nonblocking(serial, &byte, 1) == 1) { + while (revents == G_IO_IN && + (num_bytes_read = serial_read_nonblocking(serial, + devc->raw_sample + devc->raw_sample_size, + num_changroups - devc->raw_sample_size)) > 0) { received_a_byte = TRUE; - devc->cnt_rx_bytes++; + devc->cnt_rx_bytes += num_bytes_read; + devc->raw_sample_size += num_bytes_read; + + sr_spew("Received data. Current sample: %.2x%.2x%.2x%.2x (%u bytes)", + devc->raw_sample[0], devc->raw_sample[1], + devc->raw_sample[2], devc->raw_sample[3], devc->raw_sample_size); - devc->raw_sample[devc->raw_sample_size++] = byte; - sr_spew("Received byte 0x%.2x.", byte); if (devc->raw_sample_size == num_changroups) { devc->cnt_rx_raw_samples++; /* From 4d22f5bef8528d29bcb0a2cbce365a915e3832a1 Mon Sep 17 00:00:00 2001 From: v1ne Date: Thu, 2 Apr 2020 20:33:48 +0200 Subject: [PATCH 25/29] ols: Determine the right trigger point when using RLE Due to the nature of RLE, the number of samples from the start to the trigger point is unknown. What is known is that the hardware triggers still records a given number of raw samples to its sample memory. When reading and expanding these raw samples from the back (remember, OLS sends the recording back-to-front), remember the expanded sample position from the back and then map it back to the right position from the front once the total number of expanded samples is known. --- src/hardware/openbench-logic-sniffer/api.c | 1 + .../openbench-logic-sniffer/protocol.c | 34 ++++++++++++++++++- .../openbench-logic-sniffer/protocol.h | 1 + 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index dc66e3133..026157be4 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -402,6 +402,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) /* Reset all operational states. */ devc->rle_count = 0; + devc->trigger_rle_at_smpl_from_end = OLS_NO_TRIGGER; devc->cnt_samples = devc->raw_sample_size = 0; devc->cnt_rx_bytes = devc->cnt_rx_raw_samples = 0; memset(devc->raw_sample, 0, 4); diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 72354cde2..93b921fec 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -159,6 +159,7 @@ SR_PRIV struct dev_context *ols_dev_new(void) devc = g_malloc0(sizeof(struct dev_context)); devc->trigger_at_smpl = OLS_NO_TRIGGER; + devc->trigger_rle_at_smpl_from_end = OLS_NO_TRIGGER; return devc; } @@ -440,6 +441,11 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) sr_dbg("RLE count: %u.", devc->rle_count); devc->raw_sample_size = 0; + if (devc->trigger_at_smpl != OLS_NO_TRIGGER + && devc->trigger_rle_at_smpl_from_end == OLS_NO_TRIGGER + && (unsigned int)devc->trigger_at_smpl == devc->cnt_rx_raw_samples) + devc->trigger_rle_at_smpl_from_end = devc->cnt_samples; + /* * Even on the rare occasion that the sampling ends with an RLE message, * the acquisition should end immediately, without any timeout. @@ -492,6 +498,12 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) memset(devc->sample_buf + old_size, 0x82, new_sample_buf_size - old_size); } + if (devc->capture_flags & CAPTURE_FLAG_RLE + && devc->trigger_at_smpl != OLS_NO_TRIGGER + && devc->trigger_rle_at_smpl_from_end == OLS_NO_TRIGGER + && (unsigned int)devc->trigger_at_smpl == devc->cnt_rx_raw_samples) + devc->trigger_rle_at_smpl_from_end = devc->cnt_samples; + for (i = 0; i < samples_to_write; i++) memcpy(devc->sample_buf + (devc->cnt_samples + i) * 4, devc->raw_sample, 4); @@ -519,6 +531,16 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) devc->cnt_rx_bytes, devc->cnt_rx_raw_samples, devc->cnt_samples); + if (devc->capture_flags & CAPTURE_FLAG_RLE) { + if (devc->trigger_rle_at_smpl_from_end != OLS_NO_TRIGGER) + devc->trigger_at_smpl = devc->cnt_samples - devc->trigger_rle_at_smpl_from_end; + else { + if (devc->trigger_at_smpl != OLS_NO_TRIGGER) + sr_warn("No trigger point found. Short read?"); + devc->trigger_at_smpl = OLS_NO_TRIGGER; + } + } + /* * The OLS sends its sample buffer backwards. * Flip it back before sending it on the session bus. @@ -615,6 +637,7 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { devc->limit_samples = (MIN(devc->max_samples / num_changroups, devc->limit_samples) + 3) / 4 * 4; uint32_t readcount = devc->limit_samples / 4; uint32_t delaycount; + int trigger_point = OLS_NO_TRIGGER; /* Basic triggers. */ struct ols_basic_trigger_desc basic_trigger_desc; @@ -631,7 +654,7 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { RETURN_ON_ERROR(ols_send_reset(serial)); delaycount = readcount * (1 - devc->capture_ratio / 100.0); - devc->trigger_at_smpl = (readcount - delaycount) * 4 - 1; + trigger_point = (readcount - delaycount) * 4 - 1; for (int i = 0; i < basic_trigger_desc.num_stages; i++) { sr_dbg("Setting OLS stage %d trigger.", i); RETURN_ON_ERROR(ols_set_basic_trigger_stage(&basic_trigger_desc, serial, i)); @@ -644,6 +667,15 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { delaycount = readcount; } + /* + * To determine the proper trigger sample position in RLE mode, a reverse + * lookup is needed while reading the samples. Set up the right trigger + * point in that case or the normal trigger point for non-RLE acquisitions. + */ + devc->trigger_at_smpl = trigger_point == OLS_NO_TRIGGER ? OLS_NO_TRIGGER + : devc->capture_flags & CAPTURE_FLAG_RLE ? + (int)devc->limit_samples - trigger_point : trigger_point; + /* Samplerate. */ sr_dbg("Setting samplerate to %" PRIu64 "Hz (divider %u)", devc->cur_samplerate, devc->cur_samplerate_divider); diff --git a/src/hardware/openbench-logic-sniffer/protocol.h b/src/hardware/openbench-logic-sniffer/protocol.h index 0af8cd57b..60acb1080 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -112,6 +112,7 @@ struct dev_context { uint64_t limit_samples; uint64_t capture_ratio; int trigger_at_smpl; + int trigger_rle_at_smpl_from_end; uint16_t capture_flags; unsigned int cnt_rx_bytes; /* number of bytes received */ From fb32bf109b19ddf50e61ec122254618b9d52f5fc Mon Sep 17 00:00:00 2001 From: v1ne Date: Thu, 2 Apr 2020 23:53:50 +0200 Subject: [PATCH 26/29] ols: Support Demon Core RLE mode 3 This mode can double the space available for RLE messages because unchanged values don't have to be repeated. --- .../openbench-logic-sniffer/protocol.c | 35 ++++++++++++------- .../openbench-logic-sniffer/protocol.h | 4 +-- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 93b921fec..0176722e3 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -385,7 +385,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) struct sr_datafeed_logic logic; uint32_t sample; int num_bytes_read; - unsigned int i, j, num_changroups; + unsigned int num_changroups; gboolean received_a_byte; (void)fd; @@ -400,7 +400,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) } num_changroups = 0; - for (i = 0x20; i > 0x02; i >>= 1) { + for (uint16_t i = 0x20; i > 0x02; i >>= 1) { if ((devc->capture_flags & i) == 0) { num_changroups++; } @@ -437,8 +437,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) if (devc->raw_sample[devc->raw_sample_size - 1] & 0x80) { /* Clear the high bit. */ sample &= ~(0x80 << (devc->raw_sample_size - 1) * 8); - devc->rle_count = sample; - sr_dbg("RLE count: %u.", devc->rle_count); + devc->rle_count += sample; + sr_dbg("RLE count: %" PRIu64, devc->rle_count); devc->raw_sample_size = 0; if (devc->trigger_at_smpl != OLS_NO_TRIGGER @@ -464,9 +464,9 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * expecting a full 32-bit sample, based on * the number of channels. */ - j = 0; + unsigned int j = 0; uint8_t tmp_sample[4] = {0,0,0,0}; - for (i = 0; i < 4; i++) { + for (unsigned int i = 0; i < 4; i++) { if (((devc->capture_flags >> 2) & (1 << i)) == 0) { /* * This channel group was @@ -481,11 +481,11 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) devc->raw_sample[3], devc->raw_sample[2], devc->raw_sample[1], devc->raw_sample[0]); } - unsigned int samples_to_write = devc->rle_count + 1; - unsigned int new_sample_buf_size = + uint64_t samples_to_write = devc->rle_count + 1; + uint64_t new_sample_buf_size = 4 * MAX(devc->limit_samples, devc->cnt_samples + samples_to_write); if (devc->sample_buf_size < new_sample_buf_size) { - unsigned int old_size = devc->sample_buf_size; + uint64_t old_size = devc->sample_buf_size; new_sample_buf_size *= 2; devc->sample_buf = g_try_realloc(devc->sample_buf, new_sample_buf_size); devc->sample_buf_size = new_sample_buf_size; @@ -504,7 +504,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) && (unsigned int)devc->trigger_at_smpl == devc->cnt_rx_raw_samples) devc->trigger_rle_at_smpl_from_end = devc->cnt_samples; - for (i = 0; i < samples_to_write; i++) + for (uint64_t i = 0; i < samples_to_write; i++) memcpy(devc->sample_buf + (devc->cnt_samples + i) * 4, devc->raw_sample, 4); devc->cnt_samples += samples_to_write; @@ -527,7 +527,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * we've acquired all the samples we asked for -- we're done. * Send the (properly-ordered) buffer to the frontend. */ - sr_dbg("Received %d bytes, %d raw samples, %d decompressed samples.", + sr_dbg("Received %d bytes, %d raw samples, %" PRIu64 " decompressed samples.", devc->cnt_rx_bytes, devc->cnt_rx_raw_samples, devc->cnt_samples); @@ -545,7 +545,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * The OLS sends its sample buffer backwards. * Flip it back before sending it on the session bus. */ - for(i = 0; i < devc->cnt_samples/2; i++) { + for(uint64_t i = 0; i < devc->cnt_samples/2; i++) { uint8_t temp[4]; memcpy(temp, &devc->sample_buf[4*i], 4); memmove(&devc->sample_buf[4*i], &devc->sample_buf[4*(devc->cnt_samples-i-1)], 4); @@ -713,7 +713,16 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { devc->capture_flags &= ~0x3c; devc->capture_flags |= ~(changroup_mask << 2) & 0x3c; - /* RLE mode is always zero, for now. */ + /* + * Demon Core supports RLE mode 3. In this mode, an arbitrary number of + * consecutive RLE messages can occur. The value is only sent whenever + * it changes. In contrast, mode 0 repeats the value after every RLE + * message, even if it didn't change. + */ + if (devc->device_flags & DEVICE_FLAG_IS_DEMON_CORE) + devc->capture_flags |= CAPTURE_FLAG_RLEMODE0 | CAPTURE_FLAG_RLEMODE1; + else + devc->capture_flags &= ~(CAPTURE_FLAG_RLEMODE0 | CAPTURE_FLAG_RLEMODE1); RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_FLAGS, devc->capture_flags)); diff --git a/src/hardware/openbench-logic-sniffer/protocol.h b/src/hardware/openbench-logic-sniffer/protocol.h index 60acb1080..5f09e7e5f 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -120,10 +120,10 @@ struct dev_context { unsigned char raw_sample[4]; /* raw sample, assembled from received bytes */ unsigned int cnt_rx_raw_samples; /* number of raw samples received */ - unsigned int rle_count; + uint64_t rle_count; unsigned char *sample_buf; unsigned int sample_buf_size; - unsigned int cnt_samples; /* number of final samples in sample_buf */ + uint64_t cnt_samples; /* number of final samples in sample_buf */ }; SR_PRIV extern const char *ols_channel_names[]; From 789e911a8adf4c1ce5e1b0643394f819186029ec Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 31 Mar 2020 19:48:52 +0200 Subject: [PATCH 27/29] ols: Add support for advanced triggers This adds code from http://web.archive.org/web/20190317154112/ http://mygizmos.org/ols/Logic-Sniffer-FPGA-Spec.pdf (GPL2 with the option to relicense it to any later version of that license) with reformatting and without typos to set up the LUT bits. The trigger setup starts with a delay to collect the required number of pre-trigger samples. Afterwards, the remaining samples are captured or further trigger stages follow. Each of these extra stages mirrors what the user has defined as trigger pattern: Level and edge triggers are combined and the state machine only advances to the next stage if all levels and at least one edge meets the conditions. Contrary to level triggers, edge triggers are ORed together. This is an undocumented property of the Demon Core. --- src/hardware/openbench-logic-sniffer/api.c | 25 +- .../openbench-logic-sniffer/protocol.c | 491 +++++++++++++++++- .../openbench-logic-sniffer/protocol.h | 11 +- 3 files changed, 489 insertions(+), 38 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 026157be4..c254af5f6 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -43,11 +43,19 @@ static const uint32_t devopts[] = { SR_CONF_RLE | SR_CONF_GET | SR_CONF_SET, }; -static const int32_t trigger_matches[] = { +static const int32_t basic_trigger_matches[] = { SR_TRIGGER_ZERO, SR_TRIGGER_ONE, }; +static const int32_t advanced_trigger_matches[] = { + SR_TRIGGER_ZERO, + SR_TRIGGER_ONE, + SR_TRIGGER_RISING, + SR_TRIGGER_FALLING, + SR_TRIGGER_EDGE, +}; + static const char* external_clock_edges[] = { "rising", // positive edge "falling" // negative edge @@ -336,7 +344,7 @@ static int config_set(uint32_t key, GVariant *data, static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { - struct dev_context *devc; + struct dev_context *devc = sdi ? sdi->priv : NULL; int num_ols_changrp, i; switch (key) { @@ -347,7 +355,12 @@ static int config_list(uint32_t key, GVariant **data, *data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates)); break; case SR_CONF_TRIGGER_MATCH: - *data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches)); + if (!devc) + return SR_ERR_ARG; + /* Advanced Triggering is only available on the Demon Core. */ + *data = devc->device_flags & DEVICE_FLAG_IS_DEMON_CORE + ? std_gvar_array_i32(ARRAY_AND_SIZE(advanced_trigger_matches)) + : std_gvar_array_i32(ARRAY_AND_SIZE(basic_trigger_matches)); break; case SR_CONF_CLOCK_EDGE: *data = std_gvar_array_str(ARRAY_AND_SIZE(external_clock_edges)); @@ -356,9 +369,8 @@ static int config_list(uint32_t key, GVariant **data, *data = g_variant_new_strv(ARRAY_AND_SIZE(patterns)); break; case SR_CONF_LIMIT_SAMPLES: - if (!sdi) + if (!devc) return SR_ERR_ARG; - devc = sdi->priv; if (devc->max_samples == 0) /* Device didn't specify sample memory size in metadata. */ return SR_ERR_NA; @@ -397,7 +409,8 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) return ret; /* Start acquisition on the device. */ - if (send_shortcommand(serial, CMD_ARM_BASIC_TRIGGER) != SR_OK) + if (send_shortcommand(serial, devc->device_flags & DEVICE_FLAG_IS_DEMON_CORE + ? CMD_ARM_ADVANCED_TRIGGER : CMD_ARM_BASIC_TRIGGER) != SR_OK) return SR_ERR; /* Reset all operational states. */ diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 0176722e3..4bdc7717f 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -2,6 +2,7 @@ * This file is part of the libsigrok project. * * Copyright (C) 2013 Bert Vermeulen + * Copyright (C) 2011 Ian Davis * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,6 +34,8 @@ struct ols_basic_trigger_desc { int num_stages; }; +static int ols_convert_and_set_up_advanced_trigger(const struct sr_dev_inst *sdi, int *num_stages); + SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial, uint8_t command) { @@ -113,7 +116,7 @@ SR_PRIV uint32_t ols_channel_mask(const struct sr_dev_inst *sdi) return channel_mask; } -static int convert_trigger(const struct sr_dev_inst *sdi, struct ols_basic_trigger_desc *ols_trigger) +static int ols_convert_basic_trigger(const struct sr_dev_inst *sdi, struct ols_basic_trigger_desc *ols_trigger) { struct sr_trigger *trigger; struct sr_trigger_stage *stage; @@ -144,9 +147,18 @@ static int convert_trigger(const struct sr_dev_inst *sdi, struct ols_basic_trigg if (!match->channel->enabled) /* Ignore disabled channels with a trigger. */ continue; + ols_trigger->trigger_mask[stage->stage] |= 1 << match->channel->index; - if (match->match == SR_TRIGGER_ONE) + switch (match->match) { + case SR_TRIGGER_ZERO: + break; + case SR_TRIGGER_ONE: ols_trigger->trigger_value[stage->stage] |= 1 << match->channel->index; + break; + default: + sr_err("Unsupported trigger type: %d", match->match); + return SR_ERR; + } } } @@ -372,8 +384,13 @@ SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi) ols_send_reset(serial); - serial_source_remove(sdi->session, serial); - std_session_send_df_end(sdi); + int ret = serial_source_remove(sdi->session, serial); + if (ret != SR_OK) + sr_warn("Couldn't close serial port: %i", ret); + + ret = std_session_send_df_end(sdi); + if (ret != SR_OK) + sr_warn("Couldn't end session: %i", ret); } SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) @@ -620,6 +637,14 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { struct dev_context *devc = sdi->priv; struct sr_serial_dev_inst *serial = sdi->conn; + /* + * According to http://mygizmos.org/ols/Logic-Sniffer-FPGA-Spec.pdf + * reset command must be send prior each arm command + */ + sr_dbg("Send reset command before trigger configure"); + RETURN_ON_ERROR(ols_send_reset(serial)); + + int num_changroups = 0; uint8_t changroup_mask = 0; uint32_t channel_mask = ols_channel_mask(sdi); @@ -639,32 +664,39 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { uint32_t delaycount; int trigger_point = OLS_NO_TRIGGER; - /* Basic triggers. */ - struct ols_basic_trigger_desc basic_trigger_desc; - if (convert_trigger(sdi, &basic_trigger_desc) != SR_OK) { - sr_err("Failed to configure channels."); - return SR_ERR; - } - if (basic_trigger_desc.num_stages > 0) { - /* - * According to http://mygizmos.org/ols/Logic-Sniffer-FPGA-Spec.pdf - * reset command must be send prior each arm command - */ - sr_dbg("Send reset command before trigger configure"); - RETURN_ON_ERROR(ols_send_reset(serial)); - - delaycount = readcount * (1 - devc->capture_ratio / 100.0); - trigger_point = (readcount - delaycount) * 4 - 1; - for (int i = 0; i < basic_trigger_desc.num_stages; i++) { - sr_dbg("Setting OLS stage %d trigger.", i); - RETURN_ON_ERROR(ols_set_basic_trigger_stage(&basic_trigger_desc, serial, i)); + if (!(devc->device_flags & DEVICE_FLAG_IS_DEMON_CORE)) { /* basic trigger only */ + struct ols_basic_trigger_desc basic_trigger_desc; + if (ols_convert_basic_trigger(sdi, &basic_trigger_desc) != SR_OK) { + sr_err("Failed to configure channels."); + return SR_ERR; + } + if (basic_trigger_desc.num_stages > 0) { + delaycount = readcount * (1 - devc->capture_ratio / 100.0); + trigger_point = (readcount - delaycount) * 4 - 1; + for (int i = 0; i < basic_trigger_desc.num_stages; i++) { + sr_dbg("Setting OLS stage %d trigger.", i); + RETURN_ON_ERROR(ols_set_basic_trigger_stage(&basic_trigger_desc, serial, i)); + } + } else { + /* No triggers configured, force trigger on first stage. */ + sr_dbg("Forcing trigger at stage 0."); + basic_trigger_desc.num_stages = 1; + RETURN_ON_ERROR(ols_set_basic_trigger_stage(&basic_trigger_desc, serial, 0)); + delaycount = readcount; } } else { - /* No triggers configured, force trigger on first stage. */ - sr_dbg("Forcing trigger at stage 0."); - basic_trigger_desc.num_stages = 1; - RETURN_ON_ERROR(ols_set_basic_trigger_stage(&basic_trigger_desc, serial, 0)); - delaycount = readcount; + /* advanced trigger setup */ + gboolean will_trigger = FALSE; + if(ols_convert_and_set_up_advanced_trigger(sdi, &will_trigger) != SR_OK) { + sr_err("Advanced trigger setup failed."); + return SR_ERR; + } + + if (will_trigger) { + delaycount = readcount * (1 - devc->capture_ratio / 100.0); + trigger_point = (readcount - delaycount) * 4; + } else + delaycount = readcount; } /* @@ -728,3 +760,406 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { return SR_OK; } + + +/* set up a level trigger stage to trigger when (input & mask) == target */ +static int ols_set_advanced_level_trigger( + struct sr_serial_dev_inst *serial, + uint8_t num_trigger_term, /* 0-9 for trigger terms a-j */ + uint32_t target, + uint32_t mask) +{ + uint32_t lutmask = 1; + uint32_t lutbits[4] = {0, 0, 0, 0}; + + for (uint32_t i = 0; i < 16; ++i) + { + if (((i ^ ((target >> 0) & 0xF)) & ((mask >> 0) & 0xF)) == 0) lutbits[0] |= lutmask; + if (((i ^ ((target >> 4) & 0xF)) & ((mask >> 4) & 0xF)) == 0) lutbits[0] |= (lutmask << 16); + if (((i ^ ((target >> 8) & 0xF)) & ((mask >> 8) & 0xF)) == 0) lutbits[1] |= lutmask; + if (((i ^ ((target >> 12) & 0xF)) & ((mask >> 12) & 0xF)) == 0) lutbits[1] |= (lutmask << 16); + if (((i ^ ((target >> 16) & 0xF)) & ((mask >> 16) & 0xF)) == 0) lutbits[2] |= lutmask; + if (((i ^ ((target >> 20) & 0xF)) & ((mask >> 20) & 0xF)) == 0) lutbits[2] |= (lutmask << 16); + if (((i ^ ((target >> 24) & 0xF)) & ((mask >> 24) & 0xF)) == 0) lutbits[3] |= lutmask; + if (((i ^ ((target >> 28) & 0xF)) & ((mask >> 28) & 0xF)) == 0) lutbits[3] |= (lutmask << 16); + lutmask <<= 1; + } + + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, 0x20 + (num_trigger_term % 10))); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits[3])); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits[2])); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits[1])); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits[0])); + return SR_OK; +} + +#define OLS_ADV_TRIG_EDGERISE0 0x0A0A +#define OLS_ADV_TRIG_EDGERISE1 0x00CC +#define OLS_ADV_TRIG_EDGEFALL0 0x5050 +#define OLS_ADV_TRIG_EDGEFALL1 0x3300 +#define OLS_ADV_TRIG_EDGEBOTH0 (OLS_ADV_TRIG_EDGERISE0 | OLS_ADV_TRIG_EDGEFALL0) +#define OLS_ADV_TRIG_EDGEBOTH1 (OLS_ADV_TRIG_EDGERISE1 | OLS_ADV_TRIG_EDGEFALL1) +#define OLS_ADV_TRIG_EDGENEITHER0 (~OLS_ADV_TRIG_EDGEBOTH0 & 0xFFFF) // means neither rise nor fall: constant signal +#define OLS_ADV_TRIG_EDGENEITHER1 (~OLS_ADV_TRIG_EDGEBOTH1 & 0xFFFF) + +/* Set up edge trigger LUTs. + * + * All edge triggers of one unit are ORed together, not ANDed. This + * differs from level triggers, where all levels have to be met at the + * same time. This code is at least consistent in that it also ORs together + * pairs of edge triggers. + */ +static int ols_set_advanced_edge_trigger( + struct sr_serial_dev_inst *serial, + int edgesel, // which edge trigger unit, 0 or 1 + uint32_t rising_edge, + uint32_t falling_edge, + uint32_t neither_edge) +{ + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, 0x34 + (edgesel & 1))); + + uint32_t lutbits = 0; + uint32_t bitmask = 0x80000000; + for (unsigned int i = 0; i < 16; i = i + 1) { + /* Evaluate indata bit1... */ + if (neither_edge & bitmask) + lutbits |= OLS_ADV_TRIG_EDGENEITHER1; + else { + if (rising_edge & bitmask) lutbits |= OLS_ADV_TRIG_EDGERISE1; + if (falling_edge & bitmask) lutbits |= OLS_ADV_TRIG_EDGEFALL1; + } + bitmask >>= 1; + + /* Evaluate indata bit0... */ + if (neither_edge & bitmask) + lutbits |= OLS_ADV_TRIG_EDGENEITHER0; + else { + if (rising_edge & bitmask) lutbits |= OLS_ADV_TRIG_EDGERISE0; + if (falling_edge & bitmask) lutbits |= OLS_ADV_TRIG_EDGEFALL0; + } + bitmask >>= 1; + + if ((i & 1) == 0) + lutbits <<= 16; + else { + /* write total of 256 bits */ + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits)); + lutbits = 0; + } + } + + return SR_OK; +} + +static int ols_set_advanced_trigger_timer ( + struct sr_serial_dev_inst *serial, + int timersel, // 0 or 1 + uint64_t count_10ns) +{ + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, 0x38 + (timersel & 1) * 2)); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, count_10ns & 0xFFFFFFFF)); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, 0x39 + (timersel & 1) * 2)); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, count_10ns >> 32)); + return SR_OK; +} + +#define OLS_ADV_TRIG_STATETERM_HIT 0 +#define OLS_ADV_TRIG_STATETERM_ELSE 1 +#define OLS_ADV_TRIG_STATETERM_CAPTURE 2 + +#define OLS_ADV_TRIG_OP_NOP 0 +#define OLS_ADV_TRIG_OP_ANY 1 +#define OLS_ADV_TRIG_OP_AND 2 +#define OLS_ADV_TRIG_OP_NAND 3 +#define OLS_ADV_TRIG_OP_OR 4 +#define OLS_ADV_TRIG_OP_NOR 5 +#define OLS_ADV_TRIG_OP_XOR 6 +#define OLS_ADV_TRIG_OP_NXOR 7 +#define OLS_ADV_TRIG_OP_A 8 +#define OLS_ADV_TRIG_OP_B 9 +// NOP ANY AND NAND OR NOR XOR NXOR A B +static const uint32_t pairvalue[] = {0x0000, 0xFFFF, 0x8000, 0x7FFF, 0xF888, 0x0777, 0x7888, 0x8777, 0x8888, 0xF000}; +static const uint32_t midvalue[] = {0x0000, 0xFFFF, 0x8000, 0x7FFF, 0xFFFE, 0x0001, 0x0116, 0xFEE9, 0xEEEE, 0xFFF0}; +static const uint32_t finalvalue[] = {0x0000, 0xFFFF, 0x0008, 0x0007, 0x000E, 0x0001, 0x0006, 0x0009, 0x0002, 0x0004}; + +/* + * Trigger input summing stage: Combines different inputs in arbitrary ways. + * Keep in mind that all primary inputs (a, edge etc.) output a pair of bits per input. + * That's why those LUTs have 2 inputs, whereas the mid LUTs have 4 inputs. Only half + * of the final LUT is used. + */ +static int ols_set_advanced_trigger_sum( + struct sr_serial_dev_inst *serial, + int statenum, // 0-15 + int stateterm, // 0: hit, 1: else, 2: capture + int op_ab, + int op_c_range1, + int op_d_edge1, + int op_e_timer1, + int op_fg, + int op_h_range2, + int op_i_edge2, + int op_j_timer2, + int op_mid1, // sums up a, b, c, range1, d, edge1, e, timer1 + int op_mid2, // sums up f, g, h, range2, i, edge2, j, timer2 + int op_final) // sums up mid1, mid2 +{ + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, 0x40 + (statenum * 4) + stateterm)); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, finalvalue[op_final])); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, (midvalue[op_mid2] << 16) | midvalue[op_mid1])); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, (pairvalue[op_j_timer2] << 16) | pairvalue[op_i_edge2])); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, (pairvalue[op_h_range2] << 16) | pairvalue[op_fg])); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, (pairvalue[op_e_timer1] << 16) | pairvalue[op_d_edge1])); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, (pairvalue[op_c_range1] << 16) | pairvalue[op_ab])); + return SR_OK; +} + +#define TRIGSTATE_STATENUM_MASK 0xF +#define TRIGSTATE_OBTAIN_MASK 0x000FFFFF +#define TRIGSTATE_ELSE_BITOFS 20 +#define TRIGSTATE_STOLS_ADV_TRIG_OP_TIMER0 0x01000000 +#define TRIGSTATE_STOLS_ADV_TRIG_OP_TIMER1 0x02000000 +#define TRIGSTATE_CLEAR_TIMER0 0x04000000 +#define TRIGSTATE_CLEAR_TIMER1 0x08000000 +#define TRIGSTATE_START_TIMER0 0x10000000 +#define TRIGSTATE_START_TIMER1 0x20000000 +#define TRIGSTATE_TRIGGER_FLAG 0x40000000 +#define TRIGSTATE_LASTSTATE 0x80000000 + +static int ols_set_advanced_trigger_state( + struct sr_serial_dev_inst *serial, + uint8_t statenum, // 0 to 15 + gboolean last_state, + gboolean set_trigger, + uint8_t start_timer, // bit0=timer1, bit1=timer2 + uint8_t stop_timer, // bit0=timer1, bit1=timer2 + uint8_t clear_timer, // bit0=timer1, bit1=timer2 + uint8_t else_state, // 0 to 15 + uint32_t obtain_count) +{ + uint32_t value = + ((else_state & TRIGSTATE_STATENUM_MASK) << TRIGSTATE_ELSE_BITOFS) | + (obtain_count & TRIGSTATE_OBTAIN_MASK); + if (last_state) value |= TRIGSTATE_LASTSTATE; + if (set_trigger) value |= TRIGSTATE_TRIGGER_FLAG; + if (start_timer & 1) value |= TRIGSTATE_START_TIMER0; + if (start_timer & 2) value |= TRIGSTATE_START_TIMER1; + if (stop_timer & 1) value |= TRIGSTATE_STOLS_ADV_TRIG_OP_TIMER0; + if (stop_timer & 2) value |= TRIGSTATE_STOLS_ADV_TRIG_OP_TIMER1; + if (clear_timer & 1) value |= TRIGSTATE_CLEAR_TIMER0; + if (clear_timer & 2) value |= TRIGSTATE_CLEAR_TIMER1; + + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, statenum & TRIGSTATE_STATENUM_MASK)); + RETURN_ON_ERROR(ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, value)); + return SR_OK; +} + +static int ols_set_advanced_trigger_sums_and_stages( + struct sr_serial_dev_inst *serial, + int ols_stage, + int sum_inputs[8], + gboolean is_last_stage, + gboolean start_timer0) +{ + /* + * Hit only when all inputs are true. Always capture for pre-trigger and acquisition. + * Never execute the "Else" action, since we advance trigger stages implicity via hits. + */ + RETURN_ON_ERROR(ols_set_advanced_trigger_sum(serial, ols_stage, OLS_ADV_TRIG_STATETERM_HIT, + sum_inputs[0], sum_inputs[1], sum_inputs[2], sum_inputs[3], + sum_inputs[4], sum_inputs[5], sum_inputs[6], sum_inputs[7], + OLS_ADV_TRIG_OP_AND, OLS_ADV_TRIG_OP_AND, + OLS_ADV_TRIG_OP_AND)); + RETURN_ON_ERROR(ols_set_advanced_trigger_sum(serial, ols_stage, OLS_ADV_TRIG_STATETERM_CAPTURE, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_AND, OLS_ADV_TRIG_OP_AND, + OLS_ADV_TRIG_OP_ANY)); + RETURN_ON_ERROR(ols_set_advanced_trigger_sum(serial, ols_stage, OLS_ADV_TRIG_STATETERM_ELSE, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_AND, OLS_ADV_TRIG_OP_AND, + OLS_ADV_TRIG_OP_NOP)); + + /* + * Tell the state machine to move to the next stage on a hit by not + * setting the trigger flag. The last stage executes the trigger. + */ + RETURN_ON_ERROR(ols_set_advanced_trigger_state(serial, ols_stage, + is_last_stage, is_last_stage, start_timer0 ? 1 : 0, 0, 0, 0, 0)); + + return SR_OK; +} + +static int ols_convert_and_set_up_advanced_trigger(const struct sr_dev_inst *sdi, gboolean* will_trigger) { + struct sr_serial_dev_inst *serial = sdi->conn; + struct dev_context *devc = sdi->priv; + + int ols_stage = 0; + + if(devc->capture_ratio > 0) { + /* + * We need to set up a timer to ensure enough samples are captured to fulfill the + * pre-trigger ratio. In RLE mode, this is not necessarily true. It would be possible + * to wait longer, to ensure that enough compressed samples are captured, but this + * could take ages and is probably not what the user wants. + */ + + uint64_t effective_divider = devc->capture_flags & CAPTURE_FLAG_DEMUX + ? (devc->cur_samplerate_divider + 1) / 2 + : (devc->cur_samplerate_divider + 1); + uint64_t pretrigger_10ns_ticks = + devc->limit_samples * effective_divider * devc->capture_ratio / 100 /* percent */; + sr_dbg("Inserting pre-trigger delay of %" PRIu64 "0 ns", pretrigger_10ns_ticks); + + RETURN_ON_ERROR(ols_set_advanced_trigger_timer(serial, 0, pretrigger_10ns_ticks)); + + int sum_inputs[8] = { + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY + }; + + /* first stage: start timer, advance immediately to second stage */ + RETURN_ON_ERROR(ols_set_advanced_trigger_sums_and_stages( + serial, ols_stage++, sum_inputs, FALSE, TRUE)); + + /* second stage: wait until timer expires */ + sum_inputs[3] = OLS_ADV_TRIG_OP_B; + RETURN_ON_ERROR(ols_set_advanced_trigger_sums_and_stages( + serial, ols_stage++, sum_inputs, FALSE, TRUE)); + } + + struct sr_trigger *trigger; + if (!(trigger = sr_session_trigger_get(sdi->session))) { + *will_trigger = FALSE; + + /* Set up immediate trigger to capture and trigger regardless of any input. */ + int sum_inputs[8] = { + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY + }; + RETURN_ON_ERROR(ols_set_advanced_trigger_sums_and_stages( + serial, ols_stage, sum_inputs, TRUE, FALSE)); + return SR_OK; + } + + int num_req_trigger_stages = g_slist_length(trigger->stages); + if (ols_stage + num_req_trigger_stages > NUM_ADVANCED_TRIGGER_STAGES) { + sr_err("Too many trigger stages: %d requested + %d internal > %d available", + num_req_trigger_stages, ols_stage, NUM_ADVANCED_TRIGGER_STAGES); + return SR_ERR; + } + + sr_dbg("Setting OLS advanced trigger for %i stages", num_req_trigger_stages); + + const int last_stage = ols_stage + num_req_trigger_stages - 1; + int num_stages_with_level_trigger = 0; + int num_stages_with_edge_trigger = 0; + for (const GSList *l = trigger->stages; l; l = l->next) { + struct sr_trigger_stage *stage = l->data; + + // channel bit masks: + uint32_t level_mask = 0; + uint32_t level_value = 0; + uint32_t edge_rising = 0; + uint32_t edge_falling = 0; + + int current_level_term = -1; + int current_edge_term = -1; + + for (const GSList *m = stage->matches; m; m = m->next) { + struct sr_trigger_match *match = m->data; + if (!match->channel->enabled) + /* Ignore disabled channels with a trigger. */ + continue; + + int chan_bit = 1 << match->channel->index; + switch (match->match) { + case SR_TRIGGER_ZERO: + level_mask |= chan_bit; + break; + case SR_TRIGGER_ONE: + level_mask |= chan_bit; + level_value |= chan_bit; + break; + case SR_TRIGGER_RISING: + edge_rising |= chan_bit; + break; + case SR_TRIGGER_FALLING: + edge_falling |= chan_bit; + break; + case SR_TRIGGER_EDGE: + edge_rising |= chan_bit; + edge_falling |= chan_bit; + break; + default: + sr_err("Unsupported trigger type: %d", match->match); + return SR_ERR; + } + } + + if (level_mask) { + if(num_stages_with_level_trigger >= NUM_ADVANCED_LEVEL_TRIGGERS) { + sr_err("Too many level triggers, only %d supported.", + NUM_ADVANCED_LEVEL_TRIGGERS); + return SR_ERR; + } + + ols_set_advanced_level_trigger(serial, num_stages_with_level_trigger, level_value, level_mask); + current_level_term = num_stages_with_level_trigger; + ++num_stages_with_level_trigger; + } + + if (edge_rising | edge_falling) { + if(num_stages_with_edge_trigger >= NUM_ADVANCED_EDGE_TRIGGERS) { + sr_err("Too many edge triggers, only %d supported.", NUM_ADVANCED_EDGE_TRIGGERS); + return SR_ERR; + } + + ols_set_advanced_edge_trigger(serial, num_stages_with_edge_trigger, edge_rising, edge_falling, 0U); + current_edge_term = num_stages_with_edge_trigger; + ++num_stages_with_edge_trigger; + } + + gboolean is_last_stage = ols_stage == last_stage; + + /* map stage indices to the input pairs and pair position in the summing unit: */ + int sum_inputs[8] = { + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY + }; + #define A OLS_ADV_TRIG_OP_A + #define B OLS_ADV_TRIG_OP_B + static const int level_stage_to_input_pair[10] = {0, 0, 1, 2, 3, 4, 4, 5, 6, 7}; + static const int level_stage_to_input_ab[10] = {A, B, A, A, A, A, B, A, A, A}; + static const int edge_stage_to_input_pair[2] = {2, 6}; + #undef A + #undef B + + int level_summing_input = current_level_term >= 0 ? level_stage_to_input_pair[current_level_term] : -1 ; + int edge_summing_input = current_edge_term >= 0 ? edge_stage_to_input_pair[current_edge_term] : -1; + + if(level_summing_input >= 0) + sum_inputs[level_summing_input] = level_stage_to_input_ab[current_level_term]; + if(edge_summing_input >= 0) + sum_inputs[edge_summing_input] = OLS_ADV_TRIG_OP_B; + + /* If level and edge input end up in on the same input pair, and them together: */ + if(level_summing_input >= 0 && level_summing_input == edge_summing_input) + sum_inputs[level_summing_input] = OLS_ADV_TRIG_OP_AND; + + sr_spew(" Stage %d, lvl mask %.4x, edge %.4x, level term %d, edge term %d -> " + "trigger sum %.4X %.4X %.4X %.4X %.4X %.4X %.4X %.4X", + ols_stage, level_mask, (edge_falling | edge_rising), current_level_term, current_edge_term, + sum_inputs[0], sum_inputs[1], sum_inputs[2], sum_inputs[3], + sum_inputs[4], sum_inputs[5], sum_inputs[6], sum_inputs[7]); + + RETURN_ON_ERROR(ols_set_advanced_trigger_sums_and_stages( + serial, ols_stage, sum_inputs, is_last_stage, 0)); + + ++ols_stage; + } + + *will_trigger = ols_stage > 0 ? TRUE : FALSE; + return SR_OK; +} diff --git a/src/hardware/openbench-logic-sniffer/protocol.h b/src/hardware/openbench-logic-sniffer/protocol.h index 5f09e7e5f..5ac9a0fd5 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -28,10 +28,13 @@ #define LOG_PREFIX "openbench-logic-sniffer" -#define NUM_BASIC_TRIGGER_STAGES 4 -#define CLOCK_RATE SR_MHZ(100) -#define MIN_NUM_SAMPLES 4 -#define DEFAULT_SAMPLERATE SR_KHZ(200) +#define NUM_BASIC_TRIGGER_STAGES 4 +#define NUM_ADVANCED_TRIGGER_STAGES 15 +#define NUM_ADVANCED_EDGE_TRIGGERS 2 +#define NUM_ADVANCED_LEVEL_TRIGGERS 10 +#define CLOCK_RATE SR_MHZ(100) +#define MIN_NUM_SAMPLES 4 +#define DEFAULT_SAMPLERATE SR_KHZ(200) /* Command opcodes */ #define CMD_RESET 0x00 From b31d2ae474718e1f11831ef956a5d0d19fe8d4f8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 17 Jan 2021 19:32:39 +0100 Subject: [PATCH 28/29] ols: don't set invalid number of basic trigger stages If the number of basic triger stages is too large, it is still copied to the device struct. Use a temporary variable and populate the struct only if it is valid. --- src/hardware/openbench-logic-sniffer/protocol.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 4bdc7717f..d81df5577 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -122,7 +122,7 @@ static int ols_convert_basic_trigger(const struct sr_dev_inst *sdi, struct ols_b struct sr_trigger_stage *stage; struct sr_trigger_match *match; const GSList *l, *m; - int i; + int i, requested_num_stages; ols_trigger->num_stages = 0; for (i = 0; i < NUM_BASIC_TRIGGER_STAGES; i++) { @@ -133,13 +133,15 @@ static int ols_convert_basic_trigger(const struct sr_dev_inst *sdi, struct ols_b if (!(trigger = sr_session_trigger_get(sdi->session))) return SR_OK; - ols_trigger->num_stages = g_slist_length(trigger->stages); - if (ols_trigger->num_stages > NUM_BASIC_TRIGGER_STAGES) { + requested_num_stages = g_slist_length(trigger->stages); + if (requested_num_stages > NUM_BASIC_TRIGGER_STAGES) { sr_err("This device only supports %d trigger stages.", NUM_BASIC_TRIGGER_STAGES); return SR_ERR; } + ols_trigger->num_stages = requested_num_stages; + for (l = trigger->stages; l; l = l->next) { stage = l->data; for (m = stage->matches; m; m = m->next) { From 52c302db330ecd2d866fc37f4a134526703d818b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 17 Jan 2021 22:41:28 +0100 Subject: [PATCH 29/29] ols: use memset instead of for-loop More efficient but as readable. --- src/hardware/openbench-logic-sniffer/protocol.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index d81df5577..51c89ba17 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -122,13 +122,11 @@ static int ols_convert_basic_trigger(const struct sr_dev_inst *sdi, struct ols_b struct sr_trigger_stage *stage; struct sr_trigger_match *match; const GSList *l, *m; - int i, requested_num_stages; + int requested_num_stages; ols_trigger->num_stages = 0; - for (i = 0; i < NUM_BASIC_TRIGGER_STAGES; i++) { - ols_trigger->trigger_mask[i] = 0; - ols_trigger->trigger_value[i] = 0; - } + memset(ols_trigger->trigger_mask, 0, NUM_BASIC_TRIGGER_STAGES * sizeof(uint32_t)); + memset(ols_trigger->trigger_value, 0, NUM_BASIC_TRIGGER_STAGES * sizeof(uint32_t)); if (!(trigger = sr_session_trigger_get(sdi->session))) return SR_OK;