Removed example project junk & added UART drivers

pull/30/head
Ondřej Hruška 8 years ago
parent be3c0fe926
commit aaec5323cd
  1. 98
      README.md
  2. 5
      compress_html.sh
  3. BIN
      html/cats/cross-eyed-cat.jpg
  4. BIN
      html/cats/junge-katze-iv.jpg
  5. BIN
      html/cats/kitten-loves-toy.jpg
  6. 2
      html/flash/140medley.min.js
  7. 82
      html/flash/index.html
  8. 34
      html/flash/style.css
  9. 1
      html/index.html
  10. 28
      html/index.tpl
  11. 15
      html/led.tpl
  12. 1
      html/script.js
  13. 18
      html/style.css
  14. 9
      html/test/index.html
  15. 205
      html/test/test.js
  16. 69
      html/websocket/index.html
  17. 2
      html/wifi/140medley.min.js
  18. 43
      html/wifi/connecting.html
  19. BIN
      html/wifi/icons.png
  20. 24
      html/wifi/style.css
  21. 94
      html/wifi/wifi.tpl
  22. 20
      html_orig/index.html
  23. 271
      html_orig/script.js
  24. 40
      html_orig/style.css
  25. 17
      include/ets_sys_extra.h
  26. 86
      user/cgi-test.c
  27. 8
      user/cgi-test.h
  28. 76
      user/cgi.c
  29. 10
      user/cgi.h
  30. 19
      user/io.c
  31. 2
      user/io.h
  32. 28
      user/serial.c
  33. 9
      user/serial.h
  34. 47
      user/stdout.c
  35. 6
      user/stdout.h
  36. 249
      user/uart_driver.c
  37. 201
      user/uart_driver.h
  38. 185
      user/uart_handler.c
  39. 27
      user/uart_handler.h
  40. 160
      user/user_main.c

@ -1,96 +1,2 @@
# esp-httpd README # # esp-vt100-firmware
ESP8266 Remote Terminal project
This is the demonstration project for the small but powerful libesphttpd webserver
for ESP8266(EX) chips. It is an example of how to make a module that can have
the AP it connects to configured over a webbrowser. It also illustrates multiple
flash layouts and some OTA update functionality.
## ABOUT THE WEBSERVER ##
The Good (aka: what's awesome)
- Supports multiple connections, for eg simultaneous html/css/js/images downloading
- Static files stored in flash, in an (optionally compressed) RO filesystem
- Pluggable using external cgi routines
- Simple template engine for mixed c and html things
- Usable as an embedded library - should be easy to drop into your existing projects
- Includes websocket support
The Bad (aka: what can be improved)
- Not built for speediness, although it's reasonable fast.
- Built according to what I remember of the HTTP protocol, not according to the
RFCs. Should work with most modern browsers, though.
- No support for https.
The Ugly (aka: bugs, misbehaviour)
- Possible buffer overflows (usually not remotely exploitable) due to no os_snprintf
This can be theoretically remedied by either Espressif including an os_snprintf in
their libs or by using some alternate printf lib, like elm-chans xprintf
## SOURCE OF THIS CODE ##
The official esphttpd repo lives at http://git.spritesserver.nl/esphttpd.git/ and
http://git.spritesserver.nl/libesphttpd.git/ . If you're a fan of Github, you can also
peruse the official mirror at https://github.com/Spritetm/esphttpd and https://github.com/Spritetm/libesphttpd . If
you want to discuss this code, there is a subforum at esp8266.com: http://www.esp8266.com/viewforum.php?f=34 .
## ABOUT THE EXAMPLE ##
When you flash the example into an ESP8266(EX) module, you get a small webserver with a few example
pages. If you've already connected your module to your WLAN before, it'll keep those settings. When
you haven't or the settings are wrong, keep GPIO0 for >5 seconds. The module will reboot into
its STA+AP mode. Connect a computer to the newly formed access point and browse to
http://192.168.4.1/wifi in order to connect the module to your WiFi network. The example also
allows you to control a LED that's connected to GPIO2.
## BUILDING EVERYTHING ##
For this, you need an environment that can compile ESP8266 firmware. Environments for this still
are in flux at the moment, but I'm using esp-open-sdk: https://github.com/pfalcon/esp-open-sdk .
You probably also need an UNIX-like system; I'm working on Debian Linux myself.
To manage the paths to all this, you can source a small shell fragment into your current session. For
example, I source a file with these contents:
export PATH=${PWD}/esp-open-sdk/xtensa-lx106-elf/bin:$PATH
export SDK_BASE=${PWD}/esp-open-sdk/sdk
export ESPTOOL=${PWD}/esptool/esptool.py
export ESPPORT=/dev/ttyUSB0
export ESPBAUD=460800
Actual setup of the SDK and toolchain is out of the scope of this document, so I hope this helps you
enough to set up your own if you haven't already.
If you have that, you can clone out the source code:
git clone http://git.spritesserver.nl/esphttpd.git/
This project makes use of heatshrink, which is a git submodule. To fetch the code:
cd esphttpd
git submodule init
git submodule update
Now, build the code:
make
Depending on the way you built it, esp-open-sdk sometimes patches Espressifs SDK, needing a slightly different
compiling process. If this is needed, you will get errors during compiling complaining about uint8_t being
undeclared. If this happens, try building like this:
make USE_OPENSDK=yes
You can also edit the Makefile to change this more permanently.
After the compile process, flash the code happens in 2 steps. First the code itself gets flashed. Reset the module into bootloader
mode and enter 'make flash'.
The 2nd step is to pack the static files the webserver will serve and flash that. Reset the module into
bootloader mode again and enter `make htmlflash`.
You should have a working webserver now.
## WRITING CODE FOR THE WEBSERVER ##
Please see the README.md of the libesphttpd project for the programming manual.

@ -0,0 +1,5 @@
#!/bin/bash
yuicompressor html_orig/style.css > html/style.css
yuicompressor html_orig/script.js > html/script.js
minify --type=html html_orig/index.html -o html/index.html

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

@ -1,2 +0,0 @@
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){}};

@ -1,82 +0,0 @@
<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() {
//Grab the /flash/reboot url in order to reboot into the new firmware.
xhr.open("GET", "reboot");
xhr.onreadystatechange=function() {
if (xhr.readyState==4 && xhr.status>=200 && xhr.status<300) {
//Reload the window after 5 seconds.
window.setTimeout(function() {
location.reload(true);
}, 5000);
}
}
xhr.send();
}
//Sets the progress bar to a specific level. Amt is between 0 and 1.
function setProgress(amt) {
$("#progressbarinner").style.width=String(amt*200)+"px";
}
//Called when the submit button is called.
function doUpgrade() {
//Grab the file, see if it's a real file.
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 the webbrowser enables it, make progress bar show progress.
if (typeof xhr.upload.onprogress != 'undefined') {
xhr.upload.onprogress=function(e) {
setProgress(e.loaded / e.total);
}
}
//Upload the file
xhr.send(f);
return false;
}
window.onload=function(e) {
//Grab the initial remark telling user which userx.bin file to upload.
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>

@ -1,34 +0,0 @@
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;
}

