Support library for the ESP8266 Wireless Terminal. Can also be used for communicating with any VT100-compatible terminal.
Diff: espterm.cpp
- Revision:
- 4:294e8f53ebcd
- Parent:
- 3:1114012184bf
- Child:
- 5:7379bd37f3e2
--- a/espterm.cpp Sun Mar 19 10:34:48 2017 +0000 +++ b/espterm.cpp Sun Mar 19 17:19:16 2017 +0000 @@ -4,17 +4,42 @@ #include <cstdarg> +void ESPTerm::init(Serial *s) +{ + cs = -1; + device_ok = false; + + on_mouse_click = NULL; + on_button = NULL; + on_esp_reset = NULL; + on_char_rx = NULL; + on_key_press = NULL; + on_osc_rx = NULL; + + ser = s; + ser->attach(callback(this, &ESPTerm::ser_rx_char), Serial::RxIrq); +} + + ESPTerm::ESPTerm(Serial *s) { - this->ser = s; + init(s); } ESPTerm::ESPTerm(void) { - this->ser = new Serial(PA_2, PA_3, 115200); + // Defaults + init(new Serial(PA_2, PA_3, 115200)); } + +ESPTerm::ESPTerm(PinName txPin, PinName rxPin, int baud) +{ + init(new Serial(txPin, rxPin, baud)); +} + + // ----- Printing ----- @@ -28,6 +53,7 @@ return r; } + // alias of printf int ESPTerm::print(const char *format, ...) { @@ -39,12 +65,6 @@ return r; } -// print without args -int ESPTerm::puts(const char *str) -{ - return ser->puts(str); -} - int ESPTerm::println(const char *format, ...) { std::va_list arg; @@ -84,26 +104,12 @@ } -void ESPTerm::colors(Color fg, Color bg) -{ - this->fg(fg); - this->bg(bg); -} - - void ESPTerm::reset_attribs(void) { ser->puts("\033[0m"); } -// alias -void ESPTerm::rst(void) -{ - this->reset_attribs(); -} - - // ----- Cursor control & erasing ----- @@ -153,3 +159,369 @@ { ser->printf("\033]W%d;%d\a", rows, cols); } + + +bool ESPTerm::query_status(void) +{ + if (device_ok) return true; + + ser->puts("\033[5n"); + return false; +} + + +// ----- Rx command parsing ----- + + +void ESPTerm::ser_rx_char(void) +{ + while (ser->readable()) { + char c = ser->getc(); + ansi_parser(&c, 1); // pretend as if it was a string, this is safe + } +} + + +void ESPTerm::apars_handle_plainchar(char c) +{ + if (c == 24) { + if (on_esp_reset) on_esp_reset(); + } + else if (c >= 1 && c <= 5) { + if (on_button) on_button((int)c); + } + else { + if (on_char_rx) on_char_rx(c); + } +} + + +void ESPTerm::apars_handle_csi(char lead, const int* nums, char keychar) +{ + // Keyboard events + if (on_key_press) { + if (keychar == 'A') on_key_press(KEY_UP); + else if (keychar == 'B') on_key_press(KEY_DOWN); + else if (keychar == 'C') on_key_press(KEY_RIGHT); + else if (keychar == 'D') on_key_press(KEY_LEFT); + } + + // Screen tapped / clicked + if (on_mouse_click && keychar == 'M') { + on_mouse_click(nums[0], nums[1]); + } + + // "Device OK" response to "Device Status Query" + if (keychar == 'n' && nums[0] == 0) { + device_ok = true; + } + + // ... other commands when added +} + + +void ESPTerm::apars_handle_osc(const char *str) +{ + // ... additional parsing when needed in later esp term versions + if (on_osc_rx) on_osc_rx(str); +} + + +void ESPTerm::apars_handle_badseq(void) +{ + // Do nothing +} + + + +/* ----- Ragel constants block ------ */ + +/* #line 38 "ansi_parser_cpp.c" */ +static const int ansi_start = 1; +//static const int ansi_first_final = 7; +//static const int ansi_error = 0; + +//static const int ansi_en_CSI_body = 3; +//static const int ansi_en_OSC_body = 5; +//static const int ansi_en_main = 1; + + + +/* Ragel generated parser */ + +/** + * \brief Linear ANSI chars stream parser (Rage generated) + * + * Parses a stream of bytes using a Ragel parser. The defined + * grammar does not use 'unget', so the entire buffer is + * always processed in a linear manner. + * + * \attention -> but always check the Ragel output for 'p--' + * or 'p -=', that means trouble. + * + * \param newdata - array of new chars to process + * \param len - length of the newdata buffer + */ +void ESPTerm::ansi_parser(const char *newdata, size_t len) +{ + if (len == 0) len = strlen(newdata); + + // Load new data to Ragel vars + const char *p = newdata; + const char *eof = NULL; + const char *pe = newdata + len; + + // Init Ragel on the first run + if (cs == -1) { + +/* #line 77 "ansi_parser_cpp.c" */ + { + cs = ansi_start; + } + +/* #line 65 "ansi_parser_cpp.rl" */ + } + + // The parser + +/* #line 87 "ansi_parser_cpp.c" */ + { + if ( p == pe ) + goto _test_eof; + switch ( cs ) + { +tr0: +/* #line 75 "ansi_parser_cpp.rl" */ + { + apars_handle_plainchar((*p)); + } + goto st1; +st1: + if ( ++p == pe ) + goto _test_eof1; +case 1: +/* #line 103 "ansi_parser_cpp.c" */ + if ( (*p) == 27 ) + goto st2; + goto tr0; +st2: + if ( ++p == pe ) + goto _test_eof2; +case 2: + switch( (*p) ) { + case 91: goto tr3; + case 93: goto tr4; + } + goto tr2; +tr2: +/* #line 116 "ansi_parser_cpp.rl" */ + { + apars_handle_badseq(); + {goto st1;} + } +// goto st0; +/* #line 123 "ansi_parser_cpp.c" */ +//st0: +//cs = 0; +// goto _out; +tr3: +/* #line 82 "ansi_parser_cpp.rl" */ + { + /* Reset the CSI builder */ + csi_leading = csi_char = 0; + csi_ni = 0; + + /* Zero out digits */ + for(int i = 0; i < CSI_N_MAX; i++) { + csi_n[i] = 0; + } + + {goto st3;} + } + //goto st7; +tr4: +/* #line 129 "ansi_parser_cpp.rl" */ + { + /* Reset the OSC buffer */ + osc_i = 0; + {goto st5;} + } + //goto st7; +//st7: +// if ( ++p == pe ) +// goto _test_eof7; +case 7: +/* #line 154 "ansi_parser_cpp.c" */ + if ( (*p) == 27 ) + goto st2; + goto tr0; +st3: + if ( ++p == pe ) + goto _test_eof3; +case 3: + if ( (*p) == 59 ) + goto tr7; + if ( (*p) < 60 ) { + if ( (*p) > 47 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr6; + } else if ( (*p) >= 32 ) + goto tr5; + } else if ( (*p) > 64 ) { + if ( (*p) > 90 ) { + if ( 97 <= (*p) && (*p) <= 122 ) + goto tr8; + } else if ( (*p) >= 65 ) + goto tr8; + } else + goto tr5; + goto tr2; +tr5: +/* #line 95 "ansi_parser_cpp.rl" */ + { + csi_leading = (*p); + } + goto st4; +tr6: +/* #line 99 "ansi_parser_cpp.rl" */ + { + /* x10 + digit */ + if (csi_ni < CSI_N_MAX) { + csi_n[csi_ni] = csi_n[csi_ni]*10 + ((*p) - '0'); + } + } + goto st4; +tr7: +/* #line 106 "ansi_parser_cpp.rl" */ + { + csi_ni++; + } + goto st4; +st4: + if ( ++p == pe ) + goto _test_eof4; +case 4: +/* #line 204 "ansi_parser_cpp.c" */ + if ( (*p) == 59 ) + goto tr7; + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr6; + } else if ( (*p) > 90 ) { + if ( 97 <= (*p) && (*p) <= 122 ) + goto tr8; + } else + goto tr8; + goto tr2; +tr8: +/* #line 110 "ansi_parser_cpp.rl" */ + { + csi_char = (*p); + apars_handle_csi(csi_leading, csi_n, csi_char); + {goto st1;} + } + // goto st8; +//st8: +// if ( ++p == pe ) +// goto _test_eof8; +case 8: +/* #line 228 "ansi_parser_cpp.c" */ + goto tr2; +tr9: +/* #line 135 "ansi_parser_cpp.rl" */ + { + if (osc_i < OSC_BUF_LEN-1) { + osc_buff[osc_i++] = (*p); + } + } + goto st5; +st5: + if ( ++p == pe ) + goto _test_eof5; +case 5: +/* #line 242 "ansi_parser_cpp.c" */ + switch( (*p) ) { + case 7: goto tr10; + case 27: goto st6; + } + goto tr9; +tr10: +/* #line 141 "ansi_parser_cpp.rl" */ + { + /** Terminate the buffer */ + osc_buff[osc_i] = '\0'; + apars_handle_osc(osc_buff); + + {goto st1;} + } + // goto st9; +//st9: +// if ( ++p == pe ) +// goto _test_eof9; +case 9: +/* #line 262 "ansi_parser_cpp.c" */ + goto tr2; +st6: + if ( ++p == pe ) + goto _test_eof6; +case 6: + if ( (*p) == 92 ) + goto tr10; + goto tr2; + } + _test_eof1: cs = 1; goto _test_eof; + _test_eof2: cs = 2; goto _test_eof; + //_test_eof7: cs = 7; goto _test_eof; + _test_eof3: cs = 3; goto _test_eof; + _test_eof4: cs = 4; goto _test_eof; + //_test_eof8: cs = 8; goto _test_eof; + _test_eof5: cs = 5; goto _test_eof; + //_test_eof9: cs = 9; goto _test_eof; + _test_eof6: cs = 6; goto _test_eof; + + _test_eof: {} + if ( p == eof ) + { + switch ( cs ) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: +/* #line 116 "ansi_parser_cpp.rl" */ + { + apars_handle_badseq(); + {goto st1;} + } + // break; +/* #line 298 "ansi_parser_cpp.c" */ + } + } + + //_out: {} + } + +/* #line 162 "ansi_parser_cpp.rl" */ + +} + + + + + + + + + + + + + + + + + + + +