From ee129219bd537597fd59f6995cc703ca9c852144 Mon Sep 17 00:00:00 2001
From: cnlohr <lohr85@gmail.com>
Date: Sun, 19 Feb 2023 01:17:08 -0800
Subject: [PATCH] Add ability to read-back data.

---
 minichlink/minichlink.c     | 112 +++++++++++++++++++++++++++++++++++-
 minichlink/test.bat         |   2 +-
 minichlink/wch_dump_flash.c |  54 +++++++++++++++++
 minichlink/wch_link_base.h  |   4 ++
 4 files changed, 170 insertions(+), 2 deletions(-)
 create mode 100644 minichlink/wch_dump_flash.c

diff --git a/minichlink/minichlink.c b/minichlink/minichlink.c
index 346ea99..cce5149 100644
--- a/minichlink/minichlink.c
+++ b/minichlink/minichlink.c
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <stdlib.h>
 #include "wch_link_base.h"
 
 
@@ -36,6 +37,8 @@ const uint8_t * bootloader = (const uint8_t*)
 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
 
+static int64_t SimpleReadNumberInt( const char * number, int64_t defaultNumber );
+
 int bootloader_len = 512;
 
 int main( int argc, char ** argv )
@@ -107,8 +110,84 @@ keep_going:
 					4, "\x81\x06\x01\x01" );
 				break;
 			*/
-			case 'w':
+			case 'o':
+			{
+				int i;
+				int transferred;
+				if( argchar[2] != 0 ) goto help;
+				iarg++;
+				argchar = 0; // Stop advancing
+				if( iarg + 2 >= argc ) goto help;
+				uint64_t offset = SimpleReadNumberInt( argv[iarg++], -1 );
+				uint64_t amount = SimpleReadNumberInt( argv[iarg++], -1 );
+				if( offset > 0xffffffff || amount > 0xffffffff )
+				{
+					fprintf( stderr, "Error: memory value request out of range.\n" );
+					return -9;
+				}
+
+				// Round up amount.
+				amount = ( amount + 3 ) & 0xfffffffc;
+				FILE * f = fopen( argv[iarg], "wb" );
+				if( !f )
+				{
+					fprintf( stderr, "Error: can't open write file \"%s\"\n", argv[iarg] );
+					return -9;
+				}
+				uint32_t * readbuff = malloc( amount );
+				int readbuffplace = 0;
+				wch_link_command( devh, "\x81\x06\x01\x01", 4, 0, 0, 0 );
+
+				// Flush out any pending data.
+				libusb_bulk_transfer( devh, 0x82, rbuff, 1024, &transferred, 1 );
+
+				// 3/8 = Read Memory
+				// First 4 bytes are big-endian location.
+				// Next 4 bytes are big-endian amount.
+				uint8_t readop[11] = { 0x81, 0x03, 0x08, };
+				
+				readop[3] = (offset>>24)&0xff;
+				readop[4] = (offset>>16)&0xff;
+				readop[5] = (offset>>8)&0xff;
+				readop[6] = (offset>>0)&0xff;
+
+				readop[7] = (amount>>24)&0xff;
+				readop[8] = (amount>>16)&0xff;
+				readop[9] = (amount>>8)&0xff;
+				readop[10] = (amount>>0)&0xff;
+				
+				wch_link_command( devh, readop, 11, 0, 0, 0 );
+
+				// Perform operation
+				wch_link_command( devh, "\x81\x02\x01\x0c", 4, 0, 0, 0 );
+
+				uint32_t remain = amount;
+				while( remain )
+				{
+					transferred = 0;
+					WCHCHECK( libusb_bulk_transfer( devh, 0x82, rbuff, 1024, &transferred, WCHTIMEOUT ) );
+					memcpy( ((uint8_t*)readbuff) + readbuffplace, rbuff, transferred );
+					readbuffplace += transferred;
+					remain -= transferred;
+				}
+
+				// Flip internal endian.  Must be done separately in case something was unaligned when
+				// reading.
+				for( i = 0; i < readbuffplace/4; i++ )
 				{
+					uint32_t r = readbuff[i];
+					readbuff[i] = (r>>24) | ((r & 0xff0000) >> 8) | ((r & 0xff00)<<8) | (( r & 0xff )<<24); 
+				}
+				
+				fwrite( readbuff, readbuffplace, 1, f );
+
+				free( readbuff );
+
+				fclose( f );
+				break;
+			}
+			case 'w':
+			{
 				if( argchar[2] != 0 ) goto help;
 				iarg++;
 				argchar = 0; // Stop advancing
@@ -207,5 +286,36 @@ help:
 //	fprintf( stderr, " -P Enable Read Protection (UNTESTED)\n" );
 //	fprintf( stderr, " -p Disable Read Protection (UNTESTED)\n" );
 	fprintf( stderr, " -w [binary image to write]\n" );
+	fprintf( stderr, " -o [memory address, decimal or 0x, try 0x08000000] [size, decimal or 0x, try 16384] [output binary image]\n" );
 	return -1;	
 }