@ -0,0 +1 @@
<!doctype html><meta charset=utf-8><title>ESP8266 Remote Terminal</title><meta name=viewport content="width=device-width,shrink-to-fit=no,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1"><link rel=stylesheet href=style.css><script src=script.js></script><header>ESP8266 Remote Terminal</header><div id=screen></div><div id=buttons><button>1</button><button>2</button><button>3</button><button>4</button></div><script>init()</script>

@ -1,28 +0,0 @@
<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>If you have a firmware upgrade file and the module is compiled for firmware upgrades, you
can <a href="flash/index.html">upgrade the firmware</a> of this module.</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>

@ -1,15 +0,0 @@
<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>

@ -0,0 +1 @@
var $=function(d,c){d=d.match(/^(\W)?(.*)/);return(c||document)["getElement"+(d[1]?d[1]=="#"?"ById":"sByClassName":"sByTagName")](d[2])};var m=function(e,d,f){d=document;f=d.createElement("p");f.innerHTML=e;e=d.createDocumentFragment();while(d=f.firstChild){e.appendChild(d)}return e};(function(){function a(r){return document.createElement(r)}var b=26,k=10;var l={a:false,x:0,y:0,suppress:false,hidden:false};var o=[];var g=["#111213","#CC0000","#4E9A06","#C4A000","#3465A4","#75507B","#06989A","#D3D7CF","#555753","#EF2929","#8AE234","#FCE94F","#729FCF","#AD7FA8","#34E2E2","#EEEEEC"];function p(){o.forEach(function(r,s){r.t=" ";r.fg=7;r.bg=0;d(r)})}function c(s,r){return o[s*b+r]}function i(){return c(l.y,l.x)}function q(r){l.hidden=!r;l.a&=r;d(i(),l.a)}function f(s,r){l.suppress=true;d(i(),false);l.x=r;l.y=s;l.suppress=false;d(i(),l.a)}function d(s,r){var v=s.e,t,u;t=r?s.bg:s.fg;u=r?s.fg:s.bg;v.innerText=(s.t+" ")[0];v.style.color=e(t);v.style.backgroundColor=e(u);v.style.fontWeight=t>7?"bold":"normal"}function h(){o.forEach(function(s,t){var r=l.a&&(t==l.y*b+l.x);d(s,r)})}function j(s){if(s.length!=b*k*3){throw"Bad data format."}for(var t=0;t<b*k;t++){var r=o[t];r.t=s[t*3];r.fg=parseInt(s[t*3+1],16);r.bg=parseInt(s[t*3+2],16)}h()}function e(r){var r=parseInt(r);if(r<0||r>15){r=0}return g[r]}function n(){var u,t=$("#screen");for(var s=0;s<b*k;s++){u=a("span");if((s>0)&&(s%b==0)){t.appendChild(a("br"))}t.appendChild(u);var r={t:" ",fg:7,bg:0,e:u};o.push(r);d(r)}setInterval(function(){l.a=!l.a;if(l.hidden){l.a=false}if(!l.suppress){d(i(),l.a)}},500)}window.Term={init:n,load:j,setCursor:f,enableCursor:q,clear:p}})();(function(){var g="ws://"+window.location.host+"/ws/update.cgi";var d;function c(i){console.log("CONNECTED")}function b(i){console.error("SOCKET CLOSED")}function f(i){console.log("Message received!",i.data)}function e(i){console.error(i.data)}function a(i){d.send(i)}function h(){d=new WebSocket(g);d.onopen=c;d.onclose=b;d.onmessage=f;d.onerror=e;console.log("Opening socket.")}window.Conn={ws:null,init:h}})();function init(){Term.init();Conn.init()};

@ -1,17 +1 @@
html,body{background:#48505f;color:#eee;font-family:monospace;font-size:16pt;text-align:center}header{font-weight:bold;font-size:14pt;padding:6px;display:block}#screen{display:block;white-space:nowrap;background:#111213;border-radius:3px;padding:6px;box-shadow:inset 0 0 5px black;display:inline-block}#screen span{white-space:pre}#buttons{margin-top:10px}button{margin:0 2px;padding:10px 0;width:22%;max-width:80px;cursor:pointer}
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
}

@ -1,9 +0,0 @@
<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>

