From d679340035fd015aec3a74697fb8be53a414c76c Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Mon, 22 Jun 2015 23:27:47 -0700 Subject: [PATCH] added no-cache headers; shrunk favicon; minimal support for static ip & hostname --- Makefile | 3 +- html/console.tpl | 40 +++++++++++----- html/favicon.ico | Bin 5430 -> 766 bytes html/style.css | 6 +++ html/ui.js | 41 ++++++++-------- html/wifi/wifi.tpl | 100 +++++++++++++++++++++++++++------------ httpd/httpd.c | 12 +++-- serial/console.c | 15 ++++-- user/cgi.c | 4 +- user/cgiwifi.c | 113 +++++++++++++++++++++++++++++++++++++++++---- user/cgiwifi.h | 1 + user/log.c | 2 + user/user_main.c | 28 +++++------ 13 files changed, 272 insertions(+), 93 deletions(-) mode change 100644 => 100755 html/favicon.ico diff --git a/Makefile b/Makefile index 1b2820b..257102e 100644 --- a/Makefile +++ b/Makefile @@ -199,12 +199,13 @@ echo_version: $(TARGET_OUT): $(APP_AR) $(LD_SCRIPT) $(vecho) "LD $@" $(Q) $(LD) -L$(SDK_LIBDIR) -T$(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $@ - @echo Dump: $(OBJDP) -x $(TARGET_OUT) # $(OBJDP) -x $(TARGET_OUT) | egrep '(espfs_img)' $(USER1_OUT): $(APP_AR) $(LD_SCRIPT1) $(vecho) "LD $@" $(Q) $(LD) -L$(SDK_LIBDIR) -T$(LD_SCRIPT1) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $@ + @echo Dump : $(OBJDP) -x $(USER1_OUT) + @echo Disass: $(OBJDP) -d -l -x $(USER1_OUT) # $(Q) $(OBJDP) -x $(TARGET_OUT) | egrep espfs_img $(USER2_OUT): $(APP_AR) $(LD_SCRIPT2) diff --git a/html/console.tpl b/html/console.tpl index 395b6d1..f45192a 100644 --- a/html/console.tpl +++ b/html/console.tpl @@ -5,14 +5,12 @@

The Microcontroller console shows the last 1024 characters - received from UART0, to which a microcontroller is typically attached.

+ received from UART0, to which a microcontroller is typically attached. + The UART is configured for 8 bits, no parity, 1 stop bit (8N1).

Reset µC  Baud: - 57600 - 115200 - 230400 - 460800 +


     
@@ -23,11 +21,26 @@ diff --git a/html/favicon.ico b/html/favicon.ico old mode 100644 new mode 100755 index a002df39f78c881153b3d0ed51357e6adc791b28..75c5ea0961aa34931cc7cfc40b102c8a62f6b09a GIT binary patch literal 766 zcmc&yJ5B>J5FHQ)zzs;*EmCp}u9V7>H^m+$kr0-~Zc;^ZTx_aHULS!2P^PC?-q=|{ zD57Q79{bJbjXhqX8+^;5Eu_o7emaWgkBbQ6^bELyWu1oTO2k6bb{Fn zLsbPA*Lrl>I4u=V@x+{yQpyG>)%XmOh+Rs%7JipeZQJs3v0pVpk%P}}&#T67TPrvr zg?Zb0r!0yIHrjNm3o4wn5!`9rsWBZFqwavqT|l^d#35tNX8>?WK1xQLV&H(K_!;r>q3YVqrBXw+?RI?E$N6YN+@PmtbO(Hl+@q-oEts&8*zB8@%ufB S;Ri$wc~8{1BKR5pRXzbI_+cOb literal 5430 zcmdUz-)mh(5XU!G=wtd9*r=^kC|D4D2>1*7P^cgjD)=s@r8K6}SS)Bm)2IGW8Zkk! zwnB?F4OK~QlIF*~Nt;GcYoeu1Zu5|sXlY2QDKRxjaNW-)bDSLaoSRF0(1pEw&hE_j zJ2N{wXSv3dm#8Ils=B$BZ%S+{pW`2aWm8J#TVzPQ*OtI`h7{`FOL|n*T$e znwnbQ+1Xij;>7V>Rn=?1R8+ibb!Uz>WRU&0d>S7g-%?*+e^GO-?A^q~Z}#N7H|)zV<$VA6)Gd4O-XEU!%$d`E zUpg-R6s?O~Xl%MLx-1{yazN2OP%p$jeEasB+jh(5&+Q`*H7@JSVHf^j1NOvaLhtw? zaT6Y0qo`Rj@ALMRs}U}o+7|qyVJDasN_P9Uj$l0SpXRZb>L#3S%Ey4ZDg5M%@PQ`{ zUh$0>fJH8XE%WSAS_4~n;B>N{U+TH!74f38ztVUX9@fA*a-`NTi@nd3XZ(9}b8}+7 zfCC%gbi$rr*(7wq5qxYA9{8uHr)~A?Uq`mxyz#4rzq`9Dh(Y}jzBoU4`FuXHSMBYJ zcrqV3S(35fx@l2j){@sH-{tB+t9L^nkz&T5*IV<`8 zVuQ1>;Qd4R;naRo2RZZcM$SpjljCr}mDCH}zvB4%9e#a&@LO{ix_@EQYVM!JfJPqZ z{l;&&S91r(4=}ZVo=p9)hK%;PSZ)Uw?G1Y+bxDulQ%7}=bBa6|8nf7E&V@dkf?H@r zCv?v&mS5zlQPfFlwR|tM4a~8IjK156{(pG1cBa(YniBh`F^3k6d3N5I^)tqljv2F- z-eb%f={4@}gtRVljAKjsV1WrX9B_F~7Zm=d;BSdC*Q5U_+by1J9C?BDL)yZrZ)`pq+QtRbUy6w-hZwETq;BYqJ+k16i+Kmriu#azS^5f;pV>X-3*(aa)!fxJl(LPklpi69t&-qXDmNnYW9o_yplgZdaZ(Xz7wzm7b=fc8*Und^u$R1%kHB$N~ zr+@Hvv}UsIu7A_tpR(OU?k;gPl0irIx4L@&vb*v1>v?bU@uR)AqvMj@`h1%`?C!tk z&Yg|q(2?B07QJ5>x!>L0ckamAwzf9g@cxjG!|-taANEW9*k9fHuH0F)JNvzh<2C=x z91U5CpL;d3f3o*p$o-T*)oeffVAzriW21|CfegOO{-IAU#PbJ?yLaaqY*$y8_b(}b zoQO%wU-Z)Q7kxT*U>Cj-Q_jvx&yQd%;S_OxjhQJmW^Ao7J!_1qDM|0hAd8MO+582X CcqNhm diff --git a/html/style.css b/html/style.css index 034d2c3..ac3ae6a 100644 --- a/html/style.css +++ b/html/style.css @@ -122,9 +122,15 @@ div.tt { color: #888; } +form button { + margin-top: 0.5em; +} .button-primary { background-color: #99f; } +.button-selected { + background-color: #fc6; +} /* Text console */ pre.console { diff --git a/html/ui.js b/html/ui.js index aced049..56d2f5f 100644 --- a/html/ui.js +++ b/html/ui.js @@ -10,31 +10,29 @@ if (v != null) { v.innerHTML = version; } }()); +function addClass(el, cl) { + el.className += ' ' + cl; +} +function removeClass(el, cl) { + var cls = el.className.split(/\s+/), + l = cls.length; + for (var i=0; iWifi Configuration -
-
-

Wifi State

-
- - - - - - - - - - -
-
-

Wifi Association

- -
- - To connect to a WiFi network, please select one of the detected networks, - enter the password, and hit the connect button... - -
Scanning...
- - - -
-
+
+
+
+

Wifi State

+
+ + + + + + + + + + +
+
+

Wifi Association

+ +
+ To connect to a WiFi network, please select one of the detected networks, + enter the password, and hit the connect button... + +
Scanning...
+ + + +
+
+
+
+
+

Special Settings

+
+ Special settings, use with care! If the Static IP field is empty + then DHCP will be used, else DHCP will be off. + + + + + + + + + +
+
+
@@ -184,7 +203,6 @@ function changeWifiAp(e) { e.preventDefault(); var passwd = $("#wifi-passwd").value; var essid = getSelectedEssid(); - console.log("Posting form", "essid=" + essid, "pwd="+passwd); showNotification("Connecting to " + essid); var url = "connect?essid="+encodeURIComponent(essid)+"&passwd="+encodeURIComponent(passwd); @@ -207,9 +225,31 @@ function changeWifiAp(e) { }); } +function changeSpecial(e) { + e.preventDefault(); + var url = "special"; + url += "?hostname=" + encodeURIComponent($("#wifi-hostname").value); + url += "&staticip=" + encodeURIComponent($("#wifi-staticip").value); + url += "&netmask=" + encodeURIComponent($("#wifi-netmask").value); + url += "&gateway=" + encodeURIComponent($("#wifi-gateway").value); + + hideWarning(); + var cb = $("#special-button"); + addClass(cb, 'pure-button-disabled'); + ajaxSpin("POST", url, function(resp) { + removeClass(cb, 'pure-button-disabled'); + getWifiInfo(); + }, function(s, st) { + showWarning("Error: "+st); + removeClass(cb, 'pure-button-disabled'); + getWifiInfo(); + }); +} + window.onload=function(e) { getWifiInfo(); $("#wifiform").onsubmit = changeWifiAp; + $("#specform").onsubmit = changeSpecial; scanTimeout = window.setTimeout(scanAPs, 500); }; diff --git a/httpd/httpd.c b/httpd/httpd.c index 28a3f84..72ccd97 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -120,7 +120,7 @@ static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(void *arg) { static void ICACHE_FLASH_ATTR httpdRetireConn(HttpdConnData *conn) { uint32 dt = conn->startTime; if (dt > 0) dt = (system_get_time() - dt)/1000; - os_printf("%s Closed, took %ums, heap=%ld\n", connStr, dt, + os_printf("%s Closed, %ums, heap=%ld\n", connStr, dt, (unsigned long)system_get_free_heap_size()); if (conn->post->buff!=NULL) os_free(conn->post->buff); conn->post->buff=NULL; @@ -405,8 +405,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 %s\n", connStr, - conn->requestType == HTTPD_METHOD_GET ? "GET" : "POST", conn->url); + // Count number of open connections + int open = 0; + for (int j=0; jrequestType == HTTPD_METHOD_GET ? "GET" : "POST", conn->url, open); //Parse out the URL part before the GET parameters. conn->getArgs=(char*)os_strstr(conn->url, "?"); if (conn->getArgs!=0) { @@ -540,9 +544,11 @@ static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) { return; } +#if 0 int num = 0; for (int j=0; jgetArgs, "rate", buff, sizeof(buff)); if (len > 0) { int rate = atoi(buff); if (rate >= 9600 && rate <= 1000000) { jsonHeader(connData, 200); uart0_baud(rate); - return HTTPD_CGI_DONE; + flashConfig.baud_rate = rate; + status = configSave() ? 200 : 400; } + } else if (connData->requestType == HTTPD_METHOD_GET) { + status = 200; } - jsonHeader(connData, 400); + + jsonHeader(connData, status); + os_sprintf(buff, "{\"rate\": %ld}", flashConfig.baud_rate); + httpdSend(connData, buff, -1); return HTTPD_CGI_DONE; } diff --git a/user/cgi.c b/user/cgi.c index 35e0080..f9b9b10 100644 --- a/user/cgi.c +++ b/user/cgi.c @@ -21,13 +21,15 @@ Some random cgi routines. void ICACHE_FLASH_ATTR jsonHeader(HttpdConnData *connData, int code) { httpdStartResponse(connData, code); + httpdHeader(connData, "Cache-Control", "no-cache, no-store, must-revalidate"); + httpdHeader(connData, "Pragma", "no-cache"); + httpdHeader(connData, "Expires", "0"); httpdHeader(connData, "Content-Type", "application/json"); httpdEndHeaders(connData); } #define TOKEN(x) (os_strcmp(token, x) == 0) #if 0 - // Handle system information variables and print their value, returns the number of // characters appended to buff int ICACHE_FLASH_ATTR printGlobalInfo(char *buff, int buflen, char *token) { diff --git a/user/cgiwifi.c b/user/cgiwifi.c index fd8c467..1ce00d1 100644 --- a/user/cgiwifi.c +++ b/user/cgiwifi.c @@ -18,6 +18,7 @@ Cgi/template routines for the /wifi url. #include "cgiwifi.h" #include "cgi.h" #include "status.h" +#include "config.h" #include "log.h" //Enable this to disallow any changes in AP settings @@ -289,10 +290,7 @@ int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) { char essid[128]; char passwd[128]; - if (connData->conn==NULL) { - //Connection aborted. Clean up. - return HTTPD_CGI_DONE; - } + if (connData->conn==NULL) return HTTPD_CGI_DONE; int el = httpdFindArg(connData->getArgs, "essid", essid, sizeof(essid)); int pl = httpdFindArg(connData->getArgs, "passwd", passwd, sizeof(passwd)); @@ -317,6 +315,104 @@ int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) { return HTTPD_CGI_DONE; } +static bool parse_ip(char *buff, ip_addr_t *ip_ptr) { + char *next = buff; // where to start parsing next integer + int found = 0; // number of integers parsed + uint32_t ip = 0; // the ip addres parsed + for (int i=0; i<32; i++) { // 32 is just a safety limit + char c = buff[i]; + if (c == '.' || c == 0) { + // parse the preceding integer and accumulate into IP address + bool last = c == 0; + buff[i] = 0; + uint32_t v = atoi(next); + ip = ip | ((v&0xff)<<(found*8)); + next = buff+i+1; // next integer starts after the '.' + found++; + if (last) { // if at end of string we better got 4 integers + ip_ptr->addr = ip; + return found == 4; + } + continue; + } + if (c < '0' || c > '9') return false; + } + return false; +} + +#define DEBUGIP +#ifdef DEBUGIP +static void ICACHE_FLASH_ATTR debugIP() { + struct ip_info info; + if (wifi_get_ip_info(0, &info)) { + os_printf("\"ip\": \"%d.%d.%d.%d\"\n", IP2STR(&info.ip.addr)); + os_printf("\"netmask\": \"%d.%d.%d.%d\"\n", IP2STR(&info.netmask.addr)); + os_printf("\"gateway\": \"%d.%d.%d.%d\"\n", IP2STR(&info.gw.addr)); + os_printf("\"hostname\": \"%s\"", flashConfig.hostname); + } else { + os_printf("\"ip\": \"-none-\"\n"); + } +} +#endif + +// Change special settings +int ICACHE_FLASH_ATTR cgiWiFiSpecial(HttpdConnData *connData) { + char hostname[32]; + char staticip[32]; + char netmask[32]; + char gateway[32]; + + if (connData->conn==NULL) return HTTPD_CGI_DONE; + + // get args and their string lengths + int hl = httpdFindArg(connData->getArgs, "hostname", hostname, sizeof(hostname)); + int sl = httpdFindArg(connData->getArgs, "staticip", staticip, sizeof(staticip)); + int nl = httpdFindArg(connData->getArgs, "netmask", netmask, sizeof(netmask)); + int gl = httpdFindArg(connData->getArgs, "gateway", gateway, sizeof(gateway)); + + if (hl >= 0 && sl >= 0 && nl >= 0 && gl >= 0) { + if (sl > 0) { + // static IP overrides hostname (HDCP stuff) + wifi_station_dhcpc_stop(); + struct ip_info ipi; + bool ok = parse_ip(staticip, &ipi.ip); + if (nl > 0) ok = ok && parse_ip(netmask, &ipi.netmask); + else IP4_ADDR(&ipi.netmask, 255, 255, 255, 0); + if (gl > 0) ok = ok && parse_ip(gateway, &ipi.gw); + else ipi.gw.addr = 0; + if (ok) { + os_printf("Setting static IP: %s\n", staticip); + ok = wifi_set_ip_info(0, &ipi); + if (ok) os_printf("Static IP set: %s\n", staticip); +#ifdef DEBUGIP + debugIP(); +#endif + jsonHeader(connData, ok ? 200: 400); + return HTTPD_CGI_DONE; + } + } else { + // no static IP, set hostname + if (hl == 0) os_strcpy(hostname, "esp-link"); + if (wifi_station_dhcpc_status() == DHCP_STARTED) + wifi_station_dhcpc_stop(); + bool hok = wifi_station_set_hostname(hostname); + if (hok) { + os_strcpy(flashConfig.hostname, hostname); + hok = hok && configSave(); + } + hok = hok && wifi_station_dhcpc_start(); + if (hok) os_printf("DHCP hostname set: %s\n", hostname); + jsonHeader(connData, hok ? 200 : 400); + if (!hok) httpdSend(connData, "Error setting hostname or starting DHCP", -1); + return HTTPD_CGI_DONE; + } + } + + jsonHeader(connData, 400); + httpdSend(connData, "Cannot parse hostname or staticip", -1); + return HTTPD_CGI_DONE; +} + //This cgi changes the operating mode: STA / AP / STA+AP int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { int len; @@ -386,9 +482,10 @@ int ICACHE_FLASH_ATTR printWifiInfo(char *buff) { 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); + len += os_sprintf(buff+len, ", \"ip\": \"%d.%d.%d.%d\"", IP2STR(&info.ip.addr)); + len += os_sprintf(buff+len, ", \"netmask\": \"%d.%d.%d.%d\"", IP2STR(&info.netmask.addr)); + len += os_sprintf(buff+len, ", \"gateway\": \"%d.%d.%d.%d\"", IP2STR(&info.gw.addr)); + len += os_sprintf(buff+len, ", \"hostname\": \"%s\"", flashConfig.hostname); } else { len += os_sprintf(buff+len, ", \"ip\": \"-none-\""); } @@ -449,7 +546,7 @@ int ICACHE_FLASH_ATTR cgiWifiInfo(HttpdConnData *connData) { // 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"); + wifi_station_set_hostname(flashConfig.hostname); int x = wifi_get_opmode() & 0x3; os_printf("Wifi init, mode=%s\n", wifiMode[x]); wifi_set_phy_mode(2); diff --git a/user/cgiwifi.h b/user/cgiwifi.h index 847e605..557c31a 100644 --- a/user/cgiwifi.h +++ b/user/cgiwifi.h @@ -11,6 +11,7 @@ int cgiWiFi(HttpdConnData *connData); int cgiWiFiConnect(HttpdConnData *connData); int cgiWiFiSetMode(HttpdConnData *connData); int cgiWiFiConnStatus(HttpdConnData *connData); +int cgiWiFiSpecial(HttpdConnData *connData); void wifiInit(void); #endif diff --git a/user/log.c b/user/log.c index cf63760..7236ef5 100644 --- a/user/log.c +++ b/user/log.c @@ -20,9 +20,11 @@ static bool log_newline; // at start of a new line void ICACHE_FLASH_ATTR log_uart(bool enable) { if (!enable && !log_no_uart) { +#if 0 os_printf("Turning OFF uart log\n"); os_delay_us(4*1000L); // time for uart to flush log_no_uart = !enable; +#endif } else if (enable && log_no_uart) { log_no_uart = !enable; os_printf("Turning ON uart log\n"); diff --git a/user/user_main.c b/user/user_main.c index 5471faf..af3b37b 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -26,8 +26,6 @@ #include "console.h" #include "config.h" #include "log.h" -#define MCU_RESET 12 -#define MCU_ISP 13 #include //#define SHOW_HEAP_USE @@ -88,6 +86,7 @@ HttpdBuiltInUrl builtInUrls[]={ {"/wifi/connect", cgiWiFiConnect, NULL}, {"/wifi/connstatus", cgiWiFiConnStatus, NULL}, {"/wifi/setmode", cgiWiFiSetMode, NULL}, + {"/wifi/special", cgiWiFiSpecial, NULL}, {"/pins", cgiPins, NULL}, {"*", cgiEspFsHook, NULL}, //Catch-all cgi function for the filesystem @@ -113,31 +112,32 @@ static char *rst_codes[] = { "normal", "wdt reset", "exception", "soft wdt", "restart", "deep sleep", "???", }; +# define VERS_STR_STR(V) #V +# define VERS_STR(V) VERS_STR_STR(V) +char *esp_link_version = VERS_STR(VERSION); + //Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done. void user_init(void) { - // init gpio pins used to reset&reprogram attached microcontrollers + // get the flash config so we know how to init things + //configWipe(); // uncomment to reset the config for testing purposes + bool restoreOk = configRestore(); + // init gpio pin registers gpio_init(); - // put MCU into reset in case it interferes with serial-programming of the esp8266 - //GPIO_OUTPUT_SET(MCU_RESET, 0); // init UART - uart_init(BIT_RATE_115200, BIT_RATE_115200); + uart_init(flashConfig.baud_rate, 115200); + logInit(); // must come after init of uart // say hello (leave some time to cause break in TX after boot loader's msg os_delay_us(10000L); -# define VERS_STR_STR(V) #V -# define VERS_STR(V) VERS_STR_STR(V) - os_printf("\n\nInitializing esp-link\n" VERS_STR(VERSION) "\n"); - //configWipe(); - if (configRestore()) os_printf("Flash config restored\n"); - else os_printf("*** Flash config restore failed, using defaults ***\n"); + os_printf("\n\n** %s\n", esp_link_version); + os_printf("Flash config restore %s\n", restoreOk ? "ok" : "*FAILED*"); // Status LEDs statusInit(); serledInit(); - logInit(); // Wifi wifiInit(); // init the flash filesystem with the html stuff EspFsInitResult res = espFsInit(&_binary_espfs_img_start); - os_printf("espFsInit(0x%08lx) returned %d\n", (uint32_t)&_binary_espfs_img_start, res); + os_printf("espFsInit %s\n", res?"ok":"ERR"); // mount the http handlers httpdInit(builtInUrls, 80); // init the wifi-serial transparent bridge (port 23)