Add libesphttpd to extras and supporting example (#458)
* libesphttpd: added extras and example * Added "heatshrink" as a submodule * Updated libesphttpd * Updated libesphttpd * Trying to fix the commit id * Updated libesphttpd * Added zlib1g-dev package * Use native gcc to build mkespfsimage and mkupgimg * Added NS and GW for DHCP server configuration
This commit is contained in:
parent
d36e9d65a0
commit
09b8b8087c
30 changed files with 1192 additions and 0 deletions
6
.gitmodules
vendored
6
.gitmodules
vendored
|
@ -28,3 +28,9 @@
|
||||||
[submodule "extras/crc_generic/crc_lib"]
|
[submodule "extras/crc_generic/crc_lib"]
|
||||||
path = extras/crc_generic/crc_lib
|
path = extras/crc_generic/crc_lib
|
||||||
url = https://github.com/Zaltora/crc_generic_lib.git
|
url = https://github.com/Zaltora/crc_generic_lib.git
|
||||||
|
[submodule "extras/libesphttpd/libesphttpd"]
|
||||||
|
path = extras/libesphttpd/libesphttpd
|
||||||
|
url = https://github.com/nochkin/libesphttpd
|
||||||
|
[submodule "extras/libesphttpd/libesphttpd/lib/heatshrink"]
|
||||||
|
path = extras/libesphttpd/libesphttpd/lib/heatshrink
|
||||||
|
url = https://github.com/atomicobject/heatshrink
|
||||||
|
|
|
@ -34,6 +34,7 @@ addons:
|
||||||
- git
|
- git
|
||||||
- help2man
|
- help2man
|
||||||
- vim-common
|
- vim-common
|
||||||
|
- zlib1g-dev
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- pip install --user pyserial
|
- pip install --user pyserial
|
||||||
|
|
11
examples/esphttpd/FreeRTOSConfig.h
Normal file
11
examples/esphttpd/FreeRTOSConfig.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/* FreeRTOSConfig overrides.
|
||||||
|
|
||||||
|
This is intended as an example of overriding some of the default FreeRTOSConfig settings,
|
||||||
|
which are otherwise found in FreeRTOS/Source/include/FreeRTOSConfig.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define configUSE_RECURSIVE_MUTEXES 1
|
||||||
|
|
||||||
|
/* Use the defaults for everything else */
|
||||||
|
#include_next<FreeRTOSConfig.h>
|
||||||
|
|
16
examples/esphttpd/Makefile
Normal file
16
examples/esphttpd/Makefile
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
PROGRAM = esphttpd
|
||||||
|
EXTRA_COMPONENTS = extras/dhcpserver extras/rboot-ota extras/libesphttpd
|
||||||
|
|
||||||
|
ESP_IP ?= 192.168.4.1
|
||||||
|
|
||||||
|
#Tag for OTA images. 0-27 characters. Change to eg your projects title.
|
||||||
|
LIBESPHTTPD_OTA_TAGNAME ?= generic
|
||||||
|
|
||||||
|
LIBESPHTTPD_MAX_CONNECTIONS ?= 8
|
||||||
|
LIBESPHTTPD_STACKSIZE ?= 2048
|
||||||
|
|
||||||
|
PROGRAM_CFLAGS += -DFREERTOS -DLIBESPHTTPD_OTA_TAGNAME="\"$(LIBESPHTTPD_OTA_TAGNAME)\"" -DFLASH_SIZE=$(FLASH_SIZE)
|
||||||
|
EXTRA_CFLAGS += -DMEMP_NUM_NETCONN=$(LIBESPHTTPD_MAX_CONNECTIONS)
|
||||||
|
|
||||||
|
include ../../common.mk
|
||||||
|
|
90
examples/esphttpd/cgi-test.c
Normal file
90
examples/esphttpd/cgi-test.c
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
Cgi routines as used by the tests in the html/test subdirectory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||||
|
* Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
|
||||||
|
* this notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
|
* and you think this stuff is worth it, you can buy me a beer in return.
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <espressif/esp_common.h>
|
||||||
|
|
||||||
|
#include "cgi-test.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int len;
|
||||||
|
int sendPos;
|
||||||
|
} TestbedState;
|
||||||
|
|
||||||
|
|
||||||
|
int ICACHE_FLASH_ATTR cgiTestbed(HttpdConnData *connData) {
|
||||||
|
char buff[1024];
|
||||||
|
int first=0;
|
||||||
|
int l, x;
|
||||||
|
TestbedState *state=(TestbedState*)connData->cgiData;
|
||||||
|
|
||||||
|
if (connData->conn==NULL) {
|
||||||
|
//Connection aborted. Clean up.
|
||||||
|
if (state) free(state);
|
||||||
|
return HTTPD_CGI_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state==NULL) {
|
||||||
|
//First call
|
||||||
|
state=malloc(sizeof(TestbedState));
|
||||||
|
memset(state, 0, sizeof(state));
|
||||||
|
connData->cgiData=state;
|
||||||
|
first=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connData->requestType==HTTPD_METHOD_GET) {
|
||||||
|
if (first) {
|
||||||
|
httpdStartResponse(connData, 200);
|
||||||
|
httpdHeader(connData, "content-type", "application/data");
|
||||||
|
httpdEndHeaders(connData);
|
||||||
|
l=httpdFindArg(connData->getArgs, "len", buff, sizeof(buff));
|
||||||
|
state->len=1024;
|
||||||
|
if (l!=-1) state->len=atoi(buff);
|
||||||
|
state->sendPos=0;
|
||||||
|
return HTTPD_CGI_MORE;
|
||||||
|
} else {
|
||||||
|
l=sizeof(buff);
|
||||||
|
if (l>(state->len-state->sendPos)) l=(state->len-state->sendPos);
|
||||||
|
//Fill with semi-random data
|
||||||
|
for (x=0; x<l; x++) buff[x]=((x^(state->sendPos>>10))&0x1F)+'0';
|
||||||
|
httpdSend(connData, buff, l);
|
||||||
|
state->sendPos+=l;
|
||||||
|
printf("Test: Uploaded %d/%d bytes\n", state->sendPos, state->len);
|
||||||
|
if (state->len<=state->sendPos) {
|
||||||
|
if (state) free(state);
|
||||||
|
return HTTPD_CGI_DONE;
|
||||||
|
} else {
|
||||||
|
return HTTPD_CGI_MORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (connData->requestType==HTTPD_METHOD_POST) {
|
||||||
|
if (connData->post->len!=connData->post->received) {
|
||||||
|
//Still receiving data. Ignore this.
|
||||||
|
printf("Test: got %d/%d bytes\n", connData->post->received, connData->post->len);
|
||||||
|
return HTTPD_CGI_MORE;
|
||||||
|
} else {
|
||||||
|
httpdStartResponse(connData, 200);
|
||||||
|
httpdHeader(connData, "content-type", "text/plain");
|
||||||
|
httpdEndHeaders(connData);
|
||||||
|
l=sprintf(buff, "%d", connData->post->received);
|
||||||
|
httpdSend(connData, buff, l);
|
||||||
|
return HTTPD_CGI_DONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return HTTPD_CGI_DONE;
|
||||||
|
}
|
8
examples/esphttpd/cgi-test.h
Normal file
8
examples/esphttpd/cgi-test.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef CGI_TEST_H
|
||||||
|
#define CGI_TEST_H
|
||||||
|
|
||||||
|
#include <libesphttpd/httpd.h>
|
||||||
|
|
||||||
|
int cgiTestbed(HttpdConnData *connData);
|
||||||
|
|
||||||
|
#endif
|
81
examples/esphttpd/cgi.c
Normal file
81
examples/esphttpd/cgi.c
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
Some random cgi routines. Used in the LED example and the page that returns the entire
|
||||||
|
flash as a binary. Also handles the hit counter on the main page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||||
|
* Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
|
||||||
|
* this notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
|
* and you think this stuff is worth it, you can buy me a beer in return.
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <espressif/esp_common.h>
|
||||||
|
|
||||||
|
#include "cgi.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
|
||||||
|
//cause I can't be bothered to write an ioGetLed()
|
||||||
|
static char currLedState=0;
|
||||||
|
|
||||||
|
//Cgi that turns the LED on or off according to the 'led' param in the POST data
|
||||||
|
int ICACHE_FLASH_ATTR cgiLed(HttpdConnData *connData) {
|
||||||
|
int len;
|
||||||
|
char buff[1024];
|
||||||
|
|
||||||
|
if (connData->conn==NULL) {
|
||||||
|
//Connection aborted. Clean up.
|
||||||
|
return HTTPD_CGI_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
len=httpdFindArg(connData->post->buff, "led", buff, sizeof(buff));
|
||||||
|
if (len!=0) {
|
||||||
|
currLedState=atoi(buff);
|
||||||
|
ioLed(currLedState);
|
||||||
|
}
|
||||||
|
|
||||||
|
httpdRedirect(connData, "led.tpl");
|
||||||
|
return HTTPD_CGI_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Template code for the led page.
|
||||||
|
int ICACHE_FLASH_ATTR tplLed(HttpdConnData *connData, char *token, void **arg) {
|
||||||
|
char buff[128];
|
||||||
|
if (token==NULL) return HTTPD_CGI_DONE;
|
||||||
|
|
||||||
|
strcpy(buff, "Unknown");
|
||||||
|
if (strcmp(token, "ledstate")==0) {
|
||||||
|
if (currLedState) {
|
||||||
|
strcpy(buff, "on");
|
||||||
|
} else {
|
||||||
|
strcpy(buff, "off");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
httpdSend(connData, buff, -1);
|
||||||
|
return HTTPD_CGI_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hitCounter=0;
|
||||||
|
|
||||||
|
//Template code for the counter on the index page.
|
||||||
|
int ICACHE_FLASH_ATTR tplCounter(HttpdConnData *connData, char *token, void **arg) {
|
||||||
|
char buff[128];
|
||||||
|
if (token==NULL) return HTTPD_CGI_DONE;
|
||||||
|
|
||||||
|
if (strcmp(token, "counter")==0) {
|
||||||
|
hitCounter++;
|
||||||
|
sprintf(buff, "%d", hitCounter);
|
||||||
|
}
|
||||||
|
httpdSend(connData, buff, -1);
|
||||||
|
return HTTPD_CGI_DONE;
|
||||||
|
}
|
10
examples/esphttpd/cgi.h
Normal file
10
examples/esphttpd/cgi.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef CGI_H
|
||||||
|
#define CGI_H
|
||||||
|
|
||||||
|
#include <libesphttpd/httpd.h>
|
||||||
|
|
||||||
|
int cgiLed(HttpdConnData *connData);
|
||||||
|
int tplLed(HttpdConnData *connData, char *token, void **arg);
|
||||||
|
int tplCounter(HttpdConnData *connData, char *token, void **arg);
|
||||||
|
|
||||||
|
#endif
|
BIN
examples/esphttpd/html/cats/cross-eyed-cat.jpg
Normal file
BIN
examples/esphttpd/html/cats/cross-eyed-cat.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
BIN
examples/esphttpd/html/cats/junge-katze-iv.jpg
Normal file
BIN
examples/esphttpd/html/cats/junge-katze-iv.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
examples/esphttpd/html/cats/kitten-loves-toy.jpg
Normal file
BIN
examples/esphttpd/html/cats/kitten-loves-toy.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
2
examples/esphttpd/html/flash/140medley.min.js
vendored
Normal file
2
examples/esphttpd/html/flash/140medley.min.js
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
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=
|
||||||
|
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){}};
|
75
examples/esphttpd/html/flash/index.html
Normal file
75
examples/esphttpd/html/flash/index.html
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
<html>
|
||||||
|
<head><title>Upgrade firmware</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css">
|
||||||
|
<script type="text/javascript" src="140medley.min.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var xhr=j();
|
||||||
|
|
||||||
|
function doReboot() {
|
||||||
|
xhr.open("GET", "reboot");
|
||||||
|
xhr.onreadystatechange=function() {
|
||||||
|
if (xhr.readyState==4 && xhr.status>=200 && xhr.status<300) {
|
||||||
|
window.setTimeout(function() {
|
||||||
|
location.reload(true);
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//ToDo: set timer to
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setProgress(amt) {
|
||||||
|
$("#progressbarinner").style.width=String(amt*200)+"px";
|
||||||
|
}
|
||||||
|
|
||||||
|
function doUpgrade() {
|
||||||
|
var f=$("#file").files[0];
|
||||||
|
if (typeof f=='undefined') {
|
||||||
|
$("#remark").innerHTML="Can't read file!";
|
||||||
|
return
|
||||||
|
}
|
||||||
|
xhr.open("POST", "upload");
|
||||||
|
xhr.onreadystatechange=function() {
|
||||||
|
if (xhr.readyState==4 && xhr.status>=200 && xhr.status<300) {
|
||||||
|
setProgress(1);
|
||||||
|
if (xhr.responseText!="") {
|
||||||
|
$("#remark").innerHTML="Error: "+xhr.responseText;
|
||||||
|
} else {
|
||||||
|
$("#remark").innerHTML="Uploading done. Rebooting.";
|
||||||
|
doReboot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof xhr.upload.onprogress != 'undefined') {
|
||||||
|
xhr.upload.onprogress=function(e) {
|
||||||
|
setProgress(e.loaded / e.total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhr.send(f);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
window.onload=function(e) {
|
||||||
|
xhr.open("GET", "next");
|
||||||
|
xhr.onreadystatechange=function() {
|
||||||
|
if (xhr.readyState==4 && xhr.status>=200 && xhr.status<300) {
|
||||||
|
var txt="Please upload "+xhr.responseText+" or ota file.";
|
||||||
|
$("#remark").innerHTML=txt;
|
||||||
|
setProgress(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="main">
|
||||||
|
<h1>Update firmware</h1>
|
||||||
|
<div id="remark">Loading...</div>
|
||||||
|
<input type="file" id="file" />
|
||||||
|
<input type="submit" value="Upgrade!" onclick="doUpgrade()" />
|
||||||
|
<div id="progressbar"><div id="progressbarinner"></div></div>
|
||||||
|
</body>
|
34
examples/esphttpd/html/flash/style.css
Normal file
34
examples/esphttpd/html/flash/style.css
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #404040;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main {
|
||||||
|
background-color: #d0d0FF;
|
||||||
|
-moz-border-radius: 5px;
|
||||||
|
-webkit-border-radius: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 2px solid #000000;
|
||||||
|
width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
#progressbar {
|
||||||
|
margin: 10px;
|
||||||
|
padding: 0;
|
||||||
|
border: 1px solid #000000;
|
||||||
|
height: 20px;
|
||||||
|
width: 200px;
|
||||||
|
background-color: #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
#progressbarinner {
|
||||||
|
width: 10px;
|
||||||
|
height: 20px;
|
||||||
|
border: none;
|
||||||
|
background-color: #00ff00;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
26
examples/esphttpd/html/index.tpl
Normal file
26
examples/esphttpd/html/index.tpl
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<html>
|
||||||
|
<head><title>Esp8266 web server</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="main">
|
||||||
|
<h1>It Works</h1>
|
||||||
|
<p>
|
||||||
|
If you see this, it means the tiny li'l website in your ESP8266 does actually work. Fyi, this page has
|
||||||
|
been loaded <b>%counter%</b> times.
|
||||||
|
<ul>
|
||||||
|
<li>If you haven't connected this device to your WLAN network now, you can <a href="/wifi">do so.</a></li>
|
||||||
|
<li>You can also control the <a href="led.tpl">LED</a>.</li>
|
||||||
|
<li>Esphttpd now also supports <a href="websocket/index.html">websockets</a>.</li>
|
||||||
|
<li>Test esphttpd using the built-in <a href="test/">test suite</a></li>
|
||||||
|
<li>And because I can, here's a link to my <a href="http://spritesmods.com/?f=esphttpd">website</a></ul>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>And because we're on the Internets now, here are the required pictures of cats:<br />
|
||||||
|
<img src="cats/cross-eyed-cat.jpg"><br />
|
||||||
|
<img src="cats/junge-katze-iv.jpg"><br />
|
||||||
|
<img src="cats/kitten-loves-toy.jpg"><br />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</body></html>
|
15
examples/esphttpd/html/led.tpl
Normal file
15
examples/esphttpd/html/led.tpl
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<html><head><title>Test</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="main">
|
||||||
|
<h1>The LED</h1>
|
||||||
|
<p>
|
||||||
|
If there's a LED connected to GPIO2, it's now %ledstate%. You can change that using the buttons below.
|
||||||
|
</p>
|
||||||
|
<form method="post" action="led.cgi">
|
||||||
|
<input type="submit" name="led" value="1">
|
||||||
|
<input type="submit" name="led" value="0">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body></html>
|
17
examples/esphttpd/html/style.css
Normal file
17
examples/esphttpd/html/style.css
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #404040;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main {
|
||||||
|
background-color: #d0d0FF;
|
||||||
|
-moz-border-radius: 5px;
|
||||||
|
-webkit-border-radius: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 2px solid #000000;
|
||||||
|
width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
|
9
examples/esphttpd/html/test/index.html
Normal file
9
examples/esphttpd/html/test/index.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<html><head><title>Webserver test</title></head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../wifi/style.css">
|
||||||
|
<script type="text/javascript" src="../wifi/140medley.min.js"></script>
|
||||||
|
<script type="text/javascript" src="test.js"></script>
|
||||||
|
<body>
|
||||||
|
<div id="main">
|
||||||
|
<div id="log">Initializing test...</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
205
examples/esphttpd/html/test/test.js
Normal file
205
examples/esphttpd/html/test/test.js
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
Code to test the webserver. This depends on:
|
||||||
|
- The cat images being available, for concurrent espfs testing
|
||||||
|
- the test.cgi script available, for generic data mangling tests
|
||||||
|
|
||||||
|
|
||||||
|
This test does a max of 4 requests in parallel. The nonos SDK supports a max of
|
||||||
|
5 connections; the default libesphttpd setting is 4 sockets at a time. Unfortunately,
|
||||||
|
the nonos sdk just closes all sockets opened after the available sockets are opened,
|
||||||
|
instead of queueing them until a socket frees up.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
function log(line) {
|
||||||
|
$("#log").insertAdjacentHTML('beforeend', line+'<br />');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Load an image multiple times in parallel
|
||||||
|
function testParLdImg(url, ct, doneFn) {
|
||||||
|
var im=[];
|
||||||
|
var state={"loaded":0, "count":ct, "doneFn": doneFn, "error":false};
|
||||||
|
for (var x=0; x<ct; x++) {
|
||||||
|
im[x]=new Image();
|
||||||
|
im[x].onload=function(no) {
|
||||||
|
log("File "+no+" loaded successfully.");
|
||||||
|
this.loaded++;
|
||||||
|
if (this.loaded==this.count) this.doneFn(!this.error);
|
||||||
|
}.bind(state, x);
|
||||||
|
im[x].onerror=function(no) {
|
||||||
|
log("Error loading image "+no+"!");
|
||||||
|
this.loaded++;
|
||||||
|
this.error++;
|
||||||
|
if (this.loaded==this.count) this.doneFn(!this.error);
|
||||||
|
}.bind(state, x);
|
||||||
|
im[x].src=url+"?"+Math.floor(Math.random()*100000).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function testDownloadCgi(len, doneFn) {
|
||||||
|
var xhr=j();
|
||||||
|
var state={"len":len, "doneFn":doneFn, "ts": Date.now()};
|
||||||
|
xhr.open("GET", "test.cgi?len="+len+"&nocache="+Math.floor(Math.random()*100000).toString());
|
||||||
|
xhr.onreadystatechange=function() {
|
||||||
|
if (xhr.readyState==4 && xhr.status>=200 && xhr.status<300) {
|
||||||
|
if (xhr.response.length==this.len) {
|
||||||
|
log("Downloaded "+this.len+" bytes successfully.");
|
||||||
|
this.doneFn(true);
|
||||||
|
} else {
|
||||||
|
log("Downloaded "+xhr.response.length+" bytes successfully, but needed "+this.len+"!");
|
||||||
|
this.doneFn(false);
|
||||||
|
}
|
||||||
|
} else if (xhr.readyState==4) {
|
||||||
|
log("Failed! Error "+xhr.status);
|
||||||
|
this.doneFn(false);
|
||||||
|
}
|
||||||
|
}.bind(state);
|
||||||
|
//If the webbrowser enables it, show progress.
|
||||||
|
if (typeof xhr.onprogress != 'undefined') {
|
||||||
|
xhr.onprogress=function(e) {
|
||||||
|
if (Date.now()>this.ts+2000) {
|
||||||
|
log("..."+Math.floor(e.loaded*100/this.len).toString()+"%");
|
||||||
|
this.ts=Date.now();
|
||||||
|
}
|
||||||
|
}.bind(state);
|
||||||
|
}
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function testUploadCgi(len, doneFn) {
|
||||||
|
var xhr=j();
|
||||||
|
var state={"len":len, "doneFn":doneFn, "ts": Date.now()};
|
||||||
|
var data="";
|
||||||
|
for (var x=0; x<len; x++) data+="X";
|
||||||
|
xhr.open("POST", "test.cgi");
|
||||||
|
xhr.onreadystatechange=function() {
|
||||||
|
if (xhr.readyState==4 && xhr.status>=200 && xhr.status<300) {
|
||||||
|
var ulen=parseInt(xhr.responseText);
|
||||||
|
if (ulen==this.len) {
|
||||||
|
log("Uploaded "+this.len+" bytes successfully.");
|
||||||
|
this.doneFn(true);
|
||||||
|
} else {
|
||||||
|
log("Webserver received "+ulen+" bytes successfully, but sent "+this.len+"!");
|
||||||
|
this.doneFn(false);
|
||||||
|
}
|
||||||
|
} else if (xhr.readyState==4) {
|
||||||
|
log("Failed! Error "+xhr.status);
|
||||||
|
this.doneFn(false);
|
||||||
|
}
|
||||||
|
}.bind(state);
|
||||||
|
//If the webbrowser enables it, show progress.
|
||||||
|
if (typeof xhr.upload.onprogress != 'undefined') {
|
||||||
|
xhr.upload.onprogress=function(e) {
|
||||||
|
if (Date.now()>this.ts+2000) {
|
||||||
|
log("..."+Math.floor(e.loaded*100/e.total).toString()+"%");
|
||||||
|
this.ts=Date.now();
|
||||||
|
}
|
||||||
|
}.bind(state);
|
||||||
|
}
|
||||||
|
//Upload the file
|
||||||
|
xhr.send(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hammerNext(state, xhr) {
|
||||||
|
if (state.done==state.count) {
|
||||||
|
state.doneFn(!state.error);
|
||||||
|
}
|
||||||
|
if (state.started==state.count) return;
|
||||||
|
xhr.open("GET", "test.cgi?len="+state.len+"&nocache="+Math.floor(Math.random()*100000).toString());
|
||||||
|
xhr.onreadystatechange=function(xhr) {
|
||||||
|
if (xhr.readyState==4 && xhr.status>=200 && xhr.status<300) {
|
||||||
|
if (xhr.response.length==this.len) {
|
||||||
|
state.done++;
|
||||||
|
hammerNext(this, xhr);
|
||||||
|
} else {
|
||||||
|
log("Downloaded "+xhr.response.length+" bytes successfully, but needed "+this.len+"!");
|
||||||
|
state.done++;
|
||||||
|
hammerNext(this, xhr);
|
||||||
|
}
|
||||||
|
} else if (xhr.readyState==4) {
|
||||||
|
log("Failed! Error "+xhr.status);
|
||||||
|
state.done++;
|
||||||
|
hammerNext(this, xhr);
|
||||||
|
}
|
||||||
|
}.bind(state, xhr);
|
||||||
|
//If the webbrowser enables it, show progress.
|
||||||
|
if (typeof xhr.onprogress != 'undefined') {
|
||||||
|
xhr.onprogress=function(e) {
|
||||||
|
if (Date.now()>this.ts+2000) {
|
||||||
|
log("..."+state.done+"/"+state.count);
|
||||||
|
this.ts=Date.now();
|
||||||
|
}
|
||||||
|
}.bind(state);
|
||||||
|
}
|
||||||
|
state.started++;
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testHammer(count, par, len, doneFn) {
|
||||||
|
var state={"count":count, "started":0, "done":0, "par":par, "len":len, "doneFn":doneFn, "ts": Date.now(), "error":false};
|
||||||
|
var xhr=[];
|
||||||
|
for (var i=0; i<par; i++) {
|
||||||
|
xhr[i]=j();
|
||||||
|
hammerNext(state, xhr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var tstState=0;
|
||||||
|
var successCnt=0;
|
||||||
|
|
||||||
|
function nextTest(lastOk) {
|
||||||
|
if (tstState!=0) {
|
||||||
|
if (lastOk) {
|
||||||
|
log("<b>Success!</b>");
|
||||||
|
successCnt++;
|
||||||
|
} else {
|
||||||
|
log("<b>Test failed!</b>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tstState++;
|
||||||
|
if (tstState==1) {
|
||||||
|
log("Testing parallel load of espfs files...");
|
||||||
|
testParLdImg("../cats/kitten-loves-toy.jpg", 3, nextTest);
|
||||||
|
} else if (tstState==2) {
|
||||||
|
log("Testing GET request of 32K...");
|
||||||
|
testDownloadCgi(32*1024, nextTest);
|
||||||
|
} else if (tstState==3) {
|
||||||
|
log("Testing GET request of 128K...");
|
||||||
|
testDownloadCgi(128*1024, nextTest);
|
||||||
|
} else if (tstState==4) {
|
||||||
|
log("Testing GET request of 512K...");
|
||||||
|
testDownloadCgi(512*1024, nextTest);
|
||||||
|
} else if (tstState==5) {
|
||||||
|
log("Testing POST request of 512 bytes...");
|
||||||
|
testUploadCgi(512, nextTest);
|
||||||
|
} else if (tstState==6) {
|
||||||
|
log("Testing POST request of 16K bytes...");
|
||||||
|
testUploadCgi(16*1024, nextTest);
|
||||||
|
} else if (tstState==7) {
|
||||||
|
log("Testing POST request of 512K bytes...");
|
||||||
|
testUploadCgi(512*1024, nextTest);
|
||||||
|
} else if (tstState==8) {
|
||||||
|
log("Hammering webserver with 500 requests of size 512...");
|
||||||
|
testHammer(500, 3, 512, nextTest);
|
||||||
|
} else if (tstState==9) {
|
||||||
|
log("Hammering webserver with 500 requests of size 2048...");
|
||||||
|
testHammer(500, 3, 2048, nextTest);
|
||||||
|
} else {
|
||||||
|
log("Tests done! "+successCnt+" out of "+(tstState-1)+" tests were successful.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.onload=function(e) {
|
||||||
|
log("Starting tests.");
|
||||||
|
nextTest(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
69
examples/esphttpd/html/websocket/index.html
Normal file
69
examples/esphttpd/html/websocket/index.html
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
|
||||||
|
<title>WebSocket Test</title>
|
||||||
|
|
||||||
|
<script language="javascript" type="text/javascript">
|
||||||
|
|
||||||
|
var wsUri = "ws://"+window.location.host+"/websocket/ws.cgi";
|
||||||
|
var output;
|
||||||
|
|
||||||
|
function init()
|
||||||
|
{
|
||||||
|
output = document.getElementById("output");
|
||||||
|
testWebSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testWebSocket()
|
||||||
|
{
|
||||||
|
websocket = new WebSocket(wsUri);
|
||||||
|
websocket.onopen = function(evt) { onOpen(evt) };
|
||||||
|
websocket.onclose = function(evt) { onClose(evt) };
|
||||||
|
websocket.onmessage = function(evt) { onMessage(evt) };
|
||||||
|
websocket.onerror = function(evt) { onError(evt) };
|
||||||
|
}
|
||||||
|
|
||||||
|
function onOpen(evt)
|
||||||
|
{
|
||||||
|
writeToScreen("CONNECTED");
|
||||||
|
doSend("WebSocket rocks");
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClose(evt)
|
||||||
|
{
|
||||||
|
writeToScreen("DISCONNECTED");
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMessage(evt)
|
||||||
|
{
|
||||||
|
writeToScreen('<span style="color: blue;">RECEIVED: ' + evt.data+'</span>');
|
||||||
|
// websocket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onError(evt)
|
||||||
|
{
|
||||||
|
writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSend(message)
|
||||||
|
{
|
||||||
|
writeToScreen("SENT: " + message);
|
||||||
|
websocket.send(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeToScreen(message)
|
||||||
|
{
|
||||||
|
var pre = document.createElement("p");
|
||||||
|
pre.style.wordWrap = "break-word";
|
||||||
|
pre.innerHTML = message;
|
||||||
|
output.appendChild(pre);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", init, false);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h2>WebSocket Test</h2>
|
||||||
|
|
||||||
|
<div id="output"></div>
|
2
examples/esphttpd/html/wifi/140medley.min.js
vendored
Normal file
2
examples/esphttpd/html/wifi/140medley.min.js
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
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=
|
||||||
|
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){}};
|
43
examples/esphttpd/html/wifi/connecting.html
Normal file
43
examples/esphttpd/html/wifi/connecting.html
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<html><head><title>Connecting...</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css">
|
||||||
|
<script type="text/javascript" src="140medley.min.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var xhr=j();
|
||||||
|
|
||||||
|
|
||||||
|
function getStatus() {
|
||||||
|
xhr.open("GET", "connstatus.cgi");
|
||||||
|
xhr.onreadystatechange=function() {
|
||||||
|
if (xhr.readyState==4 && xhr.status>=200 && xhr.status<300) {
|
||||||
|
var data=JSON.parse(xhr.responseText);
|
||||||
|
if (data.status=="idle") {
|
||||||
|
$("#status").innerHTML="Preparing to connect...";
|
||||||
|
window.setTimeout(getStatus, 1000);
|
||||||
|
} else if (data.status=="success") {
|
||||||
|
$("#status").innerHTML="Connected! Got IP "+data.ip+". If you're in the same network, you can access it <a href=\"http://"+data.ip+"/\">here</a>.";
|
||||||
|
} else if (data.status=="working") {
|
||||||
|
$("#status").innerHTML="Trying to connect to selected access point...";
|
||||||
|
window.setTimeout(getStatus, 1000);
|
||||||
|
} else if (data.status=="fail") {
|
||||||
|
$("#status").innerHTML="Connection failed. Check password and selected AP.<br /><a href=\"wifi.tpl\">Go Back</a>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload=function(e) {
|
||||||
|
getStatus();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="main">
|
||||||
|
<h2>Connecting to AP...</h2>
|
||||||
|
<p>Status:<br />
|
||||||
|
<div id="status">...</div>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
examples/esphttpd/html/wifi/icons.png
Normal file
BIN
examples/esphttpd/html/wifi/icons.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 914 B |
24
examples/esphttpd/html/wifi/style.css
Normal file
24
examples/esphttpd/html/wifi/style.css
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #404040;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main {
|
||||||
|
background-color: #d0d0FF;
|
||||||
|
-moz-border-radius: 5px;
|
||||||
|
-webkit-border-radius: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 2px solid #000000;
|
||||||
|
width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
background-image: url("icons.png");
|
||||||
|
background-color: transparent;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
94
examples/esphttpd/html/wifi/wifi.tpl
Normal file
94
examples/esphttpd/html/wifi/wifi.tpl
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
<html><head><title>WiFi connection</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css">
|
||||||
|
<script type="text/javascript" src="140medley.min.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var xhr=j();
|
||||||
|
var currAp="%currSsid%";
|
||||||
|
|
||||||
|
function createInputForAp(ap) {
|
||||||
|
if (ap.essid=="" && ap.rssi==0) return;
|
||||||
|
var div=document.createElement("div");
|
||||||
|
div.id="apdiv";
|
||||||
|
var rssi=document.createElement("div");
|
||||||
|
var rssiVal=-Math.floor(ap.rssi/51)*32;
|
||||||
|
rssi.className="icon";
|
||||||
|
rssi.style.backgroundPosition="0px "+rssiVal+"px";
|
||||||
|
var encrypt=document.createElement("div");
|
||||||
|
var encVal="-64"; //assume wpa/wpa2
|
||||||
|
if (ap.enc=="0") encVal="0"; //open
|
||||||
|
if (ap.enc=="1") encVal="-32"; //wep
|
||||||
|
encrypt.className="icon";
|
||||||
|
encrypt.style.backgroundPosition="-32px "+encVal+"px";
|
||||||
|
var input=document.createElement("input");
|
||||||
|
input.type="radio";
|
||||||
|
input.name="essid";
|
||||||
|
input.value=ap.essid;
|
||||||
|
if (currAp==ap.essid) input.checked="1";
|
||||||
|
input.id="opt-"+ap.essid;
|
||||||
|
var label=document.createElement("label");
|
||||||
|
label.htmlFor="opt-"+ap.essid;
|
||||||
|
label.textContent=ap.essid;
|
||||||
|
div.appendChild(input);
|
||||||
|
div.appendChild(rssi);
|
||||||
|
div.appendChild(encrypt);
|
||||||
|
div.appendChild(label);
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectedEssid() {
|
||||||
|
var e=document.forms.wifiform.elements;
|
||||||
|
for (var i=0; i<e.length; i++) {
|
||||||
|
if (e[i].type=="radio" && e[i].checked) return e[i].value;
|
||||||
|
}
|
||||||
|
return currAp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function scanAPs() {
|
||||||
|
xhr.open("GET", "wifiscan.cgi");
|
||||||
|
xhr.onreadystatechange=function() {
|
||||||
|
if (xhr.readyState==4 && xhr.status>=200 && xhr.status<300) {
|
||||||
|
var data=JSON.parse(xhr.responseText);
|
||||||
|
currAp=getSelectedEssid();
|
||||||
|
if (data.result.inProgress=="0" && data.result.APs.length>1) {
|
||||||
|
$("#aps").innerHTML="";
|
||||||
|
for (var i=0; i<data.result.APs.length; i++) {
|
||||||
|
if (data.result.APs[i].essid=="" && data.result.APs[i].rssi==0) continue;
|
||||||
|
$("#aps").appendChild(createInputForAp(data.result.APs[i]));
|
||||||
|
}
|
||||||
|
window.setTimeout(scanAPs, 20000);
|
||||||
|
} else {
|
||||||
|
window.setTimeout(scanAPs, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
window.onload=function(e) {
|
||||||
|
scanAPs();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="main">
|
||||||
|
<p>
|
||||||
|
Current WiFi mode: %WiFiMode%
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Note: %WiFiapwarn%
|
||||||
|
</p>
|
||||||
|
<form name="wifiform" action="connect.cgi" method="post">
|
||||||
|
<p>
|
||||||
|
To connect to a WiFi network, please select one of the detected networks...<br>
|
||||||
|
<div id="aps">Scanning...</div>
|
||||||
|
<br>
|
||||||
|
WiFi password, if applicable: <br />
|
||||||
|
<input type="text" name="passwd" val="%WiFiPasswd%"> <br />
|
||||||
|
<input type="submit" name="connect" value="Connect!">
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
72
examples/esphttpd/io.c
Normal file
72
examples/esphttpd/io.c
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||||
|
* Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
|
||||||
|
* this notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
|
* and you think this stuff is worth it, you can buy me a beer in return.
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <espressif/esp_common.h>
|
||||||
|
//#include <c_types.h>
|
||||||
|
#include <etstimer.h>
|
||||||
|
#include <espressif/esp_system.h>
|
||||||
|
#include <espressif/esp_timer.h>
|
||||||
|
#include <espressif/esp_wifi.h>
|
||||||
|
#include <espressif/esp_sta.h>
|
||||||
|
#include <espressif/esp_misc.h>
|
||||||
|
#include <espressif/osapi.h>
|
||||||
|
|
||||||
|
#include <espressif/esp8266/eagle_soc.h>
|
||||||
|
#include <espressif/esp8266/gpio_register.h>
|
||||||
|
#include <espressif/esp8266/pin_mux_register.h>
|
||||||
|
|
||||||
|
#define LEDGPIO 2
|
||||||
|
#define BTNGPIO 0
|
||||||
|
|
||||||
|
#ifndef ESP32
|
||||||
|
static ETSTimer resetBtntimer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ioLed(int ena) {
|
||||||
|
#ifndef ESP32
|
||||||
|
//gpio_output_set is overkill. ToDo: use better mactos
|
||||||
|
if (ena) {
|
||||||
|
sdk_gpio_output_set((1<<LEDGPIO), 0, (1<<LEDGPIO), 0);
|
||||||
|
} else {
|
||||||
|
sdk_gpio_output_set(0, (1<<LEDGPIO), (1<<LEDGPIO), 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef ESP32
|
||||||
|
static void resetBtnTimerCb(void *arg) {
|
||||||
|
static int resetCnt=0;
|
||||||
|
if ((GPIO_REG_READ(GPIO_IN_ADDRESS)&(1<<BTNGPIO))==0) {
|
||||||
|
resetCnt++;
|
||||||
|
} else {
|
||||||
|
if (resetCnt>=6) { //3 sec pressed
|
||||||
|
sdk_wifi_station_disconnect();
|
||||||
|
sdk_wifi_set_opmode(STATIONAP_MODE); //reset to AP+STA mode
|
||||||
|
printf("Reset to AP mode. Restarting system...\n");
|
||||||
|
sdk_system_restart();
|
||||||
|
}
|
||||||
|
resetCnt=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void ioInit() {
|
||||||
|
#ifndef ESP32
|
||||||
|
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
|
||||||
|
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
|
||||||
|
sdk_gpio_output_set(0, 0, (1<<LEDGPIO), (1<<BTNGPIO));
|
||||||
|
sdk_os_timer_disarm(&resetBtntimer);
|
||||||
|
sdk_os_timer_setfn(&resetBtntimer, resetBtnTimerCb, NULL);
|
||||||
|
sdk_os_timer_arm(&resetBtntimer, 500, 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
7
examples/esphttpd/io.h
Normal file
7
examples/esphttpd/io.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef IO_H
|
||||||
|
#define IO_H
|
||||||
|
|
||||||
|
void ICACHE_FLASH_ATTR ioLed(int ena);
|
||||||
|
void ioInit(void);
|
||||||
|
|
||||||
|
#endif
|
210
examples/esphttpd/user_main.c
Normal file
210
examples/esphttpd/user_main.c
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||||
|
* Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
|
||||||
|
* this notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
|
* and you think this stuff is worth it, you can buy me a beer in return.
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is example code for the esphttpd library. It's a small-ish demo showing off
|
||||||
|
the server, including WiFi connection management capabilities, some IO and
|
||||||
|
some pictures of cats.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <espressif/esp_common.h>
|
||||||
|
#include <etstimer.h>
|
||||||
|
#include <libesphttpd/httpd.h>
|
||||||
|
#include <libesphttpd/httpdespfs.h>
|
||||||
|
#include <libesphttpd/cgiwifi.h>
|
||||||
|
#include <libesphttpd/cgiflash.h>
|
||||||
|
#include <libesphttpd/auth.h>
|
||||||
|
#include <libesphttpd/espfs.h>
|
||||||
|
#include <libesphttpd/captdns.h>
|
||||||
|
#include <libesphttpd/webpages-espfs.h>
|
||||||
|
#include <libesphttpd/cgiwebsocket.h>
|
||||||
|
#include <dhcpserver.h>
|
||||||
|
|
||||||
|
#include <FreeRTOS.h>
|
||||||
|
#include <task.h>
|
||||||
|
#include <semphr.h>
|
||||||
|
#include <queue.h>
|
||||||
|
#include <esp/uart.h>
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
#include "cgi.h"
|
||||||
|
#include "cgi-test.h"
|
||||||
|
|
||||||
|
#define AP_SSID "esp-open-rtos AP"
|
||||||
|
#define AP_PSK "esp-open-rtos"
|
||||||
|
|
||||||
|
//Function that tells the authentication system what users/passwords live on the system.
|
||||||
|
//This is disabled in the default build; if you want to try it, enable the authBasic line in
|
||||||
|
//the builtInUrls below.
|
||||||
|
int myPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen) {
|
||||||
|
if (no==0) {
|
||||||
|
strcpy(user, "admin");
|
||||||
|
strcpy(pass, "s3cr3t");
|
||||||
|
return 1;
|
||||||
|
//Add more users this way. Check against incrementing no for each user added.
|
||||||
|
// } else if (no==1) {
|
||||||
|
// strcpy(user, "user1");
|
||||||
|
// strcpy(pass, "something");
|
||||||
|
// return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ETSTimer websockTimer;
|
||||||
|
|
||||||
|
//Broadcast the uptime in seconds every second over connected websockets
|
||||||
|
static void websocketBcast(void *arg) {
|
||||||
|
static int ctr=0;
|
||||||
|
char buff[128];
|
||||||
|
while(1) {
|
||||||
|
ctr++;
|
||||||
|
sprintf(buff, "Up for %d minutes %d seconds!\n", ctr/60, ctr%60);
|
||||||
|
cgiWebsockBroadcast("/websocket/ws.cgi", buff, strlen(buff), WEBSOCK_FLAG_NONE);
|
||||||
|
vTaskDelay(1000/portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//On reception of a message, send "You sent: " plus whatever the other side sent
|
||||||
|
static void myWebsocketRecv(Websock *ws, char *data, int len, int flags) {
|
||||||
|
int i;
|
||||||
|
char buff[128];
|
||||||
|
sprintf(buff, "You sent: ");
|
||||||
|
for (i=0; i<len; i++) buff[i+10]=data[i];
|
||||||
|
buff[i+10]=0;
|
||||||
|
cgiWebsocketSend(ws, buff, strlen(buff), WEBSOCK_FLAG_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Websocket connected. Install reception handler and send welcome message.
|
||||||
|
static void myWebsocketConnect(Websock *ws) {
|
||||||
|
ws->recvCb=myWebsocketRecv;
|
||||||
|
cgiWebsocketSend(ws, "Hi, Websocket!", 14, WEBSOCK_FLAG_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//On reception of a message, echo it back verbatim
|
||||||
|
void myEchoWebsocketRecv(Websock *ws, char *data, int len, int flags) {
|
||||||
|
printf("EchoWs: echo, len=%d\n", len);
|
||||||
|
cgiWebsocketSend(ws, data, len, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Echo websocket connected. Install reception handler.
|
||||||
|
void myEchoWebsocketConnect(Websock *ws) {
|
||||||
|
printf("EchoWs: connect\n");
|
||||||
|
ws->recvCb=myEchoWebsocketRecv;
|
||||||
|
}
|
||||||
|
|
||||||
|
CgiUploadFlashDef uploadParams={
|
||||||
|
.type=CGIFLASH_TYPE_FW,
|
||||||
|
.fw1Pos=0x2000,
|
||||||
|
.fw2Pos=((FLASH_SIZE*1024*1024)/2)+0x2000,
|
||||||
|
.fwSize=((FLASH_SIZE*1024*1024)/2)-0x2000,
|
||||||
|
.tagName=LIBESPHTTPD_OTA_TAGNAME
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is the main url->function dispatching data struct.
|
||||||
|
In short, it's a struct with various URLs plus their handlers. The handlers can
|
||||||
|
be 'standard' CGI functions you wrote, or 'special' CGIs requiring an argument.
|
||||||
|
They can also be auth-functions. An asterisk will match any url starting with
|
||||||
|
everything before the asterisks; "*" matches everything. The list will be
|
||||||
|
handled top-down, so make sure to put more specific rules above the more
|
||||||
|
general ones. Authorization things (like authBasic) act as a 'barrier' and
|
||||||
|
should be placed above the URLs they protect.
|
||||||
|
*/
|
||||||
|
HttpdBuiltInUrl builtInUrls[]={
|
||||||
|
{"*", cgiRedirectApClientToHostname, "esp8266.nonet"},
|
||||||
|
{"/", cgiRedirect, "/index.tpl"},
|
||||||
|
{"/led.tpl", cgiEspFsTemplate, tplLed},
|
||||||
|
{"/index.tpl", cgiEspFsTemplate, tplCounter},
|
||||||
|
{"/led.cgi", cgiLed, NULL},
|
||||||
|
#ifndef ESP32
|
||||||
|
{"/flash/", cgiRedirect, "/flash/index.html"},
|
||||||
|
{"/flash/next", cgiGetFirmwareNext, &uploadParams},
|
||||||
|
{"/flash/upload", cgiUploadFirmware, &uploadParams},
|
||||||
|
{"/flash/reboot", cgiRebootFirmware, NULL},
|
||||||
|
#endif
|
||||||
|
//Routines to make the /wifi URL and everything beneath it work.
|
||||||
|
|
||||||
|
//Enable the line below to protect the WiFi configuration with an username/password combo.
|
||||||
|
// {"/wifi/*", authBasic, myPassFn},
|
||||||
|
|
||||||
|
{"/wifi", cgiRedirect, "/wifi/wifi.tpl"},
|
||||||
|
{"/wifi/", cgiRedirect, "/wifi/wifi.tpl"},
|
||||||
|
{"/wifi/wifiscan.cgi", cgiWiFiScan, NULL},
|
||||||
|
{"/wifi/wifi.tpl", cgiEspFsTemplate, tplWlan},
|
||||||
|
{"/wifi/connect.cgi", cgiWiFiConnect, NULL},
|
||||||
|
{"/wifi/connstatus.cgi", cgiWiFiConnStatus, NULL},
|
||||||
|
{"/wifi/setmode.cgi", cgiWiFiSetMode, NULL},
|
||||||
|
|
||||||
|
{"/websocket/ws.cgi", cgiWebsocket, myWebsocketConnect},
|
||||||
|
{"/websocket/echo.cgi", cgiWebsocket, myEchoWebsocketConnect},
|
||||||
|
|
||||||
|
{"/test", cgiRedirect, "/test/index.html"},
|
||||||
|
{"/test/", cgiRedirect, "/test/index.html"},
|
||||||
|
{"/test/test.cgi", cgiTestbed, NULL},
|
||||||
|
|
||||||
|
{"*", cgiEspFsHook, NULL}, //Catch-all cgi function for the filesystem
|
||||||
|
{NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
void wifiInit() {
|
||||||
|
struct ip_info ap_ip;
|
||||||
|
uint8_t sdk_wifi_get_opmode();
|
||||||
|
switch(sdk_wifi_get_opmode()) {
|
||||||
|
case STATIONAP_MODE:
|
||||||
|
case SOFTAP_MODE:
|
||||||
|
IP4_ADDR(&ap_ip.ip, 172, 16, 0, 1);
|
||||||
|
IP4_ADDR(&ap_ip.gw, 0, 0, 0, 0);
|
||||||
|
IP4_ADDR(&ap_ip.netmask, 255, 255, 0, 0);
|
||||||
|
sdk_wifi_set_ip_info(1, &ap_ip);
|
||||||
|
|
||||||
|
struct sdk_softap_config ap_config = {
|
||||||
|
.ssid = AP_SSID,
|
||||||
|
.ssid_hidden = 0,
|
||||||
|
.channel = 3,
|
||||||
|
.ssid_len = strlen(AP_SSID),
|
||||||
|
.authmode = AUTH_WPA_WPA2_PSK,
|
||||||
|
.password = AP_PSK,
|
||||||
|
.max_connection = 3,
|
||||||
|
.beacon_interval = 100,
|
||||||
|
};
|
||||||
|
sdk_wifi_softap_set_config(&ap_config);
|
||||||
|
|
||||||
|
ip_addr_t first_client_ip;
|
||||||
|
IP4_ADDR(&first_client_ip, 172, 16, 0, 2);
|
||||||
|
dhcpserver_start(&first_client_ip, 4);
|
||||||
|
dhcpserver_set_dns(&ap_ip.ip);
|
||||||
|
dhcpserver_set_router(&ap_ip.ip);
|
||||||
|
break;
|
||||||
|
case STATION_MODE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done.
|
||||||
|
void user_init(void) {
|
||||||
|
uart_set_baud(0, 115200);
|
||||||
|
|
||||||
|
wifiInit();
|
||||||
|
ioInit();
|
||||||
|
captdnsInit();
|
||||||
|
|
||||||
|
espFsInit((void*)(_binary_build_web_espfs_bin_start));
|
||||||
|
httpdInit(builtInUrls, 80);
|
||||||
|
|
||||||
|
xTaskCreate(websocketBcast, "wsbcast", 300, NULL, 3, NULL);
|
||||||
|
|
||||||
|
printf("\nReady\n");
|
||||||
|
}
|
64
extras/libesphttpd/component.mk
Normal file
64
extras/libesphttpd/component.mk
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
# Component makefile for extras/libesphttpd
|
||||||
|
|
||||||
|
INC_DIRS += $(libesphttpd_ROOT)/libesphttpd/include $(libesphttpd_ROOT)/libesphttpd/espfs $(libesphttpd_ROOT)/libesphttpd/lib/heatshrink
|
||||||
|
|
||||||
|
LIBESPHTTPD_MAX_CONNECTIONS ?= 4
|
||||||
|
LIBESPHTTPD_STACKSIZE ?= 2048
|
||||||
|
LIBESPHTTPD_OTA_TAGNAME ?= generic
|
||||||
|
|
||||||
|
RBOOT_OTA ?= 1
|
||||||
|
ESP_IP ?= 192.168.4.1
|
||||||
|
|
||||||
|
# args for passing into compile rule generation
|
||||||
|
libesphttpd_SRC_DIR = $(libesphttpd_ROOT)/libesphttpd/core $(libesphttpd_ROOT)/libesphttpd/espfs $(libesphttpd_ROOT)/libesphttpd/util
|
||||||
|
libesphttpd_CFLAGS += -DFREERTOS -DUSE_OPEN_SDK -DHTTPD_MAX_CONNECTIONS=$(LIBESPHTTPD_MAX_CONNECTIONS) -DHTTPD_STACKSIZE=$(LIBESPHTTPD_STACKSIZE) -DESPFS_HEATSHRINK -D__ets__ -DRBOOT_OTA=1 -std=gnu99
|
||||||
|
|
||||||
|
$(eval $(call component_compile_rules,libesphttpd))
|
||||||
|
|
||||||
|
rwildcard = $(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
|
||||||
|
|
||||||
|
LIBESPHTTPD_MKESPFSIMAGE_DIR = $(BUILD_DIR)mkespfsimage
|
||||||
|
|
||||||
|
LIBESPHTTPD_MKESPFS = $(LIBESPHTTPD_MKESPFSIMAGE_DIR)/mkespfsimage
|
||||||
|
LIBESPHTTPD_HTML_DIR = html
|
||||||
|
LIBESPHTTPD_HTML_FILES = $(call rwildcard,$(LIBESPHTTPD_HTML_DIR),*)
|
||||||
|
LIBESPHTTPD_HTML_TINY_DIR = $(BUILD_DIR)html
|
||||||
|
LIBESPHTTPD_HTML_ESPFS = $(BUILD_DIR)web.espfs.bin
|
||||||
|
LIBESPHTTPD_HTML_ESPFS_PATH = $(PROGRAM_REAL_ROOT)/$(LIBESPHTTPD_HTML_ESPFS)
|
||||||
|
LIBESPHTTPD_HTML_ESPFS_OBJ = $(BUILD_DIR)web.espfs.o
|
||||||
|
|
||||||
|
CROSS_BINARY_ARCH ?= xtensa
|
||||||
|
CROSS_OUTPUT_TARGET ?= elf32-xtensa-le
|
||||||
|
|
||||||
|
LIBESPHTTPD_HTML_TINY ?= no
|
||||||
|
|
||||||
|
CURL = curl
|
||||||
|
LIBESPHTTPD_CURL_OPTS = --connect-timeout 3 --max-time 60 -s
|
||||||
|
|
||||||
|
$(LIBESPHTTPD_MKESPFSIMAGE_DIR):
|
||||||
|
$(Q)mkdir -p $(LIBESPHTTPD_MKESPFSIMAGE_DIR)
|
||||||
|
|
||||||
|
$(PROGRAM_REAL_ROOT)/$(LIBESPHTTPD_MKESPFS): $(LIBESPHTTPD_MKESPFSIMAGE_DIR)
|
||||||
|
make -C $(libesphttpd_ROOT)/libesphttpd/espfs/mkespfsimage CC=gcc GZIP_COMPRESSION=yes USE_HEATSHRINK=yes BUILD_DIR=$(PROGRAM_REAL_ROOT)/$(BUILD_DIR)
|
||||||
|
|
||||||
|
$(LIBESPHTTPD_HTML_ESPFS): $(PROGRAM_REAL_ROOT)/$(LIBESPHTTPD_MKESPFS) $(LIBESPHTTPD_HTML_FILES)
|
||||||
|
cd $(LIBESPHTTPD_HTML_DIR) && find . | $< > $(LIBESPHTTPD_HTML_ESPFS_PATH) || rm -f $(LIBESPHTTPD_HTML_ESPFS_PATH)
|
||||||
|
|
||||||
|
$(LIBESPHTTPD_HTML_ESPFS_OBJ): $(LIBESPHTTPD_HTML_ESPFS)
|
||||||
|
$(Q)$(OBJCOPY) -I binary -O $(CROSS_OUTPUT_TARGET) -B $(CROSS_BINARY_ARCH) --rename-section .data=.irom.espfs $^ $@
|
||||||
|
|
||||||
|
$(BUILD_DIR)libesphttpd.a: $(LIBESPHTTPD_HTML_ESPFS_OBJ)
|
||||||
|
|
||||||
|
htmlfs: $(LIBESPHTTPD_HTML_ESPFS_OBJ)
|
||||||
|
|
||||||
|
$(libesphttpd_ROOT)/libesphttpd/mkupgimg/mkupgimg:
|
||||||
|
make -C $(libesphttpd_ROOT)/libesphttpd/mkupgimg CC=gcc RBOOT_OTA=$(RBOOT_OTA)
|
||||||
|
|
||||||
|
$(FIRMWARE_DIR)ota_$(PROGRAM).bin: $(FW_FILE) $(libesphttpd_ROOT)/libesphttpd/mkupgimg/mkupgimg
|
||||||
|
$(libesphttpd_ROOT)/libesphttpd/mkupgimg/mkupgimg $(FW_FILE) "$(LIBESPHTTPD_OTA_TAGNAME)" $(FIRMWARE_DIR)ota_$(PROGRAM).bin
|
||||||
|
|
||||||
|
ota: $(FIRMWARE_DIR)ota_$(PROGRAM).bin $(libesphttpd_ROOT)/libesphttpd/mkupgimg/mkupgimg
|
||||||
|
|
||||||
|
webflash: $(FIRMWARE_DIR)ota_$(PROGRAM).bin
|
||||||
|
$(CURL) $(LIBESPHTTPD_CURL_OPTS) --data-binary "@$(FIRMWARE_DIR)ota_$(PROGRAM).bin" http://$(ESP_IP)/flash/upload && $(CURL) $(LIBESPHTTPD_CURL_OPTS) http://$(ESP_IP)/flash/reboot
|
||||||
|
|
1
extras/libesphttpd/libesphttpd
Submodule
1
extras/libesphttpd/libesphttpd
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit c329aeef0469a40152e1630dbd0f0b34bcebd4d5
|
Loading…
Reference in a new issue