From 184fdfd1b30410db59b50b427ce5c7b817ae4c88 Mon Sep 17 00:00:00 2001
From: cnlohr <lohr85@gmail.com>
Date: Wed, 21 Jun 2023 00:49:41 -0400
Subject: [PATCH] Integrate most changes from Alexander M, bmx and Pokey.

---
 minichlink/minichlink.c    |  32 +++++----
 minichlink/minichlink.h    |   1 +
 minichlink/pgm-wch-linke.c | 134 +++++++++++++++++++++++--------------
 3 files changed, 99 insertions(+), 68 deletions(-)

diff --git a/minichlink/minichlink.c b/minichlink/minichlink.c
index 83c4de7..c73558d 100644
--- a/minichlink/minichlink.c
+++ b/minichlink/minichlink.c
@@ -18,11 +18,6 @@ void Sleep(uint32_t dwMilliseconds);
 #include <unistd.h>
 #endif
 
-
-#if defined(WINDOWS) || defined(WIN32) || defined(_WIN32)
-	#define usleep(x) Sleep((x)/1000);
-#endif
-
 static int64_t StringToMemoryAddress( const char * number ) __attribute__((used));
 static void StaticUpdatePROGBUFRegs( void * dev ) __attribute__((used));
 int DefaultReadBinaryBlob( void * dev, uint32_t address_to_read_from, uint32_t read_size, uint8_t * blob );
@@ -59,6 +54,14 @@ void * MiniCHLinkInitAsDLL( struct MiniChlinkFunctions ** MCFO, const init_hints
 		return 0;
 	}
 
+	struct InternalState * iss = calloc( 1, sizeof( struct InternalState ) );
+	((struct ProgrammerStructBase*)dev)->internal = iss;
+	iss->ram_base = 0x20000000;
+	iss->ram_size = 2048;
+	iss->sector_size = 64;
+	iss->flash_size = 16384;
+	iss->target_chip_type = 0;
+
 	SetupAutomaticHighLevelFunctions( dev );
 
 	if( MCFO )
@@ -468,6 +471,7 @@ keep_going:
 			}
 			case 'w':
 			{
+				struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal);
 				if( argchar[2] != 0 ) goto help;
 				iarg++;
 				argchar = 0; // Stop advancing
@@ -684,7 +688,7 @@ static int DefaultWaitForFlash( void * dev )
 		rw = 0;
 		MCF.ReadWord( dev, (intptr_t)&FLASH->STATR, &rw ); // FLASH_STATR => 0x4002200C
 		if( timeout++ > 100 ) return -1;
-	} while(rw & 1);  // BSY flag.
+	} while(rw & 2);  // BSY flag for 003, or WRBSY for other processors.
 
 	if( rw & FLASH_STATR_WRPRTERR )
 	{
@@ -1715,10 +1719,7 @@ int DefaultUnbrick( void * dev )
 	// After more experimentation, it appaers to work best by not clearing the halt request.
 
 	MCF.FlushLLCommands( dev );
-	if( MCF.DelayUS )
-		MCF.DelayUS( dev, 20000 );
-	else
-		usleep(20000);
+	MCF.DelayUS( dev, 20000 );
 
 	if( timeout == max_timeout ) 
 	{
@@ -1778,7 +1779,11 @@ int DefaultVoidHighLevelState( void * dev )
 
 int DefaultDelayUS( void * dev, int us )
 {
+#if defined(WINDOWS) || defined(WIN32) || defined(_WIN32)
+	Sleep( (us+9999) / 1000 );
+#else
 	usleep( us );
+#endif
 	return 0;
 }
 
@@ -1839,13 +1844,6 @@ int SetupAutomaticHighLevelFunctions( void * dev )
 	if( !MCF.DelayUS )
 		MCF.DelayUS = DefaultDelayUS;
 
-	struct InternalState * iss = calloc( 1, sizeof( struct InternalState ) );
-	iss->ram_base = 0x20000000;
-	iss->ram_size = 2048;
-	iss->sector_size = 64;
-	iss->flash_size = 16384;
-
-	((struct ProgrammerStructBase*)dev)->internal = iss;
 	return 0;
 }
 
diff --git a/minichlink/minichlink.h b/minichlink/minichlink.h
index 50f859c..dfdb244 100644
--- a/minichlink/minichlink.h
+++ b/minichlink/minichlink.h
@@ -116,6 +116,7 @@ struct InternalState
 	uint32_t ram_size;
 	int sector_size;
 	int flash_size;
+	int target_chip_type; // 0 for unknown (or 003), otherwise a part number.
 	uint8_t flash_sector_status[MAX_FLASH_SECTORS];  // 0 means unerased/unknown. 1 means erased.
 };
 
