wifi settings remake, now correctly applied only as needed via change flags

pull/30/head
Ondřej Hruška 8 years ago
parent d5bd53b78a
commit a85582b94e
  1. 510
      user/cgi_wifi.c
  2. 37
      user/persist.c
  3. 2
      user/persist.h
  4. 67
      user/wifimgr.c
  5. 25
      user/wifimgr.h

@ -19,6 +19,11 @@ Cgi/template routines for the /wifi url.
#include <esp8266.h> #include <esp8266.h>
#include "cgi_wifi.h" #include "cgi_wifi.h"
#include "wifimgr.h"
#include "persist.h"
// strcpy that adds 0 at the end of the buffer. Returns void.
#define strncpy_safe(dst, src, n) do { strncpy((char *)(dst), (char *)(src), (n)); dst[(n)-1]=0; } while (0)
/** WiFi access point data */ /** WiFi access point data */
typedef struct { typedef struct {
@ -53,28 +58,6 @@ static ConnTry connTryStatus = CONNTRY_IDLE;
/** Connection to AP periodic check timer */ /** Connection to AP periodic check timer */
static os_timer_t staCheckTimer; static os_timer_t staCheckTimer;
/** reset_later() timer */
static ETSTimer resetTmr;
/**
* Callback for reset_later()
*/
static void ICACHE_FLASH_ATTR resetTmrCb(void *arg)
{
system_restart();
}
/**
* Schedule a reset
* @param ms reset delay (milliseconds)
*/
static void ICACHE_FLASH_ATTR reset_later(int ms)
{
os_timer_disarm(&resetTmr);
os_timer_setfn(&resetTmr, resetTmrCb, NULL);
os_timer_arm(&resetTmr, ms, false);
}
/** /**
* Calculate approximate signal strength % from RSSI * Calculate approximate signal strength % from RSSI
*/ */
@ -278,9 +261,6 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData)
} }
} }
/** Temp store for new ap info. */
static struct station_config stconf;
/** /**
* This routine is ran some time after a connection attempt to an access point. If * 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. * the connect succeeds, this gets the module in STA-only mode.
@ -305,23 +285,29 @@ static void ICACHE_FLASH_ATTR staCheckConnStatus(void *arg)
} }
/** /**
* Actually connect to a station. This routine is timed because I had problems * Delayed connect callback
* with immediate connections earlier. It probably was something else that caused it,
* but I can't be arsed to put the code back :P
*/ */
static void ICACHE_FLASH_ATTR cgiWiFiConnect_do(void *arg) static void ICACHE_FLASH_ATTR cgiWiFiConnect_do(void *arg)
{ {
int x; int x;
struct station_config cfg;
dbg("Try to connect to AP..."); dbg("Try to connect to AP...");
strncpy_safe(cfg.password, wificonf->sta_password, PASSWORD_LEN);
strncpy_safe(cfg.ssid, wificonf->sta_ssid, SSID_LEN);
cfg.bssid_set = 0;
wifi_station_disconnect(); wifi_station_disconnect();
wifi_station_set_config(&stconf); wifi_station_set_config(&cfg);
wifi_station_connect(); wifi_station_connect();
x = wifi_get_opmode(); x = wifi_get_opmode();
connTryStatus = CONNTRY_WORKING; connTryStatus = CONNTRY_WORKING;
// Assumption:
// if we're in station mode, no need to check: the browser will be disconnected
// and the user finds out whether it succeeded or not by checking if they can connect
if (x != STATION_MODE) { if (x != STATION_MODE) {
//Schedule check
os_timer_disarm(&staCheckTimer); os_timer_disarm(&staCheckTimer);
os_timer_setfn(&staCheckTimer, staCheckConnStatus, NULL); os_timer_setfn(&staCheckTimer, staCheckConnStatus, NULL);
os_timer_arm(&staCheckTimer, 15000, 0); //time out after 15 secs of trying to connect os_timer_arm(&staCheckTimer, 15000, 0); //time out after 15 secs of trying to connect
@ -338,8 +324,8 @@ static void ICACHE_FLASH_ATTR cgiWiFiConnect_do(void *arg)
*/ */
httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData)
{ {
char essid[128]; char ssid[100];
char passwd[128]; char password[100];
static os_timer_t reassTimer; static os_timer_t reassTimer;
if (connData->conn == NULL) { if (connData->conn == NULL) {
@ -347,26 +333,26 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData)
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
int ssilen = httpdFindArg(connData->post->buff, "essid", essid, sizeof(essid)); int ssilen = httpdFindArg(connData->post->buff, "sta_ssid", ssid, sizeof(ssid));
int passlen = httpdFindArg(connData->post->buff, "passwd", passwd, sizeof(passwd)); int passlen = httpdFindArg(connData->post->buff, "sta_password", password, sizeof(password));
if (ssilen == -1 || passlen == -1) { if (ssilen == -1 || passlen == -1) {
error("Not rx needed args!"); error("Did not receive the required arguments!");
httpdRedirect(connData, "/wifi"); httpdRedirect(connData, "/wifi");
} }
else { else {
strncpy((char *) stconf.ssid, essid, 32); strncpy_safe(wificonf->sta_ssid, ssid, SSID_LEN);
strncpy((char *) stconf.password, passwd, 64); strncpy_safe(wificonf->sta_password, password, PASSWORD_LEN);
info("Try to connect to AP %s pw %s", essid, passwd); info("Try to connect to AP \"%s\" pw \"%s\".", ssid, password);
//Schedule disconnect/connect //Schedule disconnect/connect
os_timer_disarm(&reassTimer); os_timer_disarm(&reassTimer);
os_timer_setfn(&reassTimer, cgiWiFiConnect_do, NULL); os_timer_setfn(&reassTimer, cgiWiFiConnect_do, NULL);
// redirect & start connecting a little bit later // redirect & start connecting a little bit later
os_timer_arm(&reassTimer, 2000, 0); // was 500, increased so the connecting page has time to load os_timer_arm(&reassTimer, 1000, 0); // was 500, increased so the connecting page has time to load
connTryStatus = CONNTRY_IDLE; connTryStatus = CONNTRY_IDLE;
httpdRedirect(connData, "/wifi/connecting"); httpdRedirect(connData, "/wifi/connecting"); // this page is meant to show progress
} }
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
@ -413,59 +399,83 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData)
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
/** reset_later() timer */
/**
* Callback for async timer
*/
static void ICACHE_FLASH_ATTR applyWifiSettingsLaterCb(void *arg)
{
wifimgr_apply_settings();
}
/** /**
* Universal CGI endpoint to set WiFi params. * Universal CGI endpoint to set WiFi params.
* Note that some may cause a (delayed) restart. * Note that some may cause a (delayed) restart.
*
* Args:
* - ap_ch = channel 1-14
* - ap_ssid = SSID name for AP mode
* - opmode = WiFi mode (resets device)
* - hostname = set client hostname
* - tpw = set transmit power
* - sta_dhcp_lt = DHCP server lease time
* - sta_ip = station mode static IP
* - sta_mask = station mode static IP mask (apply only if 'ip' is also sent)
* - sta_gw = station mode default gateway (apply only if 'ip' is also sent)
* (can be left out, then 0.0.0.0 is used and outbound connections won't work -
* but we're normally not making any)
* - dhcp = enable or disable DHCP on the station interface
*/ */
httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData) httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData)
{ {
int len, len2, len3; static ETSTimer timer;
char buff[50]; char buff[50];
char buff2[50];
char buff3[50];
// TODO change so that settings are not applied immediately, but persisted first char redir_url_buf[300];
// TODO apply temporary changes like static IP in wifi event CBs char *redir_url = redir_url_buf;
redir_url += sprintf(redir_url, "/wifi?err=");
// we'll test if anything was printed by looking for \0 in failed_keys_buf
if (connData->conn == NULL) { if (connData->conn == NULL) {
//Connection aborted. Clean up. //Connection aborted. Clean up.
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
// AP channel (applies in AP-only mode) #define GET_ARG(key) (httpdFindArg(connData->getArgs, key, buff, sizeof(buff)) > 0)
len = httpdFindArg(connData->getArgs, "ap_ch", buff, sizeof(buff));
if (len > 0) { // ---- WiFi opmode ----
info("Setting WiFi channel for AP-only mode to: %s", buff);
if (GET_ARG("opmode")) {
dbg("Setting WiFi opmode to: %s", buff);
int mode = atoi(buff);
if (mode > NULL_MODE && mode < MAX_MODE) {
wificonf->opmode = (WIFI_MODE) mode;
} else {
warn("Bad opmode value \"%s\"", buff);
redir_url += sprintf(redir_url, "opmode,");
}
}
// ---- AP transmit power ----
if (GET_ARG("tpw")) {
dbg("Setting AP power to: %s", buff);
int tpw = atoi(buff);
if (tpw >= 0 && tpw <= 82) { // 0 actually isn't 0 but quite low. 82 is very strong
wificonf->tpw = (u8) tpw;
wifi_change_flags.ap = true;
} else {
warn("tpw %s out of allowed range 0-82.", buff);
redir_url += sprintf(redir_url, "tpw,");
}
}
// ---- AP channel (applies in AP-only mode) ----
if (GET_ARG("ap_channel")) {
info("ap_channel = %s", buff);
int channel = atoi(buff); int channel = atoi(buff);
if (channel > 0 && channel < 15) { if (channel > 0 && channel < 15) {
dbg("Setting channel=%d", channel); wificonf->ap_channel = (u8) channel;
wifi_change_flags.ap = true;
struct softap_config wificfg;
wifi_softap_get_config(&wificfg);
wificfg.channel = (uint8) channel;
wifi_softap_set_config(&wificfg);
} else { } else {
warn("Bad channel value %s, allowed 1-14", buff); warn("Bad channel value \"%s\", allowed 1-14", buff);
redir_url += sprintf(redir_url, "ap_channel,");
} }
} }
// SSID name in AP mode // ---- SSID name in AP mode ----
len = httpdFindArg(connData->getArgs, "ap_ssid", buff, sizeof(buff));
if (len > 0) { if (GET_ARG("ap_ssid")) {
// Replace all invalid ASCII with underscores
int i; int i;
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
char c = buff[i]; char c = buff[i];
@ -474,103 +484,198 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData)
} }
buff[i] = 0; buff[i] = 0;
info("Setting SSID to %s", buff); if (strlen(buff) > 0) {
info("Setting SSID to \"%s\"", buff);
struct softap_config wificfg; strncpy_safe(wificonf->ap_ssid, buff, SSID_LEN);
wifi_softap_get_config(&wificfg); wifi_change_flags.ap = true;
sprintf((char *) wificfg.ssid, buff);
wificfg.ssid_len = strlen((char *) wificfg.ssid);
wifi_softap_set_config(&wificfg);
}
// WiFi mode
len = httpdFindArg(connData->getArgs, "opmode", buff, sizeof(buff));
if (len > 0) {
dbg("Setting WiFi opmode to: %s", buff);
int mode = atoi(buff);
if (mode > NULL_MODE && mode < MAX_MODE) {
wifi_set_opmode(mode);
reset_later(200);
} else { } else {
warn("Bad opmode value %s", buff); warn("Bad SSID len.");
redir_url += sprintf(redir_url, "ap_ssid,");
} }
} }
// Hostname in station mode (for DHCP) // ---- AP password ----
len = httpdFindArg(connData->getArgs, "hostname", buff, sizeof(buff));
if (len > 0) {
dbg("Setting station sta_hostname to: %s", buff);
wifi_station_set_hostname(buff);
// TODO persistency, re-apply on boot
}
// Hostname in station mode (for DHCP) if (GET_ARG("ap_password")) {
len = httpdFindArg(connData->getArgs, "tpw", buff, sizeof(buff)); // Users are free to use any stupid shit in ther password,
if (len > 0) { // but it may lock them out.
dbg("Setting AP power to: %s", buff); if (strlen(buff) == 0 || (strlen(buff) >= 8 && strlen(buff) < PASSWORD_LEN-1)) {
int tpw = atoi(buff); info("Setting AP password to \"%s\"", buff);
// min tpw to avoid user locking themselves out TODO verify strncpy_safe(wificonf->ap_password, buff, PASSWORD_LEN);
if (tpw >= 0 && tpw <= 82) { wifi_change_flags.ap = true;
// TODO persistency, re-apply on boot
system_phy_set_max_tpw(tpw);
} else { } else {
warn("tpw %s out of allowed range 0-82.", buff); warn("Bad password len.");
redir_url += sprintf(redir_url, "ap_password,");
} }
} }
// DHCP server lease time // ---- Hide AP network (do not announce) ----
len = httpdFindArg(connData->getArgs, "ap_dhcp_lt", buff, sizeof(buff));
if (len > 0) { if (GET_ARG("ap_hidden")) {
dbg("AP hidden = %s", buff);
int hidden = atoi(buff);
wificonf->ap_hidden = (hidden != 0);
wifi_change_flags.ap = true;
}
// ---- AP DHCP server lease time ----
if (GET_ARG("ap_dhcp_time")) {
dbg("Setting DHCP lease time to: %s min.", buff); dbg("Setting DHCP lease time to: %s min.", buff);
int min = atoi(buff); int min = atoi(buff);
if (min >= 1 && min <= 2880) { if (min >= 1 && min <= 2880) {
// TODO persistency, re-apply on boot wificonf->ap_dhcp_time = (u16) min;
// TODO set only if we're in the right opmode wifi_change_flags.ap = true;
wifi_softap_set_dhcps_lease_time(min);
} else { } else {
warn("Lease time %s out of allowed range 1-2880.", buff); warn("Lease time %s out of allowed range 1-2880.", buff);
redir_url += sprintf(redir_url, "ap_dhcp_time,");
} }
} }
// ---- AP DHCP start and end IP ----
if (GET_ARG("ap_dhcp_range_start")) {
dbg("Setting DHCP range start IP to: \"%s\"", buff);
u32 ip = ipaddr_addr(buff);
if (ip != 0) {
wificonf->ap_dhcp_range.start_ip.addr = ip;
wifi_change_flags.ap = true;
} else {
warn("Bad IP: %s", buff);
redir_url += sprintf(redir_url, "ap_dhcp_range_start,");
}
}
if (GET_ARG("ap_dhcp_range_end")) {
dbg("Setting DHCP range end IP to: \"%s\"", buff);
u32 ip = ipaddr_addr(buff);
if (ip != 0) {
wificonf->ap_dhcp_range.end_ip.addr = ip;
wifi_change_flags.ap = true;
} else {
warn("Bad IP: %s", buff);
redir_url += sprintf(redir_url, "ap_dhcp_range_end,");
}
}
// ---- AP local address & config ----
if (GET_ARG("ap_addr_ip")) {
dbg("Setting AP local IP to: \"%s\"", buff);
u32 ip = ipaddr_addr(buff);
if (ip != 0) {
wificonf->ap_addr.ip.addr = ip;
wificonf->ap_addr.gw.addr = ip; // always the same, we're the router here
wifi_change_flags.ap = true;
} else {
warn("Bad IP: %s", buff);
redir_url += sprintf(redir_url, "ap_addr_ip,");
}
}
if (GET_ARG("ap_addr_mask")) {
dbg("Setting AP local IP netmask to: \"%s\"", buff);
u32 ip = ipaddr_addr(buff);
if (ip != 0) {
// ideally this should be checked to match the IP.
// Let's hope users know what they're doing
wificonf->ap_addr.netmask.addr = ip;
wifi_change_flags.ap = true;
} else {
warn("Bad IP mask: %s", buff);
redir_url += sprintf(redir_url, "ap_addr_mask,");
}
}
// ---- Station SSID (to connect to) ----
if (GET_ARG("sta_ssid")) {
// No verification needed, at worst it fails to connect
info("Setting station SSID to: \"%s\"", buff);
strncpy_safe(wificonf->sta_ssid, buff, SSID_LEN);
wifi_change_flags.sta = true;
}
// ---- Station password (empty for none is allowed) ----
if (GET_ARG("sta_password")) {
// No verification needed, at worst it fails to connect
info("Setting station password to: \"%s\"", buff);
strncpy_safe(wificonf->sta_password, buff, PASSWORD_LEN);
wifi_change_flags.sta = true;
}
// ---- Station enable/disable DHCP ----
// DHCP enable / disable (disable means static IP is enabled) // DHCP enable / disable (disable means static IP is enabled)
len = httpdFindArg(connData->getArgs, "sta_dhcp", buff, sizeof(buff)); if (GET_ARG("sta_dhcp_enable")) {
if (len > 0) { dbg("DHCP enable = %s", buff);
dbg("DHCP enable = %s", buff);
int enable = atoi(buff); int enable = atoi(buff);
if (enable != 0) { wificonf->sta_dhcp_enable = (enable != 0);
wifi_station_dhcpc_stop(); wifi_change_flags.sta = true;
}
// ---- Station IP config (Static IP) ----
if (GET_ARG("sta_addr_ip")) {
dbg("Setting Station mode static IP to: \"%s\"", buff);
u32 ip = ipaddr_addr(buff);
if (ip != 0) {
wificonf->sta_addr.ip.addr = ip;
wifi_change_flags.sta = true;
} else { } else {
wifi_station_dhcpc_start(); warn("Bad IP: %s", buff);
redir_url += sprintf(redir_url, "sta_addr_ip,");
} }
// TODO persistency }
}
if (GET_ARG("sta_addr_mask")) {
// Static IP dbg("Setting Station mode static IP netmask to: \"%s\"", buff);
len = httpdFindArg(connData->getArgs, "sta_ip", buff, sizeof(buff)); u32 ip = ipaddr_addr(buff);
len2 = httpdFindArg(connData->getArgs, "sta_mask", buff2, sizeof(buff2)); if (ip != 0 && ip != 0xFFFFFFFFUL) {
len3 = httpdFindArg(connData->getArgs, "sta_gw", buff3, sizeof(buff3)); wificonf->sta_addr.netmask.addr = ip;
if (len > 0) { wifi_change_flags.sta = true;
// TODO set only if we're in the right opmode } else {
// TODO persistency warn("Bad IP mask: %s", buff);
dbg("Setting static IP = %s", buff); redir_url += sprintf(redir_url, "sta_addr_mask,");
struct ip_info ipinfo;
ipinfo.ip.addr = ipaddr_addr(buff);
ipinfo.netmask.addr = IPADDR_NONE;
ipinfo.gw.addr = IPADDR_NONE;
if (len2 > 0) {
dbg("Netmask = %s", buff2);
ipinfo.netmask.addr = ipaddr_addr(buff2);
} }
if (len3 > 0) { }
dbg("Gateway = %s", buff3);
ipinfo.gw.addr = ipaddr_addr(buff3); if (GET_ARG("sta_addr_gw")) {
dbg("Setting Station mode static IP default gateway to: \"%s\"", buff);
u32 ip = ipaddr_addr(buff);
if (ip != 0) {
wificonf->sta_addr.gw.addr = ip;
wifi_change_flags.sta = true;
} else {
warn("Bad gw IP: %s", buff);
redir_url += sprintf(redir_url, "sta_addr_gw,");
} }
// TODO ...
wifi_station_dhcpc_stop();
wifi_set_ip_info(STATION_IF, &ipinfo);
} }
httpdRedirect(connData, "/wifi"); if (redir_url_buf[10] == 0) {
// All was OK
info("Set WiFi params - success, applying in 1000 ms");
// Settings are applied only if all was OK
//
// This is so that options that consist of multiple keys sent together are not applied
// only partially if set wrong, which could lead to eg. user losing access and having
// to reset to defaults.
persist_store();
// Delayed settings apply, so the response page has a chance to load.
// If user connects via the Station IF, they may not even notice the connection reset.
os_timer_disarm(&timer);
os_timer_setfn(&timer, applyWifiSettingsLaterCb, NULL);
os_timer_arm(&timer, 1000, false);
httpdRedirect(connData, "/wifi");
} else {
warn("Some WiFi settings did not validate, asking for correction");
// Some errors, appended to the URL as ?err=
httpdRedirect(connData, redir_url_buf);
}
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
@ -578,77 +683,104 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData)
//Template code for the WLAN page. //Template code for the WLAN page.
httpd_cgi_state ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token, void **arg) httpd_cgi_state ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token, void **arg)
{ {
char buff[500]; char buff[100];
int x; int x;
int connectStatus; int connectStatus;
static struct station_config stconf;
static struct softap_config apconf;
if (token == NULL) { if (token == NULL) {
// We're done // We're done
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
wifi_station_get_config(&stconf); strcpy(buff, ""); // fallback
wifi_softap_get_config(&apconf);
if (streq(token, "opmode_name")) {
strcpy(buff, "Unknown"); strcpy(buff, opmode2str(wificonf->opmode));
if (streq(token, "WiFiMode")) {
x = wifi_get_opmode();
strcpy(buff, opmode2str(x));
} }
else if (streq(token, "WiFiModeNum")) { else if (streq(token, "opmode")) {
x = wifi_get_opmode(); sprintf(buff, "%d", wificonf->opmode);
sprintf(buff, "%d", x);
} }
else if (streq(token, "WiFiChannel")) { else if (streq(token, "tpw")) {
sprintf(buff, "%d", apconf.channel); sprintf(buff, "%d", wificonf->tpw);
} }
else if (streq(token, "APName")) { else if (streq(token, "ap_channel")) {
sprintf(buff, "%s", apconf.ssid); sprintf(buff, "%d", wificonf->ap_channel);
} }
else if (streq(token, "StaIP")) { else if (streq(token, "ap_ssid")) {
x = wifi_get_opmode(); sprintf(buff, "%s", wificonf->ap_ssid);
}
else if (streq(token, "ap_password")) {
sprintf(buff, "%s", wificonf->ap_password);
}
else if (streq(token, "ap_hidden")) {
sprintf(buff, "%d", wificonf->ap_hidden);
}
else if (streq(token, "ap_dhcp_time")) {
sprintf(buff, "%d", wificonf->ap_dhcp_time);
}
else if (streq(token, "ap_dhcp_range_start")) {
sprintf(buff, IPSTR, GOOD_IP2STR(wificonf->ap_dhcp_range.start_ip.addr));
}
else if (streq(token, "ap_dhcp_range_end")) {
sprintf(buff, IPSTR, GOOD_IP2STR(wificonf->ap_dhcp_range.end_ip.addr));
}
else if (streq(token, "ap_addr_ip")) {
sprintf(buff, IPSTR, GOOD_IP2STR(wificonf->ap_addr.ip.addr));
}
else if (streq(token, "ap_addr_mask")) {
sprintf(buff, IPSTR, GOOD_IP2STR(wificonf->ap_addr.netmask.addr));
}
else if (streq(token, "sta_ssid")) {
sprintf(buff, "%s", wificonf->sta_ssid);
}
else if (streq(token, "sta_password")) {
sprintf(buff, "%s", wificonf->sta_password);
}
else if (streq(token, "sta_dhcp_enable")) {
sprintf(buff, "%d", wificonf->sta_dhcp_enable);
}
else if (streq(token, "sta_addr_ip")) {
sprintf(buff, IPSTR, GOOD_IP2STR(wificonf->sta_addr.ip.addr));
}
else if (streq(token, "ap_addr_mask")) {
sprintf(buff, IPSTR, GOOD_IP2STR(wificonf->sta_addr.netmask.addr));
}
else if (streq(token, "ap_addr_gw")) {
sprintf(buff, IPSTR, GOOD_IP2STR(wificonf->sta_addr.gw.addr));
}
else if (streq(token, "sta_rssi")) {
sprintf(buff, "%d", wifi_station_get_rssi());
}
else if (streq(token, "sta_active_ssid")) {
// For display of our current SSID
connectStatus = wifi_station_get_connect_status(); connectStatus = wifi_station_get_connect_status();
x = wifi_get_opmode();
if (x == SOFTAP_MODE || connectStatus != STATION_GOT_IP) { if (x == SOFTAP_MODE || connectStatus != STATION_GOT_IP) {
strcpy(buff, ""); strcpy(buff, "");
} }
else { else {
struct ip_info info; struct station_config staconf;
wifi_get_ip_info(STATION_IF, &info); wifi_station_get_config(&staconf);
sprintf(buff, IPSTR, GOOD_IP2STR(info.ip.addr)); strcpy(buff, (char *) staconf.ssid);
} }
} }
else if (streq(token, "StaSSID")) { else if (streq(token, "sta_active_ip")) {
connectStatus = wifi_station_get_connect_status();
x = wifi_get_opmode(); x = wifi_get_opmode();
connectStatus = wifi_station_get_connect_status();
if (x == SOFTAP_MODE || connectStatus != STATION_GOT_IP) { if (x == SOFTAP_MODE || connectStatus != STATION_GOT_IP) {
strcpy(buff, ""); strcpy(buff, "");
} }
else { else {
strcpy(buff, (char *) stconf.ssid); struct ip_info info;
} wifi_get_ip_info(STATION_IF, &info);
} sprintf(buff, "ip: "IPSTR", mask: "IPSTR", gw: "IPSTR,
else if (streq(token, "WiFiPasswd")) { GOOD_IP2STR(info.ip.addr),
strcpy(buff, (char *) stconf.password); GOOD_IP2STR(info.netmask.addr),
} GOOD_IP2STR(info.gw.addr));
else if (streq(token, "WiFiapwarn")) {
// TODO get rid of this
x = wifi_get_opmode();
if (x == SOFTAP_MODE) { // 2
strcpy(buff, "<a href=\"/wifi/setmode?mode=3\">Enable client</a> for scanning.");
}
else if (x == STATIONAP_MODE) { // 3
strcpy(buff,
"Switch: <a href=\"/wifi/setmode?mode=1\">Client only</a>, <a href=\"/wifi/setmode?mode=2\">AP only</a>");
}
else { // 1
strcpy(buff,
"Switch: <a href=\"/wifi/setmode?mode=3\">Client+AP</a>, <a href=\"/wifi/setmode?mode=2\">AP only</a>");
} }
} }
httpdSend(connData, buff, -1); httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }

@ -11,28 +11,10 @@ PersistBlock persist;
#define PERSIST_SECTOR_ID 0x3D #define PERSIST_SECTOR_ID 0x3D
//region Persist and restore individual modules // This is used to force-erase the config area (when it's changed)
#define CHECKSUM_SALT 0x02
/**
* Load persistent settings to live config structs
*/
static void ICACHE_FLASH_ATTR
load_settings_to_live(void)
{
dbg("[Persist] Loading current settings to modules...");
memcpy(wificonf, &persist.current.wificonf, sizeof(WiFiConfigBundle));
memcpy(termconf, &persist.current.termconf, sizeof(TerminalConfigBundle));
// ...
}
static void ICACHE_FLASH_ATTR //region Persist and restore individual modules
store_all_settings_from_live(void)
{
dbg("[Persist] Collecting live settings to persist block...");
memcpy(&persist.current.wificonf, wificonf, sizeof(WiFiConfigBundle));
memcpy(&persist.current.termconf, termconf, sizeof(TerminalConfigBundle));
// ...
}
static void ICACHE_FLASH_ATTR static void ICACHE_FLASH_ATTR
apply_live_settings(void) apply_live_settings(void)
@ -88,7 +70,7 @@ calculateCRC32(const uint8_t *data, size_t length)
static uint32_t ICACHE_FLASH_ATTR static uint32_t ICACHE_FLASH_ATTR
compute_checksum(AppConfigBundle *bundle) compute_checksum(AppConfigBundle *bundle)
{ {
return calculateCRC32((uint8_t *) bundle, sizeof(AppConfigBundle) - 4); return calculateCRC32((uint8_t *) bundle, sizeof(AppConfigBundle) - 4) ^ CHECKSUM_SALT;
} }
/** /**
@ -108,15 +90,16 @@ persist_load(void)
if (hard_reset || if (hard_reset ||
(compute_checksum(&persist.defaults) != persist.defaults.checksum) || (compute_checksum(&persist.defaults) != persist.defaults.checksum) ||
(compute_checksum(&persist.current) != persist.current.checksum)) { (compute_checksum(&persist.current) != persist.current.checksum)) {
error("[Persist] Config block failed to load, restoring to hard defaults."); dbg("[Persist] Checksum verification: FAILED");
hard_reset = true; hard_reset = true;
} else {
dbg("[Persist] Checksum verification: PASSED");
} }
if (hard_reset) { if (hard_reset) {
persist_restore_hard_default(); persist_restore_hard_default();
// this also stores them to flash and applies to modues // this also stores them to flash and applies to modues
} else { } else {
load_settings_to_live();
apply_live_settings(); apply_live_settings();
} }
@ -127,7 +110,6 @@ void ICACHE_FLASH_ATTR
persist_store(void) persist_store(void)
{ {
info("[Persist] Storing all settings to FLASH..."); info("[Persist] Storing all settings to FLASH...");
store_all_settings_from_live();
// Update checksums before write // Update checksums before write
persist.current.checksum = compute_checksum(&persist.current); persist.current.checksum = compute_checksum(&persist.current);
@ -150,9 +132,6 @@ persist_restore_hard_default(void)
// Set live config to default values // Set live config to default values
restore_live_settings_to_hard_defaults(); restore_live_settings_to_hard_defaults();
// Store live -> current
store_all_settings_from_live();
// Store current -> default // Store current -> default
memcpy(&persist.defaults, &persist.current, sizeof(AppConfigBundle)); memcpy(&persist.defaults, &persist.current, sizeof(AppConfigBundle));
persist_store(); persist_store();
@ -170,7 +149,6 @@ persist_restore_default(void)
{ {
info("[Persist] Restoring live settings to stored defaults..."); info("[Persist] Restoring live settings to stored defaults...");
memcpy(&persist.current, &persist.defaults, sizeof(AppConfigBundle)); memcpy(&persist.current, &persist.defaults, sizeof(AppConfigBundle));
load_settings_to_live();
apply_live_settings(); apply_live_settings();
info("[Persist] Settings restored to stored defaults."); info("[Persist] Settings restored to stored defaults.");
} }
@ -183,7 +161,6 @@ persist_set_as_default(void)
{ {
info("[Persist] Storing live settings as defaults.."); info("[Persist] Storing live settings as defaults..");
store_all_settings_from_live();
memcpy(&persist.defaults, &persist.current, sizeof(AppConfigBundle)); memcpy(&persist.defaults, &persist.current, sizeof(AppConfigBundle));
persist_store(); persist_store();

@ -24,7 +24,7 @@ typedef struct {
typedef struct { typedef struct {
AppConfigBundle defaults; // defaults are stored here AppConfigBundle defaults; // defaults are stored here
AppConfigBundle current; // settings persisted by user AppConfigBundle current; // active settings adjusted by the user
} PersistBlock; } PersistBlock;
// Persist holds the data currently loaded from the flash // Persist holds the data currently loaded from the flash

@ -6,6 +6,7 @@
#include "persist.h" #include "persist.h"
WiFiConfigBundle * const wificonf = &persist.current.wificonf; WiFiConfigBundle * const wificonf = &persist.current.wificonf;
WiFiConfChangeFlags wifi_change_flags;
/** /**
* Restore defaults in the WiFi config block. * Restore defaults in the WiFi config block.
@ -25,24 +26,23 @@ wifimgr_restore_defaults(void)
wificonf->ap_password[0] = 0; // PSK2 always if password is not null. wificonf->ap_password[0] = 0; // PSK2 always if password is not null.
wificonf->ap_hidden = false; wificonf->ap_hidden = false;
IP4_ADDR(&wificonf->ap_ip.ip, 192, 168, 4, 60); IP4_ADDR(&wificonf->ap_addr.ip, 192, 168, 4, 1);
IP4_ADDR(&wificonf->ap_ip.netmask, 255, 255, 255, 0); IP4_ADDR(&wificonf->ap_addr.netmask, 255, 255, 255, 0);
wificonf->ap_ip.gw.addr = wificonf->ap_ip.gw.addr; wificonf->ap_addr.gw.addr = wificonf->ap_addr.gw.addr;
IP4_ADDR(&wificonf->ap_dhcp_range.start_ip, 192, 168, 4, 100); IP4_ADDR(&wificonf->ap_dhcp_range.start_ip, 192, 168, 4, 100);
IP4_ADDR(&wificonf->ap_dhcp_range.end_ip, 192, 168, 4, 200); IP4_ADDR(&wificonf->ap_dhcp_range.end_ip, 192, 168, 4, 200);
wificonf->ap_dhcp_range.enable = 1; wificonf->ap_dhcp_range.enable = 1; // this will never get changed, idk why it's even there
wificonf->ap_dhcp_lease_time = 120; wificonf->ap_dhcp_time = 120;
// --- Client config --- // --- Client config ---
wificonf->sta_ssid[0] = 0; wificonf->sta_ssid[0] = 0;
wificonf->sta_password[0] = 0; wificonf->sta_password[0] = 0;
strcpy((char *) wificonf->sta_hostname, (char *) wificonf->ap_ssid); // use the same value for sta_hostname as AP name
wificonf->sta_dhcp_enable = true; wificonf->sta_dhcp_enable = true;
IP4_ADDR(&wificonf->sta_ip.ip, 192, 168, 0, (mac[5]==1?2:mac[5])); // avoid being the same as "default gw" IP4_ADDR(&wificonf->sta_addr.ip, 192, 168, 0, (mac[5] == 1 ? 2 : mac[5])); // avoid being the same as "default gw"
IP4_ADDR(&wificonf->sta_ip.netmask, 255, 255, 255, 0); IP4_ADDR(&wificonf->sta_addr.netmask, 255, 255, 255, 0);
IP4_ADDR(&wificonf->sta_ip.gw, 192, 168, 0, 1); IP4_ADDR(&wificonf->sta_addr.gw, 192, 168, 0, 1);
} }
static void ICACHE_FLASH_ATTR static void ICACHE_FLASH_ATTR
@ -57,25 +57,23 @@ configure_station(void)
conf.bssid[0] = 0; conf.bssid[0] = 0;
wifi_station_disconnect(); wifi_station_disconnect();
wifi_station_set_config_current(&conf); wifi_station_set_config_current(&conf);
dbg("[WiFi] Hostname = %s", wificonf->sta_hostname);
wifi_station_set_hostname((char*)wificonf->sta_hostname);
if (wificonf->sta_dhcp_enable) { if (wificonf->sta_dhcp_enable) {
dbg("[WiFi] Starting DHCP..."); dbg("[WiFi] Starting DHCP...");
if (!wifi_station_dhcpc_start()) { if (!wifi_station_dhcpc_start()) {
error("[WiFi] DHCp failed to start!"); error("[WiFi] DHCP failed to start!");
return; return;
} }
} }
else { else {
info("[WiFi] Setting up static IP..."); info("[WiFi] Setting up static IP...");
dbg("[WiFi] Client.ip = "IPSTR, GOOD_IP2STR(wificonf->sta_ip.ip.addr)); dbg("[WiFi] Client.ip = "IPSTR, GOOD_IP2STR(wificonf->sta_addr.ip.addr));
dbg("[WiFi] Client.mask = "IPSTR, GOOD_IP2STR(wificonf->sta_ip.netmask.addr)); dbg("[WiFi] Client.mask = "IPSTR, GOOD_IP2STR(wificonf->sta_addr.netmask.addr));
dbg("[WiFi] Client.gw = "IPSTR, GOOD_IP2STR(wificonf->sta_ip.gw.addr)); dbg("[WiFi] Client.gw = "IPSTR, GOOD_IP2STR(wificonf->sta_addr.gw.addr));
wifi_station_dhcpc_stop(); wifi_station_dhcpc_stop();
// Load static IP config // Load static IP config
if (!wifi_set_ip_info(STATION_IF, &wificonf->sta_ip)) { if (!wifi_set_ip_info(STATION_IF, &wificonf->sta_addr)) {
error("[WiFi] Error setting static IP!"); error("[WiFi] Error setting static IP!");
return; return;
} }
@ -113,14 +111,14 @@ configure_ap(void)
// Set IP // Set IP
info("[WiFi] Configuring SoftAP local IP..."); info("[WiFi] Configuring SoftAP local IP...");
dbg("[WiFi] SoftAP.ip = "IPSTR, GOOD_IP2STR(wificonf->ap_ip.ip.addr)); dbg("[WiFi] SoftAP.ip = "IPSTR, GOOD_IP2STR(wificonf->ap_addr.ip.addr));
dbg("[WiFi] SoftAP.mask = "IPSTR, GOOD_IP2STR(wificonf->ap_ip.netmask.addr)); dbg("[WiFi] SoftAP.mask = "IPSTR, GOOD_IP2STR(wificonf->ap_addr.netmask.addr));
dbg("[WiFi] SoftAP.gw = "IPSTR, GOOD_IP2STR(wificonf->ap_ip.gw.addr)); dbg("[WiFi] SoftAP.gw = "IPSTR, GOOD_IP2STR(wificonf->ap_addr.gw.addr));
wifi_softap_dhcps_stop(); wifi_softap_dhcps_stop();
// Configure DHCP // Configure DHCP
if (!wifi_set_ip_info(SOFTAP_IF, &wificonf->ap_ip)) { if (!wifi_set_ip_info(SOFTAP_IF, &wificonf->ap_addr)) {
error("[WiFi] IP set fail!"); error("[WiFi] IP set fail!");
return; return;
} }
@ -128,14 +126,14 @@ configure_ap(void)
info("[WiFi] Configuring SoftAP DHCP server..."); info("[WiFi] Configuring SoftAP DHCP server...");
dbg("[WiFi] DHCP.start = "IPSTR, GOOD_IP2STR(wificonf->ap_dhcp_range.start_ip.addr)); dbg("[WiFi] DHCP.start = "IPSTR, GOOD_IP2STR(wificonf->ap_dhcp_range.start_ip.addr));
dbg("[WiFi] DHCP.end = "IPSTR, GOOD_IP2STR(wificonf->ap_dhcp_range.end_ip.addr)); dbg("[WiFi] DHCP.end = "IPSTR, GOOD_IP2STR(wificonf->ap_dhcp_range.end_ip.addr));
dbg("[WiFi] DHCP.lease = %d minutes", wificonf->ap_dhcp_lease_time); dbg("[WiFi] DHCP.lease = %d minutes", wificonf->ap_dhcp_time);
if (!wifi_softap_set_dhcps_lease(&wificonf->ap_dhcp_range)) { if (!wifi_softap_set_dhcps_lease(&wificonf->ap_dhcp_range)) {
error("[WiFi] DHCP address range set fail!"); error("[WiFi] DHCP address range set fail!");
return; return;
} }
if (!wifi_softap_set_dhcps_lease_time(wificonf->ap_dhcp_lease_time)) { if (!wifi_softap_set_dhcps_lease_time(wificonf->ap_dhcp_time)) {
error("[WiFi] DHCP lease time set fail!"); error("[WiFi] DHCP lease time set fail!");
return; return;
} }
@ -161,23 +159,34 @@ wifimgr_apply_settings(void)
// Force wifi cycle // Force wifi cycle
// Disconnect - may not be needed? // Disconnect - may not be needed?
WIFI_MODE opmode = wifi_get_opmode(); WIFI_MODE opmode = wifi_get_opmode();
if (opmode == STATIONAP_MODE || opmode == STATION_MODE) {
wifi_station_disconnect(); bool is_sta = wificonf->opmode & STATION_MODE;
bool is_ap = wificonf->opmode & SOFTAP_MODE;
if ((wificonf->opmode & STATION_MODE) && !(opmode & STATION_MODE)) {
wifi_change_flags.sta = true;
}
if ((wificonf->opmode & SOFTAP_MODE) && !(opmode & SOFTAP_MODE)) {
wifi_change_flags.ap = true;
} }
// This should hopefully deinit everything if (opmode != wificonf->opmode) {
wifi_set_opmode_current(NULL_MODE); wifi_set_opmode_current(wificonf->opmode);
wifi_set_opmode_current(wificonf->opmode); }
// Configure the client // Configure the client
if (wificonf->opmode == STATIONAP_MODE || wificonf->opmode == STATION_MODE) { if (is_sta && wifi_change_flags.sta) {
configure_station(); configure_station();
} }
// Configure the AP // Configure the AP
if (wificonf->opmode == STATIONAP_MODE || wificonf->opmode == SOFTAP_MODE) { if (is_ap && wifi_change_flags.ap) {
configure_ap(); configure_ap();
} }
wifi_change_flags.ap = false;
wifi_change_flags.sta = false;
info("[WiFi] WiFi settings applied."); info("[WiFi] WiFi settings applied.");
} }

@ -10,6 +10,9 @@
#include <esp8266.h> #include <esp8266.h>
#include "cgi_wifi.h" #include "cgi_wifi.h"
#define SSID_LEN 32
#define PASSWORD_LEN 64
/** /**
* A structure holding all configured WiFi parameters * A structure holding all configured WiFi parameters
* and the active state. * and the active state.
@ -22,23 +25,29 @@ typedef struct {
// --- AP config --- // --- AP config ---
u8 ap_channel; u8 ap_channel;
u8 ap_ssid[32]; u8 ap_ssid[SSID_LEN];
u8 ap_password[32]; u8 ap_password[PASSWORD_LEN];
bool ap_hidden; bool ap_hidden;
u16 ap_dhcp_lease_time; // in minutes u16 ap_dhcp_time; // in minutes
struct dhcps_lease ap_dhcp_range; struct dhcps_lease ap_dhcp_range;
struct ip_info ap_ip; struct ip_info ap_addr;
// --- Client config --- // --- Client config ---
u8 sta_ssid[32]; u8 sta_ssid[SSID_LEN];
u8 sta_password[64]; u8 sta_password[PASSWORD_LEN];
u8 sta_hostname[32]; // hostname set via the API. This does not seem to have much effect.
bool sta_dhcp_enable; bool sta_dhcp_enable;
struct ip_info sta_ip; struct ip_info sta_addr;
} WiFiConfigBundle; } WiFiConfigBundle;
typedef struct {
bool sta;
bool ap;
} WiFiConfChangeFlags;
extern WiFiConfChangeFlags wifi_change_flags;
extern WiFiConfigBundle * const wificonf; extern WiFiConfigBundle * const wificonf;
void wifimgr_restore_defaults(void); void wifimgr_restore_defaults(void);

Loading…
Cancel
Save