├── include ├── user_config.h └── uart_hw.h ├── html ├── wifi │ ├── icons.png │ ├── style.css │ ├── 140medley.min.js │ ├── connecting.html │ └── wifi.tpl ├── cats │ ├── cross-eyed-cat.jpg │ ├── junge-katze-iv.jpg │ └── kitten-loves-toy.jpg ├── style.css ├── test │ ├── index.html │ └── test.js ├── led.tpl ├── flash │ ├── style.css │ ├── 140medley.min.js │ └── index.html ├── index.tpl └── websocket │ └── index.html ├── user ├── stdout.h ├── io.h ├── cgi-test.h ├── cgi.h ├── io.c ├── stdout.c ├── cgi.c ├── cgi-test.c └── user_main.c ├── .gitmodules ├── .gitignore ├── Makefile.combined ├── Makefile.separate ├── esphttpdconfig.mk ├── README.md ├── Makefile.ota └── Makefile /include/user_config.h: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /html/wifi/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chmorgan/esphttpd/HEAD/html/wifi/icons.png -------------------------------------------------------------------------------- /user/stdout.h: -------------------------------------------------------------------------------- 1 | #ifndef STDOUT_H 2 | #define STDOUT_H 3 | 4 | void stdoutInit(); 5 | 6 | #endif -------------------------------------------------------------------------------- /html/cats/cross-eyed-cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chmorgan/esphttpd/HEAD/html/cats/cross-eyed-cat.jpg -------------------------------------------------------------------------------- /html/cats/junge-katze-iv.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chmorgan/esphttpd/HEAD/html/cats/junge-katze-iv.jpg -------------------------------------------------------------------------------- /html/cats/kitten-loves-toy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chmorgan/esphttpd/HEAD/html/cats/kitten-loves-toy.jpg -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libesphttpd"] 2 | path = libesphttpd 3 | url = http://git.spritesserver.nl/libesphttpd.git/ 4 | -------------------------------------------------------------------------------- /user/io.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_H 2 | #define IO_H 3 | 4 | void ICACHE_FLASH_ATTR ioLed(int ena); 5 | void ioInit(void); 6 | 7 | #endif -------------------------------------------------------------------------------- /user/cgi-test.h: -------------------------------------------------------------------------------- 1 | #ifndef CGI_TEST_H 2 | #define CGI_TEST_H 3 | 4 | #include "httpd.h" 5 | 6 | int cgiTestbed(HttpdConnData *connData); 7 | 8 | #endif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | firmware/ 3 | espfs/mkespfsimage/*.o 4 | espfs/mkespfsimage/mkespfsimage 5 | webpages.espfs 6 | espfs/espfstest/*.o 7 | espfs/espfstest/espfstest 8 | *.DS_Store 9 | html_compressed/ 10 | ldscript_memspecific.ld 11 | eagle.app.sym 12 | -------------------------------------------------------------------------------- /user/cgi.h: -------------------------------------------------------------------------------- 1 | #ifndef CGI_H 2 | #define CGI_H 3 | 4 | #include "httpd.h" 5 | 6 | int cgiLed(HttpdConnData *connData); 7 | int tplLed(HttpdConnData *connData, char *token, void **arg); 8 | int tplCounter(HttpdConnData *connData, char *token, void **arg); 9 | 10 | #endif -------------------------------------------------------------------------------- /html/style.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | background-color: #404040; 4 | font-family: sans-serif; 5 | } 6 | 7 | #main { 8 | background-color: #d0d0FF; 9 | -moz-border-radius: 5px; 10 | -webkit-border-radius: 5px; 11 | border-radius: 5px; 12 | border: 2px solid #000000; 13 | width: 800px; 14 | margin: 0 auto; 15 | padding: 20px 16 | } 17 | 18 | -------------------------------------------------------------------------------- /html/test/index.html: -------------------------------------------------------------------------------- 1 | Webserver test 2 | 3 | 4 | 5 | 6 |
7 |
Initializing test...
8 |
9 | -------------------------------------------------------------------------------- /html/led.tpl: -------------------------------------------------------------------------------- 1 | Test 2 | 3 | 4 | 5 |
6 |

The LED

7 |

8 | If there's a LED connected to GPIO2, it's now %ledstate%. You can change that using the buttons below. 9 |

10 |
11 | 12 | 13 |
14 |
15 | 16 | -------------------------------------------------------------------------------- /html/wifi/style.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | background-color: #404040; 4 | font-family: sans-serif; 5 | } 6 | 7 | #main { 8 | background-color: #d0d0FF; 9 | -moz-border-radius: 5px; 10 | -webkit-border-radius: 5px; 11 | border-radius: 5px; 12 | border: 2px solid #000000; 13 | width: 800px; 14 | margin: 0 auto; 15 | padding: 20px 16 | } 17 | 18 | .icon { 19 | background-image: url("icons.png"); 20 | background-color: transparent; 21 | width: 32px; 22 | height: 32px; 23 | display: inline-block; 24 | } -------------------------------------------------------------------------------- /html/flash/style.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | background-color: #404040; 4 | font-family: sans-serif; 5 | } 6 | 7 | #main { 8 | background-color: #d0d0FF; 9 | -moz-border-radius: 5px; 10 | -webkit-border-radius: 5px; 11 | border-radius: 5px; 12 | border: 2px solid #000000; 13 | width: 800px; 14 | margin: 0 auto; 15 | padding: 20px 16 | } 17 | 18 | #progressbar { 19 | margin: 10px; 20 | padding: 0; 21 | border: 1px solid #000000; 22 | height: 20px; 23 | width: 200px; 24 | background-color: #808080; 25 | } 26 | 27 | #progressbarinner { 28 | width: 10px; 29 | height: 20px; 30 | border: none; 31 | background-color: #00ff00; 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /html/flash/140medley.min.js: -------------------------------------------------------------------------------- 1 | var t=function(a,b){return function(c,d){return a.replace(/#{([^}]*)}/g,function(a,f){return Function("x","with(x)return "+f).call(c,d||b||{})})}},s=function(a,b){return b?{get:function(c){return a[c]&&b.parse(a[c])},set:function(c,d){a[c]=b.stringify(d)}}:{}}(this.localStorage||{},JSON),p=function(a,b,c,d){c=c||document;d=c[b="on"+b];a=c[b]=function(e){d=d&&d(e=e||c.event);return(a=a&&b(e))?b:d};c=this},m=function(a,b,c){b=document;c=b.createElement("p");c.innerHTML=a;for(a=b.createDocumentFragment();b= 2 | c.firstChild;)a.appendChild(b);return a},$=function(a,b){a=a.match(/^(\W)?(.*)/);return(b||document)["getElement"+(a[1]?a[1]=="#"?"ById":"sByClassName":"sByTagName")](a[2])},j=function(a){for(a=0;a<4;a++)try{return a?new ActiveXObject([,"Msxml2","Msxml3","Microsoft"][a]+".XMLHTTP"):new XMLHttpRequest}catch(b){}}; 3 | -------------------------------------------------------------------------------- /html/wifi/140medley.min.js: -------------------------------------------------------------------------------- 1 | var t=function(a,b){return function(c,d){return a.replace(/#{([^}]*)}/g,function(a,f){return Function("x","with(x)return "+f).call(c,d||b||{})})}},s=function(a,b){return b?{get:function(c){return a[c]&&b.parse(a[c])},set:function(c,d){a[c]=b.stringify(d)}}:{}}(this.localStorage||{},JSON),p=function(a,b,c,d){c=c||document;d=c[b="on"+b];a=c[b]=function(e){d=d&&d(e=e||c.event);return(a=a&&b(e))?b:d};c=this},m=function(a,b,c){b=document;c=b.createElement("p");c.innerHTML=a;for(a=b.createDocumentFragment();b= 2 | c.firstChild;)a.appendChild(b);return a},$=function(a,b){a=a.match(/^(\W)?(.*)/);return(b||document)["getElement"+(a[1]?a[1]=="#"?"ById":"sByClassName":"sByTagName")](a[2])},j=function(a){for(a=0;a<4;a++)try{return a?new ActiveXObject([,"Msxml2","Msxml3","Microsoft"][a]+".XMLHTTP"):new XMLHttpRequest}catch(b){}}; 3 | -------------------------------------------------------------------------------- /html/index.tpl: -------------------------------------------------------------------------------- 1 | 2 | Esp8266 web server 3 | 4 | 5 | 6 |
7 |

It Works

8 |

9 | If you see this, it means the tiny li'l website in your ESP8266 does actually work. Fyi, this page has 10 | been loaded %counter% times. 11 |

19 | 20 |

21 | 22 |

And because we're on the Internets now, here are the required pictures of cats:
23 |
24 |
25 |
26 |

27 |
28 | 29 | -------------------------------------------------------------------------------- /html/wifi/connecting.html: -------------------------------------------------------------------------------- 1 | Connecting... 2 | 3 | 4 | 34 | 35 | 36 |
37 |

Connecting to AP...

38 |

Status:
39 |

...
40 |