+
+
+#if defined(WINDOWS) || defined(WIN32) || defined(_WIN32)
+#define strtoll _strtoi64
+#endif
+
+static int64_t SimpleReadNumberInt( const char * number, int64_t defaultNumber )
+{
+	if( !number || !number[0] ) return defaultNumber;
+	int radix = 10;
+	if( number[0] == '0' )
+	{
+		char nc = number[1];
+		number+=2;
+		if( nc == 0 ) return 0;
+		else if( nc == 'x' ) radix = 16;
+		else if( nc == 'b' ) radix = 2;
+		else { number--; radix = 8; }
+	}
+	char * endptr;
+	uint64_t ret = strtoll( number, &endptr, radix );
+	if( endptr == number )
+	{
+		return defaultNumber;
+	}
+	else
+	{
+		return ret;
+	}
+}
diff --git a/minichlink/test.bat b/minichlink/test.bat
index 912a017..6761071 100644
--- a/minichlink/test.bat
+++ b/minichlink/test.bat
@@ -4,7 +4,7 @@ tcc wch_erase.c libusb-1.0.dll
 tcc wch_reset.c libusb-1.0.dll
 tcc wch_write_simple.c libusb-1.0.dll
 tcc minichlink.c libusb-1.0.dll
-
+tcc wch_dump_flash.c libusb-1.0.dll
 rem wch_erase.exe
 rem wch_write_simple.exe ..\barebones\barebones.bin
 rem wch_reset.exe
diff --git a/minichlink/wch_dump_flash.c b/minichlink/wch_dump_flash.c
new file mode 100644
index 0000000..43857b2
--- /dev/null
+++ b/minichlink/wch_dump_flash.c
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include "wch_link_base.h"
+
+// TODO Make me actually query data!
+
+int main()
+{
+	int i;
+	int transferred;
+	int status;
+	char rbuff[1024];
+	libusb_device_handle * devh = wch_link_base_setup();
+
+	wch_link_command( devh, "\x81\x06\x01\x01", 4, 0, 0, 0 );
+
+	// Flush out any pending data.
+	libusb_bulk_transfer( devh, 0x82, rbuff, 1024, &transferred, 1 );
+
+	// 3/8 = Read Memory
+	// First 4 bytes are big-endian location.
+	// Next 4 bytes are big-endian amount.
+	uint8_t readop[11] = { 0x81, 0x03, 0x08, };
+	uint32_t readptr = 0x08000000;
+	uint32_t amount = 16384;
+	
+	readop[3] = (readptr>>24)&0xff;
+	readop[4] = (readptr>>16)&0xff;
+	readop[5] = (readptr>>8)&0xff;
+	readop[6] = (readptr>>0)&0xff;
+
+	readop[7] = (amount>>24)&0xff;
+	readop[8] = (amount>>16)&0xff;
+	readop[9] = (amount>>8)&0xff;
+	readop[10] = (amount>>0)&0xff;
+	
+	wch_link_command( devh, readop, 11, 0, 0, 0 );
+
+	// Perform operation
+	wch_link_command( devh, "\x81\x02\x01\x0c", 4, 0, 0, 0 );
+
+	printf( "WARNING ENDIAN WILL BE REVERSED\n" );
+
+	uint32_t remain = amount;
+	while( remain )
+	{
+		WCHCHECK( libusb_bulk_transfer( devh, 0x82, rbuff, 1024, &transferred, WCHTIMEOUT ) );
+		for( i = 0; i < transferred; i++ )
+			printf( "%08x", (uint8_t)rbuff[i] );
+		printf( "\n" );
+		remain -= transferred;
+	}
+
+	wch_link_command( devh, "\x81\x0d\x01\xff", 4, 0, 0, 0 );
+}
diff --git a/minichlink/wch_link_base.h b/minichlink/wch_link_base.h
index ee41455..62f57ec 100644
--- a/minichlink/wch_link_base.h
+++ b/minichlink/wch_link_base.h
@@ -99,8 +99,12 @@ static inline libusb_device_handle * wch_link_base_setup()
 	// Place part into reset.
 	wch_link_command( devh, "\x81\x0d\x01\x01", 4, &transferred, rbuff, 1024 );	// Reply is: "\x82\x0d\x04\x02\x08\x02\x00"
 
+	// TODO: What in the world is this?  It doesn't appear to be needed.
 	wch_link_command( devh, "\x81\x0c\x02\x09\x01", 5, 0, 0, 0 ); //Reply is: 820c0101
+
+	// This puts the processor on hold to allow the debugger to run.
 	wch_link_command( devh, "\x81\x0d\x01\x02", 4, 0, 0, 0 ); // Reply: Ignored, 820d050900300500
+
 	wch_link_command( devh, "\x81\x11\x01\x09", 4, &transferred, rbuff, 1024 ); // Reply: Chip ID + Other data (see below)
 	if( transferred != 20 )
 	{
-- 
GitLab