parent
be3c0fe926
commit
aaec5323cd
@ -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 |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 34 KiB |
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> |
|
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 |
|
@ -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 |
Loading…
Reference in new issue