|
|
|
@ -9,8 +9,9 @@ |
|
|
|
|
#include "config.h" |
|
|
|
|
#include "web-server.h" |
|
|
|
|
|
|
|
|
|
int upload_offset = 0; // flash offset where to store page upload
|
|
|
|
|
int html_header_len = 0; // HTML header length (for uploading HTML files)
|
|
|
|
|
int header_position = 0; // flash offset of the file header
|
|
|
|
|
int upload_position = 0; // flash offset where to store page upload
|
|
|
|
|
int html_header_len = 0; // length of the HTML header added to the file
|
|
|
|
|
|
|
|
|
|
// this is the header to add if user uploads HTML file
|
|
|
|
|
const char * HTML_HEADER = "<!doctype html><html><head><title>esp-link</title>" |
|
|
|
@ -18,127 +19,157 @@ const char * HTML_HEADER = "<!doctype html><html><head><title>esp-link</title> |
|
|
|
|
"<meta name=viewport content=\"width=device-width, initial-scale=1\"><script src=\"/ui.js\">" |
|
|
|
|
"</script><script src=\"/userpage.js\"></script></head><body><div id=layout> "; |
|
|
|
|
|
|
|
|
|
// this method is for flash writing and erasing the page
|
|
|
|
|
// write is incremental, so whenever a page border is reached, the next page will be erased
|
|
|
|
|
int ICACHE_FLASH_ATTR webServerSetupWriteFlash( int addr, void * data, int length ) |
|
|
|
|
{ |
|
|
|
|
int end_addr = addr + length; |
|
|
|
|
if( end_addr >= getUserPageSectionEnd() ) |
|
|
|
|
{ |
|
|
|
|
os_printf("No more space in the flash!\n"); |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void * free_ptr = 0; |
|
|
|
|
if(( length & 3 ) != 0 ) // ESP8266 always writes 4 bytes, so the remaining ones should be oxFF-ed out
|
|
|
|
|
{ |
|
|
|
|
free_ptr = os_malloc(length + 4); |
|
|
|
|
os_memset(free_ptr, 0xFF, length + 4); |
|
|
|
|
os_memcpy(free_ptr, data, length); |
|
|
|
|
data = free_ptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int ptr = 0; |
|
|
|
|
while( addr < end_addr ) |
|
|
|
|
{ |
|
|
|
|
if (addr % SPI_FLASH_SEC_SIZE == 0){ |
|
|
|
|
spi_flash_erase_sector(addr/SPI_FLASH_SEC_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int max = (addr | (SPI_FLASH_SEC_SIZE - 1)) + 1; |
|
|
|
|
int len = end_addr - addr; |
|
|
|
|
if( end_addr > max ) |
|
|
|
|
len = max - addr; |
|
|
|
|
|
|
|
|
|
spi_flash_write( addr, (uint32_t *)((char *)data + ptr), len ); |
|
|
|
|
ptr += len; |
|
|
|
|
addr += len; |
|
|
|
|
} |
|
|
|
|
if( free_ptr != 0 ) |
|
|
|
|
os_free(free_ptr); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// debug code
|
|
|
|
|
void ICACHE_FLASH_ATTR dumpFlash( int end ) |
|
|
|
|
{ |
|
|
|
|
int dump = getUserPageSectionStart(); |
|
|
|
|
while( dump < end ) |
|
|
|
|
{ |
|
|
|
|
char buffer[16]; |
|
|
|
|
spi_flash_read(dump, (uint32_t *)buffer, sizeof(buffer)); |
|
|
|
|
char dmpstr[sizeof(buffer)*3]; |
|
|
|
|
os_sprintf(dmpstr, "%06X: ", dump); |
|
|
|
|
for(int i=0; i < sizeof(buffer); i++ ) |
|
|
|
|
os_sprintf(dmpstr + os_strlen(dmpstr), "%02X ", buffer[i]); |
|
|
|
|
os_printf("%s\n", dmpstr); |
|
|
|
|
dump += sizeof(buffer); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// multipart callback for uploading user defined pages
|
|
|
|
|
int ICACHE_FLASH_ATTR webServerSetupMultipartCallback(MultipartCmd cmd, char *data, int dataLen, int position) |
|
|
|
|
{ |
|
|
|
|
switch(cmd) |
|
|
|
|
{ |
|
|
|
|
case FILE_UPLOAD_START: |
|
|
|
|
upload_position = getUserPageSectionStart(); |
|
|
|
|
header_position = upload_position; |
|
|
|
|
break; |
|
|
|
|
case FILE_START: |
|
|
|
|
upload_offset = 0; |
|
|
|
|
html_header_len = 0; |
|
|
|
|
// simple HTML file
|
|
|
|
|
if( ( dataLen > 5 ) && ( os_strcmp(data + dataLen - 5, ".html") == 0 ) ) // if the file ends with .html, wrap into an espfs image
|
|
|
|
|
{ |
|
|
|
|
// write the start block on esp-fs
|
|
|
|
|
int spi_flash_addr = getUserPageSectionStart(); |
|
|
|
|
spi_flash_erase_sector(spi_flash_addr/SPI_FLASH_SEC_SIZE); |
|
|
|
|
html_header_len = 0; |
|
|
|
|
|
|
|
|
|
// write the starting block on esp-fs
|
|
|
|
|
EspFsHeader hdr; |
|
|
|
|
hdr.magic = 0xFFFFFFFF; // espfs magic is invalid during upload
|
|
|
|
|
hdr.flags = 0; |
|
|
|
|
hdr.compression = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int len = dataLen + 1; |
|
|
|
|
while(( len & 3 ) != 0 ) |
|
|
|
|
len++; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hdr.nameLen = len; |
|
|
|
|
hdr.fileLenComp = hdr.fileLenDecomp = 0xFFFFFFFF; |
|
|
|
|
|
|
|
|
|
spi_flash_write( spi_flash_addr + upload_offset, (uint32_t *)(&hdr), sizeof(EspFsHeader) ); |
|
|
|
|
upload_offset += sizeof(EspFsHeader); |
|
|
|
|
|
|
|
|
|
header_position = upload_position; |
|
|
|
|
if( webServerSetupWriteFlash( upload_position, (uint32_t *)(&hdr), sizeof(EspFsHeader) ) ) |
|
|
|
|
return 1; |
|
|
|
|
upload_position += sizeof(EspFsHeader); |
|
|
|
|
|
|
|
|
|
char nameBuf[len]; |
|
|
|
|
os_memset(nameBuf, 0, len); |
|
|
|
|
os_memcpy(nameBuf, data, dataLen); |
|
|
|
|
|
|
|
|
|
spi_flash_write( spi_flash_addr + upload_offset, (uint32_t *)(nameBuf), len ); |
|
|
|
|
upload_offset += len; |
|
|
|
|
|
|
|
|
|
html_header_len = os_strlen(HTML_HEADER) & ~3; // upload only 4 byte aligned part
|
|
|
|
|
char buf[html_header_len]; |
|
|
|
|
os_memcpy(buf, HTML_HEADER, html_header_len); |
|
|
|
|
spi_flash_write( spi_flash_addr + upload_offset, (uint32_t *)(buf), html_header_len ); |
|
|
|
|
upload_offset += html_header_len; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case FILE_DATA: |
|
|
|
|
if(( position < 4 ) && (upload_offset == 0)) // for espfs images check the magic number
|
|
|
|
|
{ |
|
|
|
|
for(int p = position; p < 4; p++ ) |
|
|
|
|
if( webServerSetupWriteFlash( upload_position, (uint32_t *)(nameBuf), len ) ) |
|
|
|
|
return 1; |
|
|
|
|
upload_position += len; |
|
|
|
|
|
|
|
|
|
// add header to HTML files
|
|
|
|
|
if( ( dataLen > 5 ) && ( os_strcmp(data + dataLen - 5, ".html") == 0 ) ) // if the file ends with .html, wrap into an espfs image
|
|
|
|
|
{ |
|
|
|
|
if( data[p - position] != ((ESPFS_MAGIC >> (p * 8) ) & 255 ) ) |
|
|
|
|
{ |
|
|
|
|
os_printf("Not an espfs image!\n"); |
|
|
|
|
html_header_len = os_strlen(HTML_HEADER) & ~3; // upload only 4 byte aligned part
|
|
|
|
|
char buf[html_header_len]; |
|
|
|
|
os_memcpy(buf, HTML_HEADER, html_header_len); |
|
|
|
|
if( webServerSetupWriteFlash( upload_position, (uint32_t *)(buf), html_header_len ) ) |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
data[p - position] = 0xFF; // espfs magic is invalid during upload
|
|
|
|
|
upload_position += html_header_len; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int spi_flash_addr = getUserPageSectionStart() + upload_offset + position; |
|
|
|
|
int spi_flash_end_addr = spi_flash_addr + dataLen; |
|
|
|
|
if( spi_flash_end_addr + dataLen >= getUserPageSectionEnd() ) |
|
|
|
|
{ |
|
|
|
|
os_printf("No more space in the flash!\n"); |
|
|
|
|
break; |
|
|
|
|
case FILE_DATA: |
|
|
|
|
if( webServerSetupWriteFlash( upload_position, data, dataLen ) ) |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int ptr = 0; |
|
|
|
|
while( spi_flash_addr < spi_flash_end_addr ) |
|
|
|
|
upload_position += dataLen; |
|
|
|
|
break; |
|
|
|
|
case FILE_DONE: |
|
|
|
|
{ |
|
|
|
|
if (spi_flash_addr % SPI_FLASH_SEC_SIZE == 0){ |
|
|
|
|
spi_flash_erase_sector(spi_flash_addr/SPI_FLASH_SEC_SIZE); |
|
|
|
|
// write padding after the file
|
|
|
|
|
uint8_t pad_cnt = (4 - position) & 3; |
|
|
|
|
if( pad_cnt ) { |
|
|
|
|
uint32_t pad = 0; |
|
|
|
|
if( webServerSetupWriteFlash( upload_position, &pad, pad_cnt ) ) |
|
|
|
|
return 1; |
|
|
|
|
upload_position += pad_cnt; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int max = (spi_flash_addr | (SPI_FLASH_SEC_SIZE - 1)) + 1; |
|
|
|
|
int len = spi_flash_end_addr - spi_flash_addr; |
|
|
|
|
if( spi_flash_end_addr > max ) |
|
|
|
|
len = max - spi_flash_addr; |
|
|
|
|
|
|
|
|
|
spi_flash_write( spi_flash_addr, (uint32_t *)(data + ptr), len ); |
|
|
|
|
ptr += len; |
|
|
|
|
spi_flash_addr += len; |
|
|
|
|
|
|
|
|
|
EspFsHeader hdr; |
|
|
|
|
hdr.magic = ESPFS_MAGIC;
|
|
|
|
|
hdr.fileLenComp = hdr.fileLenDecomp = position + html_header_len; |
|
|
|
|
|
|
|
|
|
// restore ESPFS magic
|
|
|
|
|
spi_flash_write( header_position + ((char *)&hdr.magic - (char*)&hdr), (uint32_t *)&hdr.magic, sizeof(uint32_t) ); |
|
|
|
|
// set file size
|
|
|
|
|
spi_flash_write( header_position + ((char *)&hdr.fileLenComp - (char*)&hdr), (uint32_t *)&hdr.fileLenComp, sizeof(uint32_t) ); |
|
|
|
|
spi_flash_write( header_position + ((char *)&hdr.fileLenDecomp - (char*)&hdr), (uint32_t *)&hdr.fileLenDecomp, sizeof(uint32_t) ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
case FILE_DONE: |
|
|
|
|
case FILE_UPLOAD_DONE: |
|
|
|
|
{ |
|
|
|
|
if( html_header_len != 0 ) |
|
|
|
|
{ |
|
|
|
|
// write the terminating block on esp-fs
|
|
|
|
|
int spi_flash_addr = getUserPageSectionStart() + upload_offset + position; |
|
|
|
|
// write the termination block
|
|
|
|
|
|
|
|
|
|
EspFsHeader hdr; |
|
|
|
|
hdr.magic = ESPFS_MAGIC;
|
|
|
|
|
hdr.flags = 1; |
|
|
|
|
hdr.compression = 0; |
|
|
|
|
hdr.nameLen = 0; |
|
|
|
|
hdr.fileLenComp = hdr.fileLenDecomp = 0; |
|
|
|
|
|
|
|
|
|
if( webServerSetupWriteFlash( upload_position, (uint32_t *)(&hdr), sizeof(EspFsHeader) ) ) |
|
|
|
|
return 1; |
|
|
|
|
upload_position += sizeof(EspFsHeader); |
|
|
|
|
|
|
|
|
|
uint32_t pad = 0; |
|
|
|
|
uint8_t pad_cnt = (4 - position) & 3; |
|
|
|
|
if( pad_cnt ) |
|
|
|
|
spi_flash_write( spi_flash_addr, &pad, pad_cnt ); |
|
|
|
|
|
|
|
|
|
spi_flash_addr += pad_cnt; |
|
|
|
|
|
|
|
|
|
// create ESPFS image
|
|
|
|
|
EspFsHeader hdr; |
|
|
|
|
hdr.magic = ESPFS_MAGIC;
|
|
|
|
|
hdr.flags = 1; |
|
|
|
|
hdr.compression = 0; |
|
|
|
|
hdr.nameLen = 0; |
|
|
|
|
hdr.fileLenComp = hdr.fileLenDecomp = 0; |
|
|
|
|
|
|
|
|
|
spi_flash_write( spi_flash_addr, (uint32_t *)(&hdr), sizeof(EspFsHeader) ); |
|
|
|
|
|
|
|
|
|
uint32_t totallen = html_header_len + position; |
|
|
|
|
|
|
|
|
|
// restore ESPFS magic
|
|
|
|
|
spi_flash_write( (int)getUserPageSectionStart(), (uint32_t *)&hdr.magic, sizeof(uint32_t) ); |
|
|
|
|
// set file size
|
|
|
|
|
spi_flash_write( (int)getUserPageSectionStart() + 8, &totallen, sizeof(uint32_t) ); |
|
|
|
|
spi_flash_write( (int)getUserPageSectionStart() + 12, &totallen, sizeof(uint32_t) ); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// set espfs magic (set it valid)
|
|
|
|
|
uint32_t magic = ESPFS_MAGIC; |
|
|
|
|
spi_flash_write( (int)getUserPageSectionStart(), (uint32_t *)&magic, sizeof(uint32_t) ); |
|
|
|
|
} |
|
|
|
|
WEB_Init(); // reload the content
|
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|