@ -1,205 +0,0 @@
/*
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);
}

@ -1,69 +0,0 @@
<!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>

@ -1,2 +0,0 @@
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){}};

@ -1,43 +0,0 @@
<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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 914 B

@ -1,24 +0,0 @@
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;
}

@ -1,94 +0,0 @@
<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>

@ -0,0 +1,20 @@
<!DOCTYPE html>
<meta charset="UTF-8">
<title>ESP8266 Remote Terminal</title>
<meta name="viewport" content="width=device-width,shrink-to-fit=no,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0">
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
<!-- Katedra mereni FEL, 2017 -->
<!-- TODO GitHub link -->
<header>ESP8266 Remote Terminal</header>
<div id="screen"></div>
<div id="buttons">
<button>1</button><button>2</button><button>3</button><button>4</button>
</div>
<script>init()</script>

@ -0,0 +1,271 @@
//region Libs / utils
/*
* DOM selector
*
* Usage:
* $('div');
* $('#name');
* $('.name');
*
*
* Copyright (C) 2011 Jed Schmidt <http://jed.is> - WTFPL
* More: https://gist.github.com/991057
*
*/
var $ = function(
a, // take a simple selector like "name", "#name", or ".name", and
b // an optional context, and
){
a = a.match(/^(\W)?(.*)/); // split the selector into name and symbol.
return( // return an element or list, from within the scope of
b // the passed context
|| document // or document,
)[
"getElement" + ( // obtained by the appropriate method calculated by
a[1]
? a[1] == "#"
? "ById" // the node by ID,
: "sByClassName" // the nodes by class name, or
: "sByTagName" // the nodes by tag name,
)
](
a[2] // called with the name.
)
};
/*
* Create DOM element
*
* Usage:
* var el = m('<h1>Hello</h1>');
* document.body.appendChild(el);
*
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) 2011 Jed Schmidt <http://jed.is> - WTFPL
* More: https://gist.github.com/966233
*
*/
var m = function(
a, // an HTML string
b, // placeholder
c // placeholder
){
b = document; // get the document,
c = b.createElement("p"); // create a container element,
c.innerHTML = a; // write the HTML to it, and
a = b.createDocumentFragment(); // create a fragment.
while ( // while
b = c.firstChild // the container element has a first child
) a.appendChild(b); // append the child to the fragment,
return a // and then return the fragment.
};
//endregion
//
// Terminal class
//
(function () {
function make(e) {return document.createElement(e)}
var W = 26, H = 10; //26, 10
var cursor = {a: false, x: 0, y: 0, suppress: false, hidden: false};
var screen = [];
/** Colors table */
var CLR = [// dark gray #2E3436
// 0 black, 1 red, 2 green, 3 yellow
// 4 blue, 5 mag, 6 cyan, 7 white
'#111213','#CC0000','#4E9A06','#C4A000',
'#3465A4','#75507B','#06989A','#D3D7CF',
// BRIGHT
// 8 black, 9 red, 10 green, 11 yellow
// 12 blue, 13 mag, 14 cyan, 15 white
'#555753','#EF2929','#8AE234','#FCE94F',
'#729FCF','#AD7FA8','#34E2E2','#EEEEEC'
];
/** Clear screen */
function cls() {
screen.forEach(function(cell, i) {
cell.t = ' ';
cell.fg = 7;
cell.bg = 0;
blit(cell);
});
}
/** Set text and color at XY */
function cellAt(y, x) {
return screen[y*W+x];
}
/** Get cell under cursor */
function cursorCell() {
return cellAt(cursor.y, cursor.x);
}
/** Enable or disable cursor visibility */
function cursorEnable(enable) {
cursor.hidden = !enable;
cursor.a &= enable;
blit(cursorCell(), cursor.a);
}
/** Safely move cursor */
function cursorSet(y, x) {
// Hide and prevent from showing up during the move
cursor.suppress = true;
blit(cursorCell(), false);
cursor.x = x;
cursor.y = y;
// Show again
cursor.suppress = false;
blit(cursorCell(), cursor.a);
}
/** Update cell on display. inv = invert (for cursor) */
function blit(cell, inv) {
var e = cell.e, fg, bg;
// Colors
fg = inv ? cell.bg : cell.fg;
bg = inv ? cell.fg : cell.bg;
// Update
e.innerText = (cell.t+' ')[0];
e.style.color = colorHex(fg);
e.style.backgroundColor = colorHex(bg);
e.style.fontWeight = fg > 7 ? 'bold' : 'normal';
}
/** Show entire screen */
function blitAll() {
screen.forEach(function(cell, i) {
/* Invert if under cursor & cursor active */
var inv = cursor.a && (i == cursor.y*W+cursor.x);
blit(cell, inv);
});
}
/** Load screen content from a 'binary' sequence */
function load(seq) {
if (seq.length != W*H*3) throw "Bad data format.";
// primitive format with 3 chars per cell: letter, fg [hex], bg [hex]
for (var i = 0; i < W * H; i++) {
var cell = screen[i];
cell.t = seq[i*3];
cell.fg = parseInt(seq[i*3+1], 16);
cell.bg = parseInt(seq[i*3+2], 16);
}
blitAll();
}
/** Parse color */
function colorHex(c) {
var c = parseInt(c);
if (c < 0 || c > 15) c = 0;
return CLR[c];
}
/** Init the terminal */
function init() {
/* Build screen & show */
var e, scr = $('#screen');
for(var i = 0; i < W*H; i++) {
e = make('span');
/* End of line */
if ((i > 0) && (i % W == 0)) {
scr.appendChild(make('br'));
}
/* The cell */
scr.appendChild(e);
var cell = {t: ' ', fg: 7, bg: 0, e: e};
screen.push(cell);
blit(cell);
}
/* Cursor blinking */
setInterval(function() {
cursor.a = !cursor.a;
if (cursor.hidden) {
cursor.a = false;
}
if (!cursor.suppress) {
blit(cursorCell(), cursor.a);
}
}, 500);
}
// publish
window.Term = {
init: init,
load: load,
setCursor: cursorSet,
enableCursor: cursorEnable,
clear: cls,
};
})();
//
// Connection class
//
(function() {
var wsUri = "ws://"+window.location.host+"/ws/update.cgi";
var ws;
function onOpen(evt) {
console.log("CONNECTED");
}
function onClose(evt) {
console.error("SOCKET CLOSED");
}
function onMessage(evt) {
console.log("Message received!", evt.data);
// TODO process
}
function onError(evt) {
console.error(evt.data);
}
function doSend(message) {
ws.send(message);
}
function init() {
ws = new WebSocket(wsUri);
ws.onopen = onOpen;
ws.onclose = onClose
ws.onmessage = onMessage;
ws.onerror = onError;
console.log("Opening socket.");
}
window.Conn = {
ws: null,
init: init,
};
})();
function init() {
Term.init();
Conn.init();
}

@ -0,0 +1,40 @@
html, body {
background: #48505F;
color: #eee;
font-family: monospace;
font-size: 16pt;
text-align: center;
}
header {
font-weight: bold;
font-size: 14pt;
padding: 6px;
display: block;
}
#screen {
display: block;
white-space: nowrap;
background: #111213;
border-radius: 3px;
padding: 6px;
box-shadow: inset 0 0 5px black;
display: inline-block;
}
#screen span {
white-space: pre;
}
#buttons {
margin-top: 10px;
}
button {
margin: 0 2px;
padding: 10px 0;
width: 22%;
max-width: 80px;
cursor: pointer;
}

@ -0,0 +1,17 @@
#pragma once
#include <c_types.h>
// copied from nodemcu source
extern uint32_t system_get_time();
extern uint32_t platform_tmr_exists(uint32_t t);
extern uint32_t system_rtc_clock_cali_proc();
extern uint32_t system_get_rtc_time();
extern void system_restart();
extern void system_soft_wdt_feed();
// https://github.com/mziwisky/esp8266-dev/blob/master/esphttpd/include/espmissingincludes.h
extern int ets_str2macaddr(void *, void *);
extern void ets_update_cpu_frequency(int freqmhz);
extern int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
//extern uint8 wifi_get_opmode(void);
extern void ets_bzero(void *s, size_t n);