diff --git a/minichlink/pgm-wch-linke.c b/minichlink/pgm-wch-linke.c
index 2a3e516..61f98d6 100644
--- a/minichlink/pgm-wch-linke.c
+++ b/minichlink/pgm-wch-linke.c
@@ -18,8 +18,8 @@ struct LinkEProgrammerStruct
 
 // For non-ch32v003 chips.
 //static int LEReadBinaryBlob( void * d, uint32_t offset, uint32_t amount, uint8_t * readbuff );
-//static int InternalLinkEHaltMode( void * d, int mode );
-//static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, uint8_t * blob );
+static int InternalLinkEHaltMode( void * d, int mode );
+static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, uint8_t * blob );
 
 #define WCHTIMEOUT 5000
 #define WCHCHECK(x) if( (status = x) ) { fprintf( stderr, "Bad USB Operation on " __FILE__ ":%d (%d)\n", __LINE__, status ); exit( status ); }
@@ -191,6 +191,8 @@ int LEFlushLLCommands( void * dev )
 static int LESetupInterface( void * d )
 {
 	libusb_device_handle * dev = ((struct LinkEProgrammerStruct*)d)->devh;
+	struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal);
+
 	uint8_t rbuff[1024];
 	uint32_t transferred = 0;
 
@@ -223,6 +225,10 @@ static int LESetupInterface( void * d )
 	// TODO: What in the world is this?  It doesn't appear to be needed.
 	wch_link_command( dev, "\x81\x0c\x02\x09\x01", 5, 0, 0, 0 ); //Reply is: 820c0101
 
+	// Note from further debugging:
+	// My capture differs in this case: \x05 instead of \x09 -> But does not seem to be needed
+	//wch_link_command( dev, "\x81\x0c\x02\x05\x01", 5, 0, 0, 0 ); //Reply is: 820c0101
+
 	// This puts the processor on hold to allow the debugger to run.
 	wch_link_command( dev, "\x81\x0d\x01\x02", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Ignored, 820d050900300500
 	if (rbuff[0] == 0x81 && rbuff[1] == 0x55 && rbuff[2] == 0x01 && rbuff[3] == 0x01)
@@ -230,8 +236,18 @@ static int LESetupInterface( void * d )
 		fprintf(stderr, "link error, nothing connected to linker\n");
 		return -1;
 	}
-        uint32_t target_chip_type = ( rbuff[4] << 4) + (rbuff[5] >> 4);
-        fprintf(stderr, "Chip Type: %03x\n", target_chip_type);
+
+    uint32_t target_chip_type = ( rbuff[4] << 4) + (rbuff[5] >> 4);
+    fprintf(stderr, "Chip Type: %03x\n", target_chip_type);
+	if( target_chip_type == 0x307 || target_chip_type == 0x203 )
+	{
+		fprintf( stderr, "CH32V307 or CH32V203 Detected.  Allowing old-flash-mode for operation.\n" );
+		MCF.WriteBinaryBlob = LEWriteBinaryBlob;
+
+		iss->sector_size = 256;
+
+		wch_link_command( dev, "\x81\x0d\x01\x03", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Ignored, 820d050900300500
+	}
 
 	// For some reason, if we don't do this sometimes the programmer starts in a hosey mode.
 	MCF.WriteReg32( d, DMCONTROL, 0x80000001 ); // Make the debug module work properly.
@@ -254,7 +270,10 @@ static int LESetupInterface( void * d )
 	}
 
 	// This puts the processor on hold to allow the debugger to run.