41 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /Makefile.combined: -------------------------------------------------------------------------------- 1 | #Makefile with the options specific to the build of a non-upgradable firmware with 2 | #the espfs combined into the flash binary. 3 | 4 | # linker script used for the linker step 5 | LD_SCRIPT = eagle.app.v6.ld 6 | # Extra script to tell the linker the correct irom0 memory available 7 | EXTRA_LD_SCRIPTS = ldscript_memspecific.ld 8 | 9 | TARGET_OUT := $(addprefix $(BUILD_BASE)/,$(TARGET).out) 10 | 11 | .PHONY: ldscript_memspecific.ld 12 | 13 | BLANKPOS="$$(printf "0x%X" $$(($(ESP_SPI_FLASH_SIZE_K)*1024-0x2000)))" 14 | INITDATAPOS="$$(printf "0x%X" $$(($(ESP_SPI_FLASH_SIZE_K)*1024-0x4000)))" 15 | 16 | ldscript_memspecific.ld: 17 | $(vecho) "GEN $@" 18 | $(Q) echo "MEMORY { irom0_0_seg : org = 0x40240000, len = "$$(printf "0x%X" $$(($(ESP_SPI_FLASH_SIZE_K)*1024-0x4000)))" }"> ldscript_memspecific.ld 19 | 20 | 21 | $(TARGET_OUT): $(APP_AR) $(EXTRA_LD_SCRIPTS) 22 | $(vecho) "LD $@" 23 | $(Q) $(LD) -Llibesphttpd -L$(SDK_LIBDIR) $(LD_SCRIPT) $(EXTRA_LD_SCRIPTS) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $@ 24 | 25 | 26 | $(FW_BASE): $(TARGET_OUT) 27 | $(vecho) "FW $@" 28 | $(Q) mkdir -p $@ 29 | $(Q) $(ESPTOOL) elf2image $(TARGET_OUT) --output $@/ 30 | 31 | flash: $(TARGET_OUT) $(FW_BASE) 32 | $(Q) $(ESPTOOL) $(ESPTOOL_OPTS) write_flash $(ESPTOOL_FLASHDEF) 0x00000 $(FW_BASE)/0x00000.bin 0x40000 $(FW_BASE)/0x40000.bin 33 | 34 | blankflash: 35 | $(Q) $(ESPTOOL) $(ESPTOOL_OPTS) write_flash $(ESPTOOL_FLASHDEF) $(BLANKPOS) $(SDK_BASE)/bin/blank.bin $(INITDATAPOS) $(SDK_BASE)/bin/esp_init_data_default.bin 36 | 37 | -------------------------------------------------------------------------------- /user/io.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ---------------------------------------------------------------------------- 4 | * "THE BEER-WARE LICENSE" (Revision 42): 5 | * Jeroen Domburg wrote this file. As long as you retain 6 | * this notice you can do whatever you want with this stuff. If we meet some day, 7 | * and you think this stuff is worth it, you can buy me a beer in return. 8 | * ---------------------------------------------------------------------------- 9 | */ 10 | 11 | 12 | #include 13 | 14 | #define LEDGPIO 2 15 | #define BTNGPIO 0 16 | 17 | static ETSTimer resetBtntimer; 18 | 19 | void ICACHE_FLASH_ATTR ioLed(int ena) { 20 | //gpio_output_set is overkill. ToDo: use better mactos 21 | if (ena) { 22 | gpio_output_set((1<=6) { //3 sec pressed 34 | wifi_station_disconnect(); 35 | wifi_set_opmode(0x3); //reset to AP+STA mode 36 | os_printf("Reset to AP mode. Restarting system...\n"); 37 | system_restart(); 38 | } 39 | resetCnt=0; 40 | } 41 | } 42 | 43 | void ioInit() { 44 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2); 45 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0); 46 | gpio_output_set(0, 0, (1< 2 | 3 | 4 | 5 | WebSocket Test 6 | 7 | 66 | 67 |

WebSocket Test

68 | 69 |
70 | -------------------------------------------------------------------------------- /Makefile.separate: -------------------------------------------------------------------------------- 1 | #Makefile with the options specific to the build of a non-upgradable firmware with 2 | #the espfs included in the firmware binary. 3 | 4 | # linker script used for the linker step 5 | LD_SCRIPT = eagle.app.v6.ld 6 | # Extra script to tell the linker the correct irom0 memory available 7 | EXTRA_LD_SCRIPTS = ldscript_memspecific.ld 8 | 9 | TARGET_OUT := $(addprefix $(BUILD_BASE)/,$(TARGET).out) 10 | 11 | .PHONY: ldscript_memspecific.ld 12 | 13 | BLANKPOS="$$(printf "0x%X" $$(($(ESP_SPI_FLASH_SIZE_K)*1024-0x2000)))" 14 | INITDATAPOS="$$(printf "0x%X" $$(($(ESP_SPI_FLASH_SIZE_K)*1024-0x4000)))" 15 | 16 | ldscript_memspecific.ld: 17 | $(vecho) "GEN $@" 18 | $(Q) echo "MEMORY { irom0_0_seg : org = 0x40240000, len = "$$(printf "0x%X" $$(($(ESP_SPI_FLASH_SIZE)-0x4000)))" }"> ldscript_memspecific.ld 19 | 20 | $(TARGET_OUT): $(APP_AR) $(EXTRA_LD_SCRIPTS) 21 | $(vecho) "LD $@" 22 | $(Q) $(LD) -Llibesphttpd -L$(SDK_LIBDIR) $(LD_SCRIPT) $(EXTRA_LD_SCRIPTS) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $@ 23 | 24 | $(FW_BASE): $(TARGET_OUT) 25 | $(vecho) "FW $@" 26 | $(Q) mkdir -p $@ 27 | $(Q) $(ESPTOOL) elf2image $(TARGET_OUT) --output $@/ 28 | 29 | flash: $(TARGET_OUT) $(FW_BASE) 30 | $(Q) $(ESPTOOL) $(ESPTOOL_OPTS) write_flash $(ESPTOOL_FLASHDEF) 0x00000 $(FW_BASE)/0x00000.bin 0x40000 $(FW_BASE)/0x40000.bin 31 | 32 | blankflash: 33 | $(Q) $(ESPTOOL) $(ESPTOOL_OPTS) write_flash $(ESPTOOL_FLASHDEF) $(BLANKPOS) $(SDK_BASE)/bin/blank.bin $(INITDATAPOS) $(SDK_BASE)/bin/esp_init_data_default.bin 34 | 35 | htmlflash: libesphttpd 36 | $(Q) if [ $$(stat -c '%s' libesphttpd/webpages.espfs) -gt $$(( $(ESPFS_SIZE) )) ]; then echo "webpages.espfs too big!"; false; fi 37 | $(Q) $(ESPTOOL) $(ESPTOOL_OPTS) write_flash $(ESPTOOL_FLASHDEF) $(ESPFS_POS) libesphttpd/webpages.espfs 38 | -------------------------------------------------------------------------------- /esphttpdconfig.mk: -------------------------------------------------------------------------------- 1 | # --------------- esphttpd config options --------------- 2 | 3 | # If GZIP_COMPRESSION is set to "yes" then the static css, js, and html files will be compressed with gzip before added to the espfs image 4 | # and will be served with gzip Content-Encoding header. 5 | # This could speed up the downloading of these files, but might break compatibility with older web browsers not supporting gzip encoding 6 | # because Accept-Encoding is simply ignored. Enable this option if you have large static files to serve (for e.g. JQuery, Twitter bootstrap) 7 | # By default only js, css and html files are compressed. 8 | # If you have text based static files with different extensions what you want to serve compressed then you will need to add the extension to the following places: 9 | # - Add the extension to this Makefile at the webpages.espfs target to the find command 10 | # - Add the extension to the gzippedFileTypes array in the user/httpd.c file 11 | # 12 | # Adding JPG or PNG files (and any other compressed formats) is not recommended, because GZIP compression does not works effectively on compressed files. 13 | 14 | #Static gzipping is disabled by default. 15 | GZIP_COMPRESSION ?= no 16 | 17 | # If COMPRESS_W_YUI is set to "yes" then the static css and js files will be compressed with yui-compressor 18 | # This option works only when GZIP_COMPRESSION is set to "yes" 19 | # http://yui.github.io/yuicompressor/ 20 | #Disabled by default. 21 | COMPRESS_W_YUI ?= no 22 | YUI-COMPRESSOR ?= /usr/bin/yui-compressor 23 | 24 | #If USE_HEATSHRINK is set to "yes" then the espfs files will be compressed with Heatshrink and decompressed 25 | #on the fly while reading the file. Because the decompression is done in the esp8266, it does not require 26 | #any support in the browser. 27 | USE_HEATSHRINK ?= yes 28 | 29 | -------------------------------------------------------------------------------- /user/stdout.c: -------------------------------------------------------------------------------- 1 | //Stupid bit of code that does the bare minimum to make os_printf work. 2 | 3 | /* 4 | * ---------------------------------------------------------------------------- 5 | * "THE BEER-WARE LICENSE" (Revision 42): 6 | * Jeroen Domburg wrote this file. As long as you retain 7 | * this notice you can do whatever you want with this stuff. If we meet some day, 8 | * and you think this stuff is worth it, you can buy me a beer in return. 9 | * ---------------------------------------------------------------------------- 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | static void ICACHE_FLASH_ATTR stdoutUartTxd(char c) { 16 | //Wait until there is room in the FIFO 17 | while (((READ_PERI_REG(UART_STATUS(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ; 18 | //Send the character 19 | WRITE_PERI_REG(UART_FIFO(0), c); 20 | } 21 | 22 | static void ICACHE_FLASH_ATTR stdoutPutchar(char c) { 23 | //convert \n -> \r\n 24 | if (c=='\n') stdoutUartTxd('\r'); 25 | stdoutUartTxd(c); 26 | } 27 | 28 | 29 | void stdoutInit() { 30 | //Enable TxD pin 31 | PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); 32 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); 33 | 34 | //Set baud rate and other serial parameters to 115200,n,8,1 35 | uart_div_modify(0, UART_CLK_FREQ/BIT_RATE_115200); 36 | WRITE_PERI_REG(UART_CONF0(0), (STICK_PARITY_DIS)|(ONE_STOP_BIT << UART_STOP_BIT_NUM_S)| \ 37 | (EIGHT_BITS << UART_BIT_NUM_S)); 38 | 39 | //Reset tx & rx fifo 40 | SET_PERI_REG_MASK(UART_CONF0(0), UART_RXFIFO_RST|UART_TXFIFO_RST); 41 | CLEAR_PERI_REG_MASK(UART_CONF0(0), UART_RXFIFO_RST|UART_TXFIFO_RST); 42 | //Clear pending interrupts 43 | WRITE_PERI_REG(UART_INT_CLR(0), 0xffff); 44 | 45 | //Install our own putchar handler 46 | os_install_putc1((void *)stdoutPutchar); 47 | } 48 | -------------------------------------------------------------------------------- /user/cgi.c: -------------------------------------------------------------------------------- 1 | /* 2 | Some random cgi routines. Used in the LED example and the page that returns the entire 3 | flash as a binary. Also handles the hit counter on the main page. 4 | */ 5 | 6 | /* 7 | * ---------------------------------------------------------------------------- 8 | * "THE BEER-WARE LICENSE" (Revision 42): 9 | * Jeroen Domburg wrote this file. As long as you retain 10 | * this notice you can do whatever you want with this stuff. If we meet some day, 11 | * and you think this stuff is worth it, you can buy me a beer in return. 12 | * ---------------------------------------------------------------------------- 13 | */ 14 | 15 | 16 | #include 17 | #include "cgi.h" 18 | #include "io.h" 19 | 20 | 21 | //cause I can't be bothered to write an ioGetLed() 22 | static char currLedState=0; 23 | 24 | //Cgi that turns the LED on or off according to the 'led' param in the POST data 25 | int ICACHE_FLASH_ATTR cgiLed(HttpdConnData *connData) { 26 | int len; 27 | char buff[1024]; 28 | 29 | if (connData->conn==NULL) { 30 | //Connection aborted. Clean up. 31 | return HTTPD_CGI_DONE; 32 | } 33 | 34 | len=httpdFindArg(connData->post->buff, "led", buff, sizeof(buff)); 35 | if (len!=0) { 36 | currLedState=atoi(buff); 37 | ioLed(currLedState); 38 | } 39 | 40 | httpdRedirect(connData, "led.tpl"); 41 | return HTTPD_CGI_DONE; 42 | } 43 | 44 | 45 | 46 | //Template code for the led page. 47 | int ICACHE_FLASH_ATTR tplLed(HttpdConnData *connData, char *token, void **arg) { 48 | char buff[128]; 49 | if (token==NULL) return HTTPD_CGI_DONE; 50 | 51 | os_strcpy(buff, "Unknown"); 52 | if (os_strcmp(token, "ledstate")==0) { 53 | if (currLedState) { 54 | os_strcpy(buff, "on"); 55 | } else { 56 | os_strcpy(buff, "off"); 57 | } 58 | } 59 | httpdSend(connData, buff, -1); 60 | return HTTPD_CGI_DONE; 61 | } 62 | 63 | static long hitCounter=0; 64 | 65 | //Template code for the counter on the index page. 66 | int ICACHE_FLASH_ATTR tplCounter(HttpdConnData *connData, char *token, void **arg) { 67 | char buff[128]; 68 | if (token==NULL) return HTTPD_CGI_DONE; 69 | 70 | if (os_strcmp(token, "counter")==0) { 71 | hitCounter++; 72 | os_sprintf(buff, "%ld", hitCounter); 73 | } 74 | httpdSend(connData, buff, -1); 75 | return HTTPD_CGI_DONE; 76 | } 77 | -------------------------------------------------------------------------------- /html/flash/index.html: -------------------------------------------------------------------------------- 1 | 2 | Upgrade firmware 3 | 4 | 5 | 74 | 75 | 76 |
77 |

