From 896693b5b2173379e5e43f9189d9d5d19e5afada Mon Sep 17 00:00:00 2001 From: KatAst Date: Sun, 27 Dec 2015 13:11:03 +0100 Subject: [PATCH] Soft-AP Settings Added Soft-AP settings support both in Makefile and web interface --- Makefile | 12 +- esp-link/cgi.c | 5 +- esp-link/cgiwifi.c | 1155 ++++++++++++++----------- esp-link/cgiwifi.h | 2 + esp-link/main.c | 20 +- html/wifi/wifiAp.html | 124 +++ html/wifi/wifiAp.js | 98 +++ html/wifi/{wifi.html => wifiSta.html} | 8 +- html/wifi/{wifi.js => wifiSta.js} | 0 9 files changed, 918 insertions(+), 506 deletions(-) create mode 100644 html/wifi/wifiAp.html create mode 100644 html/wifi/wifiAp.js rename html/wifi/{wifi.html => wifiSta.html} (96%) rename html/wifi/{wifi.js => wifiSta.js} (100%) diff --git a/Makefile b/Makefile index 95e2b82..98660ae 100644 --- a/Makefile +++ b/Makefile @@ -35,12 +35,12 @@ # Max connections default 4, ( 1 ~ 4 ) # Beacon interval default 100, ( 100 ~ 60000ms ) -AP_SSID ?=esp-link-test -AP_PASS ?=esp-link-test -# AP_AUTH_MODE ?=AUTH_WPA_WPA2_PSK -# AP_SSID_HIDDEN ?=0 -# AP_MAX_CONN ?=3 -# AP_BEACON_INTERVAL ?=150 +# AP_SSID ?= +# AP_PASS ?= +# AP_AUTH_MODE ?= +# AP_SSID_HIDDEN ?= +# AP_MAX_CONN ?= +# AP_BEACON_INTERVAL ?= # If CHANGE_TO_STA is set to "yes" the esp-link module will switch to station mode diff --git a/esp-link/cgi.c b/esp-link/cgi.c index 081ef49..c658fb6 100644 --- a/esp-link/cgi.c +++ b/esp-link/cgi.c @@ -106,7 +106,7 @@ int8_t ICACHE_FLASH_ATTR getUInt16Arg(HttpdConnData *connData, char *name, uint1 return 1; } -int8_t ICACHE_FLASH_ATTR getBoolArg(HttpdConnData *connData, char *name, bool *config) { +int8_t ICACHE_FLASH_ATTR getBoolArg(HttpdConnData *connData, char *name, uint8_t *config) { char buff[16]; int len = httpdFindArg(connData->getArgs, name, buff, sizeof(buff)); if (len < 0) return 0; // not found, skip @@ -206,7 +206,8 @@ int ICACHE_FLASH_ATTR cgiMenu(HttpdConnData *connData) { "{ " "\"menu\": [ " "\"Home\", \"/home.html\", " - "\"WiFI\", \"/wifi/wifi.html\", " + "\"WiFi Station\", \"/wifi/wifiSta.html\", " + "\"WiFi Soft-AP\", \"/wifi/wifiAp.html\", " "\"µC Console\", \"/console.html\", " "\"Services\", \"/services.html\", " #ifdef MQTT diff --git a/esp-link/cgiwifi.c b/esp-link/cgiwifi.c index cf36135..be63d85 100644 --- a/esp-link/cgiwifi.c +++ b/esp-link/cgiwifi.c @@ -1,7 +1,3 @@ -/* - Cgi/template routines for the /wifi url. - */ - /* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): @@ -11,6 +7,8 @@ * ---------------------------------------------------------------------------- * Heavily modified and enhanced by Thorsten von Eicken in 2015 * ---------------------------------------------------------------------------- + * Once again heavily modified to add soft-ap settings by KatAst in 2015 + * ---------------------------------------------------------------------------- */ #include @@ -34,22 +32,23 @@ bool mdns_started = false; // ===== wifi status change callbacks static WifiStateChangeCb wifi_state_change_cb[4]; -// Temp store for new ap info. -static struct station_config stconf; +// Temp store for new staion config +struct station_config stconf; // Temp store for new ap config -static struct softap_config apconf; +struct softap_config apconf; uint8_t wifiState = wifiIsDisconnected; + // reasons for which a connection failed uint8_t wifiReason = 0; static char *wifiReasons[] = { - "", "unspecified", "auth_expire", "auth_leave", "assoc_expire", "assoc_toomany", "not_authed", - "not_assoced", "assoc_leave", "assoc_not_authed", "disassoc_pwrcap_bad", "disassoc_supchan_bad", - "ie_invalid", "mic_failure", "4way_handshake_timeout", "group_key_update_timeout", - "ie_in_4way_differs", "group_cipher_invalid", "pairwise_cipher_invalid", "akmp_invalid", - "unsupp_rsn_ie_version", "invalid_rsn_ie_cap", "802_1x_auth_failed", "cipher_suite_rejected", - "beacon_timeout", "no_ap_found" }; + "", "unspecified", "auth_expire", "auth_leave", "assoc_expire", "assoc_toomany", "not_authed", + "not_assoced", "assoc_leave", "assoc_not_authed", "disassoc_pwrcap_bad", "disassoc_supchan_bad", + "ie_invalid", "mic_failure", "4way_handshake_timeout", "group_key_update_timeout", + "ie_in_4way_differs", "group_cipher_invalid", "pairwise_cipher_invalid", "akmp_invalid", + "unsupp_rsn_ie_version", "invalid_rsn_ie_cap", "802_1x_auth_failed", "cipher_suite_rejected", + "beacon_timeout", "no_ap_found" }; static char *wifiMode[] = { 0, "STA", "AP", "AP+STA" }; static char *wifiPhy[] = { 0, "11b", "11g", "11n" }; @@ -57,100 +56,100 @@ static char *wifiPhy[] = { 0, "11b", "11g", "11n" }; void (*wifiStatusCb)(uint8_t); // callback when wifi status changes static char* ICACHE_FLASH_ATTR wifiGetReason(void) { - if (wifiReason <= 24) return wifiReasons[wifiReason]; - if (wifiReason >= 200 && wifiReason <= 201) return wifiReasons[wifiReason-200+24]; - return wifiReasons[1]; + if (wifiReason <= 24) return wifiReasons[wifiReason]; + if (wifiReason >= 200 && wifiReason <= 201) return wifiReasons[wifiReason-200+24]; + return wifiReasons[1]; } // handler for wifi status change callback coming in from espressif library static void ICACHE_FLASH_ATTR wifiHandleEventCb(System_Event_t *evt) { - switch (evt->event) { - case EVENT_STAMODE_CONNECTED: - wifiState = wifiIsConnected; - wifiReason = 0; - DBG("Wifi connected to ssid %s, ch %d\n", evt->event_info.connected.ssid, - evt->event_info.connected.channel); - statusWifiUpdate(wifiState); - break; - case EVENT_STAMODE_DISCONNECTED: - wifiState = wifiIsDisconnected; - wifiReason = evt->event_info.disconnected.reason; - DBG("Wifi disconnected from ssid %s, reason %s (%d)\n", - evt->event_info.disconnected.ssid, wifiGetReason(), evt->event_info.disconnected.reason); - statusWifiUpdate(wifiState); - break; - case EVENT_STAMODE_AUTHMODE_CHANGE: - DBG("Wifi auth mode: %d -> %d\n", - evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode); - break; - case EVENT_STAMODE_GOT_IP: - wifiState = wifiGotIP; - wifiReason = 0; - DBG("Wifi got ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR "\n", - IP2STR(&evt->event_info.got_ip.ip), IP2STR(&evt->event_info.got_ip.mask), - IP2STR(&evt->event_info.got_ip.gw)); - statusWifiUpdate(wifiState); - if (!mdns_started) - wifiStartMDNS(evt->event_info.got_ip.ip); - break; - case EVENT_SOFTAPMODE_STACONNECTED: - DBG("Wifi AP: station " MACSTR " joined, AID = %d\n", - MAC2STR(evt->event_info.sta_connected.mac), evt->event_info.sta_connected.aid); - break; - case EVENT_SOFTAPMODE_STADISCONNECTED: - DBG("Wifi AP: station " MACSTR " left, AID = %d\n", - MAC2STR(evt->event_info.sta_disconnected.mac), evt->event_info.sta_disconnected.aid); - break; - default: - break; - } - - for (int i = 0; i < 4; i++) { - if (wifi_state_change_cb[i] != NULL) (wifi_state_change_cb[i])(wifiState); - } + switch (evt->event) { + case EVENT_STAMODE_CONNECTED: + wifiState = wifiIsConnected; + wifiReason = 0; + DBG("Wifi connected to ssid %s, ch %d\n", evt->event_info.connected.ssid, + evt->event_info.connected.channel); + statusWifiUpdate(wifiState); + break; + case EVENT_STAMODE_DISCONNECTED: + wifiState = wifiIsDisconnected; + wifiReason = evt->event_info.disconnected.reason; + DBG("Wifi disconnected from ssid %s, reason %s (%d)\n", + evt->event_info.disconnected.ssid, wifiGetReason(), evt->event_info.disconnected.reason); + statusWifiUpdate(wifiState); + break; + case EVENT_STAMODE_AUTHMODE_CHANGE: + DBG("Wifi auth mode: %d -> %d\n", + evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode); + break; + case EVENT_STAMODE_GOT_IP: + wifiState = wifiGotIP; + wifiReason = 0; + DBG("Wifi got ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR "\n", + IP2STR(&evt->event_info.got_ip.ip), IP2STR(&evt->event_info.got_ip.mask), + IP2STR(&evt->event_info.got_ip.gw)); + statusWifiUpdate(wifiState); + if (!mdns_started) + wifiStartMDNS(evt->event_info.got_ip.ip); + break; + case EVENT_SOFTAPMODE_STACONNECTED: + DBG("Wifi AP: station " MACSTR " joined, AID = %d\n", + MAC2STR(evt->event_info.sta_connected.mac), evt->event_info.sta_connected.aid); + break; + case EVENT_SOFTAPMODE_STADISCONNECTED: + DBG("Wifi AP: station " MACSTR " left, AID = %d\n", + MAC2STR(evt->event_info.sta_disconnected.mac), evt->event_info.sta_disconnected.aid); + break; + default: + break; + } + + for (int i = 0; i < 4; i++) { + if (wifi_state_change_cb[i] != NULL) (wifi_state_change_cb[i])(wifiState); + } } void ICACHE_FLASH_ATTR wifiAddStateChangeCb(WifiStateChangeCb cb) { - for (int i = 0; i < 4; i++) { - if (wifi_state_change_cb[i] == cb) return; - if (wifi_state_change_cb[i] == NULL) { - wifi_state_change_cb[i] = cb; - return; - } + for (int i = 0; i < 4; i++) { + if (wifi_state_change_cb[i] == cb) return; + if (wifi_state_change_cb[i] == NULL) { + wifi_state_change_cb[i] = cb; + return; } - DBG("WIFI: max state change cb count exceeded\n"); + } + DBG("WIFI: max state change cb count exceeded\n"); } void ICACHE_FLASH_ATTR wifiStartMDNS(struct ip_addr ip) { - if (flashConfig.mdns_enable) { - struct mdns_info *mdns_info = (struct mdns_info *)os_zalloc(sizeof(struct mdns_info)); - mdns_info->host_name = flashConfig.hostname; - mdns_info->server_name = flashConfig.mdns_servername; - mdns_info->server_port = 80; - mdns_info->ipAddr = ip.addr; - espconn_mdns_init(mdns_info); - } - else { - espconn_mdns_server_unregister(); - espconn_mdns_close(); - } - mdns_started = true; + if (flashConfig.mdns_enable) { + struct mdns_info *mdns_info = (struct mdns_info *)os_zalloc(sizeof(struct mdns_info)); + mdns_info->host_name = flashConfig.hostname; + mdns_info->server_name = flashConfig.mdns_servername; + mdns_info->server_port = 80; + mdns_info->ipAddr = ip.addr; + espconn_mdns_init(mdns_info); + } + else { + espconn_mdns_server_unregister(); + espconn_mdns_close(); + } + mdns_started = true; } // ===== wifi scanning //WiFi access point data typedef struct { - char ssid[32]; - sint8 rssi; - char enc; + char ssid[32]; + sint8 rssi; + char enc; } ApData; //Scan result typedef struct { - char scanInProgress; //if 1, don't access the underlying stuff from the webpage. - ApData **apData; - int noAps; + char scanInProgress; //if 1, don't access the underlying stuff from the webpage. + ApData **apData; + int noAps; } ScanResultData; //Static scan status storage. @@ -159,126 +158,135 @@ static ScanResultData cgiWifiAps; //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; - struct bss_info *bss_link = (struct bss_info *)arg; - - if (status!=OK) { - DBG("wifiScanDoneCb status=%d\n", status); - cgiWifiAps.scanInProgress=0; - return; - } - - //Clear prev ap data if needed. - if (cgiWifiAps.apData!=NULL) { - for (n=0; nnext.stqe_next; - n++; - } - //Allocate memory for access point data - cgiWifiAps.apData=(ApData **)os_malloc(sizeof(ApData *)*n); - cgiWifiAps.noAps=n; - DBG("Scan done: found %d APs\n", n); - - //Copy access point data to the static struct - n=0; - bss_link = (struct bss_info *)arg; - while (bss_link != NULL) { - if (n>=cgiWifiAps.noAps) { - //This means the bss_link changed under our nose. Shouldn't happen! - //Break because otherwise we will write in unallocated memory. - DBG("Huh? I have more than the allocated %d aps!\n", cgiWifiAps.noAps); - break; - } - //Save the ap data. - cgiWifiAps.apData[n]=(ApData *)os_malloc(sizeof(ApData)); - cgiWifiAps.apData[n]->rssi=bss_link->rssi; - cgiWifiAps.apData[n]->enc=bss_link->authmode; - strncpy(cgiWifiAps.apData[n]->ssid, (char*)bss_link->ssid, 32); - DBG("bss%d: %s (%d)\n", n+1, (char*)bss_link->ssid, bss_link->rssi); - - bss_link = bss_link->next.stqe_next; - n++; - } - //We're done. + int n; + struct bss_info *bss_link = (struct bss_info *)arg; + + if (status!=OK) { + DBG("wifiScanDoneCb status=%d\n", status); cgiWifiAps.scanInProgress=0; + return; + } + + //Clear prev ap data if needed. + if (cgiWifiAps.apData!=NULL) { + for (n=0; nnext.stqe_next; + n++; + } + //Allocate memory for access point data + cgiWifiAps.apData=(ApData **)os_malloc(sizeof(ApData *)*n); + cgiWifiAps.noAps=n; + DBG("Scan done: found %d APs\n", n); + + //Copy access point data to the static struct + n=0; + bss_link = (struct bss_info *)arg; + while (bss_link != NULL) { + if (n>=cgiWifiAps.noAps) { + //This means the bss_link changed under our nose. Shouldn't happen! + //Break because otherwise we will write in unallocated memory. + DBG("Huh? I have more than the allocated %d aps!\n", cgiWifiAps.noAps); + break; + } + //Save the ap data. + cgiWifiAps.apData[n]=(ApData *)os_malloc(sizeof(ApData)); + cgiWifiAps.apData[n]->rssi=bss_link->rssi; + cgiWifiAps.apData[n]->enc=bss_link->authmode; + strncpy(cgiWifiAps.apData[n]->ssid, (char*)bss_link->ssid, 32); + DBG("bss%d: %s (%d)\n", n+1, (char*)bss_link->ssid, bss_link->rssi); + + bss_link = bss_link->next.stqe_next; + n++; + } + //We're done. + cgiWifiAps.scanInProgress=0; } static ETSTimer scanTimer; static void ICACHE_FLASH_ATTR scanStartCb(void *arg) { - DBG("Starting a scan\n"); - wifi_station_scan(NULL, wifiScanDoneCb); + DBG("Starting a scan\n"); + wifi_station_scan(NULL, wifiScanDoneCb); } static int ICACHE_FLASH_ATTR cgiWiFiStartScan(HttpdConnData *connData) { - if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. - jsonHeader(connData, 200); - if (!cgiWifiAps.scanInProgress) { - cgiWifiAps.scanInProgress = 1; - os_timer_disarm(&scanTimer); - os_timer_setfn(&scanTimer, scanStartCb, NULL); - os_timer_arm(&scanTimer, 200, 0); - } - return HTTPD_CGI_DONE; + if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. + jsonHeader(connData, 200); + if (!cgiWifiAps.scanInProgress) { + cgiWifiAps.scanInProgress = 1; + os_timer_disarm(&scanTimer); + os_timer_setfn(&scanTimer, scanStartCb, NULL); + os_timer_arm(&scanTimer, 200, 0); + } + return HTTPD_CGI_DONE; } static int ICACHE_FLASH_ATTR cgiWiFiGetScan(HttpdConnData *connData) { - if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. - char buff[1460]; - const int chunk = 1460/64; // ssid is up to 32 chars - int len = 0; - - os_printf("GET scan: cgiData=%d noAps=%d\n", (int)connData->cgiData, cgiWifiAps.noAps); - - // handle continuation call, connData->cgiData-1 is the position in the scan results where we - // we need to continue sending from (using -1 'cause 0 means it's the first call) - if (connData->cgiData) { - int next = (int)connData->cgiData-1; - int pos = next; - while (pos < cgiWifiAps.noAps && pos < next+chunk) { - len += os_sprintf(buff+len, "{\"essid\": \"%s\", \"rssi\": %d, \"enc\": \"%d\"}%c\n", - cgiWifiAps.apData[pos]->ssid, cgiWifiAps.apData[pos]->rssi, cgiWifiAps.apData[pos]->enc, - (pos+1 == cgiWifiAps.noAps) ? ' ' : ','); - pos++; - } - // done or more? - if (pos == cgiWifiAps.noAps) { - len += os_sprintf(buff+len, "]}}\n"); - httpdSend(connData, buff, len); - return HTTPD_CGI_DONE; - } else { - connData->cgiData = (void*)(pos+1); - httpdSend(connData, buff, len); - return HTTPD_CGI_MORE; - } + if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. + char buff[1460]; + const int chunk = 1460/64; // ssid is up to 32 chars + int len = 0; + + os_printf("GET scan: cgiData=%d noAps=%d\n", (int)connData->cgiData, cgiWifiAps.noAps); + + // handle continuation call, connData->cgiData-1 is the position in the scan results where we + // we need to continue sending from (using -1 'cause 0 means it's the first call) + if (connData->cgiData) { + int next = (int)connData->cgiData-1; + int pos = next; + while (pos < cgiWifiAps.noAps && pos < next+chunk) { + len += os_sprintf(buff+len, "{\"essid\": \"%s\", \"rssi\": %d, \"enc\": \"%d\"}%c\n", + cgiWifiAps.apData[pos]->ssid, cgiWifiAps.apData[pos]->rssi, cgiWifiAps.apData[pos]->enc, + (pos+1 == cgiWifiAps.noAps) ? ' ' : ','); + pos++; } - - 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"); - httpdSend(connData, buff, len); - return HTTPD_CGI_DONE; + // done or more? + if (pos == cgiWifiAps.noAps) { + len += os_sprintf(buff+len, "]}}\n"); + httpdSend(connData, buff, len); + return HTTPD_CGI_DONE; + } else { + connData->cgiData = (void*)(pos+1); + httpdSend(connData, buff, len); + return HTTPD_CGI_MORE; } - - len = os_sprintf(buff, "{\"result\": {\"inProgress\": \"0\", \"APs\": [\n"); - connData->cgiData = (void *)1; // start with first result next time we're called + } + + 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"); httpdSend(connData, buff, len); - return HTTPD_CGI_MORE; + return HTTPD_CGI_DONE; + } + + len = os_sprintf(buff, "{\"result\": {\"inProgress\": \"0\", \"APs\": [\n"); + connData->cgiData = (void *)1; // start with first result next time we're called + httpdSend(connData, buff, len); + return HTTPD_CGI_MORE; } 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 { + }else if(connData->requestType == HTTPD_METHOD_POST) + { + // DO NOT start APs scan in AP mode + int mode = wifi_get_opmode(); + if(mode==2){ + jsonHeader(connData, 400); + return HTTPD_CGI_DONE; + }else{ + return cgiWiFiStartScan(connData); + } + }else{ jsonHeader(connData, 404); return HTTPD_CGI_DONE; } @@ -290,39 +298,32 @@ int ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) { #define RESET_TIMEOUT (15000) // 15 seconds static ETSTimer resetTimer; -// 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. If it fails, it ensures -// that the module is in STA+AP mode so the user has a chance to recover. +/* + * This routine is ran some time after a connection attempt to an access point. + * If the connection succeeds and Makefile hard-coded CHANGE_TO_STA is set to yes, this gets the module in STA-only mode. + * If it fails and only STA mode is set, it ensures that the module is in STA+AP mode so the user has a chance to recover. + */ static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { + int x = wifi_station_get_connect_status(); int m = wifi_get_opmode() & 0x3; DBG("Wifi check: mode=%s status=%d\n", wifiMode[m], x); - if (x == STATION_GOT_IP) { - if (m != 1) { -#ifdef CHANGE_TO_STA - // We're happily connected, go to STA mode - DBG("Wifi got IP. Going into STA mode..\n"); - wifi_set_opmode(1); - os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); // check one more time after switching to STA-only -#endif - } - log_uart(false); - // no more resetTimer at this point, gotta use physical reset to recover if in trouble - } else { - - if (m != 3) { - DBG("Wifi connect failed. Going into STA+AP mode..\n"); - // Set STA+AP mode - wifi_set_opmode(3); -#ifdef AP_SSID - // Call ap set after mode change to AP or STA+AP - wifi_softap_set_config(&apconf); -#endif + if(m!=2){ + if( x == STATION_GOT_IP ){ + #ifdef CHANGE_TO_STA + wifi_set_opmode(1); + #endif + log_uart(false); + }else{ + log_uart(true); + DBG("Enabling/continuing uart log\n"); + if (m==1){ + wifi_set_opmode(3); + wifi_softap_set_config(&apconf); + } + os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); } - log_uart(true); - DBG("Enabling/continuing uart log\n"); - os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); } } @@ -331,191 +332,347 @@ static ETSTimer reassTimer; // Callback actually doing reassociation static void ICACHE_FLASH_ATTR reassTimerCb(void *arg) { - DBG("Wifi changing association\n"); - wifi_station_disconnect(); - stconf.bssid_set = 0; - wifi_station_set_config(&stconf); - wifi_station_connect(); - // Schedule check, we give some extra time (4x) 'cause the reassociation can cause the AP - // to have to change channel, and then the client needs to follow before it can see the - // IP address - os_timer_disarm(&resetTimer); - os_timer_setfn(&resetTimer, resetTimerCb, NULL); - os_timer_arm(&resetTimer, 4*RESET_TIMEOUT, 0); + DBG("Wifi changing association\n"); + wifi_station_disconnect(); + stconf.bssid_set = 0; + wifi_station_set_config(&stconf); + wifi_station_connect(); + // Schedule check, we give some extra time (4x) 'cause the reassociation can cause the AP + // to have to change channel, and then the client needs to follow before it can see the + // IP address + os_timer_disarm(&resetTimer); + os_timer_setfn(&resetTimer, resetTimerCb, NULL); + os_timer_arm(&resetTimer, 4*RESET_TIMEOUT, 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 cgiWiFiConnect(HttpdConnData *connData) { - char essid[128]; - char passwd[128]; - - 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)); - - if (el > 0 && pl >= 0) { - //Set to 0 if you want to disable the actual reconnecting bit - os_strncpy((char*)stconf.ssid, essid, 32); - os_strncpy((char*)stconf.password, passwd, 64); - DBG("Wifi try to connect to AP %s pw %s\n", essid, passwd); - - //Schedule disconnect/connect - os_timer_disarm(&reassTimer); - os_timer_setfn(&reassTimer, reassTimerCb, NULL); - os_timer_arm(&reassTimer, 1000, 0); // 1 second for the response of this request to make it - jsonHeader(connData, 200); - } else { + + int mode = wifi_get_opmode(); + if(mode == 2){ jsonHeader(connData, 400); - httpdSend(connData, "Cannot parse ssid or password", -1); + httpdSend(connData, "Can't associate to an AP en SoftAP mode", -1); + return HTTPD_CGI_DONE; } - return HTTPD_CGI_DONE; + + char essid[128]; + char passwd[128]; + + 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)); + + if (el > 0 && pl >= 0) { + //Set to 0 if you want to disable the actual reconnecting bit + os_strncpy((char*)stconf.ssid, essid, 32); + os_strncpy((char*)stconf.password, passwd, 64); + DBG("Wifi try to connect to AP %s pw %s\n", essid, passwd); + + //Schedule disconnect/connect + os_timer_disarm(&reassTimer); + os_timer_setfn(&reassTimer, reassTimerCb, NULL); + os_timer_arm(&reassTimer, 1000, 0); // 1 second for the response of this request to make it + jsonHeader(connData, 200); + } else { + jsonHeader(connData, 400); + httpdSend(connData, "Cannot parse ssid or password", -1); + } + jsonHeader(connData, 400); + httpdSend(connData, "Invalid ssid or password", -1); + return HTTPD_CGI_DONE; } static bool ICACHE_FLASH_ATTR 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; + 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; } - return false; + if (c < '0' || c > '9') return false; + } + return false; } #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\"\n", wifi_station_get_hostname()); - } else { - os_printf("\"ip\": \"-none-\"\n"); - } + 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\"\n", wifi_station_get_hostname()); + } else { + os_printf("\"ip\": \"-none-\"\n"); + } } #endif // configure Wifi, specifically DHCP vs static IP address based on flash config void ICACHE_FLASH_ATTR configWifiIP() { - if (flashConfig.staticip == 0) { - // let's DHCP! - wifi_station_set_hostname(flashConfig.hostname); - if (wifi_station_dhcpc_status() == DHCP_STARTED) - wifi_station_dhcpc_stop(); - wifi_station_dhcpc_start(); - DBG("Wifi uses DHCP, hostname=%s\n", flashConfig.hostname); - } else { - // no DHCP, we got static network config! - wifi_station_dhcpc_stop(); - struct ip_info ipi; - ipi.ip.addr = flashConfig.staticip; - ipi.netmask.addr = flashConfig.netmask; - ipi.gw.addr = flashConfig.gateway; - wifi_set_ip_info(0, &ipi); - DBG("Wifi uses static IP %d.%d.%d.%d\n", IP2STR(&ipi.ip.addr)); - } + if (flashConfig.staticip == 0) { + // let's DHCP! + wifi_station_set_hostname(flashConfig.hostname); + if (wifi_station_dhcpc_status() == DHCP_STARTED) + wifi_station_dhcpc_stop(); + wifi_station_dhcpc_start(); + DBG("Wifi uses DHCP, hostname=%s\n", flashConfig.hostname); + } else { + // no DHCP, we got static network config! + wifi_station_dhcpc_stop(); + struct ip_info ipi; + ipi.ip.addr = flashConfig.staticip; + ipi.netmask.addr = flashConfig.netmask; + ipi.gw.addr = flashConfig.gateway; + wifi_set_ip_info(0, &ipi); + DBG("Wifi uses static IP %d.%d.%d.%d\n", IP2STR(&ipi.ip.addr)); + } #ifdef DEBUGIP - debugIP(); + debugIP(); #endif } // Change special settings int ICACHE_FLASH_ATTR cgiWiFiSpecial(HttpdConnData *connData) { - char dhcp[8]; - char staticip[20]; - char netmask[20]; - char gateway[20]; - - if (connData->conn==NULL) return HTTPD_CGI_DONE; + char dhcp[8]; + char staticip[20]; + char netmask[20]; + char gateway[20]; + + if (connData->conn==NULL) return HTTPD_CGI_DONE; + + // get args and their string lengths + int dl = httpdFindArg(connData->getArgs, "dhcp", dhcp, sizeof(dhcp)); + 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 (!(dl > 0 && sl >= 0 && nl >= 0 && gl >= 0)) { + jsonHeader(connData, 400); + httpdSend(connData, "Request is missing fields", -1); + return HTTPD_CGI_DONE; + } + + char url[64]; // redirect URL + if (os_strcmp(dhcp, "off") == 0) { + // parse static IP params + 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) { + jsonHeader(connData, 400); + httpdSend(connData, "Cannot parse static IP config", -1); + return HTTPD_CGI_DONE; + } + // save the params in flash + flashConfig.staticip = ipi.ip.addr; + flashConfig.netmask = ipi.netmask.addr; + flashConfig.gateway = ipi.gw.addr; + // construct redirect URL + os_sprintf(url, "{\"url\": \"http://%d.%d.%d.%d\"}", IP2STR(&ipi.ip)); + + } else { + // dynamic IP + flashConfig.staticip = 0; + os_sprintf(url, "{\"url\": \"http://%s\"}", flashConfig.hostname); + } + + configSave(); // ignore error... + // schedule change-over + os_timer_disarm(&reassTimer); + os_timer_setfn(&reassTimer, configWifiIP, NULL); + os_timer_arm(&reassTimer, 1000, 0); // 1 second for the response of this request to make it + // return redirect info + jsonHeader(connData, 200); + httpdSend(connData, url, -1); + return HTTPD_CGI_DONE; +} + +// ==== Soft-AP related functions + +// Change Soft-AP main settings +int ICACHE_FLASH_ATTR cgiApSettingsChange(HttpdConnData *connData) { - // get args and their string lengths - int dl = httpdFindArg(connData->getArgs, "dhcp", dhcp, sizeof(dhcp)); - 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 (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. - if (!(dl > 0 && sl >= 0 && nl >= 0 && gl >= 0)) { + // No changes for Soft-AP in STA mode + int mode = wifi_get_opmode(); + if ( mode == 1 ){ jsonHeader(connData, 400); - httpdSend(connData, "Request is missing fields", -1); + httpdSend(connData, "No changes allowed in STA mode", -1); return HTTPD_CGI_DONE; } + // Get Soft-Ap config, just in case + wifi_softap_get_config(&apconf); + + char buff[96]; + int len; - char url[64]; // redirect URL - if (os_strcmp(dhcp, "off") == 0) { - // parse static IP params - 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) { + // Check extra security measure + len=httpdFindArg(connData->getArgs, "100", buff, sizeof(buff)); + if(len>0){ + if(atoi(buff)!=1){ jsonHeader(connData, 400); - httpdSend(connData, "Cannot parse static IP config", -1); return HTTPD_CGI_DONE; } - // save the params in flash - flashConfig.staticip = ipi.ip.addr; - flashConfig.netmask = ipi.netmask.addr; - flashConfig.gateway = ipi.gw.addr; - // construct redirect URL - os_sprintf(url, "{\"url\": \"http://%d.%d.%d.%d\"}", IP2STR(&ipi.ip)); + } + // Get the new SSID and set + len=httpdFindArg(connData->getArgs, "ap_ssid", buff, sizeof(buff)); + if(len>7 && len<30){ + // STRING PREPROCESSING DONE IN CLIENT SIDE + memset(apconf.ssid, 0, 32); + os_memcpy(apconf.ssid, buff, len); + }else{ + jsonHeader(connData, 400); + httpdSend(connData, "SSID name out of range", -1); + return HTTPD_CGI_DONE; + } + // Set new PASSWORD + len=httpdFindArg(connData->getArgs, "ap_password", buff, sizeof(buff)); + if(len>7 && len<62){ + // STRING PREPROCESSING DONE IN CLIENT SIDE + memset(apconf.password, 0, 64); + os_memcpy(apconf.password, buff, len); + }else{ + jsonHeader(connData, 400); + httpdSend(connData, "PASSWORD out of range", -1); + return HTTPD_CGI_DONE; + } + // Set max connection number + len=httpdFindArg(connData->getArgs, "ap_maxconn", buff, sizeof(buff)); + if(len>0){ - } else { - // dynamic IP - flashConfig.staticip = 0; - os_sprintf(url, "{\"url\": \"http://%s\"}", flashConfig.hostname); + int value = atoi(buff); + if(value > 0 && value <= 4){ + apconf.max_connection = value; + }else{ + // If out of range set by default + apconf.max_connection = 4; + } } + // Set beacon interval value + len=httpdFindArg(connData->getArgs, "ap_beacon", buff, sizeof(buff)); + if(len>0){ + int value = atoi(buff); + if(value >= 100 && value <= 60000){ + apconf.beacon_interval = value; + }else{ + // If out of range set by default + apconf.beacon_interval = 100; + } + } + // Set authentication mode + len=httpdFindArg(connData->getArgs, "ap_authmode", buff, sizeof(buff)); + if(len>0){ + int value = atoi(buff); + if(value >= 0 && value <= 4){ + apconf.authmode = value; + }else{ + // If out of range set by default + apconf.authmode = 4; + } + } + // Set ssid to be hidden or not + len=httpdFindArg(connData->getArgs, "ap_hidden", buff, sizeof(buff)); + if(len>0){ + int value = atoi(buff); + if(value == 0 || value == 1){ + apconf.ssid_hidden = value; + }else{ + // If out of range set by default + apconf.ssid_hidden = 0; + } + } + // Store new configuration + // This should apply new config values + wifi_softap_set_config(&apconf); + + jsonHeader(connData, 200); + return HTTPD_CGI_DONE; +} + +// Get current Soft-AP settings +int ICACHE_FLASH_ATTR cgiApSettingsInfo(HttpdConnData *connData) { + + char buff[1024]; + if (connData->conn == NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. + os_sprintf(buff, + "{ " + "\"ap_ssid\": \"%s\", " + "\"ap_password\": \"%s\", " + "\"ap_authmode\": %d, " + "\"ap_maxconn\": %d, " + "\"ap_beacon\": %d, " + "\"ap_hidden\": \"%s\" " + " }", + apconf.ssid, + apconf.password, + apconf.authmode, + apconf.max_connection, + apconf.beacon_interval, + apconf.ssid_hidden ? "enabled" : "disabled" + ); - configSave(); // ignore error... - // schedule change-over - os_timer_disarm(&reassTimer); - os_timer_setfn(&reassTimer, configWifiIP, NULL); - os_timer_arm(&reassTimer, 1000, 0); // 1 second for the response of this request to make it - // return redirect info jsonHeader(connData, 200); - httpdSend(connData, url, -1); + httpdSend(connData, buff, -1); return HTTPD_CGI_DONE; } +// ===== Wifi set mode end info functions + //This cgi changes the operating mode: STA / AP / STA+AP int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { + + if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. int len; char buff[1024]; - if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. + int previous_mode = wifi_get_opmode(); len=httpdFindArg(connData->getArgs, "mode", buff, sizeof(buff)); + + int next_mode = atoi(buff); + if (len!=0) { - int m = atoi(buff); - DBG("Wifi switching to mode %d\n", m); - wifi_set_opmode(m&3); - // Call softap set after changing to AP or STA+AP - wifi_softap_set_config(&apconf); - - if (m == 1) { - // STA-only mode, reset into STA+AP after a timeout if we don't get an IP address + if (next_mode == 2){ + // moving to AP mode, so disconnect before leave STA mode + wifi_station_disconnect(); + } + + DBG("Wifi switching to mode %d\n", next_mode); + wifi_set_opmode(next_mode&3); + + if (previous_mode == 2) { + // movint to STA-only mode from AP, so reset into STA+AP after a timeout if we don't get an IP address + stconf.bssid_set = 0; + wifi_station_set_config(&stconf); + wifi_station_connect(); os_timer_disarm(&resetTimer); os_timer_setfn(&resetTimer, resetTimerCb, NULL); os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); } + if(previous_mode == 1){ + // moving to STA or STA+AP, so softap config call needed + wifi_softap_set_config(&apconf); + } jsonHeader(connData, 200); } else { jsonHeader(connData, 400); @@ -523,15 +680,30 @@ int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { return HTTPD_CGI_DONE; } +// Collection of wifi info variables + static char *connStatuses[] = { "idle", "connecting", "wrong password", "AP not found", - "failed", "got IP address" }; + "failed", "got IP address" }; static char *wifiWarn[] = { 0, "Switch to STA+AP mode", - "Can't scan in this mode! Switch to STA+AP mode", + "Switch to STA+AP mode", "Switch to STA mode", }; +static char *apWifiWarn[] = { 0, + "Switch to STA+AP mode", + "Switch to STA+AP mode", + "Switch to AP mode", +}; + +static char *apAuthMode[] = { "OPEN", + "WEP", + "WPA_PSK", + "WPA2_PSK", + "WPA_WPA2_PSK", +}; + #ifdef CHANGE_TO_STA #define MODECHANGE "yes" #else @@ -540,176 +712,191 @@ static char *wifiWarn[] = { 0, // 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); - uint8_t chan = wifi_get_channel(); - - len = os_sprintf(buff, - "\"mode\": \"%s\", \"modechange\": \"%s\", \"ssid\": \"%s\", \"status\": \"%s\", \"phy\": \"%s\", " - "\"rssi\": \"%ddB\", \"warn\": \"%s\", \"mac\":\"%02x:%02x:%02x:%02x:%02x:%02x\", \"chan\":%d", - mode, MODECHANGE, (char*)stconf.ssid, status, phy, rssi, warn, - mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], chan); - - struct ip_info info; - if (wifi_get_ip_info(0, &info)) { - 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-\""); - } - len += os_sprintf(buff+len, ", \"staticip\": \"%d.%d.%d.%d\"", IP2STR(&flashConfig.staticip)); - len += os_sprintf(buff+len, ", \"dhcp\": \"%s\"", flashConfig.staticip > 0 ? "off" : "on"); - - return len; + + int len; + //struct station_config stconf; + wifi_station_get_config(&stconf); + //struct softap_config apconf; + wifi_softap_get_config(&apconf); + + 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]; + char *apwarn = apWifiWarn[op]; + char *apauth = apAuthMode[apconf.authmode]; + sint8 rssi = wifi_station_get_rssi(); + if (rssi > 0) rssi = 0; + uint8 mac_addr[6]; + uint8 apmac_addr[6]; + wifi_get_macaddr(0, mac_addr); + wifi_get_macaddr(1, apmac_addr); + uint8_t chan = wifi_get_channel(); + + len = os_sprintf(buff, + "\"mode\": \"%s\", \"modechange\": \"%s\", \"ssid\": \"%s\", \"status\": \"%s\", \"phy\": \"%s\", " + "\"rssi\": \"%ddB\", \"warn\": \"%s\", \"apwarn\": \"%s\",\"mac\":\"%02x:%02x:%02x:%02x:%02x:%02x\", \"chan\":\"%d\", \"apssid\": \"%s\", " + "\"appass\": \"%s\", \"apchan\": \"%d\", \"apmaxc\": \"%d\", \"aphidd\": \"%s\", \"apbeac\": \"%d\", \"apauth\": \"%s\",\"apmac\":\"%02x:%02x:%02x:%02x:%02x:%02x\"", + mode, MODECHANGE, (char*)stconf.ssid, status, phy, rssi, warn, apwarn, + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], chan, (char*)apconf.ssid,(char*)apconf.password,apconf.channel,apconf.max_connection,apconf.ssid_hidden?"enabled":"disabled",apconf.beacon_interval, apauth,apmac_addr[0], apmac_addr[1], apmac_addr[2], apmac_addr[3], apmac_addr[4], apmac_addr[5]); + + struct ip_info info; + if (wifi_get_ip_info(0, &info)) { + 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-\""); + } + len += os_sprintf(buff+len, ", \"staticip\": \"%d.%d.%d.%d\"", IP2STR(&flashConfig.staticip)); + len += os_sprintf(buff+len, ", \"dhcp\": \"%s\"", flashConfig.staticip > 0 ? "off" : "on"); + + return len; } int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) { - char buff[1024]; - int len; - - if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. - jsonHeader(connData, 200); - - len = os_sprintf(buff, "{"); - len += printWifiInfo(buff+len); - len += os_sprintf(buff+len, ", "); - - if (wifiReason != 0) { - len += os_sprintf(buff+len, "\"reason\": \"%s\", ", wifiGetReason()); - } - + char buff[1024]; + int len; + + if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. + jsonHeader(connData, 200); + + len = os_sprintf(buff, "{"); + len += printWifiInfo(buff+len); + len += os_sprintf(buff+len, ", "); + + if (wifiReason != 0) { + len += os_sprintf(buff+len, "\"reason\": \"%s\", ", wifiGetReason()); + } + #if 0 - // commented out 'cause often the client that requested the change can't get a request in to - // find out that it succeeded. Better to just wait the std 15 seconds... - int st=wifi_station_get_connect_status(); - if (st == STATION_GOT_IP) { - if (wifi_get_opmode() != 1) { - // Reset into AP-only mode sooner. - os_timer_disarm(&resetTimer); - os_timer_setfn(&resetTimer, resetTimerCb, NULL); - os_timer_arm(&resetTimer, 1000, 0); - } + // commented out 'cause often the client that requested the change can't get a request in to + // find out that it succeeded. Better to just wait the std 15 seconds... + int st=wifi_station_get_connect_status(); + if (st == STATION_GOT_IP) { + if (wifi_get_opmode() != 1) { + // Reset into AP-only mode sooner. + os_timer_disarm(&resetTimer); + os_timer_setfn(&resetTimer, resetTimerCb, NULL); + os_timer_arm(&resetTimer, 1000, 0); } + } #endif - - len += os_sprintf(buff+len, "\"x\":0}\n"); - //DBG(" -> %s\n", buff); - httpdSend(connData, buff, len); - return HTTPD_CGI_DONE; + + len += os_sprintf(buff+len, "\"x\":0}\n"); + DBG(" -> %s\n", buff); + httpdSend(connData, buff, len); + return HTTPD_CGI_DONE; } // Cgi to return various Wifi information int ICACHE_FLASH_ATTR cgiWifiInfo(HttpdConnData *connData) { - char buff[1024]; - - if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. - - os_strcpy(buff, "{"); - printWifiInfo(buff+1); - os_strcat(buff, "}"); - - jsonHeader(connData, 200); - httpdSend(connData, buff, -1); - return HTTPD_CGI_DONE; + char buff[1024]; + + if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. + + os_strcpy(buff, "{"); + printWifiInfo(buff+1); + os_strcat(buff, "}"); + + jsonHeader(connData, 200); + 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. +/* Init the wireless + * + * Call both Soft-AP and Station default config + * Change values according to Makefile hard-coded variables + * Anyway set wifi opmode to STA+AP, it will change to STA if CHANGE_TO_STA is set to yes in Makefile + * Call a timer to check the STA connection + */ void ICACHE_FLASH_ATTR wifiInit() { - + // Check te wifi opmode int x = wifi_get_opmode() & 0x3; -#ifdef CGIWIFI_DBG - os_printf("Wifi init, mode=%s\n",wifiMode[x]); -#endif + // Set opmode to 3 to let system scan aps, otherwise it won't scan + wifi_set_opmode(3); - // STATION parameters only on a full flash -#if defined(STA_SSID) && defined(STA_PASS) + // Call both STATION and SOFTAP default config + wifi_station_get_config_default(&stconf); + wifi_softap_get_config_default(&apconf); + + #ifdef CGIWIFI_DBG + os_printf("Wifi init, mode=%s\n",wifiMode[x]); + #endif + + // STATION parameters only on a full flash, because default opmode is 2 + #if defined(STA_SSID) && defined(STA_PASS) if( x == 2 ){ - // Create struct for station config - struct station_config stconf; - // Call it - wifi_station_get_config(&stconf); // Set parameters if (os_strlen((char*)stconf.ssid) == 0 && os_strlen((char*)stconf.password) == 0) { os_strncpy((char*)stconf.ssid, VERS_STR(STA_SSID), 32); os_strncpy((char*)stconf.password, VERS_STR(STA_PASS), 64); -#ifdef CGIWIFI_DBG + #ifdef CGIWIFI_DBG os_printf("Wifi pre-config trying to connect to AP %s pw %s\n",(char*)stconf.ssid, (char*)stconf.password); -#endif + #endif // wifi_set_phy_mode(2); // limit to 802.11b/g 'cause n is flaky - // Set wifi mode - wifi_set_opmode(3); // sta+ap, will switch to sta-only 15 secs after connecting stconf.bssid_set = 0; wifi_station_set_config(&stconf); } } -#endif - - // SOFT_AP parameters -#if defined(AP_SSID) && defined(AP_PASS) - // Call it - wifi_softap_get_config(&apconf); - // Clean memory and set the value of SSID - memset(apconf.ssid, 0, sizeof(apconf.ssid)); - os_memcpy(apconf.ssid, VERS_STR(AP_SSID), strlen(VERS_STR(AP_SSID))); - // Clean memory and set the value of PASS - memset(apconf.password, 0, sizeof(apconf.password)); - os_memcpy(apconf.password, VERS_STR(AP_PASS), strlen(VERS_STR(AP_PASS))); - // Specify the length of pass - apconf.ssid_len= os_strlen((char*)VERS_STR(AP_PASS)); -#ifdef AP_AUTH_MODE - // If set, use specified auth mode - apconf.authmode = AP_AUTH_MODE; -#else - // If not, use wpa wpa2 psk - apconf.authmode = AUTH_WPA_WPA2_PSK; -#endif -#ifdef AP_SSID_HIDDEN - // If set, use specified ssid hidden parameter - apconf.ssid_hidden = AP_SSID_HIDDEN; -#endif -#ifdef AP_MAX_CONN - // If set, use specified max conn number - apconf.max_connection = AP_MAX_CONN; -#endif -#ifdef AP_BEACON_INTERVAL - // If set use specified beacon interval - apconf.beacon_interval = AP_BEACON_INTERVAL; -#endif - // Set to use the new conf -#ifdef CGIWIFI_DBG - os_printf("Wifi AP parameters: %s pw %s\n",(char*)apconf.ssid, (char*)apconf.password); -#endif - // MUST BE called after enabling AP or STA+AP mode - wifi_softap_set_config(&apconf); -#endif // AP_SSID && AP_PASS - + #endif + + // Change SOFT_AP parameters if defined + #if defined(AP_SSID) && defined(AP_PASS) + // Clean memory and set the value of SSID + memset(apconf.ssid, 0, 32); + os_memcpy(apconf.ssid, VERS_STR(AP_SSID), strlen(VERS_STR(AP_SSID))); + + // Clean memory and set the value of PASS + memset(apconf.password, 0, 64); + os_memcpy(apconf.password, VERS_STR(AP_PASS), strlen(VERS_STR(AP_PASS))); + + // Specify the length of pass + apconf.ssid_len= os_strlen((char*)VERS_STR(AP_PASS)); + #ifdef AP_AUTH_MODE + // If set, use specified auth mode + apconf.authmode = AP_AUTH_MODE; + #else + // If not, use wpa wpa2 psk + apconf.authmode = AUTH_WPA_WPA2_PSK; + #endif + #ifdef AP_SSID_HIDDEN + // If set, use specified ssid hidden parameter + apconf.ssid_hidden = AP_SSID_HIDDEN; + #endif + #ifdef AP_MAX_CONN + // If set, use specified max conn number + apconf.max_connection = AP_MAX_CONN; + #endif + #ifdef AP_BEACON_INTERVAL + // If set use specified beacon interval + apconf.beacon_interval = AP_BEACON_INTERVAL; + #endif + // Check save softap config + bool softap_set_conf = wifi_softap_set_config(&apconf); + #ifdef CGIWIFI_DBG + // Debug info + os_printf("Wifi AP parameters: %s pw %s\n",(char*)apconf.ssid, (char*)apconf.password); + os_printf("Wifi Soft-AP parameters set: %s\n",softap_set_conf? "success":"fail"); + #endif + + #endif // AP_SSID && AP_PASS + configWifiIP(); - + // The default sleep mode should be modem_sleep, but we set it here explicitly for good // measure. We can't use light_sleep because that powers off everthing and we would loose // all connections. wifi_set_sleep_type(MODEM_SLEEP_T); - + wifi_set_event_handler_cb(wifiHandleEventCb); // check on the wifi in a few seconds to see whether we need to switch mode os_timer_disarm(&resetTimer); diff --git a/esp-link/cgiwifi.h b/esp-link/cgiwifi.h index e2e98bc..5fa177c 100644 --- a/esp-link/cgiwifi.h +++ b/esp-link/cgiwifi.h @@ -13,6 +13,8 @@ int cgiWiFiConnect(HttpdConnData *connData); int cgiWiFiSetMode(HttpdConnData *connData); int cgiWiFiConnStatus(HttpdConnData *connData); int cgiWiFiSpecial(HttpdConnData *connData); +int cgiApSettingsChange(HttpdConnData *connData); +int cgiApSettingsInfo(HttpdConnData *connData); void configWifiIP(); void wifiInit(void); void wifiAddStateChangeCb(WifiStateChangeCb cb); diff --git a/esp-link/main.c b/esp-link/main.c index bfbea0f..1bbf3b6 100644 --- a/esp-link/main.c +++ b/esp-link/main.c @@ -72,6 +72,8 @@ HttpdBuiltInUrl builtInUrls[] = { { "/wifi/connstatus", cgiWiFiConnStatus, NULL }, { "/wifi/setmode", cgiWiFiSetMode, NULL }, { "/wifi/special", cgiWiFiSpecial, NULL }, + { "/wifi/apinfo", cgiApSettingsInfo, NULL }, + { "/wifi/apchange", cgiApSettingsChange, NULL }, { "/system/info", cgiSystemInfo, NULL }, { "/system/update", cgiSystemSet, NULL }, { "/services/info", cgiServicesInfo, NULL }, @@ -86,7 +88,6 @@ HttpdBuiltInUrl builtInUrls[] = { #ifdef SHOW_HEAP_USE static ETSTimer prHeapTimer; - static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg) { os_printf("Heap: %ld\n", (unsigned long)system_get_free_heap_size()); } @@ -109,26 +110,25 @@ void user_rf_pre_init(void) { // Main routine to initialize esp-link. void user_init(void) { + // get the flash config so we know how to init things -// configWipe(); // uncomment to reset the config for testing purposes + // configWipe(); // uncomment to reset the config for testing purposes bool restoreOk = configRestore(); - // init gpio pin registers + // Init gpio pin registers gpio_init(); gpio_output_set(0, 0, 0, (1<<15)); // some people tie it to GND, gotta ensure it's disabled // init UART 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 + // Say hello (leave some time to cause break in TX after boot loader's msg os_delay_us(10000L); os_printf("\n\n** %s\n", esp_link_version); os_printf("Flash config restore %s\n", restoreOk ? "ok" : "*FAILED*"); - // Status LEDs statusInit(); serledInit(); // Wifi wifiInit(); - // init the flash filesystem with the html stuff espFsInit(&_binary_espfs_img_start); //EspFsInitResult res = espFsInit(&_binary_espfs_img_start); @@ -153,16 +153,14 @@ void user_init(void) { NOTICE("Flash map %s, manuf 0x%02lX chip 0x%04lX", flash_maps[system_get_flash_size_map()], fid & 0xff, (fid&0xff00)|((fid>>16)&0xff)); NOTICE("** esp-link ready"); - + + // Init SNTP service cgiServicesSNTPInit(); - #ifdef MQTT NOTICE("initializing MQTT"); mqtt_client_init(); #endif - NOTICE("initializing user application"); app_init(); - - NOTICE("waiting for work to do..."); + NOTICE("Waiting for work to do..."); } diff --git a/html/wifi/wifiAp.html b/html/wifi/wifiAp.html new file mode 100644 index 0000000..e93e54d --- /dev/null +++ b/html/wifi/wifiAp.html @@ -0,0 +1,124 @@ +
+
+

