From 75d830a778cf99767e9f55d529ac6320993b1c16 Mon Sep 17 00:00:00 2001
From: profezzorn <hubbe@hubbe.net>
Date: Mon, 31 Jan 2022 19:07:18 -0800
Subject: [PATCH 01/13] fix read32 byte order

---
 Software/libthunderscopehw/library/thunderscopehw_internals.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Software/libthunderscopehw/library/thunderscopehw_internals.c b/Software/libthunderscopehw/library/thunderscopehw_internals.c
index 2a0ed246..2547ca6f 100644
--- a/Software/libthunderscopehw/library/thunderscopehw_internals.c
+++ b/Software/libthunderscopehw/library/thunderscopehw_internals.c
@@ -210,7 +210,7 @@ uint32_t thunderscopehw_read32(struct ThunderScopeHW* ts, size_t addr)
 {
 	uint8_t bytes[4];
 	thunderscopehw_read_handle(ts, ts->user_handle, bytes, addr, 4);
-	return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
+	return (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
 }
 
 enum ThunderScopeHWStatus thunderscopehw_write32(struct ThunderScopeHW* ts, size_t addr, uint32_t value)

From 61120acf3043ac8e16f60178d0fab203d59a05a2 Mon Sep 17 00:00:00 2001
From: Aleksa <abjelogr@uwaterloo.ca>
Date: Mon, 31 Jan 2022 22:40:17 -0500
Subject: [PATCH 02/13] Changed FIFO_ISR Value to use uppermost byte

---
 Software/libthunderscopehw/library/thunderscopehw_internals.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Software/libthunderscopehw/library/thunderscopehw_internals.c b/Software/libthunderscopehw/library/thunderscopehw_internals.c
index 2547ca6f..6e1af1d6 100644
--- a/Software/libthunderscopehw/library/thunderscopehw_internals.c
+++ b/Software/libthunderscopehw/library/thunderscopehw_internals.c
@@ -37,7 +37,7 @@ enum ThunderScopeHWStatus thunderscopehw_fifo_write(struct ThunderScopeHW* ts, u
 	// write to TLR (the size of the packet)
 	THUNDERSCOPEHW_RUN(write32(ts, SERIAL_FIFO_TLR_ADDRESS, (uint32_t)(bytes * 4)));
 	// read ISR for a done value
-	while ((thunderscopehw_read32(ts, SERIAL_FIFO_ISR_ADDRESS) & 0xff) != 8) {
+	while ((thunderscopehw_read32(ts, SERIAL_FIFO_ISR_ADDRESS) >> 24) != 8) {
 #ifdef WIN32
 		Sleep(1);
 #else

From 79acd473eed02e7cd5caac6d9aa8d70f2b125c51 Mon Sep 17 00:00:00 2001
From: profezzorn <hubbe@hubbe.net>
Date: Mon, 31 Jan 2022 22:57:56 -0800
Subject: [PATCH 03/13] several bugfixes, now getting ramp data

---
 .../thunderscopehwdump/thunderscopehwdump.c      | 16 +++++++++-------
 .../libthunderscopehw/library/thunderscopehw.c   |  3 +--
 .../library/thunderscopehw_internals.c           |  7 ++++++-
 3 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
index 3d6c493a..00967ab4 100644
--- a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
+++ b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
@@ -82,7 +82,8 @@ int mygetopt(int argc, char** argv) {
 	       optind++;
 	       return options[i].return_value;
 	}
-	return -1;
+	fprintf(stderr, "Unknown option: %s\n", argv[optind]);
+	exit(1);
 }
 
 int main(int argc, char** argv) {
@@ -252,22 +253,23 @@ int main(int argc, char** argv) {
 		exit(1);
 	}
 
+#define BUFFER_SIZE (1<<20)
 	uint8_t* buffer;
 #ifdef _WIN32
-        buffer = _aligned_malloc(1 << 20, 4096);
-#else	
-	posix_memalign((void**)&buffer, 4096, 1 << 20);
+        buffer = _aligned_malloc(BUFFER_SIZE, 4096);
+#else
+	posix_memalign((void**)&buffer, 4096, BUFFER_SIZE);
 #endif
 
 	while (samples) {
 		int64_t to_copy = samples;
-		if (to_copy > sizeof(buffer)) to_copy = sizeof(buffer);
-		ret = thunderscopehw_read(ts, buffer, sizeof(buffer));
+		if (to_copy > BUFFER_SIZE) to_copy = BUFFER_SIZE;
+		ret = thunderscopehw_read(ts, buffer, to_copy);
 		if (ret != THUNDERSCOPEHW_STATUS_OK) {
 			fprintf(stderr, "Thunderscope read error, error = %s\n", thunderscopehw_describe_error(ret));
 			exit(1);
 		}
-		if (fwrite(buffer, 1, sizeof(buffer), outfile) != sizeof(buffer)) {
+		if (fwrite(buffer, 1, to_copy, outfile) != to_copy) {
 			perror("fwrite");
 			exit(1);
 		}
diff --git a/Software/libthunderscopehw/library/thunderscopehw.c b/Software/libthunderscopehw/library/thunderscopehw.c
index 2764d026..da0fb62a 100644
--- a/Software/libthunderscopehw/library/thunderscopehw.c
+++ b/Software/libthunderscopehw/library/thunderscopehw.c
@@ -119,7 +119,6 @@ static enum ThunderScopeHWStatus thunderscopehw_update_buffer_head(struct Thunde
 
 	uint32_t overflow_cycles = (transfer_counter >> 16) & 0x3FFF;
 	if (overflow_cycles) {
-		fprintf(stderr, "TRANSFER COUNTER = %llx\n", (long long)transfer_counter);
 		return THUNDERSCOPEHW_STATUS_PIPELINE_OVERFLOW;
 	}
 
@@ -168,7 +167,7 @@ enum ThunderScopeHWStatus thunderscopehw_read(struct ThunderScopeHW* ts, uint8_t
 		if (pages_to_read > ts->ram_size_pages - buffer_read_pos) pages_to_read = ts->ram_size_pages - buffer_read_pos;
 		if (pages_to_read > ts->ram_size_pages / 4) pages_to_read = ts->ram_size_pages / 4;
 
-		thunderscopehw_read_handle(ts, ts->user_handle, data, buffer_read_pos << 12, pages_to_read << 12);
+		THUNDERSCOPEHW_RUN(read_handle(ts, ts->c2h0_handle, data, buffer_read_pos << 12, pages_to_read << 12));
 
 		data += pages_to_read << 12;
 		length -= pages_to_read << 12;
diff --git a/Software/libthunderscopehw/library/thunderscopehw_internals.c b/Software/libthunderscopehw/library/thunderscopehw_internals.c
index 6e1af1d6..eab907e6 100644
--- a/Software/libthunderscopehw/library/thunderscopehw_internals.c
+++ b/Software/libthunderscopehw/library/thunderscopehw_internals.c
@@ -1,6 +1,8 @@
 #include "thunderscopehw_private.h"
 
 #include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 #ifdef WIN32
 #else
@@ -209,7 +211,10 @@ enum ThunderScopeHWStatus thunderscopehw_configure_channel(struct ThunderScopeHW
 uint32_t thunderscopehw_read32(struct ThunderScopeHW* ts, size_t addr)
 {
 	uint8_t bytes[4];
-	thunderscopehw_read_handle(ts, ts->user_handle, bytes, addr, 4);
+	if (thunderscopehw_read_handle(ts, ts->user_handle, bytes, addr, 4) != THUNDERSCOPEHW_STATUS_OK) {
+		fprintf(stderr, "Error in thunderscopehw_read32\n");
+		exit(1);
+	}
 	return (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
 }
 

From 06c0310e37a98a4d535c0fba0e3e94f981c63996 Mon Sep 17 00:00:00 2001
From: Aleksa <abjelogr@uwaterloo.ca>
Date: Tue, 1 Feb 2022 22:16:09 -0500
Subject: [PATCH 04/13] Fix return value on windows read_handle function

---
 Software/libthunderscopehw/library/thunderscopehw_win.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Software/libthunderscopehw/library/thunderscopehw_win.c b/Software/libthunderscopehw/library/thunderscopehw_win.c
index e8a9ff68..187887cb 100644
--- a/Software/libthunderscopehw/library/thunderscopehw_win.c
+++ b/Software/libthunderscopehw/library/thunderscopehw_win.c
@@ -153,7 +153,7 @@ enum ThunderScopeHWStatus thunderscopehw_read_handle(struct ThunderScopeHW* ts,
 		fprintf(stderr, "read handle failed, win32 error code: %d\n", GetLastError());
 		return THUNDERSCOPEHW_STATUS_READ_ERROR;
 	}
-	return true;
+	return THUNDERSCOPEHW_STATUS_OK;
 }
 
 enum ThunderScopeHWStatus thunderscopehw_write_handle(struct ThunderScopeHW* ts, HANDLE h, uint8_t* data, uint64_t addr, int64_t bytes)

From 91a88f978e06e75f974459b4ef4958b3343b2bf9 Mon Sep 17 00:00:00 2001
From: Aleksa <abjelogr@uwaterloo.ca>
Date: Sun, 6 Feb 2022 14:15:34 -0500
Subject: [PATCH 05/13] Some register fixes, still stalls on read with
 ThunderScope board though

---
 Software/libthunderscopehw/library/thunderscopehw_adc.c     | 2 +-
 Software/libthunderscopehw/library/thunderscopehw_private.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Software/libthunderscopehw/library/thunderscopehw_adc.c b/Software/libthunderscopehw/library/thunderscopehw_adc.c
index 89ea7803..03709be8 100644
--- a/Software/libthunderscopehw/library/thunderscopehw_adc.c
+++ b/Software/libthunderscopehw/library/thunderscopehw_adc.c
@@ -25,7 +25,7 @@ enum ThunderScopeHWStatus thunderscopehw_configure_adc(struct ThunderScopeHW* ts
 	THUNDERSCOPEHW_RUN(adc_power(ts, false));
 
 	// invert channels
-	THUNDERSCOPEHW_RUN(adc_set_reg(ts, THUNDERSCOPEHW_ADC_REG_INVERT, 0x0074));
+	THUNDERSCOPEHW_RUN(adc_set_reg(ts, THUNDERSCOPEHW_ADC_REG_INVERT, 0x007F));
 
 	// Adjust full scale value
 	THUNDERSCOPEHW_RUN(adc_set_reg(ts, THUNDERSCOPEHW_ADC_REG_FS_CNTRL, 0x0010));
diff --git a/Software/libthunderscopehw/library/thunderscopehw_private.h b/Software/libthunderscopehw/library/thunderscopehw_private.h
index 4820a0df..4de3a98a 100644
--- a/Software/libthunderscopehw/library/thunderscopehw_private.h
+++ b/Software/libthunderscopehw/library/thunderscopehw_private.h
@@ -102,7 +102,7 @@ enum ThunderScopeHWAdcRegister {
 	THUNDERSCOPEHW_ADC_REG_CHNUM_CLKDIV = 0x31,
 	THUNDERSCOPEHW_ADC_REG_GAIN_CFG = 0x33,
 	THUNDERSCOPEHW_ADC_REG_INSEL12 = 0x3A,
-	THUNDERSCOPEHW_ADC_REG_INSEL34 = 0x3A,
+	THUNDERSCOPEHW_ADC_REG_INSEL34 = 0x3B,
 	THUNDERSCOPEHW_ADC_REG_FS_CNTRL = 0x55,
 };
 enum ThunderScopeHWStatus thunderscopehw_adc_set_reg(struct ThunderScopeHW* ts, enum ThunderScopeHWAdcRegister reg, uint16_t value);

From 3d89cb41f1199df0614c9869e4b373be669dad73 Mon Sep 17 00:00:00 2001
From: profezzorn <hubbe@hubbe.net>
Date: Sun, 6 Feb 2022 19:18:13 -0800
Subject: [PATCH 06/13] adc bugfixes

---
 Software/libthunderscopehw/library/thunderscopehw_adc.c     | 2 +-
 Software/libthunderscopehw/library/thunderscopehw_private.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Software/libthunderscopehw/library/thunderscopehw_adc.c b/Software/libthunderscopehw/library/thunderscopehw_adc.c
index 03709be8..308f36d2 100644
--- a/Software/libthunderscopehw/library/thunderscopehw_adc.c
+++ b/Software/libthunderscopehw/library/thunderscopehw_adc.c
@@ -14,7 +14,7 @@ enum ThunderScopeHWStatus thunderscopehw_adc_power(struct ThunderScopeHW* ts, bo
 {
 	return thunderscopehw_adc_set_reg(ts,
 					THUNDERSCOPEHW_ADC_REG_POWER,
-					on ? 0x0200 : 0x0000);
+					on ? 0x0000 : 0x0200);
 }
 
 enum ThunderScopeHWStatus thunderscopehw_configure_adc(struct ThunderScopeHW* ts)
diff --git a/Software/libthunderscopehw/library/thunderscopehw_private.h b/Software/libthunderscopehw/library/thunderscopehw_private.h
index 4de3a98a..612aae7c 100644
--- a/Software/libthunderscopehw/library/thunderscopehw_private.h
+++ b/Software/libthunderscopehw/library/thunderscopehw_private.h
@@ -33,7 +33,7 @@
 #define SPI_FRONT_END_CHANNEL_3             0xFA
 #define SPI_FRONT_END_CHANNEL_4             0xFB
 
-#define SPI_BYTE_ADC                        0xFC
+#define SPI_BYTE_ADC                        0xFD
 
 #define I2C_BYTE_PLL                        0xFF
 

From ff6df7e2ea729a9fd284e890204da14a4fc8db7e Mon Sep 17 00:00:00 2001
From: profezzorn <hubbe@hubbe.net>
Date: Sun, 6 Feb 2022 21:58:24 -0800
Subject: [PATCH 07/13] invert relay

---
 Software/libthunderscopehw/library/thunderscopehw_internals.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/Software/libthunderscopehw/library/thunderscopehw_internals.c b/Software/libthunderscopehw/library/thunderscopehw_internals.c
index eab907e6..e03eb1df 100644
--- a/Software/libthunderscopehw/library/thunderscopehw_internals.c
+++ b/Software/libthunderscopehw/library/thunderscopehw_internals.c
@@ -65,19 +65,17 @@ enum ThunderScopeHWStatus thunderscopehw_set_datamover_reg(struct ThunderScopeHW
 	if (ts->datamover_en)  datamover_reg |= 0x1;
 	if (ts->fpga_adc_en)  datamover_reg |= 0x2;
 
-#if 1
 	for (int channel = 0; channel < 4; channel++) {
 		if (ts->channels[channel].on == true) {
 			num_channels_on++;
 		}
-		if (ts->channels[channel].vdiv > 100) {
+		if (ts->channels[channel].vdiv <= 100) {
 			datamover_reg |= 1 << (16 + channel);
 		}
 		if (ts->channels[channel].coupling == THUNDERSCOPEHW_COUPLING_DC) {
 			datamover_reg |= 1 << (20 + channel);
 		}
 	}
-#endif
 	switch (num_channels_on) {
 	case 0:
 	case 1: break; // do nothing

From dd17422182d36c3e48faa58ade3234183dbfe2cf Mon Sep 17 00:00:00 2001
From: profezzorn <hubbe@hubbe.net>
Date: Sun, 6 Feb 2022 22:12:21 -0800
Subject: [PATCH 08/13] convert signed bytes to unsigned bytes since 8-bit wav
 files are unsigned

---
 .../examples/thunderscopehwdump/thunderscopehwdump.c          | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
index 00967ab4..4bfe6b38 100644
--- a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
+++ b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
@@ -269,6 +269,10 @@ int main(int argc, char** argv) {
 			fprintf(stderr, "Thunderscope read error, error = %s\n", thunderscopehw_describe_error(ret));
 			exit(1);
 		}
+		// Convert signed output to unsigned output
+		for (size_t i = 0; i < BUFFER_SIZE; i++) {
+			buffer[i] += 0x80;
+		}
 		if (fwrite(buffer, 1, to_copy, outfile) != to_copy) {
 			perror("fwrite");
 			exit(1);

From 454052c05046766ba690a0eb57e99adb3fa6b21a Mon Sep 17 00:00:00 2001
From: profezzorn <hubbe@hubbe.net>
Date: Sun, 13 Feb 2022 01:04:00 -0800
Subject: [PATCH 09/13] start calibration program

---
 Software/libthunderscopehw/CMakeLists.txt     |   1 +
 .../thunderscopehwcalibrate/CMakeLists.txt    |   4 +
 .../thunderscopehwcalibrate.c                 | 150 ++++++++++++++++++
 .../thunderscopehwdump/thunderscopehwdump.c   |  77 +++++----
 .../include/thunderscopehw.h                  |   2 +
 .../library/thunderscopehw.c                  |   6 +
 .../library/thunderscopehw_internals.c        |   9 +-
 7 files changed, 214 insertions(+), 35 deletions(-)
 create mode 100644 Software/libthunderscopehw/examples/thunderscopehwcalibrate/CMakeLists.txt
 create mode 100644 Software/libthunderscopehw/examples/thunderscopehwcalibrate/thunderscopehwcalibrate.c

diff --git a/Software/libthunderscopehw/CMakeLists.txt b/Software/libthunderscopehw/CMakeLists.txt
index 546ecaa4..0890d133 100644
--- a/Software/libthunderscopehw/CMakeLists.txt
+++ b/Software/libthunderscopehw/CMakeLists.txt
@@ -6,6 +6,7 @@ project(thunderscopehwlib VERSION ${PROJECT_VERSION})
 
 add_subdirectory(library)
 add_subdirectory(examples/thunderscopehwdump)
+add_subdirectory(examples/thunderscopehwcalibrate)
 
 enable_testing()
 add_subdirectory(test)
diff --git a/Software/libthunderscopehw/examples/thunderscopehwcalibrate/CMakeLists.txt b/Software/libthunderscopehw/examples/thunderscopehwcalibrate/CMakeLists.txt
new file mode 100644
index 00000000..f168201c
--- /dev/null
+++ b/Software/libthunderscopehw/examples/thunderscopehwcalibrate/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_executable(thunderscopehwcalibrate
+	thunderscopehwcalibrate.c)
+target_link_libraries(thunderscopehwcalibrate
+	thunderscopehwlib)
diff --git a/Software/libthunderscopehw/examples/thunderscopehwcalibrate/thunderscopehwcalibrate.c b/Software/libthunderscopehw/examples/thunderscopehwcalibrate/thunderscopehwcalibrate.c
new file mode 100644
index 00000000..7976afe9
--- /dev/null
+++ b/Software/libthunderscopehw/examples/thunderscopehwcalibrate/thunderscopehwcalibrate.c
@@ -0,0 +1,150 @@
+#include "thunderscopehw.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
+struct Option {
+        const char* name;
+        bool needs_argument;
+        int return_value;
+};
+
+struct Option options[] = {
+	{"device",             true,  1 },
+};
+
+#define TS_RUN(X) do {							\
+	enum ThunderScopeHWStatus ret = thunderscopehw_##X;		\
+        if (ret != THUNDERSCOPEHW_STATUS_OK) {				\
+		fprintf(stderr, "thunderscope_%s failed @ line %d, error = %s\n", #X, __LINE__, thunderscopehw_describe_error(ret)); \
+		exit(1);						\
+	}								\
+} while(0)
+
+char* optarg;
+int optind = 1;
+int mygetopt(int argc, char** argv) {
+        if (optind >= argc) return -1;
+	if (!argv[optind][0] == '-' || argv[optind][1] != '-') return -1;
+	char *arg = strchr(argv[optind], '=');
+	for (size_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
+               size_t len = strlen(options[i].name);
+	       if (strncmp(options[i].name, argv[optind] + 2, len)) continue;
+	       if (options[i].needs_argument) {
+	               if (!arg) continue;
+	               if (argv[optind] + 2 + len != arg) continue;
+		       optarg = arg + 1;
+	       } else {
+	               if (arg) continue;
+		       if (argv[optind][2 + len]) continue;
+		       optarg = NULL;
+	       }
+	       optind++;
+	       return options[i].return_value;
+	}
+	fprintf(stderr, "Unknown option: %s\n", argv[optind]);
+	exit(1);
+}
+
+int main(int argc, char** argv) {
+	uint64_t scope_id = 0;
+	uint64_t samples = 0;
+	int samplerate = 0;
+	while (1) {
+		switch (mygetopt(argc, argv)) {
+		case 1:
+			if (!sscanf(optarg, "%" PRIx64, &scope_id)) {
+			         fprintf(stderr, "Scope ID must be hexadecimal.\n");
+			         exit(1);
+			}
+			continue;
+		default:
+			continue;
+		case -1:
+			break;
+		}
+		break;
+	}
+
+	if (scope_id == 0) {
+		uint64_t scope_ids[32];
+		int scopes = thunderscopehw_scan(scope_ids, 32);
+		if (scopes == 0) {
+			fprintf(stderr, "No thunderscopehw hardware found.\n");
+			exit(1);
+		}
+		if (scopes > 1) {
+			fprintf(stderr, "Multiple scopes found, please select one with --device.\n");
+			for (int i = 0; i < scopes; i++) {
+				fprintf(stderr, "  %0" PRIx64 "\n", scope_ids[i]);
+			}
+			exit(1);
+		}
+		scope_id = scope_ids[0];
+	}
+
+#define BUFFER_SIZE (1<<20)
+	uint8_t* buffer;
+#ifdef _WIN32
+        buffer = _aligned_malloc(BUFFER_SIZE, 4096);
+#else
+	posix_memalign((void**)&buffer, 4096, BUFFER_SIZE);
+#endif
+
+	struct ThunderScopeHW *ts = thunderscopehw_create();
+	enum ThunderScopeHWStatus ret;
+	TS_RUN(connect(ts, scope_id));
+
+	for (int channel = 0; channel < 4; channel++) {
+		TS_RUN(enable_channel(ts, channel));
+		// 1mV / div
+		TS_RUN(voltage_division_set(ts, channel, 1));
+#ifdef WIN32
+		Sleep(500);
+#else
+		usleep(500000);
+#endif
+
+		double minoffset = -0.5;
+		double maxoffset = 0.5;
+
+		for (int i =0; i < 1000; i++) {
+			for (int j = 0; j < 20; j++) {
+				double midoffset = (minoffset + maxoffset) / 2;
+				TS_RUN(voltage_offset_set(ts, channel, midoffset));
+				TS_RUN(start(ts));
+				TS_RUN(read(ts, buffer, BUFFER_SIZE));
+				// Convert signed output to unsigned output
+				for (size_t i = 0; i < BUFFER_SIZE; i++) {
+					buffer[i] += 0x80;
+				}
+				TS_RUN(stop(ts));
+				int high = 0;
+				int low = 0;
+				uint64_t sum = 0;
+				for (size_t i = 0; i < BUFFER_SIZE; i++) {
+					if (buffer[i] > 0x80) high++;
+					if (buffer[i] < 0x80) low++;
+					sum += buffer[i];
+				}
+//			fprintf(stderr," min = %8.4f  max = %8.4f  mid = %8.4f  high=%d low=%d avg=%f\n",
+//				minoffset, maxoffset, midoffset,
+//				high, low,
+//				sum / (double)BUFFER_SIZE);
+				if (high > low) {
+					minoffset = midoffset;
+				} else {
+					maxoffset = midoffset;
+				}
+			}
+			printf("Channel %d calibration = %f\n", channel + 1, (minoffset + maxoffset) / 2);
+		}
+		TS_RUN(disable_channel(ts, channel));
+	}
+}
diff --git a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
index 4bfe6b38..94869fa7 100644
--- a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
+++ b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
@@ -21,44 +21,45 @@ struct Option {
 };
 
 struct Option options[] = {
-	{"device",      true,  1 },
-	{"samples",     true,  2 },
+	{"device",             true,  1 },
+	{"samples",            true,  2 },
+	{"output-samplerate",  true,  3 },
 
-	{"bw-all",      true,  0x10 },
-	{"bw1",         true,  0x11 },
-	{"bw2",         true,  0x12 },
-	{"bw3",         true,  0x13 },
-	{"bw4",         true,  0x14 },
+	{"bw-all",             true,  0x10 },
+	{"bw1",                true,  0x11 },
+	{"bw2",                true,  0x12 },
+	{"bw3",                true,  0x13 },
+	{"bw4",                true,  0x14 },
 
-	{"vdiv-all",    true,  0x20 },
-	{"vdiv1",       true,  0x21 },
-	{"vdiv2",       true,  0x22 },
-	{"vdiv3",       true,  0x23 },
-	{"vdiv4",       true,  0x24 },
+	{"vdiv-all",           true,  0x20 },
+	{"vdiv1",              true,  0x21 },
+	{"vdiv2",              true,  0x22 },
+	{"vdiv3",              true,  0x23 },
+	{"vdiv4",              true,  0x24 },
 
-	{"voffset-all", true,  0x30 },
-	{"voffset1",    true,  0x31 },
-	{"voffset2",    true,  0x32 },
-	{"voffset3",    true,  0x33 },
-	{"voffset4",    true,  0x34 },
+	{"voffset-all",        true,  0x30 },
+	{"voffset1",           true,  0x31 },
+	{"voffset2",           true,  0x32 },
+	{"voffset3",           true,  0x33 },
+	{"voffset4",           true,  0x34 },
 
-	{"ac-all",      false, 0x40 },
-	{"ac1",         false, 0x41 },
-	{"ac2",         false, 0x42 },
-	{"ac3",         false, 0x43 },
-	{"ac4",         false, 0x44 },
+	{"ac-all",             false, 0x40 },
+	{"ac1",                false, 0x41 },
+	{"ac2",                false, 0x42 },
+	{"ac3",                false, 0x43 },
+	{"ac4",                false, 0x44 },
 
-	{"dc-all",      false, 0x50 },
-	{"ac1",         false, 0x51 },
-	{"ac2",         false, 0x52 },
-	{"ac3",         false, 0x53 },
-	{"ac4",         false, 0x54 },
+	{"dc-all",             false, 0x50 },
+	{"ac1",                false, 0x51 },
+	{"ac2",                false, 0x52 },
+	{"ac3",                false, 0x53 },
+	{"ac4",                false, 0x54 },
 
-	{"enable-all",  false, 0x60 },
-	{"enable1",     false, 0x61 },
-	{"enable2",     false, 0x62 },
-	{"enable3",     false, 0x63 },
-	{"enable4",     false, 0x64 },
+	{"enable-all",         false, 0x60 },
+	{"enable1",            false, 0x61 },
+	{"enable2",            false, 0x62 },
+	{"enable3",            false, 0x63 },
+	{"enable4",            false, 0x64 },
 };
 
 char* optarg;
@@ -89,6 +90,7 @@ int mygetopt(int argc, char** argv) {
 int main(int argc, char** argv) {
 	uint64_t scope_id = 0;
 	uint64_t samples = 0;
+	int samplerate = 0;
 	while (1) {
 		switch (mygetopt(argc, argv)) {
 		case 1:
@@ -102,6 +104,11 @@ int main(int argc, char** argv) {
 			        fprintf(stderr, "Number of samples must be a number.\n");
 				exit(1);
 			}
+		case 3:
+			if (!sscanf(optarg, "%d", &samplerate)) {
+			        fprintf(stderr, "Output samplerate must be a number.\n");
+				exit(1);
+			}
 		default:
 			continue;
 		case -1:
@@ -232,7 +239,11 @@ int main(int argc, char** argv) {
 	struct Fmt fmt;
 	fmt.pcm = 1;
 	fmt.channels = num_channels;
-	fmt.rate = 1000000000 / fmt.channels;
+	if (samplerate) {
+		fmt.rate = samplerate;
+	} else {
+		fmt.rate = 1000000000 / fmt.channels;
+	}
 	fmt.byterate = 1000000000;
 	fmt.block_align = 0;
 	fmt.bits_per_sample = 8;
diff --git a/Software/libthunderscopehw/include/thunderscopehw.h b/Software/libthunderscopehw/include/thunderscopehw.h
index e214666c..9f6225f8 100644
--- a/Software/libthunderscopehw/include/thunderscopehw.h
+++ b/Software/libthunderscopehw/include/thunderscopehw.h
@@ -25,6 +25,8 @@ enum ThunderScopeHWStatus {
 	THUNDERSCOPEHW_STATUS_ALREADY_STARTED,
 	THUNDERSCOPEHW_STATUS_NOT_STARTED,
 	THUNDERSCOPEHW_STATUS_ALREADY_STOPPED,
+	THUNDERSCOPEHW_STATUS_OFFSET_TOO_LOW,
+	THUNDERSCOPEHW_STATUS_OFFSET_TOO_HIGH,
 };
 
 // Return's number of scopes.
diff --git a/Software/libthunderscopehw/library/thunderscopehw.c b/Software/libthunderscopehw/library/thunderscopehw.c
index da0fb62a..4bbd50da 100644
--- a/Software/libthunderscopehw/library/thunderscopehw.c
+++ b/Software/libthunderscopehw/library/thunderscopehw.c
@@ -93,6 +93,8 @@ enum ThunderScopeHWStatus thunderscopehw_start(struct ThunderScopeHW* ts) {
 		return THUNDERSCOPEHW_STATUS_ALREADY_STARTED;
 	ts->datamover_en = true;
 	ts->fpga_adc_en = true;
+	ts->buffer_head = 0;
+	ts->buffer_tail = 0;
 	return thunderscopehw_set_datamover_reg(ts);
 }
 
@@ -220,6 +222,10 @@ const char* thunderscopehw_describe_error(enum ThunderScopeHWStatus err) {
 		return "not started";
 	case THUNDERSCOPEHW_STATUS_ALREADY_STOPPED:
 		return "already stopped";
+	case THUNDERSCOPEHW_STATUS_OFFSET_TOO_LOW:
+		return "voffset too low";
+	case THUNDERSCOPEHW_STATUS_OFFSET_TOO_HIGH:
+		return "voffset too high";
 	}
 	return "unkonwn error";
 }
diff --git a/Software/libthunderscopehw/library/thunderscopehw_internals.c b/Software/libthunderscopehw/library/thunderscopehw_internals.c
index e03eb1df..f178ae54 100644
--- a/Software/libthunderscopehw/library/thunderscopehw_internals.c
+++ b/Software/libthunderscopehw/library/thunderscopehw_internals.c
@@ -126,7 +126,12 @@ enum ThunderScopeHWStatus thunderscopehw_set_dac(struct ThunderScopeHW* ts, int
 {
 	// value is 12-bit
 	// Is this right?? Or is it rounding wrong?
-	unsigned int dac_value = (unsigned int)round((ts->channels[channel].voffset + 0.5) * 4095);
+	int dac_value = (unsigned int)round((ts->channels[channel].voffset + 0.5) * 4095);
+	if (dac_value < 0)
+		return THUNDERSCOPEHW_STATUS_OFFSET_TOO_LOW;
+	if (dac_value > 0xFFF)
+		return THUNDERSCOPEHW_STATUS_OFFSET_TOO_HIGH;
+
 	uint8_t fifo[5];
 	fifo[0] = 0xFF;  // I2C
 	fifo[1] = 0xC2;  // DAC?
@@ -151,7 +156,7 @@ enum ThunderScopeHWStatus thunderscopehw_configure_channels(struct ThunderScopeH
 
 	switch (num_channels_on) {
 	case 0:
-		return false;
+		return THUNDERSCOPEHW_STATUS_NO_CHANNELS;
 
 	case 1:
 		on_channels[1] = on_channels[2] = on_channels[3] = on_channels[0];

From b6c9e37abd7324b356f1eb54e5eba0fd470e50af Mon Sep 17 00:00:00 2001
From: profezzorn <hubbe@hubbe.net>
Date: Wed, 16 Feb 2022 10:21:41 -0800
Subject: [PATCH 10/13] fix dc couple options

---
 .../examples/thunderscopehwdump/thunderscopehwdump.c      | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
index 94869fa7..2c28cb3e 100644
--- a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
+++ b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
@@ -50,10 +50,10 @@ struct Option options[] = {
 	{"ac4",                false, 0x44 },
 
 	{"dc-all",             false, 0x50 },
-	{"ac1",                false, 0x51 },
-	{"ac2",                false, 0x52 },
-	{"ac3",                false, 0x53 },
-	{"ac4",                false, 0x54 },
+	{"dc1",                false, 0x51 },
+	{"dc2",                false, 0x52 },
+	{"dc3",                false, 0x53 },
+	{"dc4",                false, 0x54 },
 
 	{"enable-all",         false, 0x60 },
 	{"enable1",            false, 0x61 },

From f33a25602e5ed6caabe92e5e60ad0ebd6e8a8aff Mon Sep 17 00:00:00 2001
From: profezzorn <hubbe@hubbe.net>
Date: Wed, 16 Feb 2022 21:10:30 -0800
Subject: [PATCH 11/13] various updates

---
 .../thunderscopehwcalibrate.c                 | 40 ++++++++++++++-----
 .../thunderscopehwdump/thunderscopehwdump.c   | 11 ++++-
 .../library/thunderscopehw_internals.c        |  4 +-
 3 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/Software/libthunderscopehw/examples/thunderscopehwcalibrate/thunderscopehwcalibrate.c b/Software/libthunderscopehw/examples/thunderscopehwcalibrate/thunderscopehwcalibrate.c
index 7976afe9..bf1e27f8 100644
--- a/Software/libthunderscopehw/examples/thunderscopehwcalibrate/thunderscopehwcalibrate.c
+++ b/Software/libthunderscopehw/examples/thunderscopehwcalibrate/thunderscopehwcalibrate.c
@@ -17,12 +17,14 @@ struct Option {
 
 struct Option options[] = {
 	{"device",             true,  1 },
+	{"verbose",            false, 2 },
+	{"retries",            true,  3 },
 };
 
 #define TS_RUN(X) do {							\
 	enum ThunderScopeHWStatus ret = thunderscopehw_##X;		\
         if (ret != THUNDERSCOPEHW_STATUS_OK) {				\
-		fprintf(stderr, "thunderscope_%s failed @ line %d, error = %s\n", #X, __LINE__, thunderscopehw_describe_error(ret)); \
+		fprintf(stderr, "thunderscopehw_%s failed @ line %d, error = %s\n", #X, __LINE__, thunderscopehw_describe_error(ret)); \
 		exit(1);						\
 	}								\
 } while(0)
@@ -53,6 +55,8 @@ int mygetopt(int argc, char** argv) {
 }
 
 int main(int argc, char** argv) {
+	int verbose = 0;
+	int retries = 1;
 	uint64_t scope_id = 0;
 	uint64_t samples = 0;
 	int samplerate = 0;
@@ -64,6 +68,15 @@ int main(int argc, char** argv) {
 			         exit(1);
 			}
 			continue;
+		case 2:
+			verbose++;
+			continue;
+		case 3:
+			if (!sscanf(optarg, "%d", &retries)) {
+			         fprintf(stderr, "--retries needs a number.\n");
+			         exit(1);
+			}
+			continue;
 		default:
 			continue;
 		case -1:
@@ -111,15 +124,20 @@ int main(int argc, char** argv) {
 		usleep(500000);
 #endif
 
-		double minoffset = -0.5;
-		double maxoffset = 0.5;
-
-		for (int i =0; i < 1000; i++) {
+		for (int i = 0; i < retries; i++) {
+			double minoffset = -0.5;
+			double maxoffset = 0.5;
 			for (int j = 0; j < 20; j++) {
 				double midoffset = (minoffset + maxoffset) / 2;
 				TS_RUN(voltage_offset_set(ts, channel, midoffset));
 				TS_RUN(start(ts));
-				TS_RUN(read(ts, buffer, BUFFER_SIZE));
+				enum ThunderScopeHWStatus status = thunderscopehw_read(ts, buffer, BUFFER_SIZE);
+				if (status != THUNDERSCOPEHW_STATUS_OK) {
+					fprintf(stderr, "thunderscopehw_read failed, error = %s\n", thunderscopehw_describe_error(status));
+					j--;
+					TS_RUN(stop(ts));
+					continue;
+				}
 				// Convert signed output to unsigned output
 				for (size_t i = 0; i < BUFFER_SIZE; i++) {
 					buffer[i] += 0x80;
@@ -133,10 +151,12 @@ int main(int argc, char** argv) {
 					if (buffer[i] < 0x80) low++;
 					sum += buffer[i];
 				}
-//			fprintf(stderr," min = %8.4f  max = %8.4f  mid = %8.4f  high=%d low=%d avg=%f\n",
-//				minoffset, maxoffset, midoffset,
-//				high, low,
-//				sum / (double)BUFFER_SIZE);
+				if (verbose) {
+					fprintf(stderr," min = %8.4f  max = %8.4f  mid = %8.4f  high=%d low=%d avg=%f\n",
+						minoffset, maxoffset, midoffset,
+						high, low,
+						sum / (double)BUFFER_SIZE);
+				}
 				if (high > low) {
 					minoffset = midoffset;
 				} else {
diff --git a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
index 2c28cb3e..26f20f56 100644
--- a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
+++ b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
@@ -5,6 +5,10 @@
 #include <inttypes.h>
 #include <string.h>
 
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
 void write32(uint64_t x, FILE* f) {
 	uint32_t v = 0;
 	if (x < (uint64_t)0xFFFFFFFF) v = (uint32_t)x;
@@ -168,7 +172,7 @@ int main(int argc, char** argv) {
 				}
 				break;
 			case 3: // voffset
-				ret = thunderscopehw_voltage_offset_set(ts, channel, atoi(optarg));
+				ret = thunderscopehw_voltage_offset_set(ts, channel, atof(optarg));
 				if (ret != THUNDERSCOPEHW_STATUS_OK) {
 					fprintf(stderr, "Failed to set voffset. error =%s\n", thunderscopehw_describe_error(ret));
 					exit(1);
@@ -235,6 +239,11 @@ int main(int argc, char** argv) {
 		uint16_t block_align;
 		uint16_t bits_per_sample;
 	};
+#ifdef WIN32
+		Sleep(500);
+#else
+		usleep(500000);
+#endif
 
 	struct Fmt fmt;
 	fmt.pcm = 1;
diff --git a/Software/libthunderscopehw/library/thunderscopehw_internals.c b/Software/libthunderscopehw/library/thunderscopehw_internals.c
index f178ae54..e3b491e2 100644
--- a/Software/libthunderscopehw/library/thunderscopehw_internals.c
+++ b/Software/libthunderscopehw/library/thunderscopehw_internals.c
@@ -156,8 +156,6 @@ enum ThunderScopeHWStatus thunderscopehw_configure_channels(struct ThunderScopeH
 
 	switch (num_channels_on) {
 	case 0:
-		return THUNDERSCOPEHW_STATUS_NO_CHANNELS;
-
 	case 1:
 		on_channels[1] = on_channels[2] = on_channels[3] = on_channels[0];
 		clkdiv = 0;
@@ -200,6 +198,8 @@ enum ThunderScopeHWStatus thunderscopehw_configure_channels(struct ThunderScopeH
 #else
 	usleep(5000);
 #endif
+	/* No channels, leave data mover off. */
+	if (num_channels_on == 0) return THUNDERSCOPEHW_STATUS_OK;
 	return thunderscopehw_set_datamover_reg(ts);
 }
 

From 9cc74528397aaf2641bb35d2a9e502f7f87f3dd2 Mon Sep 17 00:00:00 2001
From: profezzorn <hubbe@hubbe.net>
Date: Wed, 16 Feb 2022 23:44:12 -0800
Subject: [PATCH 12/13] add thunderscopehwbench and some minor fixes

---
 Software/libthunderscopehw/CMakeLists.txt     |   1 +
 .../thunderscopehwbench/CMakeLists.txt        |   4 +
 .../thunderscopehwbench/thunderscopehwbench.c | 150 ++++++++++++++++++
 .../thunderscopehwdump/thunderscopehwdump.c   |   2 +-
 .../library/thunderscopehw.c                  |   4 +-
 5 files changed, 158 insertions(+), 3 deletions(-)
 create mode 100644 Software/libthunderscopehw/examples/thunderscopehwbench/CMakeLists.txt
 create mode 100644 Software/libthunderscopehw/examples/thunderscopehwbench/thunderscopehwbench.c

diff --git a/Software/libthunderscopehw/CMakeLists.txt b/Software/libthunderscopehw/CMakeLists.txt
index 0890d133..5b83eed1 100644
--- a/Software/libthunderscopehw/CMakeLists.txt
+++ b/Software/libthunderscopehw/CMakeLists.txt
@@ -7,6 +7,7 @@ project(thunderscopehwlib VERSION ${PROJECT_VERSION})
 add_subdirectory(library)
 add_subdirectory(examples/thunderscopehwdump)
 add_subdirectory(examples/thunderscopehwcalibrate)
+add_subdirectory(examples/thunderscopehwbench)
 
 enable_testing()
 add_subdirectory(test)
diff --git a/Software/libthunderscopehw/examples/thunderscopehwbench/CMakeLists.txt b/Software/libthunderscopehw/examples/thunderscopehwbench/CMakeLists.txt
new file mode 100644
index 00000000..22305733
--- /dev/null
+++ b/Software/libthunderscopehw/examples/thunderscopehwbench/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_executable(thunderscopehwbench
+	thunderscopehwbench.c)
+target_link_libraries(thunderscopehwbench
+	thunderscopehwlib)
diff --git a/Software/libthunderscopehw/examples/thunderscopehwbench/thunderscopehwbench.c b/Software/libthunderscopehw/examples/thunderscopehwbench/thunderscopehwbench.c
new file mode 100644
index 00000000..0001b297
--- /dev/null
+++ b/Software/libthunderscopehw/examples/thunderscopehwbench/thunderscopehwbench.c
@@ -0,0 +1,150 @@
+#include "thunderscopehw.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+
+
+static uint64_t time_ns(void)
+{
+#ifdef WIN32
+    struct timespec tv;
+    if (timespec_get(&ts, TIME_UTC) != TIME_UTC)
+    {
+	    fprintf(stderr, "timespec_get failed!");
+	    exit(1);
+    }
+    return 1000000000 * ts.tv_sec + ts.tv_nsec;
+#else
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return 1000000000 * tv.tv_sec + tv.tv_usec * 1000;
+#endif
+}
+
+struct Option {
+        const char* name;
+        bool needs_argument;
+        int return_value;
+};
+
+struct Option options[] = {
+	{"device",             true,  1 },
+	{"verbose",            false, 2 },
+	{"repeat",             true,  3 },
+};
+
+#define TS_RUN(X) do {							\
+	enum ThunderScopeHWStatus ret = thunderscopehw_##X;		\
+        if (ret != THUNDERSCOPEHW_STATUS_OK) {				\
+		fprintf(stderr, "thunderscopehw_%s failed @ line %d, error = %s\n", #X, __LINE__, thunderscopehw_describe_error(ret)); \
+		exit(1);						\
+	}								\
+} while(0)
+
+char* optarg;
+int optind = 1;
+int mygetopt(int argc, char** argv) {
+        if (optind >= argc) return -1;
+	if (!argv[optind][0] == '-' || argv[optind][1] != '-') return -1;
+	char *arg = strchr(argv[optind], '=');
+	for (size_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
+               size_t len = strlen(options[i].name);
+	       if (strncmp(options[i].name, argv[optind] + 2, len)) continue;
+	       if (options[i].needs_argument) {
+	               if (!arg) continue;
+	               if (argv[optind] + 2 + len != arg) continue;
+		       optarg = arg + 1;
+	       } else {
+	               if (arg) continue;
+		       if (argv[optind][2 + len]) continue;
+		       optarg = NULL;
+	       }
+	       optind++;
+	       return options[i].return_value;
+	}
+	fprintf(stderr, "Unknown option: %s\n", argv[optind]);
+	exit(1);
+}
+
+int main(int argc, char** argv) {
+	int verbose = 0;
+	int repeat = 1;
+	uint64_t scope_id = 0;
+	uint64_t samples = 0;
+	int samplerate = 0;
+	while (1) {
+		switch (mygetopt(argc, argv)) {
+		case 1:
+			if (!sscanf(optarg, "%" PRIx64, &scope_id)) {
+			         fprintf(stderr, "Scope ID must be hexadecimal.\n");
+			         exit(1);
+			}
+			continue;
+		case 2:
+			verbose++;
+			continue;
+		case 3:
+			if (!sscanf(optarg, "%d", &repeat)) {
+			         fprintf(stderr, "--repeat needs a number.\n");
+			         exit(1);
+			}
+			continue;
+		default:
+			continue;
+		case -1:
+			break;
+		}
+		break;
+	}
+
+	if (scope_id == 0) {
+		uint64_t scope_ids[32];
+		int scopes = thunderscopehw_scan(scope_ids, 32);
+		if (scopes == 0) {
+			fprintf(stderr, "No thunderscopehw hardware found.\n");
+			exit(1);
+		}
+		if (scopes > 1) {
+			fprintf(stderr, "Multiple scopes found, please select one with --device.\n");
+			for (int i = 0; i < scopes; i++) {
+				fprintf(stderr, "  %0" PRIx64 "\n", scope_ids[i]);
+			}
+			exit(1);
+		}
+		scope_id = scope_ids[0];
+	}
+
+	// 32Mb
+#define BUFFER_SIZE (32<<20)
+	uint8_t* buffer;
+#ifdef _WIN32
+        buffer = _aligned_malloc(BUFFER_SIZE, 4096);
+#else
+	posix_memalign((void**)&buffer, 4096, BUFFER_SIZE);
+#endif
+
+	struct ThunderScopeHW *ts = thunderscopehw_create();
+	enum ThunderScopeHWStatus ret;
+	TS_RUN(connect(ts, scope_id));
+
+
+	TS_RUN(enable_channel(ts, 0));
+	TS_RUN(start(ts));
+	for (int i = 0; i < repeat; i++) {
+		uint64_t start = time_ns();
+		uint64_t bytes = 0;
+		for (int j = 0; j < (1<<30) / BUFFER_SIZE; j++) {
+			TS_RUN(read(ts, buffer, BUFFER_SIZE));
+			bytes += BUFFER_SIZE;
+		}
+		uint64_t end = time_ns();
+		printf("Rate = %f Mib/s\n", bytes / 1000.0 / 1000.0 * 1000000000.0 / (end - start));
+	}
+}
diff --git a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
index 26f20f56..e29331cd 100644
--- a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
+++ b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c
@@ -273,7 +273,7 @@ int main(int argc, char** argv) {
 		exit(1);
 	}
 
-#define BUFFER_SIZE (1<<20)
+#define BUFFER_SIZE samples
 	uint8_t* buffer;
 #ifdef _WIN32
         buffer = _aligned_malloc(BUFFER_SIZE, 4096);
diff --git a/Software/libthunderscopehw/library/thunderscopehw.c b/Software/libthunderscopehw/library/thunderscopehw.c
index 4bbd50da..0356e995 100644
--- a/Software/libthunderscopehw/library/thunderscopehw.c
+++ b/Software/libthunderscopehw/library/thunderscopehw.c
@@ -116,13 +116,13 @@ static enum ThunderScopeHWStatus thunderscopehw_update_buffer_head(struct Thunde
 	uint32_t error_code = transfer_counter >> 30;
 	if (error_code & 1)
 		return THUNDERSCOPEHW_STATUS_DATAMOVER_ERROR;
+
 	if (error_code & 2)
 		return THUNDERSCOPEHW_STATUS_FIFO_OVERFLOW;
 
 	uint32_t overflow_cycles = (transfer_counter >> 16) & 0x3FFF;
-	if (overflow_cycles) {
+	if (overflow_cycles)
 		return THUNDERSCOPEHW_STATUS_PIPELINE_OVERFLOW;
-	}
 
 	uint32_t pages_moved = transfer_counter & 0xFFFF;
 	uint64_t buffer_head = (ts->buffer_head & ~0xFFFFULL) | pages_moved;

From 191b10304e44edb4157fe95b221b0e9be80ee761 Mon Sep 17 00:00:00 2001
From: profezzorn <hubbe@hubbe.net>
Date: Thu, 17 Feb 2022 09:56:43 -0800
Subject: [PATCH 13/13] swap fifo/datamover error bits

---
 Software/libthunderscopehw/library/thunderscopehw.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Software/libthunderscopehw/library/thunderscopehw.c b/Software/libthunderscopehw/library/thunderscopehw.c
index 0356e995..1b8f2495 100644
--- a/Software/libthunderscopehw/library/thunderscopehw.c
+++ b/Software/libthunderscopehw/library/thunderscopehw.c
@@ -114,10 +114,10 @@ static enum ThunderScopeHWStatus thunderscopehw_update_buffer_head(struct Thunde
 	// 1 page = 4k
 	uint32_t transfer_counter = thunderscopehw_read32(ts, DATAMOVER_TRANSFER_COUNTER);
 	uint32_t error_code = transfer_counter >> 30;
-	if (error_code & 1)
+	if (error_code & 2)
 		return THUNDERSCOPEHW_STATUS_DATAMOVER_ERROR;
 
-	if (error_code & 2)
+	if (error_code & 1)
 		return THUNDERSCOPEHW_STATUS_FIFO_OVERFLOW;
 
 	uint32_t overflow_cycles = (transfer_counter >> 16) & 0x3FFF;