@ -1,86 +0,0 @@
/*
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 <esp8266.h>
#include "cgi-test.h"
typedef struct {
int len;
int sendPos;
} TestbedState;
httpd_cgi_state 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;
}

@ -1,8 +0,0 @@
#ifndef CGI_TEST_H
#define CGI_TEST_H
#include "httpd.h"
httpd_cgi_state cgiTestbed(HttpdConnData *connData);
#endif

@ -1,76 +0,0 @@
/*
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 <esp8266.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
httpd_cgi_state 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.
httpd_cgi_state ICACHE_FLASH_ATTR tplLed(HttpdConnData *connData, char *token, void **arg) {
char buff[128];
if (token==NULL) return HTTPD_CGI_DONE;
os_strcpy(buff, "Unknown");
if (os_strcmp(token, "ledstate")==0) {
if (currLedState) {
os_strcpy(buff, "on");
} else {
os_strcpy(buff, "off");
}
}
httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE;
}
static long hitCounter=0;
//Template code for the counter on the index page.
httpd_cgi_state ICACHE_FLASH_ATTR tplCounter(HttpdConnData *connData, char *token, void **arg) {
char buff[128];
if (token==NULL) return HTTPD_CGI_DONE;
if (os_strcmp(token, "counter")==0) {
hitCounter++;
os_sprintf(buff, "%ld", hitCounter);
}
httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE;
}

@ -1,10 +0,0 @@
#ifndef CGI_H
#define CGI_H
#include "httpd.h"
httpd_cgi_state cgiLed(HttpdConnData *connData);
httpd_cgi_state tplLed(HttpdConnData *connData, char *token, void **arg);
httpd_cgi_state tplCounter(HttpdConnData *connData, char *token, void **arg);
#endif

@ -14,6 +14,8 @@
#define LEDGPIO 2 #define LEDGPIO 2
#define BTNGPIO 0 #define BTNGPIO 0
static bool enable_ap_button = false;
static ETSTimer resetBtntimer; static ETSTimer resetBtntimer;
void ICACHE_FLASH_ATTR ioLed(int ena) { void ICACHE_FLASH_ATTR ioLed(int ena) {
@ -27,25 +29,34 @@ void ICACHE_FLASH_ATTR ioLed(int ena) {
static void ICACHE_FLASH_ATTR resetBtnTimerCb(void *arg) { static void ICACHE_FLASH_ATTR resetBtnTimerCb(void *arg) {
static int resetCnt=0; static int resetCnt=0;
if (!GPIO_INPUT_GET(BTNGPIO)) { if (enable_ap_button && !GPIO_INPUT_GET(BTNGPIO)) {
resetCnt++; resetCnt++;
} else { } else {
if (resetCnt>=6) { //3 sec pressed if (resetCnt>=6) { //3 sec pressed
wifi_station_disconnect(); wifi_station_disconnect();
wifi_set_opmode(0x3); //reset to AP+STA mode wifi_set_opmode(STATIONAP_MODE); //reset to AP+STA mode
os_printf("Reset to AP mode. Restarting system...\n"); info("Reset to AP mode from GPIO0, Restarting system...");
system_restart(); system_restart();
} }
resetCnt=0; resetCnt=0;
} }
} }
void ioInit() { void ICACHE_FLASH_ATTR ioInit() {
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2); PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0); PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
gpio_output_set(0, 0, (1<<LEDGPIO), (1<<BTNGPIO)); gpio_output_set(0, 0, (1<<LEDGPIO), (1<<BTNGPIO));
os_timer_disarm(&resetBtntimer); os_timer_disarm(&resetBtntimer);
os_timer_setfn(&resetBtntimer, resetBtnTimerCb, NULL); os_timer_setfn(&resetBtntimer, resetBtnTimerCb, NULL);
os_timer_arm(&resetBtntimer, 500, 1); os_timer_arm(&resetBtntimer, 500, 1);
// One way to enter AP mode - hold GPIO0 low.
if (GPIO_INPUT_GET(BTNGPIO) == 0) {
// starting "in BOOT mode" - do not install the AP reset timer
warn("GPIO0 stuck low - AP reset button disabled.\n");
} else {
enable_ap_button = true;
dbg("Note: Hold GPIO0 low for reset to AP mode.\n");
}
} }

@ -1,7 +1,7 @@
#ifndef IO_H #ifndef IO_H
#define IO_H #define IO_H
void ICACHE_FLASH_ATTR ioLed(int ena); void ioLed(int ena);
void ioInit(void); void ioInit(void);
#endif #endif

@ -0,0 +1,28 @@
#include <esp8266.h>
#include "uart_driver.h"
#include "uart_handler.h"
// Here the bitrates are defined
#define UART0_BAUD BIT_RATE_115200
#define UART1_BAUD BIT_RATE_115200
/**
* Init the serial ports
*/
void ICACHE_FLASH_ATTR serialInit(void)
{
UART_Init(UART0_BAUD, UART1_BAUD);
UART_SetPrintPort(UART0);
UART_SetupAsyncReceiver();
}
/**
* Handle a byte received from UART.
* Might do some buffering here maybe
*
* @param c
*/
void ICACHE_FLASH_ATTR UART_HandleRxByte(char c)
{
printf("'%c',", c);
}

@ -0,0 +1,9 @@
#ifndef SERIAL_H
#define SERIAL_H
/** Init the uarts */
void serialInit(void);
void UART_HandleRxByte(char c);
#endif //SERIAL_H

