From 34416b8d5e247b9771e21622a163a4d81525b49a Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:34 +0100 Subject: [PATCH 01/12] 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 e97a7c9f0..4e81afc57 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -615,8 +615,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 30be2e8cb73c280255fae914297c1c03feeba8e2 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:34 +0100 Subject: [PATCH 02/12] 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, 26 insertions(+), 18 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 4e81afc57..b0c299de4 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -362,7 +362,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; @@ -406,6 +406,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++; /* @@ -436,13 +438,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) { /* @@ -476,17 +471,15 @@ 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. - * Here cropping to devc->unitsize happens - */ - offset = (devc->limit_samples - devc->num_samples) * devc->unitsize; - for (i = 0; i <= devc->rle_count; i++) { - memcpy(devc->raw_sample_buf + offset + (i * devc->unitsize), + /* Here cropping to devc->unitsize happens */ + samples_to_write = devc->rle_count + 1; + for (i = 0; i < samples_to_write; i++) + memcpy(devc->raw_sample_buf + + (devc->num_samples + i) * devc->unitsize, devc->sample, devc->unitsize); - } + + devc->num_samples += samples_to_write; + memset(devc->sample, 0, 4); devc->num_bytes = 0; devc->rle_count = 0; @@ -500,6 +493,21 @@ 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[devc->unitsize]; + memcpy(temp, &devc->raw_sample_buf[devc->unitsize * i], devc->unitsize); + memmove(&devc->raw_sample_buf[devc->unitsize * i], + &devc->raw_sample_buf[devc->unitsize * (devc->num_samples - i - 1)], + devc->unitsize); + memcpy(&devc->raw_sample_buf[devc->unitsize * (devc->num_samples - i - 1)], + temp, devc->unitsize); + } + if (devc->trigger_at_smpl != OLS_NO_TRIGGER) { /* * A trigger was set up, so we need to tell the frontend From 9c5325c9a3ac8ea3de7ed2ed7a2f0e4368d694a5 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:34 +0100 Subject: [PATCH 03/12] 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 | 56 ++++++++++--------- .../openbench-logic-sniffer/protocol.h | 2 +- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 988a157ab..0ae5ee67e 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -457,7 +457,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 b0c299de4..bcb160551 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -372,21 +372,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) { @@ -394,19 +384,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++; @@ -473,6 +459,27 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) /* Here cropping to devc->unitsize happens */ samples_to_write = devc->rle_count + 1; + new_sample_buf_size = devc->unitsize * + 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, 0xAA, + new_sample_buf_size - old_size); + } + for (i = 0; i < samples_to_write; i++) memcpy(devc->raw_sample_buf + (devc->num_samples + i) * devc->unitsize, @@ -519,10 +526,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) packet.payload = &logic; logic.length = devc->trigger_at_smpl * devc->unitsize; logic.unitsize = devc->unitsize; - logic.data = devc->raw_sample_buf + - (devc->limit_samples - - devc->num_samples) * - devc->unitsize; + logic.data = devc->raw_sample_buf; sr_session_send(sdi, &packet); } @@ -538,15 +542,13 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = - (devc->num_samples - num_pre_trigger_samples) * devc->unitsize; - logic.unitsize = devc->unitsize; - logic.data = devc->raw_sample_buf + - (num_pre_trigger_samples + devc->limit_samples - - devc->num_samples) * - devc->unitsize; + (devc->num_samples - num_pre_trigger_samples) * devc->unit_size; + logic.unitsize = devc->unit_size; + logic.data = devc->raw_sample_buf + num_pre_trigger_samples * devc->unit_size; 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 652ee8d18..1f1d1c920 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -116,7 +116,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; @@ -126,6 +125,7 @@ struct dev_context { unsigned int rle_count; unsigned char sample[4]; unsigned char *raw_sample_buf; + unsigned int raw_sample_buf_size; uint16_t unitsize; }; From 28a1173c9e28358e913b42056c7a012af203fec0 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:35 +0100 Subject: [PATCH 04/12] 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 bcb160551..8cc3f6190 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -492,6 +492,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. @@ -520,7 +522,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; @@ -535,17 +539,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) * devc->unit_size; - logic.unitsize = devc->unit_size; - logic.data = devc->raw_sample_buf + num_pre_trigger_samples * devc->unit_size; - 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) * + devc->unitsize; + logic.unitsize = devc->unitsize; + logic.data = devc->raw_sample_buf + + num_pre_trigger_samples * devc->unitsize; + sr_session_send(sdi, &packet); + } g_free(devc->raw_sample_buf); devc->raw_sample_buf = 0; From a16adc745605d6623aba4e6b147f5c9389a56df2 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:35 +0100 Subject: [PATCH 05/12] 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. --- .../openbench-logic-sniffer/protocol.c | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 8cc3f6190..c1e737a40 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -73,14 +73,30 @@ 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. */ @@ -344,13 +360,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 a19dd413708b82168544dffcd921dc33fb5e39ce Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:35 +0100 Subject: [PATCH 06/12] 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 | 111 +++++++++--------- .../openbench-logic-sniffer/protocol.h | 16 +-- 3 files changed, 67 insertions(+), 68 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 0ae5ee67e..c15abc275 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -457,10 +457,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 c1e737a40..ac17f5d37 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -376,8 +376,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; @@ -386,7 +385,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; } @@ -401,40 +400,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; } } @@ -462,47 +461,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]); } /* Here cropping to devc->unitsize happens */ samples_to_write = devc->rle_count + 1; new_sample_buf_size = devc->unitsize * - MAX(devc->limit_samples, devc->num_samples + samples_to_write); + MAX(devc->limit_samples, 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, 0xAA, + memset(devc->sample_buf + old_size, 0xAA, new_sample_buf_size - old_size); } for (i = 0; i < samples_to_write; i++) - memcpy(devc->raw_sample_buf + - (devc->num_samples + i) * devc->unitsize, - devc->sample, devc->unitsize); + memcpy(devc->sample_buf + + (devc->cnt_samples + i) * devc->unitsize, + devc->raw_sample, devc->unitsize); - 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 { @@ -513,21 +512,21 @@ 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[devc->unitsize]; - memcpy(temp, &devc->raw_sample_buf[devc->unitsize * i], devc->unitsize); - memmove(&devc->raw_sample_buf[devc->unitsize * i], - &devc->raw_sample_buf[devc->unitsize * (devc->num_samples - i - 1)], + memcpy(temp, &devc->sample_buf[devc->unitsize * i], devc->unitsize); + memmove(&devc->sample_buf[devc->unitsize * i], + &devc->sample_buf[devc->unitsize * (devc->cnt_samples - i - 1)], devc->unitsize); - memcpy(&devc->raw_sample_buf[devc->unitsize * (devc->num_samples - i - 1)], + memcpy(&devc->sample_buf[devc->unitsize * (devc->cnt_samples - i - 1)], temp, devc->unitsize); } @@ -538,13 +537,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 * devc->unitsize; logic.unitsize = devc->unitsize; - logic.data = devc->raw_sample_buf; + logic.data = devc->sample_buf; sr_session_send(sdi, &packet); } @@ -557,21 +556,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) * devc->unitsize; logic.unitsize = devc->unitsize; - logic.data = devc->raw_sample_buf + - num_pre_trigger_samples * devc->unitsize; + logic.data = + devc->sample_buf + num_pre_trigger_samples * devc->unitsize; 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 1f1d1c920..6cfc6dae6 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -116,16 +116,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 raw_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 */ uint16_t unitsize; }; From c9d78a05e362a8a5768318c454330a04890fb5d8 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:35 +0100 Subject: [PATCH 07/12] ols: Clean up: Always keep sample_buf_size up to date Previously, sample_buf_size was reset at a different time than the sample buffer itself. Reset both at the same time for consistency. --- 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 c15abc275..1edd90f6e 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -457,7 +457,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 ac17f5d37..4888e65a8 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -571,6 +571,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 d62827bb1e78c10bdaa37aa83c76add4e2d0c333 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:36 +0100 Subject: [PATCH 08/12] 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 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 4888e65a8..6c47748e1 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -609,6 +609,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; @@ -624,13 +625,12 @@ 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; + uint32_t exact_samplecount = MIN(devc->max_samples / num_changroups, devc->limit_samples); + devc->limit_samples = (exact_samplecount + 3) / 4 * 4; + readcount = devc->limit_samples / 4; /* Basic triggers. */ struct ols_basic_trigger_desc basic_trigger_desc; From edb566ab030b1bb038c9ce75d55da978a588e9a5 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:36 +0100 Subject: [PATCH 09/12] 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 1edd90f6e..9a7d4af0a 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -465,9 +465,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 6c47748e1..736c1a7ea 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -434,7 +434,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; } } @@ -504,9 +509,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 bc8ea796ebfc55b921b7db115a4ffe8d1cbb8609 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:36 +0100 Subject: [PATCH 10/12] 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 736c1a7ea..b03591cc0 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -378,6 +378,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; @@ -397,9 +398,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; @@ -510,6 +512,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 62fc69055de324df673862e4d11c091fb8e8632a Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:36 +0100 Subject: [PATCH 11/12] ols: Capture multiple bytes at once Why just read a single byte when you can read a whole sample? --- .../openbench-logic-sniffer/protocol.c | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index b03591cc0..f9784beda 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -376,8 +376,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, bytes_left_to_read; unsigned int i, j, num_changroups; - unsigned char byte; gboolean received_a_byte; (void)fd; @@ -399,13 +399,21 @@ 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) { + bytes_left_to_read = 64 * 1024; /* in this function call; give event loop a chance to run, too */ + while (revents == G_IO_IN && bytes_left_to_read >= 0 && + (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; + bytes_left_to_read -= 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 d62c909f2e1f592d354af6e738b6abce7185d054 Mon Sep 17 00:00:00 2001 From: v1ne Date: Tue, 23 Feb 2021 22:36:37 +0100 Subject: [PATCH 12/12] 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 | 2 + .../openbench-logic-sniffer/protocol.c | 43 ++++++++++++++++++- .../openbench-logic-sniffer/protocol.h | 2 + 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 9a7d4af0a..043c08551 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -191,6 +191,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) devc = g_malloc0(sizeof(*devc)); sdi->priv = devc; devc->trigger_at_smpl = OLS_NO_TRIGGER; + devc->trigger_rle_at_smpl_from_end = OLS_NO_TRIGGER; devc->channel_names = sr_parse_probe_names(probe_names, ols_channel_names, ARRAY_SIZE(ols_channel_names), ARRAY_SIZE(ols_channel_names), &ch_max); @@ -458,6 +459,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 f9784beda..6bbbd5977 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -368,6 +368,14 @@ SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi) std_session_send_df_end(sdi); } +SR_PRIV void set_rle_trigger_point_if_unset(struct dev_context *devc) +{ + 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; +} + SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) { struct dev_context *devc; @@ -445,6 +453,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) devc->rle_count); devc->raw_sample_size = 0; + set_rle_trigger_point_if_unset(devc); + /* * Even on the rare occasion that the sampling ends with an RLE message, * the acquisition should end immediately, without any timeout. @@ -508,6 +518,9 @@ 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) + set_rle_trigger_point_if_unset(devc); + for (i = 0; i < samples_to_write; i++) memcpy(devc->sample_buf + (devc->cnt_samples + i) * devc->unitsize, @@ -540,6 +553,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. @@ -632,7 +658,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; @@ -655,6 +681,7 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) uint32_t exact_samplecount = MIN(devc->max_samples / num_changroups, devc->limit_samples); devc->limit_samples = (exact_samplecount + 3) / 4 * 4; readcount = devc->limit_samples / 4; + trigger_point = OLS_NO_TRIGGER; /* Basic triggers. */ struct ols_basic_trigger_desc basic_trigger_desc; @@ -672,7 +699,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( @@ -689,6 +716,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 6cfc6dae6..dd7ae422b 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -114,6 +114,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 */ @@ -143,6 +144,7 @@ SR_PRIV int ols_get_metadata(struct sr_dev_inst *sdi); SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate); SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi); +SR_PRIV void set_rle_trigger_point_if_unset(struct dev_context *devc); SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data); #endif