Inspired by Simon Ford's "Terminal" library, this is a clean-room reimplementation that supports a larger set of the ANSI escape sequences and includes a few handy drawing routines. Useful for making console UIs for your projects. The box-drawing stuff requires your terminal to be set to codepage 850.

Fork of ANSITerm by Dan Summers

Revision:
0:863811463610
Child:
2:a681bda60db7
diff -r 000000000000 -r 863811463610 ANSITerm.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ANSITerm.cpp	Tue Sep 18 18:58:19 2012 +0000
@@ -0,0 +1,174 @@
+/*
+Copyright (c) 2012 dansummers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in 
+the Software without restriction, including without limitation the rights to 
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
+of the Software, and to permit persons to whom the Software is furnished to do 
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all 
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
+SOFTWARE.
+ */
+#include "ANSITerm.h"
+#include "mbed.h"
+
+//Box styles
+/* topleft, topright, bottomleft, bottomright, horiz, vert, uptee, downtee, lefttee, righttee,cross */
+const char ANSITerm::two_lines[11] = {0xC9,0xBB,0xC8,0xBC,0xCD,0xBA,0xCA,0xCB,0xB9,0xCC,0xCE};
+const char ANSITerm::one_line[11] = {0xDA,0xBF,0xC0,0xD9,0xC4,0xB3,0xC1,0xC2,0xB4,0xC3,0xC5};
+const char ANSITerm::simple[11] = {'+','+','+','+','-','|','+','+','+','+','+'};
+
+ANSITerm::ANSITerm(PinName tx, PinName rx) : Serial(tx, rx) {current_style = 0;}
+
+/* Device Status Report (Returns CSIn;mR, where n,m is the coordinates of the cursor). */
+void ANSITerm::ansi_dsr(int* x_coord, int* y_coord)
+{
+    char _r; bool reading_x = false; bool reading_y = false;
+    this->puts("6n"); wait(0.02);
+
+    /* detect presence of symbol "CMSIS_OS_RTX", and switch on thread safety if we spot it (mutexes, thread.wait instead of wait, etc) */
+    /* TODO: Make thread-safe at some point. */
+    /*Reply format is "\033[<ycoord>;<xcoord>R" */
+    *x_coord = 0; *y_coord = 0;
+    while(this->readable() == 1) 
+    {
+        _r = this->getc();
+        switch(_r) {
+            case 033:
+                //ignore, start of DSR
+                break;
+            case '[':
+                //next char starts the y-coordinate
+                reading_y = true;
+                break;
+            default:
+                //this is probably a numeric: check and, if so, subtract 48 to decode the ASCII to int.
+                if((_r>47) && (_r<58)) {
+                    if(reading_x == true) {
+                        *x_coord = ((*x_coord)*10) + (_r-48);
+                    } else if(reading_y == true) {
+                        *y_coord = ((*y_coord)*10) + (_r-48);
+                    }
+                } else {
+                    /* Not a numeric, ignore it.*/
+                }
+                break;
+            case ';':
+                //next char starts the x-coordinate
+                reading_y = false; reading_x = true;
+                break;
+            case 'R':
+                //end of ANSI-DSR reply
+                return;
+        }
+    }
+}
+
+/* Select Graphic Rendition - Make the output bold, underlined, coloured... all manner of things.*/
+void ANSITerm::ansi_sgr(bool reset, char text_style, char text_colour, char background_colour)
+{
+  bool needs_sep = false;
+  if(reset) { this->putc('0'); }
+  else
+  {
+    /* text style (select many) */
+    // These two are mutually exclusive
+    if((text_style & SGR_BOLD) == SGR_BOLD) { this->putc('1'); }
+    else if ((text_style & SGR_FAINT) == SGR_FAINT){ this->putc('2'); }
+    else{ this->puts("22"); }
+    this->putc(';');
+    
+    if((text_style & SGR_ITALIC) == SGR_ITALIC) { this->putc('3'); }
+    else{ this->puts("23"); }
+    this->putc(';');
+    
+    if((text_style & SGR_UNDERLINE) == SGR_UNDERLINE) { this->putc('4'); }
+    else{ this->puts("24"); }
+    this->putc(';');
+    
+    // These two are mutually exclusive
+    if((text_style & SGR_BLINK_SLOW) == SGR_BLINK_SLOW) { this->putc('5'); }
+    else if ((text_style & SGR_BLINK_RAPID) == SGR_BLINK_RAPID) { this->putc('6'); }
+    else{ this->puts("25"); }
+    this->putc(';');
+    
+    if((text_style & SGR_IMAGE_NEGATIVE) == SGR_IMAGE_NEGATIVE) { this->putc('7'); }
+    else{ this->puts("27"); }
+    this->putc(';');
+    
+    if((text_style & SGR_CROSSED_OUT) == SGR_CROSSED_OUT) { this->putc('9'); }
+    else{ this->puts("29"); }
+    needs_sep = true;
+    
+    /* text colour (select 1) */
+    if(text_colour != 0)
+    {
+      if(needs_sep) { this->putc(';'); }/* Emit a separator if needed. */
+      if ((text_colour & SGR_BLACK) == SGR_BLACK) { this->puts("30"); }
+      else if((text_colour & SGR_RED) == SGR_RED) { this->puts("31"); }
+      else if((text_colour & SGR_GREEN) == SGR_GREEN) { this->puts("32"); }
+      else if((text_colour & SGR_YELLOW) == SGR_YELLOW) { this->puts("33"); }
+      else if((text_colour & SGR_BLUE) == SGR_BLUE) { this->puts("34"); }
+      else if((text_colour & SGR_MAGENTA) == SGR_MAGENTA) { this->puts("35"); }
+      else if((text_colour & SGR_CYAN) == SGR_CYAN) { this->puts("36"); }
+      else if((text_colour & SGR_WHITE) == SGR_WHITE) { this->puts("37"); }
+    }
+    /* background_colour (select 1) */
+    if(background_colour != 0)
+    {
+      if(needs_sep) { this->putc(';'); needs_sep = false; }
+      if ((background_colour & SGR_BLACK) == SGR_BLACK) { this->puts("40"); }
+      else if((background_colour & SGR_RED) == SGR_RED) { this->puts("41"); }
+      else if((background_colour & SGR_GREEN) == SGR_GREEN) { this->puts("42"); }
+      else if((background_colour & SGR_YELLOW) == SGR_YELLOW) { this->puts("43"); }
+      else if((background_colour & SGR_BLUE) == SGR_BLUE) { this->puts("44"); }
+      else if((background_colour & SGR_MAGENTA) == SGR_MAGENTA) { this->puts("45"); }
+      else if((background_colour & SGR_CYAN) == SGR_CYAN) { this->puts("46"); }
+      else if((background_colour & SGR_WHITE) == SGR_WHITE) { this->puts("47"); }
+    }
+  }
+  putc('m');
+}
+
+/*
+  Draw a box with the specified top-left and bottom-right points (these are the coords of the box, not its contents!)
+  Style is an array of chars to use to draw the box, [topleft, topright, bottomleft, bottomright, horiz, vert, uptee, downtee, lefttee, righttee,cross].
+  if clear_inner is set, the 'contents' of the box onscreen will be erased.  If it's clear, they won't be.
+ */
+void ANSITerm::draw_box(int x1, int y1, int x2, int y2, const char* style, bool clear_inner)
+{
+  this->set_cursor_position(x1,y1);
+  //draw the top row
+  this->putc(style[0]); for(int i = x1; i<(x2-1);i++) this->putc(style[4]); this->putc(style[1]);
+  
+  for(int i=(y1+1); i<(y2);i++)
+  {
+    this->set_cursor_position(x1,i);
+    this->putc(style[5]);//draw the left-hand side of this row
+    this->set_cursor_position(x2,i);
+    this->putc(style[5]);//draw the right-hand side of this row
+  }
+  
+  if(clear_inner)
+  {
+    for(int i = (y1+1);i<(y2);i++)
+    {
+      this->set_cursor_position((x1+1),i); //position at the start of this row
+      for(int j=x1;j<(x2-1);j++) this->putc(' '); //fill it with spaces
+    }
+  }
+  
+  this->set_cursor_position(x1,y2);
+  //draw the bottom row
+  this->putc(style[2]); for(int i = x1; i<(x2-1);i++) this->putc(style[4]); this->putc(style[3]);
+}
\ No newline at end of file