Update firmware

78 |
Loading...
79 | 80 | 81 |
82 | -------------------------------------------------------------------------------- /user/cgi-test.c: -------------------------------------------------------------------------------- 1 | /* 2 | Cgi routines as used by the tests in the html/test subdirectory. 3 | */ 4 | 5 | /* 6 | * ---------------------------------------------------------------------------- 7 | * "THE BEER-WARE LICENSE" (Revision 42): 8 | * Jeroen Domburg wrote this file. As long as you retain 9 | * this notice you can do whatever you want with this stuff. If we meet some day, 10 | * and you think this stuff is worth it, you can buy me a beer in return. 11 | * ---------------------------------------------------------------------------- 12 | */ 13 | 14 | 15 | #include 16 | #include "cgi-test.h" 17 | 18 | 19 | typedef struct { 20 | int len; 21 | int sendPos; 22 | } TestbedState; 23 | 24 | 25 | int ICACHE_FLASH_ATTR cgiTestbed(HttpdConnData *connData) { 26 | char buff[1024]; 27 | int first=0; 28 | int l, x; 29 | TestbedState *state=(TestbedState*)connData->cgiData; 30 | 31 | if (connData->conn==NULL) { 32 | //Connection aborted. Clean up. 33 | if (state) free(state); 34 | return HTTPD_CGI_DONE; 35 | } 36 | 37 | if (state==NULL) { 38 | //First call 39 | state=malloc(sizeof(TestbedState)); 40 | memset(state, 0, sizeof(state)); 41 | connData->cgiData=state; 42 | first=1; 43 | } 44 | 45 | if (connData->requestType==HTTPD_METHOD_GET) { 46 | if (first) { 47 | httpdStartResponse(connData, 200); 48 | httpdHeader(connData, "content-type", "application/data"); 49 | httpdEndHeaders(connData); 50 | l=httpdFindArg(connData->getArgs, "len", buff, sizeof(buff)); 51 | state->len=1024; 52 | if (l!=-1) state->len=atoi(buff); 53 | state->sendPos=0; 54 | return HTTPD_CGI_MORE; 55 | } else { 56 | l=sizeof(buff); 57 | if (l>(state->len-state->sendPos)) l=(state->len-state->sendPos); 58 | //Fill with semi-random data 59 | for (x=0; xsendPos>>10))&0x1F)+'0'; 60 | httpdSend(connData, buff, l); 61 | state->sendPos+=l; 62 | printf("Test: Uploaded %d/%d bytes\n", state->sendPos, state->len); 63 | if (state->len<=state->sendPos) { 64 | if (state) free(state); 65 | return HTTPD_CGI_DONE; 66 | } else { 67 | return HTTPD_CGI_MORE; 68 | } 69 | } 70 | } 71 | if (connData->requestType==HTTPD_METHOD_POST) { 72 | if (connData->post->len!=connData->post->received) { 73 | //Still receiving data. Ignore this. 74 | printf("Test: got %d/%d bytes\n", connData->post->received, connData->post->len); 75 | return HTTPD_CGI_MORE; 76 | } else { 77 | httpdStartResponse(connData, 200); 78 | httpdHeader(connData, "content-type", "text/plain"); 79 | httpdEndHeaders(connData); 80 | l=sprintf(buff, "%d", connData->post->received); 81 | httpdSend(connData, buff, l); 82 | return HTTPD_CGI_DONE; 83 | } 84 | } 85 | return HTTPD_CGI_DONE; 86 | } 87 | -------------------------------------------------------------------------------- /html/wifi/wifi.tpl: -------------------------------------------------------------------------------- 1 | WiFi connection 2 | 3 | 4 | 74 | 75 | 76 |
77 |

78 | Current WiFi mode: %WiFiMode% 79 |

80 |

81 | Note: %WiFiapwarn% 82 |

83 |
84 |

85 | To connect to a WiFi network, please select one of the detected networks...
86 |

Scanning...
87 |
88 | WiFi password, if applicable:
89 |
90 | 91 |

