From 8ea06d643a9abc0d1edb37f47adeb46c72acc888 Mon Sep 17 00:00:00 2001 From: v1ne Date: Sat, 23 Jan 2021 22:50:10 +0100 Subject: [PATCH 01/20] ols: Clean up: Obey code style --- src/hardware/openbench-logic-sniffer/api.c | 44 +++-- .../openbench-logic-sniffer/protocol.c | 185 +++++++++++------- .../openbench-logic-sniffer/protocol.h | 16 +- 3 files changed, 152 insertions(+), 93 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 7a5f22011..c6a2cd2f4 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -48,9 +48,9 @@ static const int32_t trigger_matches[] = { SR_TRIGGER_ONE, }; -static const char* external_clock_edges[] = { - "rising", // positive edge - "falling" // negative edge +static const char *external_clock_edges[] = { + "rising", /* positive edge */ + "falling" /* negative edge */ }; #define STR_PATTERN_NONE "None" @@ -146,7 +146,8 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) return NULL; } - num_read = serial_read_blocking(serial, buf, 4, serial_timeout(serial, 4)); + num_read = + serial_read_blocking(serial, buf, 4, serial_timeout(serial, 4)); if (num_read < 0) { sr_err("Getting ID reply failed (%d).", num_read); return NULL; @@ -181,13 +182,13 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) sdi->version = g_strdup("v1.0"); for (i = 0; i < ARRAY_SIZE(ols_channel_names); i++) sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, - ols_channel_names[i]); + ols_channel_names[i]); sdi->priv = ols_dev_new(); } /* Configure samplerate and divider. */ if (ols_set_samplerate(sdi, DEFAULT_SAMPLERATE) != SR_OK) - sr_dbg("Failed to set default samplerate (%"PRIu64").", - DEFAULT_SAMPLERATE); + sr_dbg("Failed to set default samplerate (%" PRIu64 ").", + DEFAULT_SAMPLERATE); sdi->inst_type = SR_INST_SERIAL; sdi->conn = serial; @@ -197,7 +198,8 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) } static int config_get(uint32_t key, GVariant **data, - const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) + const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg) { struct dev_context *devc; @@ -227,15 +229,18 @@ static int config_get(uint32_t key, GVariant **data, *data = g_variant_new_string(STR_PATTERN_NONE); break; case SR_CONF_RLE: - *data = g_variant_new_boolean(devc->capture_flags & CAPTURE_FLAG_RLE ? TRUE : FALSE); + *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); + 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]); + devc->capture_flags & CAPTURE_FLAG_INVERT_EXT_CLOCK + ? 1 : 0]); break; default: return SR_ERR_NA; @@ -245,7 +250,8 @@ static int config_get(uint32_t key, GVariant **data, } static int config_set(uint32_t key, GVariant *data, - const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) + const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg) { struct dev_context *devc; uint16_t flag; @@ -334,7 +340,8 @@ 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) + const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg) { struct dev_context *devc; int num_ols_changrp, i; @@ -342,7 +349,8 @@ static int config_list(uint32_t key, GVariant **data, switch (key) { case SR_CONF_SCAN_OPTIONS: case SR_CONF_DEVICE_OPTIONS: - return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); + return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, + devopts); case SR_CONF_SAMPLERATE: *data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates)); break; @@ -375,8 +383,8 @@ static int config_list(uint32_t key, GVariant **data, num_ols_changrp++; } - *data = std_gvar_tuple_u64(MIN_NUM_SAMPLES, - (num_ols_changrp) ? devc->max_samples / num_ols_changrp : MIN_NUM_SAMPLES); + *data = std_gvar_tuple_u64(MIN_NUM_SAMPLES, (num_ols_changrp) + ? devc->max_samples / num_ols_changrp : MIN_NUM_SAMPLES); break; default: return SR_ERR_NA; @@ -413,8 +421,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, - ols_receive_data, (struct sr_dev_inst *)sdi); + serial_source_add(sdi->session, serial, G_IO_IN, 100, ols_receive_data, + (struct sr_dev_inst *)sdi); return SR_OK; } diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 9ac91982a..dbf291439 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -27,7 +27,7 @@ struct ols_basic_trigger_desc { }; SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial, - uint8_t command) + uint8_t command) { char buf[1]; @@ -42,13 +42,13 @@ SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial, return SR_OK; } -SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial, - uint8_t command, uint8_t *data) +SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial, uint8_t command, + uint8_t *data) { char buf[5]; - sr_dbg("Sending cmd 0x%.2x data 0x%.2x%.2x%.2x%.2x.", command, - data[0], data[1], data[2], data[3]); + sr_dbg("Sending cmd 0x%.2x data 0x%.2x%.2x%.2x%.2x.", command, data[0], + data[1], data[2], data[3]); buf[0] = command; buf[1] = data[0]; buf[2] = data[1]; @@ -63,8 +63,8 @@ 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) +static int ols_send_longdata(struct sr_serial_dev_inst *serial, uint8_t command, + uint32_t value) { uint8_t data[4]; WL32(data, value); @@ -96,7 +96,8 @@ 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 convert_trigger(const struct sr_dev_inst *sdi, + struct ols_basic_trigger_desc *ols_trigger) { struct sr_trigger *trigger; struct sr_trigger_stage *stage; @@ -116,7 +117,7 @@ static int convert_trigger(const struct sr_dev_inst *sdi, struct ols_basic_trigg 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_BASIC_TRIGGER_STAGES); + NUM_BASIC_TRIGGER_STAGES); return SR_ERR; } @@ -127,9 +128,11 @@ 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; + ols_trigger->trigger_mask[stage->stage] |= + 1 << match->channel->index; if (match->match == SR_TRIGGER_ONE) - ols_trigger->trigger_value[stage->stage] |= 1 << match->channel->index; + ols_trigger->trigger_value[stage->stage] |= + 1 << match->channel->index; } } @@ -153,7 +156,7 @@ static void ols_channel_new(struct sr_dev_inst *sdi, int num_chan) for (i = 0; i < num_chan; i++) sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, - ols_channel_names[i]); + ols_channel_names[i]); devc->max_channels = num_chan; } @@ -216,13 +219,17 @@ SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial) /* NULL-terminated string */ tmp_str = g_string_new(""); delay_ms = serial_timeout(serial, 1); - while (serial_read_blocking(serial, &tmp_c, 1, delay_ms) == 1 && tmp_c != '\0') + while (serial_read_blocking(serial, &tmp_c, 1, + delay_ms) == 1 && + tmp_c != '\0') g_string_append_c(tmp_str, tmp_c); - sr_dbg("Got metadata token 0x%.2x value '%s'.", key, tmp_str->str); + sr_dbg("Got metadata token 0x%.2x value '%s'.", key, + tmp_str->str); switch (key) { case METADATA_TOKEN_DEVICE_NAME: /* Device name */ - devname = g_string_append(devname, tmp_str->str); + devname = + g_string_append(devname, tmp_str->str); break; case METADATA_TOKEN_FPGA_VERSION: /* FPGA firmware version */ @@ -239,7 +246,8 @@ SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial) g_string_append(version, tmp_str->str); break; default: - sr_info("ols: unknown token 0x%.2x: '%s'", key, tmp_str->str); + sr_info("ols: unknown token 0x%.2x: '%s'", key, + tmp_str->str); break; } g_string_free(tmp_str, TRUE); @@ -247,10 +255,12 @@ SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial) case 1: /* 32-bit unsigned integer */ delay_ms = serial_timeout(serial, 4); - if (serial_read_blocking(serial, &tmp_int, 4, delay_ms) != 4) + if (serial_read_blocking(serial, &tmp_int, 4, + delay_ms) != 4) break; tmp_int = RB32(&tmp_int); - sr_dbg("Got metadata token 0x%.2x value 0x%.8x.", key, tmp_int); + sr_dbg("Got metadata token 0x%.2x value 0x%.8x.", key, + tmp_int); switch (key) { case METADATA_TOKEN_NUM_PROBES_LONG: /* Number of usable channels */ @@ -273,7 +283,8 @@ SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial) devc->protocol_version = tmp_int; break; default: - sr_info("Unknown token 0x%.2x: 0x%.8x.", key, tmp_int); + sr_info("Unknown token 0x%.2x: 0x%.8x.", key, + tmp_int); break; } break; @@ -282,7 +293,8 @@ SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial) delay_ms = serial_timeout(serial, 1); if (serial_read_blocking(serial, &tmp_c, 1, delay_ms) != 1) break; - sr_dbg("Got metadata token 0x%.2x value 0x%.2x.", key, tmp_c); + sr_dbg("Got metadata token 0x%.2x value 0x%.2x.", key, + tmp_c); switch (key) { case METADATA_TOKEN_NUM_PROBES_SHORT: /* Number of usable channels */ @@ -293,7 +305,8 @@ SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial) devc->protocol_version = tmp_c; break; default: - sr_info("Unknown token 0x%.2x: 0x%.2x.", key, tmp_c); + sr_info("Unknown token 0x%.2x: 0x%.2x.", key, + tmp_c); break; } break; @@ -315,7 +328,7 @@ 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, - const uint64_t samplerate) + const uint64_t samplerate) { struct dev_context *devc; @@ -327,7 +340,8 @@ SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi, sr_info("Enabling demux mode."); devc->capture_flags |= CAPTURE_FLAG_DEMUX; devc->capture_flags &= ~CAPTURE_FLAG_NOISE_FILTER; - devc->cur_samplerate_divider = (CLOCK_RATE * 2 / samplerate) - 1; + devc->cur_samplerate_divider = + (CLOCK_RATE * 2 / samplerate) - 1; } else { sr_info("Disabling demux mode."); devc->capture_flags &= ~CAPTURE_FLAG_DEMUX; @@ -342,8 +356,9 @@ SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi, if (devc->capture_flags & CAPTURE_FLAG_DEMUX) devc->cur_samplerate *= 2; if (devc->cur_samplerate != samplerate) - sr_info("Can't match samplerate %" PRIu64 ", using %" - PRIu64 ".", samplerate, devc->cur_samplerate); + sr_info("Can't match samplerate %" PRIu64 ", using %" PRIu64 + ".", + samplerate, devc->cur_samplerate); return SR_OK; } @@ -418,9 +433,11 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * 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->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); if (devc->capture_flags & CAPTURE_FLAG_RLE) { /* * In RLE mode the high bit of the sample is the @@ -429,10 +446,13 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) */ if (devc->sample[devc->num_bytes - 1] & 0x80) { /* Clear the high bit. */ - sample &= ~(0x80 << (devc->num_bytes - 1) * 8); + sample &= ~(0x80 << (devc->num_bytes - + 1) * 8); devc->rle_count = sample; - devc->cnt_samples_rle += devc->rle_count; - sr_dbg("RLE count: %u.", devc->rle_count); + devc->cnt_samples_rle += + devc->rle_count; + sr_dbg("RLE count: %u.", + devc->rle_count); devc->num_bytes = 0; return TRUE; } @@ -440,7 +460,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) 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->rle_count -= + devc->num_samples - devc->limit_samples; devc->num_samples = devc->limit_samples; } @@ -457,21 +478,27 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) j = 0; memset(devc->tmp_sample, 0, 4); for (i = 0; i < 4; i++) { - if (((devc->capture_flags >> 2) & (1 << i)) == 0) { + if (((devc->capture_flags >> 2) & + (1 << i)) == 0) { /* * This channel group was * enabled, copy from received * sample. */ - devc->tmp_sample[i] = devc->sample[j++]; - } else if (devc->capture_flags & CAPTURE_FLAG_DEMUX && (i > 2)) { + devc->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++]; + devc->tmp_sample[i - 2] = + devc->sample[j++]; } } memcpy(devc->sample, devc->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->sample[3], devc->sample[2], + devc->sample[1], devc->sample[0]); } /* @@ -495,8 +522,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * 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); + devc->cnt_bytes, devc->cnt_samples, + devc->cnt_samples_rle); if (devc->trigger_at_smpl != OLS_NO_TRIGGER) { /* * A trigger was set up, so we need to tell the frontend @@ -509,7 +536,9 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) logic.length = devc->trigger_at_smpl * 4; logic.unitsize = 4; logic.data = devc->raw_sample_buf + - (devc->limit_samples - devc->num_samples) * 4; + (devc->limit_samples - + devc->num_samples) * + 4; sr_session_send(sdi, &packet); } @@ -518,14 +547,19 @@ 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; + 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.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 + devc->limit_samples - + devc->num_samples) * + 4; sr_session_send(sdi, &packet); g_free(devc->raw_sample_buf); @@ -537,7 +571,9 @@ 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) +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]; @@ -561,7 +597,8 @@ static int ols_set_basic_trigger_stage(const struct ols_basic_trigger_desc *trig return SR_OK; } -SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { +SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) +{ int ret; struct dev_context *devc = sdi->priv; @@ -581,7 +618,8 @@ 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. */ - uint32_t samplecount = MIN(devc->max_samples / num_changroups, devc->limit_samples); + uint32_t samplecount = + MIN(devc->max_samples / num_changroups, devc->limit_samples); uint32_t readcount = (samplecount + 3) / 4; uint32_t delaycount; @@ -601,53 +639,66 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { return SR_ERR; 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 - + 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) + 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) + 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); - if (ols_send_longdata(serial, CMD_SET_DIVIDER, devc->cur_samplerate_divider & 0x00FFFFFF) != SR_OK) + 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; /* 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); + (readcount - 1) * 4, (delaycount - 1) * 4); if (devc->max_samples > 256 * 1024) { - if (ols_send_longdata(serial, CMD_CAPTURE_READCOUNT, readcount-1) != SR_OK) + 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) + if (ols_send_longdata(serial, CMD_CAPTURE_DELAYCOUNT, + delaycount - 1) != SR_OK) return SR_ERR; } else { uint8_t arg[4]; - WL16(&arg[0], readcount-1); - WL16(&arg[2], delaycount-1); + WL16(&arg[0], readcount - 1); + WL16(&arg[2], delaycount - 1); 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") : ""); + 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 diff --git a/src/hardware/openbench-logic-sniffer/protocol.h b/src/hardware/openbench-logic-sniffer/protocol.h index 6b8c2422b..612b069f6 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -28,10 +28,10 @@ #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 CLOCK_RATE SR_MHZ(100) +#define MIN_NUM_SAMPLES 4 +#define DEFAULT_SAMPLERATE SR_KHZ(200) /* Command opcodes */ #define CMD_RESET 0x00 @@ -130,16 +130,16 @@ struct dev_context { SR_PRIV extern const char *ols_channel_names[]; SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial, - uint8_t command); -SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial, - uint8_t command, uint8_t *data); + uint8_t command); +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 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, - uint64_t samplerate); + uint64_t samplerate); SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi); SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data); From e5dc9e60b2c862bd60370b7c83f7035d85bfd545 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:32 +0100 Subject: [PATCH 02/20] 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 c6a2cd2f4..426d253a7 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -367,8 +367,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 86bf1d51ff8c7581de9aa05db903a451416f8c30 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:33 +0100 Subject: [PATCH 03/20] 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 dbf291439..bf065c760 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -476,7 +476,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) { @@ -485,17 +485,17 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * enabled, copy from received * sample. */ - devc->tmp_sample[i] = + 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] = + 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 612b069f6..01a382136 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 fd87a596b5ff6889c18410641dfa44c431c55337 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:33 +0100 Subject: [PATCH 04/20] ols: Don't silently ignore error when setting up the device --- src/hardware/openbench-logic-sniffer/api.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 426d253a7..788d4b809 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -419,10 +419,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, ols_receive_data, - (struct sr_dev_inst *)sdi); - - return SR_OK; + return serial_source_add(sdi->session, serial, G_IO_IN, 100, + ols_receive_data, (struct sr_dev_inst *)sdi); } static int dev_acquisition_stop(struct sr_dev_inst *sdi) From 23f90476cf99cfed548bf72df871650a6819c82f Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:33 +0100 Subject: [PATCH 05/20] 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 | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index bf065c760..68022a1c6 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -487,12 +487,6 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) */ 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 b3ef78e4e64d03601a944a21f53f20b308d79e73 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:34 +0100 Subject: [PATCH 06/20] 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 68022a1c6..c747753ab 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -582,7 +582,7 @@ ols_set_basic_trigger_stage(const struct ols_basic_trigger_desc *trigger_desc, 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; if (send_longcommand(serial, cmd, arg) != SR_OK) @@ -635,7 +635,7 @@ 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); if ((ret = ols_set_basic_trigger_stage( &basic_trigger_desc, serial, i)) != SR_OK) @@ -644,6 +644,7 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) } else { /* No triggers configured, force trigger on first stage. */ sr_dbg("Forcing trigger at stage 0."); + basic_trigger_desc.num_stages = 1; if ((ret = ols_set_basic_trigger_stage(&basic_trigger_desc, serial, 0)) != SR_OK) return ret; From 6621a2257979bae30a055d577633ac32decb1ad6 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:34 +0100 Subject: [PATCH 07/20] 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 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index c747753ab..0215a6fa2 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -633,8 +633,7 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) return SR_ERR; 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); if ((ret = ols_set_basic_trigger_stage( From c67f08794300af7b156b0944b66eb411b2ff2ca1 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:34 +0100 Subject: [PATCH 08/20] 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 | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 0215a6fa2..319c82ed3 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -383,7 +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, offset, j; + int num_changroups, j; unsigned int i; unsigned char byte; @@ -427,6 +427,8 @@ 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_changroups) { + unsigned int samples_to_write; + devc->cnt_samples++; devc->cnt_samples_rle++; /* @@ -457,13 +459,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) { /* @@ -495,16 +490,14 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) 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), + 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; @@ -518,6 +511,23 @@ 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 f05c0409b6272248c9ab119b079b2da17c4b6c62 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:34 +0100 Subject: [PATCH 09/20] 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 | 53 ++++++++++--------- .../openbench-logic-sniffer/protocol.h | 2 +- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 788d4b809..da13d10f3 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -409,7 +409,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 319c82ed3..1af66cf3a 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -393,21 +393,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) { @@ -415,19 +405,15 @@ 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) { - unsigned int samples_to_write; + unsigned int samples_to_write, new_sample_buf_size; devc->cnt_samples++; devc->cnt_samples_rle++; @@ -491,6 +477,28 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) } samples_to_write = devc->rle_count + 1; + 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, @@ -539,10 +547,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); } @@ -560,13 +565,11 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) 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 01a382136..2be90d5f4 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 84d6e002f785344fc97dc9a39ee5c3d1622f8f22 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:35 +0100 Subject: [PATCH 10/20] 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 | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 1af66cf3a..9617623a0 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -511,6 +511,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) devc->rle_count = 0; } } else { + unsigned int num_pre_trigger_samples; + /* * This is the main loop telling us a timeout was reached, or * we've acquired all the samples we asked for -- we're done. @@ -541,7 +543,9 @@ 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; @@ -556,17 +560,22 @@ 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); + 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 72fae1a0493a1d06602e1b40aa12cc5d227ce167 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:35 +0100 Subject: [PATCH 11/20] 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 | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 9617623a0..ba4d1ffc9 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -73,14 +73,28 @@ static int ols_send_longdata(struct sr_serial_dev_inst *serial, uint8_t command, SR_PRIV int ols_send_reset(struct sr_serial_dev_inst *serial) { - unsigned int i; + int i, ret, delay_ms; + 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++) { - if (send_shortcommand(serial, CMD_RESET) != SR_OK) - return SR_ERR; + if ((ret = send_shortcommand(serial, CMD_RESET)) != SR_OK) + return ret; } - 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. + */ + 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. */ @@ -365,13 +379,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 7fc0db42a8d0fed146b06e255cd34fbbfe048d82 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:35 +0100 Subject: [PATCH 12/20] 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 | 115 +++++++++--------- .../openbench-logic-sniffer/protocol.h | 16 +-- 3 files changed, 69 insertions(+), 70 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index da13d10f3..f11f911bc 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -409,10 +409,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 ba4d1ffc9..01fe3926c 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -395,8 +395,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; @@ -405,7 +404,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; } @@ -420,40 +419,40 @@ 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) { + if (devc->raw_sample_size == num_changroups) { unsigned int samples_to_write, new_sample_buf_size; - devc->cnt_samples++; - devc->cnt_samples_rle++; + 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; } } @@ -479,47 +478,47 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * sample. */ tmp_sample[i] = - devc->sample[j++]; + 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]); } samples_to_write = devc->rle_count + 1; new_sample_buf_size = 4 * MAX(devc->limit_samples, - devc->num_samples + samples_to_write); + devc->cnt_samples + samples_to_write); - if (devc->raw_sample_buf_size < new_sample_buf_size) { - unsigned int old_size = - devc->raw_sample_buf_size; + 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, + 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 { @@ -530,23 +529,23 @@ 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)], + 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->raw_sample_buf[4 * (devc->num_samples - - i - 1)], + memcpy(&devc->sample_buf[4 * + (devc->cnt_samples - i - 1)], temp, 4); } @@ -557,13 +556,13 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) */ if (devc->trigger_at_smpl > 0 && (unsigned int)devc->trigger_at_smpl <= - devc->num_samples) { + 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); } @@ -576,21 +575,21 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) 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) { + 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) * + (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 2be90d5f4..73b55c090 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -114,16 +114,16 @@ 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 3a39f134c87f47cad65f40f9cc50f469de0db0a6 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:35 +0100 Subject: [PATCH 13/20] 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 f11f911bc..3f686538a 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -409,7 +409,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 01fe3926c..1e38af447 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -590,6 +590,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 05e39c52cc2e70ebbf519f23b346670e9aa88a75 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:36 +0100 Subject: [PATCH 14/20] 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 | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 1e38af447..5c23a50ef 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -628,6 +628,7 @@ ols_set_basic_trigger_stage(const struct ols_basic_trigger_desc *trigger_desc, SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { int ret; + uint32_t readcount, delaycount; struct dev_context *devc = sdi->priv; struct sr_serial_dev_inst *serial = sdi->conn; @@ -643,13 +644,13 @@ 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; - uint32_t delaycount; + devc->limit_samples = + (MIN(devc->max_samples / num_changroups, devc->limit_samples) + 3) + / 4 * 4; + readcount = devc->limit_samples / 4; /* Basic triggers. */ struct ols_basic_trigger_desc basic_trigger_desc; From 1a2437b4c82c261c0ef4031bf62e686425eda456 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:36 +0100 Subject: [PATCH 15/20] 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 | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 3f686538a..322cab895 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -417,9 +417,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 5c23a50ef..7d8bb27f2 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -453,7 +453,12 @@ 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; - 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; } } @@ -521,9 +526,16 @@ 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) { unsigned int num_pre_trigger_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 e068d80d04e4e5b72e88575cafc17c317ee9d361 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:36 +0100 Subject: [PATCH 16/20] 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 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 7d8bb27f2..b3b118a08 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -397,6 +397,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; @@ -416,9 +417,10 @@ 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; @@ -527,6 +529,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 || From fadfd5e1729375f868a8f5275d7e830ffb657d64 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:36 +0100 Subject: [PATCH 17/20] 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 b3b118a08..98e8f0606 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -395,8 +395,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; @@ -419,12 +419,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) { + (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) { unsigned int samples_to_write, new_sample_buf_size; From e58ecb2ff3aa9740ce93451cb79640083f22768b Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:37 +0100 Subject: [PATCH 18/20] 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 | 49 ++++++++++++++++++- .../openbench-logic-sniffer/protocol.h | 1 + 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 322cab895..b3f486f3e 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -410,6 +410,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 98e8f0606..64089fd93 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; } @@ -462,6 +463,15 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) 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. @@ -523,6 +533,15 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) 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, @@ -555,6 +574,19 @@ 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. @@ -649,7 +681,7 @@ ols_set_basic_trigger_stage(const struct ols_basic_trigger_desc *trigger_desc, SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) { - int ret; + int ret, trigger_point; uint32_t readcount, delaycount; struct dev_context *devc = sdi->priv; @@ -673,6 +705,7 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) (MIN(devc->max_samples / num_changroups, devc->limit_samples) + 3) / 4 * 4; readcount = devc->limit_samples / 4; + trigger_point = OLS_NO_TRIGGER; /* Basic triggers. */ struct ols_basic_trigger_desc basic_trigger_desc; @@ -690,7 +723,7 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) return SR_ERR; 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); if ((ret = ols_set_basic_trigger_stage( @@ -707,6 +740,18 @@ 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 73b55c090..76c307f6d 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 6af1de20452171d728c024d42afb363f1cb4448c Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:37 +0100 Subject: [PATCH 19/20] 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 | 37 +++++++++++++------ .../openbench-logic-sniffer/protocol.h | 4 +- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 64089fd93..27e4ac492 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -397,7 +397,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; @@ -412,7 +412,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++; } @@ -433,7 +433,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) devc->raw_sample_size); if (devc->raw_sample_size == num_changroups) { - unsigned int samples_to_write, new_sample_buf_size; + unsigned int samples_to_write; + uint64_t new_sample_buf_size; devc->cnt_rx_raw_samples++; /* @@ -458,8 +459,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) sample &= ~(0x80 << (devc->raw_sample_size - 1) * 8); - devc->rle_count = sample; - sr_dbg("RLE count: %u.", + devc->rle_count += sample; + sr_dbg("RLE count: %" PRIu64, devc->rle_count); devc->raw_sample_size = 0; @@ -490,9 +491,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) { /* @@ -518,7 +519,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) 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); @@ -542,7 +543,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) 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); @@ -570,7 +571,8 @@ 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); @@ -591,7 +593,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], @@ -803,7 +805,18 @@ 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); if (ols_send_longdata(serial, CMD_SET_FLAGS, devc->capture_flags) != SR_OK) return SR_ERR; diff --git a/src/hardware/openbench-logic-sniffer/protocol.h b/src/hardware/openbench-logic-sniffer/protocol.h index 76c307f6d..dd7a5d7d4 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -121,10 +121,10 @@ struct dev_context { 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 5696a4dbc1962d99d57c911282e122ca25c135b9 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:37 +0100 Subject: [PATCH 20/20] 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 | 27 +- .../openbench-logic-sniffer/protocol.c | 638 +++++++++++++++++- .../openbench-logic-sniffer/protocol.h | 3 + 3 files changed, 631 insertions(+), 37 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index b3f486f3e..e78ff5d82 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 */ @@ -343,7 +351,7 @@ 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) { @@ -355,7 +363,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)); @@ -364,9 +377,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; @@ -405,7 +417,10 @@ 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 27e4ac492..df34c690e 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 @@ -26,6 +27,10 @@ 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) { @@ -110,8 +115,8 @@ 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; @@ -142,11 +147,21 @@ static int convert_trigger(const struct sr_dev_inst *sdi, 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; + } } } @@ -380,12 +395,18 @@ SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi, SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi) { + int ret; struct sr_serial_dev_inst *serial = sdi->conn; ols_send_reset(serial); - serial_source_remove(sdi->session, serial); - std_session_send_df_end(sdi); + 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) @@ -689,6 +710,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"); + if ((ret = ols_send_reset(serial)) != SR_OK) + return ret; + int num_changroups = 0; uint8_t changroup_mask = 0; uint32_t channel_mask = ols_channel_mask(sdi); @@ -709,37 +738,51 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) readcount = devc->limit_samples / 4; 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"); - if (ols_send_reset(serial) != SR_OK) + 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; - - 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); + } + 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); + ret = ols_set_basic_trigger_stage( + &basic_trigger_desc, serial, i); + if (ret != SR_OK) + return ret; + } + } else { + /* No triggers configured, force trigger on first stage. */ + sr_dbg("Forcing trigger at stage 0."); + basic_trigger_desc.num_stages = 1; if ((ret = ols_set_basic_trigger_stage( - &basic_trigger_desc, serial, i)) != SR_OK) + &basic_trigger_desc, serial, 0)) != SR_OK) return ret; + + delaycount = readcount; } } else { - /* No triggers configured, force trigger on first stage. */ - sr_dbg("Forcing trigger at stage 0."); - basic_trigger_desc.num_stages = 1; - if ((ret = ols_set_basic_trigger_stage(&basic_trigger_desc, - serial, 0)) != SR_OK) - return ret; - 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; } /* @@ -823,3 +866,536 @@ 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) +{ + int ret; + 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; + } + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, 0x20 + (num_trigger_term % 10)); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits[3]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits[2]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits[1]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits[0]); + if (ret != SR_OK) + return ret; + + 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) +{ + int ret; + uint32_t lutbits = 0; + uint32_t bitmask = 0x80000000; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, + 0x34 + (edgesel & 1)); + if (ret != SR_OK) + return ret; + + 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 */ + ret = ols_send_longdata( + serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits); + if (ret != SR_OK) + return ret; + 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) +{ + int ret; + + ret = ols_send_longdata( + serial, CMD_SET_ADVANCED_TRIG_SEL, 0x38 + (timersel & 1) * 2); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata( + serial, CMD_SET_ADVANCED_TRIG_WRITE, count_10ns & 0xFFFFFFFF); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata( + serial, CMD_SET_ADVANCED_TRIG_SEL, 0x39 + (timersel & 1) * 2); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata( + serial, CMD_SET_ADVANCED_TRIG_WRITE, count_10ns >> 32); + if (ret != SR_OK) + return ret; + + 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 */ +{ + int ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, + 0x40 + (statenum * 4) + stateterm); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, + finalvalue[op_final]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, + (midvalue[op_mid2] << 16) | midvalue[op_mid1]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, + (pairvalue[op_j_timer2] << 16) | pairvalue[op_i_edge2]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, + (pairvalue[op_h_range2] << 16) | pairvalue[op_fg]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, + (pairvalue[op_e_timer1] << 16) | pairvalue[op_d_edge1]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, + (pairvalue[op_c_range1] << 16) | pairvalue[op_ab]); + if (ret != SR_OK) + return ret; + + 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) +{ + int ret; + + 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; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, + statenum & TRIGSTATE_STATENUM_MASK); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, value); + if (ret != SR_OK) + return ret; + + 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) +{ + int ret; + + /* + * 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. + */ + ret = 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); + if (ret != SR_OK) + return ret; + + ret = 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); + if (ret != SR_OK) + return ret; + + ret = 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); + if (ret != SR_OK) + return ret; + + /* + * 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. + */ + ret = ols_set_advanced_trigger_state(serial, ols_stage, is_last_stage, + is_last_stage, + start_timer0 ? 1 : 0, 0, 0, 0, 0); + if (ret != SR_OK) + return ret; + + return SR_OK; +} + +static int +ols_convert_and_set_up_advanced_trigger(const struct sr_dev_inst *sdi, + gboolean *will_trigger) +{ + int ret; + + 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); + + if ((ret = ols_set_advanced_trigger_timer( + serial, 0, pretrigger_10ns_ticks)) != SR_OK) + return ret; + + 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 */ + if ((ret = ols_set_advanced_trigger_sums_and_stages( + serial, ols_stage++, sum_inputs, FALSE, TRUE)) != SR_OK) + return ret; + + /* second stage: wait until timer expires */ + sum_inputs[3] = OLS_ADV_TRIG_OP_B; + if ((ret = ols_set_advanced_trigger_sums_and_stages( + serial, ols_stage++, sum_inputs, FALSE, TRUE)) != SR_OK) + return ret; + } + + 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 ols_set_advanced_trigger_sums_and_stages( + serial, ols_stage, sum_inputs, TRUE, FALSE); + } + + 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]); + + ret = ols_set_advanced_trigger_sums_and_stages( + serial, ols_stage, sum_inputs, is_last_stage, 0); + if (ret != SR_OK) + return ret; + + ++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 dd7a5d7d4..f96afd39d 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -29,6 +29,9 @@ #define LOG_PREFIX "openbench-logic-sniffer" #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)