-	wch_link_command( dev, "\x81\x11\x01\x09", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Chip ID + Other data (see below)
+	// Recommended to switch to 05 from 09 by Alexander M
+	//	wch_link_command( dev, "\x81\x11\x01\x09", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Chip ID + Other data (see below)
+	wch_link_command( dev, "\x81\x11\x01\x05", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Chip ID + Other data (see below)
+
 	if( transferred != 20 )
 	{
 		fprintf( stderr, "Error: could not get part status\n" );
@@ -264,7 +283,24 @@ static int LESetupInterface( void * d )
 	fprintf( stderr, "Part UUID    : %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", rbuff[4], rbuff[5], rbuff[6], rbuff[7], rbuff[8], rbuff[9], rbuff[10], rbuff[11] );
 	fprintf( stderr, "PFlags       : %02x-%02x-%02x-%02x\n", rbuff[12], rbuff[13], rbuff[14], rbuff[15] );
 	fprintf( stderr, "Part Type (B): %02x-%02x-%02x-%02x\n", rbuff[16], rbuff[17], rbuff[18], rbuff[19] );
-	
+
+	// Check for read protection
+	wch_link_command( dev, "\x81\x06\x01\x01", 4, (int*)&transferred, rbuff, 1024 );
+	if(transferred != 4) {
+		fprintf(stderr, "Error: could not get read protection status\n");
+		return -1;
+	}
+
+	if(rbuff[3] == 0x01) {
+		fprintf(stderr, "Read protection: enabled\n");
+	} else {
+		fprintf(stderr, "Read protection: disabled\n");
+	}
+
+
+	iss->flash_size = (rbuff[2]<<8) | rbuff[3];
+	iss->target_chip_type = target_chip_type;
+
 	return 0;
 }
 
@@ -365,49 +401,47 @@ void * TryInit_WCHLinkE()
 };
 
 
-#if 0
+#if 1
 
 // In case you are using a non-CH32V003 board.
 
-
 const uint8_t * bootloader = (const uint8_t*)
-"\x21\x11\x22\xca\x26\xc8\x93\x77\x15\x00\x99\xcf\xb7\x06\x67\x45" \
-"\xb7\x27\x02\x40\x93\x86\x36\x12\x37\x97\xef\xcd\xd4\xc3\x13\x07" \
-"\xb7\x9a\xd8\xc3\xd4\xd3\xd8\xd3\x93\x77\x25\x00\x9d\xc7\xb7\x27" \
-"\x02\x40\x98\x4b\xad\x66\x37\x33\x00\x40\x13\x67\x47\x00\x98\xcb" \
-"\x98\x4b\x93\x86\xa6\xaa\x13\x67\x07\x04\x98\xcb\xd8\x47\x05\x8b" \
-"\x63\x16\x07\x10\x98\x4b\x6d\x9b\x98\xcb\x93\x77\x45\x00\xa9\xcb" \
-"\x93\x07\xf6\x03\x99\x83\x2e\xc0\x2d\x63\x81\x76\x3e\xc4\xb7\x32" \
-"\x00\x40\xb7\x27\x02\x40\x13\x03\xa3\xaa\xfd\x16\x98\x4b\xb7\x03" \
-"\x02\x00\x33\x67\x77\x00\x98\xcb\x02\x47\xd8\xcb\x98\x4b\x13\x67" \
-"\x07\x04\x98\xcb\xd8\x47\x05\x8b\x69\xe7\x98\x4b\x75\x8f\x98\xcb" \
-"\x02\x47\x13\x07\x07\x04\x3a\xc0\x22\x47\x7d\x17\x3a\xc4\x79\xf7" \
-"\x93\x77\x85\x00\xf1\xcf\x93\x07\xf6\x03\x2e\xc0\x99\x83\x37\x27" \
-"\x02\x40\x3e\xc4\x1c\x4b\xc1\x66\x2d\x63\xd5\x8f\x1c\xcb\x37\x07" \
-"\x00\x20\x13\x07\x07\x20\xb7\x27\x02\x40\xb7\x03\x08\x00\xb7\x32" \
-"\x00\x40\x13\x03\xa3\xaa\x94\x4b\xb3\xe6\x76\x00\x94\xcb\xd4\x47" \
-"\x85\x8a\xf5\xfe\x82\x46\xba\x84\x37\x04\x04\x00\x36\xc2\xc1\x46" \
-"\x36\xc6\x92\x46\x84\x40\x11\x07\x84\xc2\x94\x4b\xc1\x8e\x94\xcb" \
-"\xd4\x47\x85\x8a\xb1\xea\x92\x46\xba\x84\x91\x06\x36\xc2\xb2\x46" \
-"\xfd\x16\x36\xc6\xf9\xfe\x82\x46\xd4\xcb\x94\x4b\x93\xe6\x06\x04" \
-"\x94\xcb\xd4\x47\x85\x8a\x85\xee\xd4\x47\xc1\x8a\x85\xce\xd8\x47" \
-"\xb7\x06\xf3\xff\xfd\x16\x13\x67\x07\x01\xd8\xc7\x98\x4b\x21\x45" \
-"\x75\x8f\x98\xcb\x52\x44\xc2\x44\x61\x01\x02\x90\x23\x20\xd3\x00" \
-"\xf5\xb5\x23\xa0\x62\x00\x3d\xb7\x23\xa0\x62\x00\x55\xb7\x23\xa0" \
-"\x62\x00\xc1\xb7\x82\x46\x93\x86\x06\x04\x36\xc0\xa2\x46\xfd\x16" \
-"\x36\xc4\xb5\xf2\x98\x4b\xb7\x06\xf3\xff\xfd\x16\x75\x8f\x98\xcb" \
-"\x41\x89\x05\xcd\x2e\xc0\x0d\x06\x02\xc4\x09\x82\xb7\x07\x00\x20" \
-"\x32\xc6\x93\x87\x07\x20\x98\x43\x13\x86\x47\x00\xa2\x47\x82\x46" \
-"\x8a\x07\xb6\x97\x9c\x43\x63\x1c\xf7\x00\xa2\x47\x85\x07\x3e\xc4" \
-"\xa2\x46\x32\x47\xb2\x87\xe3\xe0\xe6\xfe\x01\x45\x61\xb7\x41\x45" \
-"\x51\xb7\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+"\x93\x77\x15\x00\x41\x11\x99\xcf\xb7\x06\x67\x45\xb7\x27\x02\x40" \
+"\x93\x86\x36\x12\x37\x97\xef\xcd\xd4\xc3\x13\x07\xb7\x9a\xd8\xc3" \
+"\xd4\xd3\xd8\xd3\x93\x77\x25\x00\x95\xc7\xb7\x27\x02\x40\x98\x4b" \
+"\xad\x66\x37\x38\x00\x40\x13\x67\x47\x00\x98\xcb\x98\x4b\x93\x86" \
+"\xa6\xaa\x13\x67\x07\x04\x98\xcb\xd8\x47\x05\x8b\x61\xeb\x98\x4b" \
+"\x6d\x9b\x98\xcb\x93\x77\x45\x00\xa9\xcb\x93\x07\xf6\x0f\xa1\x83" \
+"\x2e\xc0\x2d\x68\x81\x76\x3e\xc4\xb7\x08\x02\x00\xb7\x27\x02\x40" \
+"\x37\x33\x00\x40\x13\x08\xa8\xaa\xfd\x16\x98\x4b\x33\x67\x17\x01" \
+"\x98\xcb\x02\x47\xd8\xcb\x98\x4b\x13\x67\x07\x04\x98\xcb\xd8\x47" \
+"\x05\x8b\x41\xeb\x98\x4b\x75\x8f\x98\xcb\x02\x47\x13\x07\x07\x10" \
+"\x3a\xc0\x22\x47\x7d\x17\x3a\xc4\x69\xfb\x93\x77\x85\x00\xd5\xcb" \
+"\x93\x07\xf6\x0f\x2e\xc0\xa1\x83\x3e\xc4\x37\x27\x02\x40\x1c\x4b" \
+"\xc1\x66\x41\x68\xd5\x8f\x1c\xcb\xb7\x16\x00\x20\xb7\x27\x02\x40" \
+"\x93\x08\x00\x04\x37\x03\x20\x00\x98\x4b\x33\x67\x07\x01\x98\xcb" \
+"\xd8\x47\x05\x8b\x75\xff\x02\x47\x3a\xc2\x46\xc6\x32\x47\x0d\xef" \
+"\x98\x4b\x33\x67\x67\x00\x98\xcb\xd8\x47\x05\x8b\x75\xff\xd8\x47" \
+"\x41\x8b\x39\xc3\xd8\x47\xc1\x76\xfd\x16\x13\x67\x07\x01\xd8\xc7" \
+"\x98\x4b\x21\x45\x75\x8f\x98\xcb\x41\x01\x02\x90\x23\x20\xd8\x00" \
+"\x25\xb7\x23\x20\x03\x01\xa5\xb7\x12\x47\x13\x8e\x46\x00\x94\x42" \
+"\x14\xc3\x12\x47\x11\x07\x3a\xc2\x32\x47\x7d\x17\x3a\xc6\xd8\x47" \
+"\x09\x8b\x75\xff\xf2\x86\x5d\xb7\x02\x47\x13\x07\x07\x10\x3a\xc0" \
+"\x22\x47\x7d\x17\x3a\xc4\x49\xf3\x98\x4b\xc1\x76\xfd\x16\x75\x8f" \
+"\x98\xcb\x41\x89\x15\xc9\x2e\xc0\x0d\x06\x02\xc4\x09\x82\x32\xc6" \
+"\xb7\x17\x00\x20\x98\x43\x13\x86\x47\x00\xa2\x47\x82\x46\x8a\x07" \
+"\xb6\x97\x9c\x43\x63\x1c\xf7\x00\xa2\x47\x85\x07\x3e\xc4\xa2\x46" \
+"\x32\x47\xb2\x87\xe3\xe0\xe6\xfe\x01\x45\xbd\xbf\x41\x45\xad\xbf" \
+"\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" \
+"\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" \
 "\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";
 
 int bootloader_len = 512;
 #endif
 
-#if 0
 static int InternalLinkEHaltMode( void * d, int mode )
 {
 	libusb_device_handle * dev = ((struct LinkEProgrammerStruct*)d)->devh;
@@ -432,7 +466,6 @@ static int InternalLinkEHaltMode( void * d, int mode )
 	}
 	return 0;
 }
