Ansiterm: a ansi terminal library

I’ve written a library that simplifies the use of ansi terminal escape codes. The updated version of the code resides at:
http://code.google.com/p/qrptracker/source/browse/#svn/trunk/Arduino/libraries/Ansiterm
And you’ll find a video of a useful application of this library at

The files as of [timestamp=1266006177] are Ansiterm.h

/* 
Ansiterm.cpp -- an Arduino library that simplifies using the ANSI terminal
control escape sequences. This allows your code to  position text exactly in the
terminal, to add colour and other effects. To use Ansiterm, an ANSI terminal must
be connected to the Arduino's serial port. The terminal built into the Arduino 
IDE does not respond to the ANSI codes, but most MacOs and Linux terminals do. 
In Windows, I read that Hyperterm responds to ANSI codes. Realterm responds to most
codes, but will not change the color of the foreground.

The accompanying example file illustrates the library's use.

Copyright (c) 2009 Bruce Robertson, VE9QRP. All rights reserved.

This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 2.1 of the License, or (at your option)
any later version.

This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.

You should have received a copy of the GNU Lesser General Public License along
with this library; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

The latest version of this software is available at http://code.google.com/p/qrptracker/
*/

#ifndef Ansiterm_h
#define Ansiterm_h
#include "WProgram.h"

#define ESCAPE 0x1B
#define BRACE '['
#define BLACK 0
#define RED 1
#define      GREEN 2
#define YELLOW 3
#define BLUE 4
#define MAGENTA 5
#define CYAN 6 
#define WHITE 7
#define BOLD_ON 1
#define BOLD_OFF 22
#define UNDERLINE_ON 4
#define UNDERLINE_OFF 24
#define ITALICS_ON 3
#define ITALICS_OFF 23
#define STRIKETHROUGH_ON 9
#define STRIKETHROUGH_OFF 29
#define INVERSE_ON 7
#define INVERSE_OFF 27
#define RESET 1
#define DEFAULT_FOREGROUND 39
#define DEFAULT_BACKGROUND 49


class Ansiterm {
      
public:
      Ansiterm();
      void home();
      void xy(int x, int y);
      void up(int x); 
      void down(int x);
      void forward(int x);
      void backward(int x);
      void eraseLine();
      void eraseScreen();
      void setBackgroundColor(int color);
      void setForegroundColor(int color);
        void boldOn();
        void boldOff();
        void underlineOn();
        void underlineOff();
        void italicsOn();
        void italicsOff();
        void strikethroughOn();
        void strikethroughOff();
        void inverseOn();
        void inverseOff();
        void reset();
        void defaultBackground();
        void defaultForeground();
        void fill(int x1, int y1, int x2, int y2);
private:
      void preamble();
      void preambleAndNumberAndValue(int x, char v);
      void setAttribute(int a);
      
};
#endif

and Ansiterm.cpp

/* 
Ansiterm.cpp -- an Arduino library that simplifies using the ANSI terminal
control escape sequences. This allows your code to  position text exactly in the
terminal, to add colour and other effects. To use Ansiterm, an ANSI terminal must
be connected to the Arduino's serial port. The terminal built into the Arduino 
IDE does not respond to the ANSI codes, but most MacOs and Linux terminals do. 
In Windows, I read that Hyperterm responds to ANSI codes. Realterm responds to most
codes, but will not change the color of the foreground.

The accompanying example file illustrates the library's use.

Copyright (c) 2009 Bruce Robertson, VE9QRP. All rights reserved.

This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 2.1 of the License, or (at your option)
any later version.

This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.

You should have received a copy of the GNU Lesser General Public License along
with this library; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

The latest version of this software is available at
*/

#include "WProgram.h"
#include "Ansiterm.h"

Ansiterm::Ansiterm()
{
}


void Ansiterm::home()
{
  preamble();
  Serial.write('H');
}


void Ansiterm::xy(int x, int y)
{
  preamble();
  Serial.print(y,DEC);
  Serial.write(';');
  Serial.print(x, DEC);
  Serial.write('H');
}


void Ansiterm::up(int x)
{
  preambleAndNumberAndValue(x,'A');
}


void Ansiterm::down(int x)
{
  preambleAndNumberAndValue(x,'B');
}


void Ansiterm::forward(int x)
{
  preambleAndNumberAndValue(x,'C');
}


void Ansiterm::backward(int x)
{
  preambleAndNumberAndValue(x,'D');
}


void Ansiterm::eraseLine()
{
  preamble();
  Serial.write('2');
  Serial.write('K');
}


void Ansiterm::eraseScreen()
{
  preamble();
  Serial.write('1');
  Serial.write('J');
}


void Ansiterm::setBackgroundColor(int color)
{
  setAttribute(color + 40);
}


void Ansiterm::setForegroundColor(int color)
{
  setAttribute(color + 30);
}


void Ansiterm::boldOn()
{
  setAttribute(BOLD_ON);
}


void Ansiterm::boldOff()
{
  setAttribute(BOLD_OFF);
}


void Ansiterm::italicsOn()
{
  setAttribute(ITALICS_ON);
}


void Ansiterm::italicsOff()
{
  setAttribute(ITALICS_OFF);
}


void Ansiterm::underlineOn()
{
  setAttribute(UNDERLINE_ON);
}


void Ansiterm::underlineOff()
{
  setAttribute(UNDERLINE_OFF);
}


