|
|
@ -13,11 +13,21 @@ Some flash handling cgi routines. Used for reading the existing flash and updati |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <esp8266.h> |
|
|
|
#include <esp8266.h> |
|
|
|
|
|
|
|
#include <osapi.h> |
|
|
|
#include "cgiflash.h" |
|
|
|
#include "cgiflash.h" |
|
|
|
#include "espfs.h" |
|
|
|
#include "espfs.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Check that the header of the firmware blob looks like actual firmware...
|
|
|
|
|
|
|
|
static char* ICACHE_FLASH_ATTR check_header(void *buf) { |
|
|
|
|
|
|
|
uint8_t *cd = (uint8_t *)buf; |
|
|
|
|
|
|
|
if (cd[0] != 0xEA) return "IROM magic missing"; |
|
|
|
|
|
|
|
if (cd[1] != 4 || cd[2] > 3 || cd[3] > 0x40) return "bad flash header"; |
|
|
|
|
|
|
|
if (((uint16_t *)buf)[3] != 0x4010) return "Invalid entry addr"; |
|
|
|
|
|
|
|
if (((uint32_t *)buf)[2] != 0) return "Invalid start offset"; |
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//Cgi that reads the SPI flash. Assumes 512KByte flash.
|
|
|
|
//===== Cgi that reads the SPI flash. Assumes 512KByte flash.
|
|
|
|
int ICACHE_FLASH_ATTR cgiReadFlash(HttpdConnData *connData) { |
|
|
|
int ICACHE_FLASH_ATTR cgiReadFlash(HttpdConnData *connData) { |
|
|
|
int *pos=(int *)&connData->cgiData; |
|
|
|
int *pos=(int *)&connData->cgiData; |
|
|
|
if (connData->conn==NULL) { |
|
|
|
if (connData->conn==NULL) { |
|
|
@ -39,7 +49,7 @@ int ICACHE_FLASH_ATTR cgiReadFlash(HttpdConnData *connData) { |
|
|
|
if (*pos>=0x40200000+(512*1024)) return HTTPD_CGI_DONE; else return HTTPD_CGI_MORE; |
|
|
|
if (*pos>=0x40200000+(512*1024)) return HTTPD_CGI_DONE; else return HTTPD_CGI_MORE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Return 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) { |
|
|
|
if (connData->conn==NULL) { |
|
|
|
//Connection aborted. Clean up.
|
|
|
|
//Connection aborted. Clean up.
|
|
|
@ -49,43 +59,67 @@ int ICACHE_FLASH_ATTR cgiGetFirmwareNext(HttpdConnData *connData) { |
|
|
|
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"); |
|
|
|
httpdEndHeaders(connData); |
|
|
|
httpdEndHeaders(connData); |
|
|
|
httpdSend(connData, (id == 1 ? "user1.bin" : "user2.bin"), -1); |
|
|
|
char *next = id == 1 ? "user1.bin" : "user2.bin"; |
|
|
|
os_printf("Next firmware: user%d.bin\n", 1-id); |
|
|
|
httpdSend(connData, next, -1); |
|
|
|
|
|
|
|
os_printf("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) { |
|
|
|
if (connData->conn==NULL) { |
|
|
|
//Connection aborted. Clean up.
|
|
|
|
//Connection aborted. Clean up.
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if(connData->post->len > FIRMWARE_SIZE){ |
|
|
|
int offset = connData->post->received - connData->post->buffLen; |
|
|
|
// The uploaded file is too large
|
|
|
|
if (offset == 0) { |
|
|
|
os_printf("Firmware image too large\n"); |
|
|
|
connData->cgiPrivData = NULL; |
|
|
|
httpdStartResponse(connData, 400); |
|
|
|
} else if (connData->cgiPrivData != NULL) { |
|
|
|
|
|
|
|
// we have an error condition, do nothing
|
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// assume no error yet...
|
|
|
|
|
|
|
|
char *err = NULL; |
|
|
|
|
|
|
|
int code = 400; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// check overall size
|
|
|
|
|
|
|
|
if (connData->post->len > FIRMWARE_SIZE) err = "Firmware image too large"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// check that data starts with an appropriate header
|
|
|
|
|
|
|
|
if (err == NULL && offset == 0) err = check_header(connData->post->buff); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// make sure we're buffering in 1024 byte chunks
|
|
|
|
|
|
|
|
if (err == NULL && offset % 1024 != 0) { |
|
|
|
|
|
|
|
err = "Buffering problem"; |
|
|
|
|
|
|
|
code = 500; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// return an error if there is one
|
|
|
|
|
|
|
|
if (err != NULL) { |
|
|
|
|
|
|
|
os_printf("Error %d: %s\n", code, err); |
|
|
|
|
|
|
|
httpdStartResponse(connData, code); |
|
|
|
httpdHeader(connData, "Content-Type", "text/plain"); |
|
|
|
httpdHeader(connData, "Content-Type", "text/plain"); |
|
|
|
|
|
|
|
//httpdHeader(connData, "Content-Length", strlen(err)+2);
|
|
|
|
httpdEndHeaders(connData); |
|
|
|
httpdEndHeaders(connData); |
|
|
|
httpdSend(connData, "Firmware image loo large.\r\n", -1); |
|
|
|
httpdSend(connData, err, -1); |
|
|
|
|
|
|
|
httpdSend(connData, "\r\n", -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
|
|
|
|
uint8 id = system_upgrade_userbin_check(); |
|
|
|
uint8 id = system_upgrade_userbin_check(); |
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
address += offset; |
|
|
|
|
|
|
|
|
|
|
|
int address; |
|
|
|
// erase next flash block if necessary
|
|
|
|
if (id == 1) { |
|
|
|
|
|
|
|
address = 4*1024; // start after 4KB boot partition
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// 4KB boot, firmware1, 16KB user param, 4KB reserved
|
|
|
|
|
|
|
|
address = 4*1024 + FIRMWARE_SIZE + 16*1024 + 4*1024; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
address += connData->post->received - connData->post->buffLen; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (address % SPI_FLASH_SEC_SIZE == 0){ |
|
|
|
if (address % SPI_FLASH_SEC_SIZE == 0){ |
|
|
|
// We need to erase this block
|
|
|
|
|
|
|
|
os_printf("Erasing flash at 0x%05x (id=%d)\n", address, 2-id); |
|
|
|
os_printf("Erasing flash at 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); |
|
|
|
} |
|
|
|
} |
|
|
@ -96,7 +130,6 @@ int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) { |
|
|
|
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){ |
|
|
|
// TODO: verify the firmware (is there a checksum or something???)
|
|
|
|
|
|
|
|
httpdStartResponse(connData, 200); |
|
|
|
httpdStartResponse(connData, 200); |
|
|
|
httpdEndHeaders(connData); |
|
|
|
httpdEndHeaders(connData); |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
return HTTPD_CGI_DONE; |
|
|
@ -105,6 +138,8 @@ int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) { |
|
|
|
if (connData->conn==NULL) { |
|
|
@ -112,16 +147,33 @@ int ICACHE_FLASH_ATTR cgiRebootFirmware(HttpdConnData *connData) { |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// TODO: 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(); |
|
|
|
// This hsould probably be forked into a separate task that waits a second to let the
|
|
|
|
int address = id == 1 ? 4*1024 // either start after 4KB boot partition
|
|
|
|
// current HTTP request finish...
|
|
|
|
: 4*1024 + FIRMWARE_SIZE + 16*1024 + 4*1024; // 4KB boot, fw1, 16KB user param, 4KB reserved
|
|
|
|
system_upgrade_flag_set(UPGRADE_FLAG_FINISH); |
|
|
|
uint32 buf[8]; |
|
|
|
system_upgrade_reboot(); |
|
|
|
spi_flash_read(address, buf, sizeof(buf)); |
|
|
|
httpdStartResponse(connData, 200); |
|
|
|
char *err = check_header(buf); |
|
|
|
|
|
|
|
if (err != NULL) { |
|
|
|
|
|
|
|
os_printf("Error %d: %s\n", 400, err); |
|
|
|
|
|
|
|
httpdStartResponse(connData, 400); |
|
|
|
|
|
|
|
httpdHeader(connData, "Content-Type", "text/plain"); |
|
|
|
|
|
|
|
//httpdHeader(connData, "Content-Length", strlen(err)+2);
|
|
|
|
httpdEndHeaders(connData); |
|
|
|
httpdEndHeaders(connData); |
|
|
|
|
|
|
|
httpdSend(connData, err, -1); |
|
|
|
|
|
|
|
httpdSend(connData, "\r\n", -1); |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
httpdStartResponse(connData, 200); |
|
|
|
|
|
|
|
httpdHeader(connData, "Content-Length", "0"); |
|
|
|
|
|
|
|
httpdEndHeaders(connData); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Schedule a reboot
|
|
|
|
|
|
|
|
system_upgrade_flag_set(UPGRADE_FLAG_FINISH); |
|
|
|
|
|
|
|
os_timer_disarm(&flash_reboot_timer); |
|
|
|
|
|
|
|
os_timer_setfn(&flash_reboot_timer, (os_timer_func_t *)system_upgrade_reboot, NULL); |
|
|
|
|
|
|
|
os_timer_arm(&flash_reboot_timer, 2000, 1); |
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|