-#endif
 
 #if 0
 static int LEReadBinaryBlob( void * d, uint32_t offset, uint32_t amount, uint8_t * readbuff )
@@ -494,10 +527,10 @@ static int LEReadBinaryBlob( void * d, uint32_t offset, uint32_t amount, uint8_t
 }
 #endif
 
-#if 0
 static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, uint8_t * blob )
 {
 	libusb_device_handle * dev = ((struct LinkEProgrammerStruct*)d)->devh;
+	struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal);
 
 	InternalLinkEHaltMode( d, 0 );
 
@@ -506,7 +539,7 @@ static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len,
 	uint8_t rbuff[1024];
 	int transferred;
 
-	int padlen = ((len-1) & (~0x3f)) + 0x40;
+	int padlen = ((len-1) & (~(iss->sector_size-1)) + iss->sector_size;
 
 	wch_link_command( (libusb_device_handle *)dev, "\x81\x06\x01\x01", 4, 0, 0, 0 );
 	wch_link_command( (libusb_device_handle *)dev, "\x81\x06\x01\x01", 4, 0, 0, 0 ); // Not sure why but it seems to work better when we request twice.
@@ -521,9 +554,9 @@ static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len,
 	wch_link_command( (libusb_device_handle *)dev, "\x81\x02\x01\x05", 4, 0, 0, 0 );
 	
 	int pplace = 0;
-	for( pplace = 0; pplace < bootloader_len; pplace += 64 )
+	for( pplace = 0; pplace < bootloader_len; pplace += iss->sector_size )
 	{
-		WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, (uint8_t*)(bootloader+pplace), 64, &transferred, WCHTIMEOUT ) );
+		WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, (uint8_t*)(bootloader+pplace), iss->sector_size, &transferred, WCHTIMEOUT ) );
 	}
 	
 	for( i = 0; i < 10; i++ )
@@ -542,24 +575,23 @@ static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len,
 	
 	wch_link_command( (libusb_device_handle *)dev, "\x81\x02\x01\x02", 4, 0, 0, 0 );
 
-	for( pplace = 0; pplace < padlen; pplace += 64 )
+	for( pplace = 0; pplace < padlen; pplace += iss->sector_size )
 	{
-		if( pplace + 64 > len )
+		if( pplace + iss->sector_size > len )
 		{
-			uint8_t paddeddata[64];
-			int gap = pplace + 64 - len;
+			uint8_t paddeddata[iss->sector_size];
+			int gap = pplace + iss->sector_size - len;
 			int okcopy = len - pplace;
 			memcpy( paddeddata, blob + pplace, okcopy );
 			memset( paddeddata + okcopy, 0xff, gap );
-			WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, paddeddata, 64, &transferred, WCHTIMEOUT ) );
+			WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, paddeddata, iss->sector_size, &transferred, WCHTIMEOUT ) );
 		}
 		else
 		{
-			WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, blob+pplace, 64, &transferred, WCHTIMEOUT ) );
+			WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, blob+pplace, iss->sector_size, &transferred, WCHTIMEOUT ) );
 		}
 	}
 	return 0;
 }
 
 
-#endif
-- 
GitLab