Support library for the ESP8266 Wireless Terminal. Can also be used for communicating with any VT100-compatible terminal.

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" */
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+