@ -27,16 +27,16 @@ Some flash handling cgi routines. Used for reading the existing flash and updati
// Check that the header of the firmware blob looks like actual firmware...
// Check that the header of the firmware blob looks like actual firmware...
static char * ICACHE_FLASH_ATTR check_header ( void * buf ) {
static char * ICACHE_FLASH_ATTR check_header ( void * buf ) {
uint8_t * cd = ( uint8_t * ) buf ;
uint8_t * cd = ( uint8_t * ) buf ;
# ifdef CGIFLASH_DBG
# ifdef CGIFLASH_DBG
uint32_t * buf32 = buf ;
uint32_t * buf32 = buf ;
os_printf ( " %p: %08lX %08lX %08lX %08lX \n " , buf , buf32 [ 0 ] , buf32 [ 1 ] , buf32 [ 2 ] , buf32 [ 3 ] ) ;
os_printf ( " %p: %08lX %08lX %08lX %08lX \n " , buf , buf32 [ 0 ] , buf32 [ 1 ] , buf32 [ 2 ] , buf32 [ 3 ] ) ;
# endif
# endif
if ( cd [ 0 ] ! = 0xEA ) return " IROM magic missing " ;
if ( cd [ 0 ] ! = 0xEA ) return " IROM magic missing " ;
if ( cd [ 1 ] ! = 4 | | cd [ 2 ] > 3 | | ( cd [ 3 ] > > 4 ) > 6 ) return " bad flash header " ;
if ( cd [ 1 ] ! = 4 | | cd [ 2 ] > 3 | | ( cd [ 3 ] > > 4 ) > 6 ) return " bad flash header " ;
if ( ( ( uint16_t * ) buf ) [ 3 ] ! = 0x4010 ) return " Invalid entry addr " ;
if ( ( ( uint16_t * ) buf ) [ 3 ] ! = 0x4010 ) return " Invalid entry addr " ;
if ( ( ( uint32_t * ) buf ) [ 2 ] ! = 0 ) return " Invalid start offset " ;
if ( ( ( uint32_t * ) buf ) [ 2 ] ! = 0 ) return " Invalid start offset " ;
return NULL ;
return NULL ;
}
}
// check whether the flash map/size we have allows for OTA upgrade
// check whether the flash map/size we have allows for OTA upgrade
@ -49,143 +49,143 @@ static char *flash_too_small = "Flash too small for OTA update";
//===== Cgi to query which firmware needs to be uploaded next
//===== Cgi to query which firmware needs to be uploaded next
int ICACHE_FLASH_ATTR cgiGetFirmwareNext ( HttpdConnData * connData ) {
int ICACHE_FLASH_ATTR cgiGetFirmwareNext ( HttpdConnData * connData ) {
if ( connData - > conn = = NULL ) return HTTPD_CGI_DONE ; // Connection aborted. Clean up.
if ( connData - > conn = = NULL ) return HTTPD_CGI_DONE ; // Connection aborted. Clean up.
if ( ! canOTA ( ) ) {
if ( ! canOTA ( ) ) {
errorResponse ( connData , 400 , flash_too_small ) ;
errorResponse ( connData , 400 , flash_too_small ) ;
return HTTPD_CGI_DONE ;
return HTTPD_CGI_DONE ;
}
}
uint8 id = system_upgrade_userbin_check ( ) ;
uint8 id = system_upgrade_userbin_check ( ) ;
httpdStartResponse ( connData , 200 ) ;
httpdStartResponse ( connData , 200 ) ;
httpdHeader ( connData , " Content-Type " , " text/plain " ) ;
httpdHeader ( connData , " Content-Type " , " text/plain " ) ;
httpdHeader ( connData , " Content-Length " , " 9 " ) ;
httpdHeader ( connData , " Content-Length " , " 9 " ) ;
httpdEndHeaders ( connData ) ;
httpdEndHeaders ( connData ) ;
char * next = id = = 1 ? " user1.bin " : " user2.bin " ;
char * next = id = = 1 ? " user1.bin " : " user2.bin " ;
httpdSend ( connData , next , - 1 ) ;
httpdSend ( connData , next , - 1 ) ;
DBG ( " Next firmware: %s (got %d) \n " , next , id ) ;
DBG ( " Next firmware: %s (got %d) \n " , next , id ) ;
return HTTPD_CGI_DONE ;
return HTTPD_CGI_DONE ;
}
}
//===== Cgi that allows the firmware to be replaced via http POST
//===== Cgi that allows the firmware to be replaced via http POST
int ICACHE_FLASH_ATTR cgiUploadFirmware ( HttpdConnData * connData ) {
int ICACHE_FLASH_ATTR cgiUploadFirmware ( HttpdConnData * connData ) {
if ( connData - > conn = = NULL ) return HTTPD_CGI_DONE ; // Connection aborted. Clean up.
if ( connData - > conn = = NULL ) return HTTPD_CGI_DONE ; // Connection aborted. Clean up.
if ( ! canOTA ( ) ) {
if ( ! canOTA ( ) ) {
errorResponse ( connData , 400 , flash_too_small ) ;
errorResponse ( connData , 400 , flash_too_small ) ;
return HTTPD_CGI_DONE ;
return HTTPD_CGI_DONE ;
}
}
int offset = connData - > post - > received - connData - > post - > buffLen ;
int offset = connData - > post - > received - connData - > post - > buffLen ;
if ( offset = = 0 ) {
if ( offset = = 0 ) {
connData - > cgiPrivData = NULL ;
connData - > cgiPrivData = NULL ;
} else if ( connData - > cgiPrivData ! = NULL ) {
} else if ( connData - > cgiPrivData ! = NULL ) {
// we have an error condition, do nothing
// we have an error condition, do nothing
return HTTPD_CGI_DONE ;
return HTTPD_CGI_DONE ;
}
}
// assume no error yet...
// assume no error yet...
char * err = NULL ;
char * err = NULL ;
int code = 400 ;
int code = 400 ;
// check overall size
// check overall size
//os_printf("FW: %d (max %d)\n", connData->post->len, FIRMWARE_SIZE);
//os_printf("FW: %d (max %d)\n", connData->post->len, FIRMWARE_SIZE);
if ( connData - > post - > len > FIRMWARE_SIZE ) err = " Firmware image too large " ;
if ( connData - > post - > len > FIRMWARE_SIZE ) err = " Firmware image too large " ;
if ( connData - > post - > buff = = NULL | | connData - > requestType ! = HTTPD_METHOD_POST | |
if ( connData - > post - > buff = = NULL | | connData - > requestType ! = HTTPD_METHOD_POST | |
connData - > post - > len < 1024 ) err = " Invalid request " ;
connData - > post - > len < 1024 ) err = " Invalid request " ;
// check that data starts with an appropriate header
// check that data starts with an appropriate header
if ( err = = NULL & & offset = = 0 ) err = check_header ( connData - > post - > buff ) ;
if ( err = = NULL & & offset = = 0 ) err = check_header ( connData - > post - > buff ) ;
// make sure we're buffering in 1024 byte chunks
// make sure we're buffering in 1024 byte chunks
if ( err = = NULL & & offset % 1024 ! = 0 ) {
if ( err = = NULL & & offset % 1024 ! = 0 ) {
err = " Buffering problem " ;
err = " Buffering problem " ;
code = 500 ;
code = 500 ;
}
}
// return an error if there is one
// return an error if there is one
if ( err ! = NULL ) {
if ( err ! = NULL ) {
DBG ( " Error %d: %s \n " , code , err ) ;
DBG ( " Error %d: %s \n " , code , err ) ;
httpdStartResponse ( connData , code ) ;
httpdStartResponse ( connData , code ) ;
httpdHeader ( connData , " Content-Type " , " text/plain " ) ;
httpdHeader ( connData , " Content-Type " , " text/plain " ) ;
//httpdHeader(connData, "Content-Length", strlen(err)+2);
//httpdHeader(connData, "Content-Length", strlen(err)+2);
httpdEndHeaders ( connData ) ;
httpdEndHeaders ( connData ) ;
httpdSend ( connData , err , - 1 ) ;
httpdSend ( connData , err , - 1 ) ;
httpdSend ( connData , " \r \n " , - 1 ) ;
httpdSend ( connData , " \r \n " , - 1 ) ;
connData - > cgiPrivData = ( void * ) 1 ;
connData - > cgiPrivData = ( void * ) 1 ;
return HTTPD_CGI_DONE ;
return HTTPD_CGI_DONE ;
}
}
// let's see which partition we need to flash and what flash address that puts us at
// let's see which partition we need to flash and what flash address that puts us at
uint8 id = system_upgrade_userbin_check ( ) ;
uint8 id = system_upgrade_userbin_check ( ) ;
int address = id = = 1 ? 4 * 1024 // either start after 4KB boot partition
int address = id = = 1 ? 4 * 1024 // either start after 4KB boot partition
: 4 * 1024 + FIRMWARE_SIZE + 16 * 1024 + 4 * 1024 ; // 4KB boot, fw1, 16KB user param, 4KB reserved
: 4 * 1024 + FIRMWARE_SIZE + 16 * 1024 + 4 * 1024 ; // 4KB boot, fw1, 16KB user param, 4KB reserved
address + = offset ;
address + = offset ;
// erase next flash block if necessary
// erase next flash block if necessary
if ( address % SPI_FLASH_SEC_SIZE = = 0 ) {
if ( address % SPI_FLASH_SEC_SIZE = = 0 ) {
DBG ( " Flashing 0x%05x (id=%d) \n " , address , 2 - id ) ;
DBG ( " Flashing 0x%05x (id=%d) \n " , address , 2 - id ) ;
spi_flash_erase_sector ( address / SPI_FLASH_SEC_SIZE ) ;
spi_flash_erase_sector ( address / SPI_FLASH_SEC_SIZE ) ;
}
}
// Write the data
// Write the data
//DBG("Writing %d bytes at 0x%05x (%d of %d)\n", connData->post->buffSize, address,
//DBG("Writing %d bytes at 0x%05x (%d of %d)\n", connData->post->buffSize, address,
// connData->post->received, connData->post->len);
// connData->post->received, connData->post->len);
spi_flash_write ( address , ( uint32 * ) connData - > post - > buff , connData - > post - > buffLen ) ;
spi_flash_write ( address , ( uint32 * ) connData - > post - > buff , connData - > post - > buffLen ) ;
if ( connData - > post - > received = = connData - > post - > len ) {
if ( connData - > post - > received = = connData - > post - > len ) {
httpdStartResponse ( connData , 200 ) ;
httpdStartResponse ( connData , 200 ) ;
httpdEndHeaders ( connData ) ;
httpdEndHeaders ( connData ) ;
return HTTPD_CGI_DONE ;
return HTTPD_CGI_DONE ;
} else {
} else {
return HTTPD_CGI_MORE ;
return HTTPD_CGI_MORE ;
}
}
}
}
static ETSTimer flash_reboot_timer ;
static ETSTimer flash_reboot_timer ;
// Handle request to reboot into the new firmware
// Handle request to reboot into the new firmware
int ICACHE_FLASH_ATTR cgiRebootFirmware ( HttpdConnData * connData ) {
int ICACHE_FLASH_ATTR cgiRebootFirmware ( HttpdConnData * connData ) {
if ( connData - > conn = = NULL ) return HTTPD_CGI_DONE ; // Connection aborted. Clean up.
if ( connData - > conn = = NULL ) return HTTPD_CGI_DONE ; // Connection aborted. Clean up.
if ( ! canOTA ( ) ) {
if ( ! canOTA ( ) ) {
errorResponse ( connData , 400 , flash_too_small ) ;
errorResponse ( connData , 400 , flash_too_small ) ;
return HTTPD_CGI_DONE ;
return HTTPD_CGI_DONE ;
}
}
// sanity-check that the 'next' partition actually contains something that looks like
// sanity-check that the 'next' partition actually contains something that looks like
// valid firmware
// valid firmware
uint8 id = system_upgrade_userbin_check ( ) ;
uint8 id = system_upgrade_userbin_check ( ) ;
int address = id = = 1 ? 4 * 1024 // either start after 4KB boot partition
int address = id = = 1 ? 4 * 1024 // either start after 4KB boot partition
: 4 * 1024 + FIRMWARE_SIZE + 16 * 1024 + 4 * 1024 ; // 4KB boot, fw1, 16KB user param, 4KB reserved
: 4 * 1024 + FIRMWARE_SIZE + 16 * 1024 + 4 * 1024 ; // 4KB boot, fw1, 16KB user param, 4KB reserved
uint32 buf [ 8 ] ;
uint32 buf [ 8 ] ;
DBG ( " Checking %p \n " , ( void * ) address ) ;
DBG ( " Checking %p \n " , ( void * ) address ) ;
spi_flash_read ( address , buf , sizeof ( buf ) ) ;
spi_flash_read ( address , buf , sizeof ( buf ) ) ;
char * err = check_header ( buf ) ;
char * err = check_header ( buf ) ;
if ( err ! = NULL ) {
if ( err ! = NULL ) {
DBG ( " Error %d: %s \n " , 400 , err ) ;
DBG ( " Error %d: %s \n " , 400 , err ) ;
httpdStartResponse ( connData , 400 ) ;
httpdStartResponse ( connData , 400 ) ;
httpdHeader ( connData , " Content-Type " , " text/plain " ) ;
httpdHeader ( connData , " Content-Type " , " text/plain " ) ;
//httpdHeader(connData, "Content-Length", strlen(err)+2);
//httpdHeader(connData, "Content-Length", strlen(err)+2);
httpdEndHeaders ( connData ) ;
httpdEndHeaders ( connData ) ;
httpdSend ( connData , err , - 1 ) ;
httpdSend ( connData , err , - 1 ) ;
httpdSend ( connData , " \r \n " , - 1 ) ;
httpdSend ( connData , " \r \n " , - 1 ) ;
return HTTPD_CGI_DONE ;
return HTTPD_CGI_DONE ;
}
}
httpdStartResponse ( connData , 200 ) ;
httpdStartResponse ( connData , 200 ) ;
httpdHeader ( connData , " Content-Length " , " 0 " ) ;
httpdHeader ( connData , " Content-Length " , " 0 " ) ;
httpdEndHeaders ( connData ) ;
httpdEndHeaders ( connData ) ;
// Schedule a reboot
// Schedule a reboot
system_upgrade_flag_set ( UPGRADE_FLAG_FINISH ) ;
system_upgrade_flag_set ( UPGRADE_FLAG_FINISH ) ;
os_timer_disarm ( & flash_reboot_timer ) ;
os_timer_disarm ( & flash_reboot_timer ) ;
os_timer_setfn ( & flash_reboot_timer , ( os_timer_func_t * ) system_upgrade_reboot , NULL ) ;
os_timer_setfn ( & flash_reboot_timer , ( os_timer_func_t * ) system_upgrade_reboot , NULL ) ;
os_timer_arm ( & flash_reboot_timer , 2000 , 1 ) ;
os_timer_arm ( & flash_reboot_timer , 2000 , 1 ) ;
return HTTPD_CGI_DONE ;
return HTTPD_CGI_DONE ;
}
}
int ICACHE_FLASH_ATTR cgiReboo t ( HttpdConnData * connData ) {
int ICACHE_FLASH_ATTR cgiRese t ( HttpdConnData * connData ) {
if ( connData - > conn = = NULL ) return HTTPD_CGI_DONE ; // Connection aborted. Clean up.
if ( connData - > conn = = NULL ) return HTTPD_CGI_DONE ; // Connection aborted. Clean up.
httpdStartResponse ( connData , 200 ) ;
httpdStartResponse ( connData , 200 ) ;
@ -193,9 +193,8 @@ int ICACHE_FLASH_ATTR cgiReboot(HttpdConnData *connData) {
httpdEndHeaders ( connData ) ;
httpdEndHeaders ( connData ) ;
// Schedule a reboot
// Schedule a reboot
system_upgrade_flag_set ( UPGRADE_FLAG_FINISH ) ;
os_timer_disarm ( & flash_reboot_timer ) ;
os_timer_disarm ( & flash_reboot_timer ) ;
os_timer_setfn ( & flash_reboot_timer , ( os_timer_func_t * ) system_upg rade_ reboo t , NULL ) ;
os_timer_setfn ( & flash_reboot_timer , ( os_timer_func_t * ) system_rest art , NULL ) ;
os_timer_arm ( & flash_reboot_timer , 2000 , 1 ) ;
os_timer_arm ( & flash_reboot_timer , 2000 , 1 ) ;
return HTTPD_CGI_DONE ;
return HTTPD_CGI_DONE ;
}
}