Ondřej Hruška / ESPTerm
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers espterm.cpp Source File

espterm.cpp

00001 #include "mbed.h"
00002 #include "espterm.hpp"
00003 
00004 #include <cstdarg>
00005 
00006 
00007 void ESPTerm::init(Serial *s)
00008 {
00009     cs = -1;
00010     device_ok = false;
00011     
00012     on_mouse = NULL;
00013     on_button = NULL;
00014     on_key = NULL;
00015     on_esp_reset = NULL;
00016     on_char_rx = NULL;
00017     on_osc_rx = NULL;
00018     
00019     ser = s;
00020     ser->attach(callback(this, &ESPTerm::ser_rx_char), Serial::RxIrq);
00021 }
00022 
00023 
00024 ESPTerm::ESPTerm(Serial *s)
00025 {
00026     init(s);    
00027 }
00028 
00029 
00030 ESPTerm::ESPTerm(void)
00031 {
00032     // Defaults
00033     init(new Serial(PA_2, PA_3, 115200));
00034 }
00035 
00036 
00037 ESPTerm::ESPTerm(PinName txPin, PinName rxPin, int baud)
00038 {
00039     init(new Serial(txPin, rxPin, baud));
00040 }
00041 
00042 
00043 // ----- Printing -----
00044 
00045 
00046 int ESPTerm::printf(const char *format, ...)
00047 {    
00048     std::va_list arg;
00049     va_start(arg, format);
00050     int r = ser->vprintf(format, arg);
00051     va_end(arg);
00052     
00053     return r;
00054 }
00055 
00056 
00057 // alias of printf
00058 int ESPTerm::print(const char *format, ...)
00059 {    
00060     std::va_list arg;
00061     va_start(arg, format);
00062     int r = ser->vprintf(format, arg);
00063     va_end(arg);
00064     
00065     return r;
00066 }
00067 
00068 
00069 int ESPTerm::println(const char *format, ...) {
00070     std::va_list arg;
00071     va_start(arg, format);
00072     int r = ser->vprintf(format, arg);
00073     va_end(arg);
00074         
00075     r += ser->puts("\r\n");    
00076     return r;   
00077 }
00078 
00079 
00080 // ----- Colors -----
00081 
00082 
00083 void ESPTerm::fg(Color c)
00084 {
00085     int ci = c;
00086     if(ci > 7) {
00087         ci += (90-8);
00088     } else {
00089         ci += 30;
00090     }
00091     ser->printf("\033[%dm", ci);
00092 }
00093 
00094 
00095 void ESPTerm::bg(Color c)
00096 {
00097     int ci = c;
00098     if(ci > 7) {
00099         ci += (100-8);
00100     } else {
00101         ci += 40;
00102     }
00103     ser->printf("\033[%dm", ci);
00104 }
00105 
00106 
00107 void ESPTerm::reset_attribs(void)
00108 {
00109     ser->puts("\033[0m");
00110 }
00111 
00112 
00113 // ----- Cursor control & erasing -----
00114 
00115 
00116 void ESPTerm::go_to(int y, int x)
00117 {
00118     ser->printf("\033[%d;%dH", y, x);
00119 }
00120 
00121 
00122 void ESPTerm::move(int dy, int dx)
00123 {
00124     if (dy != 0) {
00125         if (dy > 0) {
00126             // Down
00127             ser->printf("\033[%dB", dy);
00128         }    
00129         else {
00130             // Up
00131             ser->printf("\033[%dA", -dy);
00132         }
00133     } 
00134     
00135     if (dx != 0) {
00136         if (dx > 0) {
00137             // Forward
00138             ser->printf("\033[%dC", dx);
00139         }    
00140         else {
00141             // Backward
00142             ser->printf("\033[%dD", -dx);
00143         }
00144     }   
00145 }
00146 
00147 
00148 void ESPTerm::clear_screen(ClearMode mode)
00149 {
00150     ser->printf("\033[%dJ", mode);
00151 }
00152 
00153 
00154 void ESPTerm::clear_line(ClearMode mode)
00155 {
00156     ser->printf("\033[%dK", mode);
00157 }
00158 
00159 
00160 void ESPTerm::screen_reset(void)
00161 {
00162     ser->puts("\033c");
00163 }
00164 
00165 
00166 void ESPTerm::show_cursor(bool yes)
00167 {
00168     if (yes) {
00169         ser->puts("\033[?25h");
00170     } 
00171     else {
00172         ser->puts("\033[?25l");
00173     }
00174 }
00175 
00176 
00177 void ESPTerm::scroll(int lines)
00178 {
00179     if (lines > 0) {        
00180         ser->printf("\033[%dT", lines);    
00181     }  
00182     else {
00183         ser->printf("\033[%dS", -lines);
00184     }  
00185 }
00186 
00187 
00188 void ESPTerm::cursor_push(bool with_attribs)
00189 {
00190     if (with_attribs) {
00191         ser->puts("\0337");
00192     } 
00193     else {
00194         ser->puts("\033[s");
00195     }
00196 }
00197 
00198 
00199 void ESPTerm::cursor_pop(bool with_attribs)
00200 {
00201     if (with_attribs) {
00202         ser->puts("\0338");
00203     } 
00204     else {
00205         ser->puts("\033[u");
00206     }    
00207 }
00208 
00209 
00210 void ESPTerm::wrap_enable(bool yes)
00211 {
00212     if (yes) {
00213         ser->puts("\033[?7h");
00214     } 
00215     else {
00216         ser->puts("\033[?7l");
00217     }    
00218 }
00219 
00220 
00221 // ----- System commands -----
00222 
00223 
00224 void ESPTerm::factory_reset(void)
00225 {
00226     ser->puts("\033]FR\a");
00227 }
00228 
00229 
00230 void ESPTerm::set_screen_size(int rows, int cols)
00231 {
00232     ser->printf("\033]W%d;%d\a", rows, cols);
00233 }
00234 
00235 
00236 bool ESPTerm::query_status(void)
00237 {
00238     if (device_ok) return true;
00239     
00240     ser->puts("\033[5n");
00241     return false;    
00242 }
00243 
00244 
00245 // ----- Rx command parsing -----
00246 
00247 
00248 void ESPTerm::ser_rx_char(void)
00249 {
00250     while (ser->readable()) {
00251         char c = ser->getc();
00252         ansi_parser(&c, 1);  // pretend as if it was a string, this is safe         
00253     }    
00254 }
00255 
00256 
00257 void ESPTerm::apars_handle_plainchar(char c)
00258 {
00259     if (c == 24) {
00260         if (on_esp_reset) on_esp_reset();    
00261     } 
00262     else if (c >= 1 && c <= 5) {
00263         if (on_button) on_button((int)c);        
00264     }
00265     else {
00266         if (on_char_rx) on_char_rx(c);            
00267     }
00268 }
00269 
00270 
00271 void ESPTerm::apars_handle_csi(char lead, const int* nums, char keychar)
00272 {
00273     // Keyboard events
00274     if (on_key) {
00275         if (keychar == 'A') on_key(KEY_UP);
00276         else if (keychar == 'B') on_key(KEY_DOWN);
00277         else if (keychar == 'C') on_key(KEY_RIGHT);
00278         else if (keychar == 'D') on_key(KEY_LEFT);        
00279     }
00280     
00281     // Screen tapped / clicked
00282     if (on_mouse && keychar == 'M') {
00283         on_mouse(nums[0], nums[1], (MouseEvent) nums[2]);    
00284     }
00285     
00286     // "Device OK" response to "Device Status Query"
00287     if (keychar == 'n' && nums[0] == 0) {
00288         device_ok = true;    
00289     }
00290        
00291     // ... other commands when added
00292 }
00293 
00294 
00295 void ESPTerm::apars_handle_osc(const char *str)
00296 {
00297     // ... additional parsing when needed in later esp term versions
00298     if (on_osc_rx) on_osc_rx(str);
00299 }
00300 
00301 
00302 void ESPTerm::apars_handle_badseq(void)
00303 {
00304     // Do nothing    
00305 }
00306 
00307 
00308 
00309 /* ----- Ragel constants block ------ */
00310 
00311 /* #line 38 "ansi_parser_cpp.c" */
00312 static const int ansi_start = 1;
00313 //static const int ansi_first_final = 7;
00314 //static const int ansi_error = 0;
00315 
00316 //static const int ansi_en_CSI_body = 3;
00317 //static const int ansi_en_OSC_body = 5;
00318 //static const int ansi_en_main = 1;
00319 
00320 
00321 
00322 /* Ragel generated parser */
00323 
00324 /**
00325  * \brief Linear ANSI chars stream parser (Rage generated)
00326  *
00327  * Parses a stream of bytes using a Ragel parser. The defined
00328  * grammar does not use 'unget', so the entire buffer is
00329  * always processed in a linear manner.
00330  *
00331  * \attention -> but always check the Ragel output for 'p--'
00332  *            or 'p -=', that means trouble.
00333  *
00334  * \param newdata - array of new chars to process
00335  * \param len - length of the newdata buffer
00336  */
00337 void ESPTerm::ansi_parser(const char *newdata, size_t len)
00338 {
00339     if (len == 0) len = strlen(newdata);
00340     
00341     // Load new data to Ragel vars
00342     const char *p = newdata;
00343     const char *eof = NULL;
00344     const char *pe = newdata + len;
00345 
00346     // Init Ragel on the first run
00347     if (cs == -1) {
00348         
00349 /* #line 77 "ansi_parser_cpp.c" */
00350     {
00351     cs = ansi_start;
00352     }
00353 
00354 /* #line 65 "ansi_parser_cpp.rl" */
00355     }
00356 
00357     // The parser
00358     
00359 /* #line 87 "ansi_parser_cpp.c" */
00360     {
00361     if ( p == pe )
00362         goto _test_eof;
00363     switch ( cs )
00364     {
00365 tr0:
00366 /* #line 75 "ansi_parser_cpp.rl" */
00367     {
00368             apars_handle_plainchar((*p));
00369         }
00370     goto st1;
00371 st1:
00372     if ( ++p == pe )
00373         goto _test_eof1;
00374 case 1:
00375 /* #line 103 "ansi_parser_cpp.c" */
00376     if ( (*p) == 27 )
00377         goto st2;
00378     goto tr0;
00379 st2:
00380     if ( ++p == pe )
00381         goto _test_eof2;
00382 case 2:
00383     switch( (*p) ) {
00384         case 91: goto tr3;
00385         case 93: goto tr4;
00386     }
00387     goto tr2;
00388 tr2:
00389 /* #line 116 "ansi_parser_cpp.rl" */
00390     {
00391             apars_handle_badseq();
00392             {goto st1;}
00393         }
00394 //    goto st0;
00395 /* #line 123 "ansi_parser_cpp.c" */
00396 //st0:
00397 //cs = 0;
00398 //    goto _out;
00399 tr3:
00400 /* #line 82 "ansi_parser_cpp.rl" */
00401     {
00402             /* Reset the CSI builder */
00403             csi_leading = csi_char = 0;
00404             csi_ni = 0;
00405 
00406             /* Zero out digits */
00407             for(int i = 0; i < CSI_N_MAX; i++) {
00408                 csi_n[i] = 0;
00409             }
00410 
00411             {goto st3;}
00412         }
00413     //goto st7;
00414 tr4:
00415 /* #line 129 "ansi_parser_cpp.rl" */
00416     {
00417             /* Reset the OSC buffer */
00418             osc_i = 0;
00419             {goto st5;}
00420         }
00421     //goto st7;
00422 //st7:
00423 //    if ( ++p == pe )
00424 //        goto _test_eof7;
00425 case 7:
00426 /* #line 154 "ansi_parser_cpp.c" */
00427     if ( (*p) == 27 )
00428         goto st2;
00429     goto tr0;
00430 st3:
00431     if ( ++p == pe )
00432         goto _test_eof3;
00433 case 3:
00434     if ( (*p) == 59 )
00435         goto tr7;
00436     if ( (*p) < 60 ) {
00437         if ( (*p) > 47 ) {
00438             if ( 48 <= (*p) && (*p) <= 57 )
00439                 goto tr6;
00440         } else if ( (*p) >= 32 )
00441             goto tr5;
00442     } else if ( (*p) > 64 ) {
00443         if ( (*p) > 90 ) {
00444             if ( 97 <= (*p) && (*p) <= 122 )
00445                 goto tr8;
00446         } else if ( (*p) >= 65 )
00447             goto tr8;
00448     } else
00449         goto tr5;
00450     goto tr2;
00451 tr5:
00452 /* #line 95 "ansi_parser_cpp.rl" */
00453     {
00454             csi_leading = (*p);
00455         }
00456     goto st4;
00457 tr6:
00458 /* #line 99 "ansi_parser_cpp.rl" */
00459     {
00460             /* x10 + digit */
00461             if (csi_ni < CSI_N_MAX) {
00462                 csi_n[csi_ni] = csi_n[csi_ni]*10 + ((*p) - '0');
00463             }
00464         }
00465     goto st4;
00466 tr7:
00467 /* #line 106 "ansi_parser_cpp.rl" */
00468     {
00469             csi_ni++;
00470         }
00471     goto st4;
00472 st4:
00473     if ( ++p == pe )
00474         goto _test_eof4;
00475 case 4:
00476 /* #line 204 "ansi_parser_cpp.c" */
00477     if ( (*p) == 59 )
00478         goto tr7;
00479     if ( (*p) < 65 ) {
00480         if ( 48 <= (*p) && (*p) <= 57 )
00481             goto tr6;
00482     } else if ( (*p) > 90 ) {
00483         if ( 97 <= (*p) && (*p) <= 122 )
00484             goto tr8;
00485     } else
00486         goto tr8;
00487     goto tr2;
00488 tr8:
00489 /* #line 110 "ansi_parser_cpp.rl" */
00490     {
00491             csi_char = (*p);
00492             apars_handle_csi(csi_leading, csi_n, csi_char);
00493             {goto st1;}
00494         }
00495    // goto st8;
00496 //st8:
00497 //    if ( ++p == pe )
00498 //        goto _test_eof8;
00499 case 8:
00500 /* #line 228 "ansi_parser_cpp.c" */
00501     goto tr2;
00502 tr9:
00503 /* #line 135 "ansi_parser_cpp.rl" */
00504     {
00505             if (osc_i < OSC_BUF_LEN-1) {
00506                 osc_buff[osc_i++] = (*p);
00507             }
00508         }
00509     goto st5;
00510 st5:
00511     if ( ++p == pe )
00512         goto _test_eof5;
00513 case 5:
00514 /* #line 242 "ansi_parser_cpp.c" */
00515     switch( (*p) ) {
00516         case 7: goto tr10;
00517         case 27: goto st6;
00518     }
00519     goto tr9;
00520 tr10:
00521 /* #line 141 "ansi_parser_cpp.rl" */
00522     {
00523             /** Terminate the buffer */
00524             osc_buff[osc_i] = '\0';
00525             apars_handle_osc(osc_buff);
00526             
00527             {goto st1;}
00528         }
00529    // goto st9;
00530 //st9:
00531 //    if ( ++p == pe )
00532 //        goto _test_eof9;
00533 case 9:
00534 /* #line 262 "ansi_parser_cpp.c" */
00535     goto tr2;
00536 st6:
00537     if ( ++p == pe )
00538         goto _test_eof6;
00539 case 6:
00540     if ( (*p) == 92 )
00541         goto tr10;
00542     goto tr2;
00543     }
00544     _test_eof1: cs = 1; goto _test_eof; 
00545     _test_eof2: cs = 2; goto _test_eof; 
00546     //_test_eof7: cs = 7; goto _test_eof; 
00547     _test_eof3: cs = 3; goto _test_eof; 
00548     _test_eof4: cs = 4; goto _test_eof; 
00549     //_test_eof8: cs = 8; goto _test_eof; 
00550     _test_eof5: cs = 5; goto _test_eof; 
00551     //_test_eof9: cs = 9; goto _test_eof; 
00552     _test_eof6: cs = 6; goto _test_eof; 
00553 
00554     _test_eof: {}
00555     if ( p == eof )
00556     {
00557     switch ( cs ) {
00558     case 1: 
00559     case 2: 
00560     case 3: 
00561     case 4: 
00562     case 5: 
00563     case 6: 
00564 /* #line 116 "ansi_parser_cpp.rl" */
00565     {
00566             apars_handle_badseq();
00567             {goto st1;}
00568         }
00569  //   break;
00570 /* #line 298 "ansi_parser_cpp.c" */
00571     }
00572     }
00573 
00574     //_out: {}
00575     }
00576 
00577 /* #line 162 "ansi_parser_cpp.rl" */
00578 
00579 }
00580 
00581 
00582 
00583 
00584 
00585 
00586 
00587 
00588 
00589 
00590 
00591 
00592 
00593 
00594 
00595 
00596 
00597 
00598 
00599