finished UI refactoring to ajax

pull/25/head
Thorsten von Eicken 9 years ago
parent b99aea9d50
commit d29fa0423f
  1. 15
      html/console.js
  2. 2
      html/console.tpl
  3. 22
      html/log.tpl
  4. 6
      html/style.css
  5. 43
      html/ui.js
  6. 147
      html/wifi/wifi.tpl
  7. 6
      httpd/auth.c
  8. 32
      httpd/httpd.c
  9. 3
      httpd/httpd.h
  10. 58
      httpd/httpdespfs.c
  11. 4
      include/espmissingincludes.h
  12. 183
      user/cgiwifi.c
  13. 19
      user/log.c
  14. 4
      user/user_main.c

@ -1,11 +1,16 @@
function fetchText(delay) {
function fetchText(delay, repeat) {
el = $("#console");
if (el.textEnd == undefined) {
el.textEnd = 0;
el.innerHTML = "";
}
window.setTimeout(function() {
ajaxJson('GET', console_url + "?start=" + el.textEnd, updateText, retryLoad);
ajaxJson('GET', console_url + "?start=" + el.textEnd,
function(resp) {
var dly = updateText(resp);
if (repeat) fetchText(dly, repeat);
},
function() { retryLoad(repeat); });
}, delay);
}
@ -22,9 +27,9 @@ function updateText(resp) {
el.textEnd = resp.start + resp.len;
delay = 500;
}
fetchText(delay);
return delay;
}
function retryLoad() {
fetchText(1000);
function retryLoad(repeat) {
fetchText(1000, repeat);
}

@ -34,7 +34,7 @@
}
window.onload = function() {
fetchText(100);
fetchText(100, true);
$("#reset-button").addEventListener("click", function(e) {
e.preventDefault();

@ -4,9 +4,18 @@
</div>
<div class="content">
<p>The debug log shows the 1024 last characters printed by the esp-link software itself to
its own debug log.</p>
<pre id="console" class="console"></pre>
<div class="pure-g">
<div class="pure-u-1-5">
<p style="padding-top: 0.4em;">
<a id="refresh-button" class="pure-button button-primary" href="#">Refresh</a>
</p>
</div>
<p class="pure-u-4-5">
The debug log shows the 1024 last characters printed by the esp-link software itself to
its own debug log.
</p>
</div>
<pre id="console" class="console" style="margin-top: 0px;"></pre>
</div>
</div>
</div>
@ -16,7 +25,12 @@
<script src="console.js"></script>
<script type="text/javascript">
window.onload = function() {
fetchText(100);
fetchText(100, false);
$("#refresh-button").addEventListener("click", function(e) {
e.preventDefault();
fetchText(100, false);
});
}
</script>
</body></html>

@ -296,6 +296,12 @@ pre.console a {
border-top: 10px solid rgba(204, 51, 0, 0.8);
border-radius: 100%;
}
.spinner-small {
display: inline-block;
height: 1em;
width: 1em;
border-width: 4px;
}
@-webkit-keyframes rotation {
from {

@ -1,6 +1,5 @@
// fill out menu items
(function() {
console.log("Filling out menu with", menu.length, "items");
html = "";
for (var i=0; i<menu.length; i+=2) {
html = html.concat(" <li class=\"pure-menu-item\"><a href=\"" + menu[i+1] +
@ -52,14 +51,19 @@ function showWarning(text) {
el.innerHTML = text;
el.removeAttribute('hidden');
}
function hideWarning(text) {
function hideWarning() {
el = $("#warning").setAttribute('hidden', '');
}
var notifTimeout = null;
function showNotification(text) {
var el = $("#notification");
el.innerHTML = text;
el.removeAttribute('hidden');
setTimeout(function() { el.setAttribute('hidden', ''); }, 4000);
if (notifTimeout != null) clearTimeout(notifTimeout);
notifTimout = setTimeout(function() {
el.setAttribute('hidden', '');
notifTimout = null;
}, 4000);
}
function ajaxReq(method, url, ok_cb, err_cb) {
@ -67,39 +71,58 @@ function ajaxReq(method, url, ok_cb, err_cb) {
xhr.open(method, url);
var timeout = setTimeout(function() {
xhr.abort();
console.log("XHR abort:", method, url);
err_cb(599, "Request timeout");
}, 20000);
}, 9000);
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) { return; }
clearTimeout(timeout);
if (xhr.status >= 200 && xhr.status < 300) {
console.log("XHR done:", method, url, "->", xhr.status);
ok_cb(xhr.responseText);
} else {
err_cb(xhr.status, xhr.statusText);
console.log("XHR ERR :", method, url, "->", xhr.status, xhr.responseText);
err_cb(xhr.status, xhr.responseText);
}
}
xhr.send();
console.log("XHR send:", method, url);
try {
xhr.send();
} catch(err) {
console.log("XHR EXC :", method, url, "->", err);
err_cb(599, err);
}
}
function dispatchJson(resp, ok_cb, err_cb) {
var j;
try { j = JSON.parse(resp); }
catch(err) {
console.log("JSON parse error: " + err + ". In: " + resp);
err_cb(500, "JSON parse error: " + err);
return;
}
ok_cb(j);
}
function ajaxJson(method, url, ok_cb, err_cb) {
ajaxReq(method, url, function(resp) { ok_cb(JSON.parse(resp)); }, err_cb);
ajaxReq(method, url, function(resp) { dispatchJson(resp, ok_cb, err_cb); }, err_cb);
}
function ajaxSpin(method, url, ok_cb, err_cb) {
$("#spinner").removeAttribute('hidden');
console.log("starting spinner");
ajaxReq(method, url, function(resp) {
$("#spinner").setAttribute('hidden', '');
ok_cb(resp);
}, function(status, statusText) {
$("#spinner").setAttribute('hidden', '');
showWarning("Request error: " + statusText);
showWarning("Error: " + statusText);
err_cb(status, statusText);
});
}
function ajaxJsonSpin(method, url, ok_cb, err_cb) {
ajaxSpin(method, url, function(resp) { ok_cb(JSON.parse(resp)); }, err_cb);
ajaxSpin(method, url, function(resp) { dispatchJson(resp, ok_cb, err_cb); }, err_cb);
}

@ -6,23 +6,27 @@
<div class="content pure-g">
<div class="pure-u-12-24"><div class="card">
<h1>Wifi State</h2>
<table class="pure-table pure-table-horizontal"><tbody>
<div id="wifi-spinner" class="spinner spinner-small"></div>
<table id="wifi-table" class="pure-table pure-table-horizontal" hidden><tbody>
<tr><td>WiFi mode</td><td id="wifi-mode"></td></tr>
<tr><td>Configured network</td><td id="wifi-ssid"></td></tr>
<tr><td>Wifi status</td><td id="wifi-status"></td></tr>
<tr><td>Wifi address</td><td id="wifi-ip"></td></tr>
<tr><td>Wifi rssi</td><td id="wifi-rssi"></td></tr>
<tr><td>Wifi phy</td><td id="wifi-phy"></td></tr>
<tr><td>Wifi MAC</td><td id="wifi-mac"></td></tr>
<tr><td colspan="2" id="wifi-warn"></td></tr>
</tbody> </table>
</div></div>
<div class="pure-u-12-24"><div class="card">
<h1>Wifi Association</h2>
<p id="reconnect" style="color: #600" hidden></p>
<form action="#" id="wifiform" class="pure-form pure-form-stacked">
<!--form name="wifiform" action="connect.cgi" method="post"-->
<legend>To connect to a WiFi network, please select one of the detected networks,
enter the password, and hit the connect button...</legend>
<label>Network SSID</label>
<div id="aps">Scanning...</div>
<div id="aps">Scanning... <div class="spinner spinner-small"></div></div>
<label>WiFi password, if applicable:</label>
<input id="wifi-passwd" type="text" name="passwd" placeholder="password">
<button id="connect-button" type="submit" class="pure-button button-primary">Connect!</button>
@ -83,95 +87,128 @@ function getSelectedEssid() {
return currAp;
}
var scan_xhr = j();
function scanAPs() {
scan_xhr.open("GET", "wifiscan");
scan_xhr.onreadystatechange = function() {
if (scan_xhr.readyState == 4 && scan_xhr.status >= 200 && scan_xhr.status < 300) {
var data = JSON.parse(scan_xhr.responseText);
var scanTimeout = null;
function scanResult() {
ajaxJson('GET', "scan", function(data) {
currAp = getSelectedEssid();
if (data.result.inProgress == "0" && data.result.APs.length > 1) {
$("#aps").innerHTML = "";
var n = 0;
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]));
n = n+1;
}
//window.setTimeout(scanAPs, 10000);
showNotification("Scan found " + n + " networks");
var cb = $("#connect-button");
cb.className = cb.className.replace(" pure-button-disabled", "");
if (scanTimeout != null) clearTimeout(scanTimeout);
scanTimeout = window.setTimeout(scanAPs, 20000);
} else {
window.setTimeout(scanAPs, 1000);
window.setTimeout(scanResult, 1000);
}
}
}
scan_xhr.send();
}, function(s, st) {
window.setTimeout(scanResult, 5000);
});
}
function scanAPs() {
scanTimeout = null;
ajaxSpin('POST', "scan", function(data) {
showNotification("Wifi scan started");
window.setTimeout(scanResult, 1000);
}, function(s, st) {
showNotification("Wifi scan may have started?");
window.setTimeout(scanResult, 1000);
});
}
function showWifiInfo(data) {
Object.keys(data).forEach(function(v) {
el = $("#wifi-" + v);
if (el != null) el.innerHTML = data[v];
});
$("#wifi-spinner").setAttribute("hidden", "");
$("#wifi-table").removeAttribute("hidden");
currAp = data.ssid;
}
function getWifiInfo() {
var xhr = j();
xhr.open("GET", "info");
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) { return; }
if (xhr.status >= 200 && xhr.status < 300) {
var data = JSON.parse(xhr.responseText);
Object.keys(data).forEach(function(v) {
el = document.getElementById("wifi-" + v);
if (el != null) el.innerHTML = data[v];
});
currAp = data.ssid;
} else {
window.setTimeout(getWifiInfo, 1000);
}
}
xhr.send();
ajaxJson('GET', "info", showWifiInfo,
function(s, st) { window.setTimeout(getWifiInfo, 1000); });
}
function getStatus() {
var xhr = j();
xhr.open("GET", "connstatus");
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) { return; }
if (xhr.status >= 200 && xhr.status < 300) {
var data = JSON.parse(xhr.responseText);
ajaxJsonSpin("GET", "connstatus", function(data) {
if (data.status == "idle" || data.status == "connecting") {
$("#aps").innerHTML = "Connecting...";
showNotification("Connecting...");
window.setTimeout(getStatus, 1000);
} else if (data.status == "got IP address") {
$("#aps").innerHTML="Connected! Got IP "+data.ip+ ".<br/>" +
"If you're in the same network, you can access it <a href=\"http://"+data.ip+
"/\">here</a>.<br/>ESP Link will switch to STA-only mode in a few seconds.";
var txt = "Connected! Got IP "+data.ip;
showNotification(txt);
showWifiInfo(data);
var txt2 = "ESP Link will switch to STA-only mode in a few seconds";
window.setTimeout(function() { showNotification(txt2); }, 4000);
$("#reconnect").removeAttribute("hidden");
$("#reconnect").innerHTML =
"If you are in the same network, go to <a href=\"http://"+data.ip+
"/\">"+data.ip+"</a>, else connect to network "+data.ssid+" first.";
} else {
$("#aps").innerHTML="Oops: " + data.status + ". Reason: " + data.reason +
"<br/>Check password and selected AP.<br/><a href=\"wifi.tpl\">Go Back</a>";
showWarning("Connection failed: " + data.status + ", " + data.reason);
$("#aps").innerHTML =
"Check password and selected AP. <a href=\"wifi.tpl\">Go Back</a>";
}
} else {
}, function(s, st) {
//showWarning("Can't get status: " + st);
window.setTimeout(getStatus, 2000);
}
}
xhr.send();
});
}
function changeWifiMode(m) {
hideWarning();
ajaxSpin("POST", "setmode?mode=" + m, function(resp) {
showNotification("Mode changed");
window.setTimeout(getWifiInfo, 100);
}, function(s, st) {
showWarning("Error changing mode: " + st);
window.setTimeout(getWifiInfo, 100);
});
}
function changeWifiAp(e) {
e.preventDefault();
var xhr = j();
var passwd = $("#wifi-passwd").value;
var essid = getSelectedEssid();
console.log("Posting form", "essid=" + essid, "pwd="+passwd);
xhr.open("POST", "connect");
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) { return; }
if (xhr.status >= 200 && xhr.status < 300) {
showNotification("Connecting to " + essid);
var url = "connect?essid="+encodeURIComponent(essid)+"&passwd="+encodeURIComponent(passwd);
hideWarning();
$("#reconnect").setAttribute("hidden", "");
$("#wifi-passwd").value = "";
var cb = $("#connect-button");
var cn = cb.className;
cb.className += ' pure-button-disabled';
ajaxSpin("POST", url, function(resp) {
$("#spinner").removeAttribute('hidden'); // hack
showNotification("Waiting for network change...");
window.scrollTo(0, 0);
window.setTimeout(getStatus, 2000);
} else {
}, function(s, st) {
showWarning("Error switching network: "+st);
cb.className = cn;
window.setTimeout(scanAPs, 1000);
}
}
xhr.setRequestHeader("Content-type", "application/x-form-urlencoded");
xhr.send("essid="+encodeURIComponent(essid)+"&passwd="+encodeURIComponent(passwd));
});
}
window.onload=function(e) {
getWifiInfo();
$("#wifiform").onsubmit = changeWifiAp;
window.setTimeout(scanAPs, 500);
scanTimeout = window.setTimeout(scanAPs, 500);
};
</script>
</body></html>