@ -1,47 +0,0 @@
//Stupid bit of code that does the bare minimum to make os_printf work.
/*
* ----------------------------------------------------------------------------
* "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 <esp8266.h>
#include <uart_hw.h>
static void ICACHE_FLASH_ATTR stdoutUartTxd(char c) {
//Wait until there is room in the FIFO
while (((READ_PERI_REG(UART_STATUS(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ;
//Send the character
WRITE_PERI_REG(UART_FIFO(0), c);
}
static void ICACHE_FLASH_ATTR stdoutPutchar(char c) {
//convert \n -> \r\n
if (c=='\n') stdoutUartTxd('\r');
stdoutUartTxd(c);
}
void stdoutInit() {
//Enable TxD pin
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
//Set baud rate and other serial parameters to 115200,n,8,1
uart_div_modify(0, UART_CLK_FREQ/BIT_RATE_115200);
WRITE_PERI_REG(UART_CONF0(0), (STICK_PARITY_DIS)|(ONE_STOP_BIT << UART_STOP_BIT_NUM_S)| \
(EIGHT_BITS << UART_BIT_NUM_S));
//Reset tx & rx fifo
SET_PERI_REG_MASK(UART_CONF0(0), UART_RXFIFO_RST|UART_TXFIFO_RST);
CLEAR_PERI_REG_MASK(UART_CONF0(0), UART_RXFIFO_RST|UART_TXFIFO_RST);
//Clear pending interrupts
WRITE_PERI_REG(UART_INT_CLR(0), 0xffff);
//Install our own putchar handler
os_install_putc1((void *)stdoutPutchar);
}

@ -1,6 +0,0 @@
#ifndef STDOUT_H
#define STDOUT_H
void stdoutInit();
#endif

@ -0,0 +1,249 @@
/*
* Driver file for ESP8266 UART, works with the SDK.
*/
#include "uart_driver.h"
#include <esp8266.h>
#include "ets_sys.h"
#include "osapi.h"
#include "mem.h"
#include "os_type.h"
#include "ets_sys_extra.h"
#include "uart_register.h"
//========================================================
void ICACHE_FLASH_ATTR UART_SetWordLength(UARTn uart_no, UartBitsNum4Char len)
{
SET_PERI_REG_BITS(UART_CONF0(uart_no), UART_BIT_NUM, len, UART_BIT_NUM_S);
}
void ICACHE_FLASH_ATTR UART_SetStopBits(UARTn uart_no, UartStopBitsNum bit_num)
{
SET_PERI_REG_BITS(UART_CONF0(uart_no), UART_STOP_BIT_NUM, bit_num, UART_STOP_BIT_NUM_S);
}
void ICACHE_FLASH_ATTR UART_SetLineInverse(UARTn uart_no, UART_LineLevelInverse inverse_mask)
{
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_LINE_INV_MASK);
SET_PERI_REG_MASK(UART_CONF0(uart_no), inverse_mask);
}
void ICACHE_FLASH_ATTR UART_SetParity(UARTn uart_no, UartParityMode Parity_mode)
{
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_PARITY | UART_PARITY_EN);
if (Parity_mode == PARITY_NONE) {
} else {
SET_PERI_REG_MASK(UART_CONF0(uart_no), Parity_mode | UART_PARITY_EN);
}
}
void ICACHE_FLASH_ATTR UART_SetBaudrate(UARTn uart_no, uint32 baud_rate)
{
uart_div_modify(uart_no, UART_CLK_FREQ / baud_rate);
}
void ICACHE_FLASH_ATTR UART_SetFlowCtrl(UARTn uart_no, UART_HwFlowCtrl flow_ctrl, uint8 rx_thresh)
{
if (flow_ctrl & USART_HWFlow_RTS) {
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
SET_PERI_REG_BITS(UART_CONF1(uart_no), UART_RX_FLOW_THRHD, rx_thresh, UART_RX_FLOW_THRHD_S);
SET_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN);
} else {
CLEAR_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN);
}
if (flow_ctrl & USART_HWFlow_CTS) {
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_UART0_CTS);
SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN);
} else {
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN);
}
}
void ICACHE_FLASH_ATTR UART_WaitTxFifoEmpty(UARTn uart_no , uint32 time_out_us) //do not use if tx flow control enabled
{
uint32 t_s = system_get_time();
while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S)) {
if ((system_get_time() - t_s) > time_out_us) {
break;
}
system_soft_wdt_feed();
}
}
bool ICACHE_FLASH_ATTR UART_CheckOutputFinished(UARTn uart_no, uint32 time_out_us)
{
uint32 t_start = system_get_time();
uint8 tx_fifo_len;
while (1) {
tx_fifo_len = UART_TxQueLen(uart_no);
// TODO If using output circbuf, check if empty
if (tx_fifo_len == 0) {
return TRUE;
}
if (system_get_time() - t_start > time_out_us) {
return FALSE;
}
system_soft_wdt_feed();
}
}
void ICACHE_FLASH_ATTR UART_ResetFifo(UARTn uart_no)
{
SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
}
void ICACHE_FLASH_ATTR UART_ClearIntrStatus(UARTn uart_no, uint32 clr_mask)
{
WRITE_PERI_REG(UART_INT_CLR(uart_no), clr_mask);
}
void ICACHE_FLASH_ATTR UART_SetIntrEna(UARTn uart_no, uint32 ena_mask)
{
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), ena_mask);
}
LOCAL void u0_putc_crlf(char c)
{
UART_WriteCharCRLF(UART0, (u8)c, UART_TIMEOUT_US);
}
LOCAL void u1_putc_crlf(char c)
{
UART_WriteCharCRLF(UART1, (u8)c, UART_TIMEOUT_US);
}
void ICACHE_FLASH_ATTR UART_SetPrintPort(UARTn uart_no)
{
if (uart_no == UART0) {
os_install_putc1((void *)u0_putc_crlf);
} else {
os_install_putc1((void *)u1_putc_crlf);
}
}
// -------------- Custom UART functions -------------------------
// !!! write handlers are not ICACHE_FLASH_ATTR -> can be used in IRQ !!!
/**
* @brief Write a char to UART.
* @param uart_no
* @param c
* @param timeout_us - how long to max wait for space in FIFO.
* @return write success
*/
STATUS UART_WriteChar(UARTn uart_no, uint8 c, uint32 timeout_us)
{
if (timeout_us == 0) {
timeout_us = UART_TIMEOUT_US;
}
uint32 t_s = system_get_time();
while ((system_get_time() - t_s) < timeout_us) {
uint8 fifo_cnt = UART_TxQueLen(uart_no);
if (fifo_cnt < UART_TX_FULL_THRESH_VAL) {
WRITE_PERI_REG(UART_FIFO(uart_no), c);
return OK;
}
system_soft_wdt_feed();
}
return FAIL;
}
/**
* @brief Write a char to UART, translating LF to CRLF and discarding CR.
* @param uart_no
* @param c
* @param timeout_us - how long to max wait for space in FIFO.
* @return write success
*/
STATUS UART_WriteCharCRLF(UARTn uart_no, uint8 c, uint32 timeout_us)
{
STATUS st;
if (c == '\r') {
return OK;
} else if (c == '\n') {
st = UART_WriteChar(uart_no, '\r', timeout_us);
if (st != OK) return st;
st = UART_WriteChar(uart_no, '\n', timeout_us);
return st;
} else {
return UART_WriteChar(uart_no, c, timeout_us);
}
}
/**
* @brief Send a string to UART.
* @param uart_no
* @param str
* @param timeout_us - how long to max wait for space in FIFO.
* @return write success
*/
STATUS UART_WriteString(UARTn uart_no, const char *str, uint32 timeout_us)
{
while (*str) {
STATUS suc = UART_WriteChar(uart_no, (u8) * str++, timeout_us);
if (suc != OK) return suc;
}
return OK;
}
/**
* @brief Send a buffer
* @param uart_no
* @param buffer - buffer to send
* @param len - buffer size
* @param timeout_us - how long to max wait for space in FIFO.
* @return write success
*/
STATUS UART_WriteBuffer(UARTn uart_no, const uint8 *buffer, size_t len, uint32 timeout_us)
{
for (size_t i = 0; i < len; i++) {
STATUS suc = UART_WriteChar(uart_no, (u8) * buffer++, timeout_us);
if (suc != OK) return suc;
}
return OK;
}

