From b283daa57f0c9b82bceb497fd6cf9c608b5ec4ef Mon Sep 17 00:00:00 2001 From: David Betz Date: Thu, 5 May 2016 07:50:28 -0400 Subject: [PATCH 01/19] A few changes to support the Propeller loader. --- Makefile | 3 ++- core/httpd.c | 28 ++++++++++++++++++++++------ include/espmissingincludes.h | 5 +++++ include/httpd.h | 3 ++- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 59a6db62..b5cab00f 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,8 @@ XTENSA_TOOLS_ROOT ?= # base directory of the ESP8266 SDK package, absolute # Only used for the non-FreeRTOS build -SDK_BASE ?= /opt/Espressif/ESP8266_SDK +#SDK_BASE ?= /opt/Espressif/ESP8266_SDK +SDK_BASE ?= $(abspath ../esp_iot_sdk_v1.5.2) # Base directory of the ESP8266 FreeRTOS SDK package, absolute # Only used for the FreeRTOS build diff --git a/core/httpd.c b/core/httpd.c index 28a1ad03..410ca640 100644 --- a/core/httpd.c +++ b/core/httpd.c @@ -51,6 +51,7 @@ struct HttpdPriv { int headPos; char *sendBuff; int sendBuffLen; + int sendBuffMax; char *chunkHdr; HttpSendBacklogItem *sendBacklog; int sendBacklogSize; @@ -229,15 +230,27 @@ void ICACHE_FLASH_ATTR httpdDisableTransferEncoding(HttpdConnData *conn) { conn->priv->flags&=~HFL_CHUNKED; } +//Setup a send buffer +void ICACHE_FLASH_ATTR httpdSetSendBuffer(HttpdConnData *conn, char *buff, short max) +{ + conn->priv->sendBuff = buff; + conn->priv->sendBuffLen = 0; + conn->priv->sendBuffMax = max; +} + //Start the response headers. void ICACHE_FLASH_ATTR httpdStartResponse(HttpdConnData *conn, int code) { char buff[256]; int l; - l=sprintf(buff, "HTTP/1.%d %d OK\r\nServer: esp8266-httpd/"HTTPDVER"\r\n%s\r\n", + l=sprintf(buff, "HTTP/1.%d %d OK\r\nServer: esp8266-httpd/"HTTPDVER"\r\n", (conn->priv->flags&HFL_HTTP11)?1:0, - code, - (conn->priv->flags&HFL_CHUNKED)?"Transfer-Encoding: chunked":"Connection: close"); + code); httpdSend(conn, buff, l); + if (code != 101) { + l=sprintf(buff, "%s\r\n", + (conn->priv->flags&HFL_CHUNKED)?"Transfer-Encoding: chunked":"Connection: close"); + httpdSend(conn, buff, l); + } } //Send a http header. @@ -352,13 +365,13 @@ int ICACHE_FLASH_ATTR httpdSend(HttpdConnData *conn, const char *data, int len) if (len<0) len=strlen(data); if (len==0) return 0; if (conn->priv->flags&HFL_CHUNKED && conn->priv->flags&HFL_SENDINGBODY && conn->priv->chunkHdr==NULL) { - if (conn->priv->sendBuffLen+len+6>MAX_SENDBUFF_LEN) return 0; + if (conn->priv->sendBuffLen+len+6>conn->priv->sendBuffMax) return 0; //Establish start of chunk conn->priv->chunkHdr=&conn->priv->sendBuff[conn->priv->sendBuffLen]; strcpy(conn->priv->chunkHdr, "0000\r\n"); conn->priv->sendBuffLen+=6; } - if (conn->priv->sendBuffLen+len>MAX_SENDBUFF_LEN) return 0; + if (conn->priv->sendBuffLen+len>conn->priv->sendBuffMax) return 0; memcpy(conn->priv->sendBuff+conn->priv->sendBuffLen, data, len); conn->priv->sendBuffLen+=len; return 1; @@ -476,6 +489,8 @@ void ICACHE_FLASH_ATTR httpdSentCb(ConnTypePtr rconn, char *remIp, int remPort) sendBuff=malloc(MAX_SENDBUFF_LEN); conn->priv->sendBuff=sendBuff; conn->priv->sendBuffLen=0; + conn->priv->sendBuffMax = MAX_SENDBUFF_LEN; + r=conn->cgi(conn); //Execute cgi fn. if (r==HTTPD_CGI_DONE) { httpdCgiIsDone(conn); @@ -581,7 +596,7 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) { e++; //Skip to protocol indicator while (*e==' ') e++; //Skip spaces. //If HTTP/1.1, note that and set chunked encoding - if (strcasecmp(e, "HTTP/1.1")==0) conn->priv->flags|=HFL_HTTP11|HFL_CHUNKED; + if (strcasecmp(e, "HTTP/1.1")==0) conn->priv->flags|=HFL_HTTP11; // BUG -- dbetz |HFL_CHUNKED; httpd_printf("URL = %s\n", conn->url); //Parse out the URL part before the GET parameters. @@ -639,6 +654,7 @@ void httpdRecvCb(ConnTypePtr rconn, char *remIp, int remPort, char *data, unsign if (conn==NULL) return; conn->priv->sendBuff=sendBuff; conn->priv->sendBuffLen=0; + conn->priv->sendBuffMax = MAX_SENDBUFF_LEN; //This is slightly evil/dirty: we abuse conn->post->len as a state variable for where in the http communications we are: //<0 (-1): Post len unknown because we're still receiving headers diff --git a/include/espmissingincludes.h b/include/espmissingincludes.h index 3126c95c..2eea75bb 100644 --- a/include/espmissingincludes.h +++ b/include/espmissingincludes.h @@ -2,6 +2,7 @@ #define ESPMISSINGINCLUDES_H #include +#include #include @@ -72,6 +73,10 @@ void pvPortFree(void *ptr, const char *file, int line); } while (0) #endif +int ets_vsprintf(char *str, const char *format, va_list argptr); +int ets_vsnprintf(char *buffer, size_t sizeOfBuffer, const char *format, va_list argptr); +int os_snprintf(char *str, size_t size, const char *format, ...) __attribute__((format(printf, 3, 4))); + #endif #endif diff --git a/include/httpd.h b/include/httpd.h index 20f6ac58..942b2fd2 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -69,6 +69,7 @@ void httpdHeader(HttpdConnData *conn, const char *field, const char *val); void httpdEndHeaders(HttpdConnData *conn); int httpdGetHeader(HttpdConnData *conn, char *header, char *ret, int retLen); int httpdSend(HttpdConnData *conn, const char *data, int len); +void httpdSetSendBuffer(HttpdConnData *conn, char *buff, short max); void httpdFlushSendBuffer(HttpdConnData *conn); //Platform dependent code should call these. @@ -78,4 +79,4 @@ void httpdDisconCb(ConnTypePtr conn, char *remIp, int remPort); int httpdConnectCb(ConnTypePtr conn, char *remIp, int remPort); -#endif \ No newline at end of file +#endif From 5583cb3cfbc703c6ddc3b063646318740f527b6d Mon Sep 17 00:00:00 2001 From: David Betz Date: Thu, 5 May 2016 08:13:46 -0400 Subject: [PATCH 02/19] Fix the path to the sdk. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b5cab00f..3fc63dec 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ XTENSA_TOOLS_ROOT ?= # base directory of the ESP8266 SDK package, absolute # Only used for the non-FreeRTOS build #SDK_BASE ?= /opt/Espressif/ESP8266_SDK -SDK_BASE ?= $(abspath ../esp_iot_sdk_v1.5.2) +SDK_BASE ?= $(abspath ../../esp_iot_sdk_v1.5.2) # Base directory of the ESP8266 FreeRTOS SDK package, absolute # Only used for the FreeRTOS build From ec7ed0e657ef07f706a9233b2cbb8e7bc3bd41e0 Mon Sep 17 00:00:00 2001 From: David Betz Date: Thu, 5 May 2016 15:07:18 -0400 Subject: [PATCH 03/19] Fix the WebSockets broadcast function. --- util/cgiwebsocket.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/util/cgiwebsocket.c b/util/cgiwebsocket.c index adf6c189..dc555a02 100644 --- a/util/cgiwebsocket.c +++ b/util/cgiwebsocket.c @@ -126,19 +126,20 @@ int ICACHE_FLASH_ATTR cgiWebsockBroadcast(char *resource, char *data, int len, i //will not have an associated send buffer. This means httpdSend will write to a dangling pointer! //Disabled for now. If you really need this, open an issue on github or otherwise poke me and I'll //see what I can do. -/* - Websock *lw=llStart; int ret=0; +#if 1 + Websock *lw=llStart; while (lw!=NULL) { + char sendBuff[1024]; + httpdSetSendBuffer(lw->conn, sendBuff, sizeof(sendBuff)); if (strcmp(lw->conn->url, resource)==0) { cgiWebsocketSend(lw, data, len, flags); ret++; } lw=lw->priv->next; } +#endif return ret; -*/ - return 0; } From 173740caa2d334f7faade13fe7a10d7f71f637ec Mon Sep 17 00:00:00 2001 From: David Betz Date: Thu, 5 May 2016 16:37:50 -0400 Subject: [PATCH 04/19] Add *~ to .gitignore. --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5e14a6fa..b72a1113 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ espfs/espfstest/*.o espfs/espfstest/espfstest *.DS_Store html_compressed/ -libwebpages-espfs.a \ No newline at end of file +libwebpages-espfs.a +*~ From bbc408e8367739a12e12bf68377a58d88e6b19ba Mon Sep 17 00:00:00 2001 From: David Betz Date: Wed, 18 May 2016 11:30:06 -0400 Subject: [PATCH 05/19] Move some stuff into cached memory. --- core/httpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/httpd.c b/core/httpd.c index 410ca640..2fba967b 100644 --- a/core/httpd.c +++ b/core/httpd.c @@ -646,7 +646,7 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) { //Callback called when there's data available on a socket. -void httpdRecvCb(ConnTypePtr rconn, char *remIp, int remPort, char *data, unsigned short len) { +void ICACHE_FLASH_ATTR httpdRecvCb(ConnTypePtr rconn, char *remIp, int remPort, char *data, unsigned short len) { int x, r; char *p, *e; char *sendBuff=malloc(MAX_SENDBUFF_LEN); From 5d6de14fc3a57a2cd0556fd9ddf6ffff74786393 Mon Sep 17 00:00:00 2001 From: David Betz Date: Tue, 31 May 2016 08:33:22 -0400 Subject: [PATCH 06/19] Add a function to join a wifi network. --- include/cgiwifi.h | 2 ++ util/cgiwifi.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/cgiwifi.h b/include/cgiwifi.h index 21ef2fc5..7fa7e7a3 100644 --- a/include/cgiwifi.h +++ b/include/cgiwifi.h @@ -10,4 +10,6 @@ int cgiWiFiConnect(HttpdConnData *connData); int cgiWiFiSetMode(HttpdConnData *connData); int cgiWiFiConnStatus(HttpdConnData *connData); +int wifiJoin(char *ssid, char *passwd); + #endif \ No newline at end of file diff --git a/util/cgiwifi.c b/util/cgiwifi.c index 4e064325..30880ef1 100644 --- a/util/cgiwifi.c +++ b/util/cgiwifi.c @@ -228,6 +228,22 @@ int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) { return HTTPD_CGI_DONE; } +int ICACHE_FLASH_ATTR wifiJoin(char *ssid, char *passwd) +{ + static os_timer_t reassTimer; + + strncpy((char*)stconf.ssid, ssid, 32); + strncpy((char*)stconf.password, passwd, 64); + httpd_printf("Try to connect to AP %s pw %s\n", ssid, passwd); + + //Schedule disconnect/connect + os_timer_disarm(&reassTimer); + os_timer_setfn(&reassTimer, reassTimerCb, NULL); + os_timer_arm(&reassTimer, 500, 0); + + return 0; +} + //This cgi uses the routines above to connect to a specific access point with the //given ESSID using the given password. int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { From bbae792a854e087473ff232ab681231ba7d58cb4 Mon Sep 17 00:00:00 2001 From: David Betz Date: Tue, 31 May 2016 09:11:52 -0400 Subject: [PATCH 07/19] Change wording from "Client" to "Station" to meet Parallax requirements. --- util/cgiwifi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/util/cgiwifi.c b/util/cgiwifi.c index 30880ef1..d6f6c79d 100644 --- a/util/cgiwifi.c +++ b/util/cgiwifi.c @@ -309,9 +309,10 @@ int ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token, void **arg) strcpy(buff, "Unknown"); if (strcmp(token, "WiFiMode")==0) { x=wifi_get_opmode(); - if (x==1) strcpy(buff, "Client"); - if (x==2) strcpy(buff, "SoftAP"); - if (x==3) strcpy(buff, "STA+AP"); + if (x==1) strcpy(buff, "Station"); + else if (x==2) strcpy(buff, "SoftAP"); + else if (x==3) strcpy(buff, "Station+SoftAP"); + else strcpy(buff, "(unknown)"); } else if (strcmp(token, "currSsid")==0) { strcpy(buff, (char*)stconf.ssid); } else if (strcmp(token, "WiFiPasswd")==0) { From ccfa95c172d2adc465b170da884a1427e8ed5143 Mon Sep 17 00:00:00 2001 From: David Betz Date: Tue, 31 May 2016 16:03:52 -0400 Subject: [PATCH 08/19] Get rid of some debugging output. --- core/httpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/httpd.c b/core/httpd.c index 2fba967b..dfd9d2d3 100644 --- a/core/httpd.c +++ b/core/httpd.c @@ -191,7 +191,7 @@ int ICACHE_FLASH_ATTR httpdFindArg(char *line, char *arg, char *buff, int buffLe p=(char*)strstr(p, "&"); if (p!=NULL) p+=1; } - httpd_printf("Finding %s in %s: Not found :/\n", arg, line); +// httpd_printf("Finding %s in %s: Not found :/\n", arg, line); return -1; //not found } From 349ecc8f62baafabbb5125e6be133b7cf4ee27b8 Mon Sep 17 00:00:00 2001 From: David Betz Date: Fri, 10 Jun 2016 10:22:15 -0400 Subject: [PATCH 09/19] Add a prototype for httpdCgiIsDone. --- include/httpd.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/httpd.h b/include/httpd.h index 942b2fd2..271782a2 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -71,6 +71,7 @@ int httpdGetHeader(HttpdConnData *conn, char *header, char *ret, int retLen); int httpdSend(HttpdConnData *conn, const char *data, int len); void httpdSetSendBuffer(HttpdConnData *conn, char *buff, short max); void httpdFlushSendBuffer(HttpdConnData *conn); +void httpdCgiIsDone(HttpdConnData *conn); //Platform dependent code should call these. void httpdSentCb(ConnTypePtr conn, char *remIp, int remPort); From 4fb147266a13bccdaf63635485ba1b046c6d2b81 Mon Sep 17 00:00:00 2001 From: David Betz Date: Sun, 24 Jul 2016 16:12:59 -0400 Subject: [PATCH 10/19] Cleanup some of the cleanup code. :-) --- core/httpd-freertos.c | 2 +- core/httpd-nonos.c | 3 +- core/httpd-platform.h | 2 +- core/httpd.c | 70 +++++++++++++++++++++---------------------- include/httpd.h | 1 + util/cgiwifi.c | 21 +++++++++++++ 6 files changed, 60 insertions(+), 39 deletions(-) diff --git a/core/httpd-freertos.c b/core/httpd-freertos.c index a1de29fa..128cbf21 100644 --- a/core/httpd-freertos.c +++ b/core/httpd-freertos.c @@ -32,7 +32,7 @@ struct RtosConnType{ static RtosConnType rconn[HTTPD_MAX_CONNECTIONS]; -int ICACHE_FLASH_ATTR httpdPlatSendData(ConnTypePtr conn, char *buff, int len) { +int ICACHE_FLASH_ATTR httpdPlatSendData(ConnTypePtr conn, const char *buff, int len) { conn->needWriteDoneNotif=1; return (write(conn->fd, buff, len)>=0); } diff --git a/core/httpd-nonos.c b/core/httpd-nonos.c index 2fc73145..f2136493 100644 --- a/core/httpd-nonos.c +++ b/core/httpd-nonos.c @@ -15,6 +15,7 @@ static esp_tcp httpdTcp; static void ICACHE_FLASH_ATTR platReconCb(void *arg, sint8 err) { +os_printf("RECON: %d\n", err); //Yeah, this is pretty useless... } @@ -46,7 +47,7 @@ static void ICACHE_FLASH_ATTR platConnCb(void *arg) { } -int ICACHE_FLASH_ATTR httpdPlatSendData(ConnTypePtr conn, char *buff, int len) { +int ICACHE_FLASH_ATTR httpdPlatSendData(ConnTypePtr conn, const char *buff, int len) { int r; r=espconn_sent(conn, (uint8_t*)buff, len); return (r>=0); diff --git a/core/httpd-platform.h b/core/httpd-platform.h index e3e5140a..e2a8bb63 100644 --- a/core/httpd-platform.h +++ b/core/httpd-platform.h @@ -1,7 +1,7 @@ #ifndef HTTPD_PLATFORM_H #define HTTPD_PLATFORM_H -int httpdPlatSendData(ConnTypePtr conn, char *buff, int len); +int httpdPlatSendData(ConnTypePtr conn, const char *buff, int len); void httpdPlatDisconnect(ConnTypePtr conn); void httpdPlatDisableTimeout(ConnTypePtr conn); void httpdPlatInit(int port, int maxConnCt); diff --git a/core/httpd.c b/core/httpd.c index dfd9d2d3..69ae6d10 100644 --- a/core/httpd.c +++ b/core/httpd.c @@ -99,23 +99,11 @@ const char ICACHE_FLASH_ATTR *httpdGetMimetype(char *url) { return mimeTypes[i].mimetype; } -//Looks up the connData info for a specific connection -static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(ConnTypePtr conn, char *remIp, int remPort) { - for (int i=0; iremote_port == remPort && - memcmp(connData[i]->remote_ip, remIp, 4) == 0) { - connData[i]->conn=conn; - return connData[i]; - } - } - //Shouldn't happen. - httpd_printf("*** Unknown connection %d.%d.%d.%d:%d\n", remIp[0]&0xff, remIp[1]&0xff, remIp[2]&0xff, remIp[3]&0xff, remPort); - httpdPlatDisconnect(conn); - return NULL; -} - //Retires a connection for re-use static void ICACHE_FLASH_ATTR httpdRetireConn(HttpdConnData *conn) { + if (conn==NULL) return; + if (conn->conn && conn->conn->reverse == conn) + conn->conn->reverse = NULL; // break reverse link if (conn->priv->sendBacklog!=NULL) { HttpSendBacklogItem *i, *j; i=conn->priv->sendBacklog; @@ -125,13 +113,15 @@ static void ICACHE_FLASH_ATTR httpdRetireConn(HttpdConnData *conn) { free(j); } while (i!=NULL); } - if (conn->post->buff!=NULL) free(conn->post->buff); - if (conn->post!=NULL) free(conn->post); + if (conn->post!=NULL) { + if (conn->post->buff!=NULL) free(conn->post->buff); + free(conn->post); + } if (conn->priv!=NULL) free(conn->priv); - if (conn) free(conn); for (int i=0; iconn==NULL) return 0; if (len<0) len=strlen(data); - if (len==0) return 0; + if (len==0) return 1; if (conn->priv->flags&HFL_CHUNKED && conn->priv->flags&HFL_SENDINGBODY && conn->priv->chunkHdr==NULL) { if (conn->priv->sendBuffLen+len+6>conn->priv->sendBuffMax) return 0; //Establish start of chunk @@ -387,7 +377,7 @@ static char ICACHE_FLASH_ATTR httpdHexNibble(int val) { //are doing! Also, if you do set conn->cgi to NULL to indicate the connection is closed, do it BEFORE //calling this. void ICACHE_FLASH_ATTR httpdFlushSendBuffer(HttpdConnData *conn) { - int r, len; + int len; if (conn->conn==NULL) return; if (conn->priv->chunkHdr!=NULL) { //We're sending chunked data, and the chunk needs fixing up. @@ -408,22 +398,28 @@ void ICACHE_FLASH_ATTR httpdFlushSendBuffer(HttpdConnData *conn) { strcpy(&conn->priv->sendBuff[conn->priv->sendBuffLen], "0\r\n\r\n"); conn->priv->sendBuffLen+=5; } - if (conn->priv->sendBuffLen!=0) { - r=httpdPlatSendData(conn->conn, conn->priv->sendBuff, conn->priv->sendBuffLen); - if (!r) { + if (!httpdUnbufferedSend(conn, conn->priv->sendBuff, conn->priv->sendBuffLen)) { + httpd_printf("Httpd: UnbufferedSend failed!\n"); + } + conn->priv->sendBuffLen=0; +} + +int ICACHE_FLASH_ATTR httpdUnbufferedSend(HttpdConnData *conn, const char *data, int len) { + if (len!=0) { + if (!httpdPlatSendData(conn->conn, data, len)) { + httpd_printf("Httpd: queuing %d byte buffer\n", len); //Can't send this for some reason. Dump packet in backlog, we can send it later. - if (conn->priv->sendBacklogSize+conn->priv->sendBuffLen>MAX_BACKLOG_SIZE) { - httpd_printf("Httpd: Backlog: Exceeded max backlog size, dropped %d bytes instead of sending them.\n", conn->priv->sendBuffLen); - conn->priv->sendBuffLen=0; - return; + if (conn->priv->sendBacklogSize+len>MAX_BACKLOG_SIZE) { + httpd_printf("Httpd: Backlog: Exceeded max backlog size, dropped %d bytes instead of sending them.\n", len); + return 0; } - HttpSendBacklogItem *i=malloc(sizeof(HttpSendBacklogItem)+conn->priv->sendBuffLen); + HttpSendBacklogItem *i=malloc(sizeof(HttpSendBacklogItem)+len); if (i==NULL) { httpd_printf("Httpd: Backlog: malloc failed, out of memory!\n"); - return; + return 0; } - memcpy(i->data, conn->priv->sendBuff, conn->priv->sendBuffLen); - i->len=conn->priv->sendBuffLen; + memcpy(i->data, data, len); + i->len=len; i->next=NULL; if (conn->priv->sendBacklog==NULL) { conn->priv->sendBacklog=i; @@ -432,10 +428,10 @@ void ICACHE_FLASH_ATTR httpdFlushSendBuffer(HttpdConnData *conn) { while (e->next!=NULL) e=e->next; e->next=i; } - conn->priv->sendBacklogSize+=conn->priv->sendBuffLen; + conn->priv->sendBacklogSize+=len; } - conn->priv->sendBuffLen=0; } + return 1; } void ICACHE_FLASH_ATTR httpdCgiIsDone(HttpdConnData *conn) { @@ -462,12 +458,13 @@ void ICACHE_FLASH_ATTR httpdCgiIsDone(HttpdConnData *conn) { //sent. void ICACHE_FLASH_ATTR httpdSentCb(ConnTypePtr rconn, char *remIp, int remPort) { int r; - HttpdConnData *conn=httpdFindConnData(rconn, remIp, remPort); + HttpdConnData *conn=rconn->reverse; char *sendBuff; if (conn==NULL) return; if (conn->priv->sendBacklog!=NULL) { + httpd_printf("Httpd: sending %d byte queued buffer\n", conn->priv->sendBacklog->len); //We have some backlog to send first. HttpSendBacklogItem *next=conn->priv->sendBacklog->next; httpdPlatSendData(conn->conn, conn->priv->sendBacklog->data, conn->priv->sendBacklog->len); @@ -650,7 +647,7 @@ void ICACHE_FLASH_ATTR httpdRecvCb(ConnTypePtr rconn, char *remIp, int remPort, int x, r; char *p, *e; char *sendBuff=malloc(MAX_SENDBUFF_LEN); - HttpdConnData *conn=httpdFindConnData(rconn, remIp, remPort); + HttpdConnData *conn=rconn->reverse; if (conn==NULL) return; conn->priv->sendBuff=sendBuff; conn->priv->sendBuffLen=0; @@ -737,7 +734,7 @@ void ICACHE_FLASH_ATTR httpdRecvCb(ConnTypePtr rconn, char *remIp, int remPort, //The platform layer should ALWAYS call this function, regardless if the connection is closed by the server //or by the client. void ICACHE_FLASH_ATTR httpdDisconCb(ConnTypePtr rconn, char *remIp, int remPort) { - HttpdConnData *hconn=httpdFindConnData(rconn, remIp, remPort); + HttpdConnData *hconn=rconn->reverse; if (hconn==NULL) return; httpd_printf("Pool slot %d: socket closed.\n", hconn->slot); hconn->conn=NULL; //indicate cgi the connection is gone @@ -760,6 +757,7 @@ int ICACHE_FLASH_ATTR httpdConnectCb(ConnTypePtr conn, char *remIp, int remPort) connData[i]->priv=malloc(sizeof(HttpdPriv)); memset(connData[i]->priv, 0, sizeof(HttpdPriv)); connData[i]->conn=conn; + conn->reverse = connData[i]; connData[i]->slot=i; connData[i]->priv->headPos=0; connData[i]->post=malloc(sizeof(HttpdPostData)); diff --git a/include/httpd.h b/include/httpd.h index 271782a2..2ea2bc5a 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -69,6 +69,7 @@ void httpdHeader(HttpdConnData *conn, const char *field, const char *val); void httpdEndHeaders(HttpdConnData *conn); int httpdGetHeader(HttpdConnData *conn, char *header, char *ret, int retLen); int httpdSend(HttpdConnData *conn, const char *data, int len); +int httpdUnbufferedSend(HttpdConnData *conn, const char *data, int len); void httpdSetSendBuffer(HttpdConnData *conn, char *buff, short max); void httpdFlushSendBuffer(HttpdConnData *conn); void httpdCgiIsDone(HttpdConnData *conn); diff --git a/util/cgiwifi.c b/util/cgiwifi.c index d6f6c79d..219c9df6 100644 --- a/util/cgiwifi.c +++ b/util/cgiwifi.c @@ -158,19 +158,29 @@ int ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) { //Temp store for new ap info. static struct station_config stconf; +//#define SWITCH_TO_STA_MODE_AFTER_CONNECT + //This routine is ran some time after a connection attempt to an access point. If //the connect succeeds, this gets the module in STA-only mode. static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { int x=wifi_station_get_connect_status(); if (x==STATION_GOT_IP) { +#ifdef SWITCH_TO_STA_MODE_AFTER_CONNECT //Go to STA mode. This needs a reset, so do that. httpd_printf("Got IP. Going into STA mode..\n"); wifi_set_opmode(1); system_restart(); +#else + httpd_printf("Got IP address\n"); +#endif } else { connTryStatus=CONNTRY_FAIL; +#ifdef SWITCH_TO_STA_MODE_AFTER_CONNECT httpd_printf("Connect fail. Not going into STA-only mode.\n"); //Maybe also pass this through on the webpage? +#else + httpd_printf("Connect failed.\n"); +#endif } } @@ -215,6 +225,8 @@ int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) { strncpy((char*)stconf.password, passwd, 64); httpd_printf("Try to connect to AP %s pw %s\n", essid, passwd); + connTryStatus=CONNTRY_IDLE; + //Schedule disconnect/connect os_timer_disarm(&reassTimer); os_timer_setfn(&reassTimer, reassTimerCb, NULL); @@ -267,6 +279,15 @@ int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { return HTTPD_CGI_DONE; } +/* + STATION_IDLE = 0, + STATION_CONNECTING, + STATION_WRONG_PASSWORD, + STATION_NO_AP_FOUND, + STATION_CONNECT_FAIL, + STATION_GOT_IP +*/ + int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) { char buff[1024]; int len; From b09e2ad6a8fcab95db6498242abd9b96d6059b42 Mon Sep 17 00:00:00 2001 From: David Betz Date: Fri, 26 Aug 2016 14:41:18 -0400 Subject: [PATCH 11/19] Add support for recon and add a way to indicate the reason for a cgi callback. --- core/httpd-nonos.c | 6 +++--- core/httpd.c | 24 ++++++++++++++++++++---- include/httpd.h | 12 +++++++++++- util/cgiwifi.c | 38 +++++++++++++++++++++++++++++++++----- 4 files changed, 67 insertions(+), 13 deletions(-) diff --git a/core/httpd-nonos.c b/core/httpd-nonos.c index f2136493..080b8f34 100644 --- a/core/httpd-nonos.c +++ b/core/httpd-nonos.c @@ -15,8 +15,8 @@ static esp_tcp httpdTcp; static void ICACHE_FLASH_ATTR platReconCb(void *arg, sint8 err) { -os_printf("RECON: %d\n", err); - //Yeah, this is pretty useless... + ConnTypePtr conn=arg; + httpdReconCb(conn, (char*)conn->proto.tcp->remote_ip, conn->proto.tcp->remote_port, err); } static void ICACHE_FLASH_ATTR platDisconCb(void *arg) { @@ -74,4 +74,4 @@ void ICACHE_FLASH_ATTR httpdPlatInit(int port, int maxConnCt) { } -#endif \ No newline at end of file +#endif diff --git a/core/httpd.c b/core/httpd.c index 69ae6d10..2129cc94 100644 --- a/core/httpd.c +++ b/core/httpd.c @@ -454,6 +454,13 @@ void ICACHE_FLASH_ATTR httpdCgiIsDone(HttpdConnData *conn) { } } +// store the cgi callback reason and call the user's function +static int ICACHE_FLASH_ATTR callCGI(HttpdConnData *connData, int reason, int value) { + connData->cgiReason = reason; + connData->cgiValue = value; + return connData->cgi(connData); +} + //Callback called when the data on a socket has been successfully //sent. void ICACHE_FLASH_ATTR httpdSentCb(ConnTypePtr rconn, char *remIp, int remPort) { @@ -488,7 +495,7 @@ void ICACHE_FLASH_ATTR httpdSentCb(ConnTypePtr rconn, char *remIp, int remPort) conn->priv->sendBuffLen=0; conn->priv->sendBuffMax = MAX_SENDBUFF_LEN; - r=conn->cgi(conn); //Execute cgi fn. + r=callCGI(conn, CGI_CB_SENT, 0); //Execute cgi fn. if (r==HTTPD_CGI_DONE) { httpdCgiIsDone(conn); } @@ -539,7 +546,7 @@ static void ICACHE_FLASH_ATTR httpdProcessRequest(HttpdConnData *conn) { //Okay, we have a CGI function that matches the URL. See if it wants to handle the //particular URL we're supposed to handle. - r=conn->cgi(conn); + r=callCGI(conn, CGI_CB_RECV, 0); if (r==HTTPD_CGI_MORE) { //Yep, it's happy to do so and has more data to send. if (conn->recvHdl) { @@ -701,7 +708,7 @@ void ICACHE_FLASH_ATTR httpdRecvCb(ConnTypePtr rconn, char *remIp, int remPort, conn->post->buff[conn->post->buffLen]=0; //zero-terminate, in case the cgi handler knows it can use strings //Process the data if (conn->cgi) { - r=conn->cgi(conn); + r=callCGI(conn, CGI_CB_RECV, 0); if (r==HTTPD_CGI_DONE) { httpdCgiIsDone(conn); } @@ -738,10 +745,19 @@ void ICACHE_FLASH_ATTR httpdDisconCb(ConnTypePtr rconn, char *remIp, int remPort if (hconn==NULL) return; httpd_printf("Pool slot %d: socket closed.\n", hconn->slot); hconn->conn=NULL; //indicate cgi the connection is gone - if (hconn->cgi) hconn->cgi(hconn); //Execute cgi fn if needed + if (hconn->cgi) callCGI(hconn, CGI_CB_DISCONNECT, 0); //Execute cgi fn if needed httpdRetireConn(hconn); } +//This seems to be called on connection failure +void ICACHE_FLASH_ATTR httpdReconCb(ConnTypePtr rconn, char *remIp, int remPort, int err) { + HttpdConnData *hconn=rconn->reverse; + if (hconn==NULL) return; + httpd_printf("Pool slot %d: socket closed.\n", hconn->slot); + hconn->conn=NULL; //indicate cgi the connection is gone + if (hconn->cgi) callCGI(hconn, CGI_CB_RECONNECT, err); //Execute cgi fn if needed + httpdRetireConn(hconn); +} int ICACHE_FLASH_ATTR httpdConnectCb(ConnTypePtr conn, char *remIp, int remPort) { int i; diff --git a/include/httpd.h b/include/httpd.h index 2ea2bc5a..b26c2aec 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -15,6 +15,13 @@ typedef struct HttpdPriv HttpdPriv; typedef struct HttpdConnData HttpdConnData; typedef struct HttpdPostData HttpdPostData; +enum { + CGI_CB_RECV, + CGI_CB_SENT, + CGI_CB_DISCONNECT, + CGI_CB_RECONNECT // connection failed? +}; + typedef int (* cgiSendCallback)(HttpdConnData *connData); typedef int (* cgiRecvHandler)(HttpdConnData *connData, char *data, int len); @@ -29,7 +36,9 @@ struct HttpdConnData { void *cgiData; // Opaque data pointer for the CGI function char *hostName; // Host name field of request HttpdPriv *priv; // Opaque pointer to data for internal httpd housekeeping - cgiSendCallback cgi; // CGI function pointer + int cgiReason; // Reason cgi is being called + int cgiValue; // Value associated with the reason (usually an error code) + cgiSendCallback cgi; // CGI function pointer cgiRecvHandler recvHdl; // Handler for data received after headers, if any HttpdPostData *post; // POST data structure int remote_port; // Remote TCP port @@ -78,6 +87,7 @@ void httpdCgiIsDone(HttpdConnData *conn); void httpdSentCb(ConnTypePtr conn, char *remIp, int remPort); void httpdRecvCb(ConnTypePtr conn, char *remIp, int remPort, char *data, unsigned short len); void httpdDisconCb(ConnTypePtr conn, char *remIp, int remPort); +void httpdReconCb(ConnTypePtr conn, char *remIp, int remPort, int err); int httpdConnectCb(ConnTypePtr conn, char *remIp, int remPort); diff --git a/util/cgiwifi.c b/util/cgiwifi.c index 219c9df6..fe0911c8 100644 --- a/util/cgiwifi.c +++ b/util/cgiwifi.c @@ -107,9 +107,9 @@ static void ICACHE_FLASH_ATTR wifiStartScan() { wifi_station_scan(NULL, wifiScanDoneCb); } -//This CGI is called from the bit of AJAX-code in wifi.tpl. It will initiate a +//This CGI is called from the bit of AJAX-code in wifi.html. 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. +//The result is embedded in a bit of JSON parsed by the javascript in wifi.html. int ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) { int pos=(int)connData->cgiData; int len; @@ -256,6 +256,25 @@ int ICACHE_FLASH_ATTR wifiJoin(char *ssid, char *passwd) return 0; } +#ifndef DEMO_MODE +static os_timer_t setModeTimer; +static int newMode; + +static void ICACHE_FLASH_ATTR setModeCb(void *arg) { + switch (newMode) { + case STATION_MODE: + case SOFTAP_MODE: + case STATIONAP_MODE: + wifi_set_opmode(newMode); + system_restart(); + break; + default: + os_printf("setModeCb: invalid mode %d\n", newMode); + break; + } +} +#endif + //This cgi uses the routines above to connect to a specific access point with the //given ESSID using the given password. int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { @@ -269,10 +288,19 @@ int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { len=httpdFindArg(connData->getArgs, "mode", buff, sizeof(buff)); if (len!=0) { - httpd_printf("cgiWifiSetMode: %s\n", buff); #ifndef DEMO_MODE - wifi_set_opmode(atoi(buff)); - system_restart(); + if (os_strcmp(buff, "STA") == 0) + newMode = STATION_MODE; + else if (os_strcmp(buff, "AP") == 0) + newMode = SOFTAP_MODE; + else if (os_strcmp(buff, "STA+AP") == 0) + newMode = STATIONAP_MODE; + else + newMode = atoi(buff); +os_printf("cgiWiFiSetMode: '%s' (%d)\n", buff, newMode); + os_timer_disarm(&setModeTimer); + os_timer_setfn(&setModeTimer, setModeCb, NULL); + os_timer_arm(&setModeTimer, 1000, 0); #endif } httpdRedirect(connData, "/wifi"); From fb9c28cf49f7a720b54b5c146b805858a022b114 Mon Sep 17 00:00:00 2001 From: David Betz Date: Wed, 28 Sep 2016 17:12:03 -0400 Subject: [PATCH 12/19] Use symbolic names for wifi modes. --- util/cgiwifi.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/util/cgiwifi.c b/util/cgiwifi.c index fe0911c8..12019f12 100644 --- a/util/cgiwifi.c +++ b/util/cgiwifi.c @@ -165,18 +165,19 @@ static struct station_config stconf; static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { int x=wifi_station_get_connect_status(); if (x==STATION_GOT_IP) { + httpd_printf("Got IP address.\n"); #ifdef SWITCH_TO_STA_MODE_AFTER_CONNECT //Go to STA mode. This needs a reset, so do that. - httpd_printf("Got IP. Going into STA mode..\n"); - wifi_set_opmode(1); - system_restart(); -#else - httpd_printf("Got IP address\n"); + if (x!=STATION_MODE) { + httpd_printf("Going into STA mode..\n"); + wifi_set_opmode(STATION_MODE); + system_restart(); + } #endif } else { connTryStatus=CONNTRY_FAIL; #ifdef SWITCH_TO_STA_MODE_AFTER_CONNECT - httpd_printf("Connect fail. Not going into STA-only mode.\n"); + httpd_printf("Connect failed. Not going into STA-only mode.\n"); //Maybe also pass this through on the webpage? #else httpd_printf("Connect failed.\n"); @@ -191,13 +192,12 @@ static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { //but I can't be arsed to put the code back :P static void ICACHE_FLASH_ATTR reassTimerCb(void *arg) { int x; - httpd_printf("Try to connect to AP....\n"); wifi_station_disconnect(); wifi_station_set_config(&stconf); wifi_station_connect(); x=wifi_get_opmode(); connTryStatus=CONNTRY_WORKING; - if (x!=1) { + if (x!=STATION_MODE) { //Schedule disconnect/connect os_timer_disarm(&resetTimer); os_timer_setfn(&resetTimer, resetTimerCb, NULL); @@ -248,6 +248,8 @@ int ICACHE_FLASH_ATTR wifiJoin(char *ssid, char *passwd) strncpy((char*)stconf.password, passwd, 64); httpd_printf("Try to connect to AP %s pw %s\n", ssid, passwd); + connTryStatus=CONNTRY_IDLE; + //Schedule disconnect/connect os_timer_disarm(&reassTimer); os_timer_setfn(&reassTimer, reassTimerCb, NULL); @@ -265,8 +267,9 @@ static void ICACHE_FLASH_ATTR setModeCb(void *arg) { case STATION_MODE: case SOFTAP_MODE: case STATIONAP_MODE: - wifi_set_opmode(newMode); - system_restart(); + if (!wifi_set_opmode(newMode)) + httpd_printf("wifi_set_opmode failed\n"); + //system_restart(); break; default: os_printf("setModeCb: invalid mode %d\n", newMode); From e184a52f64990076da6efc82c023d982dcacc391 Mon Sep 17 00:00:00 2001 From: David Betz Date: Fri, 7 Oct 2016 14:06:45 -0400 Subject: [PATCH 13/19] Improve mode changing code so a mode change followed by a scan doesn't end up scanning in the wrong mode due to the delay between cgiWiFiSetMode and when the mode is actually set. --- util/cgiwifi.c | 67 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/util/cgiwifi.c b/util/cgiwifi.c index 12019f12..4c676d35 100644 --- a/util/cgiwifi.c +++ b/util/cgiwifi.c @@ -37,6 +37,19 @@ typedef struct { //Static scan status storage. static ScanResultData cgiWifiAps; +#ifndef DEMO_MODE + +typedef struct { + os_timer_t timer; + char inProgress; + char newMode; + char needScan; +} NewModeData; + +static NewModeData newModeData; + +#endif + #define CONNTRY_IDLE 0 #define CONNTRY_WORKING 1 #define CONNTRY_SUCCESS 2 @@ -103,8 +116,21 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { static void ICACHE_FLASH_ATTR wifiStartScan() { // int x; if (cgiWifiAps.scanInProgress) return; - cgiWifiAps.scanInProgress=1; - wifi_station_scan(NULL, wifiScanDoneCb); + if (newModeData.inProgress) { + if (newModeData.newMode == STATIONAP_MODE) + newModeData.needScan = 1; + else + httpd_printf("Must be in STA+AP mode to start AP scan: mode=%d\n", newModeData.newMode); + } + else { + if (wifi_get_opmode() == STATIONAP_MODE) { + httpd_printf("Starting scan...\n"); + wifi_station_scan(NULL, wifiScanDoneCb); + cgiWifiAps.scanInProgress=1; + } + else + httpd_printf("Must be in STA+AP mode to start AP scan: mode=%d\n", wifi_get_opmode()); + } } //This CGI is called from the bit of AJAX-code in wifi.html. It will initiate a @@ -171,7 +197,6 @@ static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { if (x!=STATION_MODE) { httpd_printf("Going into STA mode..\n"); wifi_set_opmode(STATION_MODE); - system_restart(); } #endif } else { @@ -259,22 +284,26 @@ int ICACHE_FLASH_ATTR wifiJoin(char *ssid, char *passwd) } #ifndef DEMO_MODE -static os_timer_t setModeTimer; -static int newMode; static void ICACHE_FLASH_ATTR setModeCb(void *arg) { - switch (newMode) { + if (!newModeData.inProgress) return; + switch (newModeData.newMode) { case STATION_MODE: case SOFTAP_MODE: case STATIONAP_MODE: - if (!wifi_set_opmode(newMode)) - httpd_printf("wifi_set_opmode failed\n"); - //system_restart(); +httpd_printf("setModeCb: %d\n", newModeData.newMode); + wifi_set_opmode(newModeData.newMode); break; default: - os_printf("setModeCb: invalid mode %d\n", newMode); + httpd_printf("setModeCb: invalid mode %d\n", newModeData.newMode); break; } + if (newModeData.needScan) { + httpd_printf("Starting deferred scan...\n"); + wifi_station_scan(NULL, wifiScanDoneCb); + cgiWifiAps.scanInProgress=1; + } + newModeData.inProgress = 0; } #endif @@ -293,17 +322,19 @@ int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { if (len!=0) { #ifndef DEMO_MODE if (os_strcmp(buff, "STA") == 0) - newMode = STATION_MODE; + newModeData.newMode = STATION_MODE; else if (os_strcmp(buff, "AP") == 0) - newMode = SOFTAP_MODE; + newModeData.newMode = SOFTAP_MODE; else if (os_strcmp(buff, "STA+AP") == 0) - newMode = STATIONAP_MODE; + newModeData.newMode = STATIONAP_MODE; else - newMode = atoi(buff); -os_printf("cgiWiFiSetMode: '%s' (%d)\n", buff, newMode); - os_timer_disarm(&setModeTimer); - os_timer_setfn(&setModeTimer, setModeCb, NULL); - os_timer_arm(&setModeTimer, 1000, 0); + newModeData.newMode = atoi(buff); +httpd_printf("cgiWiFiSetMode: '%s' (%d)\n", buff, newModeData.newMode); + newModeData.inProgress = 1; + newModeData.needScan = 0; + os_timer_disarm(&newModeData.timer); + os_timer_setfn(&newModeData.timer, setModeCb, NULL); + os_timer_arm(&newModeData.timer, 1000, 0); #endif } httpdRedirect(connData, "/wifi"); From 183e9d4ef4a9da89db422ee680935bdc6f0778b3 Mon Sep 17 00:00:00 2001 From: David Betz Date: Mon, 14 Nov 2016 17:08:01 -0500 Subject: [PATCH 14/19] Change SDK path in Makefile. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3fc63dec..5d465bd3 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ XTENSA_TOOLS_ROOT ?= # base directory of the ESP8266 SDK package, absolute # Only used for the non-FreeRTOS build #SDK_BASE ?= /opt/Espressif/ESP8266_SDK -SDK_BASE ?= $(abspath ../../esp_iot_sdk_v1.5.2) +SDK_BASE ?= $(abspath ../esp_iot_sdk_v2.0.0.p1) # Base directory of the ESP8266 FreeRTOS SDK package, absolute # Only used for the FreeRTOS build From 1580e3ab7512bafc8b00adb3596f4eeafda3be51 Mon Sep 17 00:00:00 2001 From: David Betz Date: Thu, 19 Jan 2017 08:27:25 -0500 Subject: [PATCH 15/19] Allow the AP scanning code to be used outside. --- include/cgiwifi.h | 15 +++++++- util/cgiwifi.c | 91 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 80 insertions(+), 26 deletions(-) diff --git a/include/cgiwifi.h b/include/cgiwifi.h index 7fa7e7a3..fcab6734 100644 --- a/include/cgiwifi.h +++ b/include/cgiwifi.h @@ -3,6 +3,15 @@ #include "httpd.h" +//WiFi access point data +typedef struct { + char ssid[32]; + char bssid[8]; + int channel; + char rssi; + char enc; +} ApData; + int cgiWiFiScan(HttpdConnData *connData); int tplWlan(HttpdConnData *connData, char *token, void **arg); int cgiWiFi(HttpdConnData *connData); @@ -12,4 +21,8 @@ int cgiWiFiConnStatus(HttpdConnData *connData); int wifiJoin(char *ssid, char *passwd); -#endif \ No newline at end of file +int cgiWiFiStartScan(void (*callback)(void *data, int count), void *data); +int cgiWiFiScanDone(void); +ApData *cgiWiFiScanResult(int n); + +#endif diff --git a/util/cgiwifi.c b/util/cgiwifi.c index 4c676d35..d9b039b5 100644 --- a/util/cgiwifi.c +++ b/util/cgiwifi.c @@ -18,15 +18,6 @@ Cgi/template routines for the /wifi url. //Enable this to disallow any changes in AP settings //#define DEMO_MODE -//WiFi access point data -typedef struct { - char ssid[32]; - char bssid[8]; - int channel; - char rssi; - char enc; -} ApData; - //Scan result typedef struct { char scanInProgress; //if 1, don't access the underlying stuff from the webpage. @@ -37,6 +28,10 @@ typedef struct { //Static scan status storage. static ScanResultData cgiWifiAps; +//Callback for outside scan clients +static void (*scanCallback)(void *data, int count) = NULL; +static void *scanCallbackData; + #ifndef DEMO_MODE typedef struct { @@ -61,8 +56,9 @@ static os_timer_t resetTimer; //Callback the code calls when a wlan ap scan is done. Basically stores the result in //the cgiWifiAps struct. void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { - int n; + int noAps, n, i; struct bss_info *bss_link = (struct bss_info *)arg; + httpd_printf("wifiScanDoneCb %d\n", status); if (status!=OK) { cgiWifiAps.scanInProgress=0; @@ -76,42 +72,64 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { } //Count amount of access points found. - n=0; + noAps=0; while (bss_link != NULL) { bss_link = bss_link->next.stqe_next; - n++; + noAps++; } + //Allocate memory for access point data - cgiWifiAps.apData=(ApData **)malloc(sizeof(ApData *)*n); - cgiWifiAps.noAps=n; - httpd_printf("Scan done: found %d APs\n", n); + cgiWifiAps.apData=(ApData **)malloc(sizeof(ApData *)*noAps); + memset(cgiWifiAps.apData, 0, sizeof(ApData *)*noAps); //Copy access point data to the static struct n=0; bss_link = (struct bss_info *)arg; while (bss_link != NULL) { - if (n>=cgiWifiAps.noAps) { + if (n>=noAps) { //This means the bss_link changed under our nose. Shouldn't happen! //Break because otherwise we will write in unallocated memory. - httpd_printf("Huh? I have more than the allocated %d aps!\n", cgiWifiAps.noAps); + httpd_printf("Huh? I have more than the allocated %d aps!\n", noAps); break; } + + // check for duplicate SSIDs and keep the one with the strongest signal + for (i = 0; i < n; ++i) { + if (strncmp((char*)bss_link->ssid, cgiWifiAps.apData[i]->ssid, 32) == 0) { + if (bss_link->rssi > cgiWifiAps.apData[i]->rssi) { + cgiWifiAps.apData[i]->rssi=bss_link->rssi; + cgiWifiAps.apData[i]->channel=bss_link->channel; + cgiWifiAps.apData[i]->enc=bss_link->authmode; + strncpy(cgiWifiAps.apData[i]->bssid, (char*)bss_link->bssid, 6); + } + break; + } + } + //Save the ap data. - cgiWifiAps.apData[n]=(ApData *)malloc(sizeof(ApData)); - cgiWifiAps.apData[n]->rssi=bss_link->rssi; - cgiWifiAps.apData[n]->channel=bss_link->channel; - cgiWifiAps.apData[n]->enc=bss_link->authmode; - strncpy(cgiWifiAps.apData[n]->ssid, (char*)bss_link->ssid, 32); - strncpy(cgiWifiAps.apData[n]->bssid, (char*)bss_link->bssid, 6); + if (i >= n) { + cgiWifiAps.apData[n]=(ApData *)malloc(sizeof(ApData)); + cgiWifiAps.apData[n]->rssi=bss_link->rssi; + cgiWifiAps.apData[n]->channel=bss_link->channel; + cgiWifiAps.apData[n]->enc=bss_link->authmode; + strncpy(cgiWifiAps.apData[n]->ssid, (char*)bss_link->ssid, 32); + strncpy(cgiWifiAps.apData[n]->bssid, (char*)bss_link->bssid, 6); + n++; + } bss_link = bss_link->next.stqe_next; - n++; } + cgiWifiAps.noAps = n; + //We're done. + httpd_printf("Scan done: found %d APs\n", cgiWifiAps.noAps); + if (scanCallback) { + (*scanCallback)(scanCallbackData, cgiWifiAps.noAps); + scanCallback = NULL; + } cgiWifiAps.scanInProgress=0; } - //Routine to start a WiFi access point scan. static void ICACHE_FLASH_ATTR wifiStartScan() { // int x; @@ -133,6 +151,29 @@ static void ICACHE_FLASH_ATTR wifiStartScan() { } } +//Routine to start a WiFi access point scan. +int ICACHE_FLASH_ATTR cgiWiFiStartScan(void (*callback)(void *data, int count), void *data) { + if (scanCallback) return 0; + scanCallback = callback; + scanCallbackData = data; + wifiStartScan(); + return 1; +} + +//Routine to check the status of a WiFi access point scan. +int ICACHE_FLASH_ATTR cgiWiFiScanDone(void) { + return cgiWifiAps.scanInProgress == 0; +} + +//Routine to return a scan result. +ApData ICACHE_FLASH_ATTR *cgiWiFiScanResult(int n) { + if (cgiWifiAps.scanInProgress) + return NULL; + else if (n < 0 || n >= cgiWifiAps.noAps) + return NULL; + return cgiWifiAps.apData[n]; +} + //This CGI is called from the bit of AJAX-code in wifi.html. 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.html. From fa127ebd332eb90b65245910505bfbd811eaebd9 Mon Sep 17 00:00:00 2001 From: David Betz Date: Mon, 13 Feb 2017 12:35:25 -0500 Subject: [PATCH 16/19] Get rid of some debugging output. --- core/httpd.c | 2 +- espfs/espfs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/httpd.c b/core/httpd.c index 2129cc94..3f6b9c34 100644 --- a/core/httpd.c +++ b/core/httpd.c @@ -529,7 +529,7 @@ static void ICACHE_FLASH_ATTR httpdProcessRequest(HttpdConnData *conn) { if (builtInUrls[i].url[strlen(builtInUrls[i].url)-1]=='*' && strncmp(builtInUrls[i].url, conn->url, strlen(builtInUrls[i].url)-1)==0) match=1; if (match) { - httpd_printf("Is url index %d\n", i); +// httpd_printf("Is url index %d\n", i); conn->cgiData=NULL; conn->cgi=builtInUrls[i].cgiCb; conn->cgiArg=builtInUrls[i].cgiArg; diff --git a/espfs/espfs.c b/espfs/espfs.c index b5cf35ee..de8c11c4 100644 --- a/espfs/espfs.c +++ b/espfs/espfs.c @@ -148,7 +148,7 @@ EspFsFile ICACHE_FLASH_ATTR *espFsOpen(char *fileName) { return NULL; } if (h.flags&FLAG_LASTFILE) { - httpd_printf("End of image.\n"); +// httpd_printf("End of image.\n"); return NULL; } //Grab the name of the file. From 5d043f064790c62432e806396a164b7c74c9b42e Mon Sep 17 00:00:00 2001 From: David Betz Date: Tue, 6 Feb 2018 15:41:39 -0500 Subject: [PATCH 17/19] Open all files in binary mode in mkroffsimage. --- include/esp8266.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/esp8266.h b/include/esp8266.h index 7b685e45..bc7bc310 100644 --- a/include/esp8266.h +++ b/include/esp8266.h @@ -31,4 +31,18 @@ #include "platform.h" #include "espmissingincludes.h" +#if 0 +void *ets_memcpy(void *dest, const void *src, size_t n); +void *ets_memset(void *s, int c, size_t n); +int ets_strcmp(const char *s1, const char *s2); +int ets_strncmp(const char *s1, const char *s2, int len); +size_t ets_strlen(const char *s); +char *ets_strcpy(char *dest, const char *src); +char *ets_strstr(const char *haystack, const char *needle); +int ets_sprintf(char *str, const char *format, ...) __attribute__ ((format (printf, 2, 3))); +int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2))); +int strcasecmp(const char *a, const char *b); +void *pvPortMalloc(size_t xWantedSize, const char *file, int line); +void vPortFree(void *ptr, const char *file, int line); +#endif From e7c5a5d9780fae06a4ab88e61dfeeee550b29263 Mon Sep 17 00:00:00 2001 From: David Betz Date: Tue, 6 Feb 2018 16:35:20 -0500 Subject: [PATCH 18/19] Add a function to return the number of access points after a scan. --- include/cgiwifi.h | 1 + util/cgiwifi.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/cgiwifi.h b/include/cgiwifi.h index fcab6734..a3a9da6e 100644 --- a/include/cgiwifi.h +++ b/include/cgiwifi.h @@ -24,5 +24,6 @@ int wifiJoin(char *ssid, char *passwd); int cgiWiFiStartScan(void (*callback)(void *data, int count), void *data); int cgiWiFiScanDone(void); ApData *cgiWiFiScanResult(int n); +int cgiWifiScanResultCount(void); #endif diff --git a/util/cgiwifi.c b/util/cgiwifi.c index d9b039b5..c7004cca 100644 --- a/util/cgiwifi.c +++ b/util/cgiwifi.c @@ -174,6 +174,12 @@ ApData ICACHE_FLASH_ATTR *cgiWiFiScanResult(int n) { return cgiWifiAps.apData[n]; } +//Routine to return the scan result count. +int cgiWifiScanResultCount(void) +{ + return cgiWifiAps.scanInProgress ? -1 : cgiWifiAps.noAps; +} + //This CGI is called from the bit of AJAX-code in wifi.html. 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.html. From f428b843d85c476a4fe85d0d06daecdeabd6e83f Mon Sep 17 00:00:00 2001 From: David Betz Date: Fri, 4 Sep 2020 11:44:43 -0400 Subject: [PATCH 19/19] Update espmissingheaders.h to match ESP SDK v2.2.1. --- include/espmissingincludes.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/include/espmissingincludes.h b/include/espmissingincludes.h index 2eea75bb..b6aaa0c2 100644 --- a/include/espmissingincludes.h +++ b/include/espmissingincludes.h @@ -15,8 +15,8 @@ int strcasecmp(const char *a, const char *b); typedef struct espconn espconn; int atoi(const char *nptr); -void ets_install_putc1(void *routine); -void ets_isr_attach(int intr, void *handler, void *arg); +//void ets_install_putc1(void *routine); +//void ets_isr_attach(int intr, void *handler, void *arg); void ets_isr_mask(unsigned intr); void ets_isr_unmask(unsigned intr); int ets_memcmp(const void *s1, const void *s2, size_t n); @@ -26,11 +26,11 @@ int ets_sprintf(char *str, const char *format, ...) __attribute__ ((format (pri int ets_str2macaddr(void *, void *); int ets_strcmp(const char *s1, const char *s2); char *ets_strcpy(char *dest, const char *src); -size_t ets_strlen(const char *s); -int ets_strncmp(const char *s1, const char *s2, int len); +//size_t ets_strlen(const char *s); +//int ets_strncmp(const char *s1, const char *s2, int len); char *ets_strncpy(char *dest, const char *src, size_t n); char *ets_strstr(const char *haystack, const char *needle); -void ets_timer_arm_new(os_timer_t *a, int b, int c, int isMstimer); +//void ets_timer_arm_new(os_timer_t *a, int b, int c, int isMstimer); void ets_timer_disarm(os_timer_t *a); void ets_timer_setfn(os_timer_t *t, ETSTimerFunc *fn, void *parg); void ets_update_cpu_frequency(int freqmhz); @@ -38,12 +38,12 @@ void *os_memmove(void *dest, const void *src, size_t n); int os_printf(const char *format, ...) __attribute__ ((format (printf, 1, 2))); int os_snprintf(char *str, size_t size, const char *format, ...) __attribute__ ((format (printf, 3, 4))); int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2))); -void uart_div_modify(int no, unsigned int freq); +//void uart_div_modify(int no, unsigned int freq); uint8 wifi_get_opmode(void); uint32 system_get_time(); int rand(void); void ets_bzero(void *s, size_t n); -void ets_delay_us(int ms); +//void ets_delay_us(int ms); //Hack: this is defined in SDK 1.4.0 and undefined in 1.3.0. It's only used for this, the symbol itself //has no meaning here. @@ -55,9 +55,9 @@ void vPortFree(void *ptr); void *vPortMalloc(size_t xWantedSize); void pvPortFree(void *ptr); #else -void *pvPortMalloc(size_t xWantedSize, const char *file, int line); -void *pvPortZalloc(size_t, const char *file, int line); -void vPortFree(void *ptr, const char *file, int line); +//void *pvPortMalloc(size_t xWantedSize, const char *file, int line); +//void *pvPortZalloc(size_t, const char *file, int line); +//void vPortFree(void *ptr, const char *file, int line); void *vPortMalloc(size_t xWantedSize, const char *file, int line); void pvPortFree(void *ptr, const char *file, int line); #endif @@ -80,3 +80,4 @@ int os_snprintf(char *str, size_t size, const char *format, ...) __attribute__(( #endif #endif +