|
|
@ -10,8 +10,11 @@ |
|
|
|
#include "serbridge.h" |
|
|
|
#include "serbridge.h" |
|
|
|
#include "serled.h" |
|
|
|
#include "serled.h" |
|
|
|
|
|
|
|
|
|
|
|
#define SYNC_TIMEOUT (2000) // to achieve sync, in milliseconds
|
|
|
|
#define SYNC_TIMEOUT 3600 // to achieve sync on initial baud rate, in milliseconds
|
|
|
|
#define PGM_TIMEOUT (20000) // when sync is achieved, in milliseconds
|
|
|
|
#define SYNC_INTERVAL 25 // interval at which we try to sync
|
|
|
|
|
|
|
|
#define BAUD_INTERVAL 400 // interval after which we change baud rate
|
|
|
|
|
|
|
|
#define PGM_TIMEOUT 20000 // timeout when sync is achieved, in milliseconds
|
|
|
|
|
|
|
|
#define PGM_INTERVAL 200 // send sync at this interval in ms when in programming mode
|
|
|
|
|
|
|
|
|
|
|
|
#define OPTIBOOT_DBG |
|
|
|
#define OPTIBOOT_DBG |
|
|
|
#undef DBG |
|
|
|
#undef DBG |
|
|
@ -21,7 +24,7 @@ |
|
|
|
#define DBG(format, ...) do { } while(0) |
|
|
|
#define DBG(format, ...) do { } while(0) |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
#define DBG_GPIO5 0 // define to 1 to use GPIO5 to trigger scope
|
|
|
|
#define DBG_GPIO5 1 // define to 1 to use GPIO5 to trigger scope
|
|
|
|
|
|
|
|
|
|
|
|
//===== global state
|
|
|
|
//===== global state
|
|
|
|
|
|
|
|
|
|
|
@ -35,8 +38,10 @@ static enum { // overall programming states |
|
|
|
stateProg, // programming...
|
|
|
|
stateProg, // programming...
|
|
|
|
} progState; |
|
|
|
} progState; |
|
|
|
static short syncCnt; // counter & timeout for sync attempts
|
|
|
|
static short syncCnt; // counter & timeout for sync attempts
|
|
|
|
|
|
|
|
static short baudCnt; // counter for sync attempts at different baud rates
|
|
|
|
static short ackWait; // counter of expected ACKs
|
|
|
|
static short ackWait; // counter of expected ACKs
|
|
|
|
static uint16_t optibootVers; |
|
|
|
static uint16_t optibootVers; |
|
|
|
|
|
|
|
static uint32_t baudRate; // baud rate at which we're programming
|
|
|
|
|
|
|
|
|
|
|
|
#define RESP_SZ 64 |
|
|
|
#define RESP_SZ 64 |
|
|
|
static char responseBuf[RESP_SZ]; // buffer to accumulate responses from optiboot
|
|
|
|
static char responseBuf[RESP_SZ]; // buffer to accumulate responses from optiboot
|
|
|
@ -65,11 +70,14 @@ static void optibootTimerCB(void *); |
|
|
|
static void optibootUartRecv(char *buffer, short length); |
|
|
|
static void optibootUartRecv(char *buffer, short length); |
|
|
|
static bool processRecord(char *buf, short len); |
|
|
|
static bool processRecord(char *buf, short len); |
|
|
|
static bool programPage(void); |
|
|
|
static bool programPage(void); |
|
|
|
static void ICACHE_FLASH_ATTR armTimer(); |
|
|
|
static void armTimer(void); |
|
|
|
|
|
|
|
static void initBaud(void); |
|
|
|
|
|
|
|
|
|
|
|
static void ICACHE_FLASH_ATTR optibootInit() { |
|
|
|
static void ICACHE_FLASH_ATTR optibootInit() { |
|
|
|
progState = stateSync; |
|
|
|
progState = stateSync; |
|
|
|
syncCnt = 0; |
|
|
|
syncCnt = 0; |
|
|
|
|
|
|
|
baudCnt = 0; |
|
|
|
|
|
|
|
uart0_baud(flashConfig.baud_rate); |
|
|
|
ackWait = 0; |
|
|
|
ackWait = 0; |
|
|
|
errMessage[0] = 0; |
|
|
|
errMessage[0] = 0; |
|
|
|
responseLen = 0; |
|
|
|
responseLen = 0; |
|
|
@ -88,14 +96,12 @@ static void ICACHE_FLASH_ATTR optibootInit() { |
|
|
|
|
|
|
|
|
|
|
|
// append one string to another but visually escape non-printing characters in the second
|
|
|
|
// append one string to another but visually escape non-printing characters in the second
|
|
|
|
// string using \x00 hex notation, max is the max chars in the concatenated string.
|
|
|
|
// string using \x00 hex notation, max is the max chars in the concatenated string.
|
|
|
|
void ICACHE_FLASH_ATTR appendPretty(char *buf, char *raw, int max) { |
|
|
|
void ICACHE_FLASH_ATTR appendPretty(char *buf, int max, char *raw, int rawLen) { |
|
|
|
int off = strlen(buf); |
|
|
|
int off = strlen(buf); |
|
|
|
int i = 0; |
|
|
|
max -= off + 1; // for null termination
|
|
|
|
while (off < max-5) { |
|
|
|
for (int i=0; i<max && i<rawLen; i++) { |
|
|
|
unsigned char c = raw[i++]; |
|
|
|
unsigned char c = raw[i++]; |
|
|
|
if (c == 0) { |
|
|
|
if (c >= ' ' && c <= '~') { |
|
|
|
break; |
|
|
|
|
|
|
|
} else if (c >= ' ' && c <= '~') { |
|
|
|
|
|
|
|
buf[off++] = c; |
|
|
|
buf[off++] = c; |
|
|
|
} else if (c == '\n') { |
|
|
|
} else if (c == '\n') { |
|
|
|
buf[off++] = '\\'; |
|
|
|
buf[off++] = '\\'; |
|
|
@ -124,7 +130,9 @@ int ICACHE_FLASH_ATTR cgiOptibootSync(HttpdConnData *connData) { |
|
|
|
} else if (connData->requestType == HTTPD_METHOD_POST) { |
|
|
|
} else if (connData->requestType == HTTPD_METHOD_POST) { |
|
|
|
// issue reset
|
|
|
|
// issue reset
|
|
|
|
optibootInit(); |
|
|
|
optibootInit(); |
|
|
|
|
|
|
|
baudRate = flashConfig.baud_rate; |
|
|
|
programmingCB = optibootUartRecv; |
|
|
|
programmingCB = optibootUartRecv; |
|
|
|
|
|
|
|
initBaud(); |
|
|
|
serbridgeReset(); |
|
|
|
serbridgeReset(); |
|
|
|
#if DBG_GPIO5 |
|
|
|
#if DBG_GPIO5 |
|
|
|
makeGpio(5); |
|
|
|
makeGpio(5); |
|
|
@ -147,13 +155,14 @@ int ICACHE_FLASH_ATTR cgiOptibootSync(HttpdConnData *connData) { |
|
|
|
if (!errMessage[0] && progState >= stateProg) { |
|
|
|
if (!errMessage[0] && progState >= stateProg) { |
|
|
|
char buf[64]; |
|
|
|
char buf[64]; |
|
|
|
DBG("OB got sync\n"); |
|
|
|
DBG("OB got sync\n"); |
|
|
|
os_sprintf(buf, "SYNC : Optiboot %d.%d", optibootVers>>8, optibootVers&0xff); |
|
|
|
os_sprintf(buf, "SYNC at %ld baud: Optiboot %d.%d", |
|
|
|
|
|
|
|
baudRate, optibootVers>>8, optibootVers&0xff); |
|
|
|
httpdSend(connData, buf, -1); |
|
|
|
httpdSend(connData, buf, -1); |
|
|
|
} else if (errMessage[0] && progState == stateSync) { |
|
|
|
} else if (errMessage[0] && progState == stateSync) { |
|
|
|
DBG("OB cannot sync\n"); |
|
|
|
DBG("OB cannot sync\n"); |
|
|
|
char buf[512]; |
|
|
|
char buf[512]; |
|
|
|
os_sprintf(buf, "FAILED to SYNC: %s, got:\r\n", errMessage); |
|
|
|
os_sprintf(buf, "FAILED to SYNC: %s, got: %d chars\r\n", errMessage, responseLen); |
|
|
|
appendPretty(buf, responseBuf, 512); |
|
|
|
appendPretty(buf, 512, responseBuf, responseLen); |
|
|
|
httpdSend(connData, buf, -1); |
|
|
|
httpdSend(connData, buf, -1); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
httpdSend(connData, errMessage[0] ? errMessage : "NOT READY", -1); |
|
|
|
httpdSend(connData, errMessage[0] ? errMessage : "NOT READY", -1); |
|
|
@ -306,9 +315,9 @@ int ICACHE_FLASH_ATTR cgiOptibootData(HttpdConnData *connData) { |
|
|
|
float dt = ((system_get_time() - optibootData->startTime)/1000)/1000.0; // in seconds
|
|
|
|
float dt = ((system_get_time() - optibootData->startTime)/1000)/1000.0; // in seconds
|
|
|
|
uint16_t pgmDone = optibootData->pgmDone; |
|
|
|
uint16_t pgmDone = optibootData->pgmDone; |
|
|
|
optibootInit(); |
|
|
|
optibootInit(); |
|
|
|
os_sprintf(errMessage, "Success. %d bytes in %d.%ds, %dB/s %d%% efficient", |
|
|
|
os_sprintf(errMessage, "Success. %d bytes at %ld baud in %d.%ds, %dB/s %d%% efficient", |
|
|
|
pgmDone, (int)dt, (int)(dt*10)%10, (int)(pgmDone/dt), |
|
|
|
pgmDone, baudRate, (int)dt, (int)(dt*10)%10, (int)(pgmDone/dt), |
|
|
|
(int)(100.0*(10.0*pgmDone/flashConfig.baud_rate)/dt)); |
|
|
|
(int)(100.0*(10.0*pgmDone/baudRate)/dt)); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
code = 400; |
|
|
|
code = 400; |
|
|
|
optibootInit(); |
|
|
|
optibootInit(); |
|
|
@ -484,24 +493,43 @@ static bool ICACHE_FLASH_ATTR programPage(void) { |
|
|
|
static void ICACHE_FLASH_ATTR armTimer() { |
|
|
|
static void ICACHE_FLASH_ATTR armTimer() { |
|
|
|
os_timer_disarm(&optibootTimer); |
|
|
|
os_timer_disarm(&optibootTimer); |
|
|
|
// time-out every 50ms, except when programming to allow for 9600baud (133ms for 128 bytes)
|
|
|
|
// time-out every 50ms, except when programming to allow for 9600baud (133ms for 128 bytes)
|
|
|
|
os_timer_arm(&optibootTimer, progState==stateProg ? 200 : 50, 0); |
|
|
|
os_timer_arm(&optibootTimer, progState==stateProg ? PGM_INTERVAL : SYNC_INTERVAL, 0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int baudRates[] = { 0, 9600, 57600, 115200 }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void ICACHE_FLASH_ATTR setBaud() { |
|
|
|
|
|
|
|
baudRate = baudRates[(syncCnt / (BAUD_INTERVAL/SYNC_INTERVAL)) % 4]; |
|
|
|
|
|
|
|
uart0_baud(baudRate); |
|
|
|
|
|
|
|
//DBG("OB changing to %d baud\n", b);
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void ICACHE_FLASH_ATTR initBaud() { |
|
|
|
|
|
|
|
baudRates[0] = flashConfig.baud_rate; |
|
|
|
|
|
|
|
setBaud(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void ICACHE_FLASH_ATTR optibootTimerCB(void *arg) { |
|
|
|
static void ICACHE_FLASH_ATTR optibootTimerCB(void *arg) { |
|
|
|
// see whether we've issued so many sync in a row that it's time to give up
|
|
|
|
// see whether we've issued so many sync in a row that it's time to give up
|
|
|
|
syncCnt++; |
|
|
|
syncCnt++; |
|
|
|
if ((progState == stateSync && syncCnt > SYNC_TIMEOUT/50) || |
|
|
|
|
|
|
|
syncCnt > PGM_TIMEOUT/50) { |
|
|
|
|
|
|
|
DBG("OB abandoned after timeout, state=%d syncCnt=%d\n", progState, syncCnt); |
|
|
|
|
|
|
|
optibootInit(); |
|
|
|
|
|
|
|
strcpy(errMessage, "abandoned after timeout"); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (progState) { |
|
|
|
switch (progState) { |
|
|
|
case stateSync: // we're trying to get sync, all we do here is send a sync request
|
|
|
|
case stateSync: // we're trying to get sync, all we do here is send a sync request
|
|
|
|
uart0_write_char(STK_GET_SYNC); |
|
|
|
if (syncCnt >= SYNC_TIMEOUT/SYNC_INTERVAL) { |
|
|
|
uart0_write_char(CRC_EOP); |
|
|
|
// we're doomed, give up
|
|
|
|
|
|
|
|
DBG("OB sync abandoned after timeout, state=%d syncCnt=%d\n", progState, syncCnt); |
|
|
|
|
|
|
|
optibootInit(); |
|
|
|
|
|
|
|
strcpy(errMessage, "sync abandoned after timeout"); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (syncCnt % (BAUD_INTERVAL/SYNC_INTERVAL) == 0) { |
|
|
|
|
|
|
|
// time to switch baud rate and issue a reset
|
|
|
|
|
|
|
|
setBaud(); |
|
|
|
|
|
|
|
serbridgeReset(); |
|
|
|
|
|
|
|
// no point sending chars if we just switched
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
uart0_write_char(STK_GET_SYNC); |
|
|
|
|
|
|
|
uart0_write_char(CRC_EOP); |
|
|
|
|
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
|
case stateProg: // we're programming and we timed-out of inaction
|
|
|
|
case stateProg: // we're programming and we timed-out of inaction
|
|
|
|
uart0_write_char(STK_GET_SYNC); |
|
|
|
uart0_write_char(STK_GET_SYNC); |
|
|
|