@ -0,0 +1,201 @@
/**
* Low level UART peripheral support functions
*/
/*
* File : uart.h
* Copyright (C) 2013 - 2016, Espressif Systems
* Copyright (C) 2016, Ondřej Hruška (cleaning, modif.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of version 3 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UART_APP_H
#define UART_APP_H
#include "uart_register.h"
#include "eagle_soc.h"
#include "c_types.h"
// ===========
// timeout for sending / receiving a char (default)
#define UART_TIMEOUT_US 5000
#define UART_TX_FULL_THRESH_VAL (UART_FIFO_LEN - 2) // if more than this many bytes in queue, don't write more
#define UART_TX_EMPTY_THRESH_VAL 16
// ===========
typedef enum {
UART0 = 0,
UART1 = 1
} UARTn;
typedef enum {
FIVE_BITS = 0x0,
SIX_BITS = 0x1,
SEVEN_BITS = 0x2,
EIGHT_BITS = 0x3
} UartBitsNum4Char;
typedef enum {
ONE_STOP_BIT = 0x1,
ONE_HALF_STOP_BIT = 0x2,
TWO_STOP_BIT = 0x3
} UartStopBitsNum;
typedef enum {
PARITY_NONE = 0x2,
PARITY_ODD = 1,
PARITY_EVEN = 0
} UartParityMode;
typedef enum {
PARITY_DIS = 0,
PARITY_EN = 1
} UartExistParity;
typedef enum {
UART_None_Inverse = 0x0,
UART_Rxd_Inverse = UART_RXD_INV,
UART_CTS_Inverse = UART_CTS_INV,
UART_Txd_Inverse = UART_TXD_INV,
UART_RTS_Inverse = UART_RTS_INV,
} UART_LineLevelInverse;
typedef enum {
BIT_RATE_300 = 300,
BIT_RATE_600 = 600,
BIT_RATE_1200 = 1200,
BIT_RATE_2400 = 2400,
BIT_RATE_4800 = 4800,
BIT_RATE_9600 = 9600,
BIT_RATE_19200 = 19200,
BIT_RATE_38400 = 38400,
BIT_RATE_57600 = 57600,
BIT_RATE_74880 = 74880,
BIT_RATE_115200 = 115200,
BIT_RATE_230400 = 230400,
BIT_RATE_460800 = 460800,
BIT_RATE_921600 = 921600,
BIT_RATE_1843200 = 1843200,
BIT_RATE_3686400 = 3686400,
} UartBautRate;
typedef enum {
NONE_CTRL,
HARDWARE_CTRL,
XON_XOFF_CTRL
} UartFlowCtrl;
typedef enum {
USART_HWFlow_None = 0x0,
USART_HWFlow_RTS = 0x1,
USART_HWFlow_CTS = 0x2,
USART_HWFlow_CTS_RTS = 0x3
} UART_HwFlowCtrl;
typedef enum {
EMPTY,
UNDER_WRITE,
WRITE_OVER
} RcvMsgBuffState;
typedef struct {
uint32 RcvBuffSize;
uint8 *pRcvMsgBuff;
uint8 *pWritePos;
uint8 *pReadPos;
uint8 TrigLvl; //JLU: may need to pad
RcvMsgBuffState BuffState;
} RcvMsgBuff;
typedef struct {
uint32 TrxBuffSize;
uint8 *pTrxBuff;
} TrxMsgBuff;
typedef enum {
BAUD_RATE_DET,
WAIT_SYNC_FRM,
SRCH_MSG_HEAD,
RCV_MSG_BODY,
RCV_ESC_CHAR,
} RcvMsgState;
typedef struct {
UartBautRate baut_rate;
UartBitsNum4Char data_bits;
UartExistParity exist_parity;
UartParityMode parity;
UartStopBitsNum stop_bits;
UartFlowCtrl flow_ctrl;
RcvMsgBuff rcv_buff;
TrxMsgBuff trx_buff;
RcvMsgState rcv_state;
int received;
int buff_uart_no; //indicate which uart use tx/rx buffer
} UartDevice;
// UartDev is defined and initialized in rom code.
extern UartDevice UartDev;
//==============================================
// FIFO used count
#define UART_TxQueLen(uart_no) ((READ_PERI_REG(UART_STATUS((uart_no))) >> UART_TXFIFO_CNT_S) & UART_TXFIFO_CNT)
#define UART_RxQueLen(uart_no) ((READ_PERI_REG(UART_STATUS((uart_no))) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT)
STATUS UART_WriteCharCRLF(UARTn uart_no, uint8 c, uint32 timeout_us);
STATUS UART_WriteChar(UARTn uart_no, uint8 c, uint32 timeout_us);
STATUS UART_WriteString(UARTn uart_no, const char *str, uint32 timeout_us);
STATUS UART_WriteBuffer(UARTn uart_no, const uint8 *buffer, size_t len, uint32 timeout_us);
//==============================================
void UART_SetWordLength(UARTn uart_no, UartBitsNum4Char len);
void UART_SetStopBits(UARTn uart_no, UartStopBitsNum bit_num);
void UART_SetLineInverse(UARTn uart_no, UART_LineLevelInverse inverse_mask);
void UART_SetParity(UARTn uart_no, UartParityMode Parity_mode);
void UART_SetBaudrate(UARTn uart_no, uint32 baud_rate);
void UART_SetFlowCtrl(UARTn uart_no, UART_HwFlowCtrl flow_ctrl, uint8 rx_thresh);
void UART_WaitTxFifoEmpty(UARTn uart_no , uint32 time_out_us); //do not use if tx flow control enabled
void UART_ResetFifo(UARTn uart_no);
void UART_ClearIntrStatus(UARTn uart_no, uint32 clr_mask);
void UART_SetIntrEna(UARTn uart_no, uint32 ena_mask);
void UART_SetPrintPort(UARTn uart_no);
bool UART_CheckOutputFinished(UARTn uart_no, uint32 time_out_us);
//==============================================
#endif

@ -0,0 +1,185 @@
//Stupid bit of code that does the bare minimum to make os_printf work.
/*
* ----------------------------------------------------------------------------
* "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 <esp8266.h>
#include "uart_driver.h"
#include "uart_handler.h"
// messy irq/task based UART handling below
static void uart0_rx_intr_handler(void *para);
static void uart_recvTask(os_event_t *events);
#define uart_recvTaskPrio 1
#define uart_recvTaskQueueLen 10
static os_event_t uart_recvTaskQueue[uart_recvTaskQueueLen];
/** Clear the fifos */
void ICACHE_FLASH_ATTR clear_rxtx(int uart_no)
{
SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
}
/**
* @brief Configure UART 115200-8-N-1
* @param uart_no
*/
static void ICACHE_FLASH_ATTR my_uart_init(UARTn uart_no, uint32 baud)
{
UART_SetParity(uart_no, PARITY_NONE);
UART_SetStopBits(uart_no, ONE_STOP_BIT);
UART_SetWordLength(uart_no, EIGHT_BITS);
UART_SetBaudrate(uart_no, baud);
UART_ResetFifo(uart_no);
}
/** Configure basic UART func and pins */
void ICACHE_FLASH_ATTR UART_Init(uint32_t baud0, uint32_t baud1)
{
// U0TXD
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
// U0RXD
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD);
// U1TXD (GPIO2)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
// Configure the UART peripherals
my_uart_init(UART0, baud0); // main
my_uart_init(UART1, baud1); // debug (output only)
}
/** Configure Rx on UART0 */
void ICACHE_FLASH_ATTR UART_SetupAsyncReceiver(void)
{
// Start the Rx reading task
system_os_task(uart_recvTask, uart_recvTaskPrio, uart_recvTaskQueue, uart_recvTaskQueueLen);
// set handler
ETS_UART_INTR_ATTACH((void *)uart0_rx_intr_handler, &(UartDev.rcv_buff)); // the buf will be used as an arg
// fifo threshold config
uint32_t conf = ((100 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S);
conf |= ((0x10 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S);
// timeout config
conf |= ((0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S); // timeout threshold
conf |= UART_RX_TOUT_EN; // enable timeout
WRITE_PERI_REG(UART_CONF1(UART0), conf);
// enable TOUT and ERR irqs
SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_RXFIFO_TOUT_INT_ENA | UART_FRM_ERR_INT_ENA);
/* clear interrupt flags */
WRITE_PERI_REG(UART_INT_CLR(UART0), 0xffff);
/* enable RX interrupts */
SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_OVF_INT_ENA);
// Enable IRQ in Extensa
ETS_UART_INTR_ENABLE();
}
// ---- async receive stuff ----
void uart_rx_intr_disable(uint8 uart_no)
{
CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA);
}
void uart_rx_intr_enable(uint8 uart_no)
{
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA);
}
/**
* @brief get number of bytes in UART tx fifo
* @param UART number
*/
#define UART_GetRxFifoCount(uart_no) ((READ_PERI_REG(UART_STATUS((uart_no))) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT)
void ICACHE_FLASH_ATTR UART_PollRx(void)
{
uint8 fifo_len = UART_GetRxFifoCount(UART0);
for (uint8 idx = 0; idx < fifo_len; idx++) {
uint8 d_tmp = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
UART_HandleRxByte(d_tmp);
}
}
static void ICACHE_FLASH_ATTR uart_recvTask(os_event_t *events)
{
if (events->sig == 0) {
UART_PollRx();
// clear irq flags
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR);
// enable rx irq again
uart_rx_intr_enable(UART0);
} else if (events->sig == 1) {
// ???
}
}
/******************************************************************************
* FunctionName : uart0_rx_intr_handler
* Description : Internal used function
* UART0 interrupt handler, add self handle code inside
* Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg
* Returns : NONE
*******************************************************************************/
static void
uart0_rx_intr_handler(void *para)
{
(void)para;
uint32_t status_reg = READ_PERI_REG(UART_INT_ST(UART0));
if (status_reg & UART_FRM_ERR_INT_ST) {
// Framing Error
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_FRM_ERR_INT_CLR);
}
if (status_reg & UART_RXFIFO_FULL_INT_ST) {
// RX fifo full
uart_rx_intr_disable(UART0);
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR);
// run handler
system_os_post(uart_recvTaskPrio, 0, 0); /* -> notify the polling thread */
}
if (status_reg & UART_RXFIFO_TOUT_INT_ST) {
// Fifo timeout
uart_rx_intr_disable(UART0);
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR);
// run handler
system_os_post(uart_recvTaskPrio, 0, 0); /* -> notify the polling thread */
}
if (status_reg & UART_TXFIFO_EMPTY_INT_ST) {
CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
}
if (status_reg & UART_RXFIFO_OVF_INT_ST) {
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_OVF_INT_CLR);
}
}