@ -5,9 +5,9 @@ HTTP auth implementation. Only does basic authentication for now.
/*
* ----------------------------------------------------------------------------
* "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.
* 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.
* ----------------------------------------------------------------------------
*/

@ -93,6 +93,10 @@ static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(void *arg) {
//Retires a connection for re-use
static void ICACHE_FLASH_ATTR httpdRetireConn(HttpdConnData *conn) {
uint32 dt = conn->startTime;
if (dt > 0) dt = (system_get_time() - dt)/1000;
os_printf("Closed %p, took %ums, heap=%ld\n", conn->conn, dt,
(unsigned long)system_get_free_heap_size());
if (conn->post->buff!=NULL) os_free(conn->post->buff);
conn->post->buff=NULL;
conn->cgi=NULL;
@ -192,7 +196,8 @@ int ICACHE_FLASH_ATTR httpdGetHeader(HttpdConnData *conn, char *header, char *re
void ICACHE_FLASH_ATTR httpdStartResponse(HttpdConnData *conn, int code) {
char buff[128];
int l;
l=os_sprintf(buff, "HTTP/1.0 %d OK\r\nServer: esp8266-httpd/"HTTPDVER"\r\nConnection: close\r\n", code);
char *status = code < 400 ? "OK" : "ERROR";
l = os_sprintf(buff, "HTTP/1.0 %d %s\r\nServer: esp-link\r\nConnection: close\r\n", code, status);
httpdSend(conn, buff, l);
}
@ -215,7 +220,7 @@ void ICACHE_FLASH_ATTR httpdEndHeaders(HttpdConnData *conn) {
void ICACHE_FLASH_ATTR httpdRedirect(HttpdConnData *conn, char *newUrl) {
char buff[1024];
int l;
l=os_sprintf(buff, "HTTP/1.0 302 Found\r\nServer: esp8266-httpd/"HTTPDVER"\r\nConnection: close\r\nLocation: %s\r\n\r\nRedirecting to %s\r\n", newUrl, newUrl);
l=os_sprintf(buff, "HTTP/1.0 302 Found\r\nServer: esp8266-link\r\nConnection: close\r\nLocation: %s\r\n\r\nRedirecting to %s\r\n", newUrl, newUrl);
httpdSend(conn, buff, l);
}
@ -372,7 +377,12 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
if (e==NULL) return; //wtf?
*e=0; //terminate url part
os_printf("%s %s\n", HTTPD_METHOD_GET?"GET":"POST", conn->url);
os_printf("%s %s (%p) %d.%d.%d.%d:%d\n",
conn->requestType == HTTPD_METHOD_GET ? "GET" : "POST",
conn->url, conn->conn,
conn->conn->proto.tcp->remote_ip[0], conn->conn->proto.tcp->remote_ip[1],
conn->conn->proto.tcp->remote_ip[2], conn->conn->proto.tcp->remote_ip[3],
conn->conn->proto.tcp->remote_port);
//Parse out the URL part before the GET parameters.
conn->getArgs=(char*)os_strstr(conn->url, "?");
if (conn->getArgs!=0) {
@ -471,13 +481,6 @@ static void ICACHE_FLASH_ATTR httpdRecvCb(void *arg, char *data, unsigned short
}
}
static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) {
HttpdConnData *conn=httpdFindConnData(arg);
os_printf("ReconCb\n");
if (conn==NULL) return;
//Yeah... No idea what to do here. ToDo: figure something out.
}
static void ICACHE_FLASH_ATTR httpdDisconCb(void *arg) {
//The esp sdk passes through wrong arg here, namely the one of the *listening* socket.
//That is why we can't use (HttpdConnData)arg->sock here.
@ -490,7 +493,6 @@ static void ICACHE_FLASH_ATTR httpdDisconCb(void *arg) {
//is then used for something else, and we can use that to capture *most* of the
//disconnect cases.
if (connData[i].conn->state==ESPCONN_NONE || connData[i].conn->state>=ESPCONN_CLOSE) {
connData[i].conn=NULL;
if (connData[i].cgi!=NULL) connData[i].cgi(&connData[i]); //flush cgi data
httpdRetireConn(&connData[i]);
}
@ -498,6 +500,13 @@ static void ICACHE_FLASH_ATTR httpdDisconCb(void *arg) {
}
}
// Callback indicating a failure in the connection. "Recon" is probably intended in the sense
// of "you need to reconnect". Sigh...
static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) {
os_printf("Connection %p died, err=%d\n", arg, err);
httpdDisconCb(arg); // no different from close...
}
static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) {
struct espconn *conn=arg;
@ -518,6 +527,7 @@ static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) {
connData[i].post->buffLen=0;
connData[i].post->received=0;
connData[i].post->len=-1;
connData[i].startTime = system_get_time();
espconn_regist_recvcb(conn, httpdRecvCb);
espconn_regist_reconcb(conn, httpdReconCb);

@ -21,6 +21,7 @@ typedef int (* cgiSendCallback)(HttpdConnData *connData);
//A struct describing a http connection. This gets passed to cgi functions.
struct HttpdConnData {
struct espconn *conn;
uint32 startTime;
char requestType;
char *url;
char *getArgs;
@ -62,4 +63,4 @@ void ICACHE_FLASH_ATTR httpdEndHeaders(HttpdConnData *conn);
int ICACHE_FLASH_ATTR httpdGetHeader(HttpdConnData *conn, char *header, char *ret, int retLen);
int ICACHE_FLASH_ATTR httpdSend(HttpdConnData *conn, const char *data, int len);
#endif
#endif

@ -108,34 +108,40 @@ int ICACHE_FLASH_ATTR cgiEspFsHtml(HttpdConnData *connData) {
os_strcpy(buff, "Header file 'head.tpl' not found\n");
os_printf(buff);
status = 500;
} else {
// read file and return it
int len = espFsRead(file, buff, sizeof(buff));
if (len == sizeof(buff)) {
os_strcpy(buff, "Header file 'head.tpl' too large!\n");
os_printf(buff);
status = 500;
}
// open the real file for next time around
file = espFsOpen(connData->url);
if (file == NULL) {
os_strcpy(buff, connData->url);
os_strcat(buff, " not found\n");
os_printf(buff);
status = 404;
} else {
connData->cgiData = file;
httpdStartResponse(connData, 200);
httpdHeader(connData, "Content-Type", "text/html; charset=UTF-8");
httpdEndHeaders(connData);
httpdSend(connData, buff, len);
printGlobalJSON(connData);
return HTTPD_CGI_MORE;
}
goto error;
}
// error response
// read file and return it
int len = espFsRead(file, buff, sizeof(buff));
espFsClose(file);
if (len == sizeof(buff)) {
os_sprintf(buff, "Header file 'head.tpl' too large (%d>%d)!\n", len, sizeof(buff));
os_printf(buff);
status = 500;
goto error;
}
// before returning, open the real file for next time around
file = espFsOpen(connData->url);
if (file == NULL) {
os_strcpy(buff, connData->url);
os_strcat(buff, " not found\n");
os_printf(buff);
status = 404;
goto error;
}
connData->cgiData = file;
httpdStartResponse(connData, status);
httpdHeader(connData, "Content-Type", "text/html; charset=UTF-8");
httpdEndHeaders(connData);
httpdSend(connData, buff, len);
printGlobalJSON(connData);
return HTTPD_CGI_MORE;
error: // error response
httpdStartResponse(connData, status);
httpdHeader(connData, "text/plain", "text/html; charset=UTF-8");
httpdHeader(connData, "Content-Type", "text/html; charset=UTF-8");
httpdEndHeaders(connData);
httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE;

@ -6,9 +6,11 @@
#include <ets_sys.h>
//Missing function prototypes in include folders. Gcc will warn on these if we don't define 'em anywhere.
//MOST OF THESE ARE GUESSED! but they seem to swork and shut up the compiler.
//MOST OF THESE ARE GUESSED! but they seem to work and shut up the compiler.
typedef struct espconn espconn;
bool wifi_station_set_hostname(char *);
int atoi(const char *nptr);
void ets_install_putc1(void *routine); // necessary for #define os_xxx -> ets_xxx

@ -159,59 +159,56 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) {
cgiWifiAps.scanInProgress=0;
}
//Routine to start a WiFi access point scan.
static void ICACHE_FLASH_ATTR wifiStartScan() {
// int x;
if (cgiWifiAps.scanInProgress) return;
cgiWifiAps.scanInProgress=1;
static ETSTimer scanTimer;
static void ICACHE_FLASH_ATTR scanStartCb(void *arg) {
os_printf("Starting a scan\n");
wifi_station_scan(NULL, wifiScanDoneCb);
}
//This CGI is called from the bit of AJAX-code in wifi.tpl. It will initiate a
//scan for access points and if available will return the result of an earlier scan.
//The result is embedded in a bit of JSON parsed by the javascript in wifi.tpl.
int ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) {
int pos=(int)connData->cgiData;
int len;
char buff[1024];
if (!cgiWifiAps.scanInProgress && pos!=0) {
//Fill in json code for an access point
if (pos-1<cgiWifiAps.noAps) {
len=os_sprintf(buff, "{\"essid\": \"%s\", \"rssi\": %d, \"enc\": \"%d\"}%s\n",
cgiWifiAps.apData[pos-1]->ssid, cgiWifiAps.apData[pos-1]->rssi,
cgiWifiAps.apData[pos-1]->enc, (pos-1==cgiWifiAps.noAps-1)?"":",");
httpdSend(connData, buff, len);
}
pos++;
if ((pos-1)>=cgiWifiAps.noAps) {
len=os_sprintf(buff, "]\n}\n}\n");
httpdSend(connData, buff, len);
//Also start a new scan.
wifiStartScan();
return HTTPD_CGI_DONE;
} else {
connData->cgiData=(void*)pos;
return HTTPD_CGI_MORE;
}
static int ICACHE_FLASH_ATTR cgiWiFiStartScan(HttpdConnData *connData) {
jsonHeader(connData, 200);
if (!cgiWifiAps.scanInProgress) {
cgiWifiAps.scanInProgress = 1;
os_timer_disarm(&scanTimer);
os_timer_setfn(&scanTimer, scanStartCb, NULL);
os_timer_arm(&scanTimer, 1000, 0);
}
return HTTPD_CGI_DONE;
}
httpdStartResponse(connData, 200);
httpdHeader(connData, "Content-Type", "text/json");
httpdEndHeaders(connData);
static int ICACHE_FLASH_ATTR cgiWiFiGetScan(HttpdConnData *connData) {
char buff[2048];
int len;
jsonHeader(connData, 200);
if (cgiWifiAps.scanInProgress==1) {
//We're still scanning. Tell Javascript code that.
len=os_sprintf(buff, "{\n \"result\": { \n\"inProgress\": \"1\"\n }\n}\n");
len = os_sprintf(buff, "{\n \"result\": { \n\"inProgress\": \"1\"\n }\n}\n");
httpdSend(connData, buff, len);
return HTTPD_CGI_DONE;
}
len = os_sprintf(buff, "{\"result\": {\"inProgress\": \"0\", \"APs\": [\n");
for (int pos=0; pos<cgiWifiAps.noAps; pos++) {
len += os_sprintf(buff+len, "{\"essid\": \"%s\", \"rssi\": %d, \"enc\": \"%d\"}%s\n",
cgiWifiAps.apData[pos]->ssid, cgiWifiAps.apData[pos]->rssi,
cgiWifiAps.apData[pos]->enc, (pos==cgiWifiAps.noAps-1)?"":",");
}
len += os_sprintf(buff+len, "]}}\n");
//os_printf("Sending %d bytes: %s\n", len, buff);
httpdSend(connData, buff, len);
return HTTPD_CGI_DONE;
}
int ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) {
if (connData->requestType == HTTPD_METHOD_GET) {
return cgiWiFiGetScan(connData);
} else if (connData->requestType == HTTPD_METHOD_POST) {
return cgiWiFiStartScan(connData);
} else {
//We have a scan result. Pass it on.
len=os_sprintf(buff, "{\n \"result\": { \n\"inProgress\": \"0\", \n\"APs\": [\n");
httpdSend(connData, buff, len);
if (cgiWifiAps.apData==NULL) cgiWifiAps.noAps=0;
connData->cgiData=(void *)1;
return HTTPD_CGI_MORE;
jsonHeader(connData, 404);
return HTTPD_CGI_DONE;
}
}
@ -295,10 +292,10 @@ int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) {
return HTTPD_CGI_DONE;
}
int el = httpdFindArg(connData->post->buff, "essid", essid, sizeof(essid));
int pl = httpdFindArg(connData->post->buff, "passwd", passwd, sizeof(passwd));
int el = httpdFindArg(connData->getArgs, "essid", essid, sizeof(essid));
int pl = httpdFindArg(connData->getArgs, "passwd", passwd, sizeof(passwd));
if (el > 0 && pl > 0) {
if (el > 0 && pl >= 0) {
//Set to 0 if you want to disable the actual reconnecting bit
#ifndef DEMO_MODE
os_strncpy((char*)stconf.ssid, essid, 32);
@ -313,6 +310,7 @@ int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) {
jsonHeader(connData, 200);
} else {
jsonHeader(connData, 400);
httpdSend(connData, "Cannot parse ssid or password", -1);
}
return HTTPD_CGI_DONE;
}
@ -323,7 +321,7 @@ int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) {
char buff[1024];
if (connData->conn==NULL) {
//Connection aborted. Clean up.
// Connection aborted. Clean up.
return HTTPD_CGI_DONE;
}
@ -348,29 +346,72 @@ int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) {
return HTTPD_CGI_DONE;
}
char *connStatuses[] = { "idle", "connecting", "wrong password", "AP not found",
static char *connStatuses[] = { "idle", "connecting", "wrong password", "AP not found",
"failed", "got IP address" };
static char *wifiWarn[] = { 0,
"Switch to <a href=\\\"#\\\" onclick=\\\"changeWifiMode(3)\\\">STA+AP mode</a>",
"<b>Can't scan in this mode!</b> Switch to <a href=\\\"#\\\" onclick=\\\"changeWifiMode(3)\\\">STA+AP mode</a>",
"Switch to <a href=\\\"#\\\" onclick=\\\"changeWifiMode(1)\\\">STA mode</a>",
};
// print various Wifi information into json buffer
int ICACHE_FLASH_ATTR printWifiInfo(char *buff) {
int len;
struct station_config stconf;
wifi_station_get_config(&stconf);
uint8_t op = wifi_get_opmode() & 0x3;
char *mode = wifiMode[op];
char *status = "unknown";
int st = wifi_station_get_connect_status();
if (st > 0 && st < sizeof(connStatuses)) status = connStatuses[st];
int p = wifi_get_phy_mode();
char *phy = wifiPhy[p&3];
char *warn = wifiWarn[op];
sint8 rssi = wifi_station_get_rssi();
if (rssi > 0) rssi = 0;
uint8 mac_addr[6];
wifi_get_macaddr(0, mac_addr);
len = os_sprintf(buff,
"\"mode\": \"%s\", \"ssid\": \"%s\", \"status\": \"%s\", \"phy\": \"%s\", "
"\"rssi\": \"%ddB\", \"warn\": \"%s\", \"passwd\": \"%s\", "
"\"mac\":\"%02x:%02x:%02x:%02x:%02x:%02x\"",
mode, (char*)stconf.ssid, status, phy, rssi, warn, (char*)stconf.password,
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
struct ip_info info;
if (wifi_get_ip_info(0, &info)) {
len += os_sprintf(buff+len, ", \"ip\": \"%d.%d.%d.%d\"",
(info.ip.addr>>0)&0xff, (info.ip.addr>>8)&0xff,
(info.ip.addr>>16)&0xff, (info.ip.addr>>24)&0xff);
} else {
len += os_sprintf(buff+len, ", \"ip\": \"-none-\"");
}
return len;
}
int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) {
char buff[1024];
int len;
struct ip_info info;
int st=wifi_station_get_connect_status();
jsonHeader(connData, 200);
len = os_sprintf(buff, "{\"status\": \"%s\"",
len = os_sprintf(buff, "{\"status\": \"%s\", ",
st > 0 && st < sizeof(connStatuses) ? connStatuses[st] : "unknown");
len += printWifiInfo(buff+len);
len += os_sprintf(buff+len, ", ");
if (wifiReason != 0) {
len += os_sprintf(buff+len, ", \"reason\": \"%s\"", wifiGetReason());
len += os_sprintf(buff+len, "\"reason\": \"%s\", ", wifiGetReason());
}
if (st == STATION_GOT_IP) {
wifi_get_ip_info(0, &info);
len+=os_sprintf(buff+len, ", \"ip\": \"%d.%d.%d.%d\"",
(info.ip.addr>>0)&0xff, (info.ip.addr>>8)&0xff,
(info.ip.addr>>16)&0xff, (info.ip.addr>>24)&0xff);
if (wifi_get_opmode() != 1) {
//Reset into AP-only mode sooner.
os_timer_disarm(&resetTimer);
@ -379,56 +420,34 @@ int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) {
}
}
len+=os_sprintf(buff+len, "}\n");
len += os_sprintf(buff+len, "\"x\":0}\n");
buff[len] = 0;
os_printf(" -> %s\n", buff);
httpdSend(connData, buff, len);
return HTTPD_CGI_DONE;
}
static char *wifiWarn[] = { 0,
"Switch to <a href=\\\"setmode?mode=3\\\">STA+AP mode</a>",
"<b>Can't scan in this mode!</b> Switch to <a href=\\\"setmode?mode=3\\\">STA+AP mode</a>",
"Switch to <a href=\\\"setmode?mode=1\\\">STA mode</a>",
};
// Cgi to return various Wifi information
int ICACHE_FLASH_ATTR cgiWifiInfo(HttpdConnData *connData) {
char buff[1024];
int len;
if (connData->conn==NULL) {
return HTTPD_CGI_DONE; // Connection aborted
}
struct station_config stconf;
wifi_station_get_config(&stconf);
uint8_t op = wifi_get_opmode() & 0x3;
char *mode = wifiMode[op];
char *status = "unknown";
int st = wifi_station_get_connect_status();
if (st > 0 && st < sizeof(connStatuses)) status = connStatuses[st];
int p = wifi_get_phy_mode();
char *phy = wifiPhy[p&3];
char *warn = wifiWarn[op];
sint8 rssi = wifi_station_get_rssi();
if (rssi > 0) rssi = 0;
len = os_sprintf(buff,
"{\"mode\": \"%s\", \"ssid\": \"%s\", \"status\": \"%s\", \"phy\": \"%s\", "
"\"rssi\": \"%ddB\", \"warn\": \"%s\", \"passwd\": \"%s\"}",
mode, (char*)stconf.ssid, status, phy, rssi, warn, (char*)stconf.password);
os_strcpy(buff, "{");
printWifiInfo(buff+1);
os_strcat(buff, "}");
jsonHeader(connData, 200);
httpdSend(connData, buff, len);
httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE;
}
// Init the wireless, which consists of setting a timer if we expect to connect to an AP
// so we can revert to STA+AP mode if we can't connect.
void ICACHE_FLASH_ATTR wifiInit() {
//wifi_station_set_hostname("esp-link");
int x = wifi_get_opmode() & 0x3;
os_printf("Wifi init, mode=%s\n", wifiMode[x]);
wifi_set_phy_mode(2);

@ -7,8 +7,8 @@
// The web log has a 1KB circular in-memory buffer which os_printf prints into and
// the HTTP handler simply displays the buffer content on a web page.
// see consolse.c for invariants (same here)
#define BUF_MAX (1024)
// see console.c for invariants (same here)
#define BUF_MAX (1400)
static char log_buf[BUF_MAX];
static int log_wr, log_rd;
static int log_pos;
@ -18,9 +18,9 @@ static bool log_newline; // at start of a new line
void ICACHE_FLASH_ATTR
log_uart(bool enable) {
if (!enable && !log_no_uart) {
os_printf("Turning OFF uart log\n");
//os_printf("Turning OFF uart log\n");
os_delay_us(4*1000L); // time for uart to flush
log_no_uart = !enable;
//log_no_uart = !enable;
} else if (enable && log_no_uart) {
log_no_uart = !enable;
os_printf("Turning ON uart log\n");
@ -54,12 +54,17 @@ log_write_char(char c) {
// Uart output unless disabled
if (!log_no_uart) {
if (log_newline) {
uart0_write_char('>');
uart0_write_char(' ');
char buff[16];
int l = os_sprintf(buff, "%6d> ", (system_get_time()/1000)%1000000);
for (int i=0; i<l; i++)
uart0_write_char(buff[i]);
log_newline = false;
}
uart0_write_char(c);
log_newline = c == '\n';
if (c == '\n') {
log_newline = true;
uart0_write_char('\r');
}
}
// Store in log buffer
if (c == '\n') log_write('\r');

@ -82,7 +82,7 @@ HttpdBuiltInUrl builtInUrls[]={
{"/wifi/", cgiRedirect, "/wifi/wifi.tpl"},
{"/wifi/wifi.tpl", cgiEspFsHtml, NULL},
{"/wifi/info", cgiWifiInfo, NULL},
{"/wifi/wifiscan", cgiWiFiScan, NULL},
{"/wifi/scan", cgiWiFiScan, NULL},
{"/wifi/connect", cgiWiFiConnect, NULL},
{"/wifi/connstatus", cgiWiFiConnStatus, NULL},
{"/wifi/setmode", cgiWiFiSetMode, NULL},
@ -122,6 +122,7 @@ void user_init(void) {
// Status LEDs
statusInit(LED_CONN_PIN);
serledInit(LED_SERIAL_PIN);
logInit();
// Wifi
wifiInit();
// init the flash filesystem with the html stuff
@ -138,5 +139,4 @@ void user_init(void) {
os_timer_arm(&prHeapTimer, 3000, 1);
#endif
os_printf("** esp-link ready\n");
logInit();
}

Loading…
Cancel
Save