WiFi Soft-AP Configuration

+
+ +
+
+
+
+

Soft-AP State

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

Soft-AP Settings

+
+ + +
+
+
+
+
+ + + + + + diff --git a/html/wifi/wifiAp.js b/html/wifi/wifiAp.js new file mode 100644 index 0000000..e2fef60 --- /dev/null +++ b/html/wifi/wifiAp.js @@ -0,0 +1,98 @@ +var specials = []; +specials["ap_ssid"] = "SSID name"; +specials["ap_password"] = "PASSWORD"; +specials["ap_maxconn"] = "Max Connections number"; +specials["ap_beacon"] = "Beacon Interval"; + +function changeWifiMode(m) { + blockScan = 1; + hideWarning(); + ajaxSpin("POST", "setmode?mode=" + m, function(resp) { + showNotification("Mode changed"); + window.setTimeout(getWifiInfo, 100); + blockScan = 0; + }, function(s, st) { + showWarning("Error changing mode: " + st); + window.setTimeout(getWifiInfo, 100); + blockScan = 0; + }); +} + +function changeApSettings(e) { + e.preventDefault(); + var url = "/wifi/apchange?100=1"; + var i, inputs = document.querySelectorAll("#" + e.target.id + " input,select"); + for (i = 0; i < inputs.length; i++) { + if (inputs[i].type == "checkbox") { + var val = (inputs[i].checked) ? 1 : 0; + url += "&" + inputs[i].name + "=" + val; + } + else{ + var clean = inputs[i].value.replace(/[^\w]/gi, ""); + var comp = clean.localeCompare(inputs[i].value); + if ( comp != 0 ){ + showWarning("Invalid characters in " + specials[inputs[i].name]); + return; + } + url += "&" + inputs[i].name + "=" + clean; + } + }; + + hideWarning(); + var n = e.target.id.replace("-form", ""); + var cb = $("#" + n + "-button"); + addClass(cb, "pure-button-disabled"); + ajaxSpin("POST", url, function (resp) { + showNotification(n + " updated"); + removeClass(cb, "pure-button-disabled"); + window.setTimeout(getWifiInfo, 100); + }, function (s, st) { + showWarning(st); + removeClass(cb, "pure-button-disabled"); + window.setTimeout(fetchApSettings, 2000); + }); +} + +function displayApSettings(data) { + Object.keys(data).forEach(function (v) { + el = $("#" + v); + if (el != null) { + if (el.nodeName === "INPUT") el.value = data[v]; + else el.innerHTML = data[v]; + return; + } + + el = document.querySelector('input[name="' + v + '"]'); + if (el == null) + el = document.querySelector('select[name="' + v + '"]'); + + if (el != null) { + if (el.type == "checkbox") { + el.checked = data[v] == "enabled"; + } else el.value = data[v]; + } + }); + + $("#AP_Settings-spinner").setAttribute("hidden", ""); + $("#AP_Settings-form").removeAttribute("hidden"); + showWarning("Don't modify SOFTAP parameters with active connections"); + window.setTimeout(hideWarning(), 2000); +} + +function fetchApSettings() { + ajaxJson("GET", "/wifi/apinfo", displayApSettings, function () { + window.setTimeout(fetchApSettings, 1000); + }); +} + +function doApAdvanced() { + $('#AP_Settings-on').removeAttribute('hidden'); + $("#AP_Settings-off").setAttribute("hidden", ""); + $("#AP_Settings-roff").removeAttribute("checked"); +} + +function undoApAdvanced(){ + $("#AP_Settings-on").setAttribute("hidden", ""); + $("#AP_Settings-off").removeAttribute("hidden"); + $("#AP_Settings-roff").setAttribute("checked", ""); +} \ No newline at end of file diff --git a/html/wifi/wifi.html b/html/wifi/wifiSta.html similarity index 96% rename from html/wifi/wifi.html rename to html/wifi/wifiSta.html index f6d6646..bdc6dca 100644 --- a/html/wifi/wifi.html +++ b/html/wifi/wifiSta.html @@ -1,6 +1,6 @@
-

WiFi Configuration

+

WiFi Station Configuration

@@ -19,7 +19,9 @@ WiFi MAC -
+ + +

WiFi Association

@@ -70,7 +72,7 @@ - +