@ -0,0 +1,27 @@
/**
* UART init & async rx module.
*
* Call UART_Init(), UART_SetupAsyncReceiver() and
* define UART_HandleRxByte() somewhere in application code.
*
* Call UART_PollRx() to allow rx in a blocking handler.
*/
#ifndef UART_HANDLER_H
#define UART_HANDLER_H
#include <esp8266.h>
/** Configure basic UART func and pins */
void UART_Init(uint32_t baud0, uint32_t baud1);
/** Configure Rx on UART0 */
void UART_SetupAsyncReceiver(void);
/** User must provide this func for handling received bytes */
extern void UART_HandleRxByte(char c);
/** poll uart while waiting for something */
void UART_PollRx(void);
#endif

@ -7,84 +7,26 @@
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/* /**
This is example code for the esphttpd library. It's a small-ish demo showing off * This is the ESP8266 Remote Terminal project main file.
the server, including WiFi connection management capabilities, some IO and
some pictures of cats.
*/ */
#include <esp8266.h> #include <esp8266.h>
#include "httpd.h" #include <httpdespfs.h>
#include <cgiwebsocket.h>
#include <captdns.h>
#include <espfs.h>
#include <webpages-espfs.h>
#include "serial.h"
#include "io.h" #include "io.h"
#include "httpdespfs.h"
#include "cgi.h"
#include "cgiwifi.h"
#include "cgiflash.h"
#include "stdout.h"
#include "auth.h"
#include "espfs.h"
#include "captdns.h"
#include "webpages-espfs.h"
#include "cgiwebsocket.h"
#include "cgi-test.h"
//The example can print out the heap use every 3 seconds. You can use this to catch memory leaks.
//#define SHOW_HEAP_USE
//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) {
os_strcpy(user, "admin");
os_strcpy(pass, "s3cr3t");
return 1;
//Add more users this way. Check against incrementing no for each user added.
// } else if (no==1) {
// os_strcpy(user, "user1");
// os_strcpy(pass, "something");
// return 1;
}
return 0;
}
static ETSTimer websockTimer; #define FIRMWARE_VERSION "0.1"
//Broadcast the uptime in seconds every second over connected websockets #define SHOW_HEAP_USE 1
static void ICACHE_FLASH_ATTR websockTimerCb(void *arg) {
static int ctr=0;
char buff[128];
ctr++;
os_sprintf(buff, "Up for %d minutes %d seconds!\n", ctr/60, ctr%60);
cgiWebsockBroadcast("/websocket/ws.cgi", buff, os_strlen(buff), WEBSOCK_FLAG_NONE);
}
//On reception of a message, send "You sent: " plus whatever the other side sent
void myWebsocketRecv(Websock *ws, char *data, int len, int flags) {
int i;
char buff[128];
os_sprintf(buff, "You sent: ");
for (i=0; i<len; i++) buff[i+10]=data[i];
buff[i+10]=0;
cgiWebsocketSend(ws, buff, os_strlen(buff), WEBSOCK_FLAG_NONE);
}
//Websocket connected. Install reception handler and send welcome message.
void myWebsocketConnect(Websock *ws) { void myWebsocketConnect(Websock *ws) {
ws->recvCb=myWebsocketRecv; // NOOP
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) {
os_printf("EchoWs: echo, len=%d\n", len);
cgiWebsocketSend(ws, data, len, flags);
}
//Echo websocket connected. Install reception handler.
void myEchoWebsocketConnect(Websock *ws) {
os_printf("EchoWs: connect\n");
ws->recvCb=myEchoWebsocketRecv;
} }
@ -108,47 +50,14 @@ CgiUploadFlashDef uploadParams={
#define INCLUDE_FLASH_FNS #define INCLUDE_FLASH_FNS
#endif #endif
/* /** Routes */
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[]={ HttpdBuiltInUrl builtInUrls[]={
ROUTE_CGI_ARG("*", cgiRedirectApClientToHostname, "esp8266.nonet"), // redirect func for the captive portal // redirect func for the captive portal
ROUTE_REDIRECT("/", "/index.tpl"), ROUTE_CGI_ARG("*", cgiRedirectApClientToHostname, "esp8266.nonet"),
ROUTE_TPL("/led.tpl", tplLed),
ROUTE_TPL("/index.tpl", tplCounter),
ROUTE_CGI("/led.cgi", cgiLed),
#ifdef INCLUDE_FLASH_FNS
ROUTE_CGI_ARG("/flash/next", cgiGetFirmwareNext, &uploadParams),
ROUTE_CGI_ARG("/flash/upload", cgiUploadFirmware, &uploadParams),
#endif
ROUTE_CGI("/flash/reboot", cgiRebootFirmware),
//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.
// ROUTE_AUTH("/wifi/*", myPassFn),
ROUTE_REDIRECT("/wifi", "/wifi/wifi.tpl"),
ROUTE_REDIRECT("/wifi/", "/wifi/wifi.tpl"),
ROUTE_CGI("/wifi/wifiscan.cgi", cgiWiFiScan),
ROUTE_TPL("/wifi/wifi.tpl", tplWlan),
ROUTE_CGI("/wifi/connect.cgi", cgiWiFiConnect),
ROUTE_CGI("/wifi/connstatus.cgi", cgiWiFiConnStatus),
ROUTE_CGI("/wifi/setmode.cgi", cgiWiFiSetMode),
ROUTE_WS("/websocket/ws.cgi", myWebsocketConnect), ROUTE_WS("/ws/update.cgi", myWebsocketConnect),
ROUTE_WS("/websocket/echo.cgi", myEchoWebsocketConnect),
ROUTE_REDIRECT("/test", "/test/index.html"), // TODO add funcs for WiFi management (when web UI is added)
ROUTE_REDIRECT("/test/", "/test/index.html"),
ROUTE_CGI("/test/test.cgi", cgiTestbed),
ROUTE_FILESYSTEM(), ROUTE_FILESYSTEM(),
ROUTE_END(), ROUTE_END(),
@ -159,15 +68,28 @@ HttpdBuiltInUrl builtInUrls[]={
static ETSTimer prHeapTimer; static ETSTimer prHeapTimer;
static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg) { static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg) {
static int led = 0;
os_printf("Heap: %ld\n", (unsigned long)system_get_free_heap_size()); os_printf("Heap: %ld\n", (unsigned long)system_get_free_heap_size());
cgiWebsockBroadcast("/ws/update.cgi", "HELLO", 5, WEBSOCK_FLAG_NONE);
ioLed(led);
led = !led;
} }
#endif #endif
//Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done. //Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done.
void user_init(void) { void user_init(void) {
stdoutInit(); serialInit();
ioInit();
banner("ESP8266 Remote Terminal");
banner_info("Version "FIRMWARE_VERSION", built "__DATE__" at "__TIME__);
dbg("!!! TODO (c) and GitHub link here !!!");
//stdoutInit();
captdnsInit(); captdnsInit();
ioInit();
// 0x40200000 is the base address for spi flash memory mapping, ESPFS_POS is the position // 0x40200000 is the base address for spi flash memory mapping, ESPFS_POS is the position
// where image is written in flash that is defined in Makefile. // where image is written in flash that is defined in Makefile.
@ -176,18 +98,30 @@ void user_init(void) {
#else #else
espFsInit((void*)(webpages_espfs_start)); espFsInit((void*)(webpages_espfs_start));
#endif #endif
httpdInit(builtInUrls, 80); httpdInit(builtInUrls, 80);
#ifdef SHOW_HEAP_USE #ifdef SHOW_HEAP_USE
os_timer_disarm(&prHeapTimer); os_timer_disarm(&prHeapTimer);
os_timer_setfn(&prHeapTimer, prHeapTimerCb, NULL); os_timer_setfn(&prHeapTimer, prHeapTimerCb, NULL);
os_timer_arm(&prHeapTimer, 3000, 1); os_timer_arm(&prHeapTimer, 3000, 1);
#endif #endif
os_timer_disarm(&websockTimer);
os_timer_setfn(&websockTimer, websockTimerCb, NULL); info("System ready!");
os_timer_arm(&websockTimer, 1000, 1);
os_printf("\nReady\n");
} }
// ---- unused funcs removed from sdk to save space ---
void user_rf_pre_init() { void user_rf_pre_init() {
//Not needed, but some SDK versions want this defined. //Not needed, but some SDK versions want this defined.
} }
// вызывается из phy_chip_v6.o
void ICACHE_FLASH_ATTR chip_v6_set_sense(void) {
// ret.n
}
// вызывается из phy_chip_v6.o
int ICACHE_FLASH_ATTR chip_v6_unset_chanfreq(void) {
return 0;
}
Loading…
Cancel
Save