working terminal
This commit is contained in:
@@ -182,9 +182,15 @@ $1/%.o: %.S
|
||||
$(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@
|
||||
endef
|
||||
|
||||
.PHONY: all checkdirs clean libesphttpd default-tgt
|
||||
.PHONY: all web parser checkdirs clean libesphttpd default-tgt
|
||||
|
||||
all: checkdirs $(TARGET_OUT) $(FW_BASE)
|
||||
web:
|
||||
$(Q) ./build_web.sh
|
||||
|
||||
parser:
|
||||
$(Q) ./build_parser.sh
|
||||
|
||||
all: checkdirs web parser $(TARGET_OUT) $(FW_BASE)
|
||||
|
||||
libesphttpd/Makefile:
|
||||
$(Q) [[ -e "libesphttpd/Makefile" ]] || echo -e "\e[31mlibesphttpd submodule missing.\nIf build fails, run \"git submodule init\" and \"git submodule update\".\e[0m"
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "-- Building parser from Ragel source --"
|
||||
|
||||
ragel -L -G0 user/ansi_parser.rl -o user/ansi_parser.c
|
||||
|
||||
+3
-1
@@ -1,6 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "-- Preparing WWW files --"
|
||||
|
||||
mkdir -p html
|
||||
yuicompressor html_orig/style.css > html/style.css
|
||||
yuicompressor html_orig/script.js > html/script.js
|
||||
minify --type=html html_orig/index.html -o html/term.tpl
|
||||
minify --type=html html_orig/term.html -o html/term.tpl
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var $=function(d,c){d=d.match(/^(\W)?(.*)/);return(c||document)["getElement"+(d[1]?d[1]=="#"?"ById":"sByClassName":"sByTagName")](d[2])};var m=function(e,d,f){d=document;f=d.createElement("p");f.innerHTML=e;e=d.createDocumentFragment();while(d=f.firstChild){e.appendChild(d)}return e};(function(){function a(r){return document.createElement(r)}var b=26,k=10;var l={a:false,x:0,y:0,suppress:false,hidden:false};var o=[];var g=["#111213","#CC0000","#4E9A06","#C4A000","#3465A4","#75507B","#06989A","#D3D7CF","#555753","#EF2929","#8AE234","#FCE94F","#729FCF","#AD7FA8","#34E2E2","#EEEEEC"];function p(){o.forEach(function(r,s){r.t=" ";r.fg=7;r.bg=0;d(r)})}function c(s,r){return o[s*b+r]}function i(){return c(l.y,l.x)}function q(r){l.hidden=!r;l.a&=r;d(i(),l.a)}function f(s,r){l.suppress=true;d(i(),false);l.x=r;l.y=s;l.suppress=false;d(i(),l.a)}function d(s,r){var v=s.e,t,u;t=r?s.bg:s.fg;u=r?s.fg:s.bg;v.innerText=(s.t+" ")[0];v.style.color=e(t);v.style.backgroundColor=e(u);v.style.fontWeight=t>7?"bold":"normal"}function h(){o.forEach(function(s,t){var r=l.a&&(t==l.y*b+l.x);d(s,r)})}function j(u){l.x=u.x;l.y=u.y;var v=0,B=0,x=u.screen;var r,w,A,z,s,y;while(v<x.length&&B<b*k){z=o[B++];r=z.fg=parseInt(x[v++],16);w=z.bg=parseInt(x[v++],16);A=z.t=x[v++];switch(x[v]){case"r":s=1;break;case"s":s=2;break;case"t":s=3;break;case"u":s=4;break;default:s=0}if(s>0){y=parseInt(x.substr(v+1,s));v=v+s+1;for(;y>0&&B<b*k;y--){z=o[B++];z.fg=r;z.bg=w;z.t=A}}}h()}function e(r){r=parseInt(r);if(r<0||r>15){r=0}return g[r]}function n(v){var u,r,t=$("#screen");for(var s=0;s<b*k;s++){u=a("span");if((s>0)&&(s%b==0)){t.appendChild(a("br"))}t.appendChild(u);r={t:" ",fg:7,bg:0,e:u};o.push(r);d(r)}setInterval(function(){l.a=!l.a;if(l.hidden){l.a=false}if(!l.suppress){d(i(),l.a)}},500);j(v)}window.Term={init:n,load:j,setCursor:f,enableCursor:q,clear:p}})();(function(){var g="ws://"+window.location.host+"/ws/update.cgi";var d;function c(i){console.log("CONNECTED")}function b(i){console.error("SOCKET CLOSED")}function f(i){try{Term.load(JSON.parse(i.data))}catch(j){console.error(j)}}function e(i){console.error(i.data)}function a(i){if(typeof i!="string"){i=JSON.stringify(i)}d.send(i)}function h(){d=new WebSocket(g);d.onopen=c;d.onclose=b;d.onmessage=f;d.onerror=e;console.log("Opening socket.")}window.Conn={ws:null,init:h,send:a}})();function init(a){Term.init(a);Conn.init()};
|
||||
var $=function(d,c){d=d.match(/^(\W)?(.*)/);return(c||document)["getElement"+(d[1]?d[1]=="#"?"ById":"sByClassName":"sByTagName")](d[2])};var m=function(e,d,f){d=document;f=d.createElement("p");f.innerHTML=e;e=d.createDocumentFragment();while(d=f.firstChild){e.appendChild(d)}return e};(function(){function a(r){return document.createElement(r)}var b=26,k=10;var l={a:false,x:0,y:0,suppress:false,hidden:false};var o=[];var g=["#111213","#CC0000","#4E9A06","#C4A000","#3465A4","#75507B","#06989A","#D3D7CF","#555753","#EF2929","#8AE234","#FCE94F","#729FCF","#AD7FA8","#34E2E2","#EEEEEC"];function p(){o.forEach(function(r,s){r.t=" ";r.fg=7;r.bg=0;d(r)})}function c(s,r){return o[s*b+r]}function i(){return c(l.y,l.x)}function q(r){l.hidden=!r;l.a&=r;d(i(),l.a)}function f(s,r){l.suppress=true;d(i(),false);l.x=r;l.y=s;l.suppress=false;d(i(),l.a)}function d(s,r){var v=s.e,t,u;t=r?s.bg:s.fg;u=r?s.fg:s.bg;v.innerText=(s.t+" ")[0];v.style.color=e(t);v.style.backgroundColor=e(u);v.style.fontWeight=t>7?"bold":"normal"}function h(){o.forEach(function(s,t){var r=l.a&&(t==l.y*b+l.x);d(s,r)})}function j(v){l.x=v.x;l.y=v.y;var w=0,C=0,y=v.screen;var r=7,x=0;while(w<y.length&&C<b*k){var A=o[C++];var u=y[w];if(u!=","){r=A.fg=parseInt(y[w++],16);x=A.bg=parseInt(y[w++],16)}else{w++;A.fg=r;A.bg=x}var B=A.t=y[w++];var s=0;switch(y[w]){case"r":s=1;break;case"s":s=2;break;case"t":s=3;break;case"u":s=4;break;default:s=0}if(s>0){var z=parseInt(y.substr(w+1,s));w=w+s+1;for(;z>0&&C<b*k;z--){A=o[C++];A.fg=r;A.bg=x;A.t=B}}}h()}function e(r){r=parseInt(r);if(r<0||r>15){r=0}return g[r]}function n(v){var u,r,t=$("#screen");for(var s=0;s<b*k;s++){u=a("span");if((s>0)&&(s%b==0)){t.appendChild(a("br"))}t.appendChild(u);r={t:" ",fg:7,bg:0,e:u};o.push(r);d(r)}setInterval(function(){l.a=!l.a;if(l.hidden){l.a=false}if(!l.suppress){d(i(),l.a)}},500);j(v)}window.Term={init:n,load:j,setCursor:f,enableCursor:q,clear:p}})();(function(){var g="ws://"+window.location.host+"/ws/update.cgi";var d;function c(i){console.log("CONNECTED")}function b(i){console.error("SOCKET CLOSED")}function f(i){try{console.log("RX: ",i.data);Term.load(JSON.parse(i.data))}catch(j){console.error(j)}}function e(i){console.error(i.data)}function a(i){if(typeof i!="string"){i=JSON.stringify(i)}d.send(i)}function h(){d=new WebSocket(g);d.onopen=c;d.onclose=b;d.onmessage=f;d.onerror=e;console.log("Opening socket.")}window.Conn={ws:null,init:h,send:a}})();function init(a){Term.init(a);Conn.init()};
|
||||
+18
-6
@@ -163,15 +163,26 @@ var m = function(
|
||||
cursor.y = obj.y;
|
||||
|
||||
// Simple compression - hexFG hexBG 'ASCII' (r/s/t/u NUM{1,2,3,4})?
|
||||
// comma instead of both colors = same as before
|
||||
|
||||
var i = 0, ci = 0, str = obj.screen;
|
||||
var fg, bg, t, cell, repchars, rep;
|
||||
var fg = 7, bg = 0;
|
||||
while(i < str.length && ci<W*H) {
|
||||
cell = screen[ci++];
|
||||
fg = cell.fg = parseInt(str[i++], 16);
|
||||
bg = cell.bg = parseInt(str[i++], 16);
|
||||
t = cell.t = str[i++];
|
||||
var cell = screen[ci++];
|
||||
|
||||
var j = str[i];
|
||||
if (j != ',') { // comma = repeat last colors
|
||||
fg = cell.fg = parseInt(str[i++], 16);
|
||||
bg = cell.bg = parseInt(str[i++], 16);
|
||||
} else {
|
||||
i++;
|
||||
cell.fg = fg;
|
||||
cell.bg = bg;
|
||||
}
|
||||
|
||||
var t = cell.t = str[i++];
|
||||
|
||||
var repchars = 0;
|
||||
switch(str[i]) {
|
||||
case 'r': repchars = 1; break;
|
||||
case 's': repchars = 2; break;
|
||||
@@ -181,7 +192,7 @@ var m = function(
|
||||
}
|
||||
|
||||
if (repchars > 0) {
|
||||
rep = parseInt(str.substr(i+1,repchars));
|
||||
var rep = parseInt(str.substr(i+1,repchars));
|
||||
i = i + repchars + 1;
|
||||
for (; rep>0 && ci<W*H; rep--) {
|
||||
cell = screen[ci++];
|
||||
@@ -263,6 +274,7 @@ var m = function(
|
||||
|
||||
function onMessage(evt) {
|
||||
try {
|
||||
console.log("RX: ", evt.data);
|
||||
// Assume all our messages are screen updates
|
||||
Term.load(JSON.parse(evt.data));
|
||||
} catch(e) {
|
||||
|
||||
+41
-28
@@ -188,11 +188,11 @@ handle_plainchar(char c)
|
||||
static const char _ansi_actions[] = {
|
||||
0, 1, 0, 1, 1, 1, 2, 1,
|
||||
3, 1, 4, 1, 5, 1, 6, 1,
|
||||
7, 1, 8
|
||||
7, 1, 8, 1, 9
|
||||
};
|
||||
|
||||
static const char _ansi_eof_actions[] = {
|
||||
0, 0, 0, 13, 13, 0, 0
|
||||
0, 15, 15, 13, 13, 0, 0
|
||||
};
|
||||
|
||||
static const int ansi_start = 1;
|
||||
@@ -267,11 +267,11 @@ case 1:
|
||||
goto tr0;
|
||||
case 2:
|
||||
switch( (*p) ) {
|
||||
case 91: goto tr2;
|
||||
case 91: goto tr3;
|
||||
case 93: goto tr4;
|
||||
case 99: goto tr5;
|
||||
}
|
||||
goto tr3;
|
||||
goto tr2;
|
||||
case 0:
|
||||
goto _out;
|
||||
case 5:
|
||||
@@ -312,27 +312,28 @@ case 6:
|
||||
goto tr6;
|
||||
}
|
||||
|
||||
tr3: cs = 0; goto _again;
|
||||
tr6: cs = 0; goto f4;
|
||||
tr0: cs = 1; goto f0;
|
||||
tr2: cs = 0; goto f0;
|
||||
tr6: cs = 0; goto f5;
|
||||
tr0: cs = 1; goto f1;
|
||||
tr1: cs = 2; goto _again;
|
||||
tr7: cs = 4; goto f5;
|
||||
tr8: cs = 4; goto f6;
|
||||
tr9: cs = 4; goto f7;
|
||||
tr2: cs = 5; goto f1;
|
||||
tr4: cs = 5; goto f2;
|
||||
tr5: cs = 5; goto f3;
|
||||
tr10: cs = 6; goto f8;
|
||||
tr7: cs = 4; goto f6;
|
||||
tr8: cs = 4; goto f7;
|
||||
tr9: cs = 4; goto f8;
|
||||
tr3: cs = 5; goto f2;
|
||||
tr4: cs = 5; goto f3;
|
||||
tr5: cs = 5; goto f4;
|
||||
tr10: cs = 6; goto f9;
|
||||
|
||||
f0: _acts = _ansi_actions + 1; goto execFuncs;
|
||||
f1: _acts = _ansi_actions + 3; goto execFuncs;
|
||||
f5: _acts = _ansi_actions + 5; goto execFuncs;
|
||||
f6: _acts = _ansi_actions + 7; goto execFuncs;
|
||||
f7: _acts = _ansi_actions + 9; goto execFuncs;
|
||||
f8: _acts = _ansi_actions + 11; goto execFuncs;
|
||||
f4: _acts = _ansi_actions + 13; goto execFuncs;
|
||||
f2: _acts = _ansi_actions + 15; goto execFuncs;
|
||||
f1: _acts = _ansi_actions + 1; goto execFuncs;
|
||||
f2: _acts = _ansi_actions + 3; goto execFuncs;
|
||||
f6: _acts = _ansi_actions + 5; goto execFuncs;
|
||||
f7: _acts = _ansi_actions + 7; goto execFuncs;
|
||||
f8: _acts = _ansi_actions + 9; goto execFuncs;
|
||||
f9: _acts = _ansi_actions + 11; goto execFuncs;
|
||||
f5: _acts = _ansi_actions + 13; goto execFuncs;
|
||||
f0: _acts = _ansi_actions + 15; goto execFuncs;
|
||||
f3: _acts = _ansi_actions + 17; goto execFuncs;
|
||||
f4: _acts = _ansi_actions + 19; goto execFuncs;
|
||||
|
||||
execFuncs:
|
||||
_nacts = *_acts++;
|
||||
@@ -397,21 +398,27 @@ execFuncs:
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
/* #line 288 "user/ansi_parser.rl" */
|
||||
/* #line 280 "user/ansi_parser.rl" */
|
||||
{
|
||||
{cs = 1; goto _again;}
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
/* #line 292 "user/ansi_parser.rl" */
|
||||
{
|
||||
// TODO implement OS control code parsing
|
||||
{cs = 1; goto _again;}
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
/* #line 293 "user/ansi_parser.rl" */
|
||||
case 9:
|
||||
/* #line 297 "user/ansi_parser.rl" */
|
||||
{
|
||||
// Reset screen
|
||||
handle_RESET_cmd();
|
||||
{cs = 1; goto _again;}
|
||||
}
|
||||
break;
|
||||
/* #line 415 "user/ansi_parser.c" */
|
||||
/* #line 422 "user/ansi_parser.c" */
|
||||
}
|
||||
}
|
||||
goto _again;
|
||||
@@ -434,7 +441,13 @@ _again:
|
||||
{cs = 1; goto _again;}
|
||||
}
|
||||
break;
|
||||
/* #line 438 "user/ansi_parser.c" */
|
||||
case 7:
|
||||
/* #line 280 "user/ansi_parser.rl" */
|
||||
{
|
||||
{cs = 1; goto _again;}
|
||||
}
|
||||
break;
|
||||
/* #line 451 "user/ansi_parser.c" */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -442,6 +455,6 @@ _again:
|
||||
_out: {}
|
||||
}
|
||||
|
||||
/* #line 311 "user/ansi_parser.rl" */
|
||||
/* #line 315 "user/ansi_parser.rl" */
|
||||
|
||||
}
|
||||
|
||||
+5
-1
@@ -277,6 +277,10 @@ ansi_parser(const char *newdata, size_t len)
|
||||
fgoto main;
|
||||
}
|
||||
|
||||
action main_fail {
|
||||
fgoto main;
|
||||
}
|
||||
|
||||
CSI_body := ((32..47|60..64) @CSI_leading)?
|
||||
((digit @CSI_digit)* ';' @CSI_semi)*
|
||||
(digit @CSI_digit)* alpha @CSI_end $!CSI_fail;
|
||||
@@ -305,7 +309,7 @@ ansi_parser(const char *newdata, size_t len)
|
||||
']' @OSC_start |
|
||||
'c' @RESET_cmd
|
||||
)
|
||||
)+;
|
||||
)+ $!main_fail;
|
||||
|
||||
write exec;
|
||||
}%%
|
||||
|
||||
+106
-22
@@ -53,10 +53,22 @@ static Coordinate W = SCREEN_DEF_W;
|
||||
*/
|
||||
static Coordinate H = SCREEN_DEF_H;
|
||||
|
||||
// XXX volatile is probably not needed
|
||||
static volatile int notifyLock = 0;
|
||||
|
||||
//endregion
|
||||
|
||||
//region Helpers
|
||||
|
||||
#define NOTIFY_LOCK() do { \
|
||||
notifyLock++; \
|
||||
} while(0)
|
||||
|
||||
#define NOTIFY_DONE() do { \
|
||||
if (notifyLock > 0) notifyLock--; \
|
||||
if (notifyLock == 0) screen_notifyChange(); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Reset a cell
|
||||
*/
|
||||
@@ -103,12 +115,13 @@ cursor_reset(void)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_init(void)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
for (unsigned int i = 0; i < MAX_SCREEN_SIZE; i++) {
|
||||
cell_init(&screen[i]);
|
||||
}
|
||||
|
||||
cursor_reset();
|
||||
screen_notifyChange();
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,9 +130,10 @@ screen_init(void)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_reset(void)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
screen_clear(CLEAR_ALL);
|
||||
cursor_reset();
|
||||
screen_notifyChange();
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,6 +142,7 @@ screen_reset(void)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_clear(ClearMode mode)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
switch (mode) {
|
||||
case CLEAR_ALL:
|
||||
clear_range(0, W * H - 1);
|
||||
@@ -141,7 +156,7 @@ screen_clear(ClearMode mode)
|
||||
clear_range(0, (cursor.y * W) + cursor.x);
|
||||
break;
|
||||
}
|
||||
screen_notifyChange();
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,6 +165,7 @@ screen_clear(ClearMode mode)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_clear_line(ClearMode mode)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
switch (mode) {
|
||||
case CLEAR_ALL:
|
||||
clear_range(cursor.y * W, (cursor.y + 1) * W - 1);
|
||||
@@ -163,7 +179,7 @@ screen_clear_line(ClearMode mode)
|
||||
clear_range(cursor.y * W, cursor.y * W + cursor.x);
|
||||
break;
|
||||
}
|
||||
screen_notifyChange();
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -179,6 +195,7 @@ screen_clear_line(ClearMode mode)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_resize(Coordinate w, Coordinate h)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
// sanitize
|
||||
if (w < 1) w = 1;
|
||||
if (h < 1) h = 1;
|
||||
@@ -186,7 +203,7 @@ screen_resize(Coordinate w, Coordinate h)
|
||||
W = w;
|
||||
H = h;
|
||||
screen_reset();
|
||||
screen_notifyChange();
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,13 +212,15 @@ screen_resize(Coordinate w, Coordinate h)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_scroll_up(unsigned int lines)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
if (lines >= H - 1) {
|
||||
screen_clear(CLEAR_ALL);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// bad cmd
|
||||
if (lines == 0) {
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
int y;
|
||||
@@ -210,7 +229,9 @@ screen_scroll_up(unsigned int lines)
|
||||
}
|
||||
|
||||
clear_range(y * W, W * H - 1);
|
||||
screen_notifyChange();
|
||||
|
||||
done:
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,13 +240,15 @@ screen_scroll_up(unsigned int lines)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_scroll_down(unsigned int lines)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
if (lines >= H - 1) {
|
||||
screen_clear(CLEAR_ALL);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// bad cmd
|
||||
if (lines == 0) {
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
int y;
|
||||
@@ -234,7 +257,8 @@ screen_scroll_down(unsigned int lines)
|
||||
}
|
||||
|
||||
clear_range(0, lines * W-1);
|
||||
screen_notifyChange();
|
||||
done:
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -247,11 +271,12 @@ screen_scroll_down(unsigned int lines)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_cursor_set(Coordinate x, Coordinate y)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
if (x >= W) x = W - 1;
|
||||
if (y >= H) y = H - 1;
|
||||
cursor.x = x;
|
||||
cursor.y = y;
|
||||
screen_notifyChange();
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,9 +285,10 @@ screen_cursor_set(Coordinate x, Coordinate y)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_cursor_set_x(Coordinate x)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
if (x >= W) x = W - 1;
|
||||
cursor.x = x;
|
||||
screen_notifyChange();
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -271,9 +297,10 @@ screen_cursor_set_x(Coordinate x)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_cursor_set_y(Coordinate y)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
if (y >= H) y = H - 1;
|
||||
cursor.y = y;
|
||||
screen_notifyChange();
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -282,10 +309,27 @@ screen_cursor_set_y(Coordinate y)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_cursor_move(int dx, int dy)
|
||||
{
|
||||
if (dx < 0 && -dx > cursor.x) dx = -cursor.x;
|
||||
if (dy < 0 && -dy > cursor.y) dy = -cursor.y;
|
||||
screen_cursor_set(cursor.x + dx, cursor.y + dy);
|
||||
screen_notifyChange();
|
||||
NOTIFY_LOCK();
|
||||
int move;
|
||||
|
||||
cursor.x += dx;
|
||||
cursor.y += dy;
|
||||
if (cursor.x >= W) cursor.x = W - 1;
|
||||
if (cursor.x < 0) cursor.x = 0;
|
||||
|
||||
if (cursor.y < 0) {
|
||||
move = -cursor.y;
|
||||
cursor.y = 0;
|
||||
screen_scroll_down((unsigned int)move);
|
||||
}
|
||||
|
||||
if (cursor.y >= H) {
|
||||
move = cursor.y - (H - 1);
|
||||
cursor.y = H - 1;
|
||||
screen_scroll_up((unsigned int)move);
|
||||
}
|
||||
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,9 +348,10 @@ screen_cursor_save(void)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_cursor_restore(void)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
cursor.x = cursor_sav.x;
|
||||
cursor.y = cursor_sav.y;
|
||||
screen_notifyChange();
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,8 +360,9 @@ screen_cursor_restore(void)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_cursor_enable(bool enable)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
cursor.visible = enable;
|
||||
screen_notifyChange();
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -383,7 +429,44 @@ screen_set_bright_fg(void)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_putchar(char ch)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
|
||||
Cell *c = &screen[cursor.x + cursor.y * W];
|
||||
|
||||
// Special treatment for CRLF
|
||||
switch (ch) {
|
||||
case '\r':
|
||||
screen_cursor_set_x(0);
|
||||
goto done;
|
||||
|
||||
case '\n':
|
||||
screen_cursor_move(0, 1);
|
||||
goto done;
|
||||
|
||||
case 8: // BS
|
||||
if (cursor.x > 0) cursor.x--;
|
||||
// erase target cell
|
||||
c = &screen[cursor.x + cursor.y * W];
|
||||
c->c = ' ';
|
||||
goto done;
|
||||
|
||||
case 9: // TAB
|
||||
c->c = ' ';
|
||||
// nested recurs >:( but it's ok
|
||||
screen_putchar(' ');
|
||||
screen_putchar(' ');
|
||||
screen_putchar(' ');
|
||||
screen_putchar(' ');
|
||||
goto done;
|
||||
|
||||
default:
|
||||
if (ch < ' ') {
|
||||
// Discard
|
||||
warn("Ignoring control char %d", (int)c);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
c->c = ch;
|
||||
|
||||
if (cursor.inverse) {
|
||||
@@ -407,7 +490,8 @@ screen_putchar(char ch)
|
||||
}
|
||||
}
|
||||
|
||||
screen_notifyChange();
|
||||
done:
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
|
||||
@@ -495,7 +579,7 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data)
|
||||
ss->lastFg = 0;
|
||||
ss->lastChar = '\0';
|
||||
|
||||
bufprint("{x:%d,y:%d,screen:\"", cursor.x, cursor.y);
|
||||
bufprint("{\"x\":%d,\"y\":%d,\"screen\":\"", cursor.x, cursor.y);
|
||||
}
|
||||
|
||||
int i = ss->index;
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ typedef enum {
|
||||
} ClearMode;
|
||||
|
||||
typedef uint8_t Color;
|
||||
typedef unsigned int Coordinate;
|
||||
typedef int Coordinate;
|
||||
|
||||
httpd_cgi_state ICACHE_FLASH_ATTR
|
||||
screenSerializeToBuffer(char *buffer, size_t buf_len, void **data);
|
||||
|
||||
+6
-3
@@ -25,7 +25,10 @@ void ICACHE_FLASH_ATTR serialInit(void)
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR UART_HandleRxByte(char c)
|
||||
{
|
||||
// TODO buffering, do not run parser after just 1 char
|
||||
printf("(%c)", c);
|
||||
ansi_parser(&c, 1);
|
||||
if (c > 0 && c < 127) {
|
||||
// TODO buffering, do not run parser after just 1 char
|
||||
ansi_parser(&c, 1);
|
||||
} else {
|
||||
warn("Bad char %d ('%c')", (unsigned char)c, c);
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -55,8 +55,7 @@ void ICACHE_FLASH_ATTR myWebsocketConnect(Websock *ws) {
|
||||
* @return
|
||||
*/
|
||||
httpd_cgi_state ICACHE_FLASH_ATTR tplScreen(HttpdConnData *connData, char *token, void **arg) {
|
||||
// cleanup
|
||||
if (!connData) {
|
||||
if (token==NULL) {
|
||||
// Release data object
|
||||
screenSerializeToBuffer(NULL, 0, arg);
|
||||
return HTTPD_CGI_DONE;
|
||||
@@ -67,6 +66,9 @@ httpd_cgi_state ICACHE_FLASH_ATTR tplScreen(HttpdConnData *connData, char *token
|
||||
|
||||
if (streq(token, "screenData")) {
|
||||
httpd_cgi_state cont = screenSerializeToBuffer(buff, bufsiz, arg);
|
||||
|
||||
dbg("Sending buf: %s", buff);
|
||||
|
||||
httpdSend(connData, buff, -1);
|
||||
return cont;
|
||||
}
|
||||
@@ -104,8 +106,7 @@ HttpdBuiltInUrl builtInUrls[]={ //ICACHE_RODATA_ATTR
|
||||
|
||||
// TODO add funcs for WiFi management (when web UI is added)
|
||||
|
||||
// ROUTE_TPL_FILE("/", tplScreen, "term.tpl"),
|
||||
ROUTE_TPL("/term.tpl", tplScreen),
|
||||
ROUTE_TPL_FILE("/", tplScreen, "term.tpl"),
|
||||
ROUTE_FILESYSTEM(),
|
||||
ROUTE_END(),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user