From 2f4cd08c6030f61784af93fcca4dccc997da3fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 23 Oct 2017 22:43:04 +0200 Subject: [PATCH] import now fully working --- esphttpdconfig.mk.example | 2 +- front-end | 2 +- user/cgi_persist.c | 198 +++++++++++++++++++++++++++++++++++--- user/config_xmacros.h | 10 ++ user/screen.c | 6 +- user/serial.c | 2 +- user/wifimgr.c | 15 +++ user/wifimgr.h | 1 + 8 files changed, 216 insertions(+), 20 deletions(-) diff --git a/esphttpdconfig.mk.example b/esphttpdconfig.mk.example index d6f0315..97c8999 100644 --- a/esphttpdconfig.mk.example +++ b/esphttpdconfig.mk.example @@ -40,7 +40,7 @@ ESP_SPI_FLASH_SIZE_K = 1024 GLOBAL_CFLAGS = \ -DASYNC_LOG=1 \ - -DDEBUG_INI=0 \ + -DDEBUG_INI=1 \ -DDEBUG_D2D=0 \ -DDEBUG_ROUTER=0 \ -DDEBUG_CAPTDNS=0 \ diff --git a/front-end b/front-end index 8327ff0..a96b522 160000 --- a/front-end +++ b/front-end @@ -1 +1 @@ -Subproject commit 8327ff010893935c0c517c729727464f66badd89 +Subproject commit a96b522ca899c687d70b9ad92f708cd416b8d460 diff --git a/user/cgi_persist.c b/user/cgi_persist.c index 0b6b9dc..46393ad 100644 --- a/user/cgi_persist.c +++ b/user/cgi_persist.c @@ -13,6 +13,7 @@ Cgi/template routines for configuring non-wifi settings #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) @@ -79,7 +80,7 @@ cgiPersistRestoreHard(HttpdConnData *connData) return HTTPD_CGI_DONE; } - +// -------------- Export -------------- #define httpdSend_orDie(conn, data, len) do { if (!httpdSend((conn), (data), (len))) return false; } while (0) @@ -217,17 +218,154 @@ cgiPersistExport(HttpdConnData *connData) } -void iniCb(const char *section, const char *key, const char *value, void *userData) +// -------------- 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) { - dbg(">>> SET: [%s] %s = %s", section, key, value); + 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; + } +} -httpd_cgi_state ICACHE_FLASH_ATTR +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; } @@ -240,27 +378,59 @@ postRecvHdl(HttpdConnData *connData, char *data, int len) 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; } - httpdStartResponse(connData, 200); - httpdHeader(connData, "Content-Type", "text/plain"); - httpdEndHeaders(connData); - char *start = strstr(connData->post->buff, "\r\n\r\n"); if (start == NULL) { error("Malformed attachment POST!"); - goto end; + + httpdStartResponse(connData, 400); + httpdHeader(connData, "Content-Type", "text/plain"); + httpdEndHeaders(connData); + httpdSend(connData, "Bad format.", -1); + return HTTPD_CGI_DONE; } - ini_parse_begin(iniCb, NULL); - ini_parse(start, (size_t) connData->post->buffLen - (start - connData->post->buff)); + 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; -end: - // TODO redirect - return HTTPD_CGI_DONE; + // continues in recvHdl + return HTTPD_CGI_MORE; } diff --git a/user/config_xmacros.h b/user/config_xmacros.h index 09c639a..3c26f06 100644 --- a/user/config_xmacros.h +++ b/user/config_xmacros.h @@ -84,6 +84,16 @@ enum xset_result xset_ustring(const char *name, u8 *field, const char *buff, con 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); diff --git a/user/screen.c b/user/screen.c index 7a9f54f..1853c41 100644 --- a/user/screen.c +++ b/user/screen.c @@ -250,11 +250,11 @@ xset_term_bm(const char *name, char *field, const char *buff, const void *arg) } if (char_i >= TERM_BTN_MSG_LEN-1) { - cgi_warn("Too long! %d", acu); + cgi_warn("Too long! %d", char_i); return XSET_FAIL; } - cgi_dbg("acu %d", acu); +// cgi_dbg("acu %d", acu); buff_bm[char_i++] = (char)acu; // prepare for next char @@ -277,7 +277,7 @@ xset_term_bm(const char *name, char *field, const char *buff, const void *arg) buff_bm[char_i++] = (char)acu; } buff_bm[char_i] = 0; - cgi_dbg("%s, chari = %d", buff_bm, char_i); +// cgi_dbg("%s, chari = %d", buff_bm, char_i); if (!streq(field, buff_bm)) { strncpy(field, buff_bm, TERM_BTN_MSG_LEN); diff --git a/user/serial.c b/user/serial.c index 9c9edce..d7382a2 100644 --- a/user/serial.c +++ b/user/serial.c @@ -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); } /** diff --git a/user/wifimgr.c b/user/wifimgr.c index efb1cd2..7083b3f 100644 --- a/user/wifimgr.c +++ b/user/wifimgr.c @@ -292,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 */ diff --git a/user/wifimgr.h b/user/wifimgr.h index 07d3d61..5637b51 100644 --- a/user/wifimgr.h +++ b/user/wifimgr.h @@ -82,6 +82,7 @@ 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);