From 62888d447345d0206dbcd8f71452fa377204b33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Wed, 13 Sep 2017 01:33:10 +0200 Subject: [PATCH 01/29] update frontend to use branch master --- front-end | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front-end b/front-end index b2174fc..891a446 160000 --- a/front-end +++ b/front-end @@ -1 +1 @@ -Subproject commit b2174fc528d2766eb82d1e828d70bb432d4ea949 +Subproject commit 891a44624eca83bd2c8d2352f5624d72eba863b0 From 184c772b5770ed096fe0a58859b9e896617e1dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Wed, 13 Sep 2017 02:30:34 +0200 Subject: [PATCH 02/29] update frontend ref --- front-end | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front-end b/front-end index 891a446..72279bf 160000 --- a/front-end +++ b/front-end @@ -1 +1 @@ -Subproject commit 891a44624eca83bd2c8d2352f5624d72eba863b0 +Subproject commit 72279bf0355af1ba56ff3950a085f38d9adb8506 From 92a454a2cf04c25a5fab60097cf80c77fac3b55c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 16 Sep 2017 01:46:41 +0200 Subject: [PATCH 03/29] renamed input debug log funcs to imp_ to avoid build collision if DEBUG_WS is enabled also --- esphttpdconfig.mk | 2 +- libesphttpd | 2 +- user/cgi_sockets.c | 8 ++++---- user/cgi_sockets.h | 12 ++++++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/esphttpdconfig.mk b/esphttpdconfig.mk index a46fa85..cd2a8ad 100644 --- a/esphttpdconfig.mk +++ b/esphttpdconfig.mk @@ -51,7 +51,7 @@ GLOBAL_CFLAGS = \ -DDEBUG_CGI=0 \ -DDEBUG_WIFI=0 \ -DDEBUG_WS=0 \ - -DDEBUG_ANSI=1 \ + -DDEBUG_ANSI=0 \ -DDEBUG_ANSI_NOIMPL=1 \ -DDEBUG_INPUT=0 \ -DDEBUG_HEAP=1 \ diff --git a/libesphttpd b/libesphttpd index 3479ab3..58c81c0 160000 --- a/libesphttpd +++ b/libesphttpd @@ -1 +1 @@ -Subproject commit 3479ab3efcb4581669370cde6a607f936ff5515a +Subproject commit 58c81c0dfe8e15888408886e168ed739aa8f311d diff --git a/user/cgi_sockets.c b/user/cgi_sockets.c index 6fcf87a..2c58514 100644 --- a/user/cgi_sockets.c +++ b/user/cgi_sockets.c @@ -235,7 +235,7 @@ void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int flags) // Add terminator if missing (seems to randomly happen) data[len] = 0; - ws_dbg("Sock RX str: %s, len %d", data, len); + inp_dbg("Sock RX str: %s, len %d", data, len); int y, x, m, b; u8 btnNum; @@ -271,7 +271,7 @@ void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int flags) case 'i': // requests initial load - ws_dbg("Client requests initial load"); + inp_dbg("Client requests initial load"); notifyContentTimCb(ws); break; @@ -290,7 +290,7 @@ void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int flags) break; default: - ws_warn("Bad command."); + inp_warn("Bad command."); } } @@ -307,7 +307,7 @@ void ICACHE_FLASH_ATTR heartbeatTimCb(void *unused) /** Socket connected for updates */ void ICACHE_FLASH_ATTR updateSockConnect(Websock *ws) { - ws_info("Socket connected to "URL_WS_UPDATE); + inp_info("Socket connected to "URL_WS_UPDATE); ws->recvCb = updateSockRx; TIMER_START(&heartbeatTim, heartbeatTimCb, HB_TIME, 1); diff --git a/user/cgi_sockets.h b/user/cgi_sockets.h index 3d3a711..2010cfb 100644 --- a/user/cgi_sockets.h +++ b/user/cgi_sockets.h @@ -17,13 +17,13 @@ void notify_growl(char *msg); // defined in the makefile #if DEBUG_INPUT -#define ws_warn warn -#define ws_dbg dbg -#define ws_info info +#define inp_warn warn +#define inp_dbg dbg +#define inp_info info #else -#define ws_warn(...) -#define ws_dbg(...) -#define ws_info(...) +#define inp_warn(...) +#define inp_dbg(...) +#define inp_info(...) #endif #endif //CGI_SOCKETS_H From 82fd9e5ad189dcba263b441cc2b980aa5c315ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 17 Sep 2017 19:10:16 +0200 Subject: [PATCH 04/29] raise utf8 cache to max of 160 characters, re-enable buttons by default --- user/screen.h | 6 +++--- user/utf8.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/user/screen.h b/user/screen.h index 30a1833..c970927 100644 --- a/user/screen.h +++ b/user/screen.h @@ -65,11 +65,11 @@ enum CursorShape { CURSOR_BAR = 6, }; -#define SCR_DEF_SHOW_BUTTONS 0 +#define SCR_DEF_SHOW_BUTTONS 1 #define SCR_DEF_SHOW_MENU 1 #define SCR_DEF_CURSOR_SHAPE CURSOR_BLOCK_BL -#define SCR_DEF_CRLF 0 -#define SCR_DEF_ALLFN 0 +#define SCR_DEF_CRLF 0 // enter sends CRLF +#define SCR_DEF_ALLFN 0 // capture F5 etc // --- Persistent Settings --- #define CURSOR_BLINKS(shape) ((shape)==CURSOR_BLOCK_BL||(shape)==CURSOR_UNDERLINE_BL||(shape)==CURSOR_BAR_BL) diff --git a/user/utf8.h b/user/utf8.h index d0c0e57..81f9372 100644 --- a/user/utf8.h +++ b/user/utf8.h @@ -8,7 +8,7 @@ #include // 160 is maximum possible -#define UNICODE_CACHE_SIZE 100 +#define UNICODE_CACHE_SIZE 160 typedef u8 UnicodeCacheRef; #define IS_UNICODE_CACHE_REF(c) ((c) < 32 || (c) >= 127) From ac56b1dc61d39fa0b5d4ef928e13e2758757809c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 17 Sep 2017 19:14:18 +0200 Subject: [PATCH 05/29] added timezone to bootlog --- CMakeLists.txt | 1 + Makefile | 1 + user/user_main.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c2e420d..c3c159d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,6 +163,7 @@ add_definitions( -DGIT_HASH="blabla" -DDEBUG_HEAP=1 -DDEBUG_MALLOC=1 + -D__TIMEZONE__="UTC" -DESPFS_HEATSHRINK) add_executable(ESPTerm ${SOURCE_FILES}) diff --git a/Makefile b/Makefile index 7c2fc02..a0ecbd3 100644 --- a/Makefile +++ b/Makefile @@ -70,6 +70,7 @@ CFLAGS = -Os -std=gnu99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inli CFLAGS += -DGIT_HASH_BACKEND='"$(shell git rev-parse --short HEAD)"' CFLAGS += -DGIT_HASH_FRONTEND='"$(shell cd front-end && git rev-parse --short HEAD)"' CFLAGS += -DADMIN_PASSWORD=$(ADMIN_PASSWORD) +CFLAGS += -D__TIMEZONE__='"$(shell date +%Z)"' ifdef GLOBAL_CFLAGS CFLAGS += $(GLOBAL_CFLAGS) diff --git a/user/user_main.c b/user/user_main.c index 5cdb3e0..e56f597 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -99,7 +99,7 @@ void ICACHE_FLASH_ATTR user_init(void) banner_info("Firmware (c) Ondrej Hruska, 2017"); banner_info(TERMINAL_GITHUB_REPO); banner_info(""); - banner_info("Version "FIRMWARE_VERSION", built " __DATE__ " at " __TIME__); + banner_info("Version "FIRMWARE_VERSION", built " __DATE__ " at " __TIME__ " " __TIMEZONE__); printf("\r\n"); ioInit(); From 471aa95c341943e893d2e939c6fddccf407c0d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 17 Sep 2017 19:18:56 +0200 Subject: [PATCH 06/29] add timezone to the about page --- CMakeLists.txt | 2 ++ user/cgi_main.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c3c159d..ea9d6ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,6 +160,8 @@ add_definitions( -DICACHE_RODATA_ATTR= -DFLAG_GZIP=2 -DADMIN_PASSWORD="asdf" + -DGIT_HASH_BACKEND="asdf" + -DGIT_HASH_FRONTEND="asdf" -DGIT_HASH="blabla" -DDEBUG_HEAP=1 -DDEBUG_MALLOC=1 diff --git a/user/cgi_main.c b/user/cgi_main.c index bb8bbfb..377666c 100644 --- a/user/cgi_main.c +++ b/user/cgi_main.c @@ -54,7 +54,7 @@ tplAbout(HttpdConnData *connData, char *token, void **arg) tplSend(connData, __DATE__, -1); } else if (streq(token, "time")) { - tplSend(connData, __TIME__, -1); + tplSend(connData, __TIME__" "__TIMEZONE__, -1); } else if (streq(token, "vers_httpd")) { tplSend(connData, httpdGetVersion(), -1); From 079b522540e93d6ff8740b8d3770d2694b62c707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 17 Sep 2017 20:18:57 +0200 Subject: [PATCH 07/29] implemented focus tracking reports --- build_parser.sh | 3 +++ user/ansi_parser.c | 4 ++-- user/cgi_sockets.c | 43 ++++++++++++++++++++++++++++++++++++++----- user/user_main.c | 2 -- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/build_parser.sh b/build_parser.sh index 3f2417a..ebcbdc2 100755 --- a/build_parser.sh +++ b/build_parser.sh @@ -3,3 +3,6 @@ echo "-- Building parser from Ragel source --" ragel -L -G0 user/ansi_parser.rl -o user/ansi_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 diff --git a/user/ansi_parser.c b/user/ansi_parser.c index 3f53c87..7b01ded 100644 --- a/user/ansi_parser.c +++ b/user/ansi_parser.c @@ -9,7 +9,7 @@ /* Ragel constants block */ /* #line 12 "user/ansi_parser.c" */ -static const char _ansi_actions[] = { +static const char _ansi_actions[] ESP_CONST_DATA = { 0, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, @@ -17,7 +17,7 @@ static const char _ansi_actions[] = { 15 }; -static const char _ansi_eof_actions[] = { +static const char _ansi_eof_actions[] ESP_CONST_DATA = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }; diff --git a/user/cgi_sockets.c b/user/cgi_sockets.c index 2c58514..f3adcb8 100644 --- a/user/cgi_sockets.c +++ b/user/cgi_sockets.c @@ -8,7 +8,6 @@ #include "ansi_parser.h" #include "jstring.h" #include "uart_driver.h" -#include "cgi_logging.h" // Heartbeat interval in ms #define HB_TIME 1000 @@ -17,9 +16,12 @@ // Must be less than httpd sendbuf #define SOCK_BUF_LEN 2000 +// flags for screen update timeouts volatile bool notify_available = true; volatile bool notify_cooldown = false; +/** True if we sent XOFF to browser to stop uploading, + * and we have to tell it we're ready again */ volatile bool browser_wants_xon = false; static ETSTimer notifyContentTim; @@ -27,6 +29,8 @@ static ETSTimer notifyLabelsTim; static ETSTimer notifyCooldownTim; static ETSTimer heartbeatTim; +volatile int active_clients = 0; + // we're trying to do a kind of mutex here, without the actual primitives // this might glitch, very rarely. // it's recommended to put some delay between setting labels and updating the screen. @@ -115,6 +119,8 @@ notifyLabelsTimCb(void *arg) void ICACHE_FLASH_ATTR send_beep(void) { + if (active_clients == 0) return; + // here's some potential for a race error with the other broadcast functions :C cgiWebsockBroadcast(URL_WS_UPDATE, "B", 1, 0); } @@ -124,6 +130,8 @@ send_beep(void) void ICACHE_FLASH_ATTR notify_growl(char *msg) { + if (active_clients == 0) return; + // TODO via timer... // here's some potential for a race error with the other broadcast functions :C cgiWebsockBroadcast(URL_WS_UPDATE, msg, (int) strlen(msg), 0); @@ -137,8 +145,9 @@ notify_growl(char *msg) */ void ICACHE_FLASH_ATTR screen_notifyChange(ScreenNotifyChangeTopic topic) { - // this is not the most ideal/cleanest implementation - // PRs are welcome for a nicer update "queue" solution + if (active_clients == 0) return; + + // this is probably not needed here - ensure timeout is not 0 if (termconf->display_tout_ms == 0) termconf->display_tout_ms = SCR_DEF_DISPLAY_TOUT_MS; // NOTE: the timers are restarted if already running @@ -297,20 +306,44 @@ void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int flags) /** Send a heartbeat msg */ void ICACHE_FLASH_ATTR heartbeatTimCb(void *unused) { - if (notify_available) { + if (notify_available && active_clients > 0) { // Heartbeat packet - indicate we're still connected // JS reloads the page if heartbeat is lost for a couple seconds cgiWebsockBroadcast(URL_WS_UPDATE, ".", 1, 0); } } +void ICACHE_FLASH_ATTR closeSockCb(Websock *ws) +{ + active_clients--; + if (active_clients <= 0) { + active_clients = 0; + + if (mouse_tracking.focus_tracking) { + UART_SendAsync("\x1b[O", 3); + } + + // stop the timer + os_timer_disarm(&heartbeatTim); + } +} + /** Socket connected for updates */ void ICACHE_FLASH_ATTR updateSockConnect(Websock *ws) { inp_info("Socket connected to "URL_WS_UPDATE); ws->recvCb = updateSockRx; + ws->closeCb = closeSockCb; + + if (active_clients == 0) { + if (mouse_tracking.focus_tracking) { + UART_SendAsync("\x1b[I", 3); + } + + TIMER_START(&heartbeatTim, heartbeatTimCb, HB_TIME, 1); + } - TIMER_START(&heartbeatTim, heartbeatTimCb, HB_TIME, 1); + active_clients++; } ETSTimer xonTim; diff --git a/user/user_main.c b/user/user_main.c index e56f597..7b9a98f 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -79,7 +79,6 @@ static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg) // Deferred init static void user_start(void *unused); -static void user_start2(void *unused); static ETSTimer userStartTimer; static ETSTimer prHeapTimer; @@ -121,7 +120,6 @@ void ICACHE_FLASH_ATTR user_init(void) TIMER_START(&userStartTimer, user_start, 10, 0); } - static void ICACHE_FLASH_ATTR user_start(void *unused) { // Load and apply stored settings, or defaults if stored settings are invalid From 781cf8825b8040eb604918549cd837b12ebdd770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 18 Sep 2017 01:58:15 +0200 Subject: [PATCH 08/29] remove theme max num chekc to allow adding themes purely by front-end --- user/cgi_term_cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user/cgi_term_cfg.c b/user/cgi_term_cfg.c index b902844..76b8bcc 100644 --- a/user/cgi_term_cfg.c +++ b/user/cgi_term_cfg.c @@ -173,7 +173,7 @@ cgiTermCfgSetParams(HttpdConnData *connData) if (GET_ARG("theme")) { cgi_dbg("Screen color theme: %s", buff); n = atoi(buff); - if (n >= 0 && n <= 5) { // ALWAYS ADJUST WHEN ADDING NEW THEME! + if (n >= 0) { termconf->theme = (u8) n; // this can't be notified, page must reload. } else { From 3bfd51061efa5504219905e35c9d2be881ba3bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Tue, 19 Sep 2017 01:44:52 +0200 Subject: [PATCH 09/29] added browser support list --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 9dc6c26..60eb857 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,26 @@ emulator backend that runs on the ESP8266. The web version will be updated to ma after each minor release (and sometimes in between for testing; the version currently being show-cased can be read on the About page of the demo). +### Browser support + +Use the above linked online demo to verify compatibility with your browser. + +To our knowledge, ESPTerm **works with**: +- Google Chrome (desktop, mobile) +- Firefox (desktop, mobile not tested) +- Safari (desktop, mobile) +- Chromium +- Opera +- Brave +- Konqueror + +It **does not work with**: +- Microsoft Edge - runs, but is extremely laggy +- Internet Explorer (any version) - crashes, missing JS features +- Opera Mini - crashes, missing JS and CSS features +- Blackberry browser - not tested, but unlikely +- Old Android Browser (before 4.4?) - not tested, likely missing JS features + ## Main features - **Almost complete VT102 emulation** with some extras from Xterm, eg. From 43241c26795bdcf79fd9fa3e89d914893cee5139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 22 Sep 2017 00:22:46 +0200 Subject: [PATCH 10/29] admin pw now lives in a separate config block. BREAKING CHANGE! will wipe old settings :( --- CMakeLists.txt | 1 + esphttpdconfig.mk | 3 ++- user/cgi_persist.c | 4 +--- user/persist.c | 32 +++++++++++++++++++++++++------- user/persist.h | 17 ++++++++++++++--- user/serial.c | 9 ++++----- 6 files changed, 47 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ea9d6ac..12dea35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,7 @@ include_directories(esp_iot_sdk_v1.5.2/include) add_definitions( -D__ets__ -DICACHE_FLASH + -DDEBUG_LOGBUF_SIZE=2048 -DUSE_OPTIMIZE_PRINTF=1 -DHTTPD_MAX_CONNECTIONS=5 -DHTTPD_STACKSIZE=1000 diff --git a/esphttpdconfig.mk b/esphttpdconfig.mk index cd2a8ad..d9b9e46 100644 --- a/esphttpdconfig.mk +++ b/esphttpdconfig.mk @@ -46,7 +46,7 @@ GLOBAL_CFLAGS = \ -DDEBUG_CAPTDNS=0 \ -DDEBUG_HTTP=0 \ -DDEBUG_ESPFS=0 \ - -DDEBUG_PERSIST=0 \ + -DDEBUG_PERSIST=1 \ -DDEBUG_UTFCACHE=0 \ -DDEBUG_CGI=0 \ -DDEBUG_WIFI=0 \ @@ -59,5 +59,6 @@ GLOBAL_CFLAGS = \ -DHTTPD_MAX_BACKLOG_SIZE=8192 \ -DHTTPD_MAX_HEAD_LEN=1024 \ -DHTTPD_MAX_POST_LEN=512 \ + -DDEBUG_LOGBUF_SIZE=2048 \ -mforce-l32 \ -DUSE_OPTIMIZE_PRINTF=1 diff --git a/user/cgi_persist.c b/user/cgi_persist.c index 4828b8a..61dee19 100644 --- a/user/cgi_persist.c +++ b/user/cgi_persist.c @@ -13,9 +13,7 @@ Cgi/template routines for configuring non-wifi settings static bool ICACHE_FLASH_ATTR verify_admin_pw(const char *pw) { - // This is not really for security, but to prevent someone who - // shouldn't touch those settings from fucking it up. - return streq(pw, STR(ADMIN_PASSWORD)); // the PW comes from the makefile + return streq(pw, persist.admin.pw); } httpd_cgi_state ICACHE_FLASH_ATTR diff --git a/user/persist.c b/user/persist.c index 5bb22d3..c9ea315 100644 --- a/user/persist.c +++ b/user/persist.c @@ -97,19 +97,27 @@ compute_checksum(AppConfigBundle *bundle) return calculateCRC32((uint8_t *) bundle, sizeof(AppConfigBundle) - 4); } +static void ICACHE_FLASH_ATTR +set_admin_block_defaults(void) +{ + persist_info("[Persist] Initing admin config block"); + strcpy(persist.admin.pw, STR(ADMIN_PASSWORD)); + persist.admin.version = ADMINCONF_VERSION; +} + /** * Load, verify and apply persistent config */ void ICACHE_FLASH_ATTR persist_load(void) { - persist_info("[Persist] Loading stored settings from FLASH..."); + persist_info("[Persist] Loading settings from FLASH..."); - persist_dbg("AppConfigBundle memory map:"); - persist_dbg("> WiFiConfigBundle at %4d (error %2d)", wconf_at, wconf_at - 0); - persist_dbg("> SystemConfigBundle at %4d (error %2d)", sconf_at, sconf_at - WIFICONF_SIZE); - persist_dbg("> TerminalConfigBundle at %4d (error %2d)", tconf_at, tconf_at - WIFICONF_SIZE - SYSCONF_SIZE); - persist_dbg("> Checksum at %4d (error %2d)", cksum_at, cksum_at - (APPCONF_SIZE - 4)); + persist_dbg("Persist memory map:"); + persist_dbg("> wifi at %4d (error %2d)", wconf_at, wconf_at - 0); + persist_dbg("> sys at %4d (error %2d)", sconf_at, sconf_at - WIFICONF_SIZE); + persist_dbg("> term at %4d (error %2d)", tconf_at, tconf_at - WIFICONF_SIZE - SYSCONF_SIZE); + persist_dbg("> cksum at %4d (error %2d)", cksum_at, cksum_at - (APPCONF_SIZE - 4)); persist_dbg("> Total size = %d bytes (error %d)", sizeof(AppConfigBundle), APPCONF_SIZE - sizeof(AppConfigBundle)); bool hard_reset = false; @@ -120,7 +128,8 @@ persist_load(void) // Verify checksums if (hard_reset || (compute_checksum(&persist.defaults) != persist.defaults.checksum) || - (compute_checksum(&persist.current) != persist.current.checksum)) { + (compute_checksum(&persist.current) != persist.current.checksum) || + (persist.admin.version != 0 && (calculateCRC32((uint8_t *) &persist.admin, sizeof(AdminConfigBlock) - 4) != persist.admin.checksum))) { error("[Persist] Checksum verification: FAILED"); hard_reset = true; } else { @@ -135,10 +144,18 @@ persist_load(void) // write them also as defaults memcpy(&persist.defaults, &persist.current, sizeof(AppConfigBundle)); + + // reset admin pw + set_admin_block_defaults(); persist_store(); // this also stores them to flash and applies to modules } else { + if (persist.admin.version == 0) { + set_admin_block_defaults(); + persist_store(); + } + apply_live_settings(); } @@ -153,6 +170,7 @@ persist_store(void) // Update checksums before write persist.current.checksum = compute_checksum(&persist.current); persist.defaults.checksum = compute_checksum(&persist.defaults); + persist.admin.checksum = calculateCRC32((uint8_t *) &persist.admin, sizeof(AdminConfigBlock) - 4); if (!system_param_save_with_protect(PERSIST_SECTOR_ID, &persist, sizeof(PersistBlock))) { error("[Persist] Store to flash failed!"); diff --git a/user/persist.h b/user/persist.h index 1cc8a67..d85c964 100644 --- a/user/persist.h +++ b/user/persist.h @@ -16,9 +16,9 @@ // Changing this could be used to force-erase the config area // after a firmware upgrade -#define CHECKSUM_SALT 3 +#define CHECKSUM_SALT 4 -#define APPCONF_SIZE 2048 +#define APPCONF_SIZE 1900 /** Struct for current or default settings */ typedef struct { // the entire block should be 1024 bytes long (for compatibility across upgrades) @@ -41,7 +41,7 @@ typedef struct { // the entire block should be 1024 bytes long (for compatibilit // it grew to a different memory area. uint8_t _filler_end[ APPCONF_SIZE - - sizeof(uint32_t) // checksum + - 4 // checksum - WIFICONF_SIZE - SYSCONF_SIZE - TERMCONF_SIZE @@ -50,10 +50,21 @@ typedef struct { // the entire block should be 1024 bytes long (for compatibilit uint32_t checksum; // computed before write and tested on load. If it doesn't match, values are reset to hard defaults. } AppConfigBundle; +#define ADMINCONF_VERSION 1 +#define ADMINCONF_SIZE 256 + +typedef struct { + u8 version; + char pw[64]; + uint8_t _filler[ADMINCONF_SIZE-64-4]; + uint32_t checksum; +} AdminConfigBlock; + /** This is the entire data block stored in FLASH */ typedef struct { AppConfigBundle defaults; // defaults are stored here AppConfigBundle current; // active settings adjusted by the user + AdminConfigBlock admin; } PersistBlock; // Persist holds the data currently loaded from the flash diff --git a/user/serial.c b/user/serial.c index 4ecb128..bcbd54c 100644 --- a/user/serial.c +++ b/user/serial.c @@ -4,8 +4,7 @@ #include "ansi_parser.h" #include "syscfg.h" -#define LOGBUF_SIZE 512 -static char logbuf[LOGBUF_SIZE]; +static char logbuf[DEBUG_LOGBUF_SIZE]; static u32 lb_nw = 1; static u32 lb_ls = 0; static ETSTimer flushLogTimer; @@ -14,7 +13,7 @@ static void buf_putc(char c) { if (lb_ls != lb_nw) { logbuf[lb_nw++] = c; - if (lb_nw >= LOGBUF_SIZE) lb_nw = 0; + if (lb_nw >= DEBUG_LOGBUF_SIZE) lb_nw = 0; } } @@ -25,11 +24,11 @@ buf_pop(void *unused) u32 old_ls; while (quantity > 0) { // stop when done - if ((lb_ls == lb_nw-1) || (lb_ls == LOGBUF_SIZE-1 && lb_nw == 0)) break; + if ((lb_ls == lb_nw-1) || (lb_ls == DEBUG_LOGBUF_SIZE-1 && lb_nw == 0)) break; old_ls = lb_ls; lb_ls++; - if (lb_ls >= LOGBUF_SIZE) lb_ls = 0; + if (lb_ls >= DEBUG_LOGBUF_SIZE) lb_ls = 0; if (OK == UART_WriteCharCRLF(UART1, logbuf[lb_ls], 5)) { quantity--; From 3849e161e52887bacc3e1dddbafd82d343a5550d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 22 Sep 2017 00:30:16 +0200 Subject: [PATCH 11/29] add pwlock settings to sysconf --- user/syscfg.c | 12 +++++++++++- user/syscfg.h | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/user/syscfg.c b/user/syscfg.c index df27de7..d4b262f 100644 --- a/user/syscfg.c +++ b/user/syscfg.c @@ -12,7 +12,17 @@ SystemConfigBundle * const sysconf = &persist.current.sysconf; void ICACHE_FLASH_ATTR sysconf_apply_settings(void) { - // !!! Update to current version !!! + bool changed = false; + if (sysconf->config_version < 1) { + dbg("Upgrading syscfg to v 1"); + changed = true; + sysconf->access_pw[0] = 0; + sysconf->pwlock = PWLOCK_NONE; + } + + if (changed) { + persist_store(); + } serialInit(); } diff --git a/user/syscfg.h b/user/syscfg.h index 92997c9..624dfe3 100644 --- a/user/syscfg.h +++ b/user/syscfg.h @@ -10,13 +10,23 @@ // Size designed for the wifi config structure // Must be constant to avoid corrupting user config after upgrade #define SYSCONF_SIZE 200 -#define SYSCONF_VERSION 0 +#define SYSCONF_VERSION 1 + +enum pwlock { + PWLOCK_NONE = 0, + PWLOCK_SETTINGS_NOTERM = 1, + PWLOCK_SETTINGS_ALL = 2, + PWLOCK_MENUS = 3, + PWLOCK_ALL = 4, +}; 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 } SystemConfigBundle; extern SystemConfigBundle * const sysconf; From 82961568b829b80d9e12b4ebc764f4ebdbad116d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 22 Sep 2017 00:33:03 +0200 Subject: [PATCH 12/29] increased sysconbf allocated flash size (safe now bc we alrady have a breaking change that wipes old settings) --- user/persist.h | 2 +- user/syscfg.c | 3 +++ user/syscfg.h | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/user/persist.h b/user/persist.h index d85c964..8f6c15a 100644 --- a/user/persist.h +++ b/user/persist.h @@ -16,7 +16,7 @@ // Changing this could be used to force-erase the config area // after a firmware upgrade -#define CHECKSUM_SALT 4 +#define CHECKSUM_SALT 5 #define APPCONF_SIZE 1900 diff --git a/user/syscfg.c b/user/syscfg.c index d4b262f..cca8a5c 100644 --- a/user/syscfg.c +++ b/user/syscfg.c @@ -33,4 +33,7 @@ sysconf_restore_defaults(void) sysconf->uart_parity = PARITY_NONE; sysconf->uart_baudrate = BIT_RATE_115200; sysconf->uart_stopbits = ONE_STOP_BIT; + sysconf->config_version = SYSCONF_VERSION; + sysconf->access_pw[0] = 0; + sysconf->pwlock = PWLOCK_NONE; } diff --git a/user/syscfg.h b/user/syscfg.h index 624dfe3..e66630c 100644 --- a/user/syscfg.h +++ b/user/syscfg.h @@ -9,7 +9,7 @@ // Size designed for the wifi config structure // Must be constant to avoid corrupting user config after upgrade -#define SYSCONF_SIZE 200 +#define SYSCONF_SIZE 300 #define SYSCONF_VERSION 1 enum pwlock { From 37de3a095d4608f720a9d4a00593151813bef0c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 22 Sep 2017 00:48:57 +0200 Subject: [PATCH 13/29] configurable pw lock (not yet tested and not connected to front-end) --- user/routes.c | 81 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 22 deletions(-) diff --git a/user/routes.c b/user/routes.c index 7711b0e..45e961c 100644 --- a/user/routes.c +++ b/user/routes.c @@ -12,12 +12,66 @@ #include "cgi_network.h" #include "cgi_term_cfg.h" #include "cgi_persist.h" +#include "syscfg.h" -#define WIFI_PROTECT 0 -#define WIFI_AUTH_NAME "wifi" -#define WIFI_AUTH_PASS "nicitel" +/** + * Password for WiFi config + */ +static int ICACHE_FLASH_ATTR wifiPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen) +{ + if (no == 0) { + os_strcpy(user, "admin"); + os_strcpy(pass, sysconf->access_pw); + return 1; + } + return 0; +} -static int wifiPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen); +httpd_cgi_state ICACHE_FLASH_ATTR cgiOptionalPwLock(HttpdConnData *connData) +{ + bool protect = false; + + switch (sysconf->pwlock) { + case PWLOCK_ALL: + protect = true; + break; + + case PWLOCK_SETTINGS_NOTERM: + protect = strstarts(connData->url, "/cfg") && !strstarts(connData->url, "/cfg/term"); + break; + + case PWLOCK_SETTINGS_ALL: + protect = strstarts(connData->url, "/cfg"); + break; + + case PWLOCK_MENUS: + protect = strstarts(connData->url, "/cfg") || strstarts(connData->url, "/about") || strstarts(connData->url, "/help"); + break; + + default: + case PWLOCK_NONE: + break; + } + + // pages outside the normal scope + + if (sysconf->pwlock > PWLOCK_NONE) { + if (strstarts(connData->url, "/system/reset")) protect = true; + } + + if (sysconf->pwlock > PWLOCK_SETTINGS_NOTERM) { + if (strstarts(connData->url, "/system/cls")) protect = true; + } + + if (sysconf->access_pw[0] == 0) protect = false; + + if (protect) { + connData->cgiArg = wifiPassFn; + return authBasic(connData); + } else { + return HTTPD_CGI_NOTFOUND; + } +} /** * Application routes @@ -25,6 +79,7 @@ static int wifiPassFn(HttpdConnData *connData, int no, char *user, int userLen, const HttpdBuiltInUrl routes[] ESP_CONST_DATA = { // redirect func for the captive portal ROUTE_CGI_ARG("*", cgiRedirectApClientToHostname, "esp-terminal.ap"), + ROUTE_CGI("*", cgiOptionalPwLock), // --- Web pages --- ROUTE_TPL_FILE("/", tplScreen, "/term.tpl"), @@ -39,10 +94,6 @@ const HttpdBuiltInUrl routes[] ESP_CONST_DATA = { ROUTE_CGI("/system/ping/?", cgiPing), ROUTE_CGI("/system/cls/?", cgiResetScreen), - // --- WiFi config --- (TODO make this conditional and configurable) -#if WIFI_PROTECT - ROUTE_AUTH("/wifi*", wifiPassFn), -#endif ROUTE_REDIRECT("/cfg/?", "/cfg/wifi"), ROUTE_TPL_FILE("/cfg/wifi/?", tplWlan, "/cfg_wifi.tpl"), @@ -67,17 +118,3 @@ const HttpdBuiltInUrl routes[] ESP_CONST_DATA = { ROUTE_END(), }; -// --- Wifi password protection --- - -/** - * Password for WiFi config - */ -static int ICACHE_FLASH_ATTR wifiPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen) -{ - if (no == 0) { - os_strcpy(user, WIFI_AUTH_NAME); - os_strcpy(pass, WIFI_AUTH_PASS); - return 1; - } - return 0; -} From 38b3ce2dc8d21795cc913b1a0aaba7d02961538c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 22 Sep 2017 01:00:52 +0200 Subject: [PATCH 14/29] cgi handler for setting passwords (not tested) --- user/cgi_system.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++- user/syscfg.h | 1 + 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/user/cgi_system.c b/user/cgi_system.c index 1b70289..7f75797 100755 --- a/user/cgi_system.c +++ b/user/cgi_system.c @@ -78,7 +78,8 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiPing(HttpdConnData *connData) httpd_cgi_state ICACHE_FLASH_ATTR cgiSystemCfgSetParams(HttpdConnData *connData) { - char buff[50]; + char buff[65]; + char buff2[65]; char redir_url_buf[100]; char *redir_url = redir_url_buf; @@ -138,6 +139,80 @@ cgiSystemCfgSetParams(HttpdConnData *connData) } } + if (GET_ARG("security")) { + cgi_dbg("*** Security config! ***"); + + if (GET_ARG("pw")) { + if (streq(buff, persist.admin.pw)) { + // authenticated OK + do { + if (GET_ARG("pwlock")) { + cgi_dbg("pwlock: %s", buff); + int pwlock = atoi(buff); + if (pwlock >= 0 && pwlock < PWLOCK_MAX) { + sysconf->pwlock = (enum pwlock) pwlock; + } + else { + cgi_warn("Bad pwlock %s", buff); + redir_url += sprintf(redir_url, "pwlock,"); + break; + } + } + + if (GET_ARG("access_pw")) { + cgi_dbg("access_pw: %s", buff); + + strcpy(buff2, buff); + if (GET_ARG("access_pw2")) { + cgi_dbg("access_pw2: %s", buff); + + if (streq(buff, buff2)) { + cgi_dbg("Changing access PW!!!"); + strncpy(sysconf->access_pw, buff, 64); + } else { + cgi_warn("Bad repeated access_pw %s", buff); + redir_url += sprintf(redir_url, "access_pw2,"); + } + } else { + cgi_warn("Missing access_pw %s", buff); + redir_url += sprintf(redir_url, "access_pw2,"); + } + + break; // access pw and admin pw are in separate forms + } + + if (GET_ARG("admin_pw")) { + cgi_dbg("admin_pw: %s", buff); + + strcpy(buff2, buff); + if (GET_ARG("admin_pw2")) { + cgi_dbg("admin_pw2: %s", buff); + + if (streq(buff, buff2)) { + cgi_dbg("Changing admin PW!!!"); + strncpy(persist.admin.pw, buff, 64); + } else { + cgi_warn("Bad repeated admin_pw %s", buff); + redir_url += sprintf(redir_url, "admin_pw2,"); + } + } else { + cgi_warn("Missing admin_pw %s", buff); + redir_url += sprintf(redir_url, "admin_pw2,"); + } + + break; + } + } while(0); + } else { + warn("Bad admin pw!"); + redir_url += sprintf(redir_url, "pw,"); + } + } else { + warn("Missing admin pw!"); + redir_url += sprintf(redir_url, "pw,"); + } + } + if (redir_url_buf[strlen(SET_REDIR_ERR)] == 0) { // All was OK cgi_info("Set system params - success, saving..."); @@ -177,6 +252,9 @@ tplSystemCfg(HttpdConnData *connData, char *token, void **arg) else if (streq(token, "uart_stopbits")) { sprintf(buff, "%d", sysconf->uart_stopbits); } + else if (streq(token, "pwlock")) { + sprintf(buff, "%d", sysconf->pwlock); + } tplSend(connData, buff, -1); return HTTPD_CGI_DONE; diff --git a/user/syscfg.h b/user/syscfg.h index e66630c..c7a47f3 100644 --- a/user/syscfg.h +++ b/user/syscfg.h @@ -18,6 +18,7 @@ enum pwlock { PWLOCK_SETTINGS_ALL = 2, PWLOCK_MENUS = 3, PWLOCK_ALL = 4, + PWLOCK_MAX = 5, }; typedef struct { From a464a73a0eba6b6f55a8b6dc5ab300b05fd012be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 22 Sep 2017 01:05:13 +0200 Subject: [PATCH 15/29] cgi form handlers for setting password stuff --- user/cgi_system.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user/cgi_system.c b/user/cgi_system.c index 7f75797..0510637 100755 --- a/user/cgi_system.c +++ b/user/cgi_system.c @@ -213,6 +213,8 @@ cgiSystemCfgSetParams(HttpdConnData *connData) } } + (void)redir_url; + if (redir_url_buf[strlen(SET_REDIR_ERR)] == 0) { // All was OK cgi_info("Set system params - success, saving..."); From 357a9d43e3badcdf7ae3305534aaab1a03f4be09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Sep 2017 01:33:55 +0200 Subject: [PATCH 16/29] password changing, changed default pw to "adminpw", added settings revert if validation fails --- esphttpdconfig.mk | 4 +- front-end | 2 +- user/cgi_network.c | 12 +++ user/cgi_system.c | 199 +++++++++++++++++--------------------------- user/cgi_term_cfg.c | 126 ++++++++++++++++++++++------ user/cgi_wifi.c | 14 ++++ user/syscfg.c | 2 + 7 files changed, 209 insertions(+), 150 deletions(-) diff --git a/esphttpdconfig.mk b/esphttpdconfig.mk index d9b9e46..f0a7175 100644 --- a/esphttpdconfig.mk +++ b/esphttpdconfig.mk @@ -39,7 +39,7 @@ OUTPUT_TYPE = combined ESP_SPI_FLASH_SIZE_K = 1024 # Admin password, used to store settings to flash as defaults -ADMIN_PASSWORD = "19738426" +ADMIN_PASSWORD = "adminpw" GLOBAL_CFLAGS = \ -DDEBUG_ROUTER=0 \ @@ -48,7 +48,7 @@ GLOBAL_CFLAGS = \ -DDEBUG_ESPFS=0 \ -DDEBUG_PERSIST=1 \ -DDEBUG_UTFCACHE=0 \ - -DDEBUG_CGI=0 \ + -DDEBUG_CGI=1 \ -DDEBUG_WIFI=0 \ -DDEBUG_WS=0 \ -DDEBUG_ANSI=0 \ diff --git a/front-end b/front-end index 72279bf..172a890 160000 --- a/front-end +++ b/front-end @@ -1 +1 @@ -Subproject commit 72279bf0355af1ba56ff3950a085f38d9adb8506 +Subproject commit 172a890be27476586a54296d6584300ad5bf1888 diff --git a/user/cgi_network.c b/user/cgi_network.c index b87dd96..3bc28b2 100644 --- a/user/cgi_network.c +++ b/user/cgi_network.c @@ -41,6 +41,11 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiNetworkSetParams(HttpdConnData *connData) return HTTPD_CGI_DONE; } + WiFiConfigBundle *wificonf_backup = malloc(sizeof(WiFiConfigBundle)); + WiFiConfChangeFlags *wcf_backup = malloc(sizeof(WiFiConfChangeFlags)); + memcpy(wificonf_backup, wificonf, sizeof(WiFiConfigBundle)); + memcpy(wcf_backup, &wifi_change_flags, sizeof(WiFiConfChangeFlags)); + // ---- AP DHCP server lease time ---- if (GET_ARG("ap_dhcp_time")) { @@ -192,9 +197,16 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiNetworkSetParams(HttpdConnData *connData) httpdRedirect(connData, SET_REDIR_SUC); } else { cgi_warn("Some WiFi settings did not validate, asking for correction"); + + memcpy(wificonf, wificonf_backup, sizeof(WiFiConfigBundle)); + memcpy(&wifi_change_flags, wcf_backup, sizeof(WiFiConfChangeFlags)); + // Some errors, appended to the URL as ?err= httpdRedirect(connData, redir_url_buf); } + + free(wificonf_backup); + free(wcf_backup); return HTTPD_CGI_DONE; } diff --git a/user/cgi_system.c b/user/cgi_system.c index 0510637..7329f97 100755 --- a/user/cgi_system.c +++ b/user/cgi_system.c @@ -91,127 +91,81 @@ cgiSystemCfgSetParams(HttpdConnData *connData) return HTTPD_CGI_DONE; } - 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; - } else { - cgi_warn("Bad baud rate %s", buff); - redir_url += sprintf(redir_url, "uart_baud,"); + AdminConfigBlock *admin_backup = malloc(sizeof(AdminConfigBlock)); + SystemConfigBundle *sysconf_backup = malloc(sizeof(SystemConfigBundle)); + memcpy(admin_backup, &persist.admin, sizeof(AdminConfigBlock)); + memcpy(sysconf_backup, sysconf, sizeof(SystemConfigBundle)); + + do { + if (!GET_ARG("pw")) { + warn("Missing admin pw!"); + redir_url += sprintf(redir_url, "pw,"); + break; } - } - if (GET_ARG("uart_parity")) { - cgi_dbg("Parity: %s", buff); - int parity = atoi(buff); - if (parity >= 0 && parity <= 2) { - sysconf->uart_parity = (UartParityMode) parity; - } else { - cgi_warn("Bad parity %s", buff); - redir_url += sprintf(redir_url, "uart_parity,"); + if (!streq(buff, persist.admin.pw)) { + warn("Bad admin pw!"); + redir_url += sprintf(redir_url, "pw,"); + break; } - } - 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; - } else { - cgi_warn("Bad stopbits %s", buff); - redir_url += sprintf(redir_url, "uart_stopbits,"); + // 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; + } + + sysconf->pwlock = (enum pwlock) pwlock; } - } - if (GET_ARG("security")) { - cgi_dbg("*** Security config! ***"); - - if (GET_ARG("pw")) { - if (streq(buff, persist.admin.pw)) { - // authenticated OK - do { - if (GET_ARG("pwlock")) { - cgi_dbg("pwlock: %s", buff); - int pwlock = atoi(buff); - if (pwlock >= 0 && pwlock < PWLOCK_MAX) { - sysconf->pwlock = (enum pwlock) pwlock; - } - else { - cgi_warn("Bad pwlock %s", buff); - redir_url += sprintf(redir_url, "pwlock,"); - break; - } - } - - if (GET_ARG("access_pw")) { - cgi_dbg("access_pw: %s", buff); - - strcpy(buff2, buff); - if (GET_ARG("access_pw2")) { - cgi_dbg("access_pw2: %s", buff); - - if (streq(buff, buff2)) { - cgi_dbg("Changing access PW!!!"); - strncpy(sysconf->access_pw, buff, 64); - } else { - cgi_warn("Bad repeated access_pw %s", buff); - redir_url += sprintf(redir_url, "access_pw2,"); - } - } else { - cgi_warn("Missing access_pw %s", buff); - redir_url += sprintf(redir_url, "access_pw2,"); - } - - break; // access pw and admin pw are in separate forms - } - - if (GET_ARG("admin_pw")) { - cgi_dbg("admin_pw: %s", buff); - - strcpy(buff2, buff); - if (GET_ARG("admin_pw2")) { - cgi_dbg("admin_pw2: %s", buff); - - if (streq(buff, buff2)) { - cgi_dbg("Changing admin PW!!!"); - strncpy(persist.admin.pw, buff, 64); - } else { - cgi_warn("Bad repeated admin_pw %s", buff); - redir_url += sprintf(redir_url, "admin_pw2,"); - } - } else { - cgi_warn("Missing admin_pw %s", buff); - redir_url += sprintf(redir_url, "admin_pw2,"); - } - - break; - } - } while(0); - } else { - warn("Bad admin pw!"); - redir_url += sprintf(redir_url, "pw,"); + if (GET_ARG("access_pw")) { + cgi_dbg("access_pw: %s", buff); + + 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; + } + + if (!streq(buff, buff2)) { + cgi_warn("Bad repeated access_pw %s", buff); + redir_url += sprintf(redir_url, "access_pw2,"); + break; + } + + cgi_dbg("Changing access PW!!!"); + strncpy(sysconf->access_pw, buff, 64); } - } else { - warn("Missing admin pw!"); - redir_url += sprintf(redir_url, "pw,"); } - } + + 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; + } + + if (!streq(buff, buff2)) { + cgi_warn("Bad repeated admin_pw %s", buff); + redir_url += sprintf(redir_url, "admin_pw2,"); + break; + } + + cgi_dbg("Changing admin PW!!!"); + strncpy(persist.admin.pw, buff, 64); + } + } + } while (0); (void)redir_url; @@ -225,9 +179,17 @@ cgiSystemCfgSetParams(HttpdConnData *connData) httpdRedirect(connData, SET_REDIR_SUC); } else { cgi_warn("Some settings did not validate, asking for correction"); + + // revert any possible changes + memcpy(&persist.admin, admin_backup, sizeof(AdminConfigBlock)); + memcpy(sysconf, sysconf_backup, sizeof(SystemConfigBundle)); + // Some errors, appended to the URL as ?err= httpdRedirect(connData, redir_url_buf); } + + free(admin_backup); + free(sysconf_backup); return HTTPD_CGI_DONE; } @@ -245,16 +207,7 @@ tplSystemCfg(HttpdConnData *connData, char *token, void **arg) strcpy(buff, ""); // fallback - 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 if (streq(token, "pwlock")) { + if (streq(token, "pwlock")) { sprintf(buff, "%d", sysconf->pwlock); } diff --git a/user/cgi_term_cfg.c b/user/cgi_term_cfg.c index 76b8bcc..5b09741 100644 --- a/user/cgi_term_cfg.c +++ b/user/cgi_term_cfg.c @@ -9,6 +9,7 @@ Cgi/template routines for configuring non-wifi settings #include "screen.h" #include "helpers.h" #include "cgi_logging.h" +#include "uart_driver.h" #define SET_REDIR_SUC "/cfg/term" #define SET_REDIR_ERR SET_REDIR_SUC"?err=" @@ -30,6 +31,11 @@ cgiTermCfgSetParams(HttpdConnData *connData) redir_url += sprintf(redir_url, SET_REDIR_ERR); // we'll test if anything was printed by looking for \0 in failed_keys_buf + SystemConfigBundle *sysconf_backup = malloc(sizeof(SystemConfigBundle)); + TerminalConfigBundle *termconf_backup = malloc(sizeof(TerminalConfigBundle)); + memcpy(sysconf_backup, sysconf, sizeof(SystemConfigBundle)); + memcpy(termconf_backup, termconf, sizeof(TerminalConfigBundle)); + if (connData->conn == NULL) { //Connection aborted. Clean up. return HTTPD_CGI_DONE; @@ -39,34 +45,40 @@ cgiTermCfgSetParams(HttpdConnData *connData) if (GET_ARG("term_width")) { cgi_dbg("Default screen width: %s", buff); w = atoi(buff); - if (w > 1) { - if (GET_ARG("term_height")) { - cgi_dbg("Default screen height: %s", buff); - h = atoi(buff); - if (h > 1) { - if (w * h <= MAX_SCREEN_SIZE) { - if (termconf->width != w || termconf->height != h) { - termconf->width = w; - termconf->height = h; - shall_clear_screen = true; // this causes a notify - } - } else { - cgi_warn("Bad dimensions: %d x %d (total %d)", w, h, w*h); - redir_url += sprintf(redir_url, "term_width,term_height,"); - } - } else { - cgi_warn("Bad height: \"%s\"", buff); - redir_url += sprintf(redir_url, "term_width,"); - } - } else { + do { + 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_width,term_height,"); + break; } - } else { - cgi_warn("Bad width: \"%s\"", buff); - redir_url += sprintf(redir_url, "term_width,"); - } + + 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; // this causes a notify + } + } while (0); } if (GET_ARG("default_bg")) { @@ -265,6 +277,56 @@ cgiTermCfgSetParams(HttpdConnData *connData) } } + 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; + } 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; + } 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; + } else { + cgi_warn("Bad stopbits %s", buff); + redir_url += sprintf(redir_url, "uart_stopbits,"); + } + } + + (void)redir_url; + if (redir_url_buf[strlen(SET_REDIR_ERR)] == 0) { // All was OK info("Set term params - success, saving..."); @@ -288,9 +350,16 @@ cgiTermCfgSetParams(HttpdConnData *connData) httpdRedirect(connData, SET_REDIR_SUC); } else { cgi_warn("Some settings did not validate, asking for correction"); + + memcpy(sysconf, sysconf_backup, sizeof(SystemConfigBundle)); + memcpy(termconf, termconf_backup, sizeof(TerminalConfigBundle)); + // Some errors, appended to the URL as ?err= httpdRedirect(connData, redir_url_buf); } + + free(sysconf_backup); + free(termconf_backup); return HTTPD_CGI_DONE; } @@ -357,6 +426,15 @@ tplTermCfg(HttpdConnData *connData, char *token, void **arg) else if (streq(token, "term_title")) { strncpy_safe(buff, termconf->title, 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); diff --git a/user/cgi_wifi.c b/user/cgi_wifi.c index df904f3..0cab1a5 100644 --- a/user/cgi_wifi.c +++ b/user/cgi_wifi.c @@ -355,6 +355,11 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData) return HTTPD_CGI_DONE; } + WiFiConfigBundle *wificonf_backup = malloc(sizeof(WiFiConfigBundle)); + WiFiConfChangeFlags *wcf_backup = malloc(sizeof(WiFiConfChangeFlags)); + memcpy(wificonf_backup, wificonf, sizeof(WiFiConfigBundle)); + memcpy(wcf_backup, &wifi_change_flags, sizeof(WiFiConfChangeFlags)); + bool sta_turned_on = false; bool sta_ssid_pw_changed = false; @@ -502,6 +507,8 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData) } } + (void)redir_url; + if (redir_url_buf[strlen(SET_REDIR_ERR)] == 0) { // All was OK cgi_info("Set WiFi params - success, applying in 2000 ms"); @@ -532,9 +539,16 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData) } } else { cgi_warn("Some WiFi settings did not validate, asking for correction"); + + memcpy(wificonf, wificonf_backup, sizeof(WiFiConfigBundle)); + memcpy(&wifi_change_flags, wcf_backup, sizeof(WiFiConfChangeFlags)); + // Some errors, appended to the URL as ?err= httpdRedirect(connData, redir_url_buf); } + + free(wificonf_backup); + free(wcf_backup); return HTTPD_CGI_DONE; } diff --git a/user/syscfg.c b/user/syscfg.c index cca8a5c..cfa0695 100644 --- a/user/syscfg.c +++ b/user/syscfg.c @@ -20,6 +20,8 @@ sysconf_apply_settings(void) sysconf->pwlock = PWLOCK_NONE; } + sysconf->config_version = SYSCONF_VERSION; + if (changed) { persist_store(); } From 80e8e4f7dac018f2cd1cffbea9f461e652b178da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Sep 2017 01:59:53 +0200 Subject: [PATCH 17/29] added username config for basic auth --- Makefile | 1 - esphttpdconfig.mk | 11 ++++------- front-end | 2 +- user/cgi_system.c | 32 ++++++++++++++++++++++++++++++-- user/persist.c | 2 +- user/persist.h | 2 ++ user/routes.c | 17 +++++++++++++++-- user/syscfg.c | 9 ++++++++- user/syscfg.h | 6 +++++- 9 files changed, 66 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index a0ecbd3..a815b7a 100644 --- a/Makefile +++ b/Makefile @@ -69,7 +69,6 @@ CFLAGS = -Os -std=gnu99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inli CFLAGS += -DGIT_HASH_BACKEND='"$(shell git rev-parse --short HEAD)"' CFLAGS += -DGIT_HASH_FRONTEND='"$(shell cd front-end && git rev-parse --short HEAD)"' -CFLAGS += -DADMIN_PASSWORD=$(ADMIN_PASSWORD) CFLAGS += -D__TIMEZONE__='"$(shell date +%Z)"' ifdef GLOBAL_CFLAGS diff --git a/esphttpdconfig.mk b/esphttpdconfig.mk index f0a7175..d8b6237 100644 --- a/esphttpdconfig.mk +++ b/esphttpdconfig.mk @@ -38,20 +38,17 @@ OUTPUT_TYPE = combined # SPI flash size, in K ESP_SPI_FLASH_SIZE_K = 1024 -# Admin password, used to store settings to flash as defaults -ADMIN_PASSWORD = "adminpw" - GLOBAL_CFLAGS = \ -DDEBUG_ROUTER=0 \ -DDEBUG_CAPTDNS=0 \ -DDEBUG_HTTP=0 \ -DDEBUG_ESPFS=0 \ - -DDEBUG_PERSIST=1 \ + -DDEBUG_PERSIST=0 \ -DDEBUG_UTFCACHE=0 \ - -DDEBUG_CGI=1 \ + -DDEBUG_CGI=0 \ -DDEBUG_WIFI=0 \ -DDEBUG_WS=0 \ - -DDEBUG_ANSI=0 \ + -DDEBUG_ANSI=1 \ -DDEBUG_ANSI_NOIMPL=1 \ -DDEBUG_INPUT=0 \ -DDEBUG_HEAP=1 \ @@ -59,6 +56,6 @@ GLOBAL_CFLAGS = \ -DHTTPD_MAX_BACKLOG_SIZE=8192 \ -DHTTPD_MAX_HEAD_LEN=1024 \ -DHTTPD_MAX_POST_LEN=512 \ - -DDEBUG_LOGBUF_SIZE=2048 \ + -DDEBUG_LOGBUF_SIZE=1024 \ -mforce-l32 \ -DUSE_OPTIMIZE_PRINTF=1 diff --git a/front-end b/front-end index 172a890..6c64248 160000 --- a/front-end +++ b/front-end @@ -1 +1 @@ -Subproject commit 172a890be27476586a54296d6584300ad5bf1888 +Subproject commit 6c6424877c49e3e23f563067a78e79338226359d diff --git a/user/cgi_system.c b/user/cgi_system.c index 7329f97..e958f4f 100755 --- a/user/cgi_system.c +++ b/user/cgi_system.c @@ -139,11 +139,29 @@ cgiSystemCfgSetParams(HttpdConnData *connData) break; } - cgi_dbg("Changing access PW!!!"); + 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); @@ -161,7 +179,13 @@ cgiSystemCfgSetParams(HttpdConnData *connData) break; } - cgi_dbg("Changing admin PW!!!"); + if (strlen(buff) >= 64) { + cgi_warn("Too long admin_pw %s", buff); + redir_url += sprintf(redir_url, "admin_pw,"); + break; + } + + cgi_dbg("Changing admin PW!"); strncpy(persist.admin.pw, buff, 64); } } @@ -211,6 +235,10 @@ tplSystemCfg(HttpdConnData *connData, char *token, void **arg) sprintf(buff, "%d", sysconf->pwlock); } + if (streq(token, "access_name")) { + sprintf(buff, "%s", sysconf->access_name); + } + tplSend(connData, buff, -1); return HTTPD_CGI_DONE; } diff --git a/user/persist.c b/user/persist.c index c9ea315..cfe189b 100644 --- a/user/persist.c +++ b/user/persist.c @@ -101,7 +101,7 @@ static void ICACHE_FLASH_ATTR set_admin_block_defaults(void) { persist_info("[Persist] Initing admin config block"); - strcpy(persist.admin.pw, STR(ADMIN_PASSWORD)); + strcpy(persist.admin.pw, DEFAULT_ADMIN_PW); persist.admin.version = ADMINCONF_VERSION; } diff --git a/user/persist.h b/user/persist.h index 8f6c15a..7591873 100644 --- a/user/persist.h +++ b/user/persist.h @@ -14,6 +14,8 @@ #include "screen.h" #include "syscfg.h" +#define DEFAULT_ADMIN_PW "adminpw" + // Changing this could be used to force-erase the config area // after a firmware upgrade #define CHECKSUM_SALT 5 diff --git a/user/routes.c b/user/routes.c index 45e961c..9dfd8a5 100644 --- a/user/routes.c +++ b/user/routes.c @@ -13,6 +13,7 @@ #include "cgi_term_cfg.h" #include "cgi_persist.h" #include "syscfg.h" +#include "persist.h" /** * Password for WiFi config @@ -20,10 +21,15 @@ static int ICACHE_FLASH_ATTR wifiPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen) { if (no == 0) { - os_strcpy(user, "admin"); + os_strcpy(user, sysconf->access_name); os_strcpy(pass, sysconf->access_pw); return 1; } + if (no == 1) { + os_strcpy(user, "admin"); + os_strcpy(pass, persist.admin.pw); + return 1; + } return 0; } @@ -31,6 +37,8 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiOptionalPwLock(HttpdConnData *connData) { bool protect = false; + http_dbg("Route, %s, pwlock=%d", connData->url, sysconf->pwlock); + switch (sysconf->pwlock) { case PWLOCK_ALL: protect = true; @@ -63,12 +71,17 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiOptionalPwLock(HttpdConnData *connData) if (strstarts(connData->url, "/system/cls")) protect = true; } - if (sysconf->access_pw[0] == 0) protect = false; + if (sysconf->access_pw[0] == 0) { + http_dbg("Access PW is nil, no protection."); + protect = false; + } if (protect) { + http_dbg("Page is protected!"); connData->cgiArg = wifiPassFn; return authBasic(connData); } else { + http_dbg("Not protected"); return HTTPD_CGI_NOTFOUND; } } diff --git a/user/syscfg.c b/user/syscfg.c index cfa0695..f9004da 100644 --- a/user/syscfg.c +++ b/user/syscfg.c @@ -15,9 +15,16 @@ sysconf_apply_settings(void) bool changed = false; if (sysconf->config_version < 1) { dbg("Upgrading syscfg to v 1"); - changed = true; sysconf->access_pw[0] = 0; sysconf->pwlock = PWLOCK_NONE; + changed = true; + } + + if (sysconf->config_version < 2) { + dbg("Upgrading syscfg to v 2"); + strcpy(sysconf->access_pw, DEF_ACCESS_PW); + strcpy(sysconf->access_name, DEF_ACCESS_NAME); + changed = true; } sysconf->config_version = SYSCONF_VERSION; diff --git a/user/syscfg.h b/user/syscfg.h index c7a47f3..359e0c9 100644 --- a/user/syscfg.h +++ b/user/syscfg.h @@ -10,7 +10,10 @@ // Size designed for the wifi config structure // Must be constant to avoid corrupting user config after upgrade #define SYSCONF_SIZE 300 -#define SYSCONF_VERSION 1 +#define SYSCONF_VERSION 2 + +#define DEF_ACCESS_PW "1234" +#define DEF_ACCESS_NAME "espterm" enum pwlock { PWLOCK_NONE = 0, @@ -28,6 +31,7 @@ typedef struct { u8 config_version; enum pwlock pwlock : 8; // page access lock char access_pw[64]; // access password + char access_name[32]; // access name } SystemConfigBundle; extern SystemConfigBundle * const sysconf; From 2e8ec41115cfb3792b17e5461061c2b10bd39947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Sep 2017 02:13:02 +0200 Subject: [PATCH 18/29] lib bump --- libesphttpd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libesphttpd b/libesphttpd index 58c81c0..24f9a37 160000 --- a/libesphttpd +++ b/libesphttpd @@ -1 +1 @@ -Subproject commit 58c81c0dfe8e15888408886e168ed739aa8f311d +Subproject commit 24f9a371eb5c0804dcc6657f99449ef07788140c From 948bcb62ffa08739e18fb2afdadf1f3842078e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Sep 2017 20:50:37 +0200 Subject: [PATCH 19/29] Backend changes for offscale default fg and bg + future-proofing - 16-bit attribs - added attribs FG and BG, if not set, default colors - added attrib INVERT, removed server-side color flipping - added screen attrib REVERSE_VIDEO (can't be done server-side if we want it to work with off-scale colors) - changed Attribs encoding to 3B - removed old migrations, made useless by the flash wipe caused by adding Admin PW section - some cleaning in CSI parser - removed function to set SGR inverse separately (now use normal SGR setter) - added functions to set fg and bg to defaults --- user/apars_csi.c | 38 +++++------- user/cgi_main.c | 8 +++ user/cgi_term_cfg.c | 4 +- user/persist.h | 2 +- user/screen.c | 147 +++++++++++++++++--------------------------- user/screen.h | 39 +++++++----- user/syscfg.c | 19 ++---- user/syscfg.h | 2 +- 8 files changed, 115 insertions(+), 144 deletions(-) diff --git a/user/apars_csi.c b/user/apars_csi.c index a83e8ba..ed18ac9 100644 --- a/user/apars_csi.c +++ b/user/apars_csi.c @@ -551,31 +551,27 @@ do_csi_sgr(CSI_Data *opts) else if (n >= SGR_FG_BRT_START && n <= SGR_FG_BRT_END) screen_set_fg((Color) ((n - SGR_FG_BRT_START) + 8)); // AIX bright fg else if (n >= SGR_BG_BRT_START && n <= SGR_BG_BRT_END) screen_set_bg((Color) ((n - SGR_BG_BRT_START) + 8)); // AIX bright bg // reset color - else if (n == SGR_FG_DEFAULT) screen_set_fg(termconf_live.default_fg); // default fg - else if (n == SGR_BG_DEFAULT) screen_set_bg(termconf_live.default_bg); // default bg + else if (n == SGR_FG_DEFAULT) screen_set_default_fg(); + else if (n == SGR_BG_DEFAULT) screen_set_default_bg(); // 256 colors else if (n == SGR_FG_256 || n == SGR_BG_256) { - if (i < count-2) { - if (opts->n[i + 1] == 5) { - u8 color = (u8) opts->n[i + 2]; - bool fg = n == SGR_FG_256; - if (fg) { - screen_set_fg(color); - } else { - screen_set_bg(color); - } - } - else { - ansi_warn("SGR syntax err"); - apars_show_context(); - break; // abandon further - } - i += 2; - } else { + if (i >= count-2) { ansi_warn("SGR syntax err"); apars_show_context(); break; // abandon further } + + if (opts->n[i + 1] != 5) { + ansi_warn("SGR syntax err"); + apars_show_context(); + break; // abandon further + } + + u8 color = (u8) opts->n[i + 2]; + bool fg = n == SGR_FG_256; + if (fg) screen_set_fg(color); + else screen_set_bg(color); + i += 2; } // -- set attr -- else if (n == SGR_BOLD) screen_set_sgr(ATTR_BOLD, 1); @@ -585,7 +581,7 @@ do_csi_sgr(CSI_Data *opts) else if (n == SGR_BLINK || n == SGR_BLINK_FAST) screen_set_sgr(ATTR_BLINK, 1); // 6 - rapid blink, not supported else if (n == SGR_STRIKE) screen_set_sgr(ATTR_STRIKE, 1); else if (n == SGR_FRAKTUR) screen_set_sgr(ATTR_FRAKTUR, 1); - else if (n == SGR_INVERSE) screen_set_sgr_inverse(1); + else if (n == SGR_INVERSE) screen_set_sgr(ATTR_INVERSE, 1); else if (n == SGR_CONCEAL) screen_set_sgr_conceal(1); else if (n == SGR_OVERLINE) screen_set_sgr(ATTR_OVERLINE, 1); // -- clear attr -- @@ -595,7 +591,7 @@ do_csi_sgr(CSI_Data *opts) else if (n == SGR_NO_UNDERLINE) screen_set_sgr(ATTR_UNDERLINE, 0); else if (n == SGR_NO_BLINK) screen_set_sgr(ATTR_BLINK, 0); else if (n == SGR_NO_STRIKE) screen_set_sgr(ATTR_STRIKE, 0); - else if (n == SGR_NO_INVERSE) screen_set_sgr_inverse(0); + else if (n == SGR_NO_INVERSE) screen_set_sgr(ATTR_INVERSE, 0); else if (n == SGR_NO_CONCEAL) screen_set_sgr_conceal(0); else if (n == SGR_NO_OVERLINE) screen_set_sgr(ATTR_OVERLINE, 0); else { diff --git a/user/cgi_main.c b/user/cgi_main.c index 377666c..e24e872 100644 --- a/user/cgi_main.c +++ b/user/cgi_main.c @@ -37,6 +37,14 @@ httpd_cgi_state ICACHE_FLASH_ATTR tplScreen(HttpdConnData *connData, char *token sprintf(buff, "%d", termconf->want_all_fn); tplSend(connData, buff, -1); } + else if (streq(token, "default_fg")) { + sprintf(buff, "0x%08X", termconf->default_fg); + tplSend(connData, buff, -1); + } + else if (streq(token, "default_bg")) { + sprintf(buff, "0x%08X", termconf->default_bg); + tplSend(connData, buff, -1); + } return HTTPD_CGI_DONE; } diff --git a/user/cgi_term_cfg.c b/user/cgi_term_cfg.c index 5b09741..25da9f6 100644 --- a/user/cgi_term_cfg.c +++ b/user/cgi_term_cfg.c @@ -86,7 +86,7 @@ cgiTermCfgSetParams(HttpdConnData *connData) n = atoi(buff); if (n >= 0 && n < 16) { if (termconf->default_bg != n) { - termconf->default_bg = (u8) n; + termconf->default_bg = n; shall_clear_screen = true; } } else { @@ -100,7 +100,7 @@ cgiTermCfgSetParams(HttpdConnData *connData) n = atoi(buff); if (n >= 0 && n < 16) { if (termconf->default_fg != n) { - termconf->default_fg = (u8) n; + termconf->default_fg = n; shall_clear_screen = true; } } else { diff --git a/user/persist.h b/user/persist.h index 7591873..50fa0f5 100644 --- a/user/persist.h +++ b/user/persist.h @@ -52,7 +52,7 @@ typedef struct { // the entire block should be 1024 bytes long (for compatibilit uint32_t checksum; // computed before write and tested on load. If it doesn't match, values are reset to hard defaults. } AppConfigBundle; -#define ADMINCONF_VERSION 1 +#define ADMINCONF_VERSION 0 #define ADMINCONF_SIZE 256 typedef struct { diff --git a/user/screen.c b/user/screen.c index 95b70d1..5fa1d2e 100644 --- a/user/screen.c +++ b/user/screen.c @@ -20,11 +20,6 @@ static void utf8_remap(char* out, char g, char charset); #define W termconf_live.width #define H termconf_live.height -/** - * Highest permissible value of the color attribute - */ -#define COLOR_MAX 15 - /** * Screen cell data type (16 bits) */ @@ -32,7 +27,7 @@ typedef struct __attribute__((packed)) { UnicodeCacheRef symbol : 8; Color fg; Color bg; - u8 attrs; + CellAttrs attrs; } Cell; /** @@ -78,9 +73,9 @@ typedef struct { bool hanging; //!< xenl state - cursor half-wrapped /* SGR */ - bool inverse; //!< not in attrs bc it's applied server-side (not sent to browser) - bool conceal; //!< similar to inverse, causes all to be replaced by SP - u8 attrs; + bool inverse; //!< not in attrs bc it's applied immediately when writing the cell + bool conceal; //!< similar to inverse, causes all to be replaced by SP + u16 attrs; Color fg; //!< Foreground color for writing Color bg; //!< Background color for writing @@ -207,45 +202,12 @@ terminal_apply_settings_noclear(void) { bool changed = false; - // Migrate to v1 - if (termconf->config_version < 1) { - persist_dbg("termconf: Updating to version 1"); - termconf->display_cooldown_ms = SCR_DEF_DISPLAY_COOLDOWN_MS; - changed = 1; - } - - // Migrate to v2 - if (termconf->config_version < 2) { - persist_dbg("termconf: Updating to version 2"); - termconf->loopback = 0; - termconf->show_config_links = 1; - termconf->show_buttons = 1; - changed = 1; - } - - // Migrate to v3 - if (termconf->config_version < 3) { - persist_dbg("termconf: Updating to version 3"); - for(int i=1; i <= TERM_BTN_COUNT; i++) { - sprintf(termconf->btn_msg[i-1], "%c", i); - } - changed = 1; - } - - // Migrate to v4 - if (termconf->config_version < 4) { - persist_dbg("termconf: Updating to version 4"); - termconf->cursor_shape = CURSOR_BLOCK_BL; - termconf->crlf_mode = false; - changed = 1; - } - - // Migrate to v5 - if (termconf->config_version < 4) { - persist_dbg("termconf: Updating to version 5"); - termconf->want_all_fn = 0; - changed = 1; - } +// // Migrate to v1 +// if (termconf->config_version < 1) { +// persist_dbg("termconf: Updating to version %d", 1); +// termconf->display_cooldown_ms = SCR_DEF_DISPLAY_COOLDOWN_MS; +// changed = 1; +// } termconf->config_version = TERMCONF_VERSION; @@ -288,9 +250,9 @@ screen_init(void) NOTIFY_LOCK(); Cell sample; sample.symbol = ' '; - sample.fg = termconf->default_fg; - sample.bg = termconf->default_bg; - sample.attrs = 0; + sample.fg = 0; + sample.bg = 0; + sample.attrs = 0; // use default colors for (unsigned int i = 0; i < MAX_SCREEN_SIZE; i++) { memcpy(&screen[i], &sample, sizeof(Cell)); } @@ -345,10 +307,9 @@ screen_reset_on_resize(void) void ICACHE_FLASH_ATTR screen_reset_sgr(void) { - cursor.fg = termconf->default_fg; - cursor.bg = termconf->default_bg; + cursor.fg = 0; + cursor.bg = 0; cursor.attrs = 0; - cursor.inverse = false; cursor.conceal = false; } @@ -588,14 +549,13 @@ static void ICACHE_FLASH_ATTR clear_range(unsigned int from, unsigned int to) { if (to >= W*H) to = W*H-1; - Color fg = (cursor.inverse) ? cursor.bg : cursor.fg; - Color bg = (cursor.inverse) ? cursor.fg : cursor.bg; Cell sample; sample.symbol = ' '; - sample.fg = fg; - sample.bg = bg; - sample.attrs = 0; + sample.fg = cursor.fg; + sample.bg = cursor.bg; + // we discard all attributes except color-set flags + sample.attrs = (CellAttrs) (cursor.attrs & (ATTR_FG | ATTR_BG)); for (unsigned int i = from; i <= to; i++) { UnicodeCacheRef symbol = screen[i].symbol; @@ -771,8 +731,8 @@ screen_fill_with_E(void) Cell sample; sample.symbol = 'E'; - sample.fg = termconf->default_fg; - sample.bg = termconf->default_bg; + sample.fg = 0; + sample.bg = 0; sample.attrs = 0; for (unsigned int i = 0; i <= W*H-1; i++) { @@ -1174,6 +1134,7 @@ void ICACHE_FLASH_ATTR screen_set_fg(Color color) { cursor.fg = color; + cursor.attrs |= ATTR_FG; } /** @@ -1183,10 +1144,31 @@ void ICACHE_FLASH_ATTR screen_set_bg(Color color) { cursor.bg = color; + cursor.attrs |= ATTR_BG; } +/** + * Set cursor foreground color to default + */ void ICACHE_FLASH_ATTR -screen_set_sgr(u8 attrs, bool ena) +screen_set_default_fg(void) +{ + cursor.fg = 0; + cursor.attrs &= ~ATTR_FG; +} + +/** + * Set cursor background color to default + */ +void ICACHE_FLASH_ATTR +screen_set_default_bg(void) +{ + cursor.bg = 0; + cursor.attrs &= ~ATTR_BG; +} + +void ICACHE_FLASH_ATTR +screen_set_sgr(CellAttrs attrs, bool ena) { if (ena) { cursor.attrs |= attrs; @@ -1196,12 +1178,6 @@ screen_set_sgr(u8 attrs, bool ena) } } -void ICACHE_FLASH_ATTR -screen_set_sgr_inverse(bool ena) -{ - cursor.inverse = ena; -} - void ICACHE_FLASH_ATTR screen_set_sgr_conceal(bool ena) { @@ -1359,9 +1335,11 @@ screen_report_sgr(char *buffer) if (cursor.attrs & ATTR_BLINK) buffer += sprintf(buffer, ";%d", SGR_BLINK); if (cursor.attrs & ATTR_FRAKTUR) buffer += sprintf(buffer, ";%d", SGR_FRAKTUR); if (cursor.attrs & ATTR_STRIKE) buffer += sprintf(buffer, ";%d", SGR_STRIKE); - if (cursor.inverse) buffer += sprintf(buffer, ";%d", SGR_INVERSE); - if (cursor.fg != termconf->default_fg) buffer += sprintf(buffer, ";%d", ((cursor.fg > 7) ? SGR_FG_BRT_START : SGR_FG_START) + (cursor.fg&7)); - if (cursor.bg != termconf->default_bg) buffer += sprintf(buffer, ";%d", ((cursor.bg > 7) ? SGR_BG_BRT_START : SGR_BG_START) + (cursor.bg&7)); + if (cursor.attrs & ATTR_INVERSE) buffer += sprintf(buffer, ";%d", SGR_INVERSE); + if (cursor.attrs & ATTR_FG) + buffer += sprintf(buffer, ";%d", ((cursor.fg > 7) ? SGR_FG_BRT_START : SGR_FG_START) + (cursor.fg&7)); + if (cursor.attrs & ATTR_BG) + buffer += sprintf(buffer, ";%d", ((cursor.bg > 7) ? SGR_BG_BRT_START : SGR_BG_START) + (cursor.bg&7)); (void)buffer; } @@ -1403,14 +1381,8 @@ putchar_graphic(const char *ch) } unicode_cache_remove(c->symbol); c->symbol = unicode_cache_add((const u8 *)ch); - - if (cursor.inverse) { - c->fg = cursor.bg; - c->bg = cursor.fg; - } else { - c->fg = cursor.fg; - c->bg = cursor.bg; - } + c->fg = cursor.fg; + c->bg = cursor.bg; c->attrs = cursor.attrs; cursor.x++; @@ -1543,7 +1515,7 @@ utf8_remap(char *out, char g, char charset) struct ScreenSerializeState { Color lastFg; Color lastBg; - bool lastAttrs; + CellAttrs lastAttrs; UnicodeCacheRef lastSymbol; char lastChar[4]; u8 lastCharLen; @@ -1656,7 +1628,8 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) (termconf_live.show_config_links << 8) | ((termconf_live.cursor_shape&0x07) << 9) | // 9,10,11 - cursor shape based on DECSCUSR (termconf_live.crlf_mode << 12) | - (scr.bracketed_paste << 13) + (scr.bracketed_paste << 13) | + (scr.reverse_video << 14) ); } @@ -1691,14 +1664,8 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) Color fg, bg; // Reverse fg and bg if we're in global reverse mode - if (! scr.reverse_video) { - fg = cell0->fg; - bg = cell0->bg; - } - else { - fg = cell0->bg; - bg = cell0->fg; - } + fg = cell0->fg; + bg = cell0->bg; if (changeColors) { bufput_t3B(SEQ_TAG_COLORS, bg<<8 | fg); @@ -1711,7 +1678,7 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) } if (changeAttrs) { - bufput_t2B(SEQ_TAG_ATTRS, cell0->attrs); + bufput_t3B(SEQ_TAG_ATTRS, cell0->attrs); } // copy the symbol, until first 0 or reached 4 bytes diff --git a/user/screen.h b/user/screen.h index c970927..37fc2cb 100644 --- a/user/screen.h +++ b/user/screen.h @@ -37,7 +37,7 @@ // Size designed for the terminal config structure // Must be constant to avoid corrupting user config after upgrade #define TERMCONF_SIZE 300 -#define TERMCONF_VERSION 5 +#define TERMCONF_VERSION 0 #define TERM_BTN_LEN 10 #define TERM_BTN_MSG_LEN 10 @@ -77,8 +77,8 @@ enum CursorShape { typedef struct { u32 width; u32 height; - u8 default_bg; // should be the Color typedef, but this way the size is more explicit - u8 default_fg; + u32 default_bg; // 00-FFh - ANSI colors, (00:00:00-FF:FF:FF)+256 - True Color, 1<<24 + 256 - default from theme + u32 default_fg; char title[TERM_TITLE_LEN]; char btn[TERM_BTN_COUNT][TERM_BTN_LEN]; u8 theme; @@ -228,25 +228,32 @@ void screen_set_origin_mode(bool region_origin); // --- Graphic rendition setting --- -typedef uint8_t Color; // 0-16 - -#define ATTR_BOLD (1<<0) -#define ATTR_FAINT (1<<1) -#define ATTR_ITALIC (1<<2) -#define ATTR_UNDERLINE (1<<3) -#define ATTR_BLINK (1<<4) -#define ATTR_FRAKTUR (1<<5) -#define ATTR_STRIKE (1<<6) -#define ATTR_OVERLINE (1<<7) +typedef uint8_t Color; +typedef uint16_t CellAttrs; + +// TODO sort by the expected frequency of being set - so when we switch to utf-8 encoding for data fields, it uses fewer bytes +#define ATTR_BOLD (1<<0) //!< Bold font +#define ATTR_FAINT (1<<1) //!< Faint foreground color (reduced alpha) +#define ATTR_ITALIC (1<<2) //!< Italic font +#define ATTR_UNDERLINE (1<<3) //!< Underline decoration +#define ATTR_BLINK (1<<4) //!< Blinking +#define ATTR_FRAKTUR (1<<5) //!< Fraktur font (unicode substitution) +#define ATTR_STRIKE (1<<6) //!< Strike-through decoration +#define ATTR_OVERLINE (1<<7) //!< Over-line decoration +#define ATTR_FG (1<<8) //!< 1 if not using default background color (ignore cell bg) - color extension bit +#define ATTR_BG (1<<9) //!< 1 if not using default foreground color (ignore cell fg) - color extension bit +#define ATTR_INVERSE (1<<10) //!< Invert colors - this is useful so we can clear then with SGR manipulation commands /** Set cursor foreground color */ void screen_set_fg(Color color); /** Set cursor background coloor */ void screen_set_bg(Color color); +/** Set cursor foreground color to default */ +void screen_set_default_fg(void); +/** Set cursor background color to default */ +void screen_set_default_bg(void); /** Enable/disable attrs by bitmask */ -void screen_set_sgr(u8 attrs, bool ena); -/** Set the inverse attribute */ -void screen_set_sgr_inverse(bool ena); +void screen_set_sgr(CellAttrs attrs, bool ena); /** Conceal style */ void screen_set_sgr_conceal(bool ena); /** Reset cursor attribs */ diff --git a/user/syscfg.c b/user/syscfg.c index f9004da..418dc85 100644 --- a/user/syscfg.c +++ b/user/syscfg.c @@ -13,19 +13,10 @@ void ICACHE_FLASH_ATTR sysconf_apply_settings(void) { bool changed = false; - if (sysconf->config_version < 1) { - dbg("Upgrading syscfg to v 1"); - sysconf->access_pw[0] = 0; - sysconf->pwlock = PWLOCK_NONE; - changed = true; - } - - if (sysconf->config_version < 2) { - dbg("Upgrading syscfg to v 2"); - strcpy(sysconf->access_pw, DEF_ACCESS_PW); - strcpy(sysconf->access_name, DEF_ACCESS_NAME); - changed = true; - } +// if (sysconf->config_version < 1) { +// dbg("Upgrading syscfg to v 1"); +// changed = true; +// } sysconf->config_version = SYSCONF_VERSION; @@ -45,4 +36,6 @@ 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); } diff --git a/user/syscfg.h b/user/syscfg.h index 359e0c9..8f1101d 100644 --- a/user/syscfg.h +++ b/user/syscfg.h @@ -10,7 +10,7 @@ // Size designed for the wifi config structure // Must be constant to avoid corrupting user config after upgrade #define SYSCONF_SIZE 300 -#define SYSCONF_VERSION 2 +#define SYSCONF_VERSION 0 #define DEF_ACCESS_PW "1234" #define DEF_ACCESS_NAME "espterm" From 692b2c4d11e2a0d6d06e8733f515d9eea8d3726d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 24 Sep 2017 00:17:58 +0200 Subject: [PATCH 20/29] fix serializer being completely broken --- user/screen.c | 75 +++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/user/screen.c b/user/screen.c index 5fa1d2e..97ef6b9 100644 --- a/user/screen.c +++ b/user/screen.c @@ -8,6 +8,7 @@ #include "jstring.h" #include "character_sets.h" #include "utf8.h" +#include "uart_buffer.h" TerminalConfigBundle * const termconf = &persist.current.termconf; TerminalConfigBundle termconf_live; @@ -1565,58 +1566,46 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) } Cell *cell, *cell0; - WordB2 w1; - WordB3 lw1; + u8 nbytes; size_t remain = buf_len; char *bb = buffer; #define bufput_c(c) do { \ - *bb = (char)c; bb++; \ + *bb = (char)(c); \ + bb++; \ remain--; \ } while(0) -#define bufput_2B(n) do { \ - encode2B((u16) n, &w1); \ - bufput_c(w1.lsb); \ - bufput_c(w1.msb); \ - } while(0) - -#define bufput_3B(n) do { \ - encode3B((u32) n, &lw1); \ - bufput_c(lw1.lsb); \ - bufput_c(lw1.msb); \ - bufput_c(lw1.xsb); \ - } while(0) - -#define bufput_t2B(t, n) do { \ - bufput_c(t); \ - bufput_2B(n); \ - } while(0) +#define bufput_utf8(num) do { \ + nbytes = utf8_encode(bb, (num)+1); \ + bb += nbytes; \ + remain -= nbytes; \ + } while(0) -#define bufput_t3B(t, n) do { \ - bufput_c(t); \ - bufput_3B(n); \ - } while(0) +#define bufput_t_utf8(t, num) do { \ + bufput_c((t)); \ + bufput_utf8((num)); \ + } while(0) if (ss == NULL) { *data = ss = malloc(sizeof(struct ScreenSerializeState)); ss->index = 0; - ss->lastBg = 0; - ss->lastFg = 0; - ss->lastAttrs = 0; + ss->lastBg = 0xFF; + ss->lastFg = 0xFF; + ss->lastAttrs = 0xFFFF; ss->lastCharLen = 0; - ss->lastSymbol = 32; + ss->lastSymbol = 0; strncpy(ss->lastChar, " ", 4); bufput_c('S'); // H W X Y Attribs - bufput_2B(H); - bufput_2B(W); - bufput_2B(cursor.y); - bufput_2B(cursor.x); + bufput_utf8(H); + bufput_utf8(W); + bufput_utf8(cursor.y); + bufput_utf8(cursor.x); // 3B has 18 free bits - bufput_3B( + bufput_utf8( (scr.cursor_visible << 0) | (cursor.hanging << 1) | (scr.cursors_alt_mode << 2) | @@ -1656,7 +1645,7 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) } if (repCnt == 0) { - // No repeat + // No repeat - first occurrence bool changeAttrs = cell0->attrs != ss->lastAttrs; bool changeFg = cell0->fg != ss->lastFg; bool changeBg = cell0->bg != ss->lastBg; @@ -1668,17 +1657,17 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) bg = cell0->bg; if (changeColors) { - bufput_t3B(SEQ_TAG_COLORS, bg<<8 | fg); + bufput_t_utf8(SEQ_TAG_COLORS, bg<<8 | fg); } else if (changeFg) { - bufput_t2B(SEQ_TAG_FG, fg); + bufput_t_utf8(SEQ_TAG_FG, fg); } else if (changeBg) { - bufput_t2B(SEQ_TAG_BG, bg); + bufput_t_utf8(SEQ_TAG_BG, bg); } if (changeAttrs) { - bufput_t3B(SEQ_TAG_ATTRS, cell0->attrs); + bufput_t_utf8(SEQ_TAG_ATTRS, cell0->attrs); } // copy the symbol, until first 0 or reached 4 bytes @@ -1703,7 +1692,7 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) int savings = ss->lastCharLen*repCnt; if (savings > 3) { // Repeat count - bufput_t2B(SEQ_TAG_REPEAT, repCnt); + bufput_t_utf8(SEQ_TAG_REPEAT, repCnt); } else { // repeat it manually for(int k = 0; k < repCnt; k++) { @@ -1718,6 +1707,14 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) ss->index = i; bufput_c('\0'); // terminate the string +#if 0 + printf("MSG: "); + for (int j=0;j Date: Sun, 24 Sep 2017 03:02:28 +0200 Subject: [PATCH 21/29] removed obsolete microoptimization from parser repeat code --- user/cgi_main.c | 4 ++-- user/screen.c | 13 +------------ user/screen.h | 2 +- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/user/cgi_main.c b/user/cgi_main.c index e24e872..f2f6977 100644 --- a/user/cgi_main.c +++ b/user/cgi_main.c @@ -38,11 +38,11 @@ httpd_cgi_state ICACHE_FLASH_ATTR tplScreen(HttpdConnData *connData, char *token tplSend(connData, buff, -1); } else if (streq(token, "default_fg")) { - sprintf(buff, "0x%08X", termconf->default_fg); + sprintf(buff, "%d", termconf->default_fg); tplSend(connData, buff, -1); } else if (streq(token, "default_bg")) { - sprintf(buff, "0x%08X", termconf->default_bg); + sprintf(buff, "%d", termconf->default_bg); tplSend(connData, buff, -1); } diff --git a/user/screen.c b/user/screen.c index 97ef6b9..da235e6 100644 --- a/user/screen.c +++ b/user/screen.c @@ -1689,18 +1689,7 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) i++; } else { // last character was repeated repCnt times - int savings = ss->lastCharLen*repCnt; - if (savings > 3) { - // Repeat count - bufput_t_utf8(SEQ_TAG_REPEAT, repCnt); - } else { - // repeat it manually - for(int k = 0; k < repCnt; k++) { - for (int j = 0; j < ss->lastCharLen; j++) { - bufput_c(ss->lastChar[j]); - } - } - } + bufput_t_utf8(SEQ_TAG_REPEAT, repCnt); } } diff --git a/user/screen.h b/user/screen.h index 37fc2cb..66b3b01 100644 --- a/user/screen.h +++ b/user/screen.h @@ -77,7 +77,7 @@ enum CursorShape { typedef struct { u32 width; u32 height; - u32 default_bg; // 00-FFh - ANSI colors, (00:00:00-FF:FF:FF)+256 - True Color, 1<<24 + 256 - default from theme + 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]; From 62a0925586654c718bedd1945a77e0063319fb1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 24 Sep 2017 14:17:41 +0200 Subject: [PATCH 22/29] fix stuff not removed from utf cache in some operations --- user/screen.c | 208 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 134 insertions(+), 74 deletions(-) diff --git a/user/screen.c b/user/screen.c index da235e6..4543a2b 100644 --- a/user/screen.c +++ b/user/screen.c @@ -60,8 +60,8 @@ static struct { char last_char[4]; } scr; -#define R0 scr.vm0 -#define R1 scr.vm1 +#define TOP scr.vm0 +#define BTM scr.vm1 #define RH (scr.vm1 - scr.vm0 + 1) // horizontal edges - will be useful if horizontal margin is implemented //#define C0 0 @@ -154,7 +154,7 @@ static volatile int notifyLock = 0; if (cursor.hanging && cursor.x != W-1) cursor.hanging = false; \ } while(false) -#define cursor_inside_region() (cursor.y >= R0 && cursor.y <= R1) +#define cursor_inside_region() (cursor.y >= TOP && cursor.y <= BTM) //region --- Settings --- @@ -547,7 +547,7 @@ screen_tab_reverse(int count) * Clear range, inclusive */ static void ICACHE_FLASH_ATTR -clear_range(unsigned int from, unsigned int to) +clear_range_do(unsigned int from, unsigned int to, bool clear_utf) { if (to >= W*H) to = W*H-1; @@ -560,11 +560,69 @@ clear_range(unsigned int from, unsigned int to) for (unsigned int i = from; i <= to; i++) { UnicodeCacheRef symbol = screen[i].symbol; - if (IS_UNICODE_CACHE_REF(symbol)) unicode_cache_remove(symbol); + if (clear_utf && IS_UNICODE_CACHE_REF(symbol)) unicode_cache_remove(symbol); memcpy(&screen[i], &sample, sizeof(Cell)); } } +/** + * Clear range, inclusive + */ +static inline void ICACHE_FLASH_ATTR +clear_range_utf(unsigned int from, unsigned int to) +{ + clear_range_do(from, to, true); +} + +/** + * Clear range, inclusive. Do not release utf characters + */ +static inline void ICACHE_FLASH_ATTR +clear_range_noutf(unsigned int from, unsigned int to) +{ + clear_range_do(from, to, false); +} + +static inline void ICACHE_FLASH_ATTR +utf_free_cell(int row, int i) +{ + UnicodeCacheRef symbol = screen[row * W + i].symbol; + if (IS_UNICODE_CACHE_REF(symbol)) + unicode_cache_remove(symbol); +} + +static inline void ICACHE_FLASH_ATTR +utf_free_row(int r) +{ + for (int i = 0; i < W; i++) { + utf_free_cell(r, i); + } +} + +static inline void ICACHE_FLASH_ATTR +copy_row(int dest, int src) +{ + memcpy(screen + dest * W, screen + src * W, sizeof(Cell) * W); +} + +static inline void ICACHE_FLASH_ATTR +copy_cell(int row, int dest_col, int src_col) +{ + memcpy(screen+row*W+dest_col, screen+row*W+src_col, sizeof(Cell)); +} + +static inline void ICACHE_FLASH_ATTR +clear_row_noutf(int r) +{ + clear_range_noutf(r * W, (r + 1) * W - 1); +} + +static inline void ICACHE_FLASH_ATTR +clear_row_utf(int r) +{ + clear_range_utf(r * W, (r + 1) * W - 1); +} + /** * Clear screen area */ @@ -575,15 +633,15 @@ screen_clear(ClearMode mode) NOTIFY_LOCK(); switch (mode) { case CLEAR_ALL: - clear_range(0, W * H - 1); + clear_range_utf(0, W * H - 1); break; case CLEAR_FROM_CURSOR: - clear_range((cursor.y * W) + cursor.x, W * H - 1); + clear_range_utf((cursor.y * W) + cursor.x, W * H - 1); break; case CLEAR_TO_CURSOR: - clear_range(0, (cursor.y * W) + cursor.x); + clear_range_utf(0, (cursor.y * W) + cursor.x); break; } NOTIFY_DONE(); @@ -598,15 +656,15 @@ screen_clear_line(ClearMode mode) NOTIFY_LOCK(); switch (mode) { case CLEAR_ALL: - clear_range(cursor.y * W, (cursor.y + 1) * W - 1); + clear_row_utf(cursor.y); break; case CLEAR_FROM_CURSOR: - clear_range(cursor.y * W + cursor.x, (cursor.y + 1) * W - 1); + clear_range_utf(cursor.y * W + cursor.x, (cursor.y + 1) * W - 1); break; case CLEAR_TO_CURSOR: - clear_range(cursor.y * W, cursor.y * W + cursor.x); + clear_range_utf(cursor.y * W, cursor.y * W + cursor.x); break; } NOTIFY_DONE(); @@ -615,14 +673,13 @@ screen_clear_line(ClearMode mode) void ICACHE_FLASH_ATTR screen_clear_in_line(unsigned int count) { + NOTIFY_LOCK(); if (cursor.x + count >= W) { screen_clear_line(CLEAR_FROM_CURSOR); + } else { + clear_range_utf(cursor.y * W + cursor.x, cursor.y * W + cursor.x + count - 1); } - else { - NOTIFY_LOCK(); - clear_range(cursor.y * W + cursor.x, cursor.y * W + cursor.x + count - 1); - NOTIFY_DONE(); - } + NOTIFY_DONE(); } void ICACHE_FLASH_ATTR @@ -631,24 +688,23 @@ screen_insert_lines(unsigned int lines) if (!cursor_inside_region()) return; // can't insert if not inside region NOTIFY_LOCK(); - // FIXME remove cleared & overwritten cells from unicode cache! - // shift the following lines int targetStart = cursor.y + lines; - if (targetStart > R1) { - targetStart = R1-1; + if (targetStart > BTM) { + targetStart = BTM - 1; } else { // do the moving - for (int i = R1; i >= targetStart; i--) { - memcpy(screen+i*W, screen+(i-lines)*W, sizeof(Cell)*W); + for (int i = BTM; i >= targetStart; i--) { + utf_free_row(i); // release old characters + copy_row(i, i - lines); } } // clear the first line - screen_clear_line(CLEAR_ALL); + clear_row_noutf(CLEAR_ALL); // copy it to the rest of the cleared region for (int i = cursor.y+1; i < targetStart; i++) { - memcpy(screen+i*W, screen+cursor.y*W, sizeof(Cell)*W); + copy_row(i, cursor.y); } NOTIFY_DONE(); } @@ -659,21 +715,21 @@ screen_delete_lines(unsigned int lines) if (!cursor_inside_region()) return; // can't delete if not inside region NOTIFY_LOCK(); - // FIXME remove cleared & overwritten cells from unicode cache! - // shift lines up - int targetEnd = R1 - lines - 1; + int targetEnd = BTM - lines - 1; if (targetEnd <= cursor.y) { + // clear the entire rest of the screen targetEnd = cursor.y; + clear_range_utf(targetEnd * W, W * BTM); } else { - // do the moving + // move some lines up, clear the rest for (int i = cursor.y; i <= targetEnd; i++) { - memcpy(screen+i*W, screen+(i+lines)*W, sizeof(Cell)*W); + utf_free_row(i); + copy_row(i, i+lines); } + clear_range_noutf(targetEnd*W, W*BTM); } - // clear the rest - clear_range(targetEnd*W, W*R1); NOTIFY_DONE(); } @@ -682,19 +738,21 @@ screen_insert_characters(unsigned int count) { NOTIFY_LOCK(); - // FIXME remove cleared & overwritten cells from unicode cache! + // shove rest of the line to the right int targetStart = cursor.x + count; if (targetStart >= W) { + // all rest of line was cleared targetStart = W-1; + clear_range_utf(cursor.y * W + cursor.x, cursor.y * W + targetStart - 1); } else { // do the moving for (int i = W-1; i >= targetStart; i--) { - memcpy(screen+cursor.y*W+i, screen+cursor.y*W+(i-count), sizeof(Cell)); + utf_free_cell(cursor.y, i); + copy_cell(cursor.y, i, i - count); } + clear_range_noutf(cursor.y * W + cursor.x, cursor.y * W + targetStart - 1); } - - clear_range(cursor.y*W+cursor.x, cursor.y*W+targetStart-1); NOTIFY_DONE(); } @@ -703,21 +761,23 @@ screen_delete_characters(unsigned int count) { NOTIFY_LOCK(); - // FIXME remove cleared & overwritten cells from unicode cache! - int targetEnd = W - count; - if (targetEnd > cursor.x) { - // do the moving - for (int i = cursor.x; i <= targetEnd; i++) { - memcpy(screen+cursor.y*W+i, screen+cursor.y*W+(i+count), sizeof(Cell)); - } - } + // pull rest of the line to the left + + int movedBlockEnd = W - count; + if (movedBlockEnd > cursor.x) { + // partial line delete / move - if (targetEnd <= cursor.x) { + for (int i = cursor.x; i <= movedBlockEnd; i++) { + utf_free_cell(cursor.y, i); + copy_cell(cursor.y, i, i + count); + } + // clear original positions of the moved characters + clear_range_utf(cursor.y * W + (W - count), (cursor.y + 1) * W - 1); + } else { + // all rest was cleared screen_clear_line(CLEAR_FROM_CURSOR); } - else { - clear_range(cursor.y * W + (W - count), (cursor.y + 1) * W - 1); - } + NOTIFY_DONE(); } //endregion @@ -798,7 +858,8 @@ screen_scroll_up(unsigned int lines) { NOTIFY_LOCK(); if (lines >= RH) { - clear_range(R0*W, (R1+1)*W-1); + // clear entire region + clear_range_utf(TOP * W, (BTM + 1) * W - 1); goto done; } @@ -807,16 +868,15 @@ screen_scroll_up(unsigned int lines) goto done; } - // FIXME remove cleared & overwritten cells from unicode cache! - int y; - for (y = R0; y <= R1 - lines; y++) { - memcpy(screen + y * W, screen + (y + lines) * W, W * sizeof(Cell)); + for (y = TOP; y <= BTM - lines; y++) { + utf_free_row(y); + copy_row(y, y+lines); } - clear_range(y * W, (R1+1)*W-1); + clear_range_noutf(y * W, (BTM + 1) * W - 1); - done: +done: NOTIFY_DONE(); } @@ -828,24 +888,24 @@ screen_scroll_down(unsigned int lines) { NOTIFY_LOCK(); if (lines >= RH) { - clear_range(R0*W, (R1+1)*W-1); + // clear entire region + clear_range_utf(TOP * W, (BTM + 1) * W - 1); goto done; } - // FIXME remove cleared & overwritten cells from unicode cache! - // bad cmd if (lines == 0) { goto done; } int y; - for (y = R1; y >= R0+lines; y--) { - memcpy(screen + y * W, screen + (y - lines) * W, W * sizeof(Cell)); + for (y = BTM; y >= TOP+lines; y--) { + utf_free_row(y); + copy_row(y, y-lines); } - clear_range(R0*W, R0*W+ lines * W-1); - done: + clear_range_noutf(TOP * W, TOP * W + lines * W - 1); +done: NOTIFY_DONE(); } @@ -921,7 +981,7 @@ screen_cursor_get(int *y, int *x) *y = cursor.y; if (cursor.origin_mode) { - *y -= R0; + *y -= TOP; } } @@ -950,9 +1010,9 @@ screen_cursor_set_y(int y) { NOTIFY_LOCK(); if (cursor.origin_mode) { - y += R0; - if (y > R1) y = R1; - if (y < R0) y = R0; + y += TOP; + if (y > BTM) y = BTM; + if (y < TOP) y = TOP; } else { if (y > H-1) y = H-1; if (y < 0) y = 0; @@ -1001,7 +1061,7 @@ screen_cursor_move(int dy, int dx, bool scroll) } else { // end of screen, end of line (wrap around) - cursor.y = R1; + cursor.y = BTM; cursor.x = W - 1; } } @@ -1011,10 +1071,10 @@ screen_cursor_move(int dy, int dx, bool scroll) } } - if (cursor.y < R0) { + if (cursor.y < TOP) { if (was_inside) { - move = -(cursor.y - R0); - cursor.y = R0; + move = -(cursor.y - TOP); + cursor.y = TOP; if (scroll) screen_scroll_down((unsigned int) move); } else { @@ -1026,10 +1086,10 @@ screen_cursor_move(int dy, int dx, bool scroll) } } - if (cursor.y > R1) { + if (cursor.y > BTM) { if (was_inside) { - move = cursor.y - R1; - cursor.y = R1; + move = cursor.y - BTM; + cursor.y = BTM; if (scroll) screen_scroll_up((unsigned int) move); } else { @@ -1360,10 +1420,10 @@ putchar_graphic(const char *ch) cursor.x = 0; cursor.y++; // Y wrap - if (cursor.y > R1) { + if (cursor.y > BTM) { // Scroll up, so we have space for writing screen_scroll_up(1); - cursor.y = R1; + cursor.y = BTM; } cursor.hanging = false; From 674e89c8c37deedc5d7bd888b0d1464d2123888a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 24 Sep 2017 14:57:10 +0200 Subject: [PATCH 23/29] fix a bug with backspace when cursor is hanging --- front-end | 2 +- user/screen.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/front-end b/front-end index 6c64248..c68017b 160000 --- a/front-end +++ b/front-end @@ -1 +1 @@ -Subproject commit 6c6424877c49e3e23f563067a78e79338226359d +Subproject commit c68017bd4ad387786dd17b213be9bdd29fe4c0ea diff --git a/user/screen.c b/user/screen.c index 4543a2b..b753d59 100644 --- a/user/screen.c +++ b/user/screen.c @@ -1033,7 +1033,7 @@ screen_cursor_move(int dy, int dx, bool scroll) clear_invalid_hanging(); if (cursor.hanging && dx < 0) { - dx += 1; // consume one step on the removal of "xenl" + //dx += 1; // consume one step on the removal of "xenl" cursor.hanging = false; } From 7eb1bdeec6d6bce11c5a2498125d19776d2ec36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 24 Sep 2017 18:16:21 +0200 Subject: [PATCH 24/29] fixed off-by one etc errors in the rewritten functions, fixed a lag due to heartbeat packet --- esphttpdconfig.mk | 16 +++--- user/cgi_sockets.c | 27 +++++++--- user/screen.c | 123 +++++++++++++++++++++++++++++++++++---------- user/utf8.c | 33 ++++++++++-- user/utf8.h | 8 +++ 5 files changed, 162 insertions(+), 45 deletions(-) diff --git a/esphttpdconfig.mk b/esphttpdconfig.mk index d8b6237..aa46aeb 100644 --- a/esphttpdconfig.mk +++ b/esphttpdconfig.mk @@ -39,15 +39,15 @@ OUTPUT_TYPE = combined ESP_SPI_FLASH_SIZE_K = 1024 GLOBAL_CFLAGS = \ - -DDEBUG_ROUTER=0 \ - -DDEBUG_CAPTDNS=0 \ - -DDEBUG_HTTP=0 \ - -DDEBUG_ESPFS=0 \ - -DDEBUG_PERSIST=0 \ - -DDEBUG_UTFCACHE=0 \ + -DDEBUG_ROUTER=1 \ + -DDEBUG_CAPTDNS=1 \ + -DDEBUG_HTTP=1 \ + -DDEBUG_ESPFS=1 \ + -DDEBUG_PERSIST=1 \ + -DDEBUG_UTFCACHE=1 \ -DDEBUG_CGI=0 \ -DDEBUG_WIFI=0 \ - -DDEBUG_WS=0 \ + -DDEBUG_WS=1 \ -DDEBUG_ANSI=1 \ -DDEBUG_ANSI_NOIMPL=1 \ -DDEBUG_INPUT=0 \ @@ -56,6 +56,6 @@ GLOBAL_CFLAGS = \ -DHTTPD_MAX_BACKLOG_SIZE=8192 \ -DHTTPD_MAX_HEAD_LEN=1024 \ -DHTTPD_MAX_POST_LEN=512 \ - -DDEBUG_LOGBUF_SIZE=1024 \ + -DDEBUG_LOGBUF_SIZE=2048 \ -mforce-l32 \ -DUSE_OPTIMIZE_PRINTF=1 diff --git a/user/cgi_sockets.c b/user/cgi_sockets.c index f3adcb8..9c7fac9 100644 --- a/user/cgi_sockets.c +++ b/user/cgi_sockets.c @@ -35,6 +35,8 @@ volatile int active_clients = 0; // this might glitch, very rarely. // it's recommended to put some delay between setting labels and updating the screen. +static void resetHeartbeatTimer(void); + /** * Cooldown delay is over * @param arg @@ -66,6 +68,8 @@ notifyContentTimCb(void *arg) } notify_available = false; + resetHeartbeatTimer(); + for (int i = 0; i < 20; i++) { httpd_cgi_state cont = screenSerializeToBuffer(sock_buff, SOCK_BUF_LEN, &data); int flg = 0; @@ -108,6 +112,7 @@ notifyLabelsTimCb(void *arg) screenSerializeLabelsToBuffer(sock_buff, SOCK_BUF_LEN); cgiWebsockBroadcast(URL_WS_UPDATE, sock_buff, (int) strlen(sock_buff), 0); + resetHeartbeatTimer(); notify_cooldown = true; notify_available = true; @@ -123,6 +128,7 @@ send_beep(void) // here's some potential for a race error with the other broadcast functions :C cgiWebsockBroadcast(URL_WS_UPDATE, "B", 1, 0); + resetHeartbeatTimer(); } @@ -135,6 +141,7 @@ notify_growl(char *msg) // TODO via timer... // here's some potential for a race error with the other broadcast functions :C cgiWebsockBroadcast(URL_WS_UPDATE, msg, (int) strlen(msg), 0); + resetHeartbeatTimer(); } @@ -170,7 +177,7 @@ void ICACHE_FLASH_ATTR screen_notifyChange(ScreenNotifyChangeTopic topic) * @param button - which button, 1-based. 0=none * @param mods - modifier keys bitmap: meta|alt|shift|ctrl */ -void ICACHE_FLASH_ATTR sendMouseAction(char evt, int y, int x, int button, u8 mods) +static void ICACHE_FLASH_ATTR sendMouseAction(char evt, int y, int x, int button, u8 mods) { // one-based x++; @@ -239,7 +246,7 @@ void ICACHE_FLASH_ATTR sendMouseAction(char evt, int y, int x, int button, u8 mo } /** Socket received a message */ -void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int flags) +static void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int flags) { // Add terminator if missing (seems to randomly happen) data[len] = 0; @@ -304,7 +311,7 @@ void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int flags) } /** Send a heartbeat msg */ -void ICACHE_FLASH_ATTR heartbeatTimCb(void *unused) +static void ICACHE_FLASH_ATTR heartbeatTimCb(void *unused) { if (notify_available && active_clients > 0) { // Heartbeat packet - indicate we're still connected @@ -313,7 +320,13 @@ void ICACHE_FLASH_ATTR heartbeatTimCb(void *unused) } } -void ICACHE_FLASH_ATTR closeSockCb(Websock *ws) +static void ICACHE_FLASH_ATTR resetHeartbeatTimer(void) +{ + TIMER_START(&heartbeatTim, heartbeatTimCb, HB_TIME, 1); +} + + +static void ICACHE_FLASH_ATTR closeSockCb(Websock *ws) { active_clients--; if (active_clients <= 0) { @@ -340,7 +353,7 @@ void ICACHE_FLASH_ATTR updateSockConnect(Websock *ws) UART_SendAsync("\x1b[I", 3); } - TIMER_START(&heartbeatTim, heartbeatTimCb, HB_TIME, 1); + resetHeartbeatTimer(); } active_clients++; @@ -348,14 +361,14 @@ void ICACHE_FLASH_ATTR updateSockConnect(Websock *ws) ETSTimer xonTim; -void ICACHE_FLASH_ATTR notify_empty_txbuf_cb(void *unused) +static void ICACHE_FLASH_ATTR notify_empty_txbuf_cb(void *unused) { UART_WriteChar(UART1, '+', 100); cgiWebsockBroadcast(URL_WS_UPDATE, "+", 1, 0); + resetHeartbeatTimer(); browser_wants_xon = false; } - void notify_empty_txbuf(void) { if (browser_wants_xon) { diff --git a/user/screen.c b/user/screen.c index b753d59..057897b 100644 --- a/user/screen.c +++ b/user/screen.c @@ -545,6 +545,10 @@ screen_tab_reverse(int count) /** * Clear range, inclusive + * + * @param from - starting absolute position + * @param to - ending absolute position + * @param clear_utf - release any encountered utf8 */ static void ICACHE_FLASH_ATTR clear_range_do(unsigned int from, unsigned int to, bool clear_utf) @@ -566,7 +570,10 @@ clear_range_do(unsigned int from, unsigned int to, bool clear_utf) } /** - * Clear range, inclusive + * Clear range, inclusive, freeing any encountered UTF8 from the cache + * + * @param from - starting absolute position + * @param to - ending absolute position */ static inline void ICACHE_FLASH_ATTR clear_range_utf(unsigned int from, unsigned int to) @@ -576,6 +583,9 @@ clear_range_utf(unsigned int from, unsigned int to) /** * Clear range, inclusive. Do not release utf characters + * + * @param from - starting absolute position + * @param to - ending absolute position */ static inline void ICACHE_FLASH_ATTR clear_range_noutf(unsigned int from, unsigned int to) @@ -583,44 +593,105 @@ clear_range_noutf(unsigned int from, unsigned int to) clear_range_do(from, to, false); } +/** + * Free a utf8 reference character in a cell + * + * @param row + * @param col + */ static inline void ICACHE_FLASH_ATTR -utf_free_cell(int row, int i) +utf_free_cell(int row, int col) { - UnicodeCacheRef symbol = screen[row * W + i].symbol; + UnicodeCacheRef symbol = screen[row * W + col].symbol; if (IS_UNICODE_CACHE_REF(symbol)) unicode_cache_remove(symbol); } +/** + * Back-up utf8 reference in a cell (i.e. increment the counter, + * so 1 subsequent free has no effect) + * + * @param row + * @param col + */ +static inline void ICACHE_FLASH_ATTR +utf_backup_cell(int row, int col) +{ + UnicodeCacheRef symbol = screen[row * W + col].symbol; + if (IS_UNICODE_CACHE_REF(symbol)) + unicode_cache_inc(symbol); +} + +/** + * Free all utf8 on a row + * + * @param row + */ static inline void ICACHE_FLASH_ATTR -utf_free_row(int r) +utf_free_row(int row) { - for (int i = 0; i < W; i++) { - utf_free_cell(r, i); + for (int col = 0; col < W; col++) { + utf_free_cell(row, col); } } +/** + * Back-up all utf8 refs on a row + * + * @param row + */ +static inline void ICACHE_FLASH_ATTR +utf_backup_row(int row) +{ + for (int col = 0; col < W; col++) { + utf_backup_cell(row, col); + } +} + +/** + * Duplicate a row + * + * @param dest - destination row number (0-based) + * @param src - source row number (0-based) + */ static inline void ICACHE_FLASH_ATTR copy_row(int dest, int src) { memcpy(screen + dest * W, screen + src * W, sizeof(Cell) * W); } +/** + * Duplicate a cell within a row + * @param row - row to work on + * @param dest_col - destination column + * @param src_col - source column + */ static inline void ICACHE_FLASH_ATTR copy_cell(int row, int dest_col, int src_col) { memcpy(screen+row*W+dest_col, screen+row*W+src_col, sizeof(Cell)); } +/** + * Clear a row, do nothing with the utf8 cache + * + * @param row + */ static inline void ICACHE_FLASH_ATTR -clear_row_noutf(int r) +clear_row_noutf(int row) { - clear_range_noutf(r * W, (r + 1) * W - 1); + clear_range_noutf(row * W, (row + 1) * W - 1); } +/** + * Clear a row, freeing any utf8 refs + * + * @param row + */ static inline void ICACHE_FLASH_ATTR -clear_row_utf(int r) +clear_row_utf(int row) { - clear_range_utf(r * W, (r + 1) * W - 1); + clear_range_utf(row * W, (row + 1) * W - 1); } /** @@ -633,7 +704,8 @@ screen_clear(ClearMode mode) NOTIFY_LOCK(); switch (mode) { case CLEAR_ALL: - clear_range_utf(0, W * H - 1); + clear_range_noutf(0, W * H - 1); + unicode_cache_clear(); break; case CLEAR_FROM_CURSOR: @@ -691,20 +763,20 @@ screen_insert_lines(unsigned int lines) // shift the following lines int targetStart = cursor.y + lines; if (targetStart > BTM) { - targetStart = BTM - 1; + clear_range_utf(cursor.y*W, (BTM+1)*W-1); } else { // do the moving for (int i = BTM; i >= targetStart; i--) { utf_free_row(i); // release old characters copy_row(i, i - lines); } - } - // clear the first line - clear_row_noutf(CLEAR_ALL); - // copy it to the rest of the cleared region - for (int i = cursor.y+1; i < targetStart; i++) { - copy_row(i, cursor.y); + // clear the first line + clear_row_noutf(cursor.y); + // copy it to the rest of the cleared region + for (int i = cursor.y+1; i < targetStart; i++) { + copy_row(i, cursor.y); + } } NOTIFY_DONE(); } @@ -716,18 +788,18 @@ screen_delete_lines(unsigned int lines) NOTIFY_LOCK(); // shift lines up - int targetEnd = BTM - lines - 1; - if (targetEnd <= cursor.y) { + int movedBlockEnd = BTM - lines ; + if (movedBlockEnd <= cursor.y) { // clear the entire rest of the screen - targetEnd = cursor.y; - clear_range_utf(targetEnd * W, W * BTM); + movedBlockEnd = cursor.y; + clear_range_utf(movedBlockEnd*W, W * BTM); } else { // move some lines up, clear the rest - for (int i = cursor.y; i <= targetEnd; i++) { + for (int i = cursor.y; i <= movedBlockEnd; i++) { utf_free_row(i); copy_row(i, i+lines); } - clear_range_noutf(targetEnd*W, W*BTM); + clear_range_noutf((movedBlockEnd+1)*W, (BTM+1)*W-1); } NOTIFY_DONE(); @@ -743,8 +815,7 @@ screen_insert_characters(unsigned int count) int targetStart = cursor.x + count; if (targetStart >= W) { // all rest of line was cleared - targetStart = W-1; - clear_range_utf(cursor.y * W + cursor.x, cursor.y * W + targetStart - 1); + clear_range_utf(cursor.y * W + cursor.x, (cursor.y + 1) * W - 1); } else { // do the moving for (int i = W-1; i >= targetStart; i--) { diff --git a/user/utf8.c b/user/utf8.c index bc67de0..3d4c693 100644 --- a/user/utf8.c +++ b/user/utf8.c @@ -20,7 +20,8 @@ static UnicodeCacheSlot cache[UNICODE_CACHE_SIZE]; * @return */ void ICACHE_FLASH_ATTR -unicode_cache_clear(void) { +unicode_cache_clear(void) +{ utfc_dbg("utf8 cache clear!"); for (int slot = 0; slot < UNICODE_CACHE_SIZE; slot++) { cache[slot].count=0; @@ -35,7 +36,8 @@ unicode_cache_clear(void) { * @return the obtained look-up reference */ UnicodeCacheRef ICACHE_FLASH_ATTR -unicode_cache_add(const u8 *bytes) { +unicode_cache_add(const u8 *bytes) +{ if (bytes[0] < 32) { utfc_warn("utf8 cache bad char '%c'", bytes[0]); return '?'; @@ -69,6 +71,27 @@ unicode_cache_add(const u8 *bytes) { return ID_TO_REF(slot); } +/** + * Increment a reference + * + * @param ref - reference + * @return success + */ +bool ICACHE_FLASH_ATTR +unicode_cache_inc(UnicodeCacheRef ref) +{ + if (!IS_UNICODE_CACHE_REF(ref)) return true; // ASCII + + int slot = REF_TO_ID(ref); + if (cache[slot].count == 0) { + utfc_warn("utf8 cache inc-after-free ref @ %d", ref); + return false; + } + cache[slot].count++; + utfc_dbg("utf8 cache inc '%.4s' @ %d, %d uses", cache[slot].bytes, slot, cache[slot].count); + return true; +} + /** * Look up a code point in the cache by reference. Do not change the use counter. * @@ -77,7 +100,8 @@ unicode_cache_add(const u8 *bytes) { * @return true if the look-up succeeded */ bool ICACHE_FLASH_ATTR -unicode_cache_retrieve(UnicodeCacheRef ref, u8 *target) { +unicode_cache_retrieve(UnicodeCacheRef ref, u8 *target) +{ if (!IS_UNICODE_CACHE_REF(ref)) { // ASCII, bypass target[0] = ref; @@ -107,7 +131,8 @@ unicode_cache_retrieve(UnicodeCacheRef ref, u8 *target) { * @return true if the code point was found in the cache */ bool ICACHE_FLASH_ATTR -unicode_cache_remove(UnicodeCacheRef ref) { +unicode_cache_remove(UnicodeCacheRef ref) +{ if (!IS_UNICODE_CACHE_REF(ref)) return true; // ASCII, bypass u8 slot = REF_TO_ID(ref); diff --git a/user/utf8.h b/user/utf8.h index 81f9372..c24bf07 100644 --- a/user/utf8.h +++ b/user/utf8.h @@ -28,6 +28,14 @@ void unicode_cache_clear(void); */ UnicodeCacheRef unicode_cache_add(const u8 *bytes); +/** + * Increment a reference + * + * @param ref - reference + * @return success + */ +bool unicode_cache_inc(UnicodeCacheRef ref); + /** * Look up a code point in the cache by reference. Do not change the use counter. * From 58bd27a082aad8df180b84a096c21eeb3bc18606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 24 Sep 2017 20:19:40 +0200 Subject: [PATCH 25/29] FIXED A BUG --- esphttpdconfig.mk | 10 ++-- user/cgi_sockets.c | 48 ++++++++++++------ user/cgi_term_cfg.c | 8 +-- user/screen.c | 118 ++++++++++++++++++++++++++------------------ 4 files changed, 112 insertions(+), 72 deletions(-) diff --git a/esphttpdconfig.mk b/esphttpdconfig.mk index aa46aeb..6cf5552 100644 --- a/esphttpdconfig.mk +++ b/esphttpdconfig.mk @@ -39,11 +39,11 @@ OUTPUT_TYPE = combined ESP_SPI_FLASH_SIZE_K = 1024 GLOBAL_CFLAGS = \ - -DDEBUG_ROUTER=1 \ - -DDEBUG_CAPTDNS=1 \ - -DDEBUG_HTTP=1 \ - -DDEBUG_ESPFS=1 \ - -DDEBUG_PERSIST=1 \ + -DDEBUG_ROUTER=0 \ + -DDEBUG_CAPTDNS=0 \ + -DDEBUG_HTTP=0 \ + -DDEBUG_ESPFS=0 \ + -DDEBUG_PERSIST=0 \ -DDEBUG_UTFCACHE=1 \ -DDEBUG_CGI=0 \ -DDEBUG_WIFI=0 \ diff --git a/user/cgi_sockets.c b/user/cgi_sockets.c index 9c7fac9..b75c87f 100644 --- a/user/cgi_sockets.c +++ b/user/cgi_sockets.c @@ -63,13 +63,12 @@ notifyContentTimCb(void *arg) if (!notify_available || notify_cooldown || (max_bl > 2048)) { // do not send if we have anything significant backlogged // postpone a little - TIMER_START(¬ifyContentTim, notifyContentTimCb, 5, 0); + TIMER_START(¬ifyContentTim, notifyContentTimCb, 4, 0); + inp_dbg("postpone notify content"); return; } notify_available = false; - resetHeartbeatTimer(); - for (int i = 0; i < 20; i++) { httpd_cgi_state cont = screenSerializeToBuffer(sock_buff, SOCK_BUF_LEN, &data); int flg = 0; @@ -79,6 +78,7 @@ notifyContentTimCb(void *arg) cgiWebsocketSend(ws, sock_buff, (int) strlen(sock_buff), flg); } else { cgiWebsockBroadcast(URL_WS_UPDATE, sock_buff, (int) strlen(sock_buff), flg); + resetHeartbeatTimer(); } if (cont == HTTPD_CGI_DONE) break; @@ -101,18 +101,25 @@ notifyContentTimCb(void *arg) static void ICACHE_FLASH_ATTR notifyLabelsTimCb(void *arg) { + Websock *ws = arg; char sock_buff[SOCK_BUF_LEN]; if (!notify_available || notify_cooldown) { // postpone a little - TIMER_START(¬ifyLabelsTim, notifyLabelsTimCb, 1, 0); + TIMER_START(¬ifyLabelsTim, notifyLabelsTimCb, 7, 0); + inp_dbg("postpone notify labels"); return; } notify_available = false; screenSerializeLabelsToBuffer(sock_buff, SOCK_BUF_LEN); - cgiWebsockBroadcast(URL_WS_UPDATE, sock_buff, (int) strlen(sock_buff), 0); - resetHeartbeatTimer(); + + if (ws) { + cgiWebsocketSend(ws, sock_buff, (int) strlen(sock_buff), 0); + } else { + cgiWebsockBroadcast(URL_WS_UPDATE, sock_buff, (int) strlen(sock_buff), 0); + resetHeartbeatTimer(); + } notify_cooldown = true; notify_available = true; @@ -155,13 +162,14 @@ void ICACHE_FLASH_ATTR screen_notifyChange(ScreenNotifyChangeTopic topic) if (active_clients == 0) return; // this is probably not needed here - ensure timeout is not 0 - if (termconf->display_tout_ms == 0) termconf->display_tout_ms = SCR_DEF_DISPLAY_TOUT_MS; + if (termconf->display_tout_ms == 0) + termconf->display_tout_ms = SCR_DEF_DISPLAY_TOUT_MS; // NOTE: the timers are restarted if already running if (topic == CHANGE_LABELS) { // separate timer from content change timer, to avoid losing that update - TIMER_START(¬ifyLabelsTim, notifyLabelsTimCb, termconf->display_tout_ms, 0); + TIMER_START(¬ifyLabelsTim, notifyLabelsTimCb, termconf->display_tout_ms+2, 0); // this delay is useful when both are fired at once on screen reset } else if (topic == CHANGE_CONTENT) { // throttle delay @@ -288,7 +296,8 @@ static void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int case 'i': // requests initial load inp_dbg("Client requests initial load"); - notifyContentTimCb(ws); + notifyContentTimCb(ws); // delay?? + notifyLabelsTimCb(ws); break; case 'm': @@ -313,16 +322,27 @@ static void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int /** Send a heartbeat msg */ static void ICACHE_FLASH_ATTR heartbeatTimCb(void *unused) { - if (notify_available && active_clients > 0) { - // Heartbeat packet - indicate we're still connected - // JS reloads the page if heartbeat is lost for a couple seconds - cgiWebsockBroadcast(URL_WS_UPDATE, ".", 1, 0); + if (active_clients > 0) { + if (notify_available) { + inp_dbg("."); + + // Heartbeat packet - indicate we're still connected + // JS reloads the page if heartbeat is lost for a couple seconds + cgiWebsockBroadcast(URL_WS_UPDATE, ".", 1, 0); + + // schedule next tick + TIMER_START(&heartbeatTim, heartbeatTimCb, HB_TIME, 0); + } else { + // postpone... + TIMER_START(&heartbeatTim, heartbeatTimCb, 10, 0); + inp_dbg("postpone heartbeat"); + } } } static void ICACHE_FLASH_ATTR resetHeartbeatTimer(void) { - TIMER_START(&heartbeatTim, heartbeatTimCb, HB_TIME, 1); + TIMER_START(&heartbeatTim, heartbeatTimCb, HB_TIME, 0); } diff --git a/user/cgi_term_cfg.c b/user/cgi_term_cfg.c index 25da9f6..ffc0011 100644 --- a/user/cgi_term_cfg.c +++ b/user/cgi_term_cfg.c @@ -43,10 +43,10 @@ cgiTermCfgSetParams(HttpdConnData *connData) // width and height must always go together so we can do max size validation if (GET_ARG("term_width")) { - cgi_dbg("Default screen width: %s", buff); - w = atoi(buff); do { - if (w <= 1) { + 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; @@ -61,7 +61,7 @@ cgiTermCfgSetParams(HttpdConnData *connData) cgi_dbg("Default screen height: %s", buff); h = atoi(buff); - if (h <= 1) { + if (h < 1) { cgi_warn("Bad height: \"%s\"", buff); redir_url += sprintf(redir_url, "term_height,"); break; diff --git a/user/screen.c b/user/screen.c index 057897b..5adca49 100644 --- a/user/screen.c +++ b/user/screen.c @@ -248,18 +248,7 @@ screen_init(void) { if(DEBUG_HEAP) dbg("Screen buffer size = %d bytes", sizeof(screen)); - NOTIFY_LOCK(); - Cell sample; - sample.symbol = ' '; - sample.fg = 0; - sample.bg = 0; - sample.attrs = 0; // use default colors - for (unsigned int i = 0; i < MAX_SCREEN_SIZE; i++) { - memcpy(&screen[i], &sample, sizeof(Cell)); - } - screen_reset(); - NOTIFY_DONE(); } /** @@ -288,16 +277,13 @@ screen_reset_on_resize(void) ansi_dbg("Screen partial reset due to resize"); NOTIFY_LOCK(); - cursor.x = 0; - cursor.y = 0; - cursor.hanging = false; + cursor_reset(); scr.vm0 = 0; scr.vm1 = H-1; // size is left unchanged - screen_clear(CLEAR_ALL); - unicode_cache_clear(); + screen_clear(CLEAR_ALL); // also clears utf cache NOTIFY_DONE(); } @@ -314,18 +300,11 @@ screen_reset_sgr(void) cursor.conceal = false; } -/** - * Reset the screen - called by ESC c - */ -void ICACHE_FLASH_ATTR -screen_reset(void) +static void ICACHE_FLASH_ATTR +screen_reset_do(bool size, bool labels) { - ansi_dbg("Screen reset."); NOTIFY_LOCK(); - cursor_reset(); - unicode_cache_clear(); - // DECopts scr.cursor_visible = true; scr.insert_mode = false; @@ -339,17 +318,21 @@ screen_reset(void) termconf_live.crlf_mode = termconf->crlf_mode; scr.reverse_video = false; - scr.vm0 = 0; - scr.vm1 = H-1; - state_backup.alternate_active = false; mouse_tracking.encoding = MTE_SIMPLE; mouse_tracking.focus_tracking = false; mouse_tracking.mode = MTM_NONE; - // size is left unchanged - screen_clear(CLEAR_ALL); + if (size) { + W = termconf->width; + H = termconf->height; + } + + scr.vm0 = 0; + scr.vm1 = H - 1; + cursor_reset(); + screen_clear(CLEAR_ALL); // also clears utf cache // Set initial tabstops for (int i = 0; i < TABSTOP_WORDS; i++) { @@ -372,8 +355,30 @@ screen_reset(void) opt_backup.show_config_links = termconf_live.show_config_links; NOTIFY_DONE(); + + if (labels) { + strcpy(termconf_live.title, termconf->title); + + 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]); + } + + screen_notifyChange(CHANGE_LABELS); + } } +/** + * Reset the screen - called by ESC c + */ +void ICACHE_FLASH_ATTR +screen_reset(void) +{ + ansi_dbg("Screen reset."); + screen_reset_do(true, true); +} + + /** * Swap screen buffer / state * this is CSI ? 47/1047/1049 h/l @@ -563,8 +568,10 @@ clear_range_do(unsigned int from, unsigned int to, bool clear_utf) sample.attrs = (CellAttrs) (cursor.attrs & (ATTR_FG | ATTR_BG)); for (unsigned int i = from; i <= to; i++) { - UnicodeCacheRef symbol = screen[i].symbol; - if (clear_utf && IS_UNICODE_CACHE_REF(symbol)) unicode_cache_remove(symbol); + if (clear_utf) { + UnicodeCacheRef symbol = screen[i].symbol; + if (IS_UNICODE_CACHE_REF(symbol)) unicode_cache_remove(symbol); + } memcpy(&screen[i], &sample, sizeof(Cell)); } } @@ -602,6 +609,7 @@ clear_range_noutf(unsigned int from, unsigned int to) static inline void ICACHE_FLASH_ATTR utf_free_cell(int row, int col) { + dbg("free cell (row %d) %d", row, col); UnicodeCacheRef symbol = screen[row * W + col].symbol; if (IS_UNICODE_CACHE_REF(symbol)) unicode_cache_remove(symbol); @@ -617,11 +625,25 @@ utf_free_cell(int row, int col) static inline void ICACHE_FLASH_ATTR utf_backup_cell(int row, int col) { + dbg("backup cell (row %d) %d", row, col); UnicodeCacheRef symbol = screen[row * W + col].symbol; if (IS_UNICODE_CACHE_REF(symbol)) unicode_cache_inc(symbol); } +/** + * Duplicate a cell within a row + * @param row - row to work on + * @param dest_col - destination column + * @param src_col - source column + */ +static inline void ICACHE_FLASH_ATTR +copy_cell(int row, int dest_col, int src_col) +{ + dbg("copy cell (row %d) %d -> %d", row, src_col, dest_col); + memcpy(screen+row*W+dest_col, screen+row*W+src_col, sizeof(Cell)); +} + /** * Free all utf8 on a row * @@ -630,6 +652,7 @@ utf_backup_cell(int row, int col) static inline void ICACHE_FLASH_ATTR utf_free_row(int row) { + dbg("free row %d", row); for (int col = 0; col < W; col++) { utf_free_cell(row, col); } @@ -643,6 +666,7 @@ utf_free_row(int row) static inline void ICACHE_FLASH_ATTR utf_backup_row(int row) { + dbg("backup row %d", row); for (int col = 0; col < W; col++) { utf_backup_cell(row, col); } @@ -657,21 +681,10 @@ utf_backup_row(int row) static inline void ICACHE_FLASH_ATTR copy_row(int dest, int src) { + dbg("copy row %d -> %d", src, dest); memcpy(screen + dest * W, screen + src * W, sizeof(Cell) * W); } -/** - * Duplicate a cell within a row - * @param row - row to work on - * @param dest_col - destination column - * @param src_col - source column - */ -static inline void ICACHE_FLASH_ATTR -copy_cell(int row, int dest_col, int src_col) -{ - memcpy(screen+row*W+dest_col, screen+row*W+src_col, sizeof(Cell)); -} - /** * Clear a row, do nothing with the utf8 cache * @@ -704,8 +717,9 @@ screen_clear(ClearMode mode) NOTIFY_LOCK(); switch (mode) { case CLEAR_ALL: - clear_range_noutf(0, W * H - 1); unicode_cache_clear(); + clear_range_noutf(0, W * H - 1); + scr.last_char[0] = 0; break; case CLEAR_FROM_CURSOR: @@ -769,6 +783,7 @@ screen_insert_lines(unsigned int lines) for (int i = BTM; i >= targetStart; i--) { utf_free_row(i); // release old characters copy_row(i, i - lines); + if (i != targetStart) utf_backup_row(i); } // clear the first line @@ -792,12 +807,13 @@ screen_delete_lines(unsigned int lines) if (movedBlockEnd <= cursor.y) { // clear the entire rest of the screen movedBlockEnd = cursor.y; - clear_range_utf(movedBlockEnd*W, W * BTM); + clear_range_utf(movedBlockEnd*W, (BTM+1)*W-1); } else { // move some lines up, clear the rest for (int i = cursor.y; i <= movedBlockEnd; i++) { utf_free_row(i); copy_row(i, i+lines); + if (i != movedBlockEnd) utf_backup_row(i); } clear_range_noutf((movedBlockEnd+1)*W, (BTM+1)*W-1); } @@ -821,8 +837,9 @@ screen_insert_characters(unsigned int count) for (int i = W-1; i >= targetStart; i--) { utf_free_cell(cursor.y, i); copy_cell(cursor.y, i, i - count); + utf_backup_cell(cursor.y, i); } - clear_range_noutf(cursor.y * W + cursor.x, cursor.y * W + targetStart - 1); + clear_range_utf(cursor.y * W + cursor.x, cursor.y * W + targetStart - 1); } NOTIFY_DONE(); } @@ -841,9 +858,10 @@ screen_delete_characters(unsigned int count) for (int i = cursor.x; i <= movedBlockEnd; i++) { utf_free_cell(cursor.y, i); copy_cell(cursor.y, i, i + count); + utf_backup_cell(cursor.y, i); } // clear original positions of the moved characters - clear_range_utf(cursor.y * W + (W - count), (cursor.y + 1) * W - 1); + clear_range_noutf(cursor.y * W + (W - count), (cursor.y + 1) * W - 1); } else { // all rest was cleared screen_clear_line(CLEAR_FROM_CURSOR); @@ -859,7 +877,7 @@ void ICACHE_FLASH_ATTR screen_fill_with_E(void) { NOTIFY_LOCK(); - screen_reset(); // based on observation from xterm + screen_reset_do(false, false); // based on observation from xterm Cell sample; sample.symbol = 'E'; @@ -943,6 +961,7 @@ screen_scroll_up(unsigned int lines) for (y = TOP; y <= BTM - lines; y++) { utf_free_row(y); copy_row(y, y+lines); + if (y < BTM - lines) utf_backup_row(y); } clear_range_noutf(y * W, (BTM + 1) * W - 1); @@ -973,6 +992,7 @@ screen_scroll_down(unsigned int lines) for (y = BTM; y >= TOP+lines; y--) { utf_free_row(y); copy_row(y, y-lines); + if (y > TOP + lines) utf_backup_row(y); } clear_range_noutf(TOP * W, TOP * W + lines * W - 1); From cb715861380e24aecca2b9911fdaf583f2e42afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 24 Sep 2017 20:35:55 +0200 Subject: [PATCH 26/29] remove spammy debug --- esphttpdconfig.mk | 6 +++--- user/screen.c | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/esphttpdconfig.mk b/esphttpdconfig.mk index 6cf5552..d8b6237 100644 --- a/esphttpdconfig.mk +++ b/esphttpdconfig.mk @@ -44,10 +44,10 @@ GLOBAL_CFLAGS = \ -DDEBUG_HTTP=0 \ -DDEBUG_ESPFS=0 \ -DDEBUG_PERSIST=0 \ - -DDEBUG_UTFCACHE=1 \ + -DDEBUG_UTFCACHE=0 \ -DDEBUG_CGI=0 \ -DDEBUG_WIFI=0 \ - -DDEBUG_WS=1 \ + -DDEBUG_WS=0 \ -DDEBUG_ANSI=1 \ -DDEBUG_ANSI_NOIMPL=1 \ -DDEBUG_INPUT=0 \ @@ -56,6 +56,6 @@ GLOBAL_CFLAGS = \ -DHTTPD_MAX_BACKLOG_SIZE=8192 \ -DHTTPD_MAX_HEAD_LEN=1024 \ -DHTTPD_MAX_POST_LEN=512 \ - -DDEBUG_LOGBUF_SIZE=2048 \ + -DDEBUG_LOGBUF_SIZE=1024 \ -mforce-l32 \ -DUSE_OPTIMIZE_PRINTF=1 diff --git a/user/screen.c b/user/screen.c index 5adca49..78c4712 100644 --- a/user/screen.c +++ b/user/screen.c @@ -609,7 +609,7 @@ clear_range_noutf(unsigned int from, unsigned int to) static inline void ICACHE_FLASH_ATTR utf_free_cell(int row, int col) { - dbg("free cell (row %d) %d", row, col); + //dbg("free cell (row %d) %d", row, col); UnicodeCacheRef symbol = screen[row * W + col].symbol; if (IS_UNICODE_CACHE_REF(symbol)) unicode_cache_remove(symbol); @@ -625,7 +625,7 @@ utf_free_cell(int row, int col) static inline void ICACHE_FLASH_ATTR utf_backup_cell(int row, int col) { - dbg("backup cell (row %d) %d", row, col); + //dbg("backup cell (row %d) %d", row, col); UnicodeCacheRef symbol = screen[row * W + col].symbol; if (IS_UNICODE_CACHE_REF(symbol)) unicode_cache_inc(symbol); @@ -640,7 +640,7 @@ utf_backup_cell(int row, int col) static inline void ICACHE_FLASH_ATTR copy_cell(int row, int dest_col, int src_col) { - dbg("copy cell (row %d) %d -> %d", row, src_col, dest_col); + //dbg("copy cell (row %d) %d -> %d", row, src_col, dest_col); memcpy(screen+row*W+dest_col, screen+row*W+src_col, sizeof(Cell)); } @@ -652,7 +652,7 @@ copy_cell(int row, int dest_col, int src_col) static inline void ICACHE_FLASH_ATTR utf_free_row(int row) { - dbg("free row %d", row); + //dbg("free row %d", row); for (int col = 0; col < W; col++) { utf_free_cell(row, col); } @@ -666,7 +666,7 @@ utf_free_row(int row) static inline void ICACHE_FLASH_ATTR utf_backup_row(int row) { - dbg("backup row %d", row); + //dbg("backup row %d", row); for (int col = 0; col < W; col++) { utf_backup_cell(row, col); } @@ -681,7 +681,7 @@ utf_backup_row(int row) static inline void ICACHE_FLASH_ATTR copy_row(int dest, int src) { - dbg("copy row %d -> %d", src, dest); + //dbg("copy row %d -> %d", src, dest); memcpy(screen + dest * W, screen + src * W, sizeof(Cell) * W); } From 0f10d84a595c395e5cbe0bbd761dbc0b9c993a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 24 Sep 2017 20:36:09 +0200 Subject: [PATCH 27/29] disable non-error ansi logging --- esphttpdconfig.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphttpdconfig.mk b/esphttpdconfig.mk index d8b6237..639eb23 100644 --- a/esphttpdconfig.mk +++ b/esphttpdconfig.mk @@ -48,7 +48,7 @@ GLOBAL_CFLAGS = \ -DDEBUG_CGI=0 \ -DDEBUG_WIFI=0 \ -DDEBUG_WS=0 \ - -DDEBUG_ANSI=1 \ + -DDEBUG_ANSI=0 \ -DDEBUG_ANSI_NOIMPL=1 \ -DDEBUG_INPUT=0 \ -DDEBUG_HEAP=1 \ From 502babf7b0e457e2935840b92d4425737e1cc650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 24 Sep 2017 20:50:01 +0200 Subject: [PATCH 28/29] updated front-end ref --- front-end | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front-end b/front-end index c68017b..6c64248 160000 --- a/front-end +++ b/front-end @@ -1 +1 @@ -Subproject commit c68017bd4ad387786dd17b213be9bdd29fe4c0ea +Subproject commit 6c6424877c49e3e23f563067a78e79338226359d From fa5489ccfcc2e160186ae1a6899b1a2807bf5814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 25 Sep 2017 01:53:59 +0200 Subject: [PATCH 29/29] support for truecolor default colors --- front-end | 2 +- user/cgi_term_cfg.c | 66 ++++++++++++++++++++++++++++++++------------- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/front-end b/front-end index 6c64248..b18a0f3 160000 --- a/front-end +++ b/front-end @@ -1 +1 @@ -Subproject commit 6c6424877c49e3e23f563067a78e79338226359d +Subproject commit b18a0f389005913a214f4a86efb27e23206fa52e diff --git a/user/cgi_term_cfg.c b/user/cgi_term_cfg.c index ffc0011..19ee825 100644 --- a/user/cgi_term_cfg.c +++ b/user/cgi_term_cfg.c @@ -14,6 +14,22 @@ 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. */ @@ -55,7 +71,7 @@ cgiTermCfgSetParams(HttpdConnData *connData) 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_width,term_height,"); + redir_url += sprintf(redir_url, "term_height,"); break; } @@ -83,29 +99,33 @@ cgiTermCfgSetParams(HttpdConnData *connData) if (GET_ARG("default_bg")) { cgi_dbg("Screen default BG: %s", buff); - n = atoi(buff); - if (n >= 0 && n < 16) { - if (termconf->default_bg != n) { - termconf->default_bg = n; - shall_clear_screen = true; - } + + if (buff[0] == '#') { + // decode hex + n = decodehex(buff+1); + n += 256; } else { - cgi_warn("Bad color %s", buff); - redir_url += sprintf(redir_url, "default_bg,"); + n = atoi(buff); + } + + if (termconf->default_bg != n) { + termconf->default_bg = n; // this is current not sent through socket, no use to notify } } if (GET_ARG("default_fg")) { cgi_dbg("Screen default FG: %s", buff); - n = atoi(buff); - if (n >= 0 && n < 16) { - if (termconf->default_fg != n) { - termconf->default_fg = n; - shall_clear_screen = true; - } + + if (buff[0] == '#') { + // decode hex + n = decodehex(buff+1); + n += 256; } else { - cgi_warn("Bad color %s", buff); - redir_url += sprintf(redir_url, "default_fg,"); + n = atoi(buff); + } + + if (termconf->default_fg != n) { + termconf->default_fg = n; // this is current not sent through socket, no use to notify } } @@ -415,10 +435,18 @@ tplTermCfg(HttpdConnData *connData, char *token, void **arg) sprintf(buff, "%d", termconf->theme); } else if (streq(token, "default_bg")) { - sprintf(buff, "%d", termconf->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")) { - sprintf(buff, "%d", termconf->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);