diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e65181..6345770 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,7 +148,7 @@ set(SOURCE_FILES user/character_sets.h user/utf8.h user/utf8.c - user/cgi_logging.h) + user/cgi_logging.h user/config_xmacros.h user/config_xmacros.c) include_directories(include) include_directories(libesphttpd/esphttpclient) diff --git a/front-end b/front-end index d2fabc4..32c889b 160000 --- a/front-end +++ b/front-end @@ -1 +1 @@ -Subproject commit d2fabc40f1874cabd7f7ceca690a5874887c3c5d +Subproject commit 32c889b714dae859f51e6b46829fd85be59d9ed0 diff --git a/prepro.sh b/prepro.sh new file mode 100755 index 0000000..997d376 --- /dev/null +++ b/prepro.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +xtensa-lx106-elf-gcc -E -Iuser -Ilibesphttpd/include -Iesp_iot_sdk_v1.5.2/include -Iinclude $@ diff --git a/user/cgi_network.c b/user/cgi_network.c index db86874..6ed9d40 100644 --- a/user/cgi_network.c +++ b/user/cgi_network.c @@ -9,6 +9,7 @@ configuring the network settings #include "persist.h" #include "helpers.h" #include "cgi_logging.h" +#include "config_xmacros.h" #define SET_REDIR_SUC "/cfg/network" #define SET_REDIR_ERR SET_REDIR_SUC"?err=" @@ -48,138 +49,9 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiNetworkSetParams(HttpdConnData *connData) // ---- AP DHCP server lease time ---- - if (GET_ARG("ap_dhcp_time")) { - cgi_dbg("Setting DHCP lease time to: %s min.", buff); - int min = atoi(buff); - if (min >= 1 && min <= 2880) { - if (wificonf->ap_dhcp_time != min) { - wificonf->ap_dhcp_time = (u16) min; - wifi_change_flags.ap = true; - } - } else { - cgi_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_start")) { - cgi_dbg("Setting DHCP range start IP to: \"%s\"", buff); - u32 ip = ipaddr_addr(buff); - if (ip != 0) { - if (wificonf->ap_dhcp_range.start_ip.addr != ip) { - wificonf->ap_dhcp_range.start_ip.addr = ip; - wifi_change_flags.ap = true; - } - } else { - cgi_warn("Bad IP: %s", buff); - redir_url += sprintf(redir_url, "ap_dhcp_start,"); - } - } - - if (GET_ARG("ap_dhcp_end")) { - cgi_dbg("Setting DHCP range end IP to: \"%s\"", buff); - u32 ip = ipaddr_addr(buff); - if (ip != 0) { - if (wificonf->ap_dhcp_range.end_ip.addr != ip) { - wificonf->ap_dhcp_range.end_ip.addr = ip; - wifi_change_flags.ap = true; - } - } else { - cgi_warn("Bad IP: %s", buff); - redir_url += sprintf(redir_url, "ap_dhcp_end,"); - } - } - - // ---- AP local address & config ---- - - if (GET_ARG("ap_addr_ip")) { - cgi_dbg("Setting AP local IP to: \"%s\"", buff); - u32 ip = ipaddr_addr(buff); - if (ip != 0) { - if (wificonf->ap_addr.ip.addr != ip) { - 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 { - cgi_warn("Bad IP: %s", buff); - redir_url += sprintf(redir_url, "ap_addr_ip,"); - } - } - - if (GET_ARG("ap_addr_mask")) { - cgi_dbg("Setting AP local IP netmask to: \"%s\"", buff); - u32 ip = ipaddr_addr(buff); - if (ip != 0) { - if (wificonf->ap_addr.netmask.addr != ip) { - // 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 { - cgi_warn("Bad IP mask: %s", buff); - redir_url += sprintf(redir_url, "ap_addr_mask,"); - } - } - - // ---- Station enable/disable DHCP ---- - - // DHCP enable / disable (disable means static IP is enabled) - if (GET_ARG("sta_dhcp_enable")) { - cgi_dbg("DHCP enable = %s", buff); - int enable = atoi(buff); - if (wificonf->sta_dhcp_enable != enable) { - wificonf->sta_dhcp_enable = (bool)enable; - wifi_change_flags.sta = true; - } - } - - // ---- Station IP config (Static IP) ---- - - if (GET_ARG("sta_addr_ip")) { - cgi_dbg("Setting Station mode static IP to: \"%s\"", buff); - u32 ip = ipaddr_addr(buff); - if (ip != 0) { - if (wificonf->sta_addr.ip.addr != ip) { - wificonf->sta_addr.ip.addr = ip; - wifi_change_flags.sta = true; - } - } else { - cgi_warn("Bad IP: %s", buff); - redir_url += sprintf(redir_url, "sta_addr_ip,"); - } - } - - if (GET_ARG("sta_addr_mask")) { - cgi_dbg("Setting Station mode static IP netmask to: \"%s\"", buff); - u32 ip = ipaddr_addr(buff); - if (ip != 0 && ip != 0xFFFFFFFFUL) { - if (wificonf->sta_addr.netmask.addr != ip) { - wificonf->sta_addr.netmask.addr = ip; - wifi_change_flags.sta = true; - } - } else { - cgi_warn("Bad IP mask: %s", buff); - redir_url += sprintf(redir_url, "sta_addr_mask,"); - } - } - - if (GET_ARG("sta_addr_gw")) { - cgi_dbg("Setting Station mode static IP default gateway to: \"%s\"", buff); - u32 ip = ipaddr_addr(buff); - if (ip != 0) { - if (wificonf->sta_addr.gw.addr != ip) { - wificonf->sta_addr.gw.addr = ip; - wifi_change_flags.sta = true; - } - } else { - cgi_warn("Bad gw IP: %s", buff); - redir_url += sprintf(redir_url, "sta_addr_gw,"); - } - } +#define X XSET_CGI_FUNC + XTABLE_WIFI +#undef X (void) redir_url; @@ -216,7 +88,7 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiNetworkSetParams(HttpdConnData *connData) //Template code for the WLAN page. httpd_cgi_state ICACHE_FLASH_ATTR tplNetwork(HttpdConnData *connData, char *token, void **arg) { - char buff[20]; + char buff[64]; u8 mac[6]; if (token == NULL) { @@ -226,34 +98,12 @@ httpd_cgi_state ICACHE_FLASH_ATTR tplNetwork(HttpdConnData *connData, char *toke strcpy(buff, ""); // fallback - if (streq(token, "ap_dhcp_time")) { - sprintf(buff, "%d", wificonf->ap_dhcp_time); - } - else if (streq(token, "ap_dhcp_start")) { - sprintf(buff, IPSTR, GOOD_IP2STR(wificonf->ap_dhcp_range.start_ip.addr)); - } - else if (streq(token, "ap_dhcp_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_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, "sta_addr_mask")) { - sprintf(buff, IPSTR, GOOD_IP2STR(wificonf->sta_addr.netmask.addr)); - } - else if (streq(token, "sta_addr_gw")) { - sprintf(buff, IPSTR, GOOD_IP2STR(wificonf->sta_addr.gw.addr)); - } - else if (streq(token, "sta_mac")) { +#define X XGET_CGI_FUNC + XTABLE_WIFI +#undef X + + // non-config + if (streq(token, "sta_mac")) { wifi_get_macaddr(STATION_IF, mac); sprintf(buff, MACSTR, MAC2STR(mac)); } diff --git a/user/cgi_wifi.c b/user/cgi_wifi.c index 7378977..41be75d 100644 --- a/user/cgi_wifi.c +++ b/user/cgi_wifi.c @@ -19,6 +19,7 @@ Cgi/template routines for the /wifi url. #include "wifimgr.h" #include "persist.h" #include "helpers.h" +#include "config_xmacros.h" #include "cgi_logging.h" #define SET_REDIR_SUC "/cfg/wifi" @@ -66,46 +67,6 @@ int ICACHE_FLASH_ATTR rssi2perc(int rssi) return r; } -/** - * Convert Auth type to string - */ -const ICACHE_FLASH_ATTR char *auth2str(AUTH_MODE auth) -{ - switch (auth) { - case AUTH_OPEN: - return "Open"; - case AUTH_WEP: - return "WEP"; - case AUTH_WPA_PSK: - return "WPA"; - case AUTH_WPA2_PSK: - return "WPA2"; - case AUTH_WPA_WPA2_PSK: - return "WPA/WPA2"; - default: - return "Unknown"; - } -} - -/** - * Convert WiFi opmode to string - */ -const ICACHE_FLASH_ATTR char *opmode2str(WIFI_MODE opmode) -{ - switch (opmode) { - case NULL_MODE: - return "Disabled"; - case STATION_MODE: - return "Client"; - case SOFTAP_MODE: - return "AP only"; - case STATIONAP_MODE: - return "Client+AP"; - default: - return "Unknown"; - } -} - /** * Callback the code calls when a wlan ap scan is done. Basically stores the result in * the static cgiWifiAps struct. @@ -363,18 +324,13 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData) bool sta_turned_on = false; bool sta_ssid_pw_changed = false; +#define X XSET_CGI_FUNC + XTABLE_WIFI +#undef X + // ---- WiFi opmode ---- - if (GET_ARG("opmode")) { - cgi_dbg("Setting WiFi opmode to: %s", buff); - int mode = atoi(buff); - if (mode > NULL_MODE && mode < MAX_MODE) { - wificonf->opmode = (WIFI_MODE) mode; - } else { - cgi_warn("Bad opmode value \"%s\"", buff); - redir_url += sprintf(redir_url, "opmode,"); - } - } + // those are helpers, not a real prop if (GET_ARG("ap_enable")) { cgi_dbg("Enable AP: %s", buff); @@ -399,114 +355,6 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData) } } - // ---- AP transmit power ---- - - if (GET_ARG("tpw")) { - cgi_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 - if (wificonf->tpw != tpw) { - wificonf->tpw = (u8) tpw; - wifi_change_flags.ap = true; - } - } else { - cgi_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")) { - cgi_info("ap_channel = %s", buff); - int channel = atoi(buff); - if (channel > 0 && channel < 15) { - if (wificonf->ap_channel != channel) { - wificonf->ap_channel = (u8) channel; - wifi_change_flags.ap = true; - } - } else { - cgi_warn("Bad channel value \"%s\", allowed 1-14", buff); - redir_url += sprintf(redir_url, "ap_channel,"); - } - } - - // ---- SSID name in AP mode ---- - - if (GET_ARG("ap_ssid")) { - // Replace all invalid ASCII with underscores - int i; - for (i = 0; i < 32; i++) { - char c = buff[i]; - if (c == 0) break; - if (c < 32 || c >= 127) buff[i] = '_'; - } - buff[i] = 0; - - if (strlen(buff) > 0) { - if (!streq(wificonf->ap_ssid, buff)) { - cgi_info("Setting SSID to \"%s\"", buff); - strncpy_safe(wificonf->ap_ssid, buff, SSID_LEN); - wifi_change_flags.ap = true; - } - } else { - cgi_warn("Bad SSID len."); - redir_url += sprintf(redir_url, "ap_ssid,"); - } - } - - // ---- AP password ---- - - if (GET_ARG("ap_password")) { - // Users are free to use any stupid shit in ther password, - // but it may lock them out. - if (strlen(buff) == 0 || (strlen(buff) >= 8 && strlen(buff) < PASSWORD_LEN-1)) { - if (!streq(wificonf->ap_password, buff)) { - cgi_info("Setting AP password to \"%s\"", buff); - strncpy_safe(wificonf->ap_password, buff, PASSWORD_LEN); - wifi_change_flags.ap = true; - } - } else { - cgi_warn("Bad password len."); - redir_url += sprintf(redir_url, "ap_password,"); - } - } - - // ---- Hide AP network (do not announce) ---- - - if (GET_ARG("ap_hidden")) { - cgi_dbg("AP hidden = %s", buff); - int hidden = atoi(buff); - if (hidden != wificonf->ap_hidden) { - wificonf->ap_hidden = (hidden != 0); - wifi_change_flags.ap = true; - } - } - - // ---- Station SSID (to connect to) ---- - - if (GET_ARG("sta_ssid")) { - if (!streq(wificonf->sta_ssid, buff)) { - // No verification needed, at worst it fails to connect - cgi_info("Setting station SSID to: \"%s\"", buff); - strncpy_safe(wificonf->sta_ssid, buff, SSID_LEN); - wifi_change_flags.sta = true; - sta_ssid_pw_changed = true; - } - } - - // ---- Station password (empty for none is allowed) ---- - - if (GET_ARG("sta_password")) { - if (!streq(wificonf->sta_password, buff)) { - // No verification needed, at worst it fails to connect - cgi_info("Setting station password to: \"%s\"", buff); - strncpy_safe(wificonf->sta_password, buff, PASSWORD_LEN); - wifi_change_flags.sta = true; - sta_ssid_pw_changed = true; - } - } - (void)redir_url; if (redir_url_buf[strlen(SET_REDIR_ERR)] == 0) { @@ -552,7 +400,6 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData) return HTTPD_CGI_DONE; } - //Template code for the WLAN page. httpd_cgi_state ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token, void **arg) { @@ -567,39 +414,17 @@ httpd_cgi_state ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token, strcpy(buff, ""); // fallback - if (streq(token, "opmode_name")) { - strcpy(buff, opmode2str(wificonf->opmode)); - } - else if (streq(token, "opmode")) { - sprintf(buff, "%d", wificonf->opmode); - } - else if (streq(token, "sta_enable")) { +#define X XGET_CGI_FUNC + XTABLE_WIFI +#undef X + + // non-config + if (streq(token, "sta_enable")) { sprintf(buff, "%d", (wificonf->opmode & STATION_MODE) != 0); } else if (streq(token, "ap_enable")) { sprintf(buff, "%d", (wificonf->opmode & SOFTAP_MODE) != 0); } - else if (streq(token, "tpw")) { - sprintf(buff, "%d", wificonf->tpw); - } - else if (streq(token, "ap_channel")) { - sprintf(buff, "%d", wificonf->ap_channel); - } - else if (streq(token, "ap_ssid")) { - 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, "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_rssi")) { sprintf(buff, "%d", wifi_station_get_rssi()); } diff --git a/user/config_xmacros.c b/user/config_xmacros.c new file mode 100644 index 0000000..55105f8 --- /dev/null +++ b/user/config_xmacros.c @@ -0,0 +1,99 @@ +// +// Created by MightyPork on 2017/10/22. +// + +#include "config_xmacros.h" +#include "cgi_logging.h" + +void ICACHE_FLASH_ATTR xget_dec(char *buff, u32 value) +{ + sprintf(buff, "%d", value); +} + +void ICACHE_FLASH_ATTR xget_bool(char *buff, bool value) +{ + sprintf(buff, "%d", value?1:0); +} + +void ICACHE_FLASH_ATTR xget_ustring(char *buff, const u8 *value) +{ + sprintf(buff, "%s", (const char *) value); +} + +void ICACHE_FLASH_ATTR xget_string(char *buff, const char *value) +{ + sprintf(buff, "%s", value); +} + +void ICACHE_FLASH_ATTR xget_ip(char *buff, const struct ip_addr *value) +{ + sprintf(buff, IPSTR, GOOD_IP2STR(value->addr)); +} + +// ------------- XSET ------------- + +enum xset_result ICACHE_FLASH_ATTR +xset_ip(const char *name, struct ip_addr *field, const char *buff, const void *arg) +{ + cgi_dbg("Setting %s = %s", name, buff); + u32 ip = ipaddr_addr(buff); + if (ip != 0 && ip != 0xFFFFFFFFUL) { + if (field->addr != ip) { + field->addr = ip; + return XSET_SET; + } + return XSET_UNCHANGED; + } else { + cgi_warn("Bad IP: %s", buff); + return XSET_FAIL; + } +} + +enum xset_result ICACHE_FLASH_ATTR +xset_bool(const char *name, bool *field, const char *buff, const void *arg) +{ + cgi_dbg("Setting %s = %s", name, buff); + bool enable = (atoi(buff) != 0); + + if (*field != enable) { + *field = enable; + return XSET_SET; + } + return XSET_UNCHANGED; +} + +enum xset_result ICACHE_FLASH_ATTR +xset_u8(const char *name, u8 *field, const char *buff, const void *arg) +{ + cgi_dbg("Setting %s = %s", name, buff); + u32 val = (u32) atoi(buff); + + if (val <= 255) { + if (*field != val) { + *field = (u8) val; + return XSET_SET; + } + return XSET_UNCHANGED; + } else { + cgi_warn("Bad value, max 255: %s", buff); + return XSET_FAIL; + } +} + +enum xset_result ICACHE_FLASH_ATTR +xset_string(const char *name, char *field, const char *buff, const void *arg) +{ + cgi_dbg("Setting %s = %s", name, buff); + u32 maxlen = (u32) arg; + + if (arg > 0 && (u32)strlen(buff) > maxlen) { + cgi_warn("String too long, max %d", maxlen); + return XSET_FAIL; + } + + if (!streq(field, buff)) { + strncpy_safe(field, buff, (u32)arg); + return XSET_SET; + } + return XSET_UNCHANGED; +} diff --git a/user/config_xmacros.h b/user/config_xmacros.h new file mode 100644 index 0000000..bad4d18 --- /dev/null +++ b/user/config_xmacros.h @@ -0,0 +1,85 @@ +// +// Created by MightyPork on 2017/10/22. +// + +#ifndef ESPTERM_CONFIG_XMACROS_H +#define ESPTERM_CONFIG_XMACROS_H + +#include +#include + +#define XJOIN(a, b) a##b + +/**Do nothing xnotify */ +#define xnoop() + +/** + * XGET interface + * + * @param buff - buffer where the value should be printed + * @param value - value to render to the buffer + */ + +static inline bool xget_dummy(char *buff, u32 value) +{ + sprintf(buff, "unused %d", value); + return false; +} + +void xget_dec(char *buff, u32 value); +void xget_bool(char *buff, bool value); +void xget_ustring(char *buff, const u8 *value); +void xget_string(char *buff, const char *value); +void xget_ip(char *buff, const struct ip_addr *value); +void xget_dhcp(char *buff, const struct dhcps_lease *value); + + +/** + * XSET interface + * + * @param name - field name (for debug) + * @param field - pointer to the target field + * @param buff - field with the value to be set + * @param arg - arbitrary argument, used to modify behavior + * + * @return xset_result + */ + +enum xset_result { + XSET_FAIL = 0, + XSET_SET = 1, + XSET_UNCHANGED = 2 +}; + +// Dummy for unimplemented setters +static inline enum xset_result xset_dummy(const char *name, void *field, const char *buff, const void *arg) +{ + return XSET_UNCHANGED; +} + +enum xset_result xset_ip(const char *name, struct ip_addr *field, const char *buff, const void *arg); +enum xset_result xset_bool(const char *name, bool *field, const char *buff, const void *arg); +enum xset_result xset_u8(const char *name, u8 *field, const char *buff, const void *arg); + +/** + * @param arg - max string length + */ +enum xset_result xset_string(const char *name, char *field, const char *buff, const void *arg); + +/** + * Helper template macro for CGI functions that load GET args to structs using XTABLE + * + * If 'name' is found in connData->getArgs, xset() is called. + * If the result is SET, xnotify() is fired. Else, 'name,' is appended to the redir_url buffer. + */ +#define XSET_CGI_FUNC(type, name, suffix, deref, xget, cast, xset, xsarg, xnotify) \ + if (GET_ARG(#name)) { \ + enum xset_result res = xset(#name, cast &wificonf->name, buff, (const void*) (xsarg)); \ + if (res == XSET_SET) { xnotify(); } \ + else if (res == XSET_FAIL) { redir_url += sprintf(redir_url, #name","); } \ + } + +#define XGET_CGI_FUNC(type, name, suffix, deref, xget, cast, xset, xsarg, xnotify) \ + if (streq(token, #name)) xget(buff, deref wificonf->name); + +#endif //ESPTERM_CONFIG_XMACROS_H diff --git a/user/wifimgr.c b/user/wifimgr.c index 2588365..46d028a 100644 --- a/user/wifimgr.c +++ b/user/wifimgr.c @@ -4,10 +4,127 @@ #include "wifimgr.h" #include "persist.h" +#include "cgi_logging.h" +#include "config_xmacros.h" WiFiConfigBundle * const wificonf = &persist.current.wificonf; WiFiConfChangeFlags wifi_change_flags; +enum xset_result ICACHE_FLASH_ATTR +xset_wifi_lease_time(const char *name, u16 *field, const char *buff, const void *arg) +{ + cgi_dbg("Setting %s = %s min", name, buff); + int min = atoi(buff); + if (min >= 1 && min <= 2880) { + if (*field != min) { + *field = (u16) min; + return XSET_SET; + } + return XSET_UNCHANGED; + } else { + cgi_warn("Lease time %s out of allowed range 1-2880.", buff); + return XSET_FAIL; + } +} + +enum xset_result ICACHE_FLASH_ATTR +xset_wifi_opmode(const char *name, u8 *field, const char *buff, const void *arg) +{ + cgi_dbg("Setting %s = %s", name, buff); + int mode = atoi(buff); + if (mode > NULL_MODE && mode < MAX_MODE) { + if (*field != mode) { + *field = (WIFI_MODE) mode; + return XSET_SET; + } + return XSET_UNCHANGED; // opmode does not use flags + } else { + cgi_warn("Bad opmode value \"%s\"", buff); + return XSET_FAIL; + } +} + +enum xset_result ICACHE_FLASH_ATTR +xset_wifi_tpw(const char *name, u8 *field, const char *buff, const void *arg) +{ + cgi_dbg("Setting %s = %s", name, buff); + int tpw = atoi(buff); + if (tpw >= 0 && tpw <= 82) { // 0 actually isn't 0 but quite low. 82 is very strong + if (*field != tpw) { + *field = (u8) tpw; + return XSET_SET; + } + return XSET_UNCHANGED; + } else { + cgi_warn("tpw %s out of allowed range 0-82.", buff); + return XSET_FAIL; + } +} + +enum xset_result ICACHE_FLASH_ATTR +xset_wifi_ap_channel(const char *name, u8 *field, const char *buff, const void *arg) +{ + cgi_dbg("Setting %s = %s", name, buff); + int channel = atoi(buff); + if (channel > 0 && channel < 15) { + if (*field != channel) { + *field = (u8) channel; + return XSET_SET; + } + return XSET_UNCHANGED; + } else { + cgi_warn("Bad channel value \"%s\", allowed 1-14", buff); + return XSET_FAIL; + } +} + +enum xset_result ICACHE_FLASH_ATTR +xset_wifi_ssid(const char *name, u8 **field, const char *buff, const void *arg) +{ + u8 buff2[SSID_LEN]; + + bool want_subs = arg!=0; + + int i; + for (i = 0; i < SSID_LEN; i++) { + char c = buff[i]; + if (c == 0) break; + if (want_subs && (c < 32 || c >= 127)) c = '_'; + buff2[i] = (u8) c; + } + buff2[i] = 0; + + cgi_dbg("Setting %s = %s", name, buff); + if (strlen((char *)buff2) > 0) { + if (!streq(*field, buff2)) { + strncpy_safe(*field, buff2, SSID_LEN); + return XSET_SET; + } + return XSET_UNCHANGED; + } else { + cgi_warn("Bad SSID len."); + return XSET_FAIL; + } +} + +/** Set PW - allow len 0 or 8-64 */ +enum xset_result ICACHE_FLASH_ATTR +xset_wifi_pwd(const char *name, u8 **field, const char *buff, const void *arg) +{ + cgi_dbg("Setting %s = %s", name, buff); + if (strlen(buff) == 0 || (strlen(buff) >= 8 && strlen(buff) < PASSWORD_LEN-1)) { + if (!streq(*field, buff)) { + strncpy_safe(*field, buff, PASSWORD_LEN); + return XSET_SET; + } + return XSET_UNCHANGED; + } else { + cgi_warn("Bad password len."); + return XSET_FAIL; + } +} + + int ICACHE_FLASH_ATTR getStaIpAsString(char *buffer) { WIFI_MODE x = wifi_get_opmode(); @@ -42,13 +159,11 @@ wifimgr_restore_defaults(void) wificonf->ap_password[0] = 0; // PSK2 always if password is not null. wificonf->ap_hidden = false; - IP4_ADDR(&wificonf->ap_addr.ip, 192, 168, 4, 1); - IP4_ADDR(&wificonf->ap_addr.netmask, 255, 255, 255, 0); - wificonf->ap_addr.gw.addr = wificonf->ap_addr.gw.addr; + IP4_ADDR(&wificonf->ap_addr_ip, 192, 168, 4, 1); + IP4_ADDR(&wificonf->ap_addr_mask, 255, 255, 255, 0); - IP4_ADDR(&wificonf->ap_dhcp_range.start_ip, 192, 168, 4, 100); - IP4_ADDR(&wificonf->ap_dhcp_range.end_ip, 192, 168, 4, 200); - wificonf->ap_dhcp_range.enable = 1; // this will never get changed, idk why it's even there + IP4_ADDR(&wificonf->ap_dhcp_start, 192, 168, 4, 100); + IP4_ADDR(&wificonf->ap_dhcp_end, 192, 168, 4, 200); wificonf->ap_dhcp_time = 120; // --- Client config --- @@ -56,9 +171,9 @@ wifimgr_restore_defaults(void) wificonf->sta_password[0] = 0; wificonf->sta_dhcp_enable = true; - 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_addr.netmask, 255, 255, 255, 0); - IP4_ADDR(&wificonf->sta_addr.gw, 192, 168, 0, 1); + 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_addr_mask, 255, 255, 255, 0); + IP4_ADDR(&wificonf->sta_addr_gw, 192, 168, 0, 1); // a common default... } static void ICACHE_FLASH_ATTR @@ -83,13 +198,18 @@ configure_station(void) } else { wifi_info("[WiFi] Setting up static IP..."); - wifi_dbg("[WiFi] Client.ip = "IPSTR, GOOD_IP2STR(wificonf->sta_addr.ip.addr)); - wifi_dbg("[WiFi] Client.mask = "IPSTR, GOOD_IP2STR(wificonf->sta_addr.netmask.addr)); - wifi_dbg("[WiFi] Client.gw = "IPSTR, GOOD_IP2STR(wificonf->sta_addr.gw.addr)); + wifi_dbg("[WiFi] Client.ip = "IPSTR, GOOD_IP2STR(wificonf->sta_addr_ip.addr)); + wifi_dbg("[WiFi] Client.mask = "IPSTR, GOOD_IP2STR(wificonf->sta_addr_mask.addr)); + wifi_dbg("[WiFi] Client.gw = "IPSTR, GOOD_IP2STR(wificonf->sta_addr_gw.addr)); wifi_station_dhcpc_stop(); // Load static IP config - if (!wifi_set_ip_info(STATION_IF, &wificonf->sta_addr)) { + struct ip_info ipstruct; + ipstruct.ip.addr = wificonf->sta_addr_ip.addr; + ipstruct.netmask.addr = wificonf->sta_addr_mask.addr; + ipstruct.gw.addr = wificonf->sta_addr_gw.addr; + + if (!wifi_set_ip_info(STATION_IF, &ipstruct)) { error("[WiFi] Error setting static IP!"); return; } @@ -112,7 +232,7 @@ configure_ap(void) strcpy((char *) conf.password, (char *) wificonf->ap_password); conf.authmode = (wificonf->ap_password[0] == 0 ? AUTH_OPEN : AUTH_WPA2_PSK); conf.ssid_len = (uint8_t) strlen((char *) conf.ssid); - conf.ssid_hidden = wificonf->ap_hidden; + conf.ssid_hidden = (uint8) wificonf->ap_hidden; conf.max_connection = 4; // default 4 (max possible) conf.beacon_interval = 100; // default 100 ms @@ -127,24 +247,32 @@ configure_ap(void) // Set IP wifi_info("[WiFi] Configuring SoftAP local IP..."); - wifi_dbg("[WiFi] SoftAP.ip = "IPSTR, GOOD_IP2STR(wificonf->ap_addr.ip.addr)); - wifi_dbg("[WiFi] SoftAP.mask = "IPSTR, GOOD_IP2STR(wificonf->ap_addr.netmask.addr)); - wifi_dbg("[WiFi] SoftAP.gw = "IPSTR, GOOD_IP2STR(wificonf->ap_addr.gw.addr)); + wifi_dbg("[WiFi] SoftAP.ip = "IPSTR, GOOD_IP2STR(wificonf->ap_addr_ip.addr)); + wifi_dbg("[WiFi] SoftAP.mask = "IPSTR, GOOD_IP2STR(wificonf->ap_addr_mask.addr)); wifi_softap_dhcps_stop(); // Configure DHCP - if (!wifi_set_ip_info(SOFTAP_IF, &wificonf->ap_addr)) { + struct ip_info ipstruct; + ipstruct.ip.addr = wificonf->ap_addr_ip.addr; + ipstruct.netmask.addr = wificonf->ap_addr_mask.addr; + ipstruct.gw.addr = wificonf->ap_addr_ip.addr; + + if (!wifi_set_ip_info(SOFTAP_IF, &ipstruct)) { error("[WiFi] IP set fail!"); return; } wifi_info("[WiFi] Configuring SoftAP DHCP server..."); - wifi_dbg("[WiFi] DHCP.start = "IPSTR, GOOD_IP2STR(wificonf->ap_dhcp_range.start_ip.addr)); - wifi_dbg("[WiFi] DHCP.end = "IPSTR, GOOD_IP2STR(wificonf->ap_dhcp_range.end_ip.addr)); + wifi_dbg("[WiFi] DHCP.start = "IPSTR, GOOD_IP2STR(wificonf->ap_dhcp_start.addr)); + wifi_dbg("[WiFi] DHCP.end = "IPSTR, GOOD_IP2STR(wificonf->ap_dhcp_end.addr)); wifi_dbg("[WiFi] DHCP.lease = %d minutes", wificonf->ap_dhcp_time); - if (!wifi_softap_set_dhcps_lease(&wificonf->ap_dhcp_range)) { + struct dhcps_lease dhcpstruct; + dhcpstruct.start_ip = wificonf->ap_dhcp_start; + dhcpstruct.end_ip = wificonf->ap_dhcp_end; + dhcpstruct.enable = 1; // ??? + if (!wifi_softap_set_dhcps_lease(&dhcpstruct)) { error("[WiFi] DHCP address range set fail!"); return; } @@ -190,7 +318,7 @@ wifimgr_apply_settings(void) } if (opmode != wificonf->opmode) { - wifi_set_opmode_current(wificonf->opmode); + wifi_set_opmode_current((WIFI_MODE) wificonf->opmode); } // Configure the client diff --git a/user/wifimgr.h b/user/wifimgr.h index 146c3c8..22e70b0 100644 --- a/user/wifimgr.h +++ b/user/wifimgr.h @@ -19,6 +19,43 @@ #define WIFICONF_VERSION 0 +#define wifimgr_notify_ap() { wifi_change_flags.ap = true; } +#define wifimgr_notify_sta() { wifi_change_flags.ap = true; } + +//....Type................Name..Suffix...............Deref..XGET.........Cast..XSET.........................NOTIFY +#define XTABLE_WIFI \ + X(u8, opmode, , , xget_dec, , xset_wifi_opmode, NULL, xnoop) \ + \ + X(u8, tpw, , , xget_dec, , xset_wifi_tpw, NULL, wifimgr_notify_ap) \ + X(u8, ap_channel, , , xget_dec, , xset_wifi_ap_channel, NULL, wifimgr_notify_ap) \ + X(u8, ap_ssid, [SSID_LEN], , xget_ustring, (u8**), xset_wifi_ssid, 1, wifimgr_notify_ap) \ + X(u8, ap_password, [PASSWORD_LEN], , xget_ustring, (u8**), xset_wifi_pwd, NULL, wifimgr_notify_ap) \ + X(bool, ap_hidden, , , xget_bool, , xset_bool, NULL, wifimgr_notify_ap) \ + \ + X(u16, ap_dhcp_time, , , xget_dec, , xset_wifi_lease_time, NULL, wifimgr_notify_ap) \ + X(u32, unused1, , , xget_dummy, , xset_dummy, NULL, xnoop) \ + X(struct ip_addr, ap_dhcp_start, , &, xget_ip, , xset_ip, NULL, wifimgr_notify_ap) \ + X(struct ip_addr, ap_dhcp_end, , &, xget_ip, , xset_ip, NULL, wifimgr_notify_ap) \ + \ + X(struct ip_addr, ap_addr_ip, , &, xget_ip, , xset_ip, NULL, wifimgr_notify_ap) \ + X(struct ip_addr, ap_addr_mask, , &, xget_ip, , xset_ip, NULL, wifimgr_notify_ap) \ + \ + \ + X(u32, unused2, , , xget_dummy, , xset_dummy, NULL, xnoop) \ + X(u8, sta_ssid, [SSID_LEN], , xget_ustring, (u8**), xset_wifi_ssid, 0, wifimgr_notify_sta) \ + X(u8, sta_password, [PASSWORD_LEN], , xget_ustring, (u8**), xset_wifi_pwd, NULL, wifimgr_notify_sta) \ + X(bool, sta_dhcp_enable, , , xget_bool, , xset_bool, NULL, wifimgr_notify_sta) \ + \ + X(struct ip_addr, sta_addr_ip, , &, xget_ip, , xset_ip, NULL, wifimgr_notify_sta) \ + X(struct ip_addr, sta_addr_mask, , &, xget_ip, , xset_ip, NULL, wifimgr_notify_sta) \ + X(struct ip_addr, sta_addr_gw, , &, xget_ip, , xset_ip, NULL, wifimgr_notify_sta) \ + \ + \ + X(u8, config_version, , , xget_dec, , xset_u8, NULL, xnoop) + +// unused1 - replaces 'enabled' bit from old dhcps_lease struct +// unused2 - gap after 'ap_gw' which isn't used and doesn't make sense + /** * A structure holding all configured WiFi parameters * and the active state. @@ -26,25 +63,15 @@ * This block can be used eg. for WiFi config backup. */ typedef struct { - WIFI_MODE opmode : 8; - u8 tpw; - - // AP config - u8 ap_channel; - u8 ap_ssid[SSID_LEN]; - u8 ap_password[PASSWORD_LEN]; - bool ap_hidden; - // - u16 ap_dhcp_time; // in minutes - struct dhcps_lease ap_dhcp_range; - struct ip_info ap_addr; - - // Client config - u8 sta_ssid[SSID_LEN]; - u8 sta_password[PASSWORD_LEN]; - bool sta_dhcp_enable; - struct ip_info sta_addr; - u8 config_version; +#define X( \ + type, name, suffix, \ + deref, xget, \ + cast, xset, xsarg, \ + xnotify) type name suffix; + + XTABLE_WIFI + +#undef X } WiFiConfigBundle; typedef struct { @@ -62,6 +89,13 @@ void wifimgr_apply_settings(void); int getStaIpAsString(char *buffer); +enum xset_result xset_wifi_lease_time(const char *name, u16 *field, const char *buff, const void *arg); +enum xset_result xset_wifi_opmode(const char *name, u8 *field, const char *buff, const void *arg); +enum xset_result xset_wifi_tpw(const char *name, u8 *field, const char *buff, const void *arg); +enum xset_result xset_wifi_ap_channel(const char *name, u8 *field, const char *buff, const void *arg); +enum xset_result xset_wifi_ssid(const char *name, u8 **field, const char *buff, const void *arg); +enum xset_result xset_wifi_pwd(const char *name, u8 **field, const char *buff, const void *arg); + #if DEBUG_WIFI #define wifi_warn warn #define wifi_dbg dbg