92 |
93 | 94 | 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esp-httpd README # 2 | 3 | This is the demonstration project for the small but powerful libesphttpd webserver 4 | for ESP8266(EX) chips. It is an example of how to make a module that can have 5 | the AP it connects to configured over a webbrowser. It also illustrates multiple 6 | flash layouts and some OTA update functionality. 7 | 8 | ## ABOUT THE WEBSERVER ## 9 | 10 | The Good (aka: what's awesome) 11 | - Supports multiple connections, for eg simultaneous html/css/js/images downloading 12 | - Static files stored in flash, in an (optionally compressed) RO filesystem 13 | - Pluggable using external cgi routines 14 | - Simple template engine for mixed c and html things 15 | - Usable as an embedded library - should be easy to drop into your existing projects 16 | - Includes websocket support 17 | 18 | The Bad (aka: what can be improved) 19 | - Not built for speediness, although it's reasonable fast. 20 | - Built according to what I remember of the HTTP protocol, not according to the 21 | RFCs. Should work with most modern browsers, though. 22 | - No support for https. 23 | 24 | The Ugly (aka: bugs, misbehaviour) 25 | - Possible buffer overflows (usually not remotely exploitable) due to no os_snprintf 26 | This can be theoretically remedied by either Espressif including an os_snprintf in 27 | their libs or by using some alternate printf lib, like elm-chans xprintf 28 | 29 | ## SOURCE OF THIS CODE ## 30 | The official esphttpd repo lives at http://git.spritesserver.nl/esphttpd.git/ and 31 | http://git.spritesserver.nl/libesphttpd.git/ . If you're a fan of Github, you can also 32 | peruse the official mirror at https://github.com/Spritetm/esphttpd and https://github.com/Spritetm/libesphttpd . If 33 | you want to discuss this code, there is a subforum at esp8266.com: http://www.esp8266.com/viewforum.php?f=34 . 34 | 35 | 36 | ## ABOUT THE EXAMPLE ## 37 | 38 | When you flash the example into an ESP8266(EX) module, you get a small webserver with a few example 39 | pages. If you've already connected your module to your WLAN before, it'll keep those settings. When 40 | you haven't or the settings are wrong, keep GPIO0 for >5 seconds. The module will reboot into 41 | its STA+AP mode. Connect a computer to the newly formed access point and browse to 42 | http://192.168.4.1/wifi in order to connect the module to your WiFi network. The example also 43 | allows you to control a LED that's connected to GPIO2. 44 | 45 | ## BUILDING EVERYTHING ## 46 | 47 | For this, you need an environment that can compile ESP8266 firmware. Environments for this still 48 | are in flux at the moment, but I'm using esp-open-sdk: https://github.com/pfalcon/esp-open-sdk . 49 | You probably also need an UNIX-like system; I'm working on Debian Linux myself. 50 | 51 | To manage the paths to all this, you can source a small shell fragment into your current session. For 52 | example, I source a file with these contents: 53 | 54 | export PATH=${PWD}/esp-open-sdk/xtensa-lx106-elf/bin:$PATH 55 | export SDK_BASE=${PWD}/esp-open-sdk/sdk 56 | export ESPTOOL=${PWD}/esptool/esptool.py 57 | export ESPPORT=/dev/ttyUSB0 58 | export ESPBAUD=460800 59 | 60 | Actual setup of the SDK and toolchain is out of the scope of this document, so I hope this helps you 61 | enough to set up your own if you haven't already. 62 | 63 | If you have that, you can clone out the source code: 64 | git clone http://git.spritesserver.nl/esphttpd.git/ 65 | 66 | This project makes use of heatshrink, which is a git submodule. To fetch the code: 67 | 68 | cd esphttpd 69 | git submodule init 70 | git submodule update 71 | 72 | Now, build the code: 73 | 74 | make 75 | 76 | Depending on the way you built it, esp-open-sdk sometimes patches Espressifs SDK, needing a slightly different 77 | compiling process. If this is needed, you will get errors during compiling complaining about uint8_t being 78 | undeclared. If this happens, try building like this: 79 | 80 | make USE_OPENSDK=yes 81 | 82 | You can also edit the Makefile to change this more permanently. 83 | 84 | After the compile process, flash the code happens in 2 steps. First the code itself gets flashed. Reset the module into bootloader 85 | mode and enter 'make flash'. 86 | 87 | The 2nd step is to pack the static files the webserver will serve and flash that. Reset the module into 88 | bootloader mode again and enter `make htmlflash`. 89 | 90 | You should have a working webserver now. 91 | 92 | ## WRITING CODE FOR THE WEBSERVER ## 93 | 94 | Please see the README.md of the libesphttpd project for the programming manual. 95 | 96 | 97 | -------------------------------------------------------------------------------- /Makefile.ota: -------------------------------------------------------------------------------- 1 | #Makefile with the options specific to the build of a non-upgradable firmware with 2 | #the espfs combined into the flash binary. 3 | 4 | # Change tagname to some identifier that's unique for your project. 27 chars max. 5 | TAGNAME ?= "generic" 6 | 7 | # linker script used for the linker step 8 | 9 | LD_MAP_1:=512:eagle.app.v6.new.512.app1.ld 1024:eagle.app.v6.new.1024.app1.ld 2048:eagle.app.v6.new.2048.ld 4096:eagle.app.v6.new.2048.ld 10 | LD_MAP_2:=512:eagle.app.v6.new.512.app2.ld 1024:eagle.app.v6.new.1024.app2.ld 2048:eagle.app.v6.new.2048.ld 4096:eagle.app.v6.new.2048.ld 11 | LD_SCRIPT_USR1 := $(call maplookup,$(ESP_SPI_FLASH_SIZE_K),$(LD_MAP_1)) 12 | LD_SCRIPT_USR2 := $(call maplookup,$(ESP_SPI_FLASH_SIZE_K),$(LD_MAP_2)) 13 | 14 | TARGET_OUT_USR1 := $(addprefix $(BUILD_BASE)/,$(TARGET).user1.out) 15 | TARGET_OUT_USR2 := $(addprefix $(BUILD_BASE)/,$(TARGET).user2.out) 16 | TARGET_OUT := $(TARGET_OUT_USR1) $(TARGET_OUT_USR2) 17 | 18 | TARGET_BIN_USR1 := $(addprefix $(BUILD_BASE)/,$(TARGET).user1.bin) 19 | TARGET_BIN_USR2 := $(addprefix $(BUILD_BASE)/,$(TARGET).user2.bin) 20 | TARGET_BIN := $(TARGET_BIN_USR1) $(TARGET_BIN_USR2) 21 | TARGET_OTAFILE := $(addprefix $(BUILD_BASE)/,$(TARGET).ota) 22 | 23 | 24 | BLANKPOS="$$(printf "0x%X" $$(($(ESP_SPI_FLASH_SIZE_K)*512-0x2000)))" 25 | INITDATAPOS="$$(printf "0x%X" $$(($(ESP_SPI_FLASH_SIZE_K)*512-0x4000)))" 26 | 27 | #Convert SPI size into arg for appgen. Format: no=size 28 | FLASH_MAP_CONV:=0:512 2:1024 5:2048 6:4096 29 | ESP_FLASH_SIZE_IX:=$(maplookup $(ESP_SPI_FLASH_SIZE_K),,$(FLASH_MAP_CONV)) 30 | 31 | CFLAGS += -DOTA_TAGNAME=\"$(TAGNAME)\" 32 | 33 | define genappbin 34 | $(1): $$(APP_AR) 35 | $$(vecho) LD $$@ 36 | $$(Q) $$(LD) -Llibesphttpd -L$$(SDK_LIBDIR) $(2) $$(LDFLAGS) -Wl,--start-group $$(LIBS) $$(APP_AR) -Wl,--end-group -o $$@ 37 | 38 | $(3): $(1) 39 | $$(vecho) APPGEN $$@ 40 | $$(Q) $$(OBJCOPY) --only-section .text -O binary $1 build/eagle.app.v6.text.bin 41 | $$(Q) $$(OBJCOPY) --only-section .data -O binary $1 build/eagle.app.v6.data.bin 42 | $$(Q) $$(OBJCOPY) --only-section .rodata -O binary $1 build/eagle.app.v6.rodata.bin 43 | $$(Q) $$(OBJCOPY) --only-section .irom0.text -O binary $1 build/eagle.app.v6.irom0text.bin 44 | $$(Q) cd build; COMPILE=gcc PATH=$$(XTENSA_TOOLS_ROOT):$$(PATH) python $$(APPGEN) $(1:build/%=%) 2 $$(ESP_FLASH_MODE) $$(ESP_FLASH_FREQ_DIV) $$(ESP_FLASH_SIZE_IX) $(4) 45 | $$(Q) rm -f eagle.app.v6.*.bin 46 | $$(Q) mv build/eagle.app.flash.bin $$@ 47 | @echo "** user1.bin uses $$$$(stat -c '%s' $$@) bytes of" $$(ESP_FLASH_MAX) "available" 48 | endef 49 | 50 | $(eval $(call genappbin,$(TARGET_OUT_USR1),$$(LD_SCRIPT_USR1),$$(TARGET_BIN_USR1),1)) 51 | $(eval $(call genappbin,$(TARGET_OUT_USR2),$$(LD_SCRIPT_USR2),$$(TARGET_BIN_USR2),2)) 52 | 53 | .PHONY: ldscript_memspecific.ld 54 | 55 | ldscript_memspecific.ld: 56 | $(vecho) "GEN $@" 57 | $(Q) echo "MEMORY { irom0_0_seg : org = 0x40240000, len = "$$(printf "0x%X" $$(($(ESP_SPI_FLASH_SIZE_K)*1024-0x4000)))" }"> ldscript_memspecific.ld 58 | 59 | 60 | #define makeuser 61 | #$1: $(APP_AR) 62 | # $(vecho) "LD $@" 63 | # $(Q) $(LD) -Llibesphttpd -L$(SDK_LIBDIR) $(LD_SCRIPT) $(EXTRA_LD_SCRIPTS) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $@ 64 | # $(Q) $(OBJCP) --only-section .text -O binary $2 build/eagle.app.v6.text.bin 65 | # $(Q) $(OBJCP) --only-section .data -O binary $2 build/eagle.app.v6.data.bin 66 | # $(Q) $(OBJCP) --only-section .rodata -O binary $2 build/eagle.app.v6.rodata.bin 67 | # $(Q) $(OBJCP) --only-section .irom0.text -O binary $2 build/eagle.app.v6.irom0text.bin 68 | # ls -ls build/eagle*bin 69 | # $(Q) COMPILE=gcc PATH=$(XTENSA_TOOLS_ROOT):$(PATH) python $(APPGEN_TOOL) $(USER1_OUT) 2 $(ESP_FLASH_MODE) $(ESP_FLASH_FREQ_DIV) $(ESP_SPI_SIZE) 70 | # $(Q) rm -f eagle.app.v6.*.bin 71 | # $(Q) mv eagle.app.flash.bin $@ 72 | # @echo "** user1.bin uses $$(stat -c '%s' $@) bytes of" $(ESP_FLASH_MAX) "available" 73 | # $(Q) if [ $$(stat -c '%s' $@) -gt $$(( $(ESP_FLASH_MAX) )) ]; then echo "$@ too big!"; false; fi 74 | #endef 75 | 76 | 77 | #user1.bin: 78 | # $(call makeuser,user1.bin,1) 79 | 80 | libesphttpd/mkupgimg/mkupgimg: libesphttpd/mkupgimg/ 81 | make -C libesphttpd/mkupgimg/ 82 | 83 | $(FW_BASE): $(TARGET_BIN) libesphttpd/mkupgimg/mkupgimg 84 | $(Q) libesphttpd/mkupgimg/mkupgimg $(TARGET_BIN_USR1) $(TARGET_BIN_USR2) $(TAGNAME) $(TARGET_OTAFILE) 85 | 86 | flash: $(TARGET_OUT) $(FW_BASE) 87 | $(Q) $(ESPTOOL) $(ESPTOOL_OPTS) write_flash $(ESPTOOL_FLASHDEF) 0x00000 "$(SDK_BASE)/bin/boot_v1.7.bin" 0x1000 $(TARGET_BIN_USR1) 88 | 89 | blankflash: 90 | $(Q) $(ESPTOOL) $(ESPTOOL_OPTS) write_flash $(ESPTOOL_FLASHDEF) $(BLANKPOS) $(SDK_BASE)/bin/blank.bin $(INITDATAPOS) $(SDK_BASE)/bin/esp_init_data_default.bin 91 | 92 | httpflash: $(FW_BASE) 93 | $(Q) curl -X POST --data-binary '@build/httpd.ota' $(ESPIP)/flash/upload > /dev/null 94 | $(Q) curl $(ESPIP)/flash/reboot 95 | $(Q) echo -e '\nDone' 96 | 97 | -------------------------------------------------------------------------------- /include/uart_hw.h: -------------------------------------------------------------------------------- 1 | //Generated at 2012-07-03 18:44:06 2 | /* 3 | * Copyright (c) 2010 - 2011 Espressif System 4 | * 5 | */ 6 | 7 | #ifndef UART_REGISTER_H_INCLUDED 8 | #define UART_REGISTER_H_INCLUDED 9 | #define REG_UART_BASE( i ) (0x60000000+(i)*0xf00) 10 | //version value:32'h062000 11 | 12 | #define UART_FIFO( i ) (REG_UART_BASE( i ) + 0x0) 13 | #define UART_RXFIFO_RD_BYTE 0x000000FF 14 | #define UART_RXFIFO_RD_BYTE_S 0 15 | 16 | #define UART_INT_RAW( i ) (REG_UART_BASE( i ) + 0x4) 17 | #define UART_RXFIFO_TOUT_INT_RAW (BIT(8)) 18 | #define UART_BRK_DET_INT_RAW (BIT(7)) 19 | #define UART_CTS_CHG_INT_RAW (BIT(6)) 20 | #define UART_DSR_CHG_INT_RAW (BIT(5)) 21 | #define UART_RXFIFO_OVF_INT_RAW (BIT(4)) 22 | #define UART_FRM_ERR_INT_RAW (BIT(3)) 23 | #define UART_PARITY_ERR_INT_RAW (BIT(2)) 24 | #define UART_TXFIFO_EMPTY_INT_RAW (BIT(1)) 25 | #define UART_RXFIFO_FULL_INT_RAW (BIT(0)) 26 | 27 | #define UART_INT_ST( i ) (REG_UART_BASE( i ) + 0x8) 28 | #define UART_RXFIFO_TOUT_INT_ST (BIT(8)) 29 | #define UART_BRK_DET_INT_ST (BIT(7)) 30 | #define UART_CTS_CHG_INT_ST (BIT(6)) 31 | #define UART_DSR_CHG_INT_ST (BIT(5)) 32 | #define UART_RXFIFO_OVF_INT_ST (BIT(4)) 33 | #define UART_FRM_ERR_INT_ST (BIT(3)) 34 | #define UART_PARITY_ERR_INT_ST (BIT(2)) 35 | #define UART_TXFIFO_EMPTY_INT_ST (BIT(1)) 36 | #define UART_RXFIFO_FULL_INT_ST (BIT(0)) 37 | 38 | #define UART_INT_ENA( i ) (REG_UART_BASE( i ) + 0xC) 39 | #define UART_RXFIFO_TOUT_INT_ENA (BIT(8)) 40 | #define UART_BRK_DET_INT_ENA (BIT(7)) 41 | #define UART_CTS_CHG_INT_ENA (BIT(6)) 42 | #define UART_DSR_CHG_INT_ENA (BIT(5)) 43 | #define UART_RXFIFO_OVF_INT_ENA (BIT(4)) 44 | #define UART_FRM_ERR_INT_ENA (BIT(3)) 45 | #define UART_PARITY_ERR_INT_ENA (BIT(2)) 46 | #define UART_TXFIFO_EMPTY_INT_ENA (BIT(1)) 47 | #define UART_RXFIFO_FULL_INT_ENA (BIT(0)) 48 | 49 | #define UART_INT_CLR( i ) (REG_UART_BASE( i ) + 0x10) 50 | #define UART_RXFIFO_TOUT_INT_CLR (BIT(8)) 51 | #define UART_BRK_DET_INT_CLR (BIT(7)) 52 | #define UART_CTS_CHG_INT_CLR (BIT(6)) 53 | #define UART_DSR_CHG_INT_CLR (BIT(5)) 54 | #define UART_RXFIFO_OVF_INT_CLR (BIT(4)) 55 | #define UART_FRM_ERR_INT_CLR (BIT(3)) 56 | #define UART_PARITY_ERR_INT_CLR (BIT(2)) 57 | #define UART_TXFIFO_EMPTY_INT_CLR (BIT(1)) 58 | #define UART_RXFIFO_FULL_INT_CLR (BIT(0)) 59 | 60 | #define UART_CLKDIV( i ) (REG_UART_BASE( i ) + 0x14) 61 | #define UART_CLKDIV_CNT 0x000FFFFF 62 | #define UART_CLKDIV_S 0 63 | 64 | #define UART_AUTOBAUD( i ) (REG_UART_BASE( i ) + 0x18) 65 | #define UART_GLITCH_FILT 0x000000FF 66 | #define UART_GLITCH_FILT_S 8 67 | #define UART_AUTOBAUD_EN (BIT(0)) 68 | 69 | #define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C) 70 | #define UART_TXD (BIT(31)) 71 | #define UART_RTSN (BIT(30)) 72 | #define UART_DTRN (BIT(29)) 73 | #define UART_TXFIFO_CNT 0x000000FF 74 | #define UART_TXFIFO_CNT_S 16 75 | #define UART_RXD (BIT(15)) 76 | #define UART_CTSN (BIT(14)) 77 | #define UART_DSRN (BIT(13)) 78 | #define UART_RXFIFO_CNT 0x000000FF 79 | #define UART_RXFIFO_CNT_S 0 80 | 81 | #define UART_CONF0( i ) (REG_UART_BASE( i ) + 0x20) 82 | #define UART_TXFIFO_RST (BIT(18)) 83 | #define UART_RXFIFO_RST (BIT(17)) 84 | #define UART_IRDA_EN (BIT(16)) 85 | #define UART_TX_FLOW_EN (BIT(15)) 86 | #define UART_LOOPBACK (BIT(14)) 87 | #define UART_IRDA_RX_INV (BIT(13)) 88 | #define UART_IRDA_TX_INV (BIT(12)) 89 | #define UART_IRDA_WCTL (BIT(11)) 90 | #define UART_IRDA_TX_EN (BIT(10)) 91 | #define UART_IRDA_DPLX (BIT(9)) 92 | #define UART_TXD_BRK (BIT(8)) 93 | #define UART_SW_DTR (BIT(7)) 94 | #define UART_SW_RTS (BIT(6)) 95 | #define UART_STOP_BIT_NUM 0x00000003 96 | #define UART_STOP_BIT_NUM_S 4 97 | #define UART_BIT_NUM 0x00000003 98 | #define UART_BIT_NUM_S 2 99 | #define UART_PARITY_EN (BIT(1)) 100 | #define UART_PARITY (BIT(0)) 101 | 102 | #define UART_CONF1( i ) (REG_UART_BASE( i ) + 0x24) 103 | #define UART_RX_TOUT_EN (BIT(31)) 104 | #define UART_RX_TOUT_THRHD 0x0000007F 105 | #define UART_RX_TOUT_THRHD_S 24 106 | #define UART_RX_FLOW_EN (BIT(23)) 107 | #define UART_RX_FLOW_THRHD 0x0000007F 108 | #define UART_RX_FLOW_THRHD_S 16 109 | #define UART_TXFIFO_EMPTY_THRHD 0x0000007F 110 | #define UART_TXFIFO_EMPTY_THRHD_S 8 111 | #define UART_RXFIFO_FULL_THRHD 0x0000007F 112 | #define UART_RXFIFO_FULL_THRHD_S 0 113 | 114 | #define UART_LOWPULSE( i ) (REG_UART_BASE( i ) + 0x28) 115 | #define UART_LOWPULSE_MIN_CNT 0x000FFFFF 116 | #define UART_LOWPULSE_MIN_CNT_S 0 117 | 118 | #define UART_HIGHPULSE( i ) (REG_UART_BASE( i ) + 0x2C) 119 | #define UART_HIGHPULSE_MIN_CNT 0x000FFFFF 120 | #define UART_HIGHPULSE_MIN_CNT_S 0 121 | 122 | #define UART_PULSE_NUM( i ) (REG_UART_BASE( i ) + 0x30) 123 | #define UART_PULSE_NUM_CNT 0x0003FF 124 | #define UART_PULSE_NUM_CNT_S 0 125 | 126 | #define UART_DATE( i ) (REG_UART_BASE( i ) + 0x78) 127 | #define UART_ID( i ) (REG_UART_BASE( i ) + 0x7C) 128 | #endif // UART_REGISTER_H_INCLUDED 129 | 130 | #define RX_BUFF_SIZE 256 131 | #define TX_BUFF_SIZE 100 132 | #define UART0 0 133 | #define UART1 1 134 | 135 | typedef enum { 136 | FIVE_BITS = 0x0, 137 | SIX_BITS = 0x1, 138 | SEVEN_BITS = 0x2, 139 | EIGHT_BITS = 0x3 140 | } UartBitsNum4Char; 141 | 142 | typedef enum { 143 | ONE_STOP_BIT = 0, 144 | ONE_HALF_STOP_BIT = BIT2, 145 | TWO_STOP_BIT = BIT2 146 | } UartStopBitsNum; 147 | 148 | typedef enum { 149 | NONE_BITS = 0, 150 | ODD_BITS = 0, 151 | EVEN_BITS = BIT4 152 | } UartParityMode; 153 | 154 | typedef enum { 155 | STICK_PARITY_DIS = 0, 156 | STICK_PARITY_EN = BIT3 | BIT5 157 | } UartExistParity; 158 | 159 | typedef enum { 160 | BIT_RATE_9600 = 9600, 161 | BIT_RATE_19200 = 19200, 162 | BIT_RATE_38400 = 38400, 163 | BIT_RATE_57600 = 57600, 164 | BIT_RATE_74880 = 74880, 165 | BIT_RATE_115200 = 115200, 166 | BIT_RATE_230400 = 230400, 167 | BIT_RATE_460800 = 460800, 168 | BIT_RATE_921600 = 921600 169 | } UartBautRate; 170 | 171 | typedef enum { 172 | NONE_CTRL, 173 | HARDWARE_CTRL, 174 | XON_XOFF_CTRL 175 | } UartFlowCtrl; 176 | 177 | typedef enum { 178 | EMPTY, 179 | UNDER_WRITE, 180 | WRITE_OVER 181 | } RcvMsgBuffState; 182 | 183 | typedef struct { 184 | uint32 TrxBuffSize; 185 | uint8 *pTrxBuff; 186 | } TrxMsgBuff; 187 | 188 | typedef enum { 189 | BAUD_RATE_DET, 190 | WAIT_SYNC_FRM, 191 | SRCH_MSG_HEAD, 192 | RCV_MSG_BODY, 193 | RCV_ESC_CHAR, 194 | } RcvMsgState; 195 | 196 | -------------------------------------------------------------------------------- /html/test/test.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Code to test the webserver. This depends on: 4 | - The cat images being available, for concurrent espfs testing 5 | - the test.cgi script available, for generic data mangling tests 6 | 7 | 8 | This test does a max of 4 requests in parallel. The nonos SDK supports a max of 9 | 5 connections; the default libesphttpd setting is 4 sockets at a time. Unfortunately, 10 | the nonos sdk just closes all sockets opened after the available sockets are opened, 11 | instead of queueing them until a socket frees up. 12 | */ 13 | 14 | 15 | function log(line) { 16 | $("#log").insertAdjacentHTML('beforeend', line+'
'); 17 | } 18 | 19 | 20 | //Load an image multiple times in parallel 21 | function testParLdImg(url, ct, doneFn) { 22 | var im=[]; 23 | var state={"loaded":0, "count":ct, "doneFn": doneFn, "error":false}; 24 | for (var x=0; xthis.ts+2000) { 63 | log("..."+Math.floor(e.loaded*100/this.len).toString()+"%"); 64 | this.ts=Date.now(); 65 | } 66 | }.bind(state); 67 | } 68 | xhr.send(); 69 | } 70 | 71 | 72 | function testUploadCgi(len, doneFn) { 73 | var xhr=j(); 74 | var state={"len":len, "doneFn":doneFn, "ts": Date.now()}; 75 | var data=""; 76 | for (var x=0; x=200 && xhr.status<300) { 80 | var ulen=parseInt(xhr.responseText); 81 | if (ulen==this.len) { 82 | log("Uploaded "+this.len+" bytes successfully."); 83 | this.doneFn(true); 84 | } else { 85 | log("Webserver received "+ulen+" bytes successfully, but sent "+this.len+"!"); 86 | this.doneFn(false); 87 | } 88 | } else if (xhr.readyState==4) { 89 | log("Failed! Error "+xhr.status); 90 | this.doneFn(false); 91 | } 92 | }.bind(state); 93 | //If the webbrowser enables it, show progress. 94 | if (typeof xhr.upload.onprogress != 'undefined') { 95 | xhr.upload.onprogress=function(e) { 96 | if (Date.now()>this.ts+2000) { 97 | log("..."+Math.floor(e.loaded*100/e.total).toString()+"%"); 98 | this.ts=Date.now(); 99 | } 100 | }.bind(state); 101 | } 102 | //Upload the file 103 | xhr.send(data); 104 | } 105 | 106 | function hammerNext(state, xhr) { 107 | if (state.done==state.count) { 108 | state.doneFn(!state.error); 109 | } 110 | if (state.started==state.count) return; 111 | xhr.open("GET", "test.cgi?len="+state.len+"&nocache="+Math.floor(Math.random()*100000).toString()); 112 | xhr.onreadystatechange=function(xhr) { 113 | if (xhr.readyState==4 && xhr.status>=200 && xhr.status<300) { 114 | if (xhr.response.length==this.len) { 115 | state.done++; 116 | hammerNext(this, xhr); 117 | } else { 118 | log("Downloaded "+xhr.response.length+" bytes successfully, but needed "+this.len+"!"); 119 | state.done++; 120 | hammerNext(this, xhr); 121 | } 122 | } else if (xhr.readyState==4) { 123 | log("Failed! Error "+xhr.status); 124 | state.done++; 125 | hammerNext(this, xhr); 126 | } 127 | }.bind(state, xhr); 128 | //If the webbrowser enables it, show progress. 129 | if (typeof xhr.onprogress != 'undefined') { 130 | xhr.onprogress=function(e) { 131 | if (Date.now()>this.ts+2000) { 132 | log("..."+state.done+"/"+state.count); 133 | this.ts=Date.now(); 134 | } 135 | }.bind(state); 136 | } 137 | state.started++; 138 | xhr.send(); 139 | } 140 | 141 | function testHammer(count, par, len, doneFn) { 142 | var state={"count":count, "started":0, "done":0, "par":par, "len":len, "doneFn":doneFn, "ts": Date.now(), "error":false}; 143 | var xhr=[]; 144 | for (var i=0; iSuccess!"); 159 | successCnt++; 160 | } else { 161 | log("Test failed!"); 162 | } 163 | } 164 | tstState++; 165 | if (tstState==1) { 166 | log("Testing parallel load of espfs files..."); 167 | testParLdImg("../cats/kitten-loves-toy.jpg", 3, nextTest); 168 | } else if (tstState==2) { 169 | log("Testing GET request of 32K..."); 170 | testDownloadCgi(32*1024, nextTest); 171 | } else if (tstState==3) { 172 | log("Testing GET request of 128K..."); 173 | testDownloadCgi(128*1024, nextTest); 174 | } else if (tstState==4) { 175 | log("Testing GET request of 512K..."); 176 | testDownloadCgi(512*1024, nextTest); 177 | } else if (tstState==5) { 178 | log("Testing POST request of 512 bytes..."); 179 | testUploadCgi(512, nextTest); 180 | } else if (tstState==6) { 181 | log("Testing POST request of 16K bytes..."); 182 | testUploadCgi(16*1024, nextTest); 183 | } else if (tstState==7) { 184 | log("Testing POST request of 512K bytes..."); 185 | testUploadCgi(512*1024, nextTest); 186 | } else if (tstState==8) { 187 | log("Hammering webserver with 500 requests of size 512..."); 188 | testHammer(500, 3, 512, nextTest); 189 | } else if (tstState==9) { 190 | log("Hammering webserver with 500 requests of size 2048..."); 191 | testHammer(500, 3, 2048, nextTest); 192 | } else { 193 | log("Tests done! "+successCnt+" out of "+(tstState-1)+" tests were successful."); 194 | } 195 | } 196 | 197 | 198 | 199 | window.onload=function(e) { 200 | log("Starting tests."); 201 | nextTest(false); 202 | } 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #You can build this example in three ways: 2 | # 'separate' - Separate espfs and binaries, no OTA upgrade 3 | # 'combined' - Combined firmware blob, no OTA upgrade 4 | # 'ota' - Combined firmware blob with OTA upgrades. 5 | #Please do a 'make clean' after changing this. 6 | #OUTPUT_TYPE=separate 7 | #OUTPUT_TYPE=combined 8 | OUTPUT_TYPE=ota 9 | 10 | #SPI flash size, in K 11 | ESP_SPI_FLASH_SIZE_K=1024 12 | #0: QIO, 1: QOUT, 2: DIO, 3: DOUT 13 | ESP_FLASH_MODE=0 14 | #0: 40MHz, 1: 26MHz, 2: 20MHz, 15: 80MHz 15 | ESP_FLASH_FREQ_DIV=0 16 | 17 | 18 | ifeq ("$(OUTPUT_TYPE)","separate") 19 | #In case of separate ESPFS and binaries, set the pos and length of the ESPFS here. 20 | ESPFS_POS = 0x18000 21 | ESPFS_SIZE = 0x28000 22 | endif 23 | 24 | # Output directors to store intermediate compiled files 25 | # relative to the project directory 26 | BUILD_BASE = build 27 | FW_BASE = firmware 28 | 29 | # Base directory for the compiler. Needs a / at the end; if not set it'll use the tools that are in 30 | # the PATH. 31 | XTENSA_TOOLS_ROOT ?= 32 | 33 | # base directory of the ESP8266 SDK package, absolute 34 | SDK_BASE ?= /opt/Espressif/ESP8266_SDK 35 | 36 | # Opensdk patches stdint.h when compiled with an internal SDK. If you run into compile problems pertaining to 37 | # redefinition of int types, try setting this to 'yes'. 38 | USE_OPENSDK?=no 39 | 40 | #Esptool.py path and port 41 | ESPTOOL ?= esptool.py 42 | ESPPORT ?= /dev/ttyUSB0 43 | #ESPDELAY indicates seconds to wait between flashing the two binary images 44 | ESPDELAY ?= 3 45 | ESPBAUD ?= 460800 46 | 47 | #Appgen path and name 48 | APPGEN ?= $(SDK_BASE)/tools/gen_appbin.py 49 | 50 | # name for the target project 51 | TARGET = httpd 52 | 53 | # which modules (subdirectories) of the project to include in compiling 54 | MODULES = user 55 | EXTRA_INCDIR = include libesphttpd/include 56 | 57 | # libraries used in this project, mainly provided by the SDK 58 | LIBS = c gcc hal phy pp net80211 wpa main lwip crypto 59 | #Add in esphttpd lib 60 | LIBS += esphttpd 61 | 62 | # compiler flags using during compilation of source files 63 | CFLAGS = -Os -ggdb -std=gnu99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \ 64 | -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH \ 65 | -Wno-address 66 | 67 | # linker flags used to generate the main object file 68 | LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static 69 | 70 | 71 | # various paths from the SDK used in this project 72 | SDK_LIBDIR = lib 73 | SDK_LDDIR = ld 74 | SDK_INCDIR = include include/json 75 | 76 | # select which tools to use as compiler, librarian and linker 77 | CC := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc 78 | AR := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-ar 79 | LD := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc 80 | OBJCOPY := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objcopy 81 | 82 | #Additional (maybe generated) ld scripts to link in 83 | EXTRA_LD_SCRIPTS:= 84 | 85 | 86 | #### 87 | #### no user configurable options below here 88 | #### 89 | SRC_DIR := $(MODULES) 90 | BUILD_DIR := $(addprefix $(BUILD_BASE)/,$(MODULES)) 91 | 92 | SDK_LIBDIR := $(addprefix $(SDK_BASE)/,$(SDK_LIBDIR)) 93 | SDK_INCDIR := $(addprefix -I$(SDK_BASE)/,$(SDK_INCDIR)) 94 | 95 | SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c)) 96 | ASMSRC = $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.S)) 97 | OBJ = $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC)) 98 | OBJ += $(patsubst %.S,$(BUILD_BASE)/%.o,$(ASMSRC)) 99 | APP_AR := $(addprefix $(BUILD_BASE)/,$(TARGET)_app.a) 100 | 101 | 102 | V ?= $(VERBOSE) 103 | ifeq ("$(V)","1") 104 | Q := 105 | vecho := @true 106 | else 107 | Q := @ 108 | vecho := @echo 109 | endif 110 | 111 | ifeq ("$(USE_OPENSDK)","yes") 112 | CFLAGS += -DUSE_OPENSDK 113 | else 114 | CFLAGS += -D_STDINT_H 115 | endif 116 | 117 | ifeq ("$(GZIP_COMPRESSION)","yes") 118 | CFLAGS += -DGZIP_COMPRESSION 119 | endif 120 | 121 | ifeq ("$(USE_HEATSHRINK)","yes") 122 | CFLAGS += -DESPFS_HEATSHRINK 123 | endif 124 | 125 | ifeq ("$(ESPFS_POS)","") 126 | #No hardcoded espfs position: link it in with the binaries. 127 | LIBS += webpages-espfs 128 | else 129 | #Hardcoded espfs location: Pass espfs position to rest of code 130 | CFLAGS += -DESPFS_POS=$(ESPFS_POS) -DESPFS_SIZE=$(ESPFS_SIZE) 131 | endif 132 | 133 | ifeq ("$(OUTPUT_TYPE)","ota") 134 | CFLAGS += -DOTA_FLASH_SIZE_K=$(ESP_SPI_FLASH_SIZE_K) 135 | endif 136 | 137 | 138 | #Define default target. If not defined here the one in the included Makefile is used as the default one. 139 | default-tgt: all 140 | 141 | define maplookup 142 | $(patsubst $(strip $(1)):%,%,$(filter $(strip $(1)):%,$(2))) 143 | endef 144 | 145 | 146 | #Include options and target specific to the OUTPUT_TYPE 147 | include Makefile.$(OUTPUT_TYPE) 148 | 149 | #Add all prefixes to paths 150 | LIBS := $(addprefix -l,$(LIBS)) 151 | ifeq ("$(LD_SCRIPT_USR1)", "") 152 | LD_SCRIPT := $(addprefix -T$(SDK_BASE)/$(SDK_LDDIR)/,$(LD_SCRIPT)) 153 | else 154 | LD_SCRIPT_USR1 := $(addprefix -T$(SDK_BASE)/$(SDK_LDDIR)/,$(LD_SCRIPT_USR1)) 155 | LD_SCRIPT_USR2 := $(addprefix -T$(SDK_BASE)/$(SDK_LDDIR)/,$(LD_SCRIPT_USR2)) 156 | endif 157 | INCDIR := $(addprefix -I,$(SRC_DIR)) 158 | EXTRA_INCDIR := $(addprefix -I,$(EXTRA_INCDIR)) 159 | MODULE_INCDIR := $(addsuffix /include,$(INCDIR)) 160 | 161 | ESP_FLASH_SIZE_IX=$(call maplookup,$(ESP_SPI_FLASH_SIZE_K),512:0 1024:2 2048:5 4096:6) 162 | ESPTOOL_FREQ=$(call maplookup,$(ESP_FLASH_FREQ_DIV),0:40m 1:26m 2:20m 0xf:80m 15:80m) 163 | ESPTOOL_MODE=$(call maplookup,$(ESP_FLASH_MODE),0:qio 1:qout 2:dio 3:dout) 164 | ESPTOOL_SIZE=$(call maplookup,$(ESP_SPI_FLASH_SIZE_K),512:4m 256:2m 1024:8m 2048:16m 4096:322m-c1) 165 | 166 | ESPTOOL_OPTS=--port $(ESPPORT) --baud $(ESPBAUD) 167 | ESPTOOL_FLASHDEF=--flash_freq $(ESPTOOL_FREQ) --flash_mode $(ESPTOOL_MODE) --flash_size $(ESPTOOL_SIZE) 168 | 169 | vpath %.c $(SRC_DIR) 170 | vpath %.S $(SRC_DIR) 171 | 172 | define compile-objects 173 | $1/%.o: %.c 174 | $(vecho) "CC $$<" 175 | $(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@ 176 | 177 | $1/%.o: %.S 178 | $(vecho) "CC $$<" 179 | $(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@ 180 | endef 181 | 182 | .PHONY: all checkdirs clean libesphttpd default-tgt 183 | 184 | all: checkdirs $(TARGET_OUT) $(FW_BASE) 185 | 186 | libesphttpd/Makefile: 187 | $(Q) echo "No libesphttpd submodule found. Using git to fetch it..." 188 | $(Q) git submodule init 189 | $(Q) git submodule update 190 | 191 | libesphttpd: libesphttpd/Makefile 192 | $(Q) make -C libesphttpd USE_OPENSDK=$(USE_OPENSDK) 193 | 194 | $(APP_AR): libesphttpd $(OBJ) 195 | $(vecho) "AR $@" 196 | $(Q) $(AR) cru $@ $(OBJ) 197 | 198 | checkdirs: $(BUILD_DIR) 199 | 200 | $(BUILD_DIR): 201 | $(Q) mkdir -p $@ 202 | 203 | clean: 204 | $(Q) make -C libesphttpd clean 205 | $(Q) rm -f $(APP_AR) 206 | $(Q) rm -f $(TARGET_OUT) 207 | $(Q) find $(BUILD_BASE) -type f | xargs rm -f 208 | $(Q) rm -rf $(FW_BASE) 209 | 210 | 211 | $(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir)))) 212 | -------------------------------------------------------------------------------- /user/user_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * "THE BEER-WARE LICENSE" (Revision 42): 4 | * Jeroen Domburg wrote this file. As long as you retain 5 | * this notice you can do whatever you want with this stuff. If we meet some day, 6 | * and you think this stuff is worth it, you can buy me a beer in return. 7 | * ---------------------------------------------------------------------------- 8 | */ 9 | 10 | /* 11 | This is example code for the esphttpd library. It's a small-ish demo showing off 12 | the server, including WiFi connection management capabilities, some IO and 13 | some pictures of cats. 14 | */ 15 | 16 | #include 17 | #include "httpd.h" 18 | #include "io.h" 19 | #include "httpdespfs.h" 20 | #include "cgi.h" 21 | #include "cgiwifi.h" 22 | #include "cgiflash.h" 23 | #include "stdout.h" 24 | #include "auth.h" 25 | #include "espfs.h" 26 | #include "captdns.h" 27 | #include "webpages-espfs.h" 28 | #include "cgiwebsocket.h" 29 | #include "cgi-test.h" 30 | 31 | //The example can print out the heap use every 3 seconds. You can use this to catch memory leaks. 32 | //#define SHOW_HEAP_USE 33 | 34 | //Function that tells the authentication system what users/passwords live on the system. 35 | //This is disabled in the default build; if you want to try it, enable the authBasic line in 36 | //the builtInUrls below. 37 | int myPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen) { 38 | if (no==0) { 39 | os_strcpy(user, "admin"); 40 | os_strcpy(pass, "s3cr3t"); 41 | return 1; 42 | //Add more users this way. Check against incrementing no for each user added. 43 | // } else if (no==1) { 44 | // os_strcpy(user, "user1"); 45 | // os_strcpy(pass, "something"); 46 | // return 1; 47 | } 48 | return 0; 49 | } 50 | 51 | static ETSTimer websockTimer; 52 | 53 | //Broadcast the uptime in seconds every second over connected websockets 54 | static void ICACHE_FLASH_ATTR websockTimerCb(void *arg) { 55 | static int ctr=0; 56 | char buff[128]; 57 | ctr++; 58 | os_sprintf(buff, "Up for %d minutes %d seconds!\n", ctr/60, ctr%60); 59 | cgiWebsockBroadcast("/websocket/ws.cgi", buff, os_strlen(buff), WEBSOCK_FLAG_NONE); 60 | } 61 | 62 | //On reception of a message, send "You sent: " plus whatever the other side sent 63 | void myWebsocketRecv(Websock *ws, char *data, int len, int flags) { 64 | int i; 65 | char buff[128]; 66 | os_sprintf(buff, "You sent: "); 67 | for (i=0; irecvCb=myWebsocketRecv; 75 | cgiWebsocketSend(ws, "Hi, Websocket!", 14, WEBSOCK_FLAG_NONE); 76 | } 77 | 78 | //On reception of a message, echo it back verbatim 79 | void myEchoWebsocketRecv(Websock *ws, char *data, int len, int flags) { 80 | os_printf("EchoWs: echo, len=%d\n", len); 81 | cgiWebsocketSend(ws, data, len, flags); 82 | } 83 | 84 | //Echo websocket connected. Install reception handler. 85 | void myEchoWebsocketConnect(Websock *ws) { 86 | os_printf("EchoWs: connect\n"); 87 | ws->recvCb=myEchoWebsocketRecv; 88 | } 89 | 90 | 91 | #ifdef ESPFS_POS 92 | CgiUploadFlashDef uploadParams={ 93 | .type=CGIFLASH_TYPE_ESPFS, 94 | .fw1Pos=ESPFS_POS, 95 | .fw2Pos=0, 96 | .fwSize=ESPFS_SIZE, 97 | }; 98 | #define INCLUDE_FLASH_FNS 99 | #endif 100 | #ifdef OTA_FLASH_SIZE_K 101 | CgiUploadFlashDef uploadParams={ 102 | .type=CGIFLASH_TYPE_FW, 103 | .fw1Pos=0x1000, 104 | .fw2Pos=((OTA_FLASH_SIZE_K*1024)/2)+0x1000, 105 | .fwSize=((OTA_FLASH_SIZE_K*1024)/2)-0x1000, 106 | .tagName=OTA_TAGNAME 107 | }; 108 | #define INCLUDE_FLASH_FNS 109 | #endif 110 | 111 | /* 112 | This is the main url->function dispatching data struct. 113 | In short, it's a struct with various URLs plus their handlers. The handlers can 114 | be 'standard' CGI functions you wrote, or 'special' CGIs requiring an argument. 115 | They can also be auth-functions. An asterisk will match any url starting with 116 | everything before the asterisks; "*" matches everything. The list will be 117 | handled top-down, so make sure to put more specific rules above the more 118 | general ones. Authorization things (like authBasic) act as a 'barrier' and 119 | should be placed above the URLs they protect. 120 | */ 121 | HttpdBuiltInUrl builtInUrls[]={ 122 | {"*", cgiRedirectApClientToHostname, "esp8266.nonet"}, 123 | {"/", cgiRedirect, "/index.tpl"}, 124 | {"/led.tpl", cgiEspFsTemplate, tplLed}, 125 | {"/index.tpl", cgiEspFsTemplate, tplCounter}, 126 | {"/led.cgi", cgiLed, NULL}, 127 | #ifdef INCLUDE_FLASH_FNS 128 | {"/flash/next", cgiGetFirmwareNext, &uploadParams}, 129 | {"/flash/upload", cgiUploadFirmware, &uploadParams}, 130 | #endif 131 | {"/flash/reboot", cgiRebootFirmware, NULL}, 132 | 133 | //Routines to make the /wifi URL and everything beneath it work. 134 | 135 | //Enable the line below to protect the WiFi configuration with an username/password combo. 136 | // {"/wifi/*", authBasic, myPassFn}, 137 | 138 | {"/wifi", cgiRedirect, "/wifi/wifi.tpl"}, 139 | {"/wifi/", cgiRedirect, "/wifi/wifi.tpl"}, 140 | {"/wifi/wifiscan.cgi", cgiWiFiScan, NULL}, 141 | {"/wifi/wifi.tpl", cgiEspFsTemplate, tplWlan}, 142 | {"/wifi/connect.cgi", cgiWiFiConnect, NULL}, 143 | {"/wifi/connstatus.cgi", cgiWiFiConnStatus, NULL}, 144 | {"/wifi/setmode.cgi", cgiWiFiSetMode, NULL}, 145 | 146 | {"/websocket/ws.cgi", cgiWebsocket, myWebsocketConnect}, 147 | {"/websocket/echo.cgi", cgiWebsocket, myEchoWebsocketConnect}, 148 | 149 | {"/test", cgiRedirect, "/test/index.html"}, 150 | {"/test/", cgiRedirect, "/test/index.html"}, 151 | {"/test/test.cgi", cgiTestbed, NULL}, 152 | 153 | {"*", cgiEspFsHook, NULL}, //Catch-all cgi function for the filesystem 154 | {NULL, NULL, NULL} 155 | }; 156 | 157 | 158 | #ifdef SHOW_HEAP_USE 159 | static ETSTimer prHeapTimer; 160 | 161 | static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg) { 162 | os_printf("Heap: %ld\n", (unsigned long)system_get_free_heap_size()); 163 | } 164 | #endif 165 | 166 | //Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done. 167 | void user_init(void) { 168 | stdoutInit(); 169 | ioInit(); 170 | captdnsInit(); 171 | 172 | // 0x40200000 is the base address for spi flash memory mapping, ESPFS_POS is the position 173 | // where image is written in flash that is defined in Makefile. 174 | #ifdef ESPFS_POS 175 | espFsInit((void*)(0x40200000 + ESPFS_POS)); 176 | #else 177 | espFsInit((void*)(webpages_espfs_start)); 178 | #endif 179 | httpdInit(builtInUrls, 80); 180 | #ifdef SHOW_HEAP_USE 181 | os_timer_disarm(&prHeapTimer); 182 | os_timer_setfn(&prHeapTimer, prHeapTimerCb, NULL); 183 | os_timer_arm(&prHeapTimer, 3000, 1); 184 | #endif 185 | os_timer_disarm(&websockTimer); 186 | os_timer_setfn(&websockTimer, websockTimerCb, NULL); 187 | os_timer_arm(&websockTimer, 1000, 1); 188 | os_printf("\nReady\n"); 189 | } 190 | 191 | void user_rf_pre_init() { 192 | //Not needed, but some SDK versions want this defined. 193 | } 194 | 195 | 196 | //Sdk 2.0.0 needs extra sector to store rf cal stuff. Place that at the end of the flash. 197 | uint32 ICACHE_FLASH_ATTR 198 | user_rf_cal_sector_set(void) 199 | { 200 | enum flash_size_map size_map = system_get_flash_size_map(); 201 | uint32 rf_cal_sec = 0; 202 | 203 | switch (size_map) { 204 | case FLASH_SIZE_4M_MAP_256_256: 205 | rf_cal_sec = 128 - 8; 206 | break; 207 | 208 | case FLASH_SIZE_8M_MAP_512_512: 209 | rf_cal_sec = 256 - 5; 210 | break; 211 | 212 | case FLASH_SIZE_16M_MAP_512_512: 213 | case FLASH_SIZE_16M_MAP_1024_1024: 214 | rf_cal_sec = 512 - 5; 215 | break; 216 | 217 | case FLASH_SIZE_32M_MAP_512_512: 218 | case FLASH_SIZE_32M_MAP_1024_1024: 219 | rf_cal_sec = 1024 - 5; 220 | break; 221 | 222 | default: 223 | rf_cal_sec = 0; 224 | break; 225 | } 226 | 227 | return rf_cal_sec; 228 | } 229 | 230 | --------------------------------------------------------------------------------