Merge branch 'xmacro-config' into work
This commit is contained in:
+4
-1
@@ -146,9 +146,12 @@ set(SOURCE_FILES
|
||||
user/jstring.c
|
||||
user/jstring.h
|
||||
user/character_sets.h
|
||||
user/ini_parser.h
|
||||
user/ini_parser.c
|
||||
user/ini_parser.rl
|
||||
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)
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
echo "-- Building parser from Ragel source --"
|
||||
|
||||
ragel -L -G0 user/ansi_parser.rl -o user/ansi_parser.c
|
||||
ragel -L -G0 user/ini_parser.rl -o user/ini_parser.c
|
||||
|
||||
sed -i "s/static const char _ansi_actions\[\]/static const char _ansi_actions\[\] ESP_CONST_DATA/" user/ansi_parser.c
|
||||
sed -i "s/static const char _ansi_eof_actions\[\]/static const char _ansi_eof_actions\[\] ESP_CONST_DATA/" user/ansi_parser.c
|
||||
|
||||
sed -i "s/static const char _ini_actions\[\]/static const char _ini_actions\[\] ESP_CONST_DATA/" user/ini_parser.c
|
||||
sed -i "s/static const char _ini_eof_actions\[\]/static const char _ini_eof_actions\[\] ESP_CONST_DATA/" user/ini_parser.c
|
||||
|
||||
@@ -40,6 +40,7 @@ ESP_SPI_FLASH_SIZE_K = 1024
|
||||
|
||||
GLOBAL_CFLAGS = \
|
||||
-DASYNC_LOG=1 \
|
||||
-DDEBUG_INI=1 \
|
||||
-DDEBUG_D2D=0 \
|
||||
-DDEBUG_ROUTER=0 \
|
||||
-DDEBUG_CAPTDNS=0 \
|
||||
|
||||
+1
-1
Submodule front-end updated: d2fabc40f1...a96b522ca8
+1
-1
Submodule libesphttpd updated: e4ecf0724e...d6651ca0d1
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
xtensa-lx106-elf-gcc -E -Iuser -Ilibesphttpd/include -Iesp_iot_sdk_v1.5.2/include -Iinclude $@
|
||||
+1
-1
@@ -59,7 +59,7 @@ apars_handle_osc(char *buffer)
|
||||
}
|
||||
else if (n >= 91 && n <= 95) {
|
||||
// ESPTerm: action button message
|
||||
strncpy(termconf_live.btn_msg[n - 91], buffer, TERM_BTN_MSG_LEN);
|
||||
screen_set_button_message(n - 90, buffer);
|
||||
}
|
||||
else {
|
||||
ansi_noimpl("OSC %d ; %s ST", n, buffer);
|
||||
|
||||
+13
-161
@@ -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,10 @@ 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 XSTRUCT wificonf
|
||||
#define X XSET_CGI_FUNC
|
||||
XTABLE_WIFICONF
|
||||
#undef X
|
||||
|
||||
(void) redir_url;
|
||||
|
||||
@@ -216,7 +89,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 +99,13 @@ 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 XSTRUCT wificonf
|
||||
#define X XGET_CGI_FUNC
|
||||
XTABLE_WIFICONF
|
||||
#undef X
|
||||
|
||||
// non-config
|
||||
if (streq(token, "sta_mac")) {
|
||||
wifi_get_macaddr(STATION_IF, mac);
|
||||
sprintf(buff, MACSTR, MAC2STR(mac));
|
||||
}
|
||||
|
||||
@@ -7,8 +7,13 @@ Cgi/template routines for configuring non-wifi settings
|
||||
#include "persist.h"
|
||||
#include "helpers.h"
|
||||
#include "cgi_logging.h"
|
||||
#include "version.h"
|
||||
#include "screen.h"
|
||||
#include "config_xmacros.h"
|
||||
#include "ini_parser.h"
|
||||
|
||||
#define SET_REDIR_SUC "/cfg/system"
|
||||
#define SET_REDIR_ERR SET_REDIR_SUC"?err="
|
||||
|
||||
static bool ICACHE_FLASH_ATTR
|
||||
verify_admin_pw(const char *pw)
|
||||
@@ -74,3 +79,358 @@ cgiPersistRestoreHard(HttpdConnData *connData)
|
||||
httpdRedirect(connData, SET_REDIR_SUC "?msg=All%20settings%20restored%20to%20factory%20defaults.");
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
// -------------- Export --------------
|
||||
|
||||
#define httpdSend_orDie(conn, data, len) do { if (!httpdSend((conn), (data), (len))) return false; } while (0)
|
||||
|
||||
/* encode for double-quoted string */
|
||||
int ICACHE_FLASH_ATTR httpdSend_dblquot(HttpdConnData *conn, const char *data, int len)
|
||||
{
|
||||
int start = 0, end = 0;
|
||||
char c;
|
||||
if (conn->conn==NULL) return 0;
|
||||
if (len < 0) len = (int) strlen(data);
|
||||
if (len==0) return 0;
|
||||
|
||||
for (end = 0; end < len; end++) {
|
||||
c = data[end];
|
||||
if (c == 0) {
|
||||
// we found EOS
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '"' || c == '\'' || c == '\\' || c == '\n' || c == '\r' || c == '\x1b') {
|
||||
if (start < end) httpdSend_orDie(conn, data + start, end - start);
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
if (c == '"') httpdSend_orDie(conn, "\\\"", 2);
|
||||
else if (c == '\'') httpdSend_orDie(conn, "\\'", 2);
|
||||
else if (c == '\\') httpdSend_orDie(conn, "\\\\", 2);
|
||||
else if (c == '\n') httpdSend_orDie(conn, "\\n", 2);
|
||||
else if (c == '\r') httpdSend_orDie(conn, "\\r", 2);
|
||||
else if (c == '\x1b') httpdSend_orDie(conn, "\\e", 2);
|
||||
}
|
||||
|
||||
if (start < end) httpdSend_orDie(conn, data + start, end - start);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export settings to INI
|
||||
*
|
||||
* @param connData
|
||||
* @return status
|
||||
*/
|
||||
httpd_cgi_state ICACHE_FLASH_ATTR
|
||||
cgiPersistExport(HttpdConnData *connData)
|
||||
{
|
||||
char buff[256];
|
||||
u8 mac[6];
|
||||
|
||||
int step = (int) connData->cgiData;
|
||||
|
||||
if (connData->conn == NULL) {
|
||||
//Connection aborted. Clean up.
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
if (step == 0) {
|
||||
wifi_get_macaddr(SOFTAP_IF, mac);
|
||||
sprintf(buff, "attachment; filename=ESPTerm_%02X%02X%02X_%s.ini",
|
||||
mac[3], mac[4], mac[5], FW_VERSION);
|
||||
|
||||
httpdStartResponse(connData, 200);
|
||||
httpdHeader(connData, "Content-Disposition", buff);
|
||||
httpdHeader(connData, "Content-Type", "text/plain");
|
||||
httpdEndHeaders(connData);
|
||||
|
||||
sprintf(buff, "# == ESPTerm config export ==\r\n"
|
||||
"# Device: %02X%02X%02X - %s\r\n"
|
||||
"# Version: %s\r\n",
|
||||
mac[3], mac[4], mac[5],
|
||||
termconf->title,
|
||||
FW_VERSION);
|
||||
|
||||
httpdSend(connData, buff, -1);
|
||||
}
|
||||
|
||||
// do not export SSID if unchanged - embeds unique ID that should
|
||||
// not be overwritten in target.
|
||||
|
||||
char defSSID[20];
|
||||
sprintf(defSSID, "TERM-%02X%02X%02X", mac[3], mac[4], mac[5]);
|
||||
|
||||
bool quoted;
|
||||
#define X(type, name, suffix, deref, xget, xset, xsarg, xnotify, allow) \
|
||||
do { if (allow) { \
|
||||
xget(buff, deref XSTRUCT->name); \
|
||||
if (streq(#name, "ap_ssid") && streq(buff, defSSID)) break; \
|
||||
\
|
||||
quoted = false; \
|
||||
quoted |= streq(#type, "char"); \
|
||||
quoted |= streq(#type, "uchar"); \
|
||||
if (strstarts(#name, "bm")) quoted=false; \
|
||||
\
|
||||
httpdSend(connData, "\r\n"#name " = ", -1); \
|
||||
if (quoted) { \
|
||||
httpdSend(connData, "\"", 1); \
|
||||
httpdSend_dblquot(connData, buff, -1); \
|
||||
httpdSend(connData, "\"", 1); \
|
||||
} else { \
|
||||
httpdSend(connData, buff, -1); \
|
||||
} \
|
||||
} } while(0);
|
||||
|
||||
#define admin 1
|
||||
#define tpl 1
|
||||
if (step == 1) {
|
||||
httpdSend(connData, "\r\n[system]", -1);
|
||||
#define XSTRUCT sysconf
|
||||
XTABLE_SYSCONF
|
||||
#undef XSTRUCT
|
||||
httpdSend(connData, "\r\n", -1);
|
||||
}
|
||||
|
||||
if (step == 2) {
|
||||
httpdSend(connData, "\r\n[wifi]", -1);
|
||||
#define XSTRUCT wificonf
|
||||
XTABLE_WIFICONF
|
||||
#undef XSTRUCT
|
||||
httpdSend(connData, "\r\n", -1);
|
||||
}
|
||||
|
||||
if (step == 3) {
|
||||
httpdSend(connData, "\r\n[terminal]", -1);
|
||||
#define XSTRUCT termconf
|
||||
XTABLE_TERMCONF
|
||||
#undef XSTRUCT
|
||||
httpdSend(connData, "\r\n", -1);
|
||||
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
#undef X
|
||||
connData->cgiData = (void *) (step + 1);
|
||||
return HTTPD_CGI_MORE;
|
||||
}
|
||||
|
||||
|
||||
// -------------- IMPORT --------------
|
||||
|
||||
struct IniUpload {
|
||||
TerminalConfigBundle *term_backup;
|
||||
WiFiConfigBundle *wifi_backup;
|
||||
SystemConfigBundle *sys_backup;
|
||||
bool term_ok;
|
||||
bool wifi_ok;
|
||||
bool sys_ok;
|
||||
};
|
||||
|
||||
static void ICACHE_FLASH_ATTR iniCb(const char *section, const char *key, const char *value, void *userData)
|
||||
{
|
||||
HttpdConnData *connData = (HttpdConnData *)userData;
|
||||
struct IniUpload *state;
|
||||
if (!connData || !connData->cgiData) {
|
||||
error("userData or state is NULL!");
|
||||
return;
|
||||
}
|
||||
state = connData->cgiData;
|
||||
|
||||
// cgi_dbg("%s.%s = %s", section, key, value);
|
||||
|
||||
#define X XSET_ASSIGN
|
||||
|
||||
bool suc = true;
|
||||
bool found = false;
|
||||
|
||||
// notify flag, unused here
|
||||
bool uart_changed = false;
|
||||
|
||||
if (streq(section, "terminal")) {
|
||||
#define XSTRUCT termconf
|
||||
XTABLE_TERMCONF
|
||||
#undef XSTRUCT
|
||||
if (!suc) state->term_ok = false;
|
||||
}
|
||||
else if (streq(section, "wifi")) {
|
||||
#define XSTRUCT wificonf
|
||||
XTABLE_WIFICONF
|
||||
#undef XSTRUCT
|
||||
if (!suc) state->wifi_ok = false;
|
||||
}
|
||||
else if (streq(section, "system")) {
|
||||
#define XSTRUCT sysconf
|
||||
XTABLE_SYSCONF
|
||||
#undef XSTRUCT
|
||||
if (!suc) state->sys_ok = false;
|
||||
}
|
||||
|
||||
if (!found) cgi_warn("Unknown key %s.%s!", section, key);
|
||||
|
||||
#undef X
|
||||
}
|
||||
|
||||
static void ICACHE_FLASH_ATTR
|
||||
freeIniUploadStruct(HttpdConnData *connData)
|
||||
{
|
||||
cgi_dbg("Free struct...");
|
||||
struct IniUpload *state;
|
||||
if (connData && connData->cgiData) {
|
||||
state = connData->cgiData;
|
||||
if (state->sys_backup != NULL) free(state->sys_backup);
|
||||
if (state->wifi_backup != NULL) free(state->wifi_backup);
|
||||
if (state->term_backup != NULL) free(state->term_backup);
|
||||
free(state);
|
||||
connData->cgiData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static httpd_cgi_state ICACHE_FLASH_ATTR
|
||||
postRecvHdl(HttpdConnData *connData, char *data, int len)
|
||||
{
|
||||
struct IniUpload *state = connData->cgiData;
|
||||
if (!state) return HTTPD_CGI_DONE;
|
||||
|
||||
// Discard the boundary marker (there is only one)
|
||||
char *bdr = connData->post->multipartBoundary;
|
||||
char *foundat = strstr(data, bdr);
|
||||
if (foundat != NULL) {
|
||||
*foundat = '#'; // make it a comment
|
||||
}
|
||||
|
||||
cgi_dbg("INI parse - postRecvHdl");
|
||||
|
||||
ini_parse(data, (size_t) len);
|
||||
|
||||
cgi_dbg("Closing parser");
|
||||
ini_parse_end();
|
||||
|
||||
cgi_dbg("INI parse - end.");
|
||||
|
||||
// abort if bad screen size
|
||||
bool tooLarge = (termconf->width*termconf->height > MAX_SCREEN_SIZE);
|
||||
state->term_ok &= !tooLarge;
|
||||
if (tooLarge) cgi_warn("Bad term screen size!");
|
||||
|
||||
bool suc = state->term_ok && state->wifi_ok && state->sys_ok;
|
||||
|
||||
cgi_dbg("Evaluating results...");
|
||||
|
||||
if (!state->term_ok) cgi_warn("Terminal settings rejected.");
|
||||
if (!state->wifi_ok) cgi_warn("WiFi settings rejected.");
|
||||
if (!state->sys_ok) cgi_warn("System settings rejected.");
|
||||
|
||||
if (!suc) {
|
||||
cgi_warn("Some validation failed, reverting all!");
|
||||
memcpy(termconf, state->term_backup, sizeof(TerminalConfigBundle));
|
||||
memcpy(wificonf, state->wifi_backup, sizeof(WiFiConfigBundle));
|
||||
memcpy(sysconf, state->sys_backup, sizeof(SystemConfigBundle));
|
||||
}
|
||||
else {
|
||||
cgi_dbg("Applying terminal settings");
|
||||
terminal_apply_settings();
|
||||
cgi_dbg("Applying system settings");
|
||||
sysconf_apply_settings();
|
||||
cgi_dbg("Applying WiFi settings (scheduling...)");
|
||||
wifimgr_apply_settings_later(1000);
|
||||
|
||||
cgi_dbg("Persisting results");
|
||||
persist_store();
|
||||
}
|
||||
|
||||
cgi_dbg("Redirect");
|
||||
char buff[100];
|
||||
char *b = buff;
|
||||
if (suc) {
|
||||
httpdRedirect(connData, SET_REDIR_SUC"?msg=Settings%20loaded%20and%20applied.");
|
||||
} else {
|
||||
b += sprintf(b, SET_REDIR_SUC"?errmsg=Errors%%20in:%%20");
|
||||
bool comma = false;
|
||||
if (!state->sys_ok) {
|
||||
b += sprintf(b, "System%%20config");
|
||||
comma = true;
|
||||
}
|
||||
if (!state->wifi_ok) {
|
||||
if (comma) b += sprintf(b, ",%%20");
|
||||
b += sprintf(b, "WiFi%%20config");
|
||||
}
|
||||
if (!state->term_ok) {
|
||||
if (comma) b += sprintf(b, ",%%20");
|
||||
b += sprintf(b, "Terminal%%20config");
|
||||
}
|
||||
httpdRedirect(connData, buff);
|
||||
}
|
||||
|
||||
// Clean up.
|
||||
freeIniUploadStruct(connData);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import settings from INI
|
||||
*
|
||||
* @param connData
|
||||
* @return status
|
||||
*/
|
||||
httpd_cgi_state ICACHE_FLASH_ATTR
|
||||
cgiPersistImport(HttpdConnData *connData)
|
||||
{
|
||||
struct IniUpload *state = NULL;
|
||||
|
||||
if (connData->conn == NULL) {
|
||||
//Connection aborted. Clean up.
|
||||
freeIniUploadStruct(connData);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
char *start = strstr(connData->post->buff, "\r\n\r\n");
|
||||
if (start == NULL) {
|
||||
error("Malformed attachment POST!");
|
||||
|
||||
httpdStartResponse(connData, 400);
|
||||
httpdHeader(connData, "Content-Type", "text/plain");
|
||||
httpdEndHeaders(connData);
|
||||
httpdSend(connData, "Bad format.", -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
cgi_info("Starting INI parser for uploaded file...");
|
||||
|
||||
state = malloc(sizeof(struct IniUpload));
|
||||
if (!state) {
|
||||
error("state struct alloc fail");
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
state->sys_backup = NULL;
|
||||
state->wifi_backup = NULL;
|
||||
state->term_backup = NULL;
|
||||
connData->cgiData = state;
|
||||
|
||||
cgi_dbg("Allocating backup buffers");
|
||||
state->sys_backup = malloc(sizeof(SystemConfigBundle));
|
||||
state->wifi_backup = malloc(sizeof(WiFiConfigBundle));
|
||||
state->term_backup = malloc(sizeof(TerminalConfigBundle));
|
||||
|
||||
cgi_dbg("Copying orig data");
|
||||
memcpy(state->sys_backup, sysconf, sizeof(SystemConfigBundle));
|
||||
memcpy(state->wifi_backup, wificonf, sizeof(WiFiConfigBundle));
|
||||
memcpy(state->term_backup, termconf, sizeof(TerminalConfigBundle));
|
||||
|
||||
state->sys_ok = true;
|
||||
state->wifi_ok = true;
|
||||
state->term_ok = true;
|
||||
|
||||
cgi_dbg("Parser starts!");
|
||||
ini_parse_begin(iniCb, connData);
|
||||
|
||||
size_t datalen = (size_t) connData->post->buffLen - (start - connData->post->buff);
|
||||
ini_parse(start, datalen);
|
||||
|
||||
connData->recvHdl = postRecvHdl;
|
||||
|
||||
// continues in recvHdl
|
||||
return HTTPD_CGI_MORE;
|
||||
}
|
||||
|
||||
@@ -6,5 +6,7 @@
|
||||
httpd_cgi_state cgiPersistWriteDefaults(HttpdConnData *connData);
|
||||
httpd_cgi_state cgiPersistRestoreDefaults(HttpdConnData *connData);
|
||||
httpd_cgi_state cgiPersistRestoreHard(HttpdConnData *connData);
|
||||
httpd_cgi_state cgiPersistExport(HttpdConnData *connData);
|
||||
httpd_cgi_state cgiPersistImport(HttpdConnData *connData);
|
||||
|
||||
#endif
|
||||
|
||||
+2
-2
@@ -271,8 +271,8 @@ static void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int
|
||||
case 'b':
|
||||
// action button press
|
||||
btnNum = (u8) (data[1]);
|
||||
if (btnNum > 0 && btnNum < 10) {
|
||||
UART_SendAsync(termconf_live.btn_msg[btnNum-1], -1);
|
||||
if (btnNum > 0 && btnNum <= TERM_BTN_COUNT) {
|
||||
UART_SendAsync(TERM_BM_N(&termconf_live, btnNum-1), -1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
+59
-83
@@ -95,108 +95,84 @@ cgiSystemCfgSetParams(HttpdConnData *connData)
|
||||
memcpy(admin_backup, &persist.admin, sizeof(AdminConfigBlock));
|
||||
memcpy(sysconf_backup, sysconf, sizeof(SystemConfigBundle));
|
||||
|
||||
// flags for the template builder
|
||||
bool uart_changed = false; //!< this is set in uart notify, for use in terminal settings (dummy here)
|
||||
bool admin = false;
|
||||
const bool tpl = false; // this optionally disables some fields
|
||||
do {
|
||||
if (!GET_ARG("pw")) {
|
||||
break; // if no PW in GET, not trying to configure anything protected
|
||||
}
|
||||
|
||||
if (!streq(buff, persist.admin.pw)) {
|
||||
warn("Bad admin pw!");
|
||||
redir_url += sprintf(redir_url, "pw,");
|
||||
break;
|
||||
}
|
||||
|
||||
// authenticated OK
|
||||
if (GET_ARG("pwlock")) {
|
||||
cgi_dbg("pwlock: %s", buff);
|
||||
int pwlock = atoi(buff);
|
||||
if (pwlock < 0 || pwlock >= PWLOCK_MAX) {
|
||||
cgi_warn("Bad pwlock %s", buff);
|
||||
redir_url += sprintf(redir_url, "pwlock,");
|
||||
break;
|
||||
// Check admin PW
|
||||
if (GET_ARG("pw")) {
|
||||
if (!streq(buff, persist.admin.pw)) {
|
||||
warn("Bad admin pw!");
|
||||
redir_url += sprintf(redir_url, "pw,");
|
||||
break; // Abort
|
||||
} else {
|
||||
admin = true;
|
||||
}
|
||||
|
||||
sysconf->pwlock = (enum pwlock) pwlock;
|
||||
}
|
||||
|
||||
if (GET_ARG("access_pw")) {
|
||||
cgi_dbg("access_pw: %s", buff);
|
||||
|
||||
// Changing admin PW
|
||||
if (admin && GET_ARG("admin_pw")) {
|
||||
if (strlen(buff)) {
|
||||
strcpy(buff2, buff);
|
||||
if (!GET_ARG("access_pw2")) {
|
||||
cgi_warn("Missing repeated access_pw %s", buff);
|
||||
redir_url += sprintf(redir_url, "access_pw2,");
|
||||
break;
|
||||
}
|
||||
cgi_dbg("admin_pw: %s", buff);
|
||||
|
||||
if (!streq(buff, buff2)) {
|
||||
cgi_warn("Bad repeated access_pw %s", buff);
|
||||
redir_url += sprintf(redir_url, "access_pw2,");
|
||||
break;
|
||||
}
|
||||
|
||||
if (strlen(buff) >= 64) {
|
||||
cgi_warn("Too long access_pw %s", buff);
|
||||
redir_url += sprintf(redir_url, "access_pw,");
|
||||
break;
|
||||
}
|
||||
|
||||
cgi_dbg("Changing access PW!");
|
||||
strncpy(sysconf->access_pw, buff, 64);
|
||||
}
|
||||
}
|
||||
|
||||
if (GET_ARG("access_name")) {
|
||||
cgi_dbg("access_name: %s", buff);
|
||||
|
||||
if (!strlen(buff) || strlen(buff) >= 32) {
|
||||
cgi_warn("Too long access_name %s", buff);
|
||||
redir_url += sprintf(redir_url, "access_name,");
|
||||
break;
|
||||
}
|
||||
|
||||
strncpy(sysconf->access_name, buff, 32);
|
||||
}
|
||||
|
||||
if (GET_ARG("admin_pw")) {
|
||||
cgi_dbg("admin_pw: %s", buff);
|
||||
|
||||
if (strlen(buff)) {
|
||||
strcpy(buff2, buff);
|
||||
if (!GET_ARG("admin_pw2")) {
|
||||
cgi_warn("Missing repeated admin_pw %s", buff);
|
||||
redir_url += sprintf(redir_url, "admin_pw2,");
|
||||
break;
|
||||
break; // Abort
|
||||
}
|
||||
|
||||
if (!streq(buff, buff2)) {
|
||||
cgi_warn("Bad repeated admin_pw %s", buff);
|
||||
redir_url += sprintf(redir_url, "admin_pw2,");
|
||||
break;
|
||||
break; // Abort
|
||||
}
|
||||
|
||||
if (strlen(buff) >= 64) {
|
||||
cgi_warn("Too long admin_pw %s", buff);
|
||||
redir_url += sprintf(redir_url, "admin_pw,");
|
||||
break;
|
||||
break; // Abort
|
||||
}
|
||||
|
||||
cgi_dbg("Changing admin PW!");
|
||||
strncpy(persist.admin.pw, buff, 64);
|
||||
|
||||
break; // this is the only field in this form
|
||||
}
|
||||
}
|
||||
|
||||
// Reject filled but unconfirmed access PW
|
||||
if (admin && GET_ARG("access_pw")) {
|
||||
if (strlen(buff)) {
|
||||
cgi_dbg("access_pw: %s", buff);
|
||||
|
||||
strcpy(buff2, buff);
|
||||
if (!GET_ARG("access_pw2")) {
|
||||
cgi_warn("Missing repeated access_pw %s", buff);
|
||||
redir_url += sprintf(redir_url, "access_pw2,");
|
||||
break; // Abort
|
||||
}
|
||||
|
||||
if (!streq(buff, buff2)) {
|
||||
cgi_warn("Bad repeated access_pw %s", buff);
|
||||
redir_url += sprintf(redir_url, "access_pw2,");
|
||||
break; // Abort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Settings in the system config block
|
||||
#define XSTRUCT sysconf
|
||||
#define X XSET_CGI_FUNC
|
||||
XTABLE_SYSCONF
|
||||
#undef X
|
||||
#undef XSTRUCT
|
||||
|
||||
} while (0);
|
||||
|
||||
if (GET_ARG("overclock")) {
|
||||
cgi_dbg("overclock = %s", buff);
|
||||
int enable = atoi(buff);
|
||||
if (sysconf->overclock != enable) {
|
||||
sysconf->overclock = (bool)enable;
|
||||
}
|
||||
}
|
||||
|
||||
(void)redir_url;
|
||||
(void)uart_changed; // unused
|
||||
|
||||
if (redir_url_buf[strlen(SET_REDIR_ERR)] == 0) {
|
||||
// All was OK
|
||||
@@ -236,13 +212,16 @@ tplSystemCfg(HttpdConnData *connData, char *token, void **arg)
|
||||
|
||||
strcpy(buff, ""); // fallback
|
||||
|
||||
if (streq(token, "pwlock")) {
|
||||
sprintf(buff, "%d", sysconf->pwlock);
|
||||
}
|
||||
else if (streq(token, "access_name")) {
|
||||
sprintf(buff, "%s", sysconf->access_name);
|
||||
}
|
||||
else if (streq(token, "def_access_name")) {
|
||||
const bool admin = false;
|
||||
const bool tpl=true;
|
||||
|
||||
#define XSTRUCT sysconf
|
||||
#define X XGET_CGI_FUNC
|
||||
XTABLE_SYSCONF
|
||||
#undef X
|
||||
#undef XSTRUCT
|
||||
|
||||
if (streq(token, "def_access_name")) {
|
||||
sprintf(buff, "%s", DEF_ACCESS_NAME);
|
||||
}
|
||||
else if (streq(token, "def_access_pw")) {
|
||||
@@ -251,9 +230,6 @@ tplSystemCfg(HttpdConnData *connData, char *token, void **arg)
|
||||
else if (streq(token, "def_admin_pw")) {
|
||||
sprintf(buff, "%s", DEFAULT_ADMIN_PW);
|
||||
}
|
||||
else if (streq(token, "overclock")) {
|
||||
sprintf(buff, "%d", sysconf->overclock);
|
||||
}
|
||||
|
||||
tplSend(connData, buff, -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
|
||||
+41
-446
@@ -15,22 +15,6 @@ Cgi/template routines for configuring non-wifi settings
|
||||
#define SET_REDIR_SUC "/cfg/term"
|
||||
#define SET_REDIR_ERR SET_REDIR_SUC"?err="
|
||||
|
||||
/** convert hex number to int */
|
||||
static ICACHE_FLASH_ATTR u32
|
||||
decodehex(const char *buf) {
|
||||
u32 n = 0;
|
||||
char c;
|
||||
while ((c = *buf++) != 0) {
|
||||
if (c >= '0' && c <= '9') c -= '0';
|
||||
else if (c >= 'a' && c <= 'f') c -= 'a'-10;
|
||||
else if (c >= 'A' && c <= 'F') c -= 'A'-10;
|
||||
else c = 0;
|
||||
n *= 16;
|
||||
n += c;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Universal CGI endpoint to set Terminal params.
|
||||
*/
|
||||
@@ -39,15 +23,11 @@ cgiTermCfgSetParams(HttpdConnData *connData)
|
||||
{
|
||||
char buff[50];
|
||||
char redir_url_buf[100];
|
||||
int32 n, w, h;
|
||||
ScreenNotifyTopics topics = 0;
|
||||
|
||||
bool shall_clear_screen = false;
|
||||
bool shall_init_uart = false;
|
||||
|
||||
char *redir_url = redir_url_buf;
|
||||
redir_url += sprintf(redir_url, SET_REDIR_ERR);
|
||||
// we'll test if anything was printed by looking for \0 in failed_keys_buf
|
||||
// we'll test if anything was printed by looking for \0 in redir_url
|
||||
|
||||
SystemConfigBundle *sysconf_backup = malloc(sizeof(SystemConfigBundle));
|
||||
TerminalConfigBundle *termconf_backup = malloc(sizeof(TerminalConfigBundle));
|
||||
@@ -59,328 +39,29 @@ cgiTermCfgSetParams(HttpdConnData *connData)
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
#define XSTRUCT termconf
|
||||
#define X XSET_CGI_FUNC
|
||||
XTABLE_TERMCONF
|
||||
#undef X
|
||||
#undef XSTRUCT
|
||||
|
||||
// width and height must always go together so we can do max size validation
|
||||
if (GET_ARG("term_width")) {
|
||||
do {
|
||||
cgi_dbg("Default screen width: %s", buff);
|
||||
w = atoi(buff);
|
||||
if (w < 1) {
|
||||
cgi_warn("Bad width: \"%s\"", buff);
|
||||
redir_url += sprintf(redir_url, "term_width,");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!GET_ARG("term_height")) {
|
||||
cgi_warn("Missing height arg!");
|
||||
// this wont happen normally when the form is used
|
||||
redir_url += sprintf(redir_url, "term_height,");
|
||||
break;
|
||||
}
|
||||
|
||||
cgi_dbg("Default screen height: %s", buff);
|
||||
h = atoi(buff);
|
||||
if (h < 1) {
|
||||
cgi_warn("Bad height: \"%s\"", buff);
|
||||
redir_url += sprintf(redir_url, "term_height,");
|
||||
break;
|
||||
}
|
||||
|
||||
if (w * h > MAX_SCREEN_SIZE) {
|
||||
cgi_warn("Bad dimensions: %d x %d (total %d)", w, h, w * h);
|
||||
redir_url += sprintf(redir_url, "term_width,term_height,");
|
||||
break;
|
||||
}
|
||||
|
||||
if (termconf->width != w || termconf->height != h) {
|
||||
termconf->width = w;
|
||||
termconf->height = h;
|
||||
shall_clear_screen = true;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS | TOPIC_CHANGE_CONTENT_ALL;
|
||||
}
|
||||
} while (0);
|
||||
u32 siz = termconf->width*termconf->height;
|
||||
if (siz == 0 || siz > MAX_SCREEN_SIZE) {
|
||||
cgi_warn("Bad dimensions: %d x %d (total %d)", termconf->width, termconf->height, termconf->width*termconf->height);
|
||||
redir_url += sprintf(redir_url, "term_width,term_height,");
|
||||
}
|
||||
|
||||
if (GET_ARG("default_bg")) {
|
||||
cgi_dbg("Screen default BG: %s", buff);
|
||||
|
||||
if (buff[0] == '#') {
|
||||
// decode hex
|
||||
n = decodehex(buff+1);
|
||||
n += 256;
|
||||
} else {
|
||||
n = atoi(buff);
|
||||
}
|
||||
|
||||
if (termconf->default_bg != n) {
|
||||
termconf->default_bg = n; // this is current not sent through socket, no use to notify
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
}
|
||||
|
||||
if (GET_ARG("default_fg")) {
|
||||
cgi_dbg("Screen default FG: %s", buff);
|
||||
|
||||
if (buff[0] == '#') {
|
||||
// decode hex
|
||||
n = decodehex(buff+1);
|
||||
n += 256;
|
||||
} else {
|
||||
n = atoi(buff);
|
||||
}
|
||||
|
||||
if (termconf->default_fg != n) {
|
||||
termconf->default_fg = n; // this is current not sent through socket, no use to notify
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
}
|
||||
|
||||
if (GET_ARG("parser_tout_ms")) {
|
||||
cgi_dbg("Parser timeout: %s ms", buff);
|
||||
n = atoi(buff);
|
||||
if (n >= 0) {
|
||||
termconf->parser_tout_ms = n;
|
||||
} else {
|
||||
cgi_warn("Bad parser timeout %s", buff);
|
||||
redir_url += sprintf(redir_url, "parser_tout_ms,");
|
||||
}
|
||||
}
|
||||
|
||||
if (GET_ARG("display_tout_ms")) {
|
||||
cgi_dbg("Display update idle timeout: %s ms", buff);
|
||||
n = atoi(buff);
|
||||
if (n >= 0) {
|
||||
termconf->display_tout_ms = n;
|
||||
} else {
|
||||
cgi_warn("Bad update timeout %s", buff);
|
||||
redir_url += sprintf(redir_url, "display_tout_ms,");
|
||||
}
|
||||
}
|
||||
|
||||
if (GET_ARG("display_cooldown_ms")) {
|
||||
cgi_dbg("Display update cooldown: %s ms", buff);
|
||||
n = atoi(buff);
|
||||
if (n > 0) {
|
||||
termconf->display_cooldown_ms = n;
|
||||
} else {
|
||||
cgi_warn("Bad cooldown %s", buff);
|
||||
redir_url += sprintf(redir_url, "display_cooldown_ms,");
|
||||
}
|
||||
}
|
||||
|
||||
if (GET_ARG("fn_alt_mode")) {
|
||||
cgi_dbg("FN alt mode: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->fn_alt_mode = (bool)n;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("want_all_fn")) {
|
||||
cgi_dbg("AllFN mode: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->want_all_fn = (bool)n;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("crlf_mode")) {
|
||||
cgi_dbg("CRLF mode: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->crlf_mode = (bool)n;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("show_buttons")) {
|
||||
cgi_dbg("Show buttons: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->show_buttons = (bool)n;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("show_config_links")) {
|
||||
cgi_dbg("Show config links: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->show_config_links = (bool)n;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("loopback")) {
|
||||
cgi_dbg("Loopback: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->loopback = (bool)n;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("debugbar")) {
|
||||
cgi_dbg("Debugbar: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->debugbar = (bool)n;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("allow_decopt_12")) {
|
||||
cgi_dbg("DECOPT 12: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->allow_decopt_12 = (bool)n;
|
||||
}
|
||||
|
||||
if (GET_ARG("ascii_debug")) {
|
||||
cgi_dbg("ascii_debug: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->ascii_debug = (bool)n;
|
||||
shall_clear_screen = true;
|
||||
}
|
||||
|
||||
if (GET_ARG("theme")) {
|
||||
cgi_dbg("Screen color theme: %s", buff);
|
||||
n = atoi(buff);
|
||||
if (n >= 0) {
|
||||
termconf->theme = (u8) n;
|
||||
// this can't be notified, page must reload.
|
||||
} else {
|
||||
cgi_warn("Bad theme num: %s", buff);
|
||||
redir_url += sprintf(redir_url, "theme,");
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
}
|
||||
|
||||
if (GET_ARG("cursor_shape")) {
|
||||
cgi_dbg("Cursor shape: %s", buff);
|
||||
n = atoi(buff);
|
||||
if (n >= 0 && n <= 6 && n != 1) {
|
||||
termconf->cursor_shape = (enum CursorShape) n;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
} else {
|
||||
cgi_warn("Bad cursor_shape num: %s", buff);
|
||||
redir_url += sprintf(redir_url, "cursor_shape,");
|
||||
}
|
||||
}
|
||||
|
||||
if (GET_ARG("term_title")) {
|
||||
cgi_dbg("Terminal title default text: \"%s\"", buff);
|
||||
strncpy_safe(termconf->title, buff, TERM_TITLE_LEN); // ATTN those must match the values in
|
||||
topics |= TOPIC_CHANGE_TITLE;
|
||||
}
|
||||
|
||||
if (GET_ARG("backdrop")) {
|
||||
cgi_dbg("Terminal backdrop url: \"%s\"", buff);
|
||||
strncpy_safe(termconf->backdrop, buff, TERM_BACKDROP_LEN); // ATTN those must match the values in
|
||||
topics |= TOPIC_CHANGE_BACKDROP;
|
||||
}
|
||||
|
||||
for (int btn_i = 1; btn_i <= TERM_BTN_COUNT; btn_i++) {
|
||||
sprintf(buff, "btn%d", btn_i);
|
||||
if (GET_ARG(buff)) {
|
||||
cgi_dbg("Button%d default text: \"%s\"", btn_i, buff);
|
||||
strncpy_safe(termconf->btn[btn_i-1], buff, TERM_BTN_LEN);
|
||||
topics |= TOPIC_CHANGE_BUTTONS;
|
||||
}
|
||||
|
||||
sprintf(buff, "bm%d", btn_i);
|
||||
if (GET_ARG(buff)) {
|
||||
cgi_dbg("Button%d message (ASCII): \"%s\"", btn_i, buff);
|
||||
|
||||
// parse: comma,space or semicolon separated decimal values of ASCII codes
|
||||
char c;
|
||||
char *cp = buff;
|
||||
int char_i = 0;
|
||||
int acu = 0;
|
||||
bool lastsp = 1;
|
||||
char buff_bm[TERM_BTN_MSG_LEN];
|
||||
while ((c = *cp++) != 0) {
|
||||
if (c == ' ' || c == ',' || c == ';') {
|
||||
if(lastsp) continue;
|
||||
|
||||
if (acu==0 || acu>255) {
|
||||
cgi_warn("Bad value! %d", acu);
|
||||
redir_url += sprintf(redir_url, "bm%d,", btn_i);
|
||||
break;
|
||||
}
|
||||
|
||||
if (char_i >= TERM_BTN_MSG_LEN-1) {
|
||||
cgi_warn("Too long! %d", acu);
|
||||
redir_url += sprintf(redir_url, "bm%d,", btn_i);
|
||||
break;
|
||||
}
|
||||
|
||||
cgi_dbg("acu %d", acu);
|
||||
buff_bm[char_i++] = (char)acu;
|
||||
|
||||
// prepare for next char
|
||||
acu = 0;
|
||||
lastsp = 1;
|
||||
} else if (c>='0'&&c<='9') {
|
||||
lastsp = 0;
|
||||
acu *= 10;
|
||||
acu += c - '0';
|
||||
} else {
|
||||
cgi_warn("Bad syntax!");
|
||||
redir_url += sprintf(redir_url, "bm%d,", btn_i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastsp && char_i == 0) {
|
||||
cgi_warn("Required!");
|
||||
redir_url += sprintf(redir_url, "bm%d,", btn_i);
|
||||
}
|
||||
if (!lastsp) {
|
||||
buff_bm[char_i++] = (char)acu;
|
||||
}
|
||||
buff_bm[char_i] = 0;
|
||||
cgi_dbg("%s, chari = %d", buff_bm, char_i);
|
||||
|
||||
strncpy(termconf->btn_msg[btn_i-1], buff_bm, TERM_BTN_MSG_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
if (GET_ARG("uart_baud")) {
|
||||
cgi_dbg("Baud rate: %s", buff);
|
||||
int baud = atoi(buff);
|
||||
if (baud == BIT_RATE_300 ||
|
||||
baud == BIT_RATE_600 ||
|
||||
baud == BIT_RATE_1200 ||
|
||||
baud == BIT_RATE_2400 ||
|
||||
baud == BIT_RATE_4800 ||
|
||||
baud == BIT_RATE_9600 ||
|
||||
baud == BIT_RATE_19200 ||
|
||||
baud == BIT_RATE_38400 ||
|
||||
baud == BIT_RATE_57600 ||
|
||||
baud == BIT_RATE_74880 ||
|
||||
baud == BIT_RATE_115200 ||
|
||||
baud == BIT_RATE_230400 ||
|
||||
baud == BIT_RATE_460800 ||
|
||||
baud == BIT_RATE_921600 ||
|
||||
baud == BIT_RATE_1843200 ||
|
||||
baud == BIT_RATE_3686400) {
|
||||
sysconf->uart_baudrate = (u32) baud;
|
||||
shall_init_uart = true;
|
||||
} else {
|
||||
cgi_warn("Bad baud rate %s", buff);
|
||||
redir_url += sprintf(redir_url, "uart_baud,");
|
||||
}
|
||||
}
|
||||
|
||||
if (GET_ARG("uart_parity")) {
|
||||
cgi_dbg("Parity: %s", buff);
|
||||
int parity = atoi(buff);
|
||||
if (parity >= 0 && parity <= 2) {
|
||||
sysconf->uart_parity = (UartParityMode) parity;
|
||||
shall_init_uart = true;
|
||||
} else {
|
||||
cgi_warn("Bad parity %s", buff);
|
||||
redir_url += sprintf(redir_url, "uart_parity,");
|
||||
}
|
||||
}
|
||||
|
||||
if (GET_ARG("uart_stopbits")) {
|
||||
cgi_dbg("Stop bits: %s", buff);
|
||||
int stopbits = atoi(buff);
|
||||
if (stopbits >= 1 && stopbits <= 3) {
|
||||
sysconf->uart_stopbits = (UartStopBitsNum) stopbits;
|
||||
shall_init_uart = true;
|
||||
} else {
|
||||
cgi_warn("Bad stopbits %s", buff);
|
||||
redir_url += sprintf(redir_url, "uart_stopbits,");
|
||||
}
|
||||
}
|
||||
// Settings from SysConf - UART
|
||||
bool uart_changed = false;
|
||||
// restrict what keys are allowed
|
||||
#define admin 0
|
||||
#define tpl 0
|
||||
#define XSTRUCT sysconf
|
||||
#define X XSET_CGI_FUNC
|
||||
XTABLE_SYSCONF
|
||||
#undef X
|
||||
#undef XSTRUCT
|
||||
|
||||
(void)redir_url;
|
||||
|
||||
@@ -390,17 +71,23 @@ cgiTermCfgSetParams(HttpdConnData *connData)
|
||||
|
||||
persist_store();
|
||||
|
||||
bool shall_clear_screen = false;
|
||||
shall_clear_screen |= (termconf_backup->width != termconf->width);
|
||||
shall_clear_screen |= (termconf_backup->height != termconf->height);
|
||||
shall_clear_screen |= (termconf_backup->ascii_debug != termconf->ascii_debug);
|
||||
|
||||
if (shall_clear_screen) {
|
||||
terminal_apply_settings();
|
||||
} else {
|
||||
terminal_apply_settings_noclear();
|
||||
}
|
||||
|
||||
if (shall_init_uart) {
|
||||
serialInit();
|
||||
if (uart_changed) {
|
||||
sysconf_apply_settings();
|
||||
}
|
||||
|
||||
if (topics) screen_notifyChange(topics);
|
||||
// Trigger a full reload
|
||||
screen_notifyChange(TOPIC_INITIAL);
|
||||
|
||||
httpdRedirect(connData, SET_REDIR_SUC "?msg=Settings%20saved%20and%20applied.");
|
||||
} else {
|
||||
@@ -424,7 +111,6 @@ tplTermCfg(HttpdConnData *connData, char *token, void **arg)
|
||||
{
|
||||
#define BUFLEN 100 // large enough for backdrop
|
||||
char buff[BUFLEN];
|
||||
char buff2[10];
|
||||
|
||||
if (token == NULL) {
|
||||
// We're done
|
||||
@@ -433,109 +119,18 @@ tplTermCfg(HttpdConnData *connData, char *token, void **arg)
|
||||
|
||||
strcpy(buff, ""); // fallback
|
||||
|
||||
if (streq(token, "term_width")) {
|
||||
sprintf(buff, "%d", termconf->width);
|
||||
}
|
||||
else if (streq(token, "term_height")) {
|
||||
sprintf(buff, "%d", termconf->height);
|
||||
}
|
||||
else if (streq(token, "parser_tout_ms")) {
|
||||
sprintf(buff, "%d", termconf->parser_tout_ms);
|
||||
}
|
||||
else if (streq(token, "display_tout_ms")) {
|
||||
sprintf(buff, "%d", termconf->display_tout_ms);
|
||||
}
|
||||
else if (streq(token, "display_cooldown_ms")) {
|
||||
sprintf(buff, "%d", termconf->display_cooldown_ms);
|
||||
}
|
||||
else if (streq(token, "fn_alt_mode")) {
|
||||
sprintf(buff, "%d", (int)termconf->fn_alt_mode);
|
||||
}
|
||||
else if (streq(token, "want_all_fn")) {
|
||||
sprintf(buff, "%d", (int)termconf->want_all_fn);
|
||||
}
|
||||
else if (streq(token, "crlf_mode")) {
|
||||
sprintf(buff, "%d", (int)termconf->crlf_mode);
|
||||
}
|
||||
else if (streq(token, "show_buttons")) {
|
||||
sprintf(buff, "%d", (int)termconf->show_buttons);
|
||||
}
|
||||
else if (streq(token, "show_config_links")) {
|
||||
sprintf(buff, "%d", (int)termconf->show_config_links);
|
||||
}
|
||||
else if (streq(token, "allow_decopt_12")) {
|
||||
sprintf(buff, "%d", (int)termconf->allow_decopt_12);
|
||||
}
|
||||
else if (streq(token, "ascii_debug")) {
|
||||
sprintf(buff, "%d", (int)termconf->ascii_debug);
|
||||
}
|
||||
else if (streq(token, "loopback")) {
|
||||
sprintf(buff, "%d", (int)termconf->loopback);
|
||||
}
|
||||
else if (streq(token, "debugbar")) {
|
||||
sprintf(buff, "%d", (int)termconf->debugbar);
|
||||
}
|
||||
else if (streq(token, "theme")) {
|
||||
sprintf(buff, "%d", termconf->theme);
|
||||
}
|
||||
else if (streq(token, "default_bg")) {
|
||||
if (termconf->default_bg < 256) {
|
||||
sprintf(buff, "%d", termconf->default_bg);
|
||||
} else {
|
||||
sprintf(buff, "#%06X", termconf->default_bg - 256);
|
||||
}
|
||||
}
|
||||
else if (streq(token, "default_fg")) {
|
||||
if (termconf->default_fg < 256) {
|
||||
sprintf(buff, "%d", termconf->default_fg);
|
||||
} else {
|
||||
sprintf(buff, "#%06X", termconf->default_fg - 256);
|
||||
}
|
||||
}
|
||||
else if (streq(token, "cursor_shape")) {
|
||||
sprintf(buff, "%d", termconf->cursor_shape);
|
||||
}
|
||||
else if (streq(token, "term_title")) {
|
||||
strncpy_safe(buff, termconf->title, BUFLEN);
|
||||
}
|
||||
else if (streq(token, "backdrop")) {
|
||||
strncpy_safe(buff, termconf->backdrop, BUFLEN);
|
||||
}
|
||||
else if (streq(token, "uart_baud")) {
|
||||
sprintf(buff, "%d", sysconf->uart_baudrate);
|
||||
}
|
||||
else if (streq(token, "uart_parity")) {
|
||||
sprintf(buff, "%d", sysconf->uart_parity);
|
||||
}
|
||||
else if (streq(token, "uart_stopbits")) {
|
||||
sprintf(buff, "%d", sysconf->uart_stopbits);
|
||||
}
|
||||
else {
|
||||
for (int btn_i = 1; btn_i <= TERM_BTN_COUNT; btn_i++) {
|
||||
sprintf(buff2, "btn%d", btn_i);
|
||||
if (streq(token, buff2)) {
|
||||
strncpy_safe(buff, termconf->btn[btn_i-1], BUFLEN);
|
||||
break;
|
||||
}
|
||||
#define XSTRUCT termconf
|
||||
#define X XGET_CGI_FUNC
|
||||
XTABLE_TERMCONF
|
||||
#undef X
|
||||
#undef XSTRUCT
|
||||
|
||||
sprintf(buff2, "bm%d", btn_i);
|
||||
if (streq(token, buff2)) {
|
||||
char c;
|
||||
char *bp = buff;
|
||||
char *cp = termconf->btn_msg[btn_i-1];
|
||||
int n = 0;
|
||||
while((c = *cp++) != 0) {
|
||||
if(n>0) {
|
||||
*bp = ',';
|
||||
bp++;
|
||||
}
|
||||
bp += sprintf(bp, "%d", (int)c);
|
||||
n++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// for uart
|
||||
#define XSTRUCT sysconf
|
||||
#define X XGET_CGI_FUNC
|
||||
XTABLE_SYSCONF
|
||||
#undef X
|
||||
#undef XSTRUCT
|
||||
|
||||
tplSend(connData, buff, -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
|
||||
+14
-187
@@ -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,14 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData)
|
||||
bool sta_turned_on = false;
|
||||
bool sta_ssid_pw_changed = false;
|
||||
|
||||
#define XSTRUCT wificonf
|
||||
#define X XSET_CGI_FUNC
|
||||
XTABLE_WIFICONF
|
||||
#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 +356,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 +401,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 +415,18 @@ 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 XSTRUCT wificonf
|
||||
#define X XGET_CGI_FUNC
|
||||
XTABLE_WIFICONF
|
||||
#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());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
//
|
||||
// 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_u32(const char *name, u32 *field, const char *buff, const void *arg)
|
||||
{
|
||||
cgi_dbg("Setting %s = %s", name, buff);
|
||||
u32 val = (u32) atoi(buff);
|
||||
|
||||
if (*field != val) {
|
||||
*field = (u32) val;
|
||||
return XSET_SET;
|
||||
}
|
||||
return XSET_UNCHANGED;
|
||||
}
|
||||
|
||||
enum xset_result ICACHE_FLASH_ATTR
|
||||
xset_u16(const char *name, u16 *field, const char *buff, const void *arg)
|
||||
{
|
||||
cgi_dbg("Setting %s = %s", name, buff);
|
||||
u16 val = (u16) atoi(buff);
|
||||
|
||||
if (*field != val) {
|
||||
*field = (u16) val;
|
||||
return XSET_SET;
|
||||
}
|
||||
return XSET_UNCHANGED;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
enum xset_result ICACHE_FLASH_ATTR
|
||||
xset_ustring(const char *name, uchar *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;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/10/22.
|
||||
//
|
||||
|
||||
#ifndef ESPTERM_CONFIG_XMACROS_H
|
||||
#define ESPTERM_CONFIG_XMACROS_H
|
||||
|
||||
#include <esp8266.h>
|
||||
#include <helpers.h>
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
#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);
|
||||
enum xset_result xset_u32(const char *name, u32 *field, const char *buff, const void *arg);
|
||||
enum xset_result xset_u16(const char *name, u16 *field, const char *buff, const void *arg);
|
||||
|
||||
// static string arrays are not &'d, so we don't get **
|
||||
/** @param arg - max string length */
|
||||
enum xset_result xset_string(const char *name, char *field, const char *buff, const void *arg);
|
||||
enum xset_result xset_ustring(const char *name, u8 *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, xset, xsarg, xnotify, allow) \
|
||||
if ((allow) && GET_ARG(#name)) { \
|
||||
type *_p = (type *) &XSTRUCT->name; \
|
||||
enum xset_result res = xset(#name, _p, buff, (const void*) (xsarg)); \
|
||||
if (res == XSET_SET) { xnotify; } \
|
||||
else if (res == XSET_FAIL) { redir_url += sprintf(redir_url, #name","); } \
|
||||
}
|
||||
|
||||
/** used for INI */
|
||||
#define XSET_ASSIGN(type, name, suffix, deref, xget, xset, xsarg, xnotify, allow) \
|
||||
if (streq(#name, key)) { \
|
||||
found = true; \
|
||||
type *_p = (type *) &XSTRUCT->name; \
|
||||
enum xset_result res = xset(#name, _p, value, (const void*) (xsarg)); \
|
||||
if (res == XSET_SET) { xnotify; } \
|
||||
else if (res == XSET_FAIL) { suc = false; } \
|
||||
}
|
||||
|
||||
#define XGET_CGI_FUNC(type, name, suffix, deref, xget, xset, xsarg, xnotify, allow) \
|
||||
if ((allow) && streq(token, #name)) xget(buff, deref XSTRUCT->name);
|
||||
|
||||
#define XSTRUCT_FIELD(type, name, suffix, deref, xget, xset, xsarg, xnotify, allow) \
|
||||
type name suffix;
|
||||
|
||||
#define XDUMP_FIELD(type, name, suffix, deref, xget, allow, xset, xsarg, xnotify) \
|
||||
{ xget(buff, deref XSTRUCT->name); dbg(#name " = %s", buff); }
|
||||
|
||||
#endif //ESPTERM_CONFIG_XMACROS_H
|
||||
@@ -0,0 +1,526 @@
|
||||
|
||||
/* #line 1 "user/ini_parser.rl" */
|
||||
|
||||
/* Ragel constants block */
|
||||
#include "ini_parser.h"
|
||||
|
||||
// Ragel setup
|
||||
|
||||
/* #line 10 "user/ini_parser.c" */
|
||||
static const char _ini_actions[] ESP_CONST_DATA = {
|
||||
0, 1, 1, 1, 2, 1, 3, 1,
|
||||
4, 1, 5, 1, 6, 1, 7, 1,
|
||||
8, 1, 9, 1, 10, 1, 11, 1,
|
||||
13, 2, 0, 4, 2, 12, 4
|
||||
};
|
||||
|
||||
static const char _ini_eof_actions[] ESP_CONST_DATA = {
|
||||
0, 23, 5, 5, 15, 15, 15, 15,
|
||||
19, 19, 0, 0, 0, 0, 0, 0,
|
||||
0
|
||||
};
|
||||
|
||||
static const int ini_start = 1;
|
||||
static const int ini_first_final = 12;
|
||||
static const int ini_error = 0;
|
||||
|
||||
static const int ini_en_section = 2;
|
||||
static const int ini_en_keyvalue = 4;
|
||||
static const int ini_en_comment = 8;
|
||||
static const int ini_en_discard2eol = 10;
|
||||
static const int ini_en_main = 1;
|
||||
|
||||
|
||||
/* #line 10 "user/ini_parser.rl" */
|
||||
|
||||
|
||||
// Persistent state
|
||||
static int8_t cs = -1; //!< Ragel's Current State variable
|
||||
static uint32_t buff_i = 0; //!< Write pointer for the buffers
|
||||
static char value_quote = 0; //!< Quote character of the currently collected value
|
||||
static bool value_nextesc = false; //!< Next character is escaped, trated specially, and if quote, as literal quote character
|
||||
static IniParserCallback keyCallback = NULL; //!< Currently assigned callback
|
||||
static void *userdata = NULL; //!< Currently assigned user data for the callback
|
||||
|
||||
// Buffers
|
||||
static char keybuf[INI_KEY_MAX];
|
||||
static char secbuf[INI_KEY_MAX];
|
||||
static char valbuf[INI_VALUE_MAX];
|
||||
|
||||
// See header for doxygen!
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
ini_parse_reset_partial(void)
|
||||
{
|
||||
buff_i = 0;
|
||||
value_quote = 0;
|
||||
value_nextesc = false;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
ini_parse_reset(void)
|
||||
{
|
||||
ini_parse_reset_partial();
|
||||
keybuf[0] = secbuf[0] = valbuf[0] = 0;
|
||||
|
||||
/* #line 67 "user/ini_parser.c" */
|
||||
{
|
||||
cs = ini_start;
|
||||
}
|
||||
|
||||
/* #line 41 "user/ini_parser.rl" */
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
ini_parser_error(const char* msg)
|
||||
{
|
||||
ini_error("Parser error: %s", msg);
|
||||
ini_parse_reset_partial();
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
ini_parse_begin(IniParserCallback callback, void *userData)
|
||||
{
|
||||
keyCallback = callback;
|
||||
userdata = userData;
|
||||
ini_parse_reset();
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
*ini_parse_end(void)
|
||||
{
|
||||
ini_parse("\n", 1);
|
||||
if (keyCallback) {
|
||||
keyCallback = NULL;
|
||||
}
|
||||
|
||||
void *ud = userdata;
|
||||
userdata = NULL;
|
||||
return ud;
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData)
|
||||
{
|
||||
ini_parse_begin(callback, userData);
|
||||
ini_parse(text, len);
|
||||
ini_parse_end();
|
||||
}
|
||||
|
||||
static void ICACHE_FLASH_ATTR
|
||||
rtrim_buf(char *buf, int32_t end)
|
||||
{
|
||||
if (end > 0) {
|
||||
while ((uint8_t)buf[--end] < 33);
|
||||
end++; // go past the last character
|
||||
}
|
||||
|
||||
buf[end] = 0;
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
ini_parse(const char *newstr, size_t len)
|
||||
{
|
||||
int32_t i;
|
||||
char c;
|
||||
bool isnl;
|
||||
bool isquot;
|
||||
|
||||
// Load new data to Ragel vars
|
||||
const uint8_t *p;
|
||||
const uint8_t *eof;
|
||||
const uint8_t *pe;
|
||||
|
||||
if (len == 0) while(newstr[++len] != 0); // alternative to strlen
|
||||
|
||||
p = (const uint8_t *) newstr;
|
||||
eof = NULL;
|
||||
pe = (const uint8_t *) (newstr + len);
|
||||
|
||||
// Init Ragel on the first run
|
||||
if (cs == -1) {
|
||||
ini_parse_reset();
|
||||
}
|
||||
|
||||
// The parser
|
||||
|
||||
/* #line 152 "user/ini_parser.c" */
|
||||
{
|
||||
const char *_acts;
|
||||
unsigned int _nacts;
|
||||
|
||||
if ( p == pe )
|
||||
goto _test_eof;
|
||||
if ( cs == 0 )
|
||||
goto _out;
|
||||
_resume:
|
||||
switch ( cs ) {
|
||||
case 1:
|
||||
switch( (*p) ) {
|
||||
case 32u: goto tr1;
|
||||
case 35u: goto tr3;
|
||||
case 58u: goto tr0;
|
||||
case 59u: goto tr3;
|
||||
case 61u: goto tr0;
|
||||
case 91u: goto tr4;
|
||||
}
|
||||
if ( (*p) < 9u ) {
|
||||
if ( (*p) <= 8u )
|
||||
goto tr0;
|
||||
} else if ( (*p) > 13u ) {
|
||||
if ( 14u <= (*p) && (*p) <= 31u )
|
||||
goto tr0;
|
||||
} else
|
||||
goto tr1;
|
||||
goto tr2;
|
||||
case 0:
|
||||
goto _out;
|
||||
case 12:
|
||||
goto tr0;
|
||||
case 2:
|
||||
switch( (*p) ) {
|
||||
case 9u: goto tr6;
|
||||
case 32u: goto tr6;
|
||||
case 93u: goto tr5;
|
||||
}
|
||||
if ( (*p) <= 31u )
|
||||
goto tr5;
|
||||
goto tr7;
|
||||
case 3:
|
||||
if ( (*p) == 93u )
|
||||
goto tr8;
|
||||
if ( (*p) > 8u ) {
|
||||
if ( 10u <= (*p) && (*p) <= 31u )
|
||||
goto tr5;
|
||||
} else
|
||||
goto tr5;
|
||||
goto tr7;
|
||||
case 13:
|
||||
goto tr5;
|
||||
case 4:
|
||||
switch( (*p) ) {
|
||||
case 10u: goto tr10;
|
||||
case 58u: goto tr11;
|
||||
case 61u: goto tr11;
|
||||
}
|
||||
goto tr9;
|
||||
case 5:
|
||||
switch( (*p) ) {
|
||||
case 9u: goto tr13;
|
||||
case 10u: goto tr14;
|
||||
case 13u: goto tr15;
|
||||
case 32u: goto tr13;
|
||||
}
|
||||
goto tr12;
|
||||
case 6:
|
||||
switch( (*p) ) {
|
||||
case 10u: goto tr14;
|
||||
case 13u: goto tr15;
|
||||
}
|
||||
goto tr12;
|
||||
case 14:
|
||||
goto tr10;
|
||||
case 7:
|
||||
if ( (*p) == 10u )
|
||||
goto tr14;
|
||||
goto tr10;
|
||||
case 8:
|
||||
switch( (*p) ) {
|
||||
case 10u: goto tr17;
|
||||
case 13u: goto tr18;
|
||||
}
|
||||
goto tr16;
|
||||
case 15:
|
||||
goto tr19;
|
||||
case 9:
|
||||
if ( (*p) == 10u )
|
||||
goto tr17;
|
||||
goto tr19;
|
||||
case 10:
|
||||
switch( (*p) ) {
|
||||
case 10u: goto tr21;
|
||||
case 13u: goto tr22;
|
||||
}
|
||||
goto tr20;
|
||||
case 16:
|
||||
goto tr23;
|
||||
case 11:
|
||||
if ( (*p) == 10u )
|
||||
goto tr21;
|
||||
goto tr23;
|
||||
}
|
||||
|
||||
tr23: cs = 0; goto _again;
|
||||
tr0: cs = 0; goto f0;
|
||||
tr5: cs = 0; goto f4;
|
||||
tr10: cs = 0; goto f7;
|
||||
tr19: cs = 0; goto f11;
|
||||
tr1: cs = 1; goto _again;
|
||||
tr6: cs = 2; goto _again;
|
||||
tr7: cs = 3; goto f5;
|
||||
tr9: cs = 4; goto f8;
|
||||
tr13: cs = 5; goto _again;
|
||||
tr11: cs = 5; goto f9;
|
||||
tr12: cs = 6; goto f10;
|
||||
tr15: cs = 7; goto _again;
|
||||
tr16: cs = 8; goto _again;
|
||||
tr18: cs = 9; goto _again;
|
||||
tr20: cs = 10; goto _again;
|
||||
tr22: cs = 11; goto _again;
|
||||
tr2: cs = 12; goto f1;
|
||||
tr3: cs = 12; goto f2;
|
||||
tr4: cs = 12; goto f3;
|
||||
tr8: cs = 13; goto f6;
|
||||
tr14: cs = 14; goto f10;
|
||||
tr17: cs = 15; goto f12;
|
||||
tr21: cs = 16; goto f13;
|
||||
|
||||
f5: _acts = _ini_actions + 1; goto execFuncs;
|
||||
f6: _acts = _ini_actions + 3; goto execFuncs;
|
||||
f4: _acts = _ini_actions + 5; goto execFuncs;
|
||||
f1: _acts = _ini_actions + 7; goto execFuncs;
|
||||
f8: _acts = _ini_actions + 9; goto execFuncs;
|
||||
f9: _acts = _ini_actions + 11; goto execFuncs;
|
||||
f10: _acts = _ini_actions + 13; goto execFuncs;
|
||||
f7: _acts = _ini_actions + 15; goto execFuncs;
|
||||
f12: _acts = _ini_actions + 17; goto execFuncs;
|
||||
f11: _acts = _ini_actions + 19; goto execFuncs;
|
||||
f13: _acts = _ini_actions + 21; goto execFuncs;
|
||||
f0: _acts = _ini_actions + 23; goto execFuncs;
|
||||
f3: _acts = _ini_actions + 25; goto execFuncs;
|
||||
f2: _acts = _ini_actions + 28; goto execFuncs;
|
||||
|
||||
execFuncs:
|
||||
_nacts = *_acts++;
|
||||
while ( _nacts-- > 0 ) {
|
||||
switch ( *_acts++ ) {
|
||||
case 0:
|
||||
/* #line 130 "user/ini_parser.rl" */
|
||||
{
|
||||
buff_i = 0;
|
||||
{cs = 2;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* #line 135 "user/ini_parser.rl" */
|
||||
{
|
||||
if (buff_i >= INI_KEY_MAX) {
|
||||
ini_parser_error("Section name too long");
|
||||
{cs = 10;goto _again;}
|
||||
}
|
||||
keybuf[buff_i++] = (*p);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* #line 143 "user/ini_parser.rl" */
|
||||
{
|
||||
// we need a separate buffer for the result, otherwise a failed
|
||||
// partial parse would corrupt the section string
|
||||
rtrim_buf(keybuf, buff_i);
|
||||
for (i = 0; (c = keybuf[i]) != 0; i++) secbuf[i] = c;
|
||||
secbuf[i] = 0;
|
||||
{cs = 1;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
/* #line 155 "user/ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in [section]");
|
||||
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
/* #line 162 "user/ini_parser.rl" */
|
||||
{
|
||||
buff_i = 0;
|
||||
keybuf[buff_i++] = (*p); // add the first char
|
||||
{cs = 4;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
/* #line 168 "user/ini_parser.rl" */
|
||||
{
|
||||
if (buff_i >= INI_KEY_MAX) {
|
||||
ini_parser_error("Key too long");
|
||||
{cs = 10;goto _again;}
|
||||
}
|
||||
keybuf[buff_i++] = (*p);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
/* #line 176 "user/ini_parser.rl" */
|
||||
{
|
||||
rtrim_buf(keybuf, buff_i);
|
||||
|
||||
// --- Value begin ---
|
||||
buff_i = 0;
|
||||
value_quote = 0;
|
||||
value_nextesc = false;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
/* #line 185 "user/ini_parser.rl" */
|
||||
{
|
||||
isnl = ((*p) == '\r' || (*p) == '\n');
|
||||
isquot = ((*p) == '\'' || (*p) == '"');
|
||||
|
||||
// detect our starting quote
|
||||
if (isquot && !value_nextesc && buff_i == 0 && value_quote == 0) {
|
||||
value_quote = (*p);
|
||||
goto valueCharDone;
|
||||
}
|
||||
|
||||
if (buff_i >= INI_VALUE_MAX) {
|
||||
ini_parser_error("Value too long");
|
||||
{cs = 10;goto _again;}
|
||||
}
|
||||
|
||||
// end of string - clean up and report
|
||||
if ((!value_nextesc && (*p) == value_quote) || isnl) {
|
||||
if (isnl && value_quote) {
|
||||
ini_parser_error("Unterminated string");
|
||||
{cs = 1;goto _again;}
|
||||
}
|
||||
|
||||
// unquoted: trim from the end
|
||||
if (!value_quote) {
|
||||
rtrim_buf(valbuf, buff_i);
|
||||
} else {
|
||||
valbuf[buff_i] = 0;
|
||||
}
|
||||
|
||||
if (keyCallback) {
|
||||
keyCallback(secbuf, keybuf, valbuf, userdata);
|
||||
}
|
||||
|
||||
// we don't want to discard to eol if the string was terminated by eol
|
||||
// - would delete the next line
|
||||
|
||||
if (isnl) {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||
}
|
||||
|
||||
c = (*p);
|
||||
// escape...
|
||||
if (value_nextesc) {
|
||||
if ((*p) == 'n') c = '\n';
|
||||
else if ((*p) == 'r') c = '\r';
|
||||
else if ((*p) == 't') c = '\t';
|
||||
else if ((*p) == 'e') c = '\033';
|
||||
}
|
||||
|
||||
// collecting characters...
|
||||
if (value_nextesc || (*p) != '\\') { // is quoted, or is not a quoting backslash - literal character
|
||||
valbuf[buff_i++] = c;
|
||||
}
|
||||
|
||||
value_nextesc = (!value_nextesc && (*p) == '\\');
|
||||
valueCharDone:;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
/* #line 247 "user/ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in key=value");
|
||||
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
/* #line 257 "user/ini_parser.rl" */
|
||||
{ {cs = 1;goto _again;} }
|
||||
break;
|
||||
case 10:
|
||||
/* #line 258 "user/ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in comment");
|
||||
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
/* #line 265 "user/ini_parser.rl" */
|
||||
{ {cs = 1;goto _again;} }
|
||||
break;
|
||||
case 12:
|
||||
/* #line 273 "user/ini_parser.rl" */
|
||||
{ {cs = 8;goto _again;} }
|
||||
break;
|
||||
case 13:
|
||||
/* #line 276 "user/ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in root");
|
||||
{cs = 10;goto _again;}
|
||||
}
|
||||
break;
|
||||
/* #line 458 "user/ini_parser.c" */
|
||||
}
|
||||
}
|
||||
goto _again;
|
||||
|
||||
_again:
|
||||
if ( cs == 0 )
|
||||
goto _out;
|
||||
if ( ++p != pe )
|
||||
goto _resume;
|
||||
_test_eof: {}
|
||||
if ( p == eof )
|
||||
{
|
||||
const char *__acts = _ini_actions + _ini_eof_actions[cs];
|
||||
unsigned int __nacts = (unsigned int) *__acts++;
|
||||
while ( __nacts-- > 0 ) {
|
||||
switch ( *__acts++ ) {
|
||||
case 3:
|
||||
/* #line 155 "user/ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in [section]");
|
||||
if((*p) == '\n') {cs = 1; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;} else {cs = 10; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;}
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
/* #line 247 "user/ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in key=value");
|
||||
if((*p) == '\n') {cs = 1; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;} else {cs = 10; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;}
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
/* #line 258 "user/ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in comment");
|
||||
if((*p) == '\n') {cs = 1; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;} else {cs = 10; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;}
|
||||
}
|
||||
break;
|
||||
case 13:
|
||||
/* #line 276 "user/ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in root");
|
||||
{cs = 10; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;}
|
||||
}
|
||||
break;
|
||||
/* #line 517 "user/ini_parser.c" */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_out: {}
|
||||
}
|
||||
|
||||
/* #line 283 "user/ini_parser.rl" */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#ifndef INIPARSE_STREAM_H
|
||||
#define INIPARSE_STREAM_H
|
||||
|
||||
#include <esp8266.h>
|
||||
|
||||
#ifdef DEBUG_INI
|
||||
#define ini_error(fmt, ...) error("[INI] "#fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define ini_error(fmt, ...)
|
||||
#endif
|
||||
|
||||
// buffer sizes
|
||||
#define INI_KEY_MAX 64
|
||||
#define INI_VALUE_MAX 256
|
||||
|
||||
/**
|
||||
* INI parser callback, called for each found key-value pair.
|
||||
*
|
||||
* @param section - current section, empty string for global keys
|
||||
* @param key - found key (trimmed of whitespace)
|
||||
* @param value - value, trimmed of quotes or whitespace
|
||||
* @param userData - opaque user data pointer, general purpose
|
||||
*/
|
||||
typedef void (*IniParserCallback)(const char *section, const char *key, const char *value, void *userData);
|
||||
|
||||
/**
|
||||
* Begin parsing a stream
|
||||
*
|
||||
* @param callback - key callback to assign
|
||||
* @param userData - optional user data that willb e passed to the callback
|
||||
*/
|
||||
void ini_parse_begin(IniParserCallback callback, void *userData);
|
||||
|
||||
/**
|
||||
* End parse stream.
|
||||
* Flushes what remains in the buffer and removes callback.
|
||||
*
|
||||
* @returns userData or NULL if none
|
||||
*/
|
||||
void* ini_parse_end(void);
|
||||
|
||||
/**
|
||||
* Parse a string (needn't be complete line or file)
|
||||
*
|
||||
* @param data - string to parse
|
||||
* @param len - string length (0 = use strlen)
|
||||
*/
|
||||
void ini_parse(const char *data, size_t len);
|
||||
|
||||
/**
|
||||
* Parse a complete file loaded to string
|
||||
*
|
||||
* @param text - entire file as string
|
||||
* @param len - file length (0 = use strlen)
|
||||
* @param callback - key callback
|
||||
* @param userData - optional user data for key callback
|
||||
*/
|
||||
void ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData);
|
||||
|
||||
/**
|
||||
* Explicitly reset the parser
|
||||
*/
|
||||
void ini_parse_reset(void);
|
||||
|
||||
#endif // INIPARSE_STREAM_H
|
||||
@@ -0,0 +1,284 @@
|
||||
|
||||
/* Ragel constants block */
|
||||
#include "ini_parser.h"
|
||||
|
||||
// Ragel setup
|
||||
%%{
|
||||
machine ini;
|
||||
write data;
|
||||
alphtype unsigned char;
|
||||
}%%
|
||||
|
||||
// Persistent state
|
||||
static int8_t cs = -1; //!< Ragel's Current State variable
|
||||
static uint32_t buff_i = 0; //!< Write pointer for the buffers
|
||||
static char value_quote = 0; //!< Quote character of the currently collected value
|
||||
static bool value_nextesc = false; //!< Next character is escaped, trated specially, and if quote, as literal quote character
|
||||
static IniParserCallback keyCallback = NULL; //!< Currently assigned callback
|
||||
static void *userdata = NULL; //!< Currently assigned user data for the callback
|
||||
|
||||
// Buffers
|
||||
static char keybuf[INI_KEY_MAX];
|
||||
static char secbuf[INI_KEY_MAX];
|
||||
static char valbuf[INI_VALUE_MAX];
|
||||
|
||||
// See header for doxygen!
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
ini_parse_reset_partial(void)
|
||||
{
|
||||
buff_i = 0;
|
||||
value_quote = 0;
|
||||
value_nextesc = false;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
ini_parse_reset(void)
|
||||
{
|
||||
ini_parse_reset_partial();
|
||||
keybuf[0] = secbuf[0] = valbuf[0] = 0;
|
||||
%% write init;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
ini_parser_error(const char* msg)
|
||||
{
|
||||
ini_error("Parser error: %s", msg);
|
||||
ini_parse_reset_partial();
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
ini_parse_begin(IniParserCallback callback, void *userData)
|
||||
{
|
||||
keyCallback = callback;
|
||||
userdata = userData;
|
||||
ini_parse_reset();
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
*ini_parse_end(void)
|
||||
{
|
||||
ini_parse("\n", 1);
|
||||
if (keyCallback) {
|
||||
keyCallback = NULL;
|
||||
}
|
||||
|
||||
void *ud = userdata;
|
||||
userdata = NULL;
|
||||
return ud;
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData)
|
||||
{
|
||||
ini_parse_begin(callback, userData);
|
||||
ini_parse(text, len);
|
||||
ini_parse_end();
|
||||
}
|
||||
|
||||
static void ICACHE_FLASH_ATTR
|
||||
rtrim_buf(char *buf, int32_t end)
|
||||
{
|
||||
if (end > 0) {
|
||||
while ((uint8_t)buf[--end] < 33);
|
||||
end++; // go past the last character
|
||||
}
|
||||
|
||||
buf[end] = 0;
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
ini_parse(const char *newstr, size_t len)
|
||||
{
|
||||
int32_t i;
|
||||
char c;
|
||||
bool isnl;
|
||||
bool isquot;
|
||||
|
||||
// Load new data to Ragel vars
|
||||
const uint8_t *p;
|
||||
const uint8_t *eof;
|
||||
const uint8_t *pe;
|
||||
|
||||
if (len == 0) while(newstr[++len] != 0); // alternative to strlen
|
||||
|
||||
p = (const uint8_t *) newstr;
|
||||
eof = NULL;
|
||||
pe = (const uint8_t *) (newstr + len);
|
||||
|
||||
// Init Ragel on the first run
|
||||
if (cs == -1) {
|
||||
ini_parse_reset();
|
||||
}
|
||||
|
||||
// The parser
|
||||
%%{
|
||||
#/ *
|
||||
ispace = [ \t]; # inline space
|
||||
wchar = any - 0..8 - 10..31;
|
||||
#apos = '\'';
|
||||
#quot = '\"';
|
||||
nonl = [^\r\n];
|
||||
nl = '\r'? '\n';
|
||||
|
||||
# ---- [SECTION] ----
|
||||
|
||||
action sectionStart {
|
||||
buff_i = 0;
|
||||
fgoto section;
|
||||
}
|
||||
|
||||
action sectionChar {
|
||||
if (buff_i >= INI_KEY_MAX) {
|
||||
ini_parser_error("Section name too long");
|
||||
fgoto discard2eol;
|
||||
}
|
||||
keybuf[buff_i++] = fc;
|
||||
}
|
||||
|
||||
action sectionEnd {
|
||||
// we need a separate buffer for the result, otherwise a failed
|
||||
// partial parse would corrupt the section string
|
||||
rtrim_buf(keybuf, buff_i);
|
||||
for (i = 0; (c = keybuf[i]) != 0; i++) secbuf[i] = c;
|
||||
secbuf[i] = 0;
|
||||
fgoto main;
|
||||
}
|
||||
|
||||
section :=
|
||||
(
|
||||
ispace* <: ((wchar - ']')+ @sectionChar) ']' @sectionEnd
|
||||
) $!{
|
||||
ini_parser_error("Syntax error in [section]");
|
||||
if(fc == '\n') fgoto main; else fgoto discard2eol;
|
||||
};
|
||||
|
||||
# ---- KEY=VALUE ----
|
||||
|
||||
action keyStart {
|
||||
buff_i = 0;
|
||||
keybuf[buff_i++] = fc; // add the first char
|
||||
fgoto keyvalue;
|
||||
}
|
||||
|
||||
action keyChar {
|
||||
if (buff_i >= INI_KEY_MAX) {
|
||||
ini_parser_error("Key too long");
|
||||
fgoto discard2eol;
|
||||
}
|
||||
keybuf[buff_i++] = fc;
|
||||
}
|
||||
|
||||
action keyEnd {
|
||||
rtrim_buf(keybuf, buff_i);
|
||||
|
||||
// --- Value begin ---
|
||||
buff_i = 0;
|
||||
value_quote = 0;
|
||||
value_nextesc = false;
|
||||
}
|
||||
|
||||
action valueChar {
|
||||
isnl = (fc == '\r' || fc == '\n');
|
||||
isquot = (fc == '\'' || fc == '"');
|
||||
|
||||
// detect our starting quote
|
||||
if (isquot && !value_nextesc && buff_i == 0 && value_quote == 0) {
|
||||
value_quote = fc;
|
||||
goto valueCharDone;
|
||||
}
|
||||
|
||||
if (buff_i >= INI_VALUE_MAX) {
|
||||
ini_parser_error("Value too long");
|
||||
fgoto discard2eol;
|
||||
}
|
||||
|
||||
// end of string - clean up and report
|
||||
if ((!value_nextesc && fc == value_quote) || isnl) {
|
||||
if (isnl && value_quote) {
|
||||
ini_parser_error("Unterminated string");
|
||||
fgoto main;
|
||||
}
|
||||
|
||||
// unquoted: trim from the end
|
||||
if (!value_quote) {
|
||||
rtrim_buf(valbuf, buff_i);
|
||||
} else {
|
||||
valbuf[buff_i] = 0;
|
||||
}
|
||||
|
||||
if (keyCallback) {
|
||||
keyCallback(secbuf, keybuf, valbuf, userdata);
|
||||
}
|
||||
|
||||
// we don't want to discard to eol if the string was terminated by eol
|
||||
// - would delete the next line
|
||||
|
||||
if (isnl) fgoto main; else fgoto discard2eol;
|
||||
}
|
||||
|
||||
c = fc;
|
||||
// escape...
|
||||
if (value_nextesc) {
|
||||
if (fc == 'n') c = '\n';
|
||||
else if (fc == 'r') c = '\r';
|
||||
else if (fc == 't') c = '\t';
|
||||
else if (fc == 'e') c = '\033';
|
||||
}
|
||||
|
||||
// collecting characters...
|
||||
if (value_nextesc || fc != '\\') { // is quoted, or is not a quoting backslash - literal character
|
||||
valbuf[buff_i++] = c;
|
||||
}
|
||||
|
||||
value_nextesc = (!value_nextesc && fc == '\\');
|
||||
valueCharDone:;
|
||||
}
|
||||
|
||||
# use * for key, first char is already consumed.
|
||||
keyvalue :=
|
||||
(
|
||||
([^\n=:]* @keyChar %keyEnd)
|
||||
[=:] ispace* <: nonl* @valueChar nl @valueChar
|
||||
) $!{
|
||||
ini_parser_error("Syntax error in key=value");
|
||||
if(fc == '\n') fgoto main; else fgoto discard2eol;
|
||||
};
|
||||
|
||||
# ---- COMMENT ----
|
||||
|
||||
comment :=
|
||||
(
|
||||
nonl* nl
|
||||
@{ fgoto main; }
|
||||
) $!{
|
||||
ini_parser_error("Syntax error in comment");
|
||||
if(fc == '\n') fgoto main; else fgoto discard2eol;
|
||||
};
|
||||
|
||||
# ---- CLEANUP ----
|
||||
|
||||
discard2eol := nonl* nl @{ fgoto main; };
|
||||
|
||||
# ---- ROOT ----
|
||||
|
||||
main :=
|
||||
(space*
|
||||
(
|
||||
'[' @sectionStart |
|
||||
[#;] @{ fgoto comment; } |
|
||||
(wchar - [\t =:]) @keyStart
|
||||
)
|
||||
) $!{
|
||||
ini_parser_error("Syntax error in root");
|
||||
fgoto discard2eol;
|
||||
};
|
||||
|
||||
write exec;
|
||||
#*/
|
||||
}%%
|
||||
}
|
||||
+4
-2
@@ -23,8 +23,8 @@
|
||||
static int ICACHE_FLASH_ATTR wifiPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen)
|
||||
{
|
||||
if (no == 0) {
|
||||
os_strcpy(user, sysconf->access_name);
|
||||
os_strcpy(pass, sysconf->access_pw);
|
||||
os_strcpy(user, (const char *) sysconf->access_name);
|
||||
os_strcpy(pass, (const char *) sysconf->access_pw);
|
||||
return 1;
|
||||
}
|
||||
if (no == 1) {
|
||||
@@ -131,6 +131,8 @@ const HttpdBuiltInUrl routes[] ESP_CONST_DATA = {
|
||||
|
||||
ROUTE_TPL_FILE("/cfg/system/?", tplSystemCfg, "/cfg_system.tpl"),
|
||||
ROUTE_CGI("/cfg/system/set", cgiSystemCfgSetParams),
|
||||
ROUTE_CGI("/cfg/system/export", cgiPersistExport),
|
||||
ROUTE_CGI("/cfg/system/import", cgiPersistImport),
|
||||
ROUTE_CGI("/cfg/system/write_defaults", cgiPersistWriteDefaults),
|
||||
ROUTE_CGI("/cfg/system/restore_defaults", cgiPersistRestoreDefaults),
|
||||
ROUTE_CGI("/cfg/system/restore_hard", cgiPersistRestoreHard),
|
||||
|
||||
+259
-54
@@ -8,6 +8,7 @@
|
||||
#include "character_sets.h"
|
||||
#include "utf8.h"
|
||||
#include "cgi_sockets.h"
|
||||
#include "cgi_logging.h"
|
||||
|
||||
TerminalConfigBundle * const termconf = &persist.current.termconf;
|
||||
TerminalConfigBundle termconf_live;
|
||||
@@ -106,8 +107,19 @@ bool cursor_saved = false;
|
||||
static struct {
|
||||
bool alternate_active;
|
||||
char title[TERM_TITLE_LEN];
|
||||
char btn[TERM_BTN_COUNT][TERM_BTN_LEN];
|
||||
char btn_msg[TERM_BTN_COUNT][TERM_BTN_MSG_LEN];
|
||||
|
||||
char btn1[TERM_BTN_LEN];
|
||||
char btn2[TERM_BTN_LEN];
|
||||
char btn3[TERM_BTN_LEN];
|
||||
char btn4[TERM_BTN_LEN];
|
||||
char btn5[TERM_BTN_LEN];
|
||||
|
||||
char btn1_msg[TERM_BTN_MSG_LEN];
|
||||
char btn2_msg[TERM_BTN_MSG_LEN];
|
||||
char btn3_msg[TERM_BTN_MSG_LEN];
|
||||
char btn4_msg[TERM_BTN_MSG_LEN];
|
||||
char btn5_msg[TERM_BTN_MSG_LEN];
|
||||
|
||||
u32 width;
|
||||
u32 height;
|
||||
int vm0;
|
||||
@@ -143,46 +155,194 @@ static struct {
|
||||
int x_min, y_min, x_max, y_max;
|
||||
} scr_dirty;
|
||||
|
||||
#define reset_screen_dirty() do { \
|
||||
scr_dirty.x_min = W; \
|
||||
scr_dirty.x_max = -1; \
|
||||
scr_dirty.y_min = H; \
|
||||
scr_dirty.y_max = -1; \
|
||||
} while(0)
|
||||
static void ICACHE_FLASH_ATTR reset_screen_dirty(void)
|
||||
{
|
||||
scr_dirty.x_min = W;
|
||||
scr_dirty.x_max = -1;
|
||||
scr_dirty.y_min = H;
|
||||
scr_dirty.y_max = -1;
|
||||
}
|
||||
|
||||
#define expand_dirty(y0, y1, x0, x1) do { \
|
||||
seri_dbg("Expand: X: (%d..%d) -> %d..%d, Y: (%d..%d) -> %d..%d", scr_dirty.x_min, scr_dirty.x_max, x0, x1, scr_dirty.y_min, scr_dirty.y_max, y0, y1); \
|
||||
if ((int)(y0) < scr_dirty.y_min) scr_dirty.y_min = (y0); \
|
||||
if ((int)(x0) < scr_dirty.x_min) scr_dirty.x_min = (x0); \
|
||||
if ((int)(y1) > scr_dirty.y_max) scr_dirty.y_max = (y1); \
|
||||
if ((int)(x1) > scr_dirty.x_max) scr_dirty.x_max = (x1); \
|
||||
} while(0)
|
||||
static void ICACHE_FLASH_ATTR expand_dirty(int y0, int y1, int x0, int x1)
|
||||
{
|
||||
seri_dbg("Expand: X: (%d..%d) -> %d..%d, Y: (%d..%d) -> %d..%d",
|
||||
scr_dirty.x_min, scr_dirty.x_max, x0, x1, scr_dirty.y_min, scr_dirty.y_max, y0, y1);
|
||||
|
||||
#define NOTIFY_LOCK() do { \
|
||||
notifyLock++; \
|
||||
} while(0)
|
||||
if ((y0) < scr_dirty.y_min) scr_dirty.y_min = (y0);
|
||||
if ((x0) < scr_dirty.x_min) scr_dirty.x_min = (x0);
|
||||
if ((y1) > scr_dirty.y_max) scr_dirty.y_max = (y1);
|
||||
if ((x1) > scr_dirty.x_max) scr_dirty.x_max = (x1);
|
||||
}
|
||||
|
||||
#define NOTIFY_DONE(updateTopics) do { \
|
||||
lockTopics |= (updateTopics); \
|
||||
if (notifyLock > 0) notifyLock--; \
|
||||
if (notifyLock == 0) { \
|
||||
screen_notifyChange(lockTopics); \
|
||||
lockTopics = 0;\
|
||||
} \
|
||||
} while(0)
|
||||
#define NOTIFY_LOCK() { notifyLock++; }
|
||||
|
||||
static void ICACHE_FLASH_ATTR NOTIFY_DONE(u32 updateTopics)
|
||||
{
|
||||
lockTopics |= (updateTopics);
|
||||
if (notifyLock > 0) notifyLock--;
|
||||
if (notifyLock == 0) {
|
||||
screen_notifyChange(lockTopics);
|
||||
lockTopics = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Clear the hanging attribute if the cursor is no longer >= W */
|
||||
#define clear_invalid_hanging() do { \
|
||||
if (cursor.hanging && cursor.x != W-1) { \
|
||||
cursor.hanging = false; \
|
||||
screen_notifyChange(TOPIC_CHANGE_CURSOR); \
|
||||
} \
|
||||
} while(false)
|
||||
static void ICACHE_FLASH_ATTR clear_invalid_hanging(void)
|
||||
{
|
||||
if (cursor.hanging && cursor.x != W-1) {
|
||||
cursor.hanging = false;
|
||||
screen_notifyChange(TOPIC_CHANGE_CURSOR);
|
||||
}
|
||||
}
|
||||
|
||||
#define cursor_inside_region() (cursor.y >= TOP && cursor.y <= BTM)
|
||||
|
||||
//region --- Settings ---
|
||||
|
||||
/** Export color for config */
|
||||
void ICACHE_FLASH_ATTR
|
||||
xget_term_color(char *buff, u32 value)
|
||||
{
|
||||
if (value < 256) {
|
||||
sprintf(buff, "%d", value);
|
||||
} else {
|
||||
sprintf(buff, "#%06X", value - 256);
|
||||
}
|
||||
}
|
||||
|
||||
/** Export button message as stirng for config */
|
||||
void ICACHE_FLASH_ATTR
|
||||
xget_term_bm(char *buff, char *value)
|
||||
{
|
||||
char c;
|
||||
char *bp = buff;
|
||||
char *cp = value;
|
||||
int n = 0;
|
||||
while((c = *cp++) != 0) {
|
||||
if(n>0) {
|
||||
*bp = ',';
|
||||
bp++;
|
||||
}
|
||||
bp += sprintf(bp, "%d", (u8)c);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
enum xset_result ICACHE_FLASH_ATTR
|
||||
xset_term_bm(const char *name, char *field, const char *buff, const void *arg)
|
||||
{
|
||||
cgi_dbg("Setting %s = %s", name, buff);
|
||||
|
||||
// parse: comma,space or semicolon separated decimal values of ASCII codes
|
||||
char c;
|
||||
const char *cp = buff;
|
||||
int char_i = 0;
|
||||
int acu = 0;
|
||||
bool lastsp = 1;
|
||||
char buff_bm[TERM_BTN_MSG_LEN];
|
||||
while ((c = *cp++) != 0) {
|
||||
if (c == ' ' || c == ',' || c == ';') {
|
||||
if(lastsp) continue;
|
||||
|
||||
if (acu==0 || acu>255) {
|
||||
cgi_warn("Bad value! %d", acu);
|
||||
return XSET_FAIL;
|
||||
}
|
||||
|
||||
if (char_i >= TERM_BTN_MSG_LEN-1) {
|
||||
cgi_warn("Too long! %d", char_i);
|
||||
return XSET_FAIL;
|
||||
}
|
||||
|
||||
// cgi_dbg("acu %d", acu);
|
||||
buff_bm[char_i++] = (char)acu;
|
||||
|
||||
// prepare for next char
|
||||
acu = 0;
|
||||
lastsp = 1;
|
||||
} else if (c>='0'&&c<='9') {
|
||||
lastsp = 0;
|
||||
acu *= 10;
|
||||
acu += c - '0';
|
||||
} else {
|
||||
cgi_warn("Bad syntax!");
|
||||
return XSET_FAIL;
|
||||
}
|
||||
}
|
||||
if (lastsp && char_i == 0) {
|
||||
cgi_warn("Required!");
|
||||
return XSET_FAIL;
|
||||
}
|
||||
if (!lastsp) {
|
||||
buff_bm[char_i++] = (char)acu;
|
||||
}
|
||||
buff_bm[char_i] = 0;
|
||||
// cgi_dbg("%s, chari = %d", buff_bm, char_i);
|
||||
|
||||
if (!streq(field, buff_bm)) {
|
||||
strncpy(field, buff_bm, TERM_BTN_MSG_LEN);
|
||||
return XSET_SET;
|
||||
}
|
||||
return XSET_UNCHANGED;
|
||||
}
|
||||
|
||||
/** convert hex number to int */
|
||||
static ICACHE_FLASH_ATTR u32
|
||||
decodehex(const char *buf) {
|
||||
u32 n = 0;
|
||||
char c;
|
||||
while ((c = *buf++) != 0) {
|
||||
if (c >= '0' && c <= '9') c -= '0';
|
||||
else if (c >= 'a' && c <= 'f') c -= 'a'-10;
|
||||
else if (c >= 'A' && c <= 'F') c -= 'A'-10;
|
||||
else c = 0;
|
||||
n *= 16;
|
||||
n += c;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
enum xset_result ICACHE_FLASH_ATTR
|
||||
xset_term_color(const char *name, u32 *field, const char *buff, const void *arg)
|
||||
{
|
||||
cgi_dbg("Setting %s = %s", name, buff);
|
||||
u32 n;
|
||||
|
||||
if (buff[0] == '#') {
|
||||
// decode hex
|
||||
n = decodehex(buff+1);
|
||||
n += 256;
|
||||
} else {
|
||||
n = atoi(buff);
|
||||
}
|
||||
|
||||
if (*field != n) {
|
||||
*field = n;
|
||||
return XSET_SET;
|
||||
}
|
||||
|
||||
return XSET_UNCHANGED;
|
||||
}
|
||||
|
||||
enum xset_result ICACHE_FLASH_ATTR
|
||||
xset_term_cursorshape(const char *name, u32 *field, const char *buff, const void *arg)
|
||||
{
|
||||
cgi_dbg("Setting %s = %s", name, buff);
|
||||
u32 n = atoi(buff);
|
||||
|
||||
if (n >= 0 && n <= 6 && n != 1) {
|
||||
if (*field != n) {
|
||||
*field = n;
|
||||
return XSET_SET;
|
||||
}
|
||||
return XSET_UNCHANGED;
|
||||
} else {
|
||||
cgi_warn("Bad cursor_shape num: %s", buff);
|
||||
return XSET_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restore hard defaults
|
||||
*/
|
||||
@@ -194,10 +354,19 @@ terminal_restore_defaults(void)
|
||||
termconf->default_bg = 0;
|
||||
termconf->default_fg = 7;
|
||||
sprintf(termconf->title, SCR_DEF_TITLE);
|
||||
for(int i=1; i <= TERM_BTN_COUNT; i++) {
|
||||
sprintf(termconf->btn[i-1], "%d", i);
|
||||
sprintf(termconf->btn_msg[i-1], "%c", i);
|
||||
}
|
||||
|
||||
strcpy(termconf->btn1, "1");
|
||||
strcpy(termconf->btn2, "2");
|
||||
strcpy(termconf->btn3, "3");
|
||||
strcpy(termconf->btn4, "4");
|
||||
strcpy(termconf->btn5, "5");
|
||||
|
||||
strcpy((char*)termconf->bm1, "\x01");
|
||||
strcpy((char*)termconf->bm2, "\x02");
|
||||
strcpy((char*)termconf->bm3, "\x03");
|
||||
strcpy((char*)termconf->bm4, "\x04");
|
||||
strcpy((char*)termconf->bm5, "\x05");
|
||||
|
||||
termconf->theme = 0;
|
||||
termconf->parser_tout_ms = SCR_DEF_PARSER_TOUT_MS;
|
||||
termconf->display_tout_ms = SCR_DEF_DISPLAY_TOUT_MS;
|
||||
@@ -232,6 +401,13 @@ terminal_apply_settings_noclear(void)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
// char buff[64];
|
||||
//#define XSTRUCT termconf
|
||||
//#define X XDUMP_FIELD
|
||||
// XTABLE_TERMCONF
|
||||
//#undef X
|
||||
// return;
|
||||
|
||||
// Migrate
|
||||
if (termconf->config_version < 1) {
|
||||
persist_dbg("termconf: Updating to version %d", 1);
|
||||
@@ -393,10 +569,11 @@ screen_reset_do(bool size, bool labels)
|
||||
strcpy(termconf_live.title, termconf->title);
|
||||
strcpy(termconf_live.backdrop, termconf->backdrop);
|
||||
|
||||
for (int i = 1; i <= TERM_BTN_COUNT; i++) {
|
||||
strcpy(termconf_live.btn[i], termconf->btn[i]);
|
||||
strcpy(termconf_live.btn_msg[i], termconf->btn_msg[i]);
|
||||
}
|
||||
strcpy(termconf_live.btn1, termconf->btn1);
|
||||
strcpy(termconf_live.btn2, termconf->btn2);
|
||||
strcpy(termconf_live.btn3, termconf->btn3);
|
||||
strcpy(termconf_live.btn4, termconf->btn4);
|
||||
strcpy(termconf_live.btn5, termconf->btn5);
|
||||
|
||||
termconf_live.show_buttons = termconf->show_buttons;
|
||||
termconf_live.show_config_links = termconf->show_config_links;
|
||||
@@ -452,8 +629,11 @@ screen_swap_state(bool alternate)
|
||||
ansi_dbg("Swap to alternate");
|
||||
// store old state
|
||||
memcpy(state_backup.title, termconf_live.title, TERM_TITLE_LEN);
|
||||
memcpy(state_backup.btn, termconf_live.btn, sizeof(termconf_live.btn));
|
||||
memcpy(state_backup.btn_msg, termconf_live.btn_msg, sizeof(termconf_live.btn_msg));
|
||||
|
||||
// copy multiple fields at once
|
||||
memcpy(state_backup.btn1, termconf_live.btn1, sizeof(termconf_live.btn1)*TERM_BTN_COUNT);
|
||||
memcpy(state_backup.btn1_msg, termconf_live.bm1, sizeof(termconf_live.bm1)*TERM_BTN_COUNT);
|
||||
|
||||
memcpy(state_backup.tab_stops, scr.tab_stops, sizeof(scr.tab_stops));
|
||||
state_backup.vm0 = scr.vm0;
|
||||
state_backup.vm1 = scr.vm1;
|
||||
@@ -465,8 +645,11 @@ screen_swap_state(bool alternate)
|
||||
else {
|
||||
ansi_dbg("Unswap from alternate");
|
||||
memcpy(termconf_live.title, state_backup.title, TERM_TITLE_LEN);
|
||||
memcpy(termconf_live.btn, state_backup.btn, sizeof(termconf_live.btn));
|
||||
memcpy(termconf_live.btn_msg, state_backup.btn_msg, sizeof(termconf_live.btn_msg));
|
||||
|
||||
// copy multiple fields at once
|
||||
memcpy(termconf_live.btn1, state_backup.btn1, sizeof(termconf_live.btn1)*TERM_BTN_COUNT);
|
||||
memcpy(termconf_live.bm1, state_backup.btn1_msg, sizeof(termconf_live.bm1)*TERM_BTN_COUNT);
|
||||
|
||||
memcpy(scr.tab_stops, state_backup.tab_stops, sizeof(scr.tab_stops));
|
||||
scr.vm0 = state_backup.vm0;
|
||||
scr.vm1 = state_backup.vm1;
|
||||
@@ -989,8 +1172,8 @@ screen_resize(int rows, int cols)
|
||||
if (W == cols && H == rows) return; // Do nothing
|
||||
|
||||
NOTIFY_LOCK();
|
||||
W = cols;
|
||||
H = rows;
|
||||
W = (u32) cols;
|
||||
H = (u32) rows;
|
||||
screen_reset_on_resize();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS|TOPIC_CHANGE_CONTENT_ALL|TOPIC_CHANGE_CURSOR);
|
||||
}
|
||||
@@ -1012,7 +1195,28 @@ void ICACHE_FLASH_ATTR
|
||||
screen_set_button_text(int num, const char *text)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
strncpy(termconf_live.btn[num-1], text, TERM_BTN_LEN);
|
||||
if (num == 1) strncpy(termconf_live.btn1, text, TERM_BTN_LEN);
|
||||
else if (num == 2) strncpy(termconf_live.btn2, text, TERM_BTN_LEN);
|
||||
else if (num == 3) strncpy(termconf_live.btn3, text, TERM_BTN_LEN);
|
||||
else if (num == 4) strncpy(termconf_live.btn4, text, TERM_BTN_LEN);
|
||||
else if (num == 5) strncpy(termconf_live.btn5, text, TERM_BTN_LEN);
|
||||
NOTIFY_DONE(TOPIC_CHANGE_BUTTONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to set terminal button label
|
||||
* @param num - button number 1-5
|
||||
* @param str - button text
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_button_message(int num, const char *msg)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
if (num == 1) strncpy(termconf_live.bm1, msg, TERM_BTN_MSG_LEN);
|
||||
else if (num == 2) strncpy(termconf_live.bm2, msg, TERM_BTN_MSG_LEN);
|
||||
else if (num == 3) strncpy(termconf_live.bm3, msg, TERM_BTN_MSG_LEN);
|
||||
else if (num == 4) strncpy(termconf_live.bm4, msg, TERM_BTN_MSG_LEN);
|
||||
else if (num == 5) strncpy(termconf_live.bm5, msg, TERM_BTN_MSG_LEN);
|
||||
NOTIFY_DONE(TOPIC_CHANGE_BUTTONS);
|
||||
}
|
||||
|
||||
@@ -1121,7 +1325,7 @@ void ICACHE_FLASH_ATTR
|
||||
screen_cursor_shape(enum CursorShape shape)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
if (shape == CURSOR_DEFAULT) shape = termconf->cursor_shape;
|
||||
if (shape == CURSOR_DEFAULT) shape = (enum CursorShape) termconf->cursor_shape;
|
||||
termconf_live.cursor_shape = shape;
|
||||
NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS);
|
||||
}
|
||||
@@ -1356,7 +1560,7 @@ screen_back_index(int count)
|
||||
cursor.x = new_x;
|
||||
} else {
|
||||
cursor.x = 0;
|
||||
screen_insert_characters(-new_x);
|
||||
screen_insert_characters((unsigned int) -new_x);
|
||||
topics |= TOPIC_CHANGE_CONTENT_PART;
|
||||
}
|
||||
NOTIFY_DONE(topics);
|
||||
@@ -1548,7 +1752,7 @@ do_save_private_opt(int n, bool save)
|
||||
{
|
||||
ScreenNotifyTopics topics = TOPIC_INTERNAL;
|
||||
if (!save) NOTIFY_LOCK();
|
||||
#define SAVE_RESTORE(sf, of) do { if (save) sf=(of); else of=(sf); } while(0)
|
||||
#define SAVE_RESTORE(sf, of) do { if (save) (sf)=(of); else (of)=(sf); } while(0)
|
||||
switch (n) {
|
||||
case 1:
|
||||
SAVE_RESTORE(opt_backup.cursors_alt_mode, scr.cursors_alt_mode);
|
||||
@@ -2044,7 +2248,7 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, ScreenNotifyTopics topics,
|
||||
BEGIN_TOPIC(TOPIC_CHANGE_TITLE, TERM_TITLE_LEN+4+1)
|
||||
bufput_c(TOPICMARK_TITLE);
|
||||
|
||||
int len = (int) strlen(termconf_live.title);
|
||||
size_t len = strlen(termconf_live.title);
|
||||
if (len > 0) {
|
||||
memcpy(bb, termconf_live.title, len);
|
||||
bb += len;
|
||||
@@ -2059,20 +2263,21 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, ScreenNotifyTopics topics,
|
||||
bufput_utf8(TERM_BTN_COUNT);
|
||||
|
||||
for (int i = 0; i < TERM_BTN_COUNT; i++) {
|
||||
int len = (int) strlen(termconf_live.btn[i]);
|
||||
size_t len = strlen(TERM_BTN_N(&termconf_live, i));
|
||||
if (len > 0) {
|
||||
memcpy(bb, termconf_live.btn[i], len);
|
||||
memcpy(bb, TERM_BTN_N(&termconf_live, i), len);
|
||||
bb += len;
|
||||
remain -= len;
|
||||
}
|
||||
bufput_c('\x01');
|
||||
}
|
||||
|
||||
END_TOPIC
|
||||
|
||||
BEGIN_TOPIC(TOPIC_CHANGE_BACKDROP, TERM_BACKDROP_LEN+1+1)
|
||||
bufput_c(TOPICMARK_BACKDROP);
|
||||
|
||||
int len = (int) strlen(termconf_live.backdrop);
|
||||
size_t len = strlen(termconf_live.backdrop);
|
||||
if (len > 0) {
|
||||
memcpy(bb, termconf_live.backdrop, len);
|
||||
bb += len;
|
||||
|
||||
+54
-23
@@ -5,6 +5,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <esp8266.h>
|
||||
#include <httpd.h>
|
||||
#include "config_xmacros.h"
|
||||
|
||||
/**
|
||||
* This module handles the virtual screen and operations on it.
|
||||
@@ -78,30 +79,59 @@ enum CursorShape {
|
||||
#define TERMCONF_SIZE 400
|
||||
#define TERMCONF_VERSION 4
|
||||
|
||||
//....Type................Name..Suffix...............Deref..XGET.........Cast..XSET.........................NOTIFY................Allow
|
||||
// Deref is used to pass the field to xget. Cast is used to convert the &'d field to what xset wants (needed for static arrays)
|
||||
#define XTABLE_TERMCONF \
|
||||
X(u32, width, /**/, /**/, xget_dec, xset_u32, NULL, /**/, 1) \
|
||||
X(u32, height, /**/, /**/, xget_dec, xset_u32, NULL, /**/, 1) \
|
||||
X(u32, default_bg, /**/, /**/, xget_term_color, xset_term_color, NULL, /**/, 1) \
|
||||
X(u32, default_fg, /**/, /**/, xget_term_color, xset_term_color, NULL, /**/, 1) \
|
||||
X(char, title, [TERM_TITLE_LEN], /**/, xget_string, xset_string, TERM_TITLE_LEN, /**/, 1) \
|
||||
X(char, btn1, [TERM_BTN_LEN], /**/, xget_string, xset_string, TERM_BTN_LEN, /**/, 1) \
|
||||
X(char, btn2, [TERM_BTN_LEN], /**/, xget_string, xset_string, TERM_BTN_LEN, /**/, 1) \
|
||||
X(char, btn3, [TERM_BTN_LEN], /**/, xget_string, xset_string, TERM_BTN_LEN, /**/, 1) \
|
||||
X(char, btn4, [TERM_BTN_LEN], /**/, xget_string, xset_string, TERM_BTN_LEN, /**/, 1) \
|
||||
X(char, btn5, [TERM_BTN_LEN], /**/, xget_string, xset_string, TERM_BTN_LEN, /**/, 1) \
|
||||
X(u8, theme, /**/, /**/, xget_dec, xset_u8, NULL, /**/, 1) \
|
||||
X(u32, parser_tout_ms, /**/, /**/, xget_dec, xset_u32, NULL, /**/, 1) \
|
||||
X(u32, display_tout_ms, /**/, /**/, xget_dec, xset_u32, NULL, /**/, 1) \
|
||||
X(bool, fn_alt_mode, /**/, /**/, xget_bool, xset_bool, NULL, /**/, 1) \
|
||||
X(u8, config_version, /**/, /**/, xget_dec, xset_u8, NULL, /**/, 1) \
|
||||
X(u32, display_cooldown_ms, /**/, /**/, xget_dec, xset_u32, NULL, /**/, 1) \
|
||||
X(bool, loopback, /**/, /**/, xget_bool, xset_bool, NULL, /**/, 1) \
|
||||
X(bool, show_buttons, /**/, /**/, xget_bool, xset_bool, NULL, /**/, 1) \
|
||||
X(bool, show_config_links, /**/, /**/, xget_bool, xset_bool, NULL, /**/, 1) \
|
||||
X(char, bm1, [TERM_BTN_MSG_LEN], /**/, xget_term_bm, xset_term_bm, NULL, /**/, 1) \
|
||||
X(char, bm2, [TERM_BTN_MSG_LEN], /**/, xget_term_bm, xset_term_bm, NULL, /**/, 1) \
|
||||
X(char, bm3, [TERM_BTN_MSG_LEN], /**/, xget_term_bm, xset_term_bm, NULL, /**/, 1) \
|
||||
X(char, bm4, [TERM_BTN_MSG_LEN], /**/, xget_term_bm, xset_term_bm, NULL, /**/, 1) \
|
||||
X(char, bm5, [TERM_BTN_MSG_LEN], /**/, xget_term_bm, xset_term_bm, NULL, /**/, 1) \
|
||||
X(u32, cursor_shape, /**/, /**/, xget_dec, xset_term_cursorshape, NULL, /**/, 1) \
|
||||
X(bool, crlf_mode, /**/, /**/, xget_bool, xset_bool, NULL, /**/, 1) \
|
||||
X(bool, want_all_fn, /**/, /**/, xget_bool, xset_bool, NULL, /**/, 1) \
|
||||
X(bool, debugbar, /**/, /**/, xget_bool, xset_bool, NULL, /**/, 1) \
|
||||
X(bool, allow_decopt_12, /**/, /**/, xget_bool, xset_bool, NULL, /**/, 1) \
|
||||
X(bool, ascii_debug, /**/, /**/, xget_bool, xset_bool, NULL, /**/, 1) \
|
||||
X(char, backdrop, [TERM_BACKDROP_LEN], /**/, xget_string, xset_string, TERM_BACKDROP_LEN, /**/, 1)
|
||||
|
||||
#define TERM_BM_N(tc, n) ((tc)->bm1+(TERM_BTN_MSG_LEN*n))
|
||||
#define TERM_BTN_N(tc, n) ((tc)->btn1+(TERM_BTN_LEN*n))
|
||||
|
||||
/** Export color for config */
|
||||
void xget_term_color(char *buff, u32 value);
|
||||
/** Export button message as stirng for config */
|
||||
void xget_term_bm(char *buff, char *value);
|
||||
/** Set button message */
|
||||
enum xset_result xset_term_bm(const char *name, char *field, const char *buff, const void *arg);
|
||||
/** Set color */
|
||||
enum xset_result xset_term_color(const char *name, u32 *field, const char *buff, const void *arg);
|
||||
/** Set cursor shape */
|
||||
enum xset_result xset_term_cursorshape(const char *name, u32 *field, const char *buff, const void *arg);
|
||||
|
||||
typedef struct {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 default_bg; // 00-FFh - ANSI colors, (00:00:00-FF:FF:FF)+256 - True Color
|
||||
u32 default_fg;
|
||||
char title[TERM_TITLE_LEN];
|
||||
char btn[TERM_BTN_COUNT][TERM_BTN_LEN];
|
||||
u8 theme;
|
||||
u32 parser_tout_ms;
|
||||
u32 display_tout_ms;
|
||||
bool fn_alt_mode; // xterm compatibility mode (alternate codes for some FN keys)
|
||||
u8 config_version;
|
||||
u32 display_cooldown_ms;
|
||||
bool loopback;
|
||||
bool show_buttons;
|
||||
bool show_config_links;
|
||||
char btn_msg[TERM_BTN_COUNT][TERM_BTN_MSG_LEN];
|
||||
enum CursorShape cursor_shape;
|
||||
bool crlf_mode;
|
||||
bool want_all_fn;
|
||||
bool debugbar;
|
||||
bool allow_decopt_12;
|
||||
bool ascii_debug;
|
||||
char backdrop[TERM_BACKDROP_LEN];
|
||||
#define X XSTRUCT_FIELD
|
||||
XTABLE_TERMCONF
|
||||
#undef X
|
||||
} TerminalConfigBundle;
|
||||
|
||||
// Live config
|
||||
@@ -150,6 +180,7 @@ void screen_resize(int rows, int cols);
|
||||
void screen_set_title(const char *title);
|
||||
/** Set a button text */
|
||||
void screen_set_button_text(int num, const char *text);
|
||||
void screen_set_button_message(int num, const char *msg);
|
||||
/** Change backdrop */
|
||||
void screen_set_backdrop(const char *url);
|
||||
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ buf_pop(void *unused)
|
||||
|
||||
LOCAL void my_putc(char c)
|
||||
{
|
||||
UART_WriteCharCRLF(UART1, (u8) c, 10);
|
||||
UART_WriteCharCRLF(UART1, (u8) c, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+102
-2
@@ -6,12 +6,112 @@
|
||||
#include "persist.h"
|
||||
#include "uart_driver.h"
|
||||
#include "serial.h"
|
||||
#include "cgi_logging.h"
|
||||
|
||||
SystemConfigBundle * const sysconf = &persist.current.sysconf;
|
||||
|
||||
enum xset_result ICACHE_FLASH_ATTR
|
||||
xset_sys_baudrate(const char *name, u32 *field, const char *buff, const void *arg)
|
||||
{
|
||||
cgi_dbg("Setting %s = %s", name, buff);
|
||||
int baud = atoi(buff);
|
||||
if (baud == BIT_RATE_300 ||
|
||||
baud == BIT_RATE_600 ||
|
||||
baud == BIT_RATE_1200 ||
|
||||
baud == BIT_RATE_2400 ||
|
||||
baud == BIT_RATE_4800 ||
|
||||
baud == BIT_RATE_9600 ||
|
||||
baud == BIT_RATE_19200 ||
|
||||
baud == BIT_RATE_38400 ||
|
||||
baud == BIT_RATE_57600 ||
|
||||
baud == BIT_RATE_74880 ||
|
||||
baud == BIT_RATE_115200 ||
|
||||
baud == BIT_RATE_230400 ||
|
||||
baud == BIT_RATE_460800 ||
|
||||
baud == BIT_RATE_921600 ||
|
||||
baud == BIT_RATE_1843200 ||
|
||||
baud == BIT_RATE_3686400) {
|
||||
if (*field != baud) {
|
||||
*field = (u32) baud;
|
||||
return XSET_SET;
|
||||
}
|
||||
return XSET_UNCHANGED;
|
||||
} else {
|
||||
cgi_warn("Bad baud rate %s", buff);
|
||||
return XSET_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
enum xset_result ICACHE_FLASH_ATTR
|
||||
xset_sys_parity(const char *name, u8 *field, const char *buff, const void *arg)
|
||||
{
|
||||
cgi_dbg("Setting %s = %s", name, buff);
|
||||
int parity = atoi(buff);
|
||||
if (parity >= 0 && parity <= 2) {
|
||||
if (*field != parity) {
|
||||
*field = (UartParityMode) parity;
|
||||
return XSET_SET;
|
||||
}
|
||||
return XSET_UNCHANGED;
|
||||
} else {
|
||||
cgi_warn("Bad parity %s", buff);
|
||||
return XSET_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
enum xset_result ICACHE_FLASH_ATTR
|
||||
xset_sys_stopbits(const char *name, u8 *field, const char *buff, const void *arg)
|
||||
{
|
||||
cgi_dbg("Setting %s = %s", name, buff);
|
||||
int stopbits = atoi(buff);
|
||||
if (stopbits >= 1 && stopbits <= 3) {
|
||||
if (*field != stopbits) {
|
||||
*field = (UartParityMode) stopbits;
|
||||
return XSET_SET;
|
||||
}
|
||||
return XSET_UNCHANGED;
|
||||
} else {
|
||||
cgi_warn("Bad stopbits %s", buff);
|
||||
return XSET_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
enum xset_result ICACHE_FLASH_ATTR
|
||||
xset_sys_pwlock(const char *name, u8 *field, const char *buff, const void *arg)
|
||||
{
|
||||
cgi_dbg("Setting %s = %s", name, buff);
|
||||
|
||||
int pwlock = atoi(buff);
|
||||
if (pwlock >= 0 && pwlock < PWLOCK_MAX) {
|
||||
if (*field != pwlock) {
|
||||
*field = (enum pwlock) pwlock;
|
||||
return XSET_SET;
|
||||
}
|
||||
return XSET_UNCHANGED;
|
||||
} else {
|
||||
cgi_warn("Bad pwlock %s", buff);
|
||||
return XSET_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
enum xset_result ICACHE_FLASH_ATTR
|
||||
xset_sys_accesspw(const char *name, uchar *field, const char *buff, const void *arg)
|
||||
{
|
||||
// Do not overwrite pw if empty
|
||||
if (strlen(buff) == 0) return XSET_UNCHANGED;
|
||||
return xset_ustring(name, field, buff, arg);
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
sysconf_apply_settings(void)
|
||||
{
|
||||
// char buff[64];
|
||||
//#define XSTRUCT sysconf
|
||||
//#define X XDUMP_FIELD
|
||||
// XTABLE_SYSCONF
|
||||
//#undef X
|
||||
|
||||
bool changed = false;
|
||||
if (sysconf->config_version < 1) {
|
||||
dbg("Upgrading syscfg to v 1");
|
||||
@@ -40,7 +140,7 @@ sysconf_restore_defaults(void)
|
||||
sysconf->config_version = SYSCONF_VERSION;
|
||||
sysconf->access_pw[0] = 0;
|
||||
sysconf->pwlock = PWLOCK_NONE;
|
||||
strcpy(sysconf->access_pw, DEF_ACCESS_PW);
|
||||
strcpy(sysconf->access_name, DEF_ACCESS_NAME);
|
||||
strcpy((char *)sysconf->access_pw, DEF_ACCESS_PW);
|
||||
strcpy((char *)sysconf->access_name, DEF_ACCESS_NAME);
|
||||
sysconf->overclock = false;
|
||||
}
|
||||
|
||||
+35
-8
@@ -6,6 +6,7 @@
|
||||
#define ESP_VT100_FIRMWARE_SYSCFG_H
|
||||
|
||||
#include <esp8266.h>
|
||||
#include "config_xmacros.h"
|
||||
|
||||
// Size designed for the wifi config structure
|
||||
// Must be constant to avoid corrupting user config after upgrade
|
||||
@@ -24,15 +25,35 @@ enum pwlock {
|
||||
PWLOCK_MAX = 5,
|
||||
};
|
||||
|
||||
//....Type................Name..Suffix...............Deref..XGET............XSET.........................NOTIFY....Allow
|
||||
// Deref is used to pass the field to xget. Cast is used to convert the &'d field to what xset wants (needed for static arrays)
|
||||
#define XTABLE_SYSCONF \
|
||||
X(u32, uart_baudrate, /**/, /**/, xget_dec, xset_sys_baudrate, NULL, uart_changed=true, 1) \
|
||||
X(u8, uart_parity, /**/, /**/, xget_dec, xset_sys_parity, NULL, uart_changed=true, 1) \
|
||||
X(u8, uart_stopbits, /**/, /**/, xget_dec, xset_sys_stopbits, NULL, uart_changed=true, 1) \
|
||||
\
|
||||
X(u8, config_version, /**/, /**/, xget_dec, xset_u8, NULL, /**/, 1) \
|
||||
\
|
||||
X(u8, pwlock, /**/, /**/, xget_dec, xset_sys_pwlock, NULL, /**/, admin|tpl) \
|
||||
X(uchar, access_pw, [64], /**/, xget_ustring, xset_sys_accesspw, NULL, /**/, admin) \
|
||||
X(uchar, access_name, [32], /**/, xget_ustring, xset_ustring, NULL, /**/, admin|tpl) \
|
||||
\
|
||||
X(bool, overclock, /**/, /**/, xget_bool, xset_bool, NULL, /**/, 1) \
|
||||
|
||||
|
||||
typedef struct {
|
||||
u32 uart_baudrate;
|
||||
u8 uart_parity;
|
||||
u8 uart_stopbits;
|
||||
u8 config_version;
|
||||
enum pwlock pwlock : 8; // page access lock
|
||||
char access_pw[64]; // access password
|
||||
char access_name[32]; // access name
|
||||
bool overclock;
|
||||
#define X XSTRUCT_FIELD
|
||||
XTABLE_SYSCONF
|
||||
#undef X
|
||||
|
||||
// u32 uart_baudrate;
|
||||
// u8 uart_parity;
|
||||
// u8 uart_stopbits;
|
||||
// u8 config_version;
|
||||
// enum pwlock pwlock : 8; // page access lock
|
||||
// char access_pw[64]; // access password
|
||||
// char access_name[32]; // access name
|
||||
// bool overclock;
|
||||
} SystemConfigBundle;
|
||||
|
||||
extern SystemConfigBundle * const sysconf;
|
||||
@@ -41,4 +62,10 @@ void sysconf_apply_settings(void);
|
||||
|
||||
void sysconf_restore_defaults(void);
|
||||
|
||||
enum xset_result xset_sys_baudrate(const char *name, u32 *field, const char *buff, const void *arg);
|
||||
enum xset_result xset_sys_parity(const char *name, u8 *field, const char *buff, const void *arg);
|
||||
enum xset_result xset_sys_stopbits(const char *name, u8 *field, const char *buff, const void *arg);
|
||||
enum xset_result xset_sys_pwlock(const char *name, u8 *field, const char *buff, const void *arg);
|
||||
enum xset_result xset_sys_accesspw(const char *name, uchar *field, const char *buff, const void *arg);
|
||||
|
||||
#endif //ESP_VT100_FIRMWARE_SYSCFG_H
|
||||
|
||||
+171
-22
@@ -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, uchar *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, uchar *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;
|
||||
}
|
||||
@@ -164,6 +292,21 @@ configure_ap(void)
|
||||
}
|
||||
}
|
||||
|
||||
static ETSTimer tim;
|
||||
|
||||
static void ICACHE_FLASH_ATTR
|
||||
wifimgr_apply_settings_later_Cb(void *unused)
|
||||
{
|
||||
wifimgr_apply_settings();
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
wifimgr_apply_settings_later(uint32_t delay_ms)
|
||||
{
|
||||
wifi_info("[WiFi] Scheduling settings apply in %d ms", delay_ms);
|
||||
TIMER_START(&tim, wifimgr_apply_settings_later_Cb, delay_ms, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the WiFi event listener, cycle WiFi, apply settings
|
||||
*/
|
||||
@@ -172,6 +315,12 @@ wifimgr_apply_settings(void)
|
||||
{
|
||||
wifi_info("[WiFi] Initializing...");
|
||||
|
||||
// char buff[64];
|
||||
//#define XSTRUCT wificonf
|
||||
//#define X XDUMP_FIELD
|
||||
// XTABLE_WIFICONF
|
||||
//#undef X
|
||||
|
||||
// !!! Update to current version !!!
|
||||
|
||||
// Force wifi cycle
|
||||
@@ -190,7 +339,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
|
||||
|
||||
+50
-19
@@ -8,6 +8,7 @@
|
||||
#define ESP_VT100_FIRMWARE_WIFI_MANAGER_H
|
||||
|
||||
#include <esp8266.h>
|
||||
#include "config_xmacros.h"
|
||||
#include "cgi_wifi.h"
|
||||
|
||||
#define SSID_LEN 32
|
||||
@@ -19,6 +20,44 @@
|
||||
|
||||
#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...........XSET.........................NOTIFY................Allow
|
||||
// Deref is used to pass the field to xget. Cast is used to convert the &'d field to what xset wants (needed for static arrays)
|
||||
#define XTABLE_WIFICONF \
|
||||
X(u8, opmode, /**/, /**/, xget_dec, xset_wifi_opmode, NULL, /**/, 1) \
|
||||
\
|
||||
X(u8, tpw, /**/, /**/, xget_dec, xset_wifi_tpw, NULL, wifimgr_notify_ap(), 1) \
|
||||
X(u8, ap_channel, /**/, /**/, xget_dec, xset_wifi_ap_channel, NULL, wifimgr_notify_ap(), 1) \
|
||||
X(uchar, ap_ssid, [SSID_LEN], /**/, xget_ustring, xset_wifi_ssid, 1, wifimgr_notify_ap(), 1) \
|
||||
X(uchar, ap_password, [PASSWORD_LEN], /**/, xget_ustring, xset_wifi_pwd, NULL, wifimgr_notify_ap(), 1) \
|
||||
X(bool, ap_hidden, /**/, /**/, xget_bool, xset_bool, NULL, wifimgr_notify_ap(), 1) \
|
||||
\
|
||||
X(u16, ap_dhcp_time, /**/, /**/, xget_dec, xset_wifi_lease_time, NULL, wifimgr_notify_ap(), 1) \
|
||||
X(u32, unused1, /**/, /**/, xget_dummy, xset_dummy, NULL, /**/, 0) \
|
||||
X(struct ip_addr, ap_dhcp_start, /**/, &, xget_ip, xset_ip, NULL, wifimgr_notify_ap(), 1) \
|
||||
X(struct ip_addr, ap_dhcp_end, /**/, &, xget_ip, xset_ip, NULL, wifimgr_notify_ap(), 1) \
|
||||
\
|
||||
X(struct ip_addr, ap_addr_ip, /**/, &, xget_ip, xset_ip, NULL, wifimgr_notify_ap(), 1) \
|
||||
X(struct ip_addr, ap_addr_mask, /**/, &, xget_ip, xset_ip, NULL, wifimgr_notify_ap(), 1) \
|
||||
\
|
||||
\
|
||||
X(u32, unused2, /**/, /**/, xget_dummy, xset_dummy, NULL, /**/, 0) \
|
||||
X(uchar, sta_ssid, [SSID_LEN], /**/, xget_ustring, xset_wifi_ssid, 0, wifimgr_notify_sta(), 1) \
|
||||
X(uchar, sta_password, [PASSWORD_LEN], /**/, xget_ustring, xset_wifi_pwd, NULL, wifimgr_notify_sta(), 1) \
|
||||
X(bool, sta_dhcp_enable, /**/, /**/, xget_bool, xset_bool, NULL, wifimgr_notify_sta(), 1) \
|
||||
\
|
||||
X(struct ip_addr, sta_addr_ip, /**/, &, xget_ip, xset_ip, NULL, wifimgr_notify_sta(), 1) \
|
||||
X(struct ip_addr, sta_addr_mask, /**/, &, xget_ip, xset_ip, NULL, wifimgr_notify_sta(), 1) \
|
||||
X(struct ip_addr, sta_addr_gw, /**/, &, xget_ip, xset_ip, NULL, wifimgr_notify_sta(), 1) \
|
||||
\
|
||||
\
|
||||
X(u8, config_version, /**/, /**/, xget_dec, xset_u8, NULL, /**/, 1)
|
||||
|
||||
// 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 +65,9 @@
|
||||
* 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 XSTRUCT_FIELD
|
||||
XTABLE_WIFICONF
|
||||
#undef X
|
||||
} WiFiConfigBundle;
|
||||
|
||||
typedef struct {
|
||||
@@ -59,9 +82,17 @@ extern WiFiConfigBundle * const wificonf;
|
||||
void wifimgr_restore_defaults(void);
|
||||
|
||||
void wifimgr_apply_settings(void);
|
||||
void wifimgr_apply_settings_later(uint32_t delay_ms);
|
||||
|
||||
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, uchar *field, const char *buff, const void *arg);
|
||||
enum xset_result xset_wifi_pwd(const char *name, uchar *field, const char *buff, const void *arg);
|
||||
|
||||
#if DEBUG_WIFI
|
||||
#define wifi_warn warn
|
||||
#define wifi_dbg dbg
|
||||
|
||||
Reference in New Issue
Block a user