use xmacros for terminal config

work
Ondřej Hruška 7 years ago
parent f0bc70553a
commit 1ab4101ac0
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 2
      front-end
  2. 2
      user/apars_osc.c
  3. 4
      user/cgi_sockets.c
  4. 15
      user/cgi_system.c
  5. 480
      user/cgi_term_cfg.c
  6. 26
      user/config_xmacros.c
  7. 10
      user/config_xmacros.h
  8. 313
      user/screen.c
  9. 77
      user/screen.h
  10. 19
      user/syscfg.h
  11. 42
      user/wifimgr.h

@ -1 +1 @@
Subproject commit 32c889b714dae859f51e6b46829fd85be59d9ed0 Subproject commit 560f5783bc0eb5bf845a55cc30a3928f1d01b85f

@ -59,7 +59,7 @@ apars_handle_osc(char *buffer)
} }
else if (n >= 91 && n <= 95) { else if (n >= 91 && n <= 95) {
// ESPTerm: action button message // ESPTerm: action button message
strncpy(termconf_live.btn_msg[n - 91], buffer, TERM_BTN_MSG_LEN); screen_set_button_message(n - 90, buffer);
} }
else { else {
ansi_noimpl("OSC %d ; %s ST", n, buffer); ansi_noimpl("OSC %d ; %s ST", n, buffer);

@ -271,8 +271,8 @@ static void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int
case 'b': case 'b':
// action button press // action button press
btnNum = (u8) (data[1]); btnNum = (u8) (data[1]);
if (btnNum > 0 && btnNum < 10) { if (btnNum > 0 && btnNum <= TERM_BTN_COUNT) {
UART_SendAsync(termconf_live.btn_msg[btnNum-1], -1); UART_SendAsync(TERM_BM_N(&termconf_live, btnNum-1), -1);
} }
break; break;

@ -12,9 +12,6 @@
#define SET_REDIR_SUC "/cfg/system" #define SET_REDIR_SUC "/cfg/system"
#define SET_REDIR_ERR SET_REDIR_SUC"?err=" #define SET_REDIR_ERR SET_REDIR_SUC"?err="
// Select which struct we want to use for X tables
#define XSTRUCT sysconf
static ETSTimer tmr; static ETSTimer tmr;
static void ICACHE_FLASH_ATTR tmrCb(void *arg) static void ICACHE_FLASH_ATTR tmrCb(void *arg)
@ -99,7 +96,9 @@ cgiSystemCfgSetParams(HttpdConnData *connData)
memcpy(sysconf_backup, sysconf, sizeof(SystemConfigBundle)); memcpy(sysconf_backup, sysconf, sizeof(SystemConfigBundle));
// flags for the template builder // flags for the template builder
bool admin = false, tpl = false; bool uart_changed = false; //!< this is set in uart notify, for use in terminal settings (dummy here)
bool admin = false;
const bool tpl = false; // this optionally disables some fields
do { do {
// Check admin PW // Check admin PW
if (GET_ARG("pw")) { if (GET_ARG("pw")) {
@ -164,13 +163,16 @@ cgiSystemCfgSetParams(HttpdConnData *connData)
} }
// Settings in the system config block // Settings in the system config block
#define XSTRUCT sysconf
#define X XSET_CGI_FUNC #define X XSET_CGI_FUNC
XTABLE_SYSCONF XTABLE_SYSCONF
#undef X #undef X
#undef XSTRUCT
} while (0); } while (0);
(void)redir_url; (void)redir_url;
(void)uart_changed; // unused
if (redir_url_buf[strlen(SET_REDIR_ERR)] == 0) { if (redir_url_buf[strlen(SET_REDIR_ERR)] == 0) {
// All was OK // All was OK
@ -210,11 +212,14 @@ tplSystemCfg(HttpdConnData *connData, char *token, void **arg)
strcpy(buff, ""); // fallback strcpy(buff, ""); // fallback
const bool admin = false, tpl=true; const bool admin = false;
const bool tpl=true;
#define XSTRUCT sysconf
#define X XGET_CGI_FUNC #define X XGET_CGI_FUNC
XTABLE_SYSCONF XTABLE_SYSCONF
#undef X #undef X
#undef XSTRUCT
if (streq(token, "def_access_name")) { if (streq(token, "def_access_name")) {
sprintf(buff, "%s", DEF_ACCESS_NAME); sprintf(buff, "%s", DEF_ACCESS_NAME);

@ -15,22 +15,6 @@ Cgi/template routines for configuring non-wifi settings
#define SET_REDIR_SUC "/cfg/term" #define SET_REDIR_SUC "/cfg/term"
#define SET_REDIR_ERR SET_REDIR_SUC"?err=" #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. * Universal CGI endpoint to set Terminal params.
*/ */
@ -39,15 +23,11 @@ cgiTermCfgSetParams(HttpdConnData *connData)
{ {
char buff[50]; char buff[50];
char redir_url_buf[100]; char redir_url_buf[100];
int32 n, w, h;
ScreenNotifyTopics topics = 0; ScreenNotifyTopics topics = 0;
bool shall_clear_screen = false;
bool shall_init_uart = false;
char *redir_url = redir_url_buf; char *redir_url = redir_url_buf;
redir_url += sprintf(redir_url, SET_REDIR_ERR); redir_url += sprintf(redir_url, SET_REDIR_ERR);
// we'll test if anything was printed by looking for \0 in failed_keys_buf // we'll test if anything was printed by looking for \0 in redir_url
SystemConfigBundle *sysconf_backup = malloc(sizeof(SystemConfigBundle)); SystemConfigBundle *sysconf_backup = malloc(sizeof(SystemConfigBundle));
TerminalConfigBundle *termconf_backup = malloc(sizeof(TerminalConfigBundle)); TerminalConfigBundle *termconf_backup = malloc(sizeof(TerminalConfigBundle));
@ -59,328 +39,29 @@ cgiTermCfgSetParams(HttpdConnData *connData)
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
// width and height must always go together so we can do max size validation #define XSTRUCT termconf
if (GET_ARG("term_width")) { #define X XSET_CGI_FUNC
do { XTABLE_TERMCONF
cgi_dbg("Default screen width: %s", buff); #undef X
w = atoi(buff); #undef XSTRUCT
if (w < 1) {
cgi_warn("Bad width: \"%s\"", buff);
redir_url += sprintf(redir_url, "term_width,");
break;
}
if (!GET_ARG("term_height")) {
cgi_warn("Missing height arg!");
// this wont happen normally when the form is used
redir_url += sprintf(redir_url, "term_height,");
break;
}
cgi_dbg("Default screen height: %s", buff); // width and height must always go together so we can do max size validation
h = atoi(buff); u32 siz = termconf->width*termconf->height;
if (h < 1) { if (siz == 0 || siz > MAX_SCREEN_SIZE) {
cgi_warn("Bad height: \"%s\"", buff); cgi_warn("Bad dimensions: %d x %d (total %d)", termconf->width, termconf->height, termconf->width*termconf->height);
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,"); redir_url += sprintf(redir_url, "term_width,term_height,");
break;
}
if (termconf->width != w || termconf->height != h) {
termconf->width = w;
termconf->height = h;
shall_clear_screen = true;
topics |= TOPIC_CHANGE_SCREEN_OPTS | TOPIC_CHANGE_CONTENT_ALL;
}
} while (0);
}
if (GET_ARG("default_bg")) {
cgi_dbg("Screen default BG: %s", buff);
if (buff[0] == '#') {
// decode hex
n = decodehex(buff+1);
n += 256;
} else {
n = atoi(buff);
}
if (termconf->default_bg != n) {
termconf->default_bg = n; // this is current not sent through socket, no use to notify
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
}
if (GET_ARG("default_fg")) {
cgi_dbg("Screen default FG: %s", buff);
if (buff[0] == '#') {
// decode hex
n = decodehex(buff+1);
n += 256;
} else {
n = atoi(buff);
}
if (termconf->default_fg != n) {
termconf->default_fg = n; // this is current not sent through socket, no use to notify
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
}
if (GET_ARG("parser_tout_ms")) {
cgi_dbg("Parser timeout: %s ms", buff);
n = atoi(buff);
if (n >= 0) {
termconf->parser_tout_ms = n;
} else {
cgi_warn("Bad parser timeout %s", buff);
redir_url += sprintf(redir_url, "parser_tout_ms,");
}
}
if (GET_ARG("display_tout_ms")) {
cgi_dbg("Display update idle timeout: %s ms", buff);
n = atoi(buff);
if (n >= 0) {
termconf->display_tout_ms = n;
} else {
cgi_warn("Bad update timeout %s", buff);
redir_url += sprintf(redir_url, "display_tout_ms,");
}
}
if (GET_ARG("display_cooldown_ms")) {
cgi_dbg("Display update cooldown: %s ms", buff);
n = atoi(buff);
if (n > 0) {
termconf->display_cooldown_ms = n;
} else {
cgi_warn("Bad cooldown %s", buff);
redir_url += sprintf(redir_url, "display_cooldown_ms,");
}
}
if (GET_ARG("fn_alt_mode")) {
cgi_dbg("FN alt mode: %s", buff);
n = atoi(buff);
termconf->fn_alt_mode = (bool)n;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("want_all_fn")) {
cgi_dbg("AllFN mode: %s", buff);
n = atoi(buff);
termconf->want_all_fn = (bool)n;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("crlf_mode")) {
cgi_dbg("CRLF mode: %s", buff);
n = atoi(buff);
termconf->crlf_mode = (bool)n;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("show_buttons")) {
cgi_dbg("Show buttons: %s", buff);
n = atoi(buff);
termconf->show_buttons = (bool)n;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("show_config_links")) {
cgi_dbg("Show config links: %s", buff);
n = atoi(buff);
termconf->show_config_links = (bool)n;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("loopback")) {
cgi_dbg("Loopback: %s", buff);
n = atoi(buff);
termconf->loopback = (bool)n;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("debugbar")) {
cgi_dbg("Debugbar: %s", buff);
n = atoi(buff);
termconf->debugbar = (bool)n;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("allow_decopt_12")) {
cgi_dbg("DECOPT 12: %s", buff);
n = atoi(buff);
termconf->allow_decopt_12 = (bool)n;
}
if (GET_ARG("ascii_debug")) {
cgi_dbg("ascii_debug: %s", buff);
n = atoi(buff);
termconf->ascii_debug = (bool)n;
shall_clear_screen = true;
}
if (GET_ARG("theme")) {
cgi_dbg("Screen color theme: %s", buff);
n = atoi(buff);
if (n >= 0) {
termconf->theme = (u8) n;
// this can't be notified, page must reload.
} else {
cgi_warn("Bad theme num: %s", buff);
redir_url += sprintf(redir_url, "theme,");
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
}
if (GET_ARG("cursor_shape")) {
cgi_dbg("Cursor shape: %s", buff);
n = atoi(buff);
if (n >= 0 && n <= 6 && n != 1) {
termconf->cursor_shape = (enum CursorShape) n;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
} else {
cgi_warn("Bad cursor_shape num: %s", buff);
redir_url += sprintf(redir_url, "cursor_shape,");
}
}
if (GET_ARG("term_title")) {
cgi_dbg("Terminal title default text: \"%s\"", buff);
strncpy_safe(termconf->title, buff, TERM_TITLE_LEN); // ATTN those must match the values in
topics |= TOPIC_CHANGE_TITLE;
}
if (GET_ARG("backdrop")) {
cgi_dbg("Terminal backdrop url: \"%s\"", buff);
strncpy_safe(termconf->backdrop, buff, TERM_BACKDROP_LEN); // ATTN those must match the values in
topics |= TOPIC_CHANGE_BACKDROP;
}
for (int btn_i = 1; btn_i <= TERM_BTN_COUNT; btn_i++) {
sprintf(buff, "btn%d", btn_i);
if (GET_ARG(buff)) {
cgi_dbg("Button%d default text: \"%s\"", btn_i, buff);
strncpy_safe(termconf->btn[btn_i-1], buff, TERM_BTN_LEN);
topics |= TOPIC_CHANGE_BUTTONS;
}
sprintf(buff, "bm%d", btn_i);
if (GET_ARG(buff)) {
cgi_dbg("Button%d message (ASCII): \"%s\"", btn_i, buff);
// parse: comma,space or semicolon separated decimal values of ASCII codes
char c;
char *cp = buff;
int char_i = 0;
int acu = 0;
bool lastsp = 1;
char buff_bm[TERM_BTN_MSG_LEN];
while ((c = *cp++) != 0) {
if (c == ' ' || c == ',' || c == ';') {
if(lastsp) continue;
if (acu==0 || acu>255) {
cgi_warn("Bad value! %d", acu);
redir_url += sprintf(redir_url, "bm%d,", btn_i);
break;
}
if (char_i >= TERM_BTN_MSG_LEN-1) {
cgi_warn("Too long! %d", acu);
redir_url += sprintf(redir_url, "bm%d,", btn_i);
break;
}
cgi_dbg("acu %d", acu);
buff_bm[char_i++] = (char)acu;
// prepare for next char
acu = 0;
lastsp = 1;
} else if (c>='0'&&c<='9') {
lastsp = 0;
acu *= 10;
acu += c - '0';
} else {
cgi_warn("Bad syntax!");
redir_url += sprintf(redir_url, "bm%d,", btn_i);
break;
}
}
if (lastsp && char_i == 0) {
cgi_warn("Required!");
redir_url += sprintf(redir_url, "bm%d,", btn_i);
} }
if (!lastsp) {
buff_bm[char_i++] = (char)acu;
}
buff_bm[char_i] = 0;
cgi_dbg("%s, chari = %d", buff_bm, char_i);
strncpy(termconf->btn_msg[btn_i-1], buff_bm, TERM_BTN_MSG_LEN); // Settings from SysConf - UART
} bool uart_changed = false;
} // restrict what keys are allowed
#define admin 0
if (GET_ARG("uart_baud")) { #define tpl 0
cgi_dbg("Baud rate: %s", buff); #define XSTRUCT sysconf
int baud = atoi(buff); #define X XSET_CGI_FUNC
if (baud == BIT_RATE_300 || XTABLE_SYSCONF
baud == BIT_RATE_600 || #undef X
baud == BIT_RATE_1200 || #undef XSTRUCT
baud == BIT_RATE_2400 ||
baud == BIT_RATE_4800 ||
baud == BIT_RATE_9600 ||
baud == BIT_RATE_19200 ||
baud == BIT_RATE_38400 ||
baud == BIT_RATE_57600 ||
baud == BIT_RATE_74880 ||
baud == BIT_RATE_115200 ||
baud == BIT_RATE_230400 ||
baud == BIT_RATE_460800 ||
baud == BIT_RATE_921600 ||
baud == BIT_RATE_1843200 ||
baud == BIT_RATE_3686400) {
sysconf->uart_baudrate = (u32) baud;
shall_init_uart = true;
} else {
cgi_warn("Bad baud rate %s", buff);
redir_url += sprintf(redir_url, "uart_baud,");
}
}
if (GET_ARG("uart_parity")) {
cgi_dbg("Parity: %s", buff);
int parity = atoi(buff);
if (parity >= 0 && parity <= 2) {
sysconf->uart_parity = (UartParityMode) parity;
shall_init_uart = true;
} else {
cgi_warn("Bad parity %s", buff);
redir_url += sprintf(redir_url, "uart_parity,");
}
}
if (GET_ARG("uart_stopbits")) {
cgi_dbg("Stop bits: %s", buff);
int stopbits = atoi(buff);
if (stopbits >= 1 && stopbits <= 3) {
sysconf->uart_stopbits = (UartStopBitsNum) stopbits;
shall_init_uart = true;
} else {
cgi_warn("Bad stopbits %s", buff);
redir_url += sprintf(redir_url, "uart_stopbits,");
}
}
(void)redir_url; (void)redir_url;
@ -390,17 +71,23 @@ cgiTermCfgSetParams(HttpdConnData *connData)
persist_store(); persist_store();
bool shall_clear_screen = false;
shall_clear_screen |= (termconf_backup->width != termconf->width);
shall_clear_screen |= (termconf_backup->height != termconf->height);
shall_clear_screen |= (termconf_backup->ascii_debug != termconf->ascii_debug);
if (shall_clear_screen) { if (shall_clear_screen) {
terminal_apply_settings(); terminal_apply_settings();
} else { } else {
terminal_apply_settings_noclear(); terminal_apply_settings_noclear();
} }
if (shall_init_uart) { if (uart_changed) {
serialInit(); sysconf_apply_settings();
} }
if (topics) screen_notifyChange(topics); // Trigger a full reload
screen_notifyChange(TOPIC_INITIAL);
httpdRedirect(connData, SET_REDIR_SUC "?msg=Settings%20saved%20and%20applied."); httpdRedirect(connData, SET_REDIR_SUC "?msg=Settings%20saved%20and%20applied.");
} else { } else {
@ -424,7 +111,6 @@ tplTermCfg(HttpdConnData *connData, char *token, void **arg)
{ {
#define BUFLEN 100 // large enough for backdrop #define BUFLEN 100 // large enough for backdrop
char buff[BUFLEN]; char buff[BUFLEN];
char buff2[10];
if (token == NULL) { if (token == NULL) {
// We're done // We're done
@ -433,109 +119,11 @@ tplTermCfg(HttpdConnData *connData, char *token, void **arg)
strcpy(buff, ""); // fallback strcpy(buff, ""); // fallback
if (streq(token, "term_width")) { #define XSTRUCT termconf
sprintf(buff, "%d", termconf->width); #define X XGET_CGI_FUNC
} XTABLE_TERMCONF
else if (streq(token, "term_height")) { #undef X
sprintf(buff, "%d", termconf->height); #undef XSTRUCT
}
else if (streq(token, "parser_tout_ms")) {
sprintf(buff, "%d", termconf->parser_tout_ms);
}
else if (streq(token, "display_tout_ms")) {
sprintf(buff, "%d", termconf->display_tout_ms);
}
else if (streq(token, "display_cooldown_ms")) {
sprintf(buff, "%d", termconf->display_cooldown_ms);
}
else if (streq(token, "fn_alt_mode")) {
sprintf(buff, "%d", (int)termconf->fn_alt_mode);
}
else if (streq(token, "want_all_fn")) {
sprintf(buff, "%d", (int)termconf->want_all_fn);
}
else if (streq(token, "crlf_mode")) {
sprintf(buff, "%d", (int)termconf->crlf_mode);
}
else if (streq(token, "show_buttons")) {
sprintf(buff, "%d", (int)termconf->show_buttons);
}
else if (streq(token, "show_config_links")) {
sprintf(buff, "%d", (int)termconf->show_config_links);
}
else if (streq(token, "allow_decopt_12")) {
sprintf(buff, "%d", (int)termconf->allow_decopt_12);
}
else if (streq(token, "ascii_debug")) {
sprintf(buff, "%d", (int)termconf->ascii_debug);
}
else if (streq(token, "loopback")) {
sprintf(buff, "%d", (int)termconf->loopback);
}
else if (streq(token, "debugbar")) {
sprintf(buff, "%d", (int)termconf->debugbar);
}
else if (streq(token, "theme")) {
sprintf(buff, "%d", termconf->theme);
}
else if (streq(token, "default_bg")) {
if (termconf->default_bg < 256) {
sprintf(buff, "%d", termconf->default_bg);
} else {
sprintf(buff, "#%06X", termconf->default_bg - 256);
}
}
else if (streq(token, "default_fg")) {
if (termconf->default_fg < 256) {
sprintf(buff, "%d", termconf->default_fg);
} else {
sprintf(buff, "#%06X", termconf->default_fg - 256);
}
}
else if (streq(token, "cursor_shape")) {
sprintf(buff, "%d", termconf->cursor_shape);
}
else if (streq(token, "term_title")) {
strncpy_safe(buff, termconf->title, BUFLEN);
}
else if (streq(token, "backdrop")) {
strncpy_safe(buff, termconf->backdrop, BUFLEN);
}
else if (streq(token, "uart_baud")) {
sprintf(buff, "%d", sysconf->uart_baudrate);
}
else if (streq(token, "uart_parity")) {
sprintf(buff, "%d", sysconf->uart_parity);
}
else if (streq(token, "uart_stopbits")) {
sprintf(buff, "%d", sysconf->uart_stopbits);
}
else {
for (int btn_i = 1; btn_i <= TERM_BTN_COUNT; btn_i++) {
sprintf(buff2, "btn%d", btn_i);
if (streq(token, buff2)) {
strncpy_safe(buff, termconf->btn[btn_i-1], BUFLEN);
break;
}
sprintf(buff2, "bm%d", btn_i);
if (streq(token, buff2)) {
char c;
char *bp = buff;
char *cp = termconf->btn_msg[btn_i-1];
int n = 0;
while((c = *cp++) != 0) {
if(n>0) {
*bp = ',';
bp++;
}
bp += sprintf(bp, "%d", (int)c);
n++;
}
break;
}
}
}
tplSend(connData, buff, -1); tplSend(connData, buff, -1);
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;

@ -80,6 +80,32 @@ xset_u8(const char *name, u8 *field, const char *buff, const void *arg)
} }
} }
enum xset_result ICACHE_FLASH_ATTR
xset_u32(const char *name, u32 *field, const char *buff, const void *arg)
{
cgi_dbg("Setting %s = %s", name, buff);
u32 val = (u32) atoi(buff);
if (*field != val) {
*field = (u32) val;
return XSET_SET;
}
return XSET_UNCHANGED;
}
enum xset_result ICACHE_FLASH_ATTR
xset_u16(const char *name, u16 *field, const char *buff, const void *arg)
{
cgi_dbg("Setting %s = %s", name, buff);
u16 val = (u16) atoi(buff);
if (*field != val) {
*field = (u16) val;
return XSET_SET;
}
return XSET_UNCHANGED;
}
enum xset_result ICACHE_FLASH_ATTR enum xset_result ICACHE_FLASH_ATTR
xset_string(const char *name, s8 **field, const char *buff, const void *arg) xset_string(const char *name, s8 **field, const char *buff, const void *arg)
{ {

@ -60,6 +60,8 @@ static inline enum xset_result xset_dummy(const char *name, void *field, const c
enum xset_result xset_ip(const char *name, struct ip_addr *field, const char *buff, const void *arg); enum xset_result xset_ip(const char *name, struct ip_addr *field, const char *buff, const void *arg);
enum xset_result xset_bool(const char *name, bool *field, const char *buff, const void *arg); enum xset_result xset_bool(const char *name, bool *field, const char *buff, const void *arg);
enum xset_result xset_u8(const char *name, u8 *field, const char *buff, const void *arg); enum xset_result xset_u8(const char *name, u8 *field, const char *buff, const void *arg);
enum xset_result xset_u32(const char *name, u32 *field, const char *buff, const void *arg);
enum xset_result xset_u16(const char *name, u16 *field, const char *buff, const void *arg);
/** /**
* @param arg - max string length * @param arg - max string length
@ -73,17 +75,17 @@ enum xset_result xset_ustring(const char *name, u8 **field, const char *buff, co
* If 'name' is found in connData->getArgs, xset() is called. * If 'name' is found in connData->getArgs, xset() is called.
* If the result is SET, xnotify() is fired. Else, 'name,' is appended to the redir_url buffer. * If the result is SET, xnotify() is fired. Else, 'name,' is appended to the redir_url buffer.
*/ */
#define XSET_CGI_FUNC(type, name, suffix, deref, xget, allow, cast, xset, xsarg, xnotify) \ #define XSET_CGI_FUNC(type, name, suffix, deref, xget, cast, xset, xsarg, xnotify, allow) \
if ((allow) && GET_ARG(#name)) { \ if ((allow) && GET_ARG(#name)) { \
enum xset_result res = xset(#name, cast &XSTRUCT->name, buff, (const void*) (xsarg)); \ enum xset_result res = xset(#name, cast &XSTRUCT->name, buff, (const void*) (xsarg)); \
if (res == XSET_SET) { xnotify(); } \ if (res == XSET_SET) { xnotify; } \
else if (res == XSET_FAIL) { redir_url += sprintf(redir_url, #name","); } \ else if (res == XSET_FAIL) { redir_url += sprintf(redir_url, #name","); } \
} }
#define XGET_CGI_FUNC(type, name, suffix, deref, xget, allow, cast, xset, xsarg, xnotify) \ #define XGET_CGI_FUNC(type, name, suffix, deref, xget, cast, xset, xsarg, xnotify, allow) \
if ((allow) && streq(token, #name)) xget(buff, deref XSTRUCT->name); if ((allow) && streq(token, #name)) xget(buff, deref XSTRUCT->name);
#define XSTRUCT_FIELD(type, name, suffix, deref, xget, allow, cast, xset, xsarg, xnotify) \ #define XSTRUCT_FIELD(type, name, suffix, deref, xget, cast, xset, xsarg, xnotify, allow) \
type name suffix; type name suffix;
#define XDUMP_FIELD(type, name, suffix, deref, xget, allow, cast, xset, xsarg, xnotify) \ #define XDUMP_FIELD(type, name, suffix, deref, xget, allow, cast, xset, xsarg, xnotify) \

@ -8,6 +8,7 @@
#include "character_sets.h" #include "character_sets.h"
#include "utf8.h" #include "utf8.h"
#include "cgi_sockets.h" #include "cgi_sockets.h"
#include "cgi_logging.h"
TerminalConfigBundle * const termconf = &persist.current.termconf; TerminalConfigBundle * const termconf = &persist.current.termconf;
TerminalConfigBundle termconf_live; TerminalConfigBundle termconf_live;
@ -106,8 +107,19 @@ bool cursor_saved = false;
static struct { static struct {
bool alternate_active; bool alternate_active;
char title[TERM_TITLE_LEN]; char title[TERM_TITLE_LEN];
char btn[TERM_BTN_COUNT][TERM_BTN_LEN];
char btn_msg[TERM_BTN_COUNT][TERM_BTN_MSG_LEN]; char btn1[TERM_BTN_LEN];
char btn2[TERM_BTN_LEN];
char btn3[TERM_BTN_LEN];
char btn4[TERM_BTN_LEN];
char btn5[TERM_BTN_LEN];
char btn1_msg[TERM_BTN_MSG_LEN];
char btn2_msg[TERM_BTN_MSG_LEN];
char btn3_msg[TERM_BTN_MSG_LEN];
char btn4_msg[TERM_BTN_MSG_LEN];
char btn5_msg[TERM_BTN_MSG_LEN];
u32 width; u32 width;
u32 height; u32 height;
int vm0; int vm0;
@ -143,46 +155,194 @@ static struct {
int x_min, y_min, x_max, y_max; int x_min, y_min, x_max, y_max;
} scr_dirty; } scr_dirty;
#define reset_screen_dirty() do { \ static void ICACHE_FLASH_ATTR reset_screen_dirty(void)
scr_dirty.x_min = W; \ {
scr_dirty.x_max = -1; \ scr_dirty.x_min = W;
scr_dirty.y_min = H; \ scr_dirty.x_max = -1;
scr_dirty.y_max = -1; \ scr_dirty.y_min = H;
} while(0) scr_dirty.y_max = -1;
}
#define expand_dirty(y0, y1, x0, x1) do { \ static void ICACHE_FLASH_ATTR expand_dirty(int y0, int y1, int x0, int x1)
seri_dbg("Expand: X: (%d..%d) -> %d..%d, Y: (%d..%d) -> %d..%d", scr_dirty.x_min, scr_dirty.x_max, x0, x1, scr_dirty.y_min, scr_dirty.y_max, y0, y1); \ {
if ((int)(y0) < scr_dirty.y_min) scr_dirty.y_min = (y0); \ seri_dbg("Expand: X: (%d..%d) -> %d..%d, Y: (%d..%d) -> %d..%d",
if ((int)(x0) < scr_dirty.x_min) scr_dirty.x_min = (x0); \ scr_dirty.x_min, scr_dirty.x_max, x0, x1, scr_dirty.y_min, scr_dirty.y_max, y0, y1);
if ((int)(y1) > scr_dirty.y_max) scr_dirty.y_max = (y1); \
if ((int)(x1) > scr_dirty.x_max) scr_dirty.x_max = (x1); \
} while(0)
#define NOTIFY_LOCK() do { \ if ((y0) < scr_dirty.y_min) scr_dirty.y_min = (y0);
notifyLock++; \ if ((x0) < scr_dirty.x_min) scr_dirty.x_min = (x0);
} while(0) if ((y1) > scr_dirty.y_max) scr_dirty.y_max = (y1);
if ((x1) > scr_dirty.x_max) scr_dirty.x_max = (x1);
}
#define NOTIFY_DONE(updateTopics) do { \ #define NOTIFY_LOCK() { notifyLock++; }
lockTopics |= (updateTopics); \
if (notifyLock > 0) notifyLock--; \ static void ICACHE_FLASH_ATTR NOTIFY_DONE(u32 updateTopics)
if (notifyLock == 0) { \ {
screen_notifyChange(lockTopics); \ lockTopics |= (updateTopics);
lockTopics = 0;\ if (notifyLock > 0) notifyLock--;
} \ if (notifyLock == 0) {
} while(0) screen_notifyChange(lockTopics);
lockTopics = 0;
}
}
/** Clear the hanging attribute if the cursor is no longer >= W */ /** Clear the hanging attribute if the cursor is no longer >= W */
#define clear_invalid_hanging() do { \ static void ICACHE_FLASH_ATTR clear_invalid_hanging(void)
if (cursor.hanging && cursor.x != W-1) { \ {
cursor.hanging = false; \ if (cursor.hanging && cursor.x != W-1) {
screen_notifyChange(TOPIC_CHANGE_CURSOR); \ cursor.hanging = false;
} \ screen_notifyChange(TOPIC_CHANGE_CURSOR);
} while(false) }
}
#define cursor_inside_region() (cursor.y >= TOP && cursor.y <= BTM) #define cursor_inside_region() (cursor.y >= TOP && cursor.y <= BTM)
//region --- Settings --- //region --- Settings ---
/** Export color for config */
void ICACHE_FLASH_ATTR
xget_term_color(char *buff, u32 value)
{
if (value < 256) {
sprintf(buff, "%d", value);
} else {
sprintf(buff, "#%06X", value - 256);
}
}
/** Export button message as stirng for config */
void ICACHE_FLASH_ATTR
xget_term_bm(char *buff, char *value)
{
u8 c;
char *bp = buff;
char *cp = value;
int n = 0;
while((c = (u8) *cp++) != 0) {
if(n>0) {
*bp = ',';
bp++;
}
bp += sprintf(bp, "%d", c);
n++;
}
}
enum xset_result ICACHE_FLASH_ATTR
xset_term_bm(const char *name, s8 **field, const char *buff, const void *arg)
{
cgi_dbg("Setting %s = %s", name, buff);
// parse: comma,space or semicolon separated decimal values of ASCII codes
char c;
const char *cp = buff;
int char_i = 0;
int acu = 0;
bool lastsp = 1;
char buff_bm[TERM_BTN_MSG_LEN];
while ((c = *cp++) != 0) {
if (c == ' ' || c == ',' || c == ';') {
if(lastsp) continue;
if (acu==0 || acu>255) {
cgi_warn("Bad value! %d", acu);
return XSET_FAIL;
}
if (char_i >= TERM_BTN_MSG_LEN-1) {
cgi_warn("Too long! %d", acu);
return XSET_FAIL;
}
cgi_dbg("acu %d", acu);
buff_bm[char_i++] = (char)acu;
// prepare for next char
acu = 0;
lastsp = 1;
} else if (c>='0'&&c<='9') {
lastsp = 0;
acu *= 10;
acu += c - '0';
} else {
cgi_warn("Bad syntax!");
return XSET_FAIL;
}
}
if (lastsp && char_i == 0) {
cgi_warn("Required!");
return XSET_FAIL;
}
if (!lastsp) {
buff_bm[char_i++] = (char)acu;
}
buff_bm[char_i] = 0;
cgi_dbg("%s, chari = %d", buff_bm, char_i);
if (!streq(*field, buff_bm)) {
strncpy((char*)*field, buff_bm, TERM_BTN_MSG_LEN);
return XSET_SET;
}
return XSET_UNCHANGED;
}
/** convert hex number to int */
static ICACHE_FLASH_ATTR u32
decodehex(const char *buf) {
u32 n = 0;
char c;
while ((c = *buf++) != 0) {
if (c >= '0' && c <= '9') c -= '0';
else if (c >= 'a' && c <= 'f') c -= 'a'-10;
else if (c >= 'A' && c <= 'F') c -= 'A'-10;
else c = 0;
n *= 16;
n += c;
}
return n;
}
enum xset_result ICACHE_FLASH_ATTR
xset_term_color(const char *name, u32 *field, const char *buff, const void *arg)
{
cgi_dbg("Setting %s = %s", name, buff);
u32 n;
if (buff[0] == '#') {
// decode hex
n = decodehex(buff+1);
n += 256;
} else {
n = atoi(buff);
}
if (*field != n) {
*field = n;
return XSET_SET;
}
return XSET_UNCHANGED;
}
enum xset_result ICACHE_FLASH_ATTR
xset_term_cursorshape(const char *name, u32 *field, const char *buff, const void *arg)
{
cgi_dbg("Setting %s = %s", name, buff);
u32 n = atoi(buff);
if (n >= 0 && n <= 6 && n != 1) {
if (*field != n) {
*field = n;
return XSET_SET;
}
return XSET_UNCHANGED;
} else {
cgi_warn("Bad cursor_shape num: %s", buff);
return XSET_FAIL;
}
}
/** /**
* Restore hard defaults * Restore hard defaults
*/ */
@ -194,10 +354,19 @@ terminal_restore_defaults(void)
termconf->default_bg = 0; termconf->default_bg = 0;
termconf->default_fg = 7; termconf->default_fg = 7;
sprintf(termconf->title, SCR_DEF_TITLE); sprintf(termconf->title, SCR_DEF_TITLE);
for(int i=1; i <= TERM_BTN_COUNT; i++) {
sprintf(termconf->btn[i-1], "%d", i); strcpy(termconf->btn1, "1");
sprintf(termconf->btn_msg[i-1], "%c", i); strcpy(termconf->btn2, "2");
} strcpy(termconf->btn3, "3");
strcpy(termconf->btn4, "4");
strcpy(termconf->btn5, "5");
strcpy(termconf->bm1, "\x01");
strcpy(termconf->bm2, "\x02");
strcpy(termconf->bm3, "\x03");
strcpy(termconf->bm4, "\x04");
strcpy(termconf->bm5, "\x05");
termconf->theme = 0; termconf->theme = 0;
termconf->parser_tout_ms = SCR_DEF_PARSER_TOUT_MS; termconf->parser_tout_ms = SCR_DEF_PARSER_TOUT_MS;
termconf->display_tout_ms = SCR_DEF_DISPLAY_TOUT_MS; termconf->display_tout_ms = SCR_DEF_DISPLAY_TOUT_MS;
@ -232,6 +401,13 @@ terminal_apply_settings_noclear(void)
{ {
bool changed = false; bool changed = false;
// char buff[64];
//#define XSTRUCT termconf
//#define X XDUMP_FIELD
// XTABLE_TERMCONF
//#undef X
// return;
// Migrate // Migrate
if (termconf->config_version < 1) { if (termconf->config_version < 1) {
persist_dbg("termconf: Updating to version %d", 1); persist_dbg("termconf: Updating to version %d", 1);
@ -393,10 +569,11 @@ screen_reset_do(bool size, bool labels)
strcpy(termconf_live.title, termconf->title); strcpy(termconf_live.title, termconf->title);
strcpy(termconf_live.backdrop, termconf->backdrop); strcpy(termconf_live.backdrop, termconf->backdrop);
for (int i = 1; i <= TERM_BTN_COUNT; i++) { strcpy(termconf_live.btn1, termconf->btn1);
strcpy(termconf_live.btn[i], termconf->btn[i]); strcpy(termconf_live.btn2, termconf->btn2);
strcpy(termconf_live.btn_msg[i], termconf->btn_msg[i]); strcpy(termconf_live.btn3, termconf->btn3);
} strcpy(termconf_live.btn4, termconf->btn4);
strcpy(termconf_live.btn5, termconf->btn5);
termconf_live.show_buttons = termconf->show_buttons; termconf_live.show_buttons = termconf->show_buttons;
termconf_live.show_config_links = termconf->show_config_links; termconf_live.show_config_links = termconf->show_config_links;
@ -452,8 +629,11 @@ screen_swap_state(bool alternate)
ansi_dbg("Swap to alternate"); ansi_dbg("Swap to alternate");
// store old state // store old state
memcpy(state_backup.title, termconf_live.title, TERM_TITLE_LEN); memcpy(state_backup.title, termconf_live.title, TERM_TITLE_LEN);
memcpy(state_backup.btn, termconf_live.btn, sizeof(termconf_live.btn));
memcpy(state_backup.btn_msg, termconf_live.btn_msg, sizeof(termconf_live.btn_msg)); // copy multiple fields at once
memcpy(state_backup.btn1, termconf_live.btn1, sizeof(termconf_live.btn1)*TERM_BTN_COUNT);
memcpy(state_backup.btn1_msg, termconf_live.bm1, sizeof(termconf_live.bm1)*TERM_BTN_COUNT);
memcpy(state_backup.tab_stops, scr.tab_stops, sizeof(scr.tab_stops)); memcpy(state_backup.tab_stops, scr.tab_stops, sizeof(scr.tab_stops));
state_backup.vm0 = scr.vm0; state_backup.vm0 = scr.vm0;
state_backup.vm1 = scr.vm1; state_backup.vm1 = scr.vm1;
@ -465,8 +645,11 @@ screen_swap_state(bool alternate)
else { else {
ansi_dbg("Unswap from alternate"); ansi_dbg("Unswap from alternate");
memcpy(termconf_live.title, state_backup.title, TERM_TITLE_LEN); memcpy(termconf_live.title, state_backup.title, TERM_TITLE_LEN);
memcpy(termconf_live.btn, state_backup.btn, sizeof(termconf_live.btn));
memcpy(termconf_live.btn_msg, state_backup.btn_msg, sizeof(termconf_live.btn_msg)); // copy multiple fields at once
memcpy(termconf_live.btn1, state_backup.btn1, sizeof(termconf_live.btn1)*TERM_BTN_COUNT);
memcpy(termconf_live.bm1, state_backup.btn1_msg, sizeof(termconf_live.bm1)*TERM_BTN_COUNT);
memcpy(scr.tab_stops, state_backup.tab_stops, sizeof(scr.tab_stops)); memcpy(scr.tab_stops, state_backup.tab_stops, sizeof(scr.tab_stops));
scr.vm0 = state_backup.vm0; scr.vm0 = state_backup.vm0;
scr.vm1 = state_backup.vm1; scr.vm1 = state_backup.vm1;
@ -989,8 +1172,8 @@ screen_resize(int rows, int cols)
if (W == cols && H == rows) return; // Do nothing if (W == cols && H == rows) return; // Do nothing
NOTIFY_LOCK(); NOTIFY_LOCK();
W = cols; W = (u32) cols;
H = rows; H = (u32) rows;
screen_reset_on_resize(); screen_reset_on_resize();
NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS|TOPIC_CHANGE_CONTENT_ALL|TOPIC_CHANGE_CURSOR); NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS|TOPIC_CHANGE_CONTENT_ALL|TOPIC_CHANGE_CURSOR);
} }
@ -1012,7 +1195,28 @@ void ICACHE_FLASH_ATTR
screen_set_button_text(int num, const char *text) screen_set_button_text(int num, const char *text)
{ {
NOTIFY_LOCK(); NOTIFY_LOCK();
strncpy(termconf_live.btn[num-1], text, TERM_BTN_LEN); if (num == 1) strncpy(termconf_live.btn1, text, TERM_BTN_LEN);
else if (num == 2) strncpy(termconf_live.btn2, text, TERM_BTN_LEN);
else if (num == 3) strncpy(termconf_live.btn3, text, TERM_BTN_LEN);
else if (num == 4) strncpy(termconf_live.btn4, text, TERM_BTN_LEN);
else if (num == 5) strncpy(termconf_live.btn5, text, TERM_BTN_LEN);
NOTIFY_DONE(TOPIC_CHANGE_BUTTONS);
}
/**
* Helper function to set terminal button label
* @param num - button number 1-5
* @param str - button text
*/
void ICACHE_FLASH_ATTR
screen_set_button_message(int num, const char *msg)
{
NOTIFY_LOCK();
if (num == 1) strncpy(termconf_live.bm1, msg, TERM_BTN_MSG_LEN);
else if (num == 2) strncpy(termconf_live.bm2, msg, TERM_BTN_MSG_LEN);
else if (num == 3) strncpy(termconf_live.bm3, msg, TERM_BTN_MSG_LEN);
else if (num == 4) strncpy(termconf_live.bm4, msg, TERM_BTN_MSG_LEN);
else if (num == 5) strncpy(termconf_live.bm5, msg, TERM_BTN_MSG_LEN);
NOTIFY_DONE(TOPIC_CHANGE_BUTTONS); NOTIFY_DONE(TOPIC_CHANGE_BUTTONS);
} }
@ -1121,7 +1325,7 @@ void ICACHE_FLASH_ATTR
screen_cursor_shape(enum CursorShape shape) screen_cursor_shape(enum CursorShape shape)
{ {
NOTIFY_LOCK(); NOTIFY_LOCK();
if (shape == CURSOR_DEFAULT) shape = termconf->cursor_shape; if (shape == CURSOR_DEFAULT) shape = (enum CursorShape) termconf->cursor_shape;
termconf_live.cursor_shape = shape; termconf_live.cursor_shape = shape;
NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS); NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS);
} }
@ -1356,7 +1560,7 @@ screen_back_index(int count)
cursor.x = new_x; cursor.x = new_x;
} else { } else {
cursor.x = 0; cursor.x = 0;
screen_insert_characters(-new_x); screen_insert_characters((unsigned int) -new_x);
topics |= TOPIC_CHANGE_CONTENT_PART; topics |= TOPIC_CHANGE_CONTENT_PART;
} }
NOTIFY_DONE(topics); NOTIFY_DONE(topics);
@ -1548,7 +1752,7 @@ do_save_private_opt(int n, bool save)
{ {
ScreenNotifyTopics topics = TOPIC_INTERNAL; ScreenNotifyTopics topics = TOPIC_INTERNAL;
if (!save) NOTIFY_LOCK(); if (!save) NOTIFY_LOCK();
#define SAVE_RESTORE(sf, of) do { if (save) sf=(of); else of=(sf); } while(0) #define SAVE_RESTORE(sf, of) do { if (save) (sf)=(of); else (of)=(sf); } while(0)
switch (n) { switch (n) {
case 1: case 1:
SAVE_RESTORE(opt_backup.cursors_alt_mode, scr.cursors_alt_mode); SAVE_RESTORE(opt_backup.cursors_alt_mode, scr.cursors_alt_mode);
@ -2044,7 +2248,7 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, ScreenNotifyTopics topics,
BEGIN_TOPIC(TOPIC_CHANGE_TITLE, TERM_TITLE_LEN+4+1) BEGIN_TOPIC(TOPIC_CHANGE_TITLE, TERM_TITLE_LEN+4+1)
bufput_c(TOPICMARK_TITLE); bufput_c(TOPICMARK_TITLE);
int len = (int) strlen(termconf_live.title); size_t len = strlen(termconf_live.title);
if (len > 0) { if (len > 0) {
memcpy(bb, termconf_live.title, len); memcpy(bb, termconf_live.title, len);
bb += len; bb += len;
@ -2059,20 +2263,21 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, ScreenNotifyTopics topics,
bufput_utf8(TERM_BTN_COUNT); bufput_utf8(TERM_BTN_COUNT);
for (int i = 0; i < TERM_BTN_COUNT; i++) { for (int i = 0; i < TERM_BTN_COUNT; i++) {
int len = (int) strlen(termconf_live.btn[i]); size_t len = strlen(TERM_BTN_N(&termconf_live, i));
if (len > 0) { if (len > 0) {
memcpy(bb, termconf_live.btn[i], len); memcpy(bb, TERM_BTN_N(&termconf_live, i), len);
bb += len; bb += len;
remain -= len; remain -= len;
} }
bufput_c('\x01'); bufput_c('\x01');
} }
END_TOPIC END_TOPIC
BEGIN_TOPIC(TOPIC_CHANGE_BACKDROP, TERM_BACKDROP_LEN+1+1) BEGIN_TOPIC(TOPIC_CHANGE_BACKDROP, TERM_BACKDROP_LEN+1+1)
bufput_c(TOPICMARK_BACKDROP); bufput_c(TOPICMARK_BACKDROP);
int len = (int) strlen(termconf_live.backdrop); size_t len = strlen(termconf_live.backdrop);
if (len > 0) { if (len > 0) {
memcpy(bb, termconf_live.backdrop, len); memcpy(bb, termconf_live.backdrop, len);
bb += len; bb += len;

@ -5,6 +5,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <esp8266.h> #include <esp8266.h>
#include <httpd.h> #include <httpd.h>
#include "config_xmacros.h"
/** /**
* This module handles the virtual screen and operations on it. * This module handles the virtual screen and operations on it.
@ -78,30 +79,59 @@ enum CursorShape {
#define TERMCONF_SIZE 400 #define TERMCONF_SIZE 400
#define TERMCONF_VERSION 4 #define TERMCONF_VERSION 4
//....Type................Name..Suffix...............Deref..XGET.........Cast..XSET.........................NOTIFY................Allow
// Deref is used to pass the field to xget. Cast is used to convert the &'d field to what xset wants (needed for static arrays)
#define XTABLE_TERMCONF \
X(u32, width, /**/, /**/, xget_dec, /**/, xset_u32, NULL, /**/, 1) \
X(u32, height, /**/, /**/, xget_dec, /**/, xset_u32, NULL, /**/, 1) \
X(u32, default_bg, /**/, /**/, xget_term_color, /**/, xset_term_color, NULL, /**/, 1) \
X(u32, default_fg, /**/, /**/, xget_term_color, /**/, xset_term_color, NULL, /**/, 1) \
X(char, title, [TERM_TITLE_LEN], /**/, xget_string, (s8**), xset_string, TERM_TITLE_LEN, /**/, 1) \
X(char, btn1, [TERM_BTN_LEN], /**/, xget_string, (s8**), xset_string, TERM_BTN_LEN, /**/, 1) \
X(char, btn2, [TERM_BTN_LEN], /**/, xget_string, (s8**), xset_string, TERM_BTN_LEN, /**/, 1) \
X(char, btn3, [TERM_BTN_LEN], /**/, xget_string, (s8**), xset_string, TERM_BTN_LEN, /**/, 1) \
X(char, btn4, [TERM_BTN_LEN], /**/, xget_string, (s8**), xset_string, TERM_BTN_LEN, /**/, 1) \
X(char, btn5, [TERM_BTN_LEN], /**/, xget_string, (s8**), xset_string, TERM_BTN_LEN, /**/, 1) \
X(u8, theme, /**/, /**/, xget_dec, /**/, xset_u8, NULL, /**/, 1) \
X(u32, parser_tout_ms, /**/, /**/, xget_dec, /**/, xset_u32, NULL, /**/, 1) \
X(u32, display_tout_ms, /**/, /**/, xget_dec, /**/, xset_u32, NULL, /**/, 1) \
X(bool, fn_alt_mode, /**/, /**/, xget_bool, /**/, xset_bool, NULL, /**/, 1) \
X(u8, config_version, /**/, /**/, xget_dec, /**/, xset_u8, NULL, /**/, 1) \
X(u32, display_cooldown_ms, /**/, /**/, xget_dec, /**/, xset_u32, NULL, /**/, 1) \
X(bool, loopback, /**/, /**/, xget_bool, /**/, xset_bool, NULL, /**/, 1) \
X(bool, show_buttons, /**/, /**/, xget_bool, /**/, xset_bool, NULL, /**/, 1) \
X(bool, show_config_links, /**/, /**/, xget_bool, /**/, xset_bool, NULL, /**/, 1) \
X(char, bm1, [TERM_BTN_MSG_LEN], /**/, xget_term_bm, (s8**), xset_term_bm, NULL, /**/, 1) \
X(char, bm2, [TERM_BTN_MSG_LEN], /**/, xget_term_bm, (s8**), xset_term_bm, NULL, /**/, 1) \
X(char, bm3, [TERM_BTN_MSG_LEN], /**/, xget_term_bm, (s8**), xset_term_bm, NULL, /**/, 1) \
X(char, bm4, [TERM_BTN_MSG_LEN], /**/, xget_term_bm, (s8**), xset_term_bm, NULL, /**/, 1) \
X(char, bm5, [TERM_BTN_MSG_LEN], /**/, xget_term_bm, (s8**), xset_term_bm, NULL, /**/, 1) \
X(u32, cursor_shape, /**/, /**/, xget_dec, /**/, xset_term_cursorshape, NULL, /**/, 1) \
X(bool, crlf_mode, /**/, /**/, xget_bool, /**/, xset_bool, NULL, /**/, 1) \
X(bool, want_all_fn, /**/, /**/, xget_bool, /**/, xset_bool, NULL, /**/, 1) \
X(bool, debugbar, /**/, /**/, xget_bool, /**/, xset_bool, NULL, /**/, 1) \
X(bool, allow_decopt_12, /**/, /**/, xget_bool, /**/, xset_bool, NULL, /**/, 1) \
X(bool, ascii_debug, /**/, /**/, xget_bool, /**/, xset_bool, NULL, /**/, 1) \
X(char, backdrop, [TERM_BACKDROP_LEN], /**/, xget_string, (s8**), xset_string, TERM_BACKDROP_LEN, /**/, 1)
#define TERM_BM_N(tc, n) ((tc)->bm1+(TERM_BTN_MSG_LEN*n))
#define TERM_BTN_N(tc, n) ((tc)->btn1+(TERM_BTN_LEN*n))
/** Export color for config */
void xget_term_color(char *buff, u32 value);
/** Export button message as stirng for config */
void xget_term_bm(char *buff, char *value);
/** Set button message */
enum xset_result xset_term_bm(const char *name, s8 **field, const char *buff, const void *arg);
/** Set color */
enum xset_result xset_term_color(const char *name, u32 *field, const char *buff, const void *arg);
/** Set cursor shape */
enum xset_result xset_term_cursorshape(const char *name, u32 *field, const char *buff, const void *arg);
typedef struct { typedef struct {
u32 width; #define X XSTRUCT_FIELD
u32 height; XTABLE_TERMCONF
u32 default_bg; // 00-FFh - ANSI colors, (00:00:00-FF:FF:FF)+256 - True Color #undef X
u32 default_fg;
char title[TERM_TITLE_LEN];
char btn[TERM_BTN_COUNT][TERM_BTN_LEN];
u8 theme;
u32 parser_tout_ms;
u32 display_tout_ms;
bool fn_alt_mode; // xterm compatibility mode (alternate codes for some FN keys)
u8 config_version;
u32 display_cooldown_ms;
bool loopback;
bool show_buttons;
bool show_config_links;
char btn_msg[TERM_BTN_COUNT][TERM_BTN_MSG_LEN];
enum CursorShape cursor_shape;
bool crlf_mode;
bool want_all_fn;
bool debugbar;
bool allow_decopt_12;
bool ascii_debug;
char backdrop[TERM_BACKDROP_LEN];
} TerminalConfigBundle; } TerminalConfigBundle;
// Live config // Live config
@ -150,6 +180,7 @@ void screen_resize(int rows, int cols);
void screen_set_title(const char *title); void screen_set_title(const char *title);
/** Set a button text */ /** Set a button text */
void screen_set_button_text(int num, const char *text); void screen_set_button_text(int num, const char *text);
void screen_set_button_message(int num, const char *msg);
/** Change backdrop */ /** Change backdrop */
void screen_set_backdrop(const char *url); void screen_set_backdrop(const char *url);

@ -25,21 +25,20 @@ enum pwlock {
PWLOCK_MAX = 5, PWLOCK_MAX = 5,
}; };
//....Type................Name..Suffix...............Deref..XGET..........Cast..XSET.........................NOTIFY....Allow
//....Type................Name..Suffix...............Deref..XGET........Allow..Cast..XSET.........................NOTIFY
// Deref is used to pass the field to xget. Cast is used to convert the &'d field to what xset wants (needed for static arrays) // Deref is used to pass the field to xget. Cast is used to convert the &'d field to what xset wants (needed for static arrays)
#define XTABLE_SYSCONF \ #define XTABLE_SYSCONF \
X(u32, uart_baudrate, /**/, /**/, xget_dec, 1, /**/, xset_sys_baudrate, NULL, xnoop) \ X(u32, uart_baudrate, /**/, /**/, xget_dec, /**/, xset_sys_baudrate, NULL, uart_changed=true, 1) \
X(u8, uart_parity, /**/, /**/, xget_dec, 1, /**/, xset_sys_parity, NULL, xnoop) \ X(u8, uart_parity, /**/, /**/, xget_dec, /**/, xset_sys_parity, NULL, uart_changed=true, 1) \
X(u8, uart_stopbits, /**/, /**/, xget_dec, 1, /**/, xset_sys_stopbits, NULL, xnoop) \ X(u8, uart_stopbits, /**/, /**/, xget_dec, /**/, xset_sys_stopbits, NULL, uart_changed=true, 1) \
\ \
X(u8, config_version, /**/, /**/, xget_dec, 0, /**/, xset_u8, NULL, xnoop) \ X(u8, config_version, /**/, /**/, xget_dec, /**/, xset_u8, NULL, /**/, 1) \
\ \
X(u8, pwlock, /**/, /**/, xget_dec, admin|tpl, /**/, xset_sys_pwlock, NULL, xnoop) \ X(u8, pwlock, /**/, /**/, xget_dec, /**/, xset_sys_pwlock, NULL, /**/, admin|tpl) \
X(u8, access_pw, [64], /**/, xget_ustring, admin, (u8**), xset_sys_accesspw, NULL, xnoop) \ X(u8, access_pw, [64], /**/, xget_ustring, (u8**), xset_sys_accesspw, NULL, /**/, admin) \
X(u8, access_name, [32], /**/, xget_ustring, admin|tpl, (u8**), xset_ustring, NULL, xnoop) \ X(u8, access_name, [32], /**/, xget_ustring, (u8**), xset_ustring, NULL, /**/, admin|tpl) \
\ \
X(bool, overclock, /**/, /**/, xget_bool, 1, /**/, xset_bool, NULL, xnoop) \ X(bool, overclock, /**/, /**/, xget_bool, /**/, xset_bool, NULL, /**/, 1) \
typedef struct { typedef struct {

@ -23,37 +23,37 @@
#define wifimgr_notify_ap() { wifi_change_flags.ap = true; } #define wifimgr_notify_ap() { wifi_change_flags.ap = true; }
#define wifimgr_notify_sta() { wifi_change_flags.ap = true; } #define wifimgr_notify_sta() { wifi_change_flags.ap = true; }
//....Type................Name..Suffix...............Deref..XGET.......Allow..Cast..XSET.........................NOTIFY //....Type................Name..Suffix...............Deref..XGET.........Cast..XSET.........................NOTIFY................Allow
// Deref is used to pass the field to xget. Cast is used to convert the &'d field to what xset wants (needed for static arrays) // Deref is used to pass the field to xget. Cast is used to convert the &'d field to what xset wants (needed for static arrays)
#define XTABLE_WIFI \ #define XTABLE_WIFI \
X(u8, opmode, /**/, /**/, xget_dec, 1, /**/, xset_wifi_opmode, NULL, xnoop) \ X(u8, opmode, /**/, /**/, xget_dec, /**/, xset_wifi_opmode, NULL, /**/, 1) \
\ \
X(u8, tpw, /**/, /**/, xget_dec, 1, /**/, xset_wifi_tpw, NULL, wifimgr_notify_ap) \ X(u8, tpw, /**/, /**/, xget_dec, /**/, xset_wifi_tpw, NULL, wifimgr_notify_ap(), 1) \
X(u8, ap_channel, /**/, /**/, xget_dec, 1, /**/, xset_wifi_ap_channel, NULL, wifimgr_notify_ap) \ X(u8, ap_channel, /**/, /**/, xget_dec, /**/, xset_wifi_ap_channel, NULL, wifimgr_notify_ap(), 1) \
X(u8, ap_ssid, [SSID_LEN], /**/, xget_ustring, 1, (u8**), xset_wifi_ssid, 1, wifimgr_notify_ap) \ X(u8, ap_ssid, [SSID_LEN], /**/, xget_ustring, (u8**), xset_wifi_ssid, 1, wifimgr_notify_ap(), 1) \
X(u8, ap_password, [PASSWORD_LEN], /**/, xget_ustring, 1, (u8**), xset_wifi_pwd, NULL, wifimgr_notify_ap) \ X(u8, ap_password, [PASSWORD_LEN], /**/, xget_ustring, (u8**), xset_wifi_pwd, NULL, wifimgr_notify_ap(), 1) \
X(bool, ap_hidden, /**/, /**/, xget_bool, 1, /**/, xset_bool, NULL, wifimgr_notify_ap) \ X(bool, ap_hidden, /**/, /**/, xget_bool, /**/, xset_bool, NULL, wifimgr_notify_ap(), 1) \
\ \
X(u16, ap_dhcp_time, /**/, /**/, xget_dec, 1, /**/, xset_wifi_lease_time, NULL, wifimgr_notify_ap) \ X(u16, ap_dhcp_time, /**/, /**/, xget_dec, /**/, xset_wifi_lease_time, NULL, wifimgr_notify_ap(), 1) \
X(u32, unused1, /**/, /**/, xget_dummy, 0, /**/, xset_dummy, NULL, xnoop) \ X(u32, unused1, /**/, /**/, xget_dummy, /**/, xset_dummy, NULL, /**/, 0) \
X(struct ip_addr, ap_dhcp_start, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_ap) \ X(struct ip_addr, ap_dhcp_start, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_ap(), 1) \
X(struct ip_addr, ap_dhcp_end, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_ap) \ X(struct ip_addr, ap_dhcp_end, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_ap(), 1) \
\ \
X(struct ip_addr, ap_addr_ip, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_ap) \ X(struct ip_addr, ap_addr_ip, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_ap(), 1) \
X(struct ip_addr, ap_addr_mask, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_ap) \ X(struct ip_addr, ap_addr_mask, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_ap(), 1) \
\ \
\ \
X(u32, unused2, /**/, /**/, xget_dummy, 0, /**/, xset_dummy, NULL, xnoop) \ X(u32, unused2, /**/, /**/, xget_dummy, /**/, xset_dummy, NULL, /**/, 0) \
X(u8, sta_ssid, [SSID_LEN], /**/, xget_ustring, 1, (u8**), xset_wifi_ssid, 0, wifimgr_notify_sta) \ X(u8, sta_ssid, [SSID_LEN], /**/, xget_ustring, (u8**), xset_wifi_ssid, 0, wifimgr_notify_sta(), 1) \
X(u8, sta_password, [PASSWORD_LEN], /**/, xget_ustring, 1, (u8**), xset_wifi_pwd, NULL, wifimgr_notify_sta) \ X(u8, sta_password, [PASSWORD_LEN], /**/, xget_ustring, (u8**), xset_wifi_pwd, NULL, wifimgr_notify_sta(), 1) \
X(bool, sta_dhcp_enable, /**/, /**/, xget_bool, 1, /**/, xset_bool, NULL, wifimgr_notify_sta) \ X(bool, sta_dhcp_enable, /**/, /**/, xget_bool, /**/, xset_bool, NULL, wifimgr_notify_sta(), 1) \
\ \
X(struct ip_addr, sta_addr_ip, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_sta) \ X(struct ip_addr, sta_addr_ip, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_sta(), 1) \
X(struct ip_addr, sta_addr_mask, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_sta) \ X(struct ip_addr, sta_addr_mask, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_sta(), 1) \
X(struct ip_addr, sta_addr_gw, /**/, &, xget_ip, 1, /**/, xset_ip, NULL, wifimgr_notify_sta) \ X(struct ip_addr, sta_addr_gw, /**/, &, xget_ip, /**/, xset_ip, NULL, wifimgr_notify_sta(), 1) \
\ \
\ \
X(u8, config_version, /**/, /**/, xget_dec, 0, /**/, xset_u8, NULL, xnoop) X(u8, config_version, /**/, /**/, xget_dec, /**/, xset_u8, NULL, /**/, 1)
// unused1 - replaces 'enabled' bit from old dhcps_lease struct // unused1 - replaces 'enabled' bit from old dhcps_lease struct
// unused2 - gap after 'ap_gw' which isn't used and doesn't make sense // unused2 - gap after 'ap_gw' which isn't used and doesn't make sense

Loading…
Cancel
Save