void Ansiterm::strikethroughOn()
{
  setAttribute(STRIKETHROUGH_ON);
}


void Ansiterm::strikethroughOff()
{
  setAttribute(STRIKETHROUGH_OFF);
}


void Ansiterm::inverseOn()
{
  setAttribute(INVERSE_ON);
}


void Ansiterm::inverseOff()
{
  setAttribute(INVERSE_OFF);
}


void Ansiterm::reset()
{
  setAttribute(RESET);
}


void Ansiterm::defaultBackground()
{
  setAttribute(DEFAULT_BACKGROUND);
}


void Ansiterm::defaultForeground()
{
  setAttribute(DEFAULT_FOREGROUND);
}


void Ansiterm::fill(int x1, int y1, int x2, int y2)
{
  for (int x = x1; x <= x2; x++)
  {
    for (int y = y1; y <= y2; y++)
    {
      xy(x,y);
      Serial.print(' ');
    }
  }
}


/* private functions */
void Ansiterm::preamble()
{
  Serial.write(ESCAPE);
  Serial.write(BRACE);
}


void Ansiterm::preambleAndNumberAndValue(int x, char v)
{
  preamble();
  Serial.print(x,DEC);
  Serial.write(v);
}


void Ansiterm::setAttribute(int a)
{
  preambleAndNumberAndValue(a, 'm');
}

A test program that puts it through its paces is:

#include <Ansiterm.h>

char * messages[][3] = {{"Name", "Age", "Favorite Sport"}, {"Bruce", "42", "Arduino"}, {"John", "23", "Baseball"}, {"Joel", "9", "Swimming"}, {"Phoebe", "14", "Highland Dancing"}};

Ansiterm ansi;
void setup() {
  Serial.begin(38400);
}

void loop() {
  splash("Testing 'forward', 'backward', 'up', 'down', and overwriting ...");
  ansi.home();//works
  ansi.eraseScreen();
  ansi.setBackgroundColor(BLUE);//works
  ansi.setForegroundColor(GREEN);//realterm doesn't do this, macos does
  ansi.forward(10);//works
  Serial.write("10");
  ansi.forward(10);
  Serial.write("20");
  ansi.forward(10);
  Serial.write("30");
 ansi.down(1);

  ansi.setBackgroundColor(RED);
  ansi.setForegroundColor(WHITE);
  Serial.print("White on red, to be erased");
  delay(1000);
  ansi.eraseLine();//works
  ansi.up(1);//works
  ansi.backward(50);
  Serial.print("One line above, this to be written over");
  ansi.backward(20);
  ansi.setForegroundColor(BLACK);
  delay(2000);
  Serial.print("this appears over the last line");
  delay(2000);
  splash("Testing tabs (doesn't seem to work)");
  ansi.setTabAtColumn(33);//doesn't seem to work
  ansi.setTabAtColumn(66);
  Serial.write(9);
  Serial.write("33");
  Serial.write(9);
  Serial.write("66");
  
  splash("Testing xy function ...");
  ansi.setBackgroundColor(YELLOW);
  ansi.setForegroundColor(BLACK);
  ansi.eraseScreen();
  
  for (int x = 1; x < 60; x+=10) {
    delay(200);
    for (int y = 1; y < 14;  y +=2) {
      ansi.xy(x,y);
      Serial.print(x,DEC);
      Serial.print(",");
      Serial.print(y,DEC);
      delay(200);
    }
  }
  
  ansi.eraseScreen();
  delay(1000);
  splash("Making a table ...");
  //ansi.setBackgroundColor(MAGENTA);
  //ansi.setForegroundColor(YELLOW);
  for (int x = 0; x < 3; x++) {
    for (int y = 0; y < 4; y++) {
      ansi.xy(x*20,y+1);    
    if (y == 0) {
      ansi.setForegroundColor(GREEN);
    }
    else {ansi.setForegroundColor(WHITE);
    }
    Serial.print(messages[y][x]);
    }
  }
  delay(4000);
  ansi.eraseScreen();
}

void splash(char * message) {
    ansi.setBackgroundColor(BLACK);
   ansi.eraseScreen();//works
  ansi.home();
  ansi.setBackgroundColor(GREEN);
  Serial.print(message);
  delay(1000);
      ansi.setBackgroundColor(BLACK);
   ansi.eraseScreen();
}

That's pretty cool, and fast refresh, too! Maybe this should go in the playground?

Thanks, cr0sh, I'm glad you like it. Would you put it under InterfacingWithHardware#Communication in playground?

Hmm - that's a tough one; it could either go there, or it could go in the output/visual area (maybe a new sub-cat of "terminal emulation"?).

I really don't know as this is one of those "crossover" areas; maybe someone else could chime in and help (or maybe you can PM one of the mods)...

:)

it would be great if the Arduino serial monitor would be enhanced with some ansi commands. Since the Arduino has no debug possibilities i use print command to track the programm flow. Sometimes these ouputs are confusing, a formatted output would be very helpful. martin

I find that terminal rather quirky in other aspects as well. However, given the number of excellent full-fledged terminal programs, I don't think it really makes sense for Arduino development to be devoted to these efforts. Rather, I just turn off the Arduino terminal and launch an ansi-compatible one when I'm using code that uses ansiterm. All macos and linux terminals are great. On windows, it's more complicated.