457 lines
10 KiB
C
457 lines
10 KiB
C
|
#include <stdint.h>
|
||
|
#include "hidapi.c"
|
||
|
#include "minichlink.h"
|
||
|
|
||
|
struct ESP32ProgrammerStruct
|
||
|
{
|
||
|
void * internal;
|
||
|
|
||
|
hid_device * hd;
|
||
|
uint32_t state;
|
||
|
uint8_t commandbuffer[256];
|
||
|
int commandplace;
|
||
|
uint8_t reply[256];
|
||
|
int replylen;
|
||
|
|
||
|
int dev_version;
|
||
|
};
|
||
|
|
||
|
int ESPFlushLLCommands( void * dev );
|
||
|
|
||
|
static inline int SRemain( struct ESP32ProgrammerStruct * e )
|
||
|
{
|
||
|
return sizeof( e->commandbuffer ) - e->commandplace - 2; //Need room for EOF.
|
||
|
}
|
||
|
|
||
|
static inline void Write4LE( struct ESP32ProgrammerStruct * e, uint32_t val )
|
||
|
{
|
||
|
if( SRemain( e ) < 4 ) return;
|
||
|
uint8_t * d = e->commandbuffer + e->commandplace;
|
||
|
d[0] = val & 0xff;
|
||
|
d[1] = (val>>8) & 0xff;
|
||
|
d[2] = (val>>16) & 0xff;
|
||
|
d[3] = (val>>24) & 0xff;
|
||
|
e->commandplace += 4;
|
||
|
}
|
||
|
|
||
|
static inline void Write2LE( struct ESP32ProgrammerStruct * e, uint16_t val )
|
||
|
{
|
||
|
if( SRemain( e ) < 2 ) return;
|
||
|
uint8_t * d = e->commandbuffer + e->commandplace;
|
||
|
d[0] = val & 0xff;
|
||
|
d[1] = (val>>8) & 0xff;
|
||
|
e->commandplace += 2;
|
||
|
}
|
||
|
|
||
|
static inline void Write1( struct ESP32ProgrammerStruct * e, uint8_t val )
|
||
|
{
|
||
|
if( SRemain( e ) < 1 ) return;
|
||
|
uint8_t * d = e->commandbuffer + e->commandplace;
|
||
|
d[0] = val & 0xff;
|
||
|
e->commandplace ++;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int ESPWriteReg32( void * dev, uint8_t reg_7_bit, uint32_t value )
|
||
|
{
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
// printf( "WriteReg: %02x -> %08x\n", reg_7_bit, value );
|
||
|
|
||
|
|
||
|
if( SRemain( eps ) < 5 ) ESPFlushLLCommands( eps );
|
||
|
|
||
|
Write1( eps, (reg_7_bit<<1) | 1 );
|
||
|
Write4LE( eps, value );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int ESPReadReg32( void * dev, uint8_t reg_7_bit, uint32_t * commandresp )
|
||
|
{
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
ESPFlushLLCommands( eps );
|
||
|
Write1( eps, (reg_7_bit<<1) | 0 );
|
||
|
|
||
|
ESPFlushLLCommands( eps );
|
||
|
|
||
|
// printf( "ReadReg: %02x -> %d\n", reg_7_bit,eps->replylen );
|
||
|
|
||
|
if( eps->replylen < 6 )
|
||
|
{
|
||
|
return -9;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
memcpy( commandresp, eps->reply+2, 4 );
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int ESPFlushLLCommands( void * dev )
|
||
|
{
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
|
||
|
if( eps->commandplace >= sizeof( eps->commandbuffer ) )
|
||
|
{
|
||
|
fprintf( stderr, "Error: Command buffer overflow\n" );
|
||
|
return -5;
|
||
|
}
|
||
|
|
||
|
if( eps->commandplace == 1 ) return 0;
|
||
|
|
||
|
int r;
|
||
|
|
||
|
eps->commandbuffer[0] = 0xad; // Key report ID
|
||
|
eps->commandbuffer[eps->commandplace] = 0xff;
|
||
|
|
||
|
#if 0
|
||
|
int i;
|
||
|
for( i = 0; i < eps->commandplace; i++ )
|
||
|
{
|
||
|
if( ( i & 0xff ) == 0 ) printf( "\n" );
|
||
|
printf( "%02x ", eps->commandbuffer[i] );
|
||
|
}
|
||
|
printf("\n" );
|
||
|
#endif
|
||
|
|
||
|
r = hid_send_feature_report( eps->hd, eps->commandbuffer, 255 );
|
||
|
eps->commandplace = 1;
|
||
|
if( r < 0 )
|
||
|
{
|
||
|
fprintf( stderr, "Error: Got error %d when sending hid feature report.\n", r );
|
||
|
exit( -9 );
|
||
|
}
|
||
|
retry:
|
||
|
eps->reply[0] = 0xad; // Key report ID
|
||
|
r = hid_get_feature_report( eps->hd, eps->reply, sizeof( eps->reply ) );
|
||
|
/*
|
||
|
int i;
|
||
|
printf( "RESP: %d\n",eps->reply[0] );
|
||
|
|
||
|
for( i = 0; i < eps->reply[0]; i++ )
|
||
|
{
|
||
|
printf( "%02x ", eps->reply[i+1] );
|
||
|
if( (i % 16) == 15 ) printf( "\n" );
|
||
|
}
|
||
|
printf( "\n" );*/
|
||
|
|
||
|
if( eps->reply[0] == 0xff ) goto retry;
|
||
|
//printf( ">:::%d: %02x %02x %02x %02x %02x %02x\n", eps->replylen, eps->reply[0], eps->reply[1], eps->reply[2], eps->reply[3], eps->reply[4], eps->reply[5] );
|
||
|
if( r < 0 )
|
||
|
{
|
||
|
fprintf( stderr, "Error: Got error %d when sending hid feature report.\n", r );
|
||
|
return r;
|
||
|
}
|
||
|
eps->replylen = eps->reply[0] + 1; // Include the header byte.
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
|
||
|
int ESPControl3v3( void * dev, int bOn )
|
||
|
{
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
|
||
|
if( SRemain( eps ) < 2 )
|
||
|
ESPFlushLLCommands( eps );
|
||
|
|
||
|
if( bOn )
|
||
|
Write2LE( eps, 0x03fe );
|
||
|
else
|
||
|
Write2LE( eps, 0x02fe );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int ESPReadWord( void * dev, uint32_t address_to_read, uint32_t * data )
|
||
|
{
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
//printf( "READ: %08x\n", address_to_read );
|
||
|
if( SRemain( eps ) < 6 )
|
||
|
ESPFlushLLCommands( eps );
|
||
|
|
||
|
Write2LE( eps, 0x09fe );
|
||
|
Write4LE( eps, address_to_read );
|
||
|
ESPFlushLLCommands( eps );
|
||
|
|
||
|
// printf( "Got: %d\n", eps->replylen );
|
||
|
if( eps->replylen < 5 )
|
||
|
{
|
||
|
return -9;
|
||
|
}
|
||
|
int tail = eps->replylen-5;
|
||
|
memcpy( data, eps->reply + tail + 1, 4 );
|
||
|
// printf( "Read Mem: %08x => %08x\n", address_to_read, *data );
|
||
|
return eps->reply[tail];
|
||
|
}
|
||
|
|
||
|
int ESPWriteWord( void * dev, uint32_t address_to_write, uint32_t data )
|
||
|
{
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
|
||
|
//printf( "WRITE: %08x\n", address_to_write );
|
||
|
|
||
|
if( SRemain( eps ) < 10 )
|
||
|
ESPFlushLLCommands( eps );
|
||
|
|
||
|
Write2LE( eps, 0x08fe );
|
||
|
Write4LE( eps, address_to_write );
|
||
|
Write4LE( eps, data );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int ESPDelayUS( void * dev, int microseconds )
|
||
|
{
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
if( SRemain( eps ) < 6 )
|
||
|
ESPFlushLLCommands( eps );
|
||
|
|
||
|
Write2LE( eps, 0x04fe );
|
||
|
Write2LE( eps, microseconds );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int ESPWaitForFlash( void * dev )
|
||
|
{
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
if( SRemain( eps ) < 2 )
|
||
|
ESPFlushLLCommands( eps );
|
||
|
Write2LE( eps, 0x06fe );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int ESPWaitForDoneOp( void * dev, int ignore )
|
||
|
{
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
if( SRemain( eps ) < 2 )
|
||
|
ESPFlushLLCommands( dev );
|
||
|
Write2LE( eps, 0x07fe );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int ESPExit( void * dev )
|
||
|
{
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
hid_close( eps->hd );
|
||
|
free( eps );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int ESPBlockWrite64( void * dev, uint32_t address_to_write, uint8_t * data )
|
||
|
{
|
||
|
int writeretry = 0;
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
ESPFlushLLCommands( dev );
|
||
|
|
||
|
retry:
|
||
|
|
||
|
if( eps->dev_version >= 2 && InternalIsMemoryErased( (struct InternalState*)eps->internal, address_to_write ) )
|
||
|
Write2LE( eps, 0x0efe );
|
||
|
else
|
||
|
Write2LE( eps, 0x0bfe );
|
||
|
Write4LE( eps, address_to_write );
|
||
|
|
||
|
int i;
|
||
|
int timeout = 0;
|
||
|
for( i = 0; i < 64; i++ ) Write1( eps, data[i] );
|
||
|
|
||
|
InternalMarkMemoryNotErased( (struct InternalState*)eps->internal, address_to_write );
|
||
|
|
||
|
do
|
||
|
{
|
||
|
ESPFlushLLCommands( dev );
|
||
|
timeout++;
|
||
|
if( timeout > 1000 )
|
||
|
{
|
||
|
fprintf( stderr, "Error: Timed out block-writing 64\n" );
|
||
|
return -49;
|
||
|
}
|
||
|
} while( eps->replylen < 2 );
|
||
|
|
||
|
if( eps->reply[1] )
|
||
|
{
|
||
|
fprintf( stderr, "Error: Got code %d from ESP write algo. %d [%02x %02x %02x]\n", (char)eps->reply[1], eps->replylen, eps->reply[0], eps->reply[1], eps->reply[2] );
|
||
|
if( writeretry < 10 )
|
||
|
{
|
||
|
writeretry++;
|
||
|
goto retry;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (char)eps->reply[1];
|
||
|
}
|
||
|
|
||
|
int ESPPerformSongAndDance( void * dev )
|
||
|
{
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
Write2LE( eps, 0x01fe );
|
||
|
ESPFlushLLCommands( dev );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int ESPVoidHighLevelState( void * dev )
|
||
|
{
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
Write2LE( eps, 0x05fe );
|
||
|
ESPFlushLLCommands( dev );
|
||
|
DefaultVoidHighLevelState( dev );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int ESPVendorCommand( void * dev, const char * cmd )
|
||
|
{
|
||
|
char command[10] = { 0 };
|
||
|
char tbuf[10] = { 0 };
|
||
|
int fields[10];
|
||
|
char c;
|
||
|
int i = 0;
|
||
|
int f = 0;
|
||
|
while( (c = *cmd++) )
|
||
|
{
|
||
|
if( c == ':' ) break;
|
||
|
if( c == '\0' ) break;
|
||
|
if( i + 1 >= sizeof( command )) break;
|
||
|
command[i++] = c;
|
||
|
command[i] = 0;
|
||
|
}
|
||
|
i = 0;
|
||
|
f = 0;
|
||
|
while( 1 )
|
||
|
{
|
||
|
c = *cmd++;
|
||
|
if( c == ':' || c == '\0' )
|
||
|
{
|
||
|
fields[f++] = SimpleReadNumberInt( tbuf, 0 );
|
||
|
puts( tbuf );
|
||
|
if( f == 10 ) break;
|
||
|
tbuf[0] = 0;
|
||
|
i = 0;
|
||
|
if( c == '\0' ) break;
|
||
|
continue;
|
||
|
}
|
||
|
if( i + 1 >= sizeof( tbuf )) break;
|
||
|
tbuf[i++] = c;
|
||
|
tbuf[i] = 0;
|
||
|
}
|
||
|
printf( "Got Vendor Command \"%s\"\n", command );
|
||
|
ESPFlushLLCommands( dev );
|
||
|
if( strcasecmp( command, "ECLK" ) == 0 )
|
||
|
{
|
||
|
printf( "Setting up external clock on pin.\n" );
|
||
|
if( f < 5 )
|
||
|
{
|
||
|
fprintf( stderr, "Error: Need fields :use_apll:sdm0:sdm1:sdm2:odiv try 1:0:0:8:3 for 24MHz\n" );
|
||
|
fprintf( stderr, "Definition:\n\
|
||
|
use_apll = Configures APLL = 480 / 4 = 120\n\
|
||
|
40 * (SDM2 + SDM1/(2^8) + SDM0/(2^16) + 4) / ( 2 * (ODIV+2) );\n\
|
||
|
Datasheet recommends that numerator is between 300 and 500MHz.\n ");
|
||
|
return -9;
|
||
|
}
|
||
|
Write2LE( dev, 0x0cfe );
|
||
|
Write1( dev, fields[0] );
|
||
|
Write1( dev, fields[1] );
|
||
|
Write1( dev, fields[2] );
|
||
|
Write1( dev, fields[3] );
|
||
|
Write1( dev, fields[4] );
|
||
|
Write1( dev, 0 );
|
||
|
Write1( dev, 0 );
|
||
|
Write1( dev, 0 );
|
||
|
ESPFlushLLCommands( dev );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fprintf( stderr, "Error: Unknown vendor command %s\n", command );
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int ESPPollTerminal( void * dev, uint8_t * buffer, int maxlen, uint32_t leaveflagA, int leaveflagB )
|
||
|
{
|
||
|
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
|
||
|
ESPFlushLLCommands( dev );
|
||
|
Write1( dev, 0xfe );
|
||
|
Write1( dev, 0x0d );
|
||
|
Write4LE( dev, leaveflagA );
|
||
|
Write4LE( dev, leaveflagB );
|
||
|
Write1( dev, 0xff );
|
||
|
|
||
|
ESPFlushLLCommands( dev );
|
||
|
|
||
|
int rlen = eps->reply[0];
|
||
|
if( rlen < 1 ) return -8;
|
||
|
|
||
|
|
||
|
#if 0
|
||
|
int i;
|
||
|
|
||
|
printf( "RESP (ML %d): %d\n", maxlen,eps->reply[0] );
|
||
|
|
||
|
for( i = 0; i < eps->reply[0]; i++ )
|
||
|
{
|
||
|
printf( "%02x ", eps->reply[i+1] );
|
||
|
if( (i % 16) == 15 ) printf( "\n" );
|
||
|
}
|
||
|
printf( "\n" );
|
||
|
#endif
|
||
|
|
||
|
int errc = eps->reply[1];
|
||
|
if( errc > 7 ) return -7;
|
||
|
|
||
|
if( rlen - 1 >= maxlen ) return -6;
|
||
|
|
||
|
memcpy( buffer, eps->reply + 2, rlen - 1 );
|
||
|
|
||
|
return rlen - 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
void * TryInit_ESP32S2CHFUN()
|
||
|
{
|
||
|
#define VID 0x303a
|
||
|
#define PID 0x4004
|
||
|
hid_init();
|
||
|
hid_device * hd = hid_open( VID, PID, L"s2-ch32xx-pgm-v0"); // third parameter is "serial"
|
||
|
if( !hd ) return 0;
|
||
|
|
||
|
struct ESP32ProgrammerStruct * eps = malloc( sizeof( struct ESP32ProgrammerStruct ) );
|
||
|
memset( eps, 0, sizeof( *eps ) );
|
||
|
eps->hd = hd;
|
||
|
eps->commandplace = 1;
|
||
|
eps->dev_version = 0;
|
||
|
|
||
|
memset( &MCF, 0, sizeof( MCF ) );
|
||
|
MCF.WriteReg32 = ESPWriteReg32;
|
||
|
MCF.ReadReg32 = ESPReadReg32;
|
||
|
MCF.FlushLLCommands = ESPFlushLLCommands;
|
||
|
MCF.DelayUS = ESPDelayUS;
|
||
|
MCF.Control3v3 = ESPControl3v3;
|
||
|
MCF.Exit = ESPExit;
|
||
|
MCF.VoidHighLevelState = ESPVoidHighLevelState;
|
||
|
MCF.PollTerminal = ESPPollTerminal;
|
||
|
|
||
|
// These are optional. Disabling these is a good mechanismto make sure the core functions still work.
|
||
|
MCF.WriteWord = ESPWriteWord;
|
||
|
MCF.ReadWord = ESPReadWord;
|
||
|
|
||
|
MCF.WaitForFlash = ESPWaitForFlash;
|
||
|
MCF.WaitForDoneOp = ESPWaitForDoneOp;
|
||
|
|
||
|
MCF.PerformSongAndDance = ESPPerformSongAndDance;
|
||
|
|
||
|
MCF.BlockWrite64 = ESPBlockWrite64;
|
||
|
MCF.VendorCommand = ESPVendorCommand;
|
||
|
|
||
|
// Reset internal programmer state.
|
||
|
Write2LE( eps, 0x0afe );
|
||
|
ESPFlushLLCommands( eps );
|
||
|
Write2LE( eps, 0xfefe );
|
||
|
ESPFlushLLCommands( eps );
|
||
|
if( eps->replylen > 1 )
|
||
|
{
|
||
|
eps->dev_version = eps->reply[1];
|
||
|
}
|
||
|
return eps;
|
||
|
}
|
||